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 java.util.List;
20  
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.hipparchus.util.FastMath;
23  import org.junit.jupiter.api.Assertions;
24  import org.junit.jupiter.api.BeforeEach;
25  import org.junit.jupiter.api.Test;
26  import org.orekit.Utils;
27  import org.orekit.attitudes.AttitudeProvider;
28  import org.orekit.attitudes.NadirPointing;
29  import org.orekit.bodies.GeodeticPoint;
30  import org.orekit.bodies.OneAxisEllipsoid;
31  import org.orekit.frames.FramesFactory;
32  import org.orekit.orbits.EquinoctialOrbit;
33  import org.orekit.orbits.KeplerianOrbit;
34  import org.orekit.orbits.Orbit;
35  import org.orekit.orbits.PositionAngleType;
36  import org.orekit.propagation.Propagator;
37  import org.orekit.propagation.SpacecraftState;
38  import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
39  import org.orekit.propagation.analytical.KeplerianPropagator;
40  import org.orekit.propagation.analytical.tle.TLE;
41  import org.orekit.propagation.analytical.tle.TLEPropagator;
42  import org.orekit.propagation.events.EventsLogger.LoggedEvent;
43  import org.orekit.propagation.events.handlers.ContinueOnEvent;
44  import org.orekit.time.AbsoluteDate;
45  import org.orekit.time.TimeScale;
46  import org.orekit.time.TimeScalesFactory;
47  import org.orekit.utils.Constants;
48  import org.orekit.utils.IERSConventions;
49  import org.orekit.utils.PVCoordinates;
50  
51  public class LongitudeCrossingDetectorTest {
52  
53      @Test
54      public void testRegularCrossing() {
55  
56          final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
57                                                              Constants.WGS84_EARTH_FLATTENING,
58                                                              FramesFactory.getITRF(IERSConventions.IERS_2010, true));
59  
60          LongitudeCrossingDetector d =
61                  new LongitudeCrossingDetector(earth, FastMath.toRadians(10.0)).
62                  withMaxCheck(60).
63                  withThreshold(1.e-6).
64                  withHandler(new ContinueOnEvent());
65  
66          Assertions.assertEquals(60.0, d.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
67          Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15);
68          Assertions.assertEquals(10.0, FastMath.toDegrees(d.getLongitude()), 1.0e-14);
69          Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount());
70          Assertions.assertSame(earth, d.getBody());
71  
72          final TimeScale utc = TimeScalesFactory.getUTC();
73          final Vector3D position = new Vector3D(-6142438.668, 3492467.56, -25767.257);
74          final Vector3D velocity = new Vector3D(505.848, 942.781, 7435.922);
75          final AbsoluteDate date = new AbsoluteDate(2003, 9, 16, utc);
76          final Orbit orbit = new EquinoctialOrbit(new PVCoordinates(position,  velocity),
77                                                   FramesFactory.getEME2000(), date,
78                                                   Constants.EIGEN5C_EARTH_MU);
79  
80          Propagator propagator =
81              new EcksteinHechlerPropagator(orbit,
82                                            Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
83                                            Constants.EIGEN5C_EARTH_MU,
84                                            Constants.EIGEN5C_EARTH_C20,
85                                            Constants.EIGEN5C_EARTH_C30,
86                                            Constants.EIGEN5C_EARTH_C40,
87                                            Constants.EIGEN5C_EARTH_C50,
88                                            Constants.EIGEN5C_EARTH_C60);
89  
90          EventsLogger logger = new EventsLogger();
91          propagator.addEventDetector(logger.monitorDetector(d));
92  
93          propagator.propagate(date.shiftedBy(Constants.JULIAN_DAY));
94          AbsoluteDate previous = null;
95          for (LoggedEvent e : logger.getLoggedEvents()) {
96              SpacecraftState state = e.getState();
97              double longitude = earth.transform(state.getPosition(earth.getBodyFrame()),
98                                                earth.getBodyFrame(), null).getLongitude();
99              Assertions.assertEquals(10.0, FastMath.toDegrees(longitude), 3.5e-7);
100             if (previous != null) {
101                 // same time interval regardless of increasing/decreasing,
102                 // as increasing/decreasing flag is irrelevant for this detector
103                  Assertions.assertEquals(4954.70, state.getDate().durationFrom(previous), 1e10);
104             }
105             previous = state.getDate();
106         }
107         Assertions.assertEquals(16, logger.getLoggedEvents().size());
108 
109     }
110 
111     @Test
112     public void testZigZag() {
113 
114         final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
115                                                             Constants.WGS84_EARTH_FLATTENING,
116                                                             FramesFactory.getITRF(IERSConventions.IERS_2010, true));
117 
118         LongitudeCrossingDetector d =
119                 new LongitudeCrossingDetector(600.0, 1.e-6, earth, FastMath.toRadians(-100.0)).
120                 withHandler(new ContinueOnEvent());
121 
122         Assertions.assertEquals(600.0, d.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
123         Assertions.assertEquals(1.0e-6, d.getThreshold(), 1.0e-15);
124         Assertions.assertEquals(-100.0, FastMath.toDegrees(d.getLongitude()), 1.0e-14);
125         Assertions.assertEquals(AbstractDetector.DEFAULT_MAX_ITER, d.getMaxIterationCount());
126 
127         KeplerianOrbit orbit =
128                         new KeplerianOrbit(24464560.0, 0.7311, 0.122138, 3.10686, 1.00681,
129                                            0.048363, PositionAngleType.MEAN,
130                                            FramesFactory.getEME2000(),
131                                            AbsoluteDate.J2000_EPOCH,
132                                            Constants.EIGEN5C_EARTH_MU);
133 
134 
135         Propagator propagator = new KeplerianPropagator(orbit);
136 
137         EventsLogger logger = new EventsLogger();
138         propagator.addEventDetector(logger.monitorDetector(d));
139 
140         propagator.propagate(orbit.getDate().shiftedBy(Constants.JULIAN_DAY));
141         double[] expectedLatitudes = new double[] { -6.5394381901, -0.4918760372, +6.5916016832 };
142         Assertions.assertEquals(3, logger.getLoggedEvents().size());
143         for (int i = 0; i < 3; ++i) {
144             SpacecraftState state = logger.getLoggedEvents().get(i).getState();
145             GeodeticPoint gp = earth.transform(state.getPosition(earth.getBodyFrame()),
146                                                earth.getBodyFrame(), null);
147             Assertions.assertEquals(expectedLatitudes[i], FastMath.toDegrees(gp.getLatitude()),  1.0e-10);
148             Assertions.assertEquals(-100.0,               FastMath.toDegrees(gp.getLongitude()), 1.2e-9);
149         }
150 
151     }
152 
153     @Test
154     public void testIssue997() {
155 
156         final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
157                                                             Constants.WGS84_EARTH_FLATTENING,
158                                                             FramesFactory.getITRF(IERSConventions.IERS_2010, true));
159 
160         TLE orekitTle = new TLE("1 25544U 98067A   22257.49623145  .00008872  00000-0  16209-3 0  9998",
161                                 "2 25544  51.6424 254.1285 0002269 232.3655 233.3422 15.50204391359035");
162         AttitudeProvider attitudeProvider = new NadirPointing(FramesFactory.getTEME(), earth);
163         TLEPropagator sgp4 = TLEPropagator.selectExtrapolator(orekitTle, attitudeProvider, 466615.0);
164 
165         final double startLon = FastMath.toRadians(0.0);
166         EventDetector lonEntryDetector = new LongitudeCrossingDetector(earth, startLon).
167                                          withHandler(new ContinueOnEvent());
168         final double endLon = FastMath.toRadians(10.0);
169         EventDetector lonExitDetector  = new LongitudeCrossingDetector(earth, endLon).
170                                          withHandler(new ContinueOnEvent());
171         EventsLogger logger= new EventsLogger();
172         sgp4.addEventDetector(logger.monitorDetector(lonEntryDetector));
173         sgp4.addEventDetector(logger.monitorDetector(lonExitDetector));
174 
175         sgp4.propagate(new AbsoluteDate("2022-09-14T21:54:34.39728Z", TimeScalesFactory.getUTC()));
176         List<EventsLogger.LoggedEvent> loggedEvents = logger.getLoggedEvents();
177         Assertions.assertEquals(12, loggedEvents.size());
178         for (int i = 0; i < loggedEvents.size(); ++i) {
179             final SpacecraftState s  = loggedEvents.get(i).getState();
180             final GeodeticPoint   gp = earth.transform(s.getPosition(), s.getFrame(), s.getDate());
181             if (i % 2 == 0) {
182                 Assertions.assertSame(lonEntryDetector, loggedEvents.get(i).getEventDetector());
183                 Assertions.assertEquals(startLon, gp.getLongitude(), 1.0e-9);
184             } else {
185                 Assertions.assertSame(lonExitDetector, loggedEvents.get(i).getEventDetector());
186                 Assertions.assertEquals(endLon, gp.getLongitude(), 1.0e-9);
187             }
188         }
189 
190     }
191 
192     @BeforeEach
193     public void setUp() {
194         Utils.setDataRoot("regular-data");
195     }
196 
197 }
198