Author: luc
Date: Sun Jan 12 14:56:04 2014
New Revision: 1557543

URL: http://svn.apache.org/r1557543
Log:
Fixed area computation on non-convex spherical polygons.

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=1557543&r1=1557542&r2=1557543&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
 Sun Jan 12 14:56:04 2014
@@ -632,8 +632,17 @@ public class SphericalPolygonsSet extend
                      edge = edge.getEnd().getOutgoing()) {
                     final Vector3D middle = edge.getPointAt(0.5 * 
edge.getLength());
                     sumP = new Vector3D(1, sumP, edge.getLength(), middle);
-                    sum += Vector3D.angle(edge.getCircle().getPole(),
-                                          
edge.getEnd().getOutgoing().getCircle().getPole());
+
+                    // 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++;
                 }
 

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=1557543&r1=1557542&r2=1557543&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
 Sun Jan 12 14:56:04 2014
@@ -21,7 +21,6 @@ import java.util.List;
 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.geometry.spherical.twod.SphericalPolygonsSet.Vertex;
 import org.apache.commons.math3.random.UnitSphereRandomVectorGenerator;
 import org.apache.commons.math3.random.Well1024a;
 import org.apache.commons.math3.util.FastMath;
@@ -87,25 +86,32 @@ public class SphericalPolygonsSetTest {
 
         List<SphericalPolygonsSet.Vertex> loops = octant.getBoundaryLoops();
         Assert.assertEquals(1, loops.size());
-        boolean xFound = false;
-        boolean yFound = false;
-        boolean zFound = false;
-        Vertex first = loops.get(0);
-        xFound = first.getLocation().getVector().distance(Vector3D.PLUS_I) < 
1.0e-10;
-        yFound = first.getLocation().getVector().distance(Vector3D.PLUS_J) < 
1.0e-10;
-        zFound = first.getLocation().getVector().distance(Vector3D.PLUS_K) < 
1.0e-10;
-        int count = 1;
-        for (Vertex v = first.getOutgoing().getEnd(); v != first; v = 
v.getOutgoing().getEnd()) {
+        boolean xPFound = false;
+        boolean yPFound = false;
+        boolean zPFound = false;
+        boolean xVFound = false;
+        boolean yVFound = false;
+        boolean zVFound = false;
+        SphericalPolygonsSet.Vertex first = loops.get(0);
+        int count = 0;
+        for (SphericalPolygonsSet.Vertex v = first; count == 0 || v != first; 
v = v.getOutgoing().getEnd()) {
             ++count;
-            Assert.assertTrue(v == 
v.getIncoming().getStart().getOutgoing().getEnd());
-            Assert.assertEquals(0.5 * FastMath.PI, 
v.getIncoming().getLength(), 1.0e-10);
-            xFound = xFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10;
-            yFound = yFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10;
-            zFound = zFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10;
-        }
-        Assert.assertTrue(xFound);
-        Assert.assertTrue(yFound);
-        Assert.assertTrue(zFound);
+            SphericalPolygonsSet.Edge e = v.getIncoming();
+            Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
+            xPFound = xPFound || 
e.getCircle().getPole().distance(Vector3D.PLUS_I) < 1.0e-10;
+            yPFound = yPFound || 
e.getCircle().getPole().distance(Vector3D.PLUS_J) < 1.0e-10;
+            zPFound = zPFound || 
e.getCircle().getPole().distance(Vector3D.PLUS_K) < 1.0e-10;
+            Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10);
+            xVFound = xVFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10;
+            yVFound = yVFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10;
+            zVFound = zVFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10;
+        }
+        Assert.assertTrue(xPFound);
+        Assert.assertTrue(yPFound);
+        Assert.assertTrue(zPFound);
+        Assert.assertTrue(xVFound);
+        Assert.assertTrue(yVFound);
+        Assert.assertTrue(zVFound);
         Assert.assertEquals(3, count);
 
         Assert.assertEquals(0.0,
@@ -134,4 +140,69 @@ public class SphericalPolygonsSetTest {
         }
     }
 
+    @Test
+    public void testNonConvex() {
+        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 threeOctants =
+                (SphericalPolygonsSet) factory.difference(plusZ, 
factory.intersection(plusX, plusY));
+
+        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, 
threeOctants.checkPoint(new S2Point(v)));
+            } else if (((v.getX() > sinTol) && (v.getY() > sinTol)) || 
(v.getZ() < -sinTol)) {
+                Assert.assertEquals(Location.OUTSIDE, 
threeOctants.checkPoint(new S2Point(v)));
+            } else {
+                Assert.assertEquals(Location.BOUNDARY, 
threeOctants.checkPoint(new S2Point(v)));
+            }
+        }
+
+        List<SphericalPolygonsSet.Vertex> loops = 
threeOctants.getBoundaryLoops();
+        Assert.assertEquals(1, loops.size());
+        boolean xPFound = false;
+        boolean yPFound = false;
+        boolean zPFound = false;
+        boolean xVFound = false;
+        boolean yVFound = false;
+        boolean zVFound = false;
+        SphericalPolygonsSet.Vertex first = loops.get(0);
+        int count = 0;
+        for (SphericalPolygonsSet.Vertex v = first; count == 0 || v != first; 
v = v.getOutgoing().getEnd()) {
+            ++count;
+            SphericalPolygonsSet.Edge e = v.getIncoming();
+            Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
+            xPFound = xPFound || 
e.getCircle().getPole().distance(Vector3D.MINUS_I) < 1.0e-10;
+            yPFound = yPFound || 
e.getCircle().getPole().distance(Vector3D.MINUS_J) < 1.0e-10;
+            zPFound = zPFound || 
e.getCircle().getPole().distance(Vector3D.PLUS_K)  < 1.0e-10;
+            if (Vector3D.PLUS_K.distance(e.getCircle().getPole()) < 1.0e-10) {
+                Assert.assertEquals(1.5 * FastMath.PI, e.getLength(), 1.0e-10);
+            } else {
+                Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10);
+            }
+            xVFound = xVFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10;
+            yVFound = yVFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10;
+            zVFound = zVFound || 
v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10;
+        }
+        Assert.assertTrue(xPFound);
+        Assert.assertTrue(yPFound);
+        Assert.assertTrue(zPFound);
+        Assert.assertTrue(xVFound);
+        Assert.assertTrue(yVFound);
+        Assert.assertTrue(zVFound);
+        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);
+
+    }
+
 }


Reply via email to