Author: luc
Date: Tue Jan 14 18:26:32 2014
New Revision: 1558149

URL: http://svn.apache.org/r1558149
Log:
Fixed problem for spherical polygons with holes.

Modified:
    
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/partitioning/BSPTree.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/twod/SphericalPolygonsSet.java
    
commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSetTest.java

Modified: 
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/partitioning/BSPTree.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/partitioning/BSPTree.java?rev=1558149&r1=1558148&r2=1558149&view=diff
==============================================================================
--- 
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/partitioning/BSPTree.java
 (original)
+++ 
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/partitioning/BSPTree.java
 Tue Jan 14 18:26:32 2014
@@ -665,6 +665,46 @@ public class BSPTree<S extends Space> {
 
     }
 
+    /** Prune a tree around a cell.
+     * <p>
+     * This method can be used to extract a convex cell from a tree.
+     * The original cell may either be a leaf node or an internal node.
+     * If it is an internal node, it's subtree will be ignored (i.e. the
+     * extracted cell will be a leaf node in all cases). The original
+     * tree to which the original cell belongs is not touched at all,
+     * a new independent tree will be built.
+     * </p>
+     * @param cellAttribute attribute to set for the leaf node
+     * corresponding to the initial instance cell
+     * @param otherLeafsAttributes attribute to set for the other leaf
+     * nodes
+     * @param internalAttributes attribute to set for the internal nodes
+     * @return a new tree (the original tree is left untouched) containing
+     * a single branch with the cell as a leaf node, and other leaf nodes
+     * as the remnants of the pruned branches
+     */
+    public BSPTree<S> pruneAroundConvexCell(final Object cellAttribute,
+                                            final Object otherLeafsAttributes,
+                                            final Object internalAttributes) {
+
+        // build the current cell leaf
+        BSPTree<S> tree = new BSPTree<S>(cellAttribute);
+
+        // build the pruned tree bottom-up
+        for (BSPTree<S> current = this; current.parent != null; current = 
current.parent) {
+            final SubHyperplane<S> parentCut = current.parent.cut.copySelf();
+            final BSPTree<S>       sibling   = new 
BSPTree<S>(otherLeafsAttributes);
+            if (current == current.parent.plus) {
+                tree = new BSPTree<S>(parentCut, tree, sibling, 
internalAttributes);
+            } else {
+                tree = new BSPTree<S>(parentCut, sibling, tree, 
internalAttributes);
+            }
+        }
+
+        return tree;
+
+    }
+
     /** Chop off parts of the tree.
      * <p>The instance is modified in place, all the parts that are on
      * the minus side of the chopping hyperplane are discarded, only the

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=1558149&r1=1558148&r2=1558149&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
 Tue Jan 14 18:26:32 2014
@@ -520,8 +520,8 @@ public class ArcsSet extends AbstractReg
             current    = firstStart;
 
             if (firstStart == null) {
-                // the tree has a single node
-                if ((Boolean) getTree(false).getAttribute()) {
+                // all the leaf tree nodes share the same inside/outside status
+                if ((Boolean) getFirstLeaf(getTree(false)).getAttribute()) {
                     // it is an inside node, it represents the full circle
                     pending = new double[] {
                         0, MathUtils.TWO_PI

Modified: 
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSet.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSet.java?rev=1558149&r1=1558148&r2=1558149&view=diff
==============================================================================
--- 
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSet.java
 (original)
+++ 
commons/proper/math/trunk/src/main/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSet.java
 Tue Jan 14 18:26:32 2014
@@ -25,7 +25,9 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.math3.exception.MathIllegalStateException;
+import org.apache.commons.math3.exception.MathInternalError;
 import org.apache.commons.math3.exception.util.LocalizedFormats;
+import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math3.geometry.partitioning.AbstractRegion;
 import org.apache.commons.math3.geometry.partitioning.BSPTree;
@@ -67,6 +69,19 @@ public class SphericalPolygonsSet extend
               tolerance);
     }
 
+    /** Build a polygons set representing a regular polygon.
+     * @param center center of the polygon (the center is in the inside half)
+     * @param meridian point defining the reference meridian for first polygon 
vertex
+     * @param outsideRadius distance of the vertices to the center
+     * @param n number of sides of the polygon
+     * @param tolerance below which points are consider to be identical
+     */
+    public SphericalPolygonsSet(final Vector3D center, final Vector3D meridian,
+                                final double outsideRadius, final int n,
+                                final double tolerance) {
+        this(tolerance, createRegularPolygonVertices(center, meridian, 
outsideRadius, n));
+    }
+
     /** Build a polygons set from a BSP tree.
      * <p>The leaf nodes of the BSP tree <em>must</em> have a
      * {@code Boolean} attribute representing the inside status of
@@ -140,6 +155,27 @@ public class SphericalPolygonsSet extend
         super(verticesToTree(hyperplaneThickness, vertices), 
hyperplaneThickness);
     }
 
+    /** Build the vertices representing a regular polygon.
+     * @param center center of the polygon (the center is in the inside half)
+     * @param meridian point defining the reference meridian for first polygon 
vertex
+     * @param outsideRadius distance of the vertices to the center
+     * @param n number of sides of the polygon
+     * @return vertices array
+     */
+    private static S2Point[] createRegularPolygonVertices(final Vector3D 
center, final Vector3D meridian,
+                                                          final double 
outsideRadius, final int n) {
+        final S2Point[] array = new S2Point[n];
+        final Rotation r0 = new Rotation(Vector3D.crossProduct(center, 
meridian), outsideRadius);
+        array[0] = new S2Point(r0.applyTo(center));
+
+        final Rotation r = new Rotation(center, MathUtils.TWO_PI / n);
+        for (int i = 1; i < n; ++i) {
+            array[i] = new S2Point(r.applyTo(array[i - 1].getVector()));
+        }
+
+        return array;
+    }
+
     /** Build the BSP tree of a polygons set from a simple list of vertices.
      * <p>The boundary is provided as a list of points considering to
      * represent the vertices of a simple loop. The interior part of the
@@ -583,70 +619,28 @@ public class SphericalPolygonsSet extend
     @Override
     protected void computeGeometricalProperties() throws 
MathIllegalStateException {
 
-        final List<Vertex> boundary = getBoundaryLoops();
+        final BSPTree<Sphere2D> tree = getTree(true);
+
+        if (tree.getCut() == null) {
+
+            // the instance has a single cell without any boundaries
 
-        if (boundary.isEmpty()) {
-            final BSPTree<Sphere2D> tree = getTree(false);
             if (tree.getCut() == null && (Boolean) tree.getAttribute()) {
                 // the instance covers the whole space
                 setSize(4 * FastMath.PI);
+                setBarycenter(new S2Point(0, 0));
             } else {
                 setSize(0);
+                setBarycenter(S2Point.NaN);
             }
-            setBarycenter(new S2Point(0, 0));
-        } else {
-
-            // compute some integrals around the shape
-            double   sumArea = 0;
-            Vector3D sumB    = Vector3D.ZERO;
-
-            for (final Vertex startVertex : boundary) {
-
-                int n = 0;
-                double sum = 0;
-                Vector3D sumP = Vector3D.ZERO;
-                for (Edge edge = startVertex.getOutgoing();
-                     n == 0 || edge.getStart() != startVertex;
-                     edge = edge.getEnd().getOutgoing()) {
-                    final Vector3D middle = edge.getPointAt(0.5 * 
edge.getLength());
-                    sumP = new Vector3D(1, sumP, edge.getLength(), middle);
-
-                    // find path interior angle at vertex
-                    final Vector3D previousPole = edge.getCircle().getPole();
-                    final Vector3D nextPole     = 
edge.getEnd().getOutgoing().getCircle().getPole();
-                    final Vector3D point        = 
edge.getEnd().getLocation().getVector();
-                    double alpha = 
FastMath.atan2(Vector3D.dotProduct(nextPole, Vector3D.crossProduct(point, 
previousPole)),
-                                                  
-Vector3D.dotProduct(nextPole, previousPole));
-                    if (alpha < 0) {
-                        alpha += MathUtils.TWO_PI;
-                    }
-                    sum += alpha;
-                    n++;
-                }
-
-                // compute area using extended Girard theorem
-                // see Spherical Trigonometry: For the Use of Colleges and 
Schools by I. Todhunter
-                // article 99 in chapter VIII Area Of a Spherical Triangle. 
Spherical Excess.
-                // book available from project Gutenberg at 
http://www.gutenberg.org/ebooks/19770
-                final double area = sum - (n - 2) * FastMath.PI;
-                sumArea += area;
 
-                sumB = new Vector3D(1, sumB, area, sumP);
+        } else {
 
-            }
-
-            if (sumArea < 0) {
-                sumArea = 4 * FastMath.PI - sumArea;
-                sumB = sumB.negate();
-            }
-
-            setSize(sumArea);
-            final double norm = sumB.getNorm();
-            if (norm == 0.0) {
-                setBarycenter(S2Point.NaN);
-            } else {
-                setBarycenter(new S2Point(new Vector3D(1.0 / norm, sumB)));
-            }
+            // the instance has a boundary
+            final PropertiesComputer pc = new 
PropertiesComputer(getTolerance());
+            tree.visit(pc);
+            setSize(pc.getArea());
+            setBarycenter(pc.getBarycenter());
 
         }
 
@@ -849,4 +843,137 @@ public class SphericalPolygonsSet extend
 
     }
 
+    /** Visitor computing geometrical properties. */
+    private static class PropertiesComputer implements 
BSPTreeVisitor<Sphere2D> {
+
+        /** Tolerance below which points are consider to be identical. */
+        private final double tolerance;
+
+        /** Summed area. */
+        private double summedArea;
+
+        /** Summed barycenter. */
+        private Vector3D summedBarycenter;
+
+        /** Simple constructor.
+     * @param tolerance below which points are consider to be identical
+         */
+        public PropertiesComputer(final double tolerance) {
+            this.tolerance        = tolerance;
+            this.summedArea       = 0;
+            this.summedBarycenter = Vector3D.ZERO;
+        }
+
+        /** {@inheritDoc} */
+        public Order visitOrder(final BSPTree<Sphere2D> node) {
+            return Order.MINUS_SUB_PLUS;
+        }
+
+        /** {@inheritDoc} */
+        public void visitInternalNode(final BSPTree<Sphere2D> node) {
+            // nothing to do here
+        }
+
+        /** {@inheritDoc} */
+        public void visitLeafNode(final BSPTree<Sphere2D> node) {
+            if ((Boolean) node.getAttribute()) {
+
+                // transform this inside leaf cell into a simple convex polygon
+                final SphericalPolygonsSet convex =
+                        new 
SphericalPolygonsSet(node.pruneAroundConvexCell(Boolean.TRUE,
+                                                                            
Boolean.FALSE,
+                                                                            
null),
+                                                 tolerance);
+
+                // extract the start of the single loop boundary of the convex 
cell
+                final List<Vertex> boundary = convex.getBoundaryLoops();
+                if (boundary.size() != 1) {
+                    // this should never happen
+                    throw new MathInternalError();
+                }
+
+                // compute the geometrical properties of the convex cell
+                final double area  = convexCellArea(boundary.get(0));
+                final Vector3D barycenter = 
convexCellBarycenter(boundary.get(0));
+
+                // add the cell contribution to the global properties
+                summedArea      += area;
+                summedBarycenter = new Vector3D(1, summedBarycenter, area, 
barycenter);
+
+            }
+        }
+
+        /** Compute convex cell area.
+         * @param start start vertex of the convex cell boundary
+         * @return area
+         */
+        private double convexCellArea(final Vertex start) {
+
+            int n = 0;
+            double sum = 0;
+
+            // loop around the cell
+            for (Edge e = start.getOutgoing(); n == 0 || e.getStart() != 
start; e = e.getEnd().getOutgoing()) {
+
+                // find path interior angle at vertex
+                final Vector3D previousPole = e.getCircle().getPole();
+                final Vector3D nextPole     = 
e.getEnd().getOutgoing().getCircle().getPole();
+                final Vector3D point        = 
e.getEnd().getLocation().getVector();
+                double alpha = FastMath.atan2(Vector3D.dotProduct(nextPole, 
Vector3D.crossProduct(point, previousPole)),
+                                              -Vector3D.dotProduct(nextPole, 
previousPole));
+                if (alpha < 0) {
+                    alpha += MathUtils.TWO_PI;
+                }
+                sum += alpha;
+                n++;
+            }
+
+            // compute area using extended Girard theorem
+            // see Spherical Trigonometry: For the Use of Colleges and Schools 
by I. Todhunter
+            // article 99 in chapter VIII Area Of a Spherical Triangle. 
Spherical Excess.
+            // book available from project Gutenberg at 
http://www.gutenberg.org/ebooks/19770
+            return sum - (n - 2) * FastMath.PI;
+
+        }
+
+        /** Compute convex cell barycenter.
+         * @param start start vertex of the convex cell boundary
+         * @return barycenter
+         */
+        private Vector3D convexCellBarycenter(final Vertex start) {
+
+            int n = 0;
+            Vector3D sumB = Vector3D.ZERO;
+
+            // loop around the cell
+            for (Edge e = start.getOutgoing(); n == 0 || e.getStart() != 
start; e = e.getEnd().getOutgoing()) {
+                final Vector3D middle = e.getPointAt(0.5 * e.getLength());
+                sumB = new Vector3D(1, sumB, e.getLength(), middle);
+                n++;
+            }
+
+            return sumB.normalize();
+
+        }
+
+        /** Get the area.
+         * @return area
+         */
+        public double getArea() {
+            return summedArea;
+        }
+
+        /** Get the barycenter.
+         * @return barycenter
+         */
+        public S2Point getBarycenter() {
+            if (summedBarycenter.getNormSq() == 0) {
+                return S2Point.NaN;
+            } else {
+                return new S2Point(summedBarycenter);
+            }
+        }
+
+    }
+
 }

Modified: 
commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSetTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSetTest.java?rev=1558149&r1=1558148&r2=1558149&view=diff
==============================================================================
--- 
commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSetTest.java
 (original)
+++ 
commons/proper/math/trunk/src/test/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSetTest.java
 Tue Jan 14 18:26:32 2014
@@ -205,9 +205,6 @@ public class SphericalPolygonsSetTest {
         Assert.assertEquals(3, count);
 
         Assert.assertEquals(1.5 * FastMath.PI, threeOctants.getSize(), 
1.0e-10);
-        Assert.assertEquals(0.0,
-                            new Vector3D(-1, -1, 
1).normalize().distance(((S2Point) threeOctants.getBarycenter()).getVector()),
-                            1.0e-10);
 
     }
 
@@ -267,6 +264,116 @@ public class SphericalPolygonsSetTest {
 
     }
 
+    @Test
+    public void testSeveralParts() {
+        double tol = 0.01;
+        double sinTol = FastMath.sin(tol);
+        List<SubHyperplane<Sphere2D>> boundary = new 
ArrayList<SubHyperplane<Sphere2D>>();
+
+        // first part: +X, +Y, +Z octant
+        boundary.add(create(Vector3D.PLUS_J,  Vector3D.PLUS_K,  
Vector3D.PLUS_I,  tol, 0.0, 0.5 * FastMath.PI));
+        boundary.add(create(Vector3D.PLUS_K,  Vector3D.PLUS_I,  
Vector3D.PLUS_J,  tol, 0.0, 0.5 * FastMath.PI));
+        boundary.add(create(Vector3D.PLUS_I,  Vector3D.PLUS_J,  
Vector3D.PLUS_K,  tol, 0.0, 0.5 * FastMath.PI));
+
+        // first part: -X, -Y, -Z octant
+        boundary.add(create(Vector3D.MINUS_J, Vector3D.MINUS_I, 
Vector3D.MINUS_K, tol, 0.0, 0.5 * FastMath.PI));
+        boundary.add(create(Vector3D.MINUS_I, Vector3D.MINUS_K, 
Vector3D.MINUS_J, tol, 0.0, 0.5 * FastMath.PI));
+        boundary.add(create(Vector3D.MINUS_K, Vector3D.MINUS_J, 
Vector3D.MINUS_I,  tol, 0.0, 0.5 * FastMath.PI));
+
+        SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
+
+        UnitSphereRandomVectorGenerator random =
+                new UnitSphereRandomVectorGenerator(3, new 
Well1024a(0xcc5ce49949e0d3ecl));
+        for (int i = 0; i < 1000; ++i) {
+            Vector3D v = new Vector3D(random.nextVector());
+            if ((v.getX() < -sinTol) && (v.getY() < -sinTol) && (v.getZ() < 
-sinTol)) {
+                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new 
S2Point(v)));
+            } else if ((v.getX() < sinTol) && (v.getY() < sinTol) && (v.getZ() 
< sinTol)) {
+                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new 
S2Point(v)));
+            } else if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() 
> sinTol)) {
+                Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new 
S2Point(v)));
+            } else if ((v.getX() > -sinTol) && (v.getY() > -sinTol) && 
(v.getZ() > -sinTol)) {
+                Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new 
S2Point(v)));
+            } else {
+                Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new 
S2Point(v)));
+            }
+        }
+
+        Assert.assertEquals(FastMath.PI, polygon.getSize(), 1.0e-10);
+        Assert.assertEquals(3 * FastMath.PI, polygon.getBoundarySize(), 
1.0e-10);
+
+        // there should be two separate boundary loops
+        Assert.assertEquals(2, polygon.getBoundaryLoops().size());
+
+    }
+
+    @Test
+    public void testPartWithHole() {
+        double tol = 0.01;
+        double alpha = 0.7;
+        S2Point center = new S2Point(new Vector3D(1, 1, 1));
+        SphericalPolygonsSet octant = new 
SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_K, alpha, 6, tol);
+        SphericalPolygonsSet hole   = new SphericalPolygonsSet(tol,
+                                                               new 
S2Point(FastMath.PI / 6, FastMath.PI / 3),
+                                                               new 
S2Point(FastMath.PI / 3, FastMath.PI / 3),
+                                                               new 
S2Point(FastMath.PI / 4, FastMath.PI / 6));
+        SphericalPolygonsSet octantWithHole =
+                (SphericalPolygonsSet) new 
RegionFactory<Sphere2D>().difference(octant, hole);
+
+        for (double phi = center.getPhi() - alpha + 0.1; phi < center.getPhi() 
+ alpha - 0.1; phi += 0.07) {
+            Location l = octantWithHole.checkPoint(new S2Point(FastMath.PI / 
4, phi));
+            if (phi < FastMath.PI / 6 || phi > FastMath.PI / 3) {
+                Assert.assertEquals(Location.INSIDE,  l);
+            } else {
+                Assert.assertEquals(Location.OUTSIDE, l);
+            }
+        }
+
+        // there should be two separate boundary loops
+        Assert.assertEquals(2, octantWithHole.getBoundaryLoops().size());
+
+        Assert.assertEquals(octant.getBoundarySize() + hole.getBoundarySize(), 
octantWithHole.getBoundarySize(), 1.0e-10);
+        Assert.assertEquals(octant.getSize() - hole.getSize(), 
octantWithHole.getSize(), 1.0e-10);
+
+    }
+
+    @Test
+    public void testConcentricSubParts() {
+        double tol = 0.001;
+        Vector3D center = new Vector3D(1, 1, 1);
+        SphericalPolygonsSet hexaOut   = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.9,  6, tol);
+        SphericalPolygonsSet hexaIn    = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.8,  6, tol);
+        SphericalPolygonsSet pentaOut  = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.7,  5, tol);
+        SphericalPolygonsSet pentaIn   = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.6,  5, tol);
+        SphericalPolygonsSet quadriOut = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.5,  4, tol);
+        SphericalPolygonsSet quadriIn  = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.4,  4, tol);
+        SphericalPolygonsSet triOut    = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.25, 3, tol);
+        SphericalPolygonsSet triIn     = new SphericalPolygonsSet(center, 
Vector3D.PLUS_K, 0.15, 3, tol);
+
+        RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
+        SphericalPolygonsSet hexa   = (SphericalPolygonsSet) 
factory.difference(hexaOut,   hexaIn);
+        SphericalPolygonsSet penta  = (SphericalPolygonsSet) 
factory.difference(pentaOut,  pentaIn);
+        SphericalPolygonsSet quadri = (SphericalPolygonsSet) 
factory.difference(quadriOut, quadriIn);
+        SphericalPolygonsSet tri    = (SphericalPolygonsSet) 
factory.difference(triOut,    triIn);
+        SphericalPolygonsSet concentric =
+                (SphericalPolygonsSet) factory.union(factory.union(hexa, 
penta), factory.union(quadri, tri));
+
+        // there should be two separate boundary loops
+        Assert.assertEquals(8, concentric.getBoundaryLoops().size());
+
+        Assert.assertEquals(hexaOut.getBoundarySize()   + 
hexaIn.getBoundarySize()   +
+                            pentaOut.getBoundarySize()  + 
pentaIn.getBoundarySize()  +
+                            quadriOut.getBoundarySize() + 
quadriIn.getBoundarySize() +
+                            triOut.getBoundarySize()    + 
triIn.getBoundarySize(),
+                            concentric.getBoundarySize(), 1.0e-10);
+        Assert.assertEquals(hexaOut.getSize()   - hexaIn.getSize()   +
+                            pentaOut.getSize()  - pentaIn.getSize()  +
+                            quadriOut.getSize() - quadriIn.getSize() +
+                            triOut.getSize()    - triIn.getSize(),
+                            concentric.getSize(), 1.0e-10);
+
+    }
+
     private SubCircle create(Vector3D pole, Vector3D x, Vector3D y,
                              double tolerance, double ... limits) {
         RegionFactory<Sphere1D> factory = new RegionFactory<Sphere1D>();
@@ -280,5 +387,93 @@ public class SphericalPolygonsSetTest {
         return new SubCircle(phased, set);
     }
 
+//    private static void displayCells(String name, SphericalPolygonsSet 
polygons, double maxStep, double grid) {
+//        TesselationDisplay td = new TesselationDisplay(name, maxStep, grid, 
polygons.getTolerance());
+//        polygons.getTree(false).visit(td);
+//        td.close();
+//    }
+//
+//    private static class TesselationDisplay implements 
BSPTreeVisitor<Sphere2D> {
+//        private double maxStep;
+//        private double grid;
+//        private double tolerance;
+//        private PrintStream out;
+//        public TesselationDisplay(String name, double maxStep, double grid, 
double tolerance) {
+//            try {
+//            this.out = new PrintStream(new File(new 
File(System.getProperty("user.home")), name));
+//            this.maxStep   = maxStep;
+//            this.grid      = grid;
+//            this.tolerance = tolerance;
+//            } catch (IOException ioe) {
+//                Assert.fail(ioe.getMessage());
+//            }
+//        }
+//        public Order visitOrder(BSPTree<Sphere2D> node) {
+//            return Order.MINUS_PLUS_SUB;
+//        }
+//        public void visitInternalNode(BSPTree<Sphere2D> node) {
+//        }
+//        public void visitLeafNode(BSPTree<Sphere2D> node) {
+//            if ((Boolean) node.getAttribute()) {
+//                final SphericalPolygonsSet cell =
+//                        new 
SphericalPolygonsSet(node.pruneAroundConvexCell(true, false, null), tolerance);
+//                display(out, cell, maxStep, grid);
+//            }
+//        }
+//        public void close() {
+//            out.close();
+//        }
+//    }
+//
+//    private static void display(String name, SphericalPolygonsSet polygons, 
double maxStep, double grid) {
+//        PrintStream out = null;
+//        try {
+//            out = new PrintStream(new File(new 
File(System.getProperty("user.home")), name));
+//            display(out, polygons, maxStep, grid);
+//        } catch (IOException ioe) {
+//            Assert.fail(ioe.getMessage());
+//        } finally {
+//            if (out != null) {
+//                out.close();
+//            }
+//        }
+//    }
+//
+//    private static void display(PrintStream out, SphericalPolygonsSet 
polygons, double maxStep, double grid) {
+//            for (final SphericalPolygonsSet.Vertex start : 
polygons.getBoundaryLoops()) {
+//                int n = 0;
+//                for (SphericalPolygonsSet.Edge edge = start.getOutgoing();
+//                     n == 0 || edge.getStart() != start;
+//                     edge = edge.getEnd().getOutgoing()) {
+//                    int m = (int) FastMath.ceil(edge.getLength() / maxStep);
+//                    double step = edge.getLength() / m;
+//                    for (int i = 0; i <= m; ++i) {
+//                       final Vector3D p = edge.getPointAt(i * step);
+//                       out.format(Locale.US, "%9.6f %9.6f %9.6f%n", 
p.getX(), p.getY(), p.getZ());
+//                    }
+//                    n++;
+//                }
+//                out.println("&");
+//            }
+//            if (grid > 0) {
+//                for (double phi = grid; phi < FastMath.PI - grid; phi += 
grid) {
+//                    Location previous = Location.OUTSIDE;
+//                    for (double theta = 0; theta < MathUtils.TWO_PI; theta 
+= grid) {
+//                        S2Point point = new S2Point(theta, phi);
+//                        Location current = polygons.checkPoint(point);
+//                        if (current == Location.OUTSIDE) {
+//                            if (previous != Location.OUTSIDE) {
+//                                out.println("&");
+//                            }
+//                        } else {
+//                            out.format(Locale.US, "%9.6f %9.6f %9.6f%n",
+//                                       point.getVector().getX(), 
point.getVector().getY(), point.getVector().getZ());
+//                        }
+//                        previous = current;
+//                    }
+//                    out.println("&");
+//                }
+//            }
+//    }
 
 }


Reply via email to