You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by lu...@apache.org on 2014/01/01 18:30:07 UTC

svn commit: r1554654 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math3/geometry/spherical/oned/ main/java/org/apache/commons/math3/geometry/spherical/twod/ test/java/org/apache/commons/math3/geometry/spherical/oned/

Author: luc
Date: Wed Jan  1 17:30:06 2014
New Revision: 1554654

URL: http://svn.apache.org/r1554654
Log:
Simplified 1-sphere case.

Added:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java   (contents, props changed)
      - copied, changed from r1554653, commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java   (with props)
Removed:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubChord.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ChordTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/SubChordTest.java
Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SubCircle.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Arc.java Wed Jan  1 17:30:06 2014
@@ -16,6 +16,8 @@
  */
 package org.apache.commons.math3.geometry.spherical.oned;
 
+import org.apache.commons.math3.exception.NumberIsTooLargeException;
+import org.apache.commons.math3.exception.util.LocalizedFormats;
 import org.apache.commons.math3.geometry.partitioning.Region.Location;
 import org.apache.commons.math3.util.FastMath;
 import org.apache.commons.math3.util.MathUtils;
@@ -38,38 +40,54 @@ public class Arc {
     /** Middle point of the arc. */
     private final double middle;
 
+    /** Tolerance below which angles are considered identical. */
+    private final double tolerance;
+
     /** Simple constructor.
      * <p>
-     * As the circle is a closed curve, {@code lower} is
-     * allowed to be greater than {@code upper}, and will
-     * be automatically canonicalized so the arc wraps
-     * around \( 2\pi \), but without exceeding a total
-     * length of \( 2\pi \). If {@code lower} is equals
-     * to {@code upper}, the arc is considered to be the full
-     * circle.
+     * If either {@code lower} is equals to {@code upper} or
+     * the interval exceeds \( 2 \pi \), the arc is considered
+     * to be the full circle and its initial defining boundaries
+     * will be forgotten. {@code lower} is not allowed to be
+     * greater than {@code upper} (an exception is thrown in this case).
+     * {@code lower} will be canonicalized between 0 and \( 2 \pi \), and
+     * upper shifted accordingly, so the {@link #getInf()} and {@link #getSup()}
+     * may not return the value used at instance construction.
      * </p>
      * @param lower lower angular bound of the arc
      * @param upper upper angular bound of the arc
+     * @param tolerance tolerance below which angles are considered identical
+     * @exception NumberIsTooLargeException if lower is greater than upper
      */
-    public Arc(final double lower, final double upper) {
-        this.lower = lower;
-        if (Precision.equals(lower, upper, 0)) {
-            this.upper = MathUtils.TWO_PI + lower;
+    public Arc(final double lower, final double upper, final double tolerance)
+        throws NumberIsTooLargeException {
+        this.tolerance = tolerance;
+        if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
+            // the arc must cover the whole circle
+            this.lower  = 0;
+            this.upper  = MathUtils.TWO_PI;
+            this.middle = FastMath.PI;
+        } else  if (lower <= upper) {
+            this.lower  = MathUtils.normalizeAngle(lower, FastMath.PI);
+            this.upper  = this.lower + (upper - lower);
+            this.middle = 0.5 * (this.lower + this.upper);
         } else {
-            this.upper = MathUtils.normalizeAngle(upper, lower + FastMath.PI);
+            throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
+                                                lower, upper, true);
         }
-        this.middle = 0.5 * (this.lower + this.upper);
     }
 
     /** Get the lower angular bound of the arc.
-     * @return lower angular bound of the arc
+     * @return lower angular bound of the arc,
+     * always between 0 and \( 2 \pi \)
      */
     public double getInf() {
         return lower;
     }
 
     /** Get the upper angular bound of the arc.
-     * @return upper angular bound of the arc
+     * @return upper angular bound of the arc,
+     * always between {@link #getInf()} and {@link #getInf()} \( + 2 \pi \)
      */
     public double getSup() {
         return upper;
@@ -89,14 +107,19 @@ public class Arc {
         return middle;
     }
 
+    /** Get the tolerance below which angles are considered identical.
+     * @return tolerance below which angles are considered identical
+     */
+    public double getTolerance() {
+        return tolerance;
+    }
+
     /** Check a point with respect to the arc.
      * @param point point to check
-     * @param tolerance tolerance below which points are considered to
-     * belong to the boundary
      * @return a code representing the point status: either {@link
      * Location#INSIDE}, {@link Location#OUTSIDE} or {@link Location#BOUNDARY}
      */
-    public Location checkPoint(final double point, final double tolerance) {
+    public Location checkPoint(final double point) {
         final double normalizedPoint = MathUtils.normalizeAngle(point, middle);
         if (normalizedPoint < lower - tolerance || normalizedPoint > upper + tolerance) {
             return Location.OUTSIDE;

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSet.java Wed Jan  1 17:30:06 2014
@@ -21,6 +21,8 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.commons.math3.exception.NumberIsTooLargeException;
+import org.apache.commons.math3.exception.util.LocalizedFormats;
 import org.apache.commons.math3.geometry.partitioning.AbstractRegion;
 import org.apache.commons.math3.geometry.partitioning.BSPTree;
 import org.apache.commons.math3.geometry.partitioning.BSPTreeVisitor;
@@ -30,6 +32,13 @@ import org.apache.commons.math3.util.Mat
 import org.apache.commons.math3.util.Precision;
 
 /** This class represents a region of a circle: a set of arcs.
+ * <p>
+ * Note that due to the wrapping around \(2 \pi\), barycenter is
+ * ill-defined here. It was defined only in order to fulfill
+ * the requirements of the {@link
+ * org.apache.commons.math3.geometry.partitioning.Region Region}
+ * interface, but its use is discouraged.
+ * </p>
  * @version $Id$
  * @since 3.3
  */
@@ -47,19 +56,19 @@ public class ArcsSet extends AbstractReg
 
     /** Build an arcs set corresponding to a single arc.
      * <p>
-     * As the circle is a closed curve, {@code lower} is
-     * allowed to be greater than {@code upper}, and will
-     * be automatically canonicalized so the arc wraps
-     * around \( 2\pi \), but without exceeding a total
-     * length of \( 2\pi \). If {@code lower} is equals
-     * to {@code upper}, the arc is considered to be the full
-     * circle.
+     * If either {@code lower} is equals to {@code upper} or
+     * the interval exceeds \( 2 \pi \), the arc is considered
+     * to be the full circle and its initial defining boundaries
+     * will be forgotten. {@code lower} is not allowed to be greater
+     * than {@code upper} (an exception is thrown in this case).
      * </p>
      * @param lower lower bound of the arc
      * @param upper upper bound of the arc
      * @param tolerance tolerance below which close sub-arcs are merged together
+     * @exception NumberIsTooLargeException if lower is greater than upper
      */
-    public ArcsSet(final double lower, final double upper, final double tolerance) {
+    public ArcsSet(final double lower, final double upper, final double tolerance)
+        throws NumberIsTooLargeException {
         super(buildTree(lower, upper, tolerance));
         this.tolerance = tolerance;
     }
@@ -105,33 +114,236 @@ public class ArcsSet extends AbstractReg
     }
 
     /** Build an inside/outside tree representing a single arc.
-     * <p>
-     * As the circle is a closed curve, {@code lower} is
-     * allowed to be greater than {@code upper}, and will
-     * be automatically canonicalized so the arc wraps
-     * around \( 2\pi \), but without exceeding a total
-     * length of \( 2\pi \). If {@code lower} is equals
-     * to {@code upper}, the arc is considered to be the full
-     * circle.
-     * </p>
      * @param lower lower angular bound of the arc
      * @param upper upper angular bound of the arc
      * @param tolerance tolerance below which close sub-arcs are merged together
      * @return the built tree
+     * @exception NumberIsTooLargeException if lower is greater than upper
      */
-    private static BSPTree<Sphere1D> buildTree(final double lower, final double upper, final double tolerance) {
+    private static BSPTree<Sphere1D> buildTree(final double lower, final double upper,
+                                               final double tolerance)
+        throws NumberIsTooLargeException {
 
-        if (Precision.equals(lower, upper, 0)) {
-            // the tree must cover the whole real line
+        if (Precision.equals(lower, upper, 0) || (upper - lower) >= MathUtils.TWO_PI) {
+            // the tree must cover the whole circle
             return new BSPTree<Sphere1D>(Boolean.TRUE);
+        } else  if (lower > upper) {
+            throw new NumberIsTooLargeException(LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
+                                                lower, upper, true);
+        }
+
+        // this is a regular arc, covering only part of the circle
+        final double normalizedLower = MathUtils.normalizeAngle(lower, FastMath.PI);
+        final double normalizedUpper = normalizedLower + (upper - lower);
+        final SubHyperplane<Sphere1D> lowerCut =
+                new LimitAngle(new S1Point(normalizedLower), false, tolerance).wholeHyperplane();
+
+        if (normalizedUpper <= MathUtils.TWO_PI) {
+            // simple arc starting after 0 and ending before 2 \pi
+            final SubHyperplane<Sphere1D> upperCut =
+                    new LimitAngle(new S1Point(normalizedUpper), true, tolerance).wholeHyperplane();
+            return new BSPTree<Sphere1D>(lowerCut,
+                                         new BSPTree<Sphere1D>(Boolean.FALSE),
+                                         new BSPTree<Sphere1D>(upperCut,
+                                                               new BSPTree<Sphere1D>(Boolean.FALSE),
+                                                               new BSPTree<Sphere1D>(Boolean.TRUE),
+                                                               null),
+                                         null);
+        } else {
+            // arc wrapping around 2 \pi
+            final SubHyperplane<Sphere1D> upperCut =
+                    new LimitAngle(new S1Point(normalizedUpper - MathUtils.TWO_PI), true, tolerance).wholeHyperplane();
+            return new BSPTree<Sphere1D>(lowerCut,
+                                         new BSPTree<Sphere1D>(upperCut,
+                                                               new BSPTree<Sphere1D>(Boolean.FALSE),
+                                                               new BSPTree<Sphere1D>(Boolean.TRUE),
+                                                               null),
+                                         new BSPTree<Sphere1D>(Boolean.TRUE),
+                                         null);
+        }
+
+    }
+
+    /** Get the tolerance below which angles are considered identical.
+     * @return tolerance below which angles are considered identical
+     */
+    public double getTolerance() {
+        return tolerance;
+    }
+
+    /** Get the smallest internal node.
+     * @return smallest internal node (i.e. first after 0.0 radians, in trigonometric direction),
+     * or null if there are no internal nodes (i.e. the set is either empty or covers the full circle)
+     */
+    public LimitAngle getSmallestLimit() {
+
+        // start search at the tree root
+        BSPTree<Sphere1D> node = getTree(false);
+        if (node.getCut() == null) {
+            return null;
+        }
+
+        BSPTree<Sphere1D> previous = previousNode(node);
+        while (previous != null) {
+            node = previous;
+            previous = previousNode(node);
+        }
+
+        return (LimitAngle) node.getCut().getHyperplane();
+
+    }
+
+    /** Get the largest limit angle in the set.
+     * @return largest limit angle (i.e. last before or at \(2 \pi) radians, in trigonometric direction),
+     * or null if there are no limits (i.e. the set is either empty or covers the full circle)
+     */
+    public LimitAngle getLargestLimit() {
+
+        // start search at the tree root
+        BSPTree<Sphere1D> node = getTree(false);
+        if (node.getCut() == null) {
+            return null;
+        }
+
+        BSPTree<Sphere1D> next = nextNode(node);
+        while (next != null) {
+            node = next;
+            next = nextNode(node);
         }
 
-        // the two boundary angles define only one cutting chord
-        final double normalizedUpper = MathUtils.normalizeAngle(upper, lower + FastMath.PI);
-        return new BSPTree<Sphere1D>(new Chord(lower, normalizedUpper, tolerance).wholeHyperplane(),
-                                     new BSPTree<Sphere1D>(Boolean.FALSE),
-                                     new BSPTree<Sphere1D>(Boolean.TRUE),
-                                     null);
+        return (LimitAngle) node.getCut().getHyperplane();
+
+    }
+
+    /** Get the next internal node.
+     * @param node current node
+     * @return next internal node in trigonometric order, or null
+     * if this is the last internal node
+     */
+    private BSPTree<Sphere1D> nextNode(BSPTree<Sphere1D> node) {
+
+        final BSPTree<Sphere1D> nextDeeper =
+                ((LimitAngle) node.getCut().getHyperplane()).isDirect() ?
+                node.getPlus() : node.getMinus();
+
+        if (nextDeeper.getCut() != null) {
+            // the next node is in the sub-tree
+            return findSmallest(nextDeeper);
+        }
+
+        // there is nothing left deeper in the tree, we backtrack
+        while (isAfterParent(node)) {
+            node = node.getParent();
+        }
+        return node.getParent();
+
+    }
+
+    /** Get the previous internal node.
+     * @param node current node
+     * @return previous internal node in trigonometric order, or null
+     * if this is the first internal node
+     */
+    private BSPTree<Sphere1D> previousNode(BSPTree<Sphere1D> node) {
+
+        final BSPTree<Sphere1D> nextDeeper =
+                ((LimitAngle) node.getCut().getHyperplane()).isDirect() ?
+                node.getMinus() : node.getPlus();
+
+        if (nextDeeper.getCut() != null) {
+            // the next node is in the sub-tree
+            return findLargest(nextDeeper);
+        }
+
+        // there is nothing left deeper in the tree, we backtrack
+        while (isBeforeParent(node)) {
+            node = node.getParent();
+        }
+        return node.getParent();
+
+    }
+
+    /** Check if a node is the child before its parent in trigonometric order.
+     * @param node child node considered
+     * @return true is the node has a parent end is before it in trigonometric order
+     */
+    private boolean isBeforeParent(final BSPTree<Sphere1D> node) {
+        final BSPTree<Sphere1D> parent = node.getParent();
+        if (parent == null) {
+            return false;
+        }
+        if (((LimitAngle) parent.getCut().getHyperplane()).isDirect()) {
+            // smaller angles are on minus side, larger angles are on plus side
+            return node == parent.getMinus();
+        } else {
+            // smaller angles are on plus side, larger angles are on minus side
+            return node == parent.getPlus();
+        }
+    }
+
+    /** Check if a node is the child after its parent in trigonometric order.
+     * @param node child node considered
+     * @return true is the node has a parent end is after it in trigonometric order
+     */
+    private boolean isAfterParent(final BSPTree<Sphere1D> node) {
+        final BSPTree<Sphere1D> parent = node.getParent();
+        if (parent == null) {
+            return false;
+        }
+        if (((LimitAngle) parent.getCut().getHyperplane()).isDirect()) {
+            // smaller angles are on minus side, larger angles are on plus side
+            return node == parent.getPlus();
+        } else {
+            // smaller angles are on plus side, larger angles are on minus side
+            return node == parent.getMinus();
+        }
+    }
+
+    /** Find the smallest internal node in a sub-tree.
+     * @param node node at which the sub-tree starts
+     * @return smallest internal node (in trigonometric order), may be the
+     * provided node if no smaller internal node exist
+     */
+    private BSPTree<Sphere1D> findSmallest(BSPTree<Sphere1D> node) {
+
+        BSPTree<Sphere1D> internal = null;
+
+        while (node.getCut() != null) {
+            internal = node;
+            if (((LimitAngle) node.getCut().getHyperplane()).isDirect()) {
+                // smaller angles are on minus side, larger angles are on plus side
+                node = node.getMinus();
+            } else {
+                // smaller angles are on plus side, larger angles are on minus side
+                node = node.getPlus();
+            }
+        }
+
+        return internal;
+
+    }
+
+    /** Find the largest internal node in a sub-tree.
+     * @param node node at which the sub-tree starts
+     * @return largest internal node (in trigonometric order), may be the
+     * provided node if no larger internal node exist
+     */
+    private BSPTree<Sphere1D> findLargest(BSPTree<Sphere1D> node) {
+
+        BSPTree<Sphere1D> internal = null;
+
+        while (node.getCut() != null) {
+            internal = node;
+            if (((LimitAngle) node.getCut().getHyperplane()).isDirect()) {
+                // smaller angles are on minus side, larger angles are on plus side
+                node = node.getPlus();
+            } else {
+                // smaller angles are on plus side, larger angles are on minus side
+                node = node.getMinus();
+            }
+        }
+
+        return internal;
 
     }
 
@@ -160,8 +372,8 @@ public class ArcsSet extends AbstractReg
             } else if (size >= Precision.SAFE_MIN) {
                 setBarycenter(new S1Point(sum / size));
             } else {
-                final Chord chord = (Chord) getTree(false).getCut().getHyperplane();
-                setBarycenter(new S1Point(0.5 * (chord.getStart() + chord.getEnd())));
+                final LimitAngle limit = (LimitAngle) getTree(false).getCut().getHyperplane();
+                setBarycenter(limit.getLocation());
             }
         }
     }
@@ -182,7 +394,7 @@ public class ArcsSet extends AbstractReg
             // the tree has a single node
             if ((Boolean) root.getAttribute()) {
                 // it is an inside node, it represents the full circle
-                list.add(new Arc(0.0, 0.0)); // since lower == upper, the arc covers the full circle
+                list.add(new Arc(0.0, 0.0, tolerance)); // since lower == upper, the arc covers the full circle
             }
         } else {
 
@@ -190,6 +402,11 @@ public class ArcsSet extends AbstractReg
             final LimitsCollector finder = new LimitsCollector();
             root.visit(finder);
             final List<Double> limits = finder.getLimits();
+            if (limits.size() < 2) {
+                // the start and end angle collapsed to the same value, its the full circle again
+                list.add(new Arc(0.0, 0.0, tolerance)); // since lower == upper, the arc covers the full circle
+                return list;
+            }
 
             // sort them so the first angle is an arc start
             Collections.sort(limits);
@@ -201,7 +418,7 @@ public class ArcsSet extends AbstractReg
 
             // we can now build the list
             for (int i = 0; i < limits.size(); i += 2) {
-                list.add(new Arc(limits.get(i), limits.get(i + 1)));
+                list.add(new Arc(limits.get(i), limits.get(i + 1), tolerance));
             }
 
         }
@@ -229,12 +446,9 @@ public class ArcsSet extends AbstractReg
         /** {@inheritDoc} */
         public void visitInternalNode(final BSPTree<Sphere1D> node) {
             // check if the chord end points are arc limits
-            final Chord chord = (Chord) node.getCut().getHyperplane();
-            if (checkPoint(new S1Point(chord.getStart())) == Location.BOUNDARY) {
-                limits.add(MathUtils.normalizeAngle(chord.getStart(), FastMath.PI));
-            }
-            if (checkPoint(new S1Point(chord.getEnd())) == Location.BOUNDARY) {
-                limits.add(MathUtils.normalizeAngle(chord.getEnd(), FastMath.PI));
+            final LimitAngle limit = (LimitAngle) node.getCut().getHyperplane();
+            if (checkPoint(limit.getLocation()) == Location.BOUNDARY) {
+                limits.add(limit.getLocation().getAlpha());
             }
         }
 

Copied: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java (from r1554653, commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java)
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java?p2=commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java&p1=commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java&r1=1554653&r2=1554654&rev=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/Chord.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java Wed Jan  1 17:30:06 2014
@@ -18,43 +18,33 @@ package org.apache.commons.math3.geometr
 
 import org.apache.commons.math3.geometry.Point;
 import org.apache.commons.math3.geometry.partitioning.Hyperplane;
-import org.apache.commons.math3.util.FastMath;
-import org.apache.commons.math3.util.MathUtils;
 
 /** This class represents a 1D oriented hyperplane on the circle.
- * <p>An hyperplane on the 1-sphere is a chord that splits
- * the circle in two parts.</p>
+ * <p>An hyperplane on the 1-sphere is an angle with an orientation.</p>
  * <p>Instances of this class are guaranteed to be immutable.</p>
  * @version $Id$
  * @since 3.3
  */
-public class Chord implements Hyperplane<Sphere1D> {
+public class LimitAngle implements Hyperplane<Sphere1D> {
 
-    /** Start angle of the chord. */
-    private final double start;
+    /** Angle location. */
+    private S1Point location;
 
-    /** End angle of the chord. */
-    private final double end;
+    /** Orientation. */
+    private boolean direct;
 
-    /** Cosine of the half aperture. */
-    private final double cos;
-
-    /** Middle point of the chord. */
-    private final S1Point middle;
-
-    /** Tolerance below which close sub-arcs are merged together. */
+    /** Tolerance below which angles are considered identical. */
     private final double tolerance;
 
     /** Simple constructor.
-     * @param start start angle of the chord
-     * @param end end angle of the chord
-     * @param tolerance tolerance below which close sub-arcs are merged together
-     */
-    public Chord(final double start, final double end, final double tolerance) {
-        this.start     = start;
-        this.end       = end;
-        this.middle    = new S1Point(0.5 * (start + end));
-        this.cos       = FastMath.cos(0.5 * (end - start));
+     * @param location location of the hyperplane
+     * @param direct if true, the plus side of the hyperplane is towards
+     * angles greater than {@code location}
+     * @param tolerance tolerance below which angles are considered identical
+     */
+    public LimitAngle(final S1Point location, final boolean direct, final double tolerance) {
+        this.location  = location;
+        this.direct    = direct;
         this.tolerance = tolerance;
     }
 
@@ -63,22 +53,31 @@ public class Chord implements Hyperplane
      * the instance.</p>
      * @return the instance itself
      */
-    public Chord copySelf() {
+    public LimitAngle copySelf() {
         return this;
     }
 
     /** {@inheritDoc} */
     public double getOffset(final Point<Sphere1D> point) {
-        return cos - middle.getVector().dotProduct(((S1Point) point).getVector());
+        final double delta = ((S1Point) point).getAlpha()- location.getAlpha();
+        return direct ? delta : -delta;
+    }
+
+    /** Check if the hyperplane orientation is direct.
+     * @return true if the plus side of the hyperplane is towards
+     * angles greater than hyperplane location
+     */
+    public boolean isDirect() {
+        return direct;
     }
 
     /** Get the reverse of the instance.
-     * <p>Get a chord with reversed orientation with respect to the
+     * <p>Get a limit angle with reversed orientation with respect to the
      * instance. A new object is built, the instance is untouched.</p>
-     * @return a new chord, with orientation opposite to the instance orientation
+     * @return a new limit angle, with orientation opposite to the instance orientation
      */
-    public Chord getReverse() {
-        return new Chord(end, MathUtils.normalizeAngle(start, end + FastMath.PI), tolerance);
+    public LimitAngle getReverse() {
+        return new LimitAngle(location, !direct, tolerance);
     }
 
     /** Build a region covering the whole hyperplane.
@@ -92,8 +91,8 @@ public class Chord implements Hyperplane
      * <em>not</em> be used otherwise.</p>
      * @return a dummy sub hyperplane
      */
-    public SubChord wholeHyperplane() {
-        return new SubChord(this);
+    public SubLimitAngle wholeHyperplane() {
+        return new SubLimitAngle(this, null);
     }
 
     /** Build a region covering the whole space.
@@ -106,25 +105,18 @@ public class Chord implements Hyperplane
 
     /** {@inheritDoc} */
     public boolean sameOrientationAs(final Hyperplane<Sphere1D> other) {
-        return middle.getVector().dotProduct(((Chord) other).middle.getVector()) >= 0.0;
-    }
-
-    /** Get the start angle of the chord.
-     * @return start angle of the chord.
-     */
-    public double getStart() {
-        return start;
+        return !(direct ^ ((LimitAngle) other).direct);
     }
 
-    /** Get the end angle of the chord.
-     * @return end angle of the chord.
+    /** Get the hyperplane location on the circle.
+     * @return the hyperplane location
      */
-    public double getEnd() {
-        return end;
+    public S1Point getLocation() {
+        return location;
     }
 
-    /** Get the tolerance below which close sub-arcs are merged together.
-     * @return tolerance below which close sub-arcs are merged together
+    /** Get the tolerance below which angles are considered identical.
+     * @return tolerance below which angles are considered identical
      */
     public double getTolerance() {
         return tolerance;

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/LimitAngle.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/S1Point.java Wed Jan  1 17:30:06 2014
@@ -49,7 +49,8 @@ public class S1Point implements Point<Sp
      * @see #getAlpha()
      */
     public S1Point(final double alpha) {
-        this(alpha, new Vector2D(FastMath.cos(alpha), FastMath.sin(alpha)));
+        this(MathUtils.normalizeAngle(alpha, FastMath.PI),
+             new Vector2D(FastMath.cos(alpha), FastMath.sin(alpha)));
     }
 
     /** Build a point from its internal components.

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java?rev=1554654&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java Wed Jan  1 17:30:06 2014
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.math3.geometry.spherical.oned;
+
+import org.apache.commons.math3.geometry.partitioning.AbstractSubHyperplane;
+import org.apache.commons.math3.geometry.partitioning.Hyperplane;
+import org.apache.commons.math3.geometry.partitioning.Region;
+import org.apache.commons.math3.geometry.partitioning.Side;
+
+/** This class represents sub-hyperplane for {@link LimitAngle}.
+ * <p>Instances of this class are guaranteed to be immutable.</p>
+ * @version $Id$
+ * @since 3.3
+ */
+public class SubLimitAngle extends AbstractSubHyperplane<Sphere1D, Sphere1D> {
+
+    /** Simple constructor.
+     * @param hyperplane underlying hyperplane
+     * @param remainingRegion remaining region of the hyperplane
+     */
+    public SubLimitAngle(final Hyperplane<Sphere1D> hyperplane,
+                         final Region<Sphere1D> remainingRegion) {
+        super(hyperplane, remainingRegion);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public double getSize() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    public boolean isEmpty() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected AbstractSubHyperplane<Sphere1D, Sphere1D> buildNew(final Hyperplane<Sphere1D> hyperplane,
+                                                                 final Region<Sphere1D> remainingRegion) {
+        return new SubLimitAngle(hyperplane, remainingRegion);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public Side side(final Hyperplane<Sphere1D> hyperplane) {
+        final double global = hyperplane.getOffset(((LimitAngle) getHyperplane()).getLocation());
+        return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public SplitSubHyperplane<Sphere1D> split(final Hyperplane<Sphere1D> hyperplane) {
+        final double global = hyperplane.getOffset(((LimitAngle) getHyperplane()).getLocation());
+        return (global < -1.0e-10) ?
+                                    new SplitSubHyperplane<Sphere1D>(null, this) :
+                                    new SplitSubHyperplane<Sphere1D>(this, null);
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/oned/SubLimitAngle.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/Circle.java Wed Jan  1 17:30:06 2014
@@ -23,8 +23,8 @@ import org.apache.commons.math3.geometry
 import org.apache.commons.math3.geometry.partitioning.Hyperplane;
 import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
 import org.apache.commons.math3.geometry.partitioning.Transform;
+import org.apache.commons.math3.geometry.spherical.oned.Arc;
 import org.apache.commons.math3.geometry.spherical.oned.ArcsSet;
-import org.apache.commons.math3.geometry.spherical.oned.Chord;
 import org.apache.commons.math3.geometry.spherical.oned.S1Point;
 import org.apache.commons.math3.geometry.spherical.oned.Sphere1D;
 import org.apache.commons.math3.util.FastMath;
@@ -223,15 +223,15 @@ public class Circle implements Hyperplan
         return pole;
     }
 
-    /** Get the chord of the instance that lies inside the other circle.
+    /** Get the arc of the instance that lies inside the other circle.
      * @param other other circle
-     * @return chord of the instance that lies inside the other circle
+     * @return arc of the instance that lies inside the other circle
      * (guaranteed to always have a length of \( \pi \))
      */
-    public Chord getChord(final Circle other) {
+    public Arc getInsideArc(final Circle other) {
         final double alpha  = getPhase(other.pole);
         final double halfPi = 0.5 * FastMath.PI;
-        return new Chord(alpha - halfPi, alpha + halfPi, tolerance);
+        return new Arc(alpha - halfPi, alpha + halfPi, tolerance);
     }
 
     /** {@inheritDoc} */

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SubCircle.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SubCircle.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SubCircle.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SubCircle.java Wed Jan  1 17:30:06 2014
@@ -22,6 +22,7 @@ import org.apache.commons.math3.geometry
 import org.apache.commons.math3.geometry.partitioning.Region;
 import org.apache.commons.math3.geometry.partitioning.Side;
 import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
+import org.apache.commons.math3.geometry.spherical.oned.Arc;
 import org.apache.commons.math3.geometry.spherical.oned.ArcsSet;
 import org.apache.commons.math3.geometry.spherical.oned.Chord;
 import org.apache.commons.math3.geometry.spherical.oned.Sphere1D;
@@ -54,16 +55,8 @@ public class SubCircle extends AbstractS
 
         final Circle thisCircle  = (Circle) getHyperplane();
         final Circle otherCircle = (Circle) hyperplane;
-        final Chord  chord       = thisCircle.getChord(otherCircle);
-
-        if (chord == null) {
-            // the circles are disjoint
-            final double global = otherCircle.getOffset(thisCircle.getXAxis());
-            return (global < -1.0e-10) ? Side.MINUS : ((global > 1.0e-10) ? Side.PLUS : Side.HYPER);
-        }
-
-        // the circles do intersect each other
-        return getRemainingRegion().side(chord);
+        final Arc    arc         = thisCircle.getInsideArc(otherCircle);
+        return ((ArcsSet) getRemainingRegion()).side(arc);
 
     }
 
@@ -73,17 +66,8 @@ public class SubCircle extends AbstractS
 
         final Circle thisCircle  = (Circle) getHyperplane();
         final Circle otherCircle = (Circle) hyperplane;
-        final Chord  chord       = thisCircle.getChord(otherCircle);
-
-        if (chord == null) {
-            // the circles are disjoint
-            final double global = otherCircle.getOffset(thisCircle.getXAxis());
-            return (global < -1.0e-10) ?
-                   new SplitSubHyperplane<Sphere2D>(null, this) :
-                   new SplitSubHyperplane<Sphere2D>(this, null);
-        }
+        final Arc    arc         = thisCircle.getInsideArc(otherCircle);
 
-        // the circles do intersect
         final SubHyperplane<Sphere1D> subMinus = chord.wholeHyperplane();
         final SubHyperplane<Sphere1D> subPlus  = chord.getReverse().wholeHyperplane();
         final BSPTree<Sphere1D> splitTree = getRemainingRegion().getTree(false).split(subMinus);

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcTest.java Wed Jan  1 17:30:06 2014
@@ -16,8 +16,10 @@
  */
 package org.apache.commons.math3.geometry.spherical.oned;
 
+import org.apache.commons.math3.exception.NumberIsTooLargeException;
 import org.apache.commons.math3.geometry.partitioning.Region;
 import org.apache.commons.math3.util.FastMath;
+import org.apache.commons.math3.util.MathUtils;
 import org.apache.commons.math3.util.Precision;
 import org.junit.Assert;
 import org.junit.Test;
@@ -26,49 +28,52 @@ public class ArcTest {
 
     @Test
     public void testArc() {
-        Arc arc = new Arc(2.3, 5.7);
+        Arc arc = new Arc(2.3, 5.7, 1.0e-10);
         Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
         Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(2.3, 1.0e-10));
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(5.7, 1.0e-10));
-        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(1.2, 1.0e-10));
-        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(8.5, 1.0e-10));
-        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(8.7, 1.0e-10));
-        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(3.0, 1.0e-10));
+        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(2.3));
+        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(5.7));
+        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(1.2));
+        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(8.5));
+        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(8.7));
+        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(3.0));
         Assert.assertEquals(2.3, arc.getInf(), 1.0e-10);
         Assert.assertEquals(5.7, arc.getSup(), 1.0e-10);
         Assert.assertEquals(4.0, arc.getBarycenter(), 1.0e-10);
         Assert.assertEquals(3.4, arc.getSize(), 1.0e-10);
     }
 
+    @Test(expected=NumberIsTooLargeException.class)
+    public void testWrongInterval() {
+        new Arc(1.2, 0.0, 1.0e-10);
+    }
+
     @Test
     public void testTolerance() {
-        Arc arc = new Arc(2.3, 5.7);
-        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(1.2, 1.0));
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(1.2, 1.2));
-        Assert.assertEquals(Region.Location.OUTSIDE,  arc.checkPoint(6.5, 0.7));
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(6.5, 0.9));
-        Assert.assertEquals(Region.Location.INSIDE,   arc.checkPoint(3.0, 0.6));
-        Assert.assertEquals(Region.Location.BOUNDARY, arc.checkPoint(3.0, 0.8));
+        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, 1.0).checkPoint(1.2));
+        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 1.2).checkPoint(1.2));
+        Assert.assertEquals(Region.Location.OUTSIDE,  new Arc(2.3, 5.7, 0.7).checkPoint(6.5));
+        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.9).checkPoint(6.5));
+        Assert.assertEquals(Region.Location.INSIDE,   new Arc(2.3, 5.7, 0.6).checkPoint(3.0));
+        Assert.assertEquals(Region.Location.BOUNDARY, new Arc(2.3, 5.7, 0.8).checkPoint(3.0));
     }
 
     @Test
     public void testFullCircle() {
-        Arc arc = new Arc(9.0, 9.0);
+        Arc arc = new Arc(9.0, 9.0, 1.0e-10);
         // no boundaries on a full circle
-        Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(9.0, 1.0e-10));
-        Assert.assertEquals(9.0, arc.getInf(), 1.0e-10);
-        Assert.assertEquals(9.0 + 2.0 * FastMath.PI, arc.getSup(), 1.0e-10);
+        Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(9.0));
+        Assert.assertEquals(.0, arc.getInf(), 1.0e-10);
+        Assert.assertEquals(MathUtils.TWO_PI, arc.getSup(), 1.0e-10);
         Assert.assertEquals(2.0 * FastMath.PI, arc.getSize(), 1.0e-10);
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
-            Assert.assertEquals(Region.Location.INSIDE,
-                                arc.checkPoint(alpha, 1.0e-10));
+            Assert.assertEquals(Region.Location.INSIDE, arc.checkPoint(alpha));
         }
     }
 
     @Test
     public void testSmall() {
-        Arc arc = new Arc(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY));
+        Arc arc = new Arc(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY), Precision.EPSILON);
         Assert.assertEquals(2 * Precision.EPSILON, arc.getSize(), Precision.SAFE_MIN);
         Assert.assertEquals(1.0, arc.getBarycenter(), Precision.EPSILON);
     }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java?rev=1554654&r1=1554653&r2=1554654&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java (original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/oned/ArcsSetTest.java Wed Jan  1 17:30:06 2014
@@ -16,11 +16,14 @@
  */
 package org.apache.commons.math3.geometry.spherical.oned;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.math3.exception.NumberIsTooLargeException;
 import org.apache.commons.math3.geometry.partitioning.Region;
 import org.apache.commons.math3.geometry.partitioning.Region.Location;
 import org.apache.commons.math3.geometry.partitioning.RegionFactory;
+import org.apache.commons.math3.geometry.partitioning.SubHyperplane;
 import org.apache.commons.math3.util.FastMath;
 import org.apache.commons.math3.util.MathUtils;
 import org.apache.commons.math3.util.Precision;
@@ -33,7 +36,7 @@ public class ArcsSetTest {
     public void testArc() {
         ArcsSet set = new ArcsSet(2.3, 5.7, 1.0e-10);
         Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
-        Assert.assertEquals(4.0, ((S1Point) set.getBarycenter()).getAlpha(), 1.0e-10);
+        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3)));
         Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(1.2)));
