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.util.FastMath;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.BeforeEach;
23  import org.junit.jupiter.api.Test;
24  import org.orekit.Utils;
25  import org.orekit.bodies.GeodeticPoint;
26  import org.orekit.bodies.OneAxisEllipsoid;
27  import org.orekit.frames.FramesFactory;
28  import org.orekit.orbits.EquinoctialOrbit;
29  import org.orekit.orbits.KeplerianOrbit;
30  import org.orekit.orbits.Orbit;
31  import org.orekit.orbits.PositionAngleType;
32  import org.orekit.propagation.Propagator;
33  import org.orekit.propagation.SpacecraftState;
34  import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
35  import org.orekit.propagation.analytical.KeplerianPropagator;
36  import org.orekit.propagation.events.handlers.ContinueOnEvent;
37  import org.orekit.time.AbsoluteDate;
38  import org.orekit.time.TimeScale;
39  import org.orekit.time.TimeScalesFactory;
40  import org.orekit.utils.Constants;
41  import org.orekit.utils.IERSConventions;
42  import org.orekit.utils.PVCoordinates;
43  
44  class LongitudeExtremumDetectorTest {
45  
46      @Test
47      void testNoCrossing() {
48  
49          final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
50                                                              Constants.WGS84_EARTH_FLATTENING,
51                                                              FramesFactory.getITRF(IERSConventions.IERS_2010, true));
52  
53          LongitudeExtremumDetector d =
54                  new LongitudeExtremumDetector(earth).
55                  withMaxCheck(60).
56                  withThreshold(1.e-6).
57                  withHandler(new ContinueOnEvent());
58  
59          Assertions.assertEquals(60.0, d.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
60          Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15);
61          Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount());
62          Assertions.assertSame(earth, d.getBody());
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(Constants.JULIAN_DAY));
86          Assertions.assertEquals(0, logger.getLoggedEvents().size());
87  
88      }
89  
90      @Test
91      void testZigZag() {
92  
93          final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
94                                                              Constants.WGS84_EARTH_FLATTENING,
95                                                              FramesFactory.getITRF(IERSConventions.IERS_2010, true));
96  
97          LongitudeExtremumDetector d =
98                  new LongitudeExtremumDetector(600.0, 1.e-6, earth).
99                  withHandler(new ContinueOnEvent());
100 
101         Assertions.assertEquals(600.0, d.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
102         Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15);
103         Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount());
104 
105         KeplerianOrbit orbit =
106                         new KeplerianOrbit(24464560.0, 0.7311, 0.122138, 3.10686, 1.00681,
107                                            0.048363, PositionAngleType.MEAN,
108                                            FramesFactory.getEME2000(),
109                                            AbsoluteDate.J2000_EPOCH,
110                                            Constants.EIGEN5C_EARTH_MU);
111 
112 
113         Propagator propagator = new KeplerianPropagator(orbit);
114 
115         EventsLogger logger = new EventsLogger();
116         propagator.addEventDetector(logger.monitorDetector(d));
117 
118         propagator.propagate(orbit.getDate().shiftedBy(Constants.JULIAN_DAY));
119         double[] expectedLongitudes = new double[] {
120             74.8511595865, 39.5103244928, -84.2572907247, -119.598124966, 116.6342589464
121         };
122         double[] expectedLatitudes  = new double[] {
123             -3.840425646067, 3.423723606556, -3.84041982822, 3.423721448341, -3.84041336057
124         };
125         Assertions.assertEquals(5, logger.getLoggedEvents().size());
126         final double angularTolerance = 1e-9;
127         for (int i = 0; i < 5; ++i) {
128             SpacecraftState state = logger.getLoggedEvents().get(i).getState();
129             GeodeticPoint gp = earth.transform(state.getPosition(earth.getBodyFrame()),
130                                                earth.getBodyFrame(), null);
131             Assertions.assertEquals(expectedLongitudes[i], FastMath.toDegrees(gp.getLongitude()), angularTolerance);
132             Assertions.assertEquals(expectedLatitudes[i],  FastMath.toDegrees(gp.getLatitude()),  angularTolerance);
133         }
134 
135     }
136 
137     @BeforeEach
138     public void setUp() {
139         Utils.setDataRoot("regular-data");
140     }
141 
142 }
143