1   /* Copyright 2002-2020 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.models.earth.tessellation;
18  
19  import java.io.IOException;
20  import java.util.List;
21  
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.hipparchus.geometry.partitioning.Region.Location;
24  import org.hipparchus.geometry.partitioning.RegionFactory;
25  import org.hipparchus.geometry.spherical.twod.S2Point;
26  import org.hipparchus.geometry.spherical.twod.Sphere2D;
27  import org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet;
28  import org.hipparchus.util.FastMath;
29  import org.junit.Assert;
30  import org.junit.Before;
31  import org.junit.Test;
32  import org.orekit.Utils;
33  import org.orekit.bodies.GeodeticPoint;
34  import org.orekit.bodies.OneAxisEllipsoid;
35  import org.orekit.errors.OrekitException;
36  import org.orekit.errors.OrekitMessages;
37  import org.orekit.frames.Frame;
38  import org.orekit.frames.FramesFactory;
39  import org.orekit.orbits.CircularOrbit;
40  import org.orekit.orbits.Orbit;
41  import org.orekit.orbits.PositionAngle;
42  import org.orekit.time.AbsoluteDate;
43  import org.orekit.time.TimeScalesFactory;
44  import org.orekit.utils.Constants;
45  import org.orekit.utils.IERSConventions;
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          Assert.assertEquals(2,   tiles.size());
57          Assert.assertEquals(109, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
58          Assert.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          Assert.assertEquals(2,   tiles.size());
70          Assert.assertEquals(108, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
71          Assert.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          Assert.assertEquals(2,   samples.size());
81          Assert.assertEquals(452, FastMath.max(samples.get(0).size(), samples.get(1).size()));
82          Assert.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          Assert.assertEquals(2,   tiles.size());
93          Assert.assertEquals(112, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
94          Assert.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         Assert.assertEquals(2,   samples.size());
104         Assert.assertEquals(452, FastMath.max(samples.get(0).size(), samples.get(1).size()));
105         Assert.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         Assert.assertEquals(2,  tiles.size());
116         Assert.assertEquals(86, FastMath.max(tiles.get(0).size(), tiles.get(1).size()));
117         Assert.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         Assert.assertEquals(2,   samples.size());
127         Assert.assertEquals(455, FastMath.max(samples.get(0).size(), samples.get(1).size()));
128         Assert.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         Assert.assertEquals(1,  tiles.size());
139         Assert.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         Assert.assertEquals(1, tiles.size());
158         Assert.assertEquals(1, tiles.get(0).size());
159         Tile t = tiles.get(0).get(0);
160 
161         // without truncation, the tile must match width and length specification
162         // (the remaining error is due to Cartesian distance and non-developable ellipsoid)
163         Assert.assertEquals(150000.0,
164                             Vector3D.distance(ellipsoid.transform(t.getVertices()[0]),
165                                               ellipsoid.transform(t.getVertices()[1])),
166                             140.0);
167         Assert.assertEquals( 50000.0,
168                             Vector3D.distance(ellipsoid.transform(t.getVertices()[1]),
169                                              ellipsoid.transform(t.getVertices()[2])),
170                             0.4);
171         Assert.assertEquals(150000.0,
172                             Vector3D.distance(ellipsoid.transform(t.getVertices()[2]),
173                                              ellipsoid.transform(t.getVertices()[3])),
174                             140.0);
175         Assert.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         Assert.assertEquals(1, tiles.size());
197         Assert.assertEquals(1, tiles.get(0).size());
198         Tile t = tiles.get(0).get(0);
199 
200         // with truncation, the tile is a fraction of the width and length specification
201         Assert.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         Assert.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         Assert.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         Assert.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         Assert.assertEquals(1, tiles.size());
237         Assert.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             Assert.assertTrue(Vector3D.distance(v0, v1) < (6.0002 / 16.0) * maxLength);
244             Assert.assertTrue(Vector3D.distance(v2, v3) < (6.0002 / 16.0) * maxLength);
245             Assert.assertEquals(maxWidth, Vector3D.distance(v1, v2), 1.0e-3);
246             Assert.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         Assert.assertEquals(1, tiles.size());
270         Assert.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             Assert.assertTrue(Vector3D.distance(v0, v1) < 0.3 * maxLength);
277             Assert.assertEquals(maxWidth, Vector3D.distance(v1, v2), 0.1);
278             Assert.assertTrue(Vector3D.distance(v2, v3) < 0.3 * maxLength);
279             Assert.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         // this used to trigger an exception in EllipsoidTessellator.recurseMeetInside (Orekit)
292         doTestVariableTolerance(1.0e-6);
293     }
294 
295     @Test
296     public void testHugeZoneTolerance() {
297         // this used to trigger an exception in Characterization.characterize (Apache Commons Math)
298         // this was due to issue MATH-1266, solved in Apache Commons Math 3.6
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         Assert.assertEquals(1, tiles.size());
323         Assert.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                                 Assert.assertEquals("tiles overlap at: " + vertex,
341                                                     Location.OUTSIDE, quadrilateral.checkPoint(toS2Point(vertex)));
342                             }
343                         }
344                     }
345                 }
346             }
347         }
348     }
349 
350     @Test
351     public void testSampleAroundPoleConstantAzimuth() {
352         SphericalPolygonsSet aoi = new SphericalPolygonsSet(1.e-9, new S2Point[] {
353             new S2Point(FastMath.toRadians(-120.0), FastMath.toRadians(5.0)),
354             new S2Point(FastMath.toRadians(   0.0), FastMath.toRadians(5.0)),
355             new S2Point(FastMath.toRadians( 120.0), FastMath.toRadians(5.0))
356         });
357         doTestSampleAroundPole(aoi, new ConstantAzimuthAiming(ellipsoid, 0.0), -1);
358     }
359 
360     @Test
361     public void testSampleAroundPoleDivertedSingularity() {
362         SphericalPolygonsSet aoi = new SphericalPolygonsSet(1.e-9, new S2Point[] {
363             new S2Point(FastMath.toRadians(-120.0), FastMath.toRadians(5.0)),
364             new S2Point(FastMath.toRadians(   0.0), FastMath.toRadians(5.0)),
365             new S2Point(FastMath.toRadians( 120.0), FastMath.toRadians(5.0))
366         });
367         doTestSampleAroundPole(aoi, new DivertedSingularityAiming(aoi), 993);
368     }
369 
370     private void doTestSampleAroundPole(final SphericalPolygonsSet aoi, final TileAiming aiming, final int expectedNodes) {
371         EllipsoidTessellator tessellator = new EllipsoidTessellator(ellipsoid, aiming, 1);
372         try {
373             List<List<GeodeticPoint>> sampledZone = tessellator.sample(aoi, 20000.0, 20000.0);
374             if (expectedNodes < 0) {
375                 Assert.fail("an exception should have been thrown");
376             } else {
377                 Assert.assertEquals(1,             sampledZone.size());
378                 Assert.assertEquals(expectedNodes, sampledZone.get(0).size());
379             }
380         } catch (OrekitException oe) {
381             Assert.assertEquals(OrekitMessages.CANNOT_COMPUTE_AIMING_AT_SINGULAR_POINT, oe.getSpecifier());
382         }
383 
384     }
385 
386     private S2Point toS2Point(final GeodeticPoint point) {
387         return new S2Point(point.getLongitude(), 0.5 * FastMath.PI - point.getLatitude());
388     }
389 
390     @Before
391     public void setUp() {
392         Utils.setDataRoot("regular-data");
393         // the following orbital parameters have been computed using
394         // Orekit tutorial about phasing, using the following configuration:
395         //
396         //  orbit.date                          = 2012-01-01T00:00:00.000
397         //  phasing.orbits.number               = 143
398         //  phasing.days.number                 =  10
399         //  sun.synchronous.reference.latitude  = 0
400         //  sun.synchronous.reference.ascending = false
401         //  sun.synchronous.mean.solar.time     = 10:30:00
402         //  gravity.field.degree                = 12
403         //  gravity.field.order                 = 12
404         AbsoluteDate date = new AbsoluteDate("2012-01-01T00:00:00.000", TimeScalesFactory.getUTC());
405         Frame eme2000 = FramesFactory.getEME2000();
406         orbit = new CircularOrbit(7173352.811913891,
407                                   -4.029194321683225E-4, 0.0013530362644647786,
408                                   FastMath.toRadians(98.63218182243709),
409                                   FastMath.toRadians(77.55565567747836),
410                                   FastMath.PI, PositionAngle.TRUE,
411                                   eme2000, date, Constants.EIGEN5C_EARTH_MU);
412         ellipsoid =
413                 new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
414                                      Constants.WGS84_EARTH_FLATTENING,
415                                      FramesFactory.getITRF(IERSConventions.IERS_2010, true));
416     }
417 
418     private SphericalPolygonsSet buildFrance() {
419 
420         final SphericalPolygonsSet continental = buildSimpleZone(1.0e-10, new double[][] {
421             { 51.14850,  2.51357 }, { 50.94660,  1.63900 }, { 50.12717,  1.33876 }, { 49.34737, -0.98946 },
422             { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 },
423             { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 },
424             { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338,  1.82679 }, { 42.47301,  2.98599 },
425             { 43.07520,  3.10041 }, { 43.39965,  4.55696 }, { 43.12889,  6.52924 }, { 43.69384,  7.43518 },
426             { 44.12790,  7.54959 }, { 45.02851,  6.74995 }, { 45.33309,  7.09665 }, { 46.42967,  6.50009 },
427             { 46.27298,  6.02260 }, { 46.72577,  6.03738 }, { 47.62058,  7.46675 }, { 49.01778,  8.09927 },
428             { 49.20195,  6.65822 }, { 49.44266,  5.89775 }, { 49.98537,  4.79922 }
429           });
430 
431         final SphericalPolygonsSet corsica =
432                 EllipsoidTessellator.buildSimpleZone(1.0e-10,
433                                                      new GeodeticPoint(FastMath.toRadians(42.15249),
434                                                                        FastMath.toRadians(9.56001),
435                                                                        0.0),
436                                                      new GeodeticPoint(FastMath.toRadians(43.00998),
437                                                                        FastMath.toRadians(9.39000),
438                                                                        0.0),
439                                                      new GeodeticPoint(FastMath.toRadians(42.62812),
440                                                                        FastMath.toRadians(8.74600),
441                                                                        0.0),
442                                                      new GeodeticPoint(FastMath.toRadians(42.25651),
443                                                                        FastMath.toRadians(8.54421),
444                                                                        0.0),
445                                                      new GeodeticPoint(FastMath.toRadians(41.58361),
446                                                                        FastMath.toRadians(8.77572),
447                                                                        0.0),
448                                                      new GeodeticPoint(FastMath.toRadians(41.38000),
449                                                                        FastMath.toRadians(9.22975),
450                                                                        0.0));
451 
452           return (SphericalPolygonsSet) new RegionFactory<Sphere2D>().union(continental, corsica);
453 
454     }
455 
456     private SphericalPolygonsSet buildSimpleZone(double tolerance, double[][] points) {
457         for (int i = 0; i < points.length; ++i) {
458             points[i][0] = FastMath.toRadians(points[i][0]);
459             points[i][1] = FastMath.toRadians(points[i][1]);
460         }
461         return EllipsoidTessellator.buildSimpleZone(tolerance, points);
462     }
463 
464     private Orbit orbit;
465     private OneAxisEllipsoid ellipsoid;
466 
467 }