1   /* Copyright 2002-2025 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.propagation.events;
18  
19  import org.hipparchus.geometry.euclidean.threed.Vector3D;
20  import org.hipparchus.geometry.partitioning.RegionFactory;
21  import org.hipparchus.geometry.spherical.twod.Circle;
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.geometry.spherical.twod.SubCircle;
26  import org.hipparchus.util.FastMath;
27  import org.junit.jupiter.api.Assertions;
28  import org.junit.jupiter.api.BeforeEach;
29  import org.junit.jupiter.api.Test;
30  import org.orekit.Utils;
31  import org.orekit.bodies.BodyShape;
32  import org.orekit.bodies.OneAxisEllipsoid;
33  import org.orekit.frames.FramesFactory;
34  import org.orekit.orbits.EquinoctialOrbit;
35  import org.orekit.orbits.Orbit;
36  import org.orekit.propagation.Propagator;
37  import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
38  import org.orekit.propagation.events.handlers.ContinueOnEvent;
39  import org.orekit.time.AbsoluteDate;
40  import org.orekit.time.TimeScale;
41  import org.orekit.time.TimeScalesFactory;
42  import org.orekit.utils.Constants;
43  import org.orekit.utils.IERSConventions;
44  import org.orekit.utils.PVCoordinates;
45  
46  public class GeographicZoneDetectorTest {
47  
48      @Test
49      public void testFrance() {
50  
51          final BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
52                                                       Constants.WGS84_EARTH_FLATTENING,
53                                                       FramesFactory.getITRF(IERSConventions.IERS_2010, true));
54  
55          GeographicZoneDetector d =
56                  new GeographicZoneDetector(20.0, 1.e-3, earth, buildFrance(), FastMath.toRadians(0.5)).
57                  withHandler(new ContinueOnEvent());
58  
59          Assertions.assertEquals(20.0, d.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
60          Assertions.assertEquals(1.0e-3, d.getThreshold(), 1.0e-15);
61          Assertions.assertEquals(0.5, FastMath.toDegrees(d.getMargin()), 1.0e-15);
62          Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount());
63  
64          final TimeScale utc = TimeScalesFactory.getUTC();
65          final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257);
66          final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922);
67          final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc);
68          final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position,  velocity),
69                                                   FramesFactory.getEME2000(), date,
70                                                   Constants.EIGEN5C_EARTH_MU);
71  
72          Propagator propagator =
73              new EcksteinHechlerPropagator(orbit,
74                                            Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
75                                            Constants.EIGEN5C_EARTH_MU,
76                                            Constants.EIGEN5C_EARTH_C20,
77                                            Constants.EIGEN5C_EARTH_C30,
78                                            Constants.EIGEN5C_EARTH_C40,
79                                            Constants.EIGEN5C_EARTH_C50,
80                                            Constants.EIGEN5C_EARTH_C60);
81  
82          EventsLogger logger = new EventsLogger();
83          propagator.addEventDetector(logger.monitorDetector(d));
84  
85          propagator.propagate(date.shiftedBy(10 * Constants.JULIAN_DAY));
86          Assertions.assertEquals(26, logger.getLoggedEvents().size());
87  
88      }
89  
90      private SphericalPolygonsSet buildFrance() {
91  
92          final SphericalPolygonsSet continental = buildSimpleZone(new double[][] {
93              { 51.14850,  2.51357 }, { 50.94660,  1.63900 }, { 50.12717,  1.33876 }, { 49.34737, -0.98946 },
94              { 49.77634, -1.93349 }, { 48.64442, -1.61651 }, { 48.90169, -3.29581 }, { 48.68416, -4.59234 },
95              { 47.95495, -4.49155 }, { 47.57032, -2.96327 }, { 46.01491, -1.19379 }, { 44.02261, -1.38422 },
96              { 43.42280, -1.90135 }, { 43.03401, -1.50277 }, { 42.34338,  1.82679 }, { 42.47301,  2.98599 },
97              { 43.07520,  3.10041 }, { 43.39965,  4.55696 }, { 43.12889,  6.52924 }, { 43.69384,  7.43518 },
98              { 44.12790,  7.54959 }, { 45.02851,  6.74995 }, { 45.33309,  7.09665 }, { 46.42967,  6.50009 },
99              { 46.27298,  6.02260 }, { 46.72577,  6.03738 }, { 47.62058,  7.46675 }, { 49.01778,  8.09927 },
100             { 49.20195,  6.65822 }, { 49.44266,  5.89775 }, { 49.98537,  4.79922 }
101           });
102 
103         final SphericalPolygonsSet corsica = buildSimpleZone(new double[][] {
104             { 42.15249,  9.56001 }, { 43.00998,  9.39000 }, { 42.62812,  8.74600 }, { 42.25651,  8.54421 },
105             { 41.58361,  8.77572 }, { 41.38000,  9.22975 }
106           });
107 
108           return (SphericalPolygonsSet) new RegionFactory<Sphere2D, S2Point, Circle, SubCircle>().
109                  union(continental, corsica);
110 
111     }
112 
113     private SphericalPolygonsSet buildSimpleZone(double[][] points) {
114         final S2Point[] vertices = new S2Point[points.length];
115         for (int i = 0; i < points.length; ++i) {
116             vertices[i] = new S2Point(FastMath.toRadians(points[i][1]),         // points[i][1] is longitude
117                                       FastMath.toRadians(90.0 - points[i][0])); // points[i][0] is latitude
118         }
119         return new SphericalPolygonsSet(1.0e-10, vertices);
120     }
121 
122     @BeforeEach
123     public void setUp() {
124         Utils.setDataRoot("regular-data");
125     }
126 
127 }
128