1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.tessellation;
18
19 import org.hipparchus.geometry.euclidean.threed.Vector3D;
20 import org.hipparchus.geometry.partitioning.Region.Location;
21 import org.hipparchus.geometry.partitioning.RegionFactory;
22 import org.hipparchus.geometry.spherical.twod.S2Point;
23 import org.hipparchus.geometry.spherical.twod.Sphere2D;
24 import org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet;
25 import org.hipparchus.util.FastMath;
26 import org.junit.jupiter.api.Assertions;
27 import org.junit.jupiter.api.BeforeEach;
28 import org.junit.jupiter.api.Test;
29 import org.orekit.Utils;
30 import org.orekit.bodies.GeodeticPoint;
31 import org.orekit.bodies.OneAxisEllipsoid;
32 import org.orekit.errors.OrekitException;
33 import org.orekit.errors.OrekitMessages;
34 import org.orekit.frames.Frame;
35 import org.orekit.frames.FramesFactory;
36 import org.orekit.orbits.CircularOrbit;
37 import org.orekit.orbits.Orbit;
38 import org.orekit.orbits.PositionAngle;
39 import org.orekit.time.AbsoluteDate;
40 import org.orekit.time.TimeScalesFactory;
41 import org.orekit.utils.Constants;
42 import org.orekit.utils.IERSConventions;
43
44 import java.io.IOException;
45 import java.util.List;
46
47 public class EllipsoidTessellatorTest {
48
49 @Test
50 public void testTilesAlongDescendingTrackWithoutTruncation() {
51 final EllipsoidTessellator tessellator =
52 new EllipsoidTessellator(ellipsoid, new AlongTrackAiming(ellipsoid, orbit, false), 16);
53 final List<List<Tile>> tiles = tessellator.tessellate(buildFrance(),
54 50000.0, 150000.0, 5000.0, 5000.0,
55 false, false);
56 Assertions.assertEquals(2, tiles.size());
57 Assertions.assertEquals(109, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
58 Assertions.assertEquals(4, FastMath.min(tiles.get(0).size(), tiles.get(1).size()));
59
60 }
61
62 @Test
63 public void testTilesAlongDescendingTrackWithTruncation() {
64 final EllipsoidTessellator tessellator =
65 new EllipsoidTessellator(ellipsoid, new AlongTrackAiming(ellipsoid, orbit, false), 16);
66 final List<List<Tile>> tiles = tessellator.tessellate(buildFrance(),
67 50000.0, 150000.0, 5000.0, 5000.0,
68 true, true);
69 Assertions.assertEquals(2, tiles.size());
70 Assertions.assertEquals(108, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
71 Assertions.assertEquals(4, FastMath.min(tiles.get(0).size(), tiles.get(1).size()));
72
73 }
74
75 @Test
76 public void testSampleAlongDescendingTrack() {
77 final EllipsoidTessellator tessellator =
78 new EllipsoidTessellator(ellipsoid, new AlongTrackAiming(ellipsoid, orbit, false), 4);
79 final List<List<GeodeticPoint>> samples = tessellator.sample(buildFrance(), 25000.0, 50000.0);
80 Assertions.assertEquals(2, samples.size());
81 Assertions.assertEquals(452, FastMath.max(samples.get(0).size(), samples.get(1).size()));
82 Assertions.assertEquals(9, FastMath.min(samples.get(0).size(), samples.get(1).size()));
83 }
84
85 @Test
86 public void testTilesAlongAscendingTrack() {
87 final EllipsoidTessellator tessellator =
88 new EllipsoidTessellator(ellipsoid, new AlongTrackAiming(ellipsoid, orbit, true), 4);
89 final List<List<Tile>> tiles = tessellator.tessellate(buildFrance(),
90 50000.0, 150000.0, 5000.0, 5000.0,
91 false, false);
92 Assertions.assertEquals(2, tiles.size());
93 Assertions.assertEquals(112, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
94 Assertions.assertEquals(6, FastMath.min(tiles.get(0).size(), tiles.get(1).size()));
95 }
96
97 @Test
98 public void testSampleAlongAscendingTrack() {
99 final EllipsoidTessellator tessellator =
100 new EllipsoidTessellator(ellipsoid, new AlongTrackAiming(ellipsoid, orbit, true), 4);
101 final List<List<GeodeticPoint>> samples = tessellator.sample(buildFrance(),
102 25000.0, 50000.0);
103 Assertions.assertEquals(2, samples.size());
104 Assertions.assertEquals(452, FastMath.max(samples.get(0).size(), samples.get(1).size()));
105 Assertions.assertEquals(10, FastMath.min(samples.get(0).size(), samples.get(1).size()));
106 }
107
108 @Test
109 public void testTilesConstantAzimuth() {
110 final EllipsoidTessellator tessellator =
111 new EllipsoidTessellator(ellipsoid, new ConstantAzimuthAiming(ellipsoid, FastMath.toRadians(120)), 4);
112 final List<List<Tile>> tiles = tessellator.tessellate(buildFrance(),
113 50000.0, 150000.0, -5000.0, -5000.0,
114 false, false);
115 Assertions.assertEquals(2, tiles.size());
116 Assertions.assertEquals(86, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
117 Assertions.assertEquals(4, FastMath.min(tiles.get(0).size(), tiles.get(1).size()));
118 checkTilesDontOverlap(tiles);
119 }
120
121 @Test
122 public void testSampleConstantAzimuth() {
123 final EllipsoidTessellator tessellator =
124 new EllipsoidTessellator(ellipsoid, new ConstantAzimuthAiming(ellipsoid, FastMath.toRadians(120)), 4);
125 final List<List<GeodeticPoint>> samples = tessellator.sample(buildFrance(), 25000.0, 50000.0);
126 Assertions.assertEquals(2, samples.size());
127 Assertions.assertEquals(455, FastMath.max(samples.get(0).size(), samples.get(1).size()));
128 Assertions.assertEquals(9, FastMath.min(samples.get(0).size(), samples.get(1).size()));
129 }
130
131 @Test
132 public void testTilesIslandJoining() {
133 final EllipsoidTessellator tessellator =
134 new EllipsoidTessellator(ellipsoid, new ConstantAzimuthAiming(ellipsoid, FastMath.toRadians(120.0)), 4);
135 final List<List<Tile>> tiles = tessellator.tessellate(buildFrance(),
136 150000.0, 250000.0, -5000.0, -5000.0,
137 false, false);
138 Assertions.assertEquals(1, tiles.size());
139 Assertions.assertEquals(28, tiles.get(0).size());
140 checkTilesDontOverlap(tiles);
141 }
142
143 @Test
144 public void testTilesSmallZoneWithoutTruncation() throws IOException {
145
146 TileAiming aiming = new ConstantAzimuthAiming(ellipsoid, FastMath.toRadians(193.7));
147 EllipsoidTessellator tessellator =
148 new EllipsoidTessellator(ellipsoid, aiming, 16);
149
150 SphericalPolygonsSet small = buildSimpleZone(1.0e-10, new double[][] {
151 { 43.6543, 1.4268 }, { 43.6120, 1.4179 }, { 43.6016, 1.3994 }, { 43.5682, 1.4159 },
152 { 43.5707, 1.4358 }, { 43.5573, 1.4941 }, { 43.6041, 1.4866 }
153 });
154
155 final List<List<Tile>> tiles = tessellator.tessellate(small, 50000.0, 150000.0, 0, 0,
156 false, false);
157 Assertions.assertEquals(1, tiles.size());
158 Assertions.assertEquals(1, tiles.get(0).size());
159 Tile t = tiles.get(0).get(0);
160
161
162
163 Assertions.assertEquals(150000.0,
164 Vector3D.distance(ellipsoid.transform(t.getVertices()[0]),
165 ellipsoid.transform(t.getVertices()[1])),
166 140.0);
167 Assertions.assertEquals( 50000.0,
168 Vector3D.distance(ellipsoid.transform(t.getVertices()[1]),
169 ellipsoid.transform(t.getVertices()[2])),
170 0.4);
171 Assertions.assertEquals(150000.0,
172 Vector3D.distance(ellipsoid.transform(t.getVertices()[2]),
173 ellipsoid.transform(t.getVertices()[3])),
174 140.0);
175 Assertions.assertEquals( 50000.0,
176 Vector3D.distance(ellipsoid.transform(t.getVertices()[3]),
177 ellipsoid.transform(t.getVertices()[0])),
178 0.4);
179
180 }
181
182 @Test
183 public void testTilesSmallZoneWithTruncation() throws IOException {
184
185 TileAiming aiming = new ConstantAzimuthAiming(ellipsoid, FastMath.toRadians(193.7));
186 EllipsoidTessellator tessellator =
187 new EllipsoidTessellator(ellipsoid, aiming, 16);
188
189 SphericalPolygonsSet small = buildSimpleZone(1.0e-10, new double[][] {
190 { 43.6543, 1.4268 }, { 43.6120, 1.4179 }, { 43.6016, 1.3994 }, { 43.5682, 1.4159 },
191 { 43.5707, 1.4358 }, { 43.5573, 1.4941 }, { 43.6041, 1.4866 }
192 });
193
194 final List<List<Tile>> tiles = tessellator.tessellate(small, 50000.0, 150000.0, 0, 0,
195 true, true);
196 Assertions.assertEquals(1, tiles.size());
197 Assertions.assertEquals(1, tiles.get(0).size());
198 Tile t = tiles.get(0).get(0);
199
200
201 Assertions.assertEquals(3.0 / 16.0 * 150000.0,
202 Vector3D.distance(ellipsoid.transform(t.getVertices()[0]),
203 ellipsoid.transform(t.getVertices()[1])),
204 10.0);
205 Assertions.assertEquals(4.0 / 16.0 * 50000.0,
206 Vector3D.distance(ellipsoid.transform(t.getVertices()[1]),
207 ellipsoid.transform(t.getVertices()[2])),
208 0.01);
209 Assertions.assertEquals(3.0 / 16.0 * 150000.0,
210 Vector3D.distance(ellipsoid.transform(t.getVertices()[2]),
211 ellipsoid.transform(t.getVertices()[3])),
212 10.0);
213 Assertions.assertEquals(4.0 / 16.0 * 50000.0,
214 Vector3D.distance(ellipsoid.transform(t.getVertices()[3]),
215 ellipsoid.transform(t.getVertices()[0])),
216 0.01);
217 }
218
219 @Test
220 public void testStairedTruncatedTiles() {
221
222 TileAiming aiming = new ConstantAzimuthAiming(ellipsoid, FastMath.toRadians(170.0));
223 EllipsoidTessellator tessellator =
224 new EllipsoidTessellator(ellipsoid, aiming, 16);
225
226 SphericalPolygonsSet small = buildSimpleZone(1.0e-10, new double[][] {
227 { 45.335, 0.457 },
228 { 45.342, 0.469 },
229 { 45.371, 0.424 }
230 });
231
232 final double maxWidth = 800.0;
233 final double maxLength = 10000.0;
234 final List<List<Tile>> tiles = tessellator.tessellate(small, maxWidth, maxLength, 0, 0,
235 false, true);
236 Assertions.assertEquals(1, tiles.size());
237 Assertions.assertEquals(4, tiles.get(0).size());
238 for (final Tile tile : tiles.get(0)) {
239 Vector3D v0 = ellipsoid.transform(tile.getVertices()[0]);
240 Vector3D v1 = ellipsoid.transform(tile.getVertices()[1]);
241 Vector3D v2 = ellipsoid.transform(tile.getVertices()[2]);
242 Vector3D v3 = ellipsoid.transform(tile.getVertices()[3]);
243 Assertions.assertTrue(Vector3D.distance(v0, v1) < (6.0002 / 16.0) * maxLength);
244 Assertions.assertTrue(Vector3D.distance(v2, v3) < (6.0002 / 16.0) * maxLength);
245 Assertions.assertEquals(maxWidth, Vector3D.distance(v1, v2), 1.0e-3);
246 Assertions.assertEquals(maxWidth, Vector3D.distance(v3, v0), 1.0e-3);
247 }
248
249 }
250
251 @Test
252 public void testTooThinRemainingRegion() {
253 TileAiming aiming = new ConstantAzimuthAiming(ellipsoid, -0.2185);
254 EllipsoidTessellator tessellator =
255 new EllipsoidTessellator(ellipsoid, aiming, 16);
256
257 SphericalPolygonsSet small = buildSimpleZone(1.0e-10, new double[][]{
258 { 32.7342, -16.9407 }, { 32.7415, -16.9422 }, { 32.7481, -16.9463 }, { 32.7531, -16.9528 },
259 { 32.7561, -16.9608 }, { 32.7567, -16.9696 }, { 32.7549, -16.9781 }, { 32.7508, -16.9855 },
260 { 32.7450, -16.9909 }, { 32.7379, -16.9937 }, { 32.7305, -16.9937 }, { 32.7235, -16.9909 },
261 { 32.7177, -16.9855 }, { 32.7136, -16.9781 }, { 32.7118, -16.9696 }, { 32.7124, -16.9608 },
262 { 32.7154, -16.9528 }, { 32.7204, -16.9463 }, { 32.7269, -16.9422 }
263 });
264
265 final double maxWidth = 40000.0;
266 final double maxLength = 40000.0;
267 final List<List<Tile>> tiles = tessellator.tessellate(small, maxWidth, maxLength, 0, 0,
268 false, true);
269 Assertions.assertEquals(1, tiles.size());
270 Assertions.assertEquals(1, tiles.get(0).size());
271 for (final Tile tile : tiles.get(0)) {
272 Vector3D v0 = ellipsoid.transform(tile.getVertices()[0]);
273 Vector3D v1 = ellipsoid.transform(tile.getVertices()[1]);
274 Vector3D v2 = ellipsoid.transform(tile.getVertices()[2]);
275 Vector3D v3 = ellipsoid.transform(tile.getVertices()[3]);
276 Assertions.assertTrue(Vector3D.distance(v0, v1) < 0.3 * maxLength);
277 Assertions.assertEquals(maxWidth, Vector3D.distance(v1, v2), 0.1);
278 Assertions.assertTrue(Vector3D.distance(v2, v3) < 0.3 * maxLength);
279 Assertions.assertEquals(maxWidth, Vector3D.distance(v3, v0), 0.1);
280 }
281
282 }
283
284 @Test
285 public void testNormalZoneTolerance() {
286 doTestVariableTolerance(1.0e-10);
287 }
288
289 @Test
290 public void testLargeZoneTolerance() {
291
292 doTestVariableTolerance(1.0e-6);
293 }
294
295 @Test
296 public void testHugeZoneTolerance() {
297
298
299 doTestVariableTolerance(1.0e-4);
300 }
301
302 private void doTestVariableTolerance(final double tolerance) {
303 final ConstantAzimuthAiming aiming = new ConstantAzimuthAiming(ellipsoid,
304 FastMath.toRadians(-168.178485));
305 EllipsoidTessellator tessellator =
306 new EllipsoidTessellator(ellipsoid, aiming, 16);
307
308 SphericalPolygonsSet small = buildSimpleZone(tolerance, new double[][]{
309 { -0.01048739, 0.01598931 }, { -0.00789627, 0.01555693 }, { -0.00558595, 0.01430664 },
310 { -0.00380677, 0.01237394 }, { -0.00275154, 0.00996826 }, { -0.00253461, 0.00735029 },
311 { -0.00317949, 0.00480374 }, { -0.00461629, 0.00260455 }, { -0.00668931, 0.00099105 },
312 { -0.00917392, 0.00013808 }, { -0.01180086, 0.00013808 }, { -0.01428546, 0.00099105 },
313 { -0.01635849, 0.00260455 }, { -0.01779529, 0.00480374 }, { -0.01844016, 0.00735029 },
314 { -0.01822323, 0.00996826 }, { -0.01716800, 0.01237394 }, { -0.01538882, 0.01430664 },
315 { -0.01307850, 0.01555693 }
316 });
317
318 final double maxWidth = 40000.0;
319 final double maxLength = 40000.0;
320 final List<List<Tile>> tiles =
321 tessellator.tessellate(small, maxWidth, maxLength, 0, 0, false, true);
322 Assertions.assertEquals(1, tiles.size());
323 Assertions.assertEquals(1, tiles.get(0).size());
324
325 }
326
327 private void checkTilesDontOverlap(final List<List<Tile>> tiles) {
328 for (final List<Tile> list : tiles) {
329 for (final Tile tile : list) {
330 final SphericalPolygonsSet quadrilateral =
331 new SphericalPolygonsSet(1.0e-10,
332 toS2Point(tile.getVertices()[0]),
333 toS2Point(tile.getVertices()[1]),
334 toS2Point(tile.getVertices()[2]),
335 toS2Point(tile.getVertices()[3]));
336 for (final List<Tile> otherList : tiles) {
337 for (final Tile otherTile : otherList) {
338 if (otherTile != tile) {
339 for (final GeodeticPoint vertex : otherTile.getVertices()) {
340 Assertions.assertEquals(Location.OUTSIDE, quadrilateral.checkPoint(toS2Point(vertex)),"tiles overlap at: " + vertex);
341 }
342 }
343 }
344 }
345 }
346 }
347 }
348
349 @Test
350 public void testSampleAroundPoleConstantAzimuth() {
351 SphericalPolygonsSet aoi = new SphericalPolygonsSet(1.e-9, new S2Point[] {
352 new S2Point(FastMath.toRadians(-120.0), FastMath.toRadians(5.0)),
353 new S2Point(FastMath.toRadians( 0.0), FastMath.toRadians(5.0)),
354 new S2Point(FastMath.toRadians( 120.0), FastMath.toRadians(5.0))
355 });
356 doTestSampleAroundPole(aoi, new ConstantAzimuthAiming(ellipsoid, 0.0), -1);
357 }
358
359 @Test
360 public void testSampleAroundPoleDivertedSingularity() {
361 SphericalPolygonsSet aoi = new SphericalPolygonsSet(1.e-9, new S2Point[] {
362 new S2Point(FastMath.toRadians(-120.0), FastMath.toRadians(5.0)),
363 new S2Point(FastMath.toRadians( 0.0), FastMath.toRadians(5.0)),
364 new S2Point(FastMath.toRadians( 120.0), FastMath.toRadians(5.0))
365 });
366 doTestSampleAroundPole(aoi, new DivertedSingularityAiming(aoi), 993);
367 }
368
369 private void doTestSampleAroundPole(final SphericalPolygonsSet aoi, final TileAiming aiming, final int expectedNodes) {
370 EllipsoidTessellator tessellator = new EllipsoidTessellator(ellipsoid, aiming, 1);
371 try {
372 List<List<GeodeticPoint>> sampledZone = tessellator.sample(aoi, 20000.0, 20000.0);
373 if (expectedNodes < 0) {
374 Assertions.fail("an exception should have been thrown");
375 } else {
376 Assertions.assertEquals(1, sampledZone.size());
377 Assertions.assertEquals(expectedNodes, sampledZone.get(0).size());
378 }
379 } catch (OrekitException oe) {
380 Assertions.assertEquals(OrekitMessages.CANNOT_COMPUTE_AIMING_AT_SINGULAR_POINT, oe.getSpecifier());
381 }
382
383 }
384
385 private S2Point toS2Point(final GeodeticPoint point) {
386 return new S2Point(point.getLongitude(), 0.5 * FastMath.PI - point.getLatitude());
387 }
388
389 @BeforeEach
390 public void setUp() {
391 Utils.setDataRoot("regular-data");
392
393
394
395
396
397
398
399
400
401
402
403 AbsoluteDate date = new AbsoluteDate("2012-01-01T00:00:00.000", TimeScalesFactory.getUTC());
404 Frame eme2000 = FramesFactory.getEME2000();
405 orbit = new CircularOrbit(7173352.811913891,
406 -4.029194321683225E-4, 0.0013530362644647786,
407 FastMath.toRadians(98.63218182243709),
408 FastMath.toRadians(77.55565567747836),
409 FastMath.PI, PositionAngle.TRUE,
410 eme2000, date, Constants.EIGEN5C_EARTH_MU);
411 ellipsoid =
412 new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
413 Constants.WGS84_EARTH_FLATTENING,
414 FramesFactory.getITRF(IERSConventions.IERS_2010, true));
415 }
416
417 private SphericalPolygonsSet buildFrance() {
418
419 final SphericalPolygonsSet continental = buildSimpleZone(1.0e-10, new double[][] {
420 { 51.14850, 2.51357 }, { 50.94660, 1.63900 }, { 50.12717, 1.33876 }, { 49.34737, -0.98946 },
421 { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 },
422 { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 },
423 { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338, 1.82679 }, { 42.47301, 2.98599 },
424 { 43.07520, 3.10041 }, { 43.39965, 4.55696 }, { 43.12889, 6.52924 }, { 43.69384, 7.43518 },
425 { 44.12790, 7.54959 }, { 45.02851, 6.74995 }, { 45.33309, 7.09665 }, { 46.42967, 6.50009 },
426 { 46.27298, 6.02260 }, { 46.72577, 6.03738 }, { 47.62058, 7.46675 }, { 49.01778, 8.09927 },
427 { 49.20195, 6.65822 }, { 49.44266, 5.89775 }, { 49.98537, 4.79922 }
428 });
429
430 final SphericalPolygonsSet corsica =
431 EllipsoidTessellator.buildSimpleZone(1.0e-10,
432 new GeodeticPoint(FastMath.toRadians(42.15249),
433 FastMath.toRadians(9.56001),
434 0.0),
435 new GeodeticPoint(FastMath.toRadians(43.00998),
436 FastMath.toRadians(9.39000),
437 0.0),
438 new GeodeticPoint(FastMath.toRadians(42.62812),
439 FastMath.toRadians(8.74600),
440 0.0),
441 new GeodeticPoint(FastMath.toRadians(42.25651),
442 FastMath.toRadians(8.54421),
443 0.0),
444 new GeodeticPoint(FastMath.toRadians(41.58361),
445 FastMath.toRadians(8.77572),
446 0.0),
447 new GeodeticPoint(FastMath.toRadians(41.38000),
448 FastMath.toRadians(9.22975),
449 0.0));
450
451 return (SphericalPolygonsSet) new RegionFactory<Sphere2D>().union(continental, corsica);
452
453 }
454
455 private SphericalPolygonsSet buildSimpleZone(double tolerance, double[][] points) {
456 for (int i = 0; i < points.length; ++i) {
457 points[i][0] = FastMath.toRadians(points[i][0]);
458 points[i][1] = FastMath.toRadians(points[i][1]);
459 }
460 return EllipsoidTessellator.buildSimpleZone(tolerance, points);
461 }
462
463 private Orbit orbit;
464 private OneAxisEllipsoid ellipsoid;
465
466 }