@@ -43,13 +46,59 @@ public class ArcsSetTest {
         Assert.assertEquals(1, set.asList().size());
         Assert.assertEquals(2.3, set.asList().get(0).getInf(), 1.0e-10);
         Assert.assertEquals(5.7, set.asList().get(0).getSup(), 1.0e-10);
-        Assert.assertEquals(4.0, ((S1Point) set.getBarycenter()).getAlpha(), 1.0e-10);
-        Assert.assertEquals(3.4, set.getSize(), 1.0e-10);
+        Assert.assertEquals(2.3, set.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
+        Assert.assertFalse(set.getSmallestLimit().isDirect());
+        Assert.assertEquals(5.7, set.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
+        Assert.assertTrue(set.getLargestLimit().isDirect());
+    }
+
+    @Test
+    public void testWrapAround2PiArc() {
+        ArcsSet set = new ArcsSet(5.7 - MathUtils.TWO_PI, 2.3, 1.0e-10);
+        Assert.assertEquals(MathUtils.TWO_PI - 3.4, set.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(2.3)));
+        Assert.assertEquals(Region.Location.BOUNDARY, set.checkPoint(new S1Point(5.7)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(1.2)));
+        Assert.assertEquals(Region.Location.INSIDE,   set.checkPoint(new S1Point(8.5)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(8.7)));
+        Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(3.0)));
+        Assert.assertEquals(1, set.asList().size());
+        Assert.assertEquals(5.7, set.asList().get(0).getInf(), 1.0e-10);
+        Assert.assertEquals(2.3 + MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(2.3, set.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
+        Assert.assertTrue(set.getSmallestLimit().isDirect());
+        Assert.assertEquals(5.7, set.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
+        Assert.assertFalse(set.getLargestLimit().isDirect());
+    }
+
+    @Test(expected=NumberIsTooLargeException.class)
+    public void testWrongInterval() {
+        new ArcsSet(1.2, 0.0, 1.0e-10);
+    }
+
+    @Test
+    public void testFullEqualEndPoints() {
+        ArcsSet set = new ArcsSet(1.0, 1.0, 1.0e-10);
+        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        Assert.assertNull(set.getSmallestLimit());
+        Assert.assertNull(set.getLargestLimit());
+        Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0)));
+        for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
+            Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
+        }
+        Assert.assertEquals(1, set.asList().size());
+        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
+        Assert.assertEquals(2 * FastMath.PI, set.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(2 * FastMath.PI, set.getSize(), 1.0e-10);
     }
 
     @Test
     public void testFullCircle() {
-        ArcsSet set = new ArcsSet(9.0, 9.0, 1.0e-10);
+        ArcsSet set = new ArcsSet(1.0e-10);
+        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        Assert.assertNull(set.getSmallestLimit());
+        Assert.assertNull(set.getLargestLimit());
         Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(9.0)));
         for (double alpha = -20.0; alpha <= 20.0; alpha += 0.1) {
             Assert.assertEquals(Region.Location.INSIDE, set.checkPoint(new S1Point(alpha)));
@@ -61,6 +110,44 @@ public class ArcsSetTest {
     }
 
     @Test
+    public void testEmpty() {
+        ArcsSet empty = (ArcsSet) new RegionFactory<Sphere1D>().getComplement(new ArcsSet(1.0e-10));
+        Assert.assertEquals(1.0e-10, empty.getTolerance(), 1.0e-20);
+        Assert.assertEquals(0.0, empty.getSize(), 1.0e-10);
+        Assert.assertTrue(empty.asList().isEmpty());
+        Assert.assertNull(empty.getSmallestLimit());
+        Assert.assertNull(empty.getLargestLimit());
+    }
+
+    @Test
+    public void testTiny() {
+        ArcsSet tiny = new ArcsSet(0.0, Precision.SAFE_MIN / 2, 1.0e-10);
+        Assert.assertEquals(1.0e-10, tiny.getTolerance(), 1.0e-20);
+        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getSize(), 1.0e-10);
+        Assert.assertEquals(1, tiny.asList().size());
+        Assert.assertEquals(0.0, tiny.asList().get(0).getInf(), 1.0e-10);
+        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(0.0, tiny.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
+        Assert.assertEquals(Precision.SAFE_MIN / 2, tiny.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
+    }
+
+    @Test
+    public void testSpecialConstruction() {
+        List<SubHyperplane<Sphere1D>> boundary = new ArrayList<SubHyperplane<Sphere1D>>();
+        boundary.add(new LimitAngle(new S1Point(0.0), false, 1.0e-10).wholeHyperplane());
+        boundary.add(new LimitAngle(new S1Point(MathUtils.TWO_PI), true, 1.0e-10).wholeHyperplane());
+        ArcsSet set = new ArcsSet(boundary, 1.0e-10);
+        Assert.assertEquals(MathUtils.TWO_PI, set.getSize(), 1.0e-10);
+        Assert.assertEquals(1.0e-10, set.getTolerance(), 1.0e-20);
+        Assert.assertEquals(1, set.asList().size());
+        Assert.assertEquals(0.0, set.asList().get(0).getInf(), 1.0e-10);
+        Assert.assertEquals(MathUtils.TWO_PI, set.asList().get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(0.0, set.getSmallestLimit().getLocation().getAlpha(), 1.0e-10);
+        Assert.assertFalse(set.getSmallestLimit().isDirect());
+        Assert.assertEquals(0.0, set.getLargestLimit().getLocation().getAlpha(), 1.0e-10);
+    }
+
+    @Test
     public void testDifference() {
 
         ArcsSet a   = new ArcsSet(1.0, 6.0, 1.0e-10);
@@ -139,9 +226,11 @@ public class ArcsSetTest {
         }
 
         List<Arc> aMbList = aMb.asList();
-        Assert.assertEquals(1,   aMbList.size());
+        Assert.assertEquals(2,   aMbList.size());
         Assert.assertEquals(1.0, aMbList.get(0).getInf(), 1.0e-10);
         Assert.assertEquals(3.0, aMbList.get(0).getSup(), 1.0e-10);
+        Assert.assertEquals(5.0, aMbList.get(1).getInf(), 1.0e-10);
+        Assert.assertEquals(5.5, aMbList.get(1).getSup(), 1.0e-10);
 
 
     }
@@ -155,7 +244,6 @@ public class ArcsSetTest {
                                                               new ArcsSet(0.5, 2.0, 1.0e-10)),
                                                               new ArcsSet(0.0, 5.5, 1.0e-10));
         Assert.assertEquals(3.0, set.getSize(), 1.0e-10);
-        Assert.assertEquals(7.0 / 3.0, ((S1Point) set.getBarycenter()).getAlpha(), 1.0e-10);
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(0.0)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(4.0)));
         Assert.assertEquals(Region.Location.OUTSIDE,  set.checkPoint(new S1Point(6.0)));
@@ -179,7 +267,6 @@ public class ArcsSetTest {
     public void testSinglePoint() {
         ArcsSet set = new ArcsSet(1.0, FastMath.nextAfter(1.0, Double.POSITIVE_INFINITY), 1.0e-10);
         Assert.assertEquals(2 * Precision.EPSILON, set.getSize(), Precision.SAFE_MIN);
-        Assert.assertEquals(1.0, ((S1Point) set.getBarycenter()).getAlpha(), Precision.EPSILON);
     }
 
 }