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/06 16:45:44 UTC

svn commit: r1555871 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSet.java test/java/org/apache/commons/math3/geometry/spherical/twod/SphericalPolygonsSetTest.java

Author: luc
Date: Mon Jan  6 15:45:43 2014
New Revision: 1555871

URL: http://svn.apache.org/r1555871
Log:
Fixed errors in spherical polygons build from vertices.

Modified:
    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/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=1555871&r1=1555870&r2=1555871&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 Mon Jan  6 15:45:43 2014
@@ -211,7 +211,7 @@ public class SphericalPolygonsSet extend
     }
 
     /** Recursively build a tree by inserting cut sub-hyperplanes.
-     * @param hyperplaneThickness tolerance below which points are consider to
+     * @param hyperplaneThickness tolerance below which points are considered to
      * belong to the hyperplane (which is therefore more a slab)
      * @param node current tree node (it is a leaf node at the beginning
      * of the call)
@@ -264,12 +264,12 @@ public class SphericalPolygonsSet extend
         if (!outsideList.isEmpty()) {
             insertEdges(hyperplaneThickness, node.getPlus(), outsideList);
         } else {
-            node.getMinus().setAttribute(Boolean.FALSE);
+            node.getPlus().setAttribute(Boolean.FALSE);
         }
         if (!insideList.isEmpty()) {
             insertEdges(hyperplaneThickness, node.getMinus(),  insideList);
         } else {
-            node.getPlus().setAttribute(Boolean.TRUE);
+            node.getMinus().setAttribute(Boolean.TRUE);
         }
 
     }
@@ -494,7 +494,7 @@ public class SphericalPolygonsSet extend
         private void split(final Circle splitCircle,
                            final List<Edge> outsideList, final List<Edge> insideList) {
 
-            // get the inside chord, synchronizing its phase with the edge itself
+            // get the inside arc, synchronizing its phase with the edge itself
             final double edgeStart        = circle.getPhase(start.getLocation().getVector());
             final double arcRelativeStart = MathUtils.normalizeAngle(circle.getInsideArc(splitCircle).getInf(),
                                                                      edgeStart + FastMath.PI) - edgeStart;
@@ -502,80 +502,93 @@ public class SphericalPolygonsSet extend
             final double unwrappedEnd     = arcRelativeStart - FastMath.PI;
 
             // build the sub-edges
-            if (arcRelativeStart < length) {
-                if (unwrappedEnd > 0) {
-                    // the edge starts inside the circle, then goes outside, then comes back inside
-
-                    // create intermediate vertices
-                    final Vertex vExit    = new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeEnd)));
-                    final Vertex vEnter   = new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart)));
-                    vExit.bindWith(splitCircle);
-                    vEnter.bindWith(splitCircle);
-
-                    // create sub-edges
-                    final Edge eStartIn   = new Edge(start,  vExit,  unwrappedEnd,                      circle);
-                    final Edge eMiddleOut = new Edge(vExit,  vEnter, arcRelativeStart - unwrappedEnd, circle);
-                    final Edge eEndIn     = new Edge(vEnter, end,    length - arcRelativeStart,       circle);
-                    eStartIn.setNode(node);
-                    eMiddleOut.setNode(node);
-                    eEndIn.setNode(node);
-
-                    // distribute the sub-edges in the appropriate lists
-                    insideList.add(eStartIn);
-                    insideList.add(eEndIn);
-                    outsideList.add(eMiddleOut);
+            final double tolerance = circle.getTolerance();
+            Vertex previousVertex = start;
+            if (unwrappedEnd >= length - tolerance) {
+
+                // the edge is entirely contained inside the circle
+                // we don't split anything
+                insideList.add(this);
 
-                } else {
-                    // the edge starts outside of the circle, then comes inside
-
-                    // create intermediate vertices
-                    final Vertex vEnter   = new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart)));
-                    vEnter.bindWith(splitCircle);
-
-                    // create sub-edges
-                    final Edge eStartOut  = new Edge(start,  vEnter, arcRelativeStart,          circle);
-                    final Edge eEndIn     = new Edge(vEnter, end,    length - arcRelativeStart, circle);
-                    eStartOut.setNode(node);
-                    eEndIn.setNode(node);
-
-                    // distribute the sub-edges in the appropriate lists
-                    outsideList.add(eStartOut);
-                    insideList.add(eEndIn);
-
-                }
             } else {
-                if (unwrappedEnd > 0) {
-                    if (unwrappedEnd > length) {
-                        // the edge is entirely contained inside the circle
-                        // we don't split anything
-                        insideList.add(this);
-                    } else {
-                        // the edge starts inside the circle, then goes outside
 
-                        // create intermediate vertices
-                        final Vertex vExit    = new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeEnd)));
-                        vExit.bindWith(splitCircle);
-
-                        // create sub-edges
-                        final Edge eStartIn   = new Edge(start, vExit, arcRelativeEnd,          circle);
-                        final Edge eEndOut    = new Edge(vExit, end,   length - arcRelativeEnd, circle);
-                        eStartIn.setNode(node);
-                        eEndOut.setNode(node);
-
-                        // distribute the sub-edges in the appropriate lists
-                        insideList.add(eStartIn);
-                        outsideList.add(eEndOut);
+                // there are at least some parts of the edge that should be outside
+                // (even is they are later be filtered out as being too small)
+                double alreadyManagedLength = 0;
+                if (unwrappedEnd >= 0) {
+                    // the start of the edge is inside the circle
+                    previousVertex = addSubEdge(previousVertex,
+                                                new Vertex(new S2Point(circle.getPointAt(edgeStart + unwrappedEnd))),
+                                                unwrappedEnd, insideList, splitCircle);
+                    alreadyManagedLength = unwrappedEnd;
+                }
 
+                if (arcRelativeStart >= length - tolerance) {
+                    // the edge ends while still outside of the circle
+                    if (unwrappedEnd >= 0) {
+                        previousVertex = addSubEdge(previousVertex, end,
+                                                    length - alreadyManagedLength, outsideList, splitCircle);
+                    } else {
+                        // the edge is entirely outside of the circle
+                        // we don't split anything
+                        outsideList.add(this);
                     }
                 } else {
-                    // the edge is entirely outside of the circle
-                    // we don't split anything
-                    outsideList.add(this);
+                    // the edge is long enough to enter inside the circle
+                    previousVertex = addSubEdge(previousVertex,
+                                                new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
+                                                arcRelativeStart - alreadyManagedLength, outsideList, splitCircle);
+                    alreadyManagedLength = arcRelativeStart;
+
+                    if (arcRelativeEnd >= length - tolerance) {
+                        // the edge ends while still inside of the circle
+                        previousVertex = addSubEdge(previousVertex, end,
+                                                    length - alreadyManagedLength, insideList, splitCircle);
+                    } else {
+                        // the edge is long enough to exit outside of the circle
+                        previousVertex = addSubEdge(previousVertex,
+                                                    new Vertex(new S2Point(circle.getPointAt(edgeStart + arcRelativeStart))),
+                                                    arcRelativeStart - alreadyManagedLength, insideList, splitCircle);
+                        alreadyManagedLength = arcRelativeStart;
+                        previousVertex = addSubEdge(previousVertex, end,
+                                                    length - alreadyManagedLength, outsideList, splitCircle);
+                    }
                 }
+
             }
 
         }
 
+        /** Add a sub-edge to a list if long enough.
+         * <p>
+         * If the length of the sub-edge to add is smaller than the {@link Circle#getTolerance()}
+         * tolerance of the support circle, it will be ignored.
+         * </p>
+         * @param subStart start of the sub-edge
+         * @param subEnd end of the sub-edge
+         * @param subLength length of the sub-edge
+         * @param splitCircle circle splitting the edge in several parts
+         * @param list list where to put the sub-edge
+         * @return end vertex of the edge ({@code subEnd} if the edge was long enough and really
+         * added, {@code subStart} if the edge was too small and therefore ignored)
+         */
+        private Vertex addSubEdge(final Vertex subStart, final Vertex subEnd, final double subLength,
+                                  final List<Edge> list, final Circle splitCircle) {
+
+            if (subLength <= circle.getTolerance()) {
+                // the edge is too short, we ignore it
+                return subStart;
+            }
+
+            // really add the edge
+            subEnd.bindWith(splitCircle);
+            final Edge edge = new Edge(subStart, subEnd, subLength, circle);
+            edge.setNode(node);
+            list.add(edge);
+            return subEnd;
+
+        }
+
     }
 
     /** {@inheritDoc} */

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=1555871&r1=1555870&r2=1555871&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 Mon Jan  6 15:45:43 2014
@@ -18,6 +18,7 @@ package org.apache.commons.math3.geometr
 
 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
 import org.apache.commons.math3.geometry.partitioning.Region.Location;
