1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.geometry.spherical.twod;
23
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.function.IntPredicate;
29
30 import org.hipparchus.exception.LocalizedCoreFormats;
31 import org.hipparchus.exception.MathIllegalArgumentException;
32 import org.hipparchus.exception.MathIllegalStateException;
33 import org.hipparchus.exception.MathRuntimeException;
34 import org.hipparchus.geometry.LocalizedGeometryFormats;
35 import org.hipparchus.geometry.enclosing.EnclosingBall;
36 import org.hipparchus.geometry.euclidean.threed.Rotation;
37 import org.hipparchus.geometry.euclidean.threed.Vector3D;
38 import org.hipparchus.geometry.partitioning.Region;
39 import org.hipparchus.geometry.partitioning.Region.Location;
40 import org.hipparchus.geometry.partitioning.RegionFactory;
41 import org.hipparchus.geometry.partitioning.SubHyperplane;
42 import org.hipparchus.geometry.spherical.oned.ArcsSet;
43 import org.hipparchus.geometry.spherical.oned.Sphere1D;
44 import org.hipparchus.random.UnitSphereRandomVectorGenerator;
45 import org.hipparchus.random.Well1024a;
46 import org.hipparchus.util.FastMath;
47 import org.hipparchus.util.MathUtils;
48 import org.junit.Assert;
49 import org.junit.Test;
50
51 public class SphericalPolygonsSetTest {
52
53 @Test
54 public void testFullSphere() {
55 SphericalPolygonsSet full = new SphericalPolygonsSet(1.0e-10);
56 UnitSphereRandomVectorGenerator random =
57 new UnitSphereRandomVectorGenerator(3, new Well1024a(0x852fd2a0ed8d2f6dl));
58 for (int i = 0; i < 1000; ++i) {
59 Vector3D v = new Vector3D(random.nextVector());
60 Assert.assertEquals(Location.INSIDE, full.checkPoint(new S2Point(v)));
61 }
62 Assert.assertEquals(4 * FastMath.PI, new SphericalPolygonsSet(0.01, new S2Point[0]).getSize(), 1.0e-10);
63 Assert.assertEquals(0, new SphericalPolygonsSet(0.01, new S2Point[0]).getBoundarySize(), 1.0e-10);
64 Assert.assertEquals(0, full.getBoundaryLoops().size());
65 Assert.assertTrue(full.getEnclosingCap().getRadius() > 0);
66 Assert.assertTrue(Double.isInfinite(full.getEnclosingCap().getRadius()));
67 }
68
69 @Test
70 public void testEmpty() {
71 SphericalPolygonsSet empty =
72 (SphericalPolygonsSet) new RegionFactory<Sphere2D>().getComplement(new SphericalPolygonsSet(1.0e-10));
73 UnitSphereRandomVectorGenerator random =
74 new UnitSphereRandomVectorGenerator(3, new Well1024a(0x76d9205d6167b6ddl));
75 for (int i = 0; i < 1000; ++i) {
76 Vector3D v = new Vector3D(random.nextVector());
77 Assert.assertEquals(Location.OUTSIDE, empty.checkPoint(new S2Point(v)));
78 }
79 Assert.assertEquals(0, empty.getSize(), 1.0e-10);
80 Assert.assertEquals(0, empty.getBoundarySize(), 1.0e-10);
81 Assert.assertEquals(0, empty.getBoundaryLoops().size());
82 Assert.assertTrue(empty.getEnclosingCap().getRadius() < 0);
83 Assert.assertTrue(Double.isInfinite(empty.getEnclosingCap().getRadius()));
84 }
85
86 @Test
87 public void testSouthHemisphere() {
88 double tol = 0.01;
89 double sinTol = FastMath.sin(tol);
90 SphericalPolygonsSet south = new SphericalPolygonsSet(Vector3D.MINUS_K, tol);
91 UnitSphereRandomVectorGenerator random =
92 new UnitSphereRandomVectorGenerator(3, new Well1024a(0x6b9d4a6ad90d7b0bl));
93 for (int i = 0; i < 1000; ++i) {
94 Vector3D v = new Vector3D(random.nextVector());
95 if (v.getZ() < -sinTol) {
96 Assert.assertEquals(Location.INSIDE, south.checkPoint(new S2Point(v)));
97 } else if (v.getZ() > sinTol) {
98 Assert.assertEquals(Location.OUTSIDE, south.checkPoint(new S2Point(v)));
99 } else {
100 Assert.assertEquals(Location.BOUNDARY, south.checkPoint(new S2Point(v)));
101 }
102 }
103 Assert.assertEquals(1, south.getBoundaryLoops().size());
104
105 EnclosingBall<Sphere2D, S2Point> southCap = south.getEnclosingCap();
106 Assert.assertEquals(0.0, S2Point.MINUS_K.distance(southCap.getCenter()), 1.0e-10);
107 Assert.assertEquals(0.5 * FastMath.PI, southCap.getRadius(), 1.0e-10);
108
109 EnclosingBall<Sphere2D, S2Point> northCap =
110 ((SphericalPolygonsSet) new RegionFactory<Sphere2D>().getComplement(south)).getEnclosingCap();
111 Assert.assertEquals(0.0, S2Point.PLUS_K.distance(northCap.getCenter()), 1.0e-10);
112 Assert.assertEquals(0.5 * FastMath.PI, northCap.getRadius(), 1.0e-10);
113
114 }
115
116 @Test
117 public void testPositiveOctantByIntersection() {
118 double tol = 0.01;
119 double sinTol = FastMath.sin(tol);
120 RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
121 SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_I, tol);
122 SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_J, tol);
123 SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_K, tol);
124 SphericalPolygonsSet octant =
125 (SphericalPolygonsSet) factory.intersection(factory.intersection(plusX, plusY), plusZ);
126 UnitSphereRandomVectorGenerator random =
127 new UnitSphereRandomVectorGenerator(3, new Well1024a(0x9c9802fde3cbcf25l));
128 for (int i = 0; i < 1000; ++i) {
129 Vector3D v = new Vector3D(random.nextVector());
130 if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
131 Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v)));
132 } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
133 Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
134 } else {
135 Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
136 }
137 }
138
139 List<Vertex> loops = octant.getBoundaryLoops();
140 Assert.assertEquals(1, loops.size());
141 boolean xPFound = false;
142 boolean yPFound = false;
143 boolean zPFound = false;
144 boolean xVFound = false;
145 boolean yVFound = false;
146 boolean zVFound = false;
147 Vertex first = loops.get(0);
148 int count = 0;
149 for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) {
150 ++count;
151 Edge e = v.getIncoming();
152 Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
153 xPFound = xPFound || e.getCircle().getPole().distance(Vector3D.PLUS_I) < 1.0e-10;
154 yPFound = yPFound || e.getCircle().getPole().distance(Vector3D.PLUS_J) < 1.0e-10;
155 zPFound = zPFound || e.getCircle().getPole().distance(Vector3D.PLUS_K) < 1.0e-10;
156 Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10);
157 xVFound = xVFound || v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10;
158 yVFound = yVFound || v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10;
159 zVFound = zVFound || v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10;
160 }
161 Assert.assertTrue(xPFound);
162 Assert.assertTrue(yPFound);
163 Assert.assertTrue(zPFound);
164 Assert.assertTrue(xVFound);
165 Assert.assertTrue(yVFound);
166 Assert.assertTrue(zVFound);
167 Assert.assertEquals(3, count);
168
169 Assert.assertEquals(0.0,
170 ((S2Point) octant.getBarycenter()).distance(new S2Point(new Vector3D(1, 1, 1))),
171 1.0e-10);
172 Assert.assertEquals(0.5 * FastMath.PI, octant.getSize(), 1.0e-10);
173
174 EnclosingBall<Sphere2D, S2Point> cap = octant.getEnclosingCap();
175 Assert.assertEquals(0.0, octant.getBarycenter().distance(cap.getCenter()), 1.0e-10);
176 Assert.assertEquals(FastMath.acos(1.0 / FastMath.sqrt(3)), cap.getRadius(), 1.0e-10);
177
178 EnclosingBall<Sphere2D, S2Point> reversedCap =
179 ((SphericalPolygonsSet) factory.getComplement(octant)).getEnclosingCap();
180 Assert.assertEquals(0, reversedCap.getCenter().distance(new S2Point(new Vector3D(-1, -1, -1))), 1.0e-10);
181 Assert.assertEquals(FastMath.PI - FastMath.asin(1.0 / FastMath.sqrt(3)), reversedCap.getRadius(), 1.0e-10);
182
183 }
184
185 @Test
186 public void testPositiveOctantByVertices() {
187 double tol = 0.01;
188 double sinTol = FastMath.sin(tol);
189 SphericalPolygonsSet octant = new SphericalPolygonsSet(tol, S2Point.PLUS_I, S2Point.PLUS_J, S2Point.PLUS_K);
190 UnitSphereRandomVectorGenerator random =
191 new UnitSphereRandomVectorGenerator(3, new Well1024a(0xb8fc5acc91044308l));
192 for (int i = 0; i < 1000; ++i) {
193 Vector3D v = new Vector3D(random.nextVector());
194 if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
195 Assert.assertEquals(Location.INSIDE, octant.checkPoint(new S2Point(v)));
196 } else if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
197 Assert.assertEquals(Location.OUTSIDE, octant.checkPoint(new S2Point(v)));
198 } else {
199 Assert.assertEquals(Location.BOUNDARY, octant.checkPoint(new S2Point(v)));
200 }
201 }
202 }
203
204 @Test
205 public void testNonConvex() {
206 double tol = 0.01;
207 double sinTol = FastMath.sin(tol);
208 RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
209 SphericalPolygonsSet plusX = new SphericalPolygonsSet(Vector3D.PLUS_I, tol);
210 SphericalPolygonsSet plusY = new SphericalPolygonsSet(Vector3D.PLUS_J, tol);
211 SphericalPolygonsSet plusZ = new SphericalPolygonsSet(Vector3D.PLUS_K, tol);
212 SphericalPolygonsSet threeOctants =
213 (SphericalPolygonsSet) factory.difference(plusZ, factory.intersection(plusX, plusY));
214
215 UnitSphereRandomVectorGenerator random =
216 new UnitSphereRandomVectorGenerator(3, new Well1024a(0x9c9802fde3cbcf25l));
217 for (int i = 0; i < 1000; ++i) {
218 Vector3D v = new Vector3D(random.nextVector());
219 if (((v.getX() < -sinTol) || (v.getY() < -sinTol)) && (v.getZ() > sinTol)) {
220 Assert.assertEquals(Location.INSIDE, threeOctants.checkPoint(new S2Point(v)));
221 } else if (((v.getX() > sinTol) && (v.getY() > sinTol)) || (v.getZ() < -sinTol)) {
222 Assert.assertEquals(Location.OUTSIDE, threeOctants.checkPoint(new S2Point(v)));
223 } else {
224 Assert.assertEquals(Location.BOUNDARY, threeOctants.checkPoint(new S2Point(v)));
225 }
226 }
227
228 List<Vertex> loops = threeOctants.getBoundaryLoops();
229 Assert.assertEquals(1, loops.size());
230 boolean xPFound = false;
231 boolean yPFound = false;
232 boolean zPFound = false;
233 boolean xVFound = false;
234 boolean yVFound = false;
235 boolean zVFound = false;
236 Vertex first = loops.get(0);
237 int count = 0;
238 double sumPoleX = 0;
239 double sumPoleY = 0;
240 double sumPoleZ = 0;
241 for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) {
242 ++count;
243 Edge e = v.getIncoming();
244 Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
245 if (e.getCircle().getPole().distance(Vector3D.MINUS_I) < 1.0e-10) {
246 xPFound = true;
247 sumPoleX += e.getLength();
248 } else if (e.getCircle().getPole().distance(Vector3D.MINUS_J) < 1.0e-10) {
249 yPFound = true;
250 sumPoleY += e.getLength();
251 } else {
252 Assert.assertEquals(0.0, e.getCircle().getPole().distance(Vector3D.PLUS_K), 1.0e-10);
253 zPFound = true;
254 sumPoleZ += e.getLength();
255 }
256 xVFound = xVFound || v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10;
257 yVFound = yVFound || v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10;
258 zVFound = zVFound || v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10;
259 }
260 Assert.assertTrue(xPFound);
261 Assert.assertTrue(yPFound);
262 Assert.assertTrue(zPFound);
263 Assert.assertTrue(xVFound);
264 Assert.assertTrue(yVFound);
265 Assert.assertTrue(zVFound);
266 Assert.assertEquals(0.5 * FastMath.PI, sumPoleX, 1.0e-10);
267 Assert.assertEquals(0.5 * FastMath.PI, sumPoleY, 1.0e-10);
268 Assert.assertEquals(1.5 * FastMath.PI, sumPoleZ, 1.0e-10);
269
270 Assert.assertEquals(1.5 * FastMath.PI, threeOctants.getSize(), 1.0e-10);
271
272 }
273
274 @Test
275 public void testModeratlyComplexShape() {
276 double tol = 0.01;
277 List<SubHyperplane<Sphere2D>> boundary = new ArrayList<SubHyperplane<Sphere2D>>();
278 boundary.add(create(Vector3D.MINUS_J, Vector3D.PLUS_I, Vector3D.PLUS_K, tol, 0.0, 0.5 * FastMath.PI));
279 boundary.add(create(Vector3D.MINUS_I, Vector3D.PLUS_K, Vector3D.PLUS_J, tol, 0.0, 0.5 * FastMath.PI));
280 boundary.add(create(Vector3D.PLUS_K, Vector3D.PLUS_J, Vector3D.MINUS_I, tol, 0.0, 0.5 * FastMath.PI));
281 boundary.add(create(Vector3D.MINUS_J, Vector3D.MINUS_I, Vector3D.MINUS_K, tol, 0.0, 0.5 * FastMath.PI));
282 boundary.add(create(Vector3D.MINUS_I, Vector3D.MINUS_K, Vector3D.MINUS_J, tol, 0.0, 0.5 * FastMath.PI));
283 boundary.add(create(Vector3D.PLUS_K, Vector3D.MINUS_J, Vector3D.PLUS_I, tol, 0.0, 0.5 * FastMath.PI));
284 SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
285
286 Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, 1, 1).normalize())));
287 Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, 1, 1).normalize())));
288 Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, -1, 1).normalize())));
289 Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, -1, 1).normalize())));
290 Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, 1, -1).normalize())));
291 Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, 1, -1).normalize())));
292 Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(new Vector3D(-1, -1, -1).normalize())));
293 Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(new Vector3D( 1, -1, -1).normalize())));
294
295 Assert.assertEquals(MathUtils.TWO_PI, polygon.getSize(), 1.0e-10);
296 Assert.assertEquals(3 * FastMath.PI, polygon.getBoundarySize(), 1.0e-10);
297
298 List<Vertex> loops = polygon.getBoundaryLoops();
299 Assert.assertEquals(1, loops.size());
300 boolean pXFound = false;
301 boolean mXFound = false;
302 boolean pYFound = false;
303 boolean mYFound = false;
304 boolean pZFound = false;
305 boolean mZFound = false;
306 Vertex first = loops.get(0);
307 int count = 0;
308 for (Vertex v = first; count == 0 || v != first; v = v.getOutgoing().getEnd()) {
309 ++count;
310 Edge e = v.getIncoming();
311 Assert.assertTrue(v == e.getStart().getOutgoing().getEnd());
312 pXFound = pXFound || v.getLocation().getVector().distance(Vector3D.PLUS_I) < 1.0e-10;
313 mXFound = mXFound || v.getLocation().getVector().distance(Vector3D.MINUS_I) < 1.0e-10;
314 pYFound = pYFound || v.getLocation().getVector().distance(Vector3D.PLUS_J) < 1.0e-10;
315 mYFound = mYFound || v.getLocation().getVector().distance(Vector3D.MINUS_J) < 1.0e-10;
316 pZFound = pZFound || v.getLocation().getVector().distance(Vector3D.PLUS_K) < 1.0e-10;
317 mZFound = mZFound || v.getLocation().getVector().distance(Vector3D.MINUS_K) < 1.0e-10;
318 Assert.assertEquals(0.5 * FastMath.PI, e.getLength(), 1.0e-10);
319 }
320 Assert.assertTrue(pXFound);
321 Assert.assertTrue(mXFound);
322 Assert.assertTrue(pYFound);
323 Assert.assertTrue(mYFound);
324 Assert.assertTrue(pZFound);
325 Assert.assertTrue(mZFound);
326 Assert.assertEquals(6, count);
327
328 }
329
330 @Test
331 public void testSeveralParts() {
332 double tol = 0.01;
333 double sinTol = FastMath.sin(tol);
334 List<SubHyperplane<Sphere2D>> boundary = new ArrayList<SubHyperplane<Sphere2D>>();
335
336
337 boundary.add(create(Vector3D.PLUS_J, Vector3D.PLUS_K, Vector3D.PLUS_I, tol, 0.0, 0.5 * FastMath.PI));
338 boundary.add(create(Vector3D.PLUS_K, Vector3D.PLUS_I, Vector3D.PLUS_J, tol, 0.0, 0.5 * FastMath.PI));
339 boundary.add(create(Vector3D.PLUS_I, Vector3D.PLUS_J, Vector3D.PLUS_K, tol, 0.0, 0.5 * FastMath.PI));
340
341
342 boundary.add(create(Vector3D.MINUS_J, Vector3D.MINUS_I, Vector3D.MINUS_K, tol, 0.0, 0.5 * FastMath.PI));
343 boundary.add(create(Vector3D.MINUS_I, Vector3D.MINUS_K, Vector3D.MINUS_J, tol, 0.0, 0.5 * FastMath.PI));
344 boundary.add(create(Vector3D.MINUS_K, Vector3D.MINUS_J, Vector3D.MINUS_I, tol, 0.0, 0.5 * FastMath.PI));
345
346 SphericalPolygonsSet polygon = new SphericalPolygonsSet(boundary, tol);
347
348 UnitSphereRandomVectorGenerator random =
349 new UnitSphereRandomVectorGenerator(3, new Well1024a(0xcc5ce49949e0d3ecl));
350 for (int i = 0; i < 1000; ++i) {
351 Vector3D v = new Vector3D(random.nextVector());
352 if ((v.getX() < -sinTol) && (v.getY() < -sinTol) && (v.getZ() < -sinTol)) {
353 Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v)));
354 } else if ((v.getX() < sinTol) && (v.getY() < sinTol) && (v.getZ() < sinTol)) {
355 Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v)));
356 } else if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
357 Assert.assertEquals(Location.INSIDE, polygon.checkPoint(new S2Point(v)));
358 } else if ((v.getX() > -sinTol) && (v.getY() > -sinTol) && (v.getZ() > -sinTol)) {
359 Assert.assertEquals(Location.BOUNDARY, polygon.checkPoint(new S2Point(v)));
360 } else {
361 Assert.assertEquals(Location.OUTSIDE, polygon.checkPoint(new S2Point(v)));
362 }
363 }
364
365 Assert.assertEquals(FastMath.PI, polygon.getSize(), 1.0e-10);
366 Assert.assertEquals(3 * FastMath.PI, polygon.getBoundarySize(), 1.0e-10);
367
368
369 Assert.assertEquals(2, polygon.getBoundaryLoops().size());
370
371 }
372
373 @Test
374 public void testPartWithHole() {
375 double tol = 0.01;
376 double alpha = 0.7;
377 S2Point center = new S2Point(new Vector3D(1, 1, 1));
378 SphericalPolygonsSet hexa = new SphericalPolygonsSet(center.getVector(), Vector3D.PLUS_K, alpha, 6, tol);
379 SphericalPolygonsSet hole = new SphericalPolygonsSet(tol,
380 new S2Point(FastMath.PI / 6, FastMath.PI / 3),
381 new S2Point(FastMath.PI / 3, FastMath.PI / 3),
382 new S2Point(FastMath.PI / 4, FastMath.PI / 6));
383 SphericalPolygonsSet hexaWithHole =
384 (SphericalPolygonsSet) new RegionFactory<Sphere2D>().difference(hexa, hole);
385
386 for (double phi = center.getPhi() - alpha + 0.1; phi < center.getPhi() + alpha - 0.1; phi += 0.07) {
387 Location l = hexaWithHole.checkPoint(new S2Point(FastMath.PI / 4, phi));
388 if (phi < FastMath.PI / 6 || phi > FastMath.PI / 3) {
389 Assert.assertEquals(Location.INSIDE, l);
390 } else {
391 Assert.assertEquals(Location.OUTSIDE, l);
392 }
393 }
394
395
396 Assert.assertEquals(2, hexaWithHole.getBoundaryLoops().size());
397
398 Assert.assertEquals(hexa.getBoundarySize() + hole.getBoundarySize(), hexaWithHole.getBoundarySize(), 1.0e-10);
399 Assert.assertEquals(hexa.getSize() - hole.getSize(), hexaWithHole.getSize(), 1.0e-10);
400
401 }
402
403 @Test
404 public void testConcentricSubParts() {
405 double tol = 0.001;
406 Vector3D center = new Vector3D(1, 1, 1);
407 SphericalPolygonsSet hexaOut = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.9, 6, tol);
408 SphericalPolygonsSet hexaIn = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.8, 6, tol);
409 SphericalPolygonsSet pentaOut = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.7, 5, tol);
410 SphericalPolygonsSet pentaIn = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.6, 5, tol);
411 SphericalPolygonsSet quadriOut = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.5, 4, tol);
412 SphericalPolygonsSet quadriIn = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.4, 4, tol);
413 SphericalPolygonsSet triOut = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.25, 3, tol);
414 SphericalPolygonsSet triIn = new SphericalPolygonsSet(center, Vector3D.PLUS_K, 0.15, 3, tol);
415
416 RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
417 SphericalPolygonsSet hexa = (SphericalPolygonsSet) factory.difference(hexaOut, hexaIn);
418 SphericalPolygonsSet penta = (SphericalPolygonsSet) factory.difference(pentaOut, pentaIn);
419 SphericalPolygonsSet quadri = (SphericalPolygonsSet) factory.difference(quadriOut, quadriIn);
420 SphericalPolygonsSet tri = (SphericalPolygonsSet) factory.difference(triOut, triIn);
421 SphericalPolygonsSet concentric =
422 (SphericalPolygonsSet) factory.union(factory.union(hexa, penta), factory.union(quadri, tri));
423
424
425 Assert.assertEquals(8, concentric.getBoundaryLoops().size());
426
427 Assert.assertEquals(hexaOut.getBoundarySize() + hexaIn.getBoundarySize() +
428 pentaOut.getBoundarySize() + pentaIn.getBoundarySize() +
429 quadriOut.getBoundarySize() + quadriIn.getBoundarySize() +
430 triOut.getBoundarySize() + triIn.getBoundarySize(),
431 concentric.getBoundarySize(), 1.0e-10);
432 Assert.assertEquals(hexaOut.getSize() - hexaIn.getSize() +
433 pentaOut.getSize() - pentaIn.getSize() +
434 quadriOut.getSize() - quadriIn.getSize() +
435 triOut.getSize() - triIn.getSize(),
436 concentric.getSize(), 1.0e-10);
437
438
439 double phi = new S2Point(center).getPhi();
440 Assert.assertEquals(+0.207, concentric.projectToBoundary(new S2Point(-0.60, phi)).getOffset(), 0.01);
441 Assert.assertEquals(-0.048, concentric.projectToBoundary(new S2Point(-0.21, phi)).getOffset(), 0.01);
442 Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point(-0.10, phi)).getOffset(), 0.01);
443 Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 0.01, phi)).getOffset(), 0.01);
444 Assert.assertEquals(+0.049, concentric.projectToBoundary(new S2Point( 0.16, phi)).getOffset(), 0.01);
445 Assert.assertEquals(-0.038, concentric.projectToBoundary(new S2Point( 0.29, phi)).getOffset(), 0.01);
446 Assert.assertEquals(+0.097, concentric.projectToBoundary(new S2Point( 0.48, phi)).getOffset(), 0.01);
447 Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.64, phi)).getOffset(), 0.01);
448 Assert.assertEquals(+0.072, concentric.projectToBoundary(new S2Point( 0.79, phi)).getOffset(), 0.01);
449 Assert.assertEquals(-0.022, concentric.projectToBoundary(new S2Point( 0.93, phi)).getOffset(), 0.01);
450 Assert.assertEquals(+0.091, concentric.projectToBoundary(new S2Point( 1.08, phi)).getOffset(), 0.01);
451 Assert.assertEquals(-0.037, concentric.projectToBoundary(new S2Point( 1.28, phi)).getOffset(), 0.01);
452 Assert.assertEquals(+0.051, concentric.projectToBoundary(new S2Point( 1.40, phi)).getOffset(), 0.01);
453 Assert.assertEquals(-0.041, concentric.projectToBoundary(new S2Point( 1.55, phi)).getOffset(), 0.01);
454 Assert.assertEquals(+0.027, concentric.projectToBoundary(new S2Point( 1.67, phi)).getOffset(), 0.01);
455 Assert.assertEquals(-0.044, concentric.projectToBoundary(new S2Point( 1.79, phi)).getOffset(), 0.01);
456 Assert.assertEquals(+0.201, concentric.projectToBoundary(new S2Point( 2.16, phi)).getOffset(), 0.01);
457
458 }
459
460 @Test
461 public void testGeographicalMap() {
462
463 SphericalPolygonsSet continental = buildSimpleZone(new double[][] {
464 { 51.14850, 2.51357 }, { 50.94660, 1.63900 }, { 50.12717, 1.33876 }, { 49.34737, -0.98946 },
465 { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 },
466 { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 },
467 { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338, 1.82679 }, { 42.47301, 2.98599 },
468 { 43.07520, 3.10041 }, { 43.39965, 4.55696 }, { 43.12889, 6.52924 }, { 43.69384, 7.43518 },
469 { 44.12790, 7.54959 }, { 45.02851, 6.74995 }, { 45.33309, 7.09665 }, { 46.42967, 6.50009 },
470 { 46.27298, 6.02260 }, { 46.72577, 6.03738 }, { 47.62058, 7.46675 }, { 49.01778, 8.09927 },
471 { 49.20195, 6.65822 }, { 49.44266, 5.89775 }, { 49.98537, 4.79922 }
472 });
473 SphericalPolygonsSet corsica = buildSimpleZone(new double[][] {
474 { 42.15249, 9.56001 }, { 43.00998, 9.39000 }, { 42.62812, 8.74600 }, { 42.25651, 8.54421 },
475 { 41.58361, 8.77572 }, { 41.38000, 9.22975 }
476 });
477 RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
478 SphericalPolygonsSet zone = (SphericalPolygonsSet) factory.union(continental, corsica);
479 EnclosingBall<Sphere2D, S2Point> enclosing = zone.getEnclosingCap();
480 Vector3D enclosingCenter = ((S2Point) enclosing.getCenter()).getVector();
481
482 double step = FastMath.toRadians(0.1);
483 for (Vertex loopStart : zone.getBoundaryLoops()) {
484 int count = 0;
485 for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
486 ++count;
487 for (int i = 0; i < FastMath.ceil(v.getOutgoing().getLength() / step); ++i) {
488 Vector3D p = v.getOutgoing().getPointAt(i * step);
489 Assert.assertTrue(Vector3D.angle(p, enclosingCenter) <= enclosing.getRadius());
490 }
491 }
492 }
493
494 S2Point supportPointA = s2Point(48.68416, -4.59234);
495 S2Point supportPointB = s2Point(41.38000, 9.22975);
496 Assert.assertEquals(enclosing.getRadius(), supportPointA.distance(enclosing.getCenter()), 1.0e-10);
497 Assert.assertEquals(enclosing.getRadius(), supportPointB.distance(enclosing.getCenter()), 1.0e-10);
498 Assert.assertEquals(0.5 * supportPointA.distance(supportPointB), enclosing.getRadius(), 1.0e-10);
499 Assert.assertEquals(2, enclosing.getSupportSize());
500
501 EnclosingBall<Sphere2D, S2Point> continentalInscribed =
502 ((SphericalPolygonsSet) factory.getComplement(continental)).getEnclosingCap();
503 Vector3D continentalCenter = ((S2Point) continentalInscribed.getCenter()).getVector();
504 Assert.assertEquals(2.2, FastMath.toDegrees(FastMath.PI - continentalInscribed.getRadius()), 0.1);
505 for (Vertex loopStart : continental.getBoundaryLoops()) {
506 int count = 0;
507 for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
508 ++count;
509 for (int i = 0; i < FastMath.ceil(v.getOutgoing().getLength() / step); ++i) {
510 Vector3D p = v.getOutgoing().getPointAt(i * step);
511 Assert.assertTrue(Vector3D.angle(p, continentalCenter) <= continentalInscribed.getRadius());
512 }
513 }
514 }
515
516 EnclosingBall<Sphere2D, S2Point> corsicaInscribed =
517 ((SphericalPolygonsSet) factory.getComplement(corsica)).getEnclosingCap();
518 Vector3D corsicaCenter = ((S2Point) corsicaInscribed.getCenter()).getVector();
519 Assert.assertEquals(0.34, FastMath.toDegrees(FastMath.PI - corsicaInscribed.getRadius()), 0.01);
520 for (Vertex loopStart : corsica.getBoundaryLoops()) {
521 int count = 0;
522 for (Vertex v = loopStart; count == 0 || v != loopStart; v = v.getOutgoing().getEnd()) {
523 ++count;
524 for (int i = 0; i < FastMath.ceil(v.getOutgoing().getLength() / step); ++i) {
525 Vector3D p = v.getOutgoing().getPointAt(i * step);
526 Assert.assertTrue(Vector3D.angle(p, corsicaCenter) <= corsicaInscribed.getRadius());
527 }
528 }
529 }
530
531 }
532
533 @Test
534 public void testZigZagBoundary() {
535 SphericalPolygonsSet zone = new SphericalPolygonsSet(1.0e-6,
536 new S2Point(-0.12630940610562444, 0.8998192093789258),
537 new S2Point(-0.12731320182988207, 0.8963735568774486),
538 new S2Point(-0.1351107624622557, 0.8978258663483273),
539 new S2Point(-0.13545331405131725, 0.8966781238246179),
540 new S2Point(-0.14324883017454967, 0.8981309629283796),
541 new S2Point(-0.14359875625524995, 0.896983965573036),
542 new S2Point(-0.14749650541159384, 0.8977109994666864),
543 new S2Point(-0.14785037758231825, 0.8965644005442432),
544 new S2Point(-0.15369807257448784, 0.8976550608135502),
545 new S2Point(-0.1526225554339386, 0.9010934265410458),
546 new S2Point(-0.14679028466684121, 0.9000043396997698),
547 new S2Point(-0.14643807494172612, 0.9011511073761742),
548 new S2Point(-0.1386609051963748, 0.8996991539048602),
549 new S2Point(-0.13831601655974668, 0.9008466623902937),
550 new S2Point(-0.1305365419828323, 0.8993961857946309),
551 new S2Point(-0.1301989630405964, 0.9005444294061787));
552 Assert.assertEquals(Region.Location.INSIDE, zone.checkPoint(new S2Point(-0.145, 0.898)));
553 Assert.assertEquals(6.463e-5, zone.getSize(), 1.0e-7);
554 Assert.assertEquals(5.487e-2, zone.getBoundarySize(), 1.0e-4);
555 }
556
557 @Test
558 public void testGitHubIssue41() {
559 RegionFactory<Sphere2D> regionFactory = new RegionFactory<>();
560 S2Point[] s2pA = new S2Point[]{
561 new S2Point(new Vector3D(0.2122954606, -0.629606302, 0.7473463333)),
562 new S2Point(new Vector3D(0.2120220248, -0.6296445493, 0.747391733)),
563 new S2Point(new Vector3D(0.2119838016, -0.6298173178, 0.7472569934)),
564 new S2Point(new Vector3D(0.2122571927, -0.6297790738, 0.7472116182))};
565
566 S2Point[] s2pB = new S2Point[]{
567 new S2Point(new Vector3D(0.2120291561, -0.629952069, 0.7471305292)),
568 new S2Point(new Vector3D(0.2123026002, -0.6299138005, 0.7470851423)),
569 new S2Point(new Vector3D(0.2123408927, -0.6297410403, 0.7472198923)),
570 new S2Point(new Vector3D(0.2120674039, -0.6297793122, 0.7472653037))};
571
572 final double tol = 0.0001;
573 final SphericalPolygonsSet spsA = new SphericalPolygonsSet(tol, s2pA);
574 final SphericalPolygonsSet spsB = new SphericalPolygonsSet(tol, s2pB);
575 Assert.assertEquals(0.61254e-7, spsA.getSize(), 1.0e-12);
576 Assert.assertEquals(1.00437e-3, spsA.getBoundarySize(), 1.0e-08);
577 Assert.assertEquals(0.61269e-7, spsB.getSize(), 1.0e-12);
578 Assert.assertEquals(1.00452e-3, spsB.getBoundarySize(), 1.0e-08);
579 SphericalPolygonsSet union = (SphericalPolygonsSet) regionFactory.union(spsA, spsB);
580
581
582
583
584
585 Assert.assertEquals(1.15628e-7, union.getSize(), 4.0e-9);
586 Assert.assertEquals(1.53824e-3, union.getBoundarySize(), 3.0e-4);
587
588 }
589
590 @Test
591 public void testGitHubIssue42A() {
592
593
594
595 try {
596 doTestGitHubIssue42(1.0e-100);
597 } catch (MathIllegalArgumentException miae) {
598 Assert.assertEquals(LocalizedGeometryFormats.TOO_SMALL_TOLERANCE, miae.getSpecifier());
599 Assert.assertEquals(1.0e-100, ((Double) miae.getParts()[0]).doubleValue(), 1.0e-110);
600 Assert.assertEquals("Sphere2D.SMALLEST_TOLERANCE", miae.getParts()[1]);
601 Assert.assertEquals(Sphere2D.SMALLEST_TOLERANCE, ((Double) miae.getParts()[2]).doubleValue(), 1.0e-20);
602 }
603 }
604
605 @Test
606 public void testGitHubIssue42B() {
607
608 try {
609
610
611
612 doTestGitHubIssue42(9.0e-16);
613 } catch (MathIllegalStateException e) {
614 Assert.assertEquals(e.getSpecifier(),
615 LocalizedGeometryFormats.OUTLINE_BOUNDARY_LOOP_OPEN);
616 }
617
618 double tol = FastMath.ulp(4 * FastMath.PI);
619
620 doTestGitHubIssue42(tol);
621 }
622
623 private void doTestGitHubIssue42(double tolerance) throws MathIllegalArgumentException {
624 S2Point[] s2pA = new S2Point[]{
625 new S2Point(new Vector3D(0.1504230736114679, -0.6603084987333554, 0.7357754993377947)),
626 new S2Point(new Vector3D(0.15011191112224423, -0.6603400871954631, 0.7358106980616113)),
627 new S2Point(new Vector3D(0.15008035620222715, -0.6605195692153062, 0.7356560238085725)),
628 new S2Point(new Vector3D(0.1503914563063968, -0.6604879854490165, 0.7356208472763267))
629 };
630 S2Point outsidePoint = new S2Point(new Vector3D( 2, s2pA[0].getVector(),
631 -1, s2pA[1].getVector(),
632 -1, s2pA[2].getVector(),
633 2, s2pA[3].getVector()).normalize());
634
635 for (int i = 0; i < s2pA.length; i++) {
636 S2Point[] points = new S2Point[s2pA.length];
637 for (int j = 0; j < s2pA.length; j++) {
638 points[j] = s2pA[(i + j) % s2pA.length];
639 }
640 final SphericalPolygonsSet spsA = new SphericalPolygonsSet(tolerance, points);
641 Assert.assertEquals(Location.OUTSIDE, spsA.checkPoint(outsidePoint));
642 Assert.assertEquals(7.4547e-8, spsA.getSize(), 1.0e-12);
643 }
644 }
645
646 @Test
647 public void testZigZagBoundaryOversampledIssue46() {
648 final double tol = 1.0e-4;
649
650 final S2Point[] vertices = {
651 new S2Point(-0.12630940610562444e1, (0.8998192093789258 - 0.89) * 100),
652 new S2Point(-0.12731320182988207e1, (0.8963735568774486 - 0.89) * 100),
653 new S2Point(-0.1351107624622557e1, (0.8978258663483273 - 0.89) * 100),
654 new S2Point(-0.13545331405131725e1, (0.8966781238246179 - 0.89) * 100),
655 new S2Point(-0.14324883017454967e1, (0.8981309629283796 - 0.89) * 100),
656 new S2Point(-0.14359875625524995e1, (0.896983965573036 - 0.89) * 100),
657 new S2Point(-0.14749650541159384e1, (0.8977109994666864 - 0.89) * 100),
658 new S2Point(-0.14785037758231825e1, (0.8965644005442432 - 0.89) * 100),
659 new S2Point(-0.15369807257448784e1, (0.8976550608135502 - 0.89) * 100),
660 new S2Point(-0.1526225554339386e1, (0.9010934265410458 - 0.89) * 100),
661 new S2Point(-0.14679028466684121e1, (0.9000043396997698 - 0.89) * 100),
662 new S2Point(-0.14643807494172612e1, (0.9011511073761742 - 0.89) * 100),
663 new S2Point(-0.1386609051963748e1, (0.8996991539048602 - 0.89) * 100),
664 new S2Point(-0.13831601655974668e1, (0.9008466623902937 - 0.89) * 100),
665 new S2Point(-0.1305365419828323e1, (0.8993961857946309 - 0.89) * 100),
666 new S2Point(-0.1301989630405964e1, (0.9005444294061787 - 0.89) * 100)};
667 SphericalPolygonsSet zone = new SphericalPolygonsSet(tol, vertices);
668
669 List<S2Point> points = new ArrayList<>();
670 final Vertex start = zone.getBoundaryLoops().get(0);
671 Vertex v = start;
672 double step = tol / 10;
673 do {
674 Edge outgoing = v.getOutgoing();
675 final double length = outgoing.getLength();
676 int n = (int) (length / step);
677 for (int i = 0; i < n; i++) {
678 points.add(new S2Point(outgoing.getPointAt(i * step)));
679 }
680 v = outgoing.getEnd();
681 } while (v != start);
682
683 zone = new SphericalPolygonsSet(tol, points.toArray(new S2Point[0]));
684 EnclosingBall<Sphere2D, S2Point> cap = zone.getEnclosingCap();
685
686 Assert.assertTrue(cap.getRadius() < 0.5);
687 Assert.assertEquals(Location.INSIDE, zone.checkPoint(zone.getBarycenter()));
688 Assert.assertEquals(Location.INSIDE, zone.checkPoint(cap.getCenter()));
689
690
691 final double cornerTol = 3.1 * tol;
692 for (S2Point vertex : vertices) {
693
694 Assert.assertEquals("" + vertex, Location.BOUNDARY, zone.checkPoint(vertex));
695 double offset = FastMath.abs(zone.projectToBoundary(vertex).getOffset());
696 Assert.assertEquals("" + vertex + " offset: " + offset, 0, offset, cornerTol);
697
698 Assert.assertTrue(
699 "vertex: " + vertex + " distance: " + (vertex.distance(cap.getCenter()) - cap.getRadius()),
700 cap.contains(vertex, tol));
701 }
702 }
703
704 @Test
705 public void testPositiveOctantByVerticesDetailIssue46() {
706 double tol = 0.01;
707 double sinTol = FastMath.sin(tol);
708 Circle x = new Circle(Vector3D.PLUS_I, tol);
709 Circle z = new Circle(Vector3D.PLUS_K, tol);
710 double length = FastMath.PI / 2;
711 double step = tol / 10;
712
713 int n = (int) (length / step);
714 List<S2Point> points = new ArrayList<>();
715 for (int i = 0; i < n; i++) {
716 double t = i * step;
717 points.add(new S2Point(z.getPointAt(z.getPhase(Vector3D.PLUS_I) + t)));
718 }
719 for (int i = 0; i < n; i++) {
720 double t = i * step;
721 points.add(new S2Point(x.getPointAt(x.getPhase(Vector3D.PLUS_J) + t)));
722 }
723 points.add(S2Point.PLUS_K);
724
725 SphericalPolygonsSet octant = new SphericalPolygonsSet(tol, points.toArray(new S2Point[0]));
726 UnitSphereRandomVectorGenerator random =
727 new UnitSphereRandomVectorGenerator(3, new Well1024a(0xb8fc5acc91044308l));
728
729
730
731
732
733 for (int i = 0; i < 1000; ++i) {
734 Vector3D v = new Vector3D(random.nextVector());
735 final Location actual = octant.checkPoint(new S2Point(v));
736 if ((v.getX() > sinTol) && (v.getY() > sinTol) && (v.getZ() > sinTol)) {
737 if ((v.getX() > 2*sinTol) && (v.getY() > 2*sinTol) && (v.getZ() > 2*sinTol)) {
738
739 Assert.assertEquals("" + v, Location.INSIDE, actual);
740 } else {
741
742 Assert.assertNotEquals("" + v, Location.OUTSIDE, actual);
743 }
744 } else if ((v.getX() < 0) || (v.getY() < 0) || (v.getZ() < 0)) {
745 if ((v.getX() < -sinTol) || (v.getY() < -sinTol) || (v.getZ() < -sinTol)) {
746
747 Assert.assertEquals(Location.OUTSIDE, actual);
748 } else {
749
750 Assert.assertNotEquals(Location.INSIDE, actual);
751 }
752 } else {
753
754 Assert.assertEquals(Location.BOUNDARY, actual);
755 }
756 }
757
758 for (S2Point point : points) {
759 Assert.assertEquals("" + point, Location.BOUNDARY, octant.checkPoint(point));
760 }
761 }
762
763
764 @Test
765 public void testConstructingFromFewPointsIssue46() {
766 double tol = 1e-9;
767 List<S2Point> points = new ArrayList<>();
768 Circle circle = new Circle(Vector3D.PLUS_K, tol);
769
770
771 SphericalPolygonsSet sps = new SphericalPolygonsSet(tol, new S2Point[0]);
772 Assert.assertEquals(sps.getSize(), 4*FastMath.PI, tol);
773
774
775 points.add(new S2Point(circle.getPointAt(0)));
776 try {
777 new SphericalPolygonsSet(tol, points.toArray(new S2Point[0]));
778 Assert.fail("expcected exception");
779 } catch (MathRuntimeException e) {
780
781 }
782
783
784 points.add(new S2Point(circle.getPointAt(FastMath.PI / 2)));
785 sps = new SphericalPolygonsSet(tol, points.toArray(new S2Point[0]));
786 Assert.assertEquals(sps.getSize(), 2*FastMath.PI, tol);
787
788
789 points.add(0, new S2Point(circle.getPointAt(FastMath.PI)));
790 sps = new SphericalPolygonsSet(tol, points.toArray(new S2Point[0]));
791 Assert.assertEquals(sps.getSize(), 2*FastMath.PI, tol);
792 Assert.assertEquals(sps.getBarycenter().distance(new S2Point(Vector3D.PLUS_K)), 0, tol);
793
794
795 points.add(1, new S2Point(circle.getPointAt(3 * FastMath.PI / 2)));
796 sps = new SphericalPolygonsSet(tol, points.toArray(new S2Point[0]));
797 Assert.assertEquals(sps.getSize(), 2*FastMath.PI, tol);
798 Assert.assertEquals(sps.getBarycenter().distance(new S2Point(Vector3D.PLUS_K)), 0, tol);
799
800
801 sps = new SphericalPolygonsSet(tol,
802 new S2Point(circle.getPointAt(0)),
803 new S2Point(circle.getPointAt(-0.3)),
804 new S2Point(circle.getPointAt(-0.2)),
805 new S2Point(circle.getPointAt(-0.1)));
806 Assert.assertEquals(sps.getSize(), 2*FastMath.PI, tol);
807 Assert.assertEquals(sps.getBarycenter().distance(new S2Point(Vector3D.PLUS_K)), 0, tol);
808 }
809
810 @Test
811 public void testDefensiveProgrammingCheck() {
812
813 try {
814 Method searchHelper = SphericalPolygonsSet.class.getDeclaredMethod("searchHelper",
815 IntPredicate.class,
816 Integer.TYPE, Integer.TYPE);
817 searchHelper.setAccessible(true);
818 searchHelper.invoke(null, (IntPredicate) (n -> true), 1, 0);
819 Assert.fail("an exception should have been thrown");
820 } catch (InvocationTargetException ite) {
821 MathIllegalArgumentException miae = (MathIllegalArgumentException) ite.getCause();
822 Assert.assertEquals(LocalizedCoreFormats.LOWER_ENDPOINT_ABOVE_UPPER_ENDPOINT, miae.getSpecifier());
823 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException e) {
824 Assert.fail(e.getLocalizedMessage());
825 }
826 }
827
828
829
830
831
832 @Test
833 public void TestIntersectionOrder() {
834
835 final S2Point[] vertices1 = {
836 new S2Point(0.0193428339344826, 1.5537209444301618),
837 new S2Point(0.0178197572212936, 1.553415699912148),
838 new S2Point(0.01628496406053076, 1.5531081515279537),
839 new S2Point(0.016284670226196844, 1.5531096373947835),
840 new S2Point(0.019342540199680208, 1.5537224293848613)
841 };
842
843 final S2Point[] vertices2 = {
844 new S2Point(0.016, 1.555),
845 new S2Point(0.017453292519943295, 1.555),
846 new S2Point(0.017453292519943295, 1.5533430342749532),
847 new S2Point(0.016, 1.5533430342749532)
848 };
849
850 final RegionFactory<Sphere2D> regionFactory = new RegionFactory<Sphere2D>();
851
852
853 double thickness1 = 4.96740426e-11;
854 final SphericalPolygonsSet sps1 = new SphericalPolygonsSet(thickness1, vertices1);
855 final SphericalPolygonsSet sps2 = new SphericalPolygonsSet(thickness1, vertices2);
856 Assert.assertEquals(1.4886e-12, regionFactory.intersection(sps1, sps2).getSize(), 1.0e-15);
857 Assert.assertEquals(1.4881e-12, regionFactory.intersection(sps2, sps1).getSize(), 1.0e-15);
858
859
860 double thickness2 = 4.96740427e-11;
861 final SphericalPolygonsSet sps3 = new SphericalPolygonsSet(thickness2, vertices1);
862 final SphericalPolygonsSet sps4 = new SphericalPolygonsSet(thickness2, vertices2);
863 Assert.assertEquals(1.4886e-12, regionFactory.intersection(sps3, sps4).getSize(), 1.0e-15);
864 Assert.assertEquals(2.4077e-06, regionFactory.intersection(sps4, sps3).getSize(), 1.0e-10);
865
866 }
867
868 private SubCircle create(Vector3D pole, Vector3D x, Vector3D y,
869 double tolerance, double ... limits) {
870 RegionFactory<Sphere1D> factory = new RegionFactory<Sphere1D>();
871 Circle circle = new Circle(pole, tolerance);
872 Circle phased =
873 (Circle) Circle.getTransform(new Rotation(circle.getXAxis(), circle.getYAxis(), x, y)).apply(circle);
874 ArcsSet set = (ArcsSet) factory.getComplement(new ArcsSet(tolerance));
875 for (int i = 0; i < limits.length; i += 2) {
876 set = (ArcsSet) factory.union(set, new ArcsSet(limits[i], limits[i + 1], tolerance));
877 }
878 return new SubCircle(phased, set);
879 }
880
881 private SphericalPolygonsSet buildSimpleZone(double[][] points) {
882 final S2Point[] vertices = new S2Point[points.length];
883 for (int i = 0; i < points.length; ++i) {
884 vertices[i] = s2Point(points[i][0], points[i][1]);
885 }
886 return new SphericalPolygonsSet(1.0e-10, vertices);
887 }
888
889 private S2Point s2Point(double latitude, double longitude) {
890 return new S2Point(FastMath.toRadians(longitude), FastMath.toRadians(90.0 - latitude));
891 }
892
893 }