SphericalPolygonsSet extends AbstractRegion<Sphere2D, Sphere1D> { public List<Vertex> getBoundaryLoops() throws MathIllegalStateException { if (loops == null) { if (getTree(false).getCut() == null) { loops = Collections.emptyList(); } else { final BSPTree<Sphere2D> root = getTree(true); final EdgesBuilder visitor = new EdgesBuilder(root, getTolerance()); root.visit(visitor); final List<Edge> edges = visitor.getEdges(); loops = new ArrayList<Vertex>(); while (!edges.isEmpty()) { Edge edge = edges.get(0); final Vertex startVertex = edge.getStart(); loops.add(startVertex); do { for (final Iterator<Edge> iterator = edges.iterator(); iterator.hasNext();) { if (iterator.next() == edge) { iterator.remove(); break; } } edge = edge.getEnd().getOutgoing(); } while (edge.getStart() != startVertex); } } } return Collections.unmodifiableList(loops); } SphericalPolygonsSet(final double tolerance);  SphericalPolygonsSet(final Vector3D pole, final double tolerance);  SphericalPolygonsSet(final Vector3D center, final Vector3D meridian,
                                final double outsideRadius, final int n,
                                final double tolerance);  SphericalPolygonsSet(final BSPTree<Sphere2D> tree, final double tolerance);  SphericalPolygonsSet(final Collection<SubHyperplane<Sphere2D>> boundary, final double tolerance);  SphericalPolygonsSet(final double hyperplaneThickness, final S2Point ... vertices); @Override SphericalPolygonsSet buildNew(final BSPTree<Sphere2D> tree); List<Vertex> getBoundaryLoops(); EnclosingBall<Sphere2D, S2Point> getEnclosingCap();  }
@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<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; Vertex first = loops.get(0); int count = 0; for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) { ++count; 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); }
@Test public void testModeratlyComplexShape() { double tol = 0.01; List<SubHyperplane<Sphere2D>> boundary = new ArrayList<SubHyperplane<Sphere2D>>(); boundary.add(create(Vector3D.MINUS_J, Vector3D.PLUS_I, Vector3D.PLUS_K, tol, 0.0, 0.5 * FastMath.PI)); boundary.add(create(Vector3D.MINUS_I, Vector3D.PLUS_K, Vector3D.PLUS_J, tol, 0.0, 0.5 * FastMath.PI)); boundary.add(create(Vector3D.PLUS_K, Vector3D.PLUS_J, Vector3D.MINUS_I, tol, 0.0, 0.5 * FastMath.PI)); 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.PLUS_K, Vector3D.MINUS_J, Vector3D.PLUS_I, tol, 0.0, 0.5 * FastMath.PI)); SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol); Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, 1, 1).normalize()))); Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, 1, 1).normalize()))); Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, -1, 1).normalize()))); Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, -1, 1).normalize()))); Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, 1, -1).normalize()))); Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, 1, -1).normalize()))); Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, -1, -1).normalize()))); Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, -1, -1).normalize()))); Assert.assertEquals(MathUtils.TWO_PI, polygon.getSize(), 1.0e-10); Assert.assertEquals(3 * FastMath.PI, polygon.getBoundarySize(), 1.0e-10); List<Vertex> loops = polygon.getBoundaryLoops(); Assert.assertEquals(1, loops.size()); boolean pXFound = false; boolean mXFound = false; boolean pYFound = false; boolean mYFound = false; boolean pZFound = false; boolean mZFound = false; Vertex first = loops.get(0); int count = 0; for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) { ++count; Edge e = v.getIncoming(); Assert.assertTrue(v == e.getStart().getOutgoing().getEnd()); pXFound = pXFound || v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10; mXFound = mXFound || v.getLocation().getVector().distance(Vector3D.MINUS_I) < 1.0e-10; pYFound = pYFound || v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10; mYFound = mYFound || v.getLocation().getVector().distance(Vector3D.MINUS_J) < 1.0e-10; pZFound = pZFound || v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10; mZFound = mZFound || v.getLocation().getVector().distance(Vector3D.MINUS_K) < 1.0e-10; Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10); } Assert.assertTrue(pXFound); Assert.assertTrue(mXFound); Assert.assertTrue(pYFound); Assert.assertTrue(mYFound); Assert.assertTrue(pZFound); Assert.assertTrue(mZFound); Assert.assertEquals(6, count); }
@Test public void testSeveralParts() { double tol = 0.01; double sinTol = FastMath.sin(tol); List<SubHyperplane<Sphere2D>> boundary = new ArrayList<SubHyperplane<Sphere2D>>(); 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)); 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); 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 hexa = 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 hexaWithHole = (SphericalPolygonsSet) new RegionFactory<Sphere2D>().difference(hexa, hole); for (double phi = center.getPhi() - alpha + 0.1; phi < center.getPhi() + alpha - 0.1; phi += 0.07) { Location l = hexaWithHole.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); } } Assert.assertEquals(2, hexaWithHole.getBoundaryLoops().size()); Assert.assertEquals(hexa.getBoundarySize() + hole.getBoundarySize(), hexaWithHole.getBoundarySize(), 1.0e-10); Assert.assertEquals(hexa.getSize() - hole.getSize(), hexaWithHole.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)); 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); double phi = new S2Point(center).getPhi(); Assert.assertEquals(+0.207, concentric.projectToBoundary(new S2Point(-0.60, phi)).getOffset(), 0.01); Assert.assertEquals(-0.048, concentric.projectToBoundary(new S2Point(-0.21, phi)).getOffset(), 0.01); Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point(-0.10, phi)).getOffset(), 0.01); Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 0.01, phi)).getOffset(), 0.01); Assert.assertEquals(+0.049, concentric.projectToBoundary(new S2Point( 0.16, phi)).getOffset(), 0.01); Assert.assertEquals(-0.038, concentric.projectToBoundary(new S2Point( 0.29, phi)).getOffset(), 0.01); Assert.assertEquals(+0.097, concentric.projectToBoundary(new S2Point( 0.48, phi)).getOffset(), 0.01); Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.64, phi)).getOffset(), 0.01); Assert.assertEquals(+0.072, concentric.projectToBoundary(new S2Point( 0.79, phi)).getOffset(), 0.01); Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.93, phi)).getOffset(), 0.01); Assert.assertEquals(+0.091, concentric.projectToBoundary(new S2Point( 1.08, phi)).getOffset(), 0.01); Assert.assertEquals(-0.037, concentric.projectToBoundary(new S2Point( 1.28, phi)).getOffset(), 0.01); Assert.assertEquals(+0.051, concentric.projectToBoundary(new S2Point( 1.40, phi)).getOffset(), 0.01); Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 1.55, phi)).getOffset(), 0.01); Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point( 1.67, phi)).getOffset(), 0.01); Assert.assertEquals(-0.044, concentric.projectToBoundary(new S2Point( 1.79, phi)).getOffset(), 0.01); Assert.assertEquals(+0.201, concentric.projectToBoundary(new S2Point( 2.16, phi)).getOffset(), 0.01); }