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  
18  package org.orekit.propagation.events;
19  
20  import org.hipparchus.geometry.euclidean.threed.Vector3D;
21  import org.hipparchus.ode.events.Action;
22  import org.hipparchus.util.FastMath;
23  import org.junit.jupiter.api.AfterEach;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  import org.orekit.Utils;
28  import org.orekit.bodies.CelestialBodyFactory;
29  import org.orekit.bodies.GeodeticPoint;
30  import org.orekit.bodies.OneAxisEllipsoid;
31  import org.orekit.errors.OrekitException;
32  import org.orekit.frames.FramesFactory;
33  import org.orekit.frames.TopocentricFrame;
34  import org.orekit.orbits.KeplerianOrbit;
35  import org.orekit.orbits.Orbit;
36  import org.orekit.orbits.PositionAngleType;
37  import org.orekit.propagation.Propagator;
38  import org.orekit.propagation.SpacecraftState;
39  import org.orekit.propagation.analytical.KeplerianPropagator;
40  import org.orekit.propagation.events.handlers.EventHandler;
41  import org.orekit.time.AbsoluteDate;
42  import org.orekit.time.TimeScalesFactory;
43  import org.orekit.utils.Constants;
44  import org.orekit.utils.IERSConventions;
45  import org.orekit.utils.PVCoordinates;
46  import org.orekit.utils.PVCoordinatesProvider;
47  
48  public class AngularSeparationFromSatelliteDetectorTest {
49  
50      private OneAxisEllipsoid earth;
51      private TopocentricFrame acatenango;
52      private AbsoluteDate     iniDate;
53      private Orbit            initialOrbit;
54      private Propagator       propagator;
55  
56      @Test
57      public void testCentralSunTransit() {
58  
59          double proximityAngle = FastMath.toRadians(10.0);
60          double maxCheck = 0.1 * proximityAngle / initialOrbit.getKeplerianMeanMotion();
61          PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
62          AngularSeparationFromSatelliteDetector detector =
63                          new AngularSeparationFromSatelliteDetector(sun, acatenango, proximityAngle).
64                          withMaxCheck(maxCheck).
65                          withThreshold(1.0e-6);
66          Assertions.assertEquals(proximityAngle, detector.getProximityAngle(), 1.0e-15);
67          Assertions.assertSame(sun,    detector.getPrimaryObject());
68          Assertions.assertSame(acatenango,  detector.getSecondaryObject());
69          Assertions.assertEquals(maxCheck, detector.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
70          propagator.addEventDetector(detector);
71          final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(3600 * 2));
72          Assertions.assertEquals(4587.6472, finalState.getDate().durationFrom(iniDate), 1.0e-3);
73  
74          final PVCoordinates sPV = finalState.getPVCoordinates();
75          final PVCoordinates primaryPV   = sun       .getPVCoordinates(finalState.getDate(), finalState.getFrame());
76          final PVCoordinates secondaryPV = acatenango.getPVCoordinates(finalState.getDate(), finalState.getFrame());
77          final double separation = Vector3D.angle(primaryPV  .getPosition().subtract(sPV.getPosition()),
78                                                   secondaryPV.getPosition().subtract(sPV.getPosition()));
79          Assertions.assertTrue(separation < proximityAngle);
80  
81      }
82  
83      @Test
84      public void testRegularProximity() {
85  
86          double proximityAngle = FastMath.toRadians(15.0);
87          double maxCheck = 0.1 * proximityAngle / initialOrbit.getKeplerianMeanMotion();
88          PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
89          AngularSeparationFromSatelliteDetector detector =
90                          new AngularSeparationFromSatelliteDetector(sun, acatenango, proximityAngle).
91                          withMaxCheck(maxCheck).
92                          withThreshold(1.0e-6).
93                          withHandler(new EventHandler() {
94                              public Action eventOccurred(SpacecraftState s, EventDetector detector, boolean increasing) {
95                                  if (increasing) {
96                                      Assertions.assertEquals(5259.6649, s.getDate().durationFrom(iniDate), 1.0e-3);
97                                  } else {
98                                      Assertions.assertEquals(4410.2581, s.getDate().durationFrom(iniDate), 1.0e-3);
99                                  }
100                                 return Action.CONTINUE;
101                             }
102                         });
103         Assertions.assertEquals(proximityAngle, detector.getProximityAngle(), 1.0e-15);
104         Assertions.assertSame(sun,    detector.getPrimaryObject());
105         Assertions.assertSame(acatenango,  detector.getSecondaryObject());
106         Assertions.assertEquals(maxCheck, detector.getMaxCheckInterval().currentInterval(null, true), 1.0e-15);
107         propagator.addEventDetector(detector);
108         final SpacecraftState finalState = propagator.propagate(iniDate.shiftedBy(3600 * 2));
109         Assertions.assertEquals(7200.0, finalState.getDate().durationFrom(iniDate), 1.0e-3);
110 
111     }
112 
113     @BeforeEach
114     public void setUp() {
115         try {
116             Utils.setDataRoot("regular-data");
117             earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
118                                          Constants.WGS84_EARTH_FLATTENING,
119                                          FramesFactory.getITRF(IERSConventions.IERS_2010, true));
120             acatenango = new TopocentricFrame(earth,
121                                               new GeodeticPoint(FastMath.toRadians(14.500833),
122                                                                 FastMath.toRadians(-90.87583),
123                                                                 3976.0),
124                                               "Acatenango");
125             iniDate = new AbsoluteDate(2003, 5, 1, 17, 30, 0.0, TimeScalesFactory.getUTC());
126             initialOrbit = new KeplerianOrbit(7e6, 1.0e-4, FastMath.toRadians(98.5),
127                                               FastMath.toRadians(87.0), FastMath.toRadians(216.59976025619),
128                                               FastMath.toRadians(319.7), PositionAngleType.MEAN,
129                                               FramesFactory.getEME2000(), iniDate,
130                                               Constants.EIGEN5C_EARTH_MU);
131             propagator = new KeplerianPropagator(initialOrbit);
132         } catch (OrekitException oe) {
133             Assertions.fail(oe.getLocalizedMessage());
134         }
135     }
136 
137     @AfterEach
138     public void tearDown() {
139         earth        = null;
140         iniDate      = null;
141         initialOrbit = null;
142         propagator   = null;
143     }
144 }