+import org.apache.commons.math3.geometry.partitioning.RegionFactory;
 import org.apache.commons.math3.random.UnitSphereRandomVectorGenerator;
 import org.apache.commons.math3.random.Well1024a;
 import org.apache.commons.math3.util.FastMath;
@@ -35,6 +36,8 @@ public class SphericalPolygonsSetTest {
             Vector3D v = new Vector3D(random.nextVector());
             Assert.assertEquals(Location.INSIDE, full.checkPoint(new S2Point(v)));
         }
+        Assert.assertEquals(4 * FastMath.PI, new SphericalPolygonsSet(0.01, new S2Point[0]).getSize(), 1.0e-10);
+        Assert.assertEquals(0, new SphericalPolygonsSet(0.01, new S2Point[0]).getBoundarySize(), 1.0e-10);
     }
 
     @Test
@@ -43,7 +46,7 @@ public class SphericalPolygonsSetTest {
         double sinTol = FastMath.sin(tol);
         SphericalPolygonsSet south = new SphericalPolygonsSet(Vector3D.MINUS_K, tol);
         UnitSphereRandomVectorGenerator random =
-                new UnitSphereRandomVectorGenerator(3, new Well1024a(0x852fd2a0ed8d2f6dl));
+                new UnitSphereRandomVectorGenerator(3, new Well1024a(0x6b9d4a6ad90d7b0bl));
         for (int i = 0; i < 1000; ++i) {
             Vector3D v = new Vector3D(random.nextVector());
             if (v.getZ() < -sinTol) {
@@ -51,8 +54,50 @@ public class SphericalPolygonsSetTest {
             } else if (v.getZ() > sinTol) {
                 Assert.assertEquals(Location.OUTSIDE, south.checkPoint(new S2Point(v)));
             } else {
-                Assert.assertEquals("" + v.getX() + " " + v.getY() + " " + v.getZ(),
-                                    Location.BOUNDARY, south.checkPoint(new S2Point(v)));
+                Assert.assertEquals(Location.BOUNDARY, south.checkPoint(new S2Point(v)));
+            }
+        }
+    }
+
+    @Test
+    public void testPositiveOctantByIntersection() {
+        double tol = 0.01;
+        double sinTol = FastMath.sin(tol);
+        RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
+        SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_I, tol);
+        SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_J, tol);
+        SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_K, tol);
+        SphericalPolygonsSet octant =
+                (SphericalPolygonsSet) factory.intersection(factory.intersection(plusX, plusY), plusZ);
+        UnitSphereRandomVectorGenerator random =
+                new UnitSphereRandomVectorGenerator(3, new Well1024a(0x9c9802fde3cbcf25l));
+        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, octant.checkPoint(new S2Point(v)));
+            } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
+                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
+            } else {
+                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
+            }
+        }
+    }
+
+    @Test
+    public void testPositiveOctantByVertices() {
+        double tol = 0.01;
+        double sinTol = FastMath.sin(tol);
+        SphericalPolygonsSet octant = new SphericalPolygonsSet(tol, S2Point.PLUS_I, S2Point.PLUS_J, S2Point.PLUS_K);
+        UnitSphereRandomVectorGenerator random =
+                new UnitSphereRandomVectorGenerator(3, new Well1024a(0xb8fc5acc91044308l));
+        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, octant.checkPoint(new S2Point(v)));
+            } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
+                Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
+            } else {
+                Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
             }
         }
     }