1   /* Copyright 2013-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.rugged.utils;
18  
19  import java.io.File;
20  import java.net.URISyntaxException;
21  import java.util.ArrayList;
22  import java.util.List;
23  
24  import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
25  import org.hipparchus.util.FastMath;
26  import org.junit.jupiter.api.AfterEach;
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.attitudes.AttitudeProvider;
31  import org.orekit.attitudes.NadirPointing;
32  import org.orekit.attitudes.YawCompensation;
33  import org.orekit.bodies.BodyShape;
34  import org.orekit.bodies.CelestialBodyFactory;
35  import org.orekit.bodies.GeodeticPoint;
36  import org.orekit.bodies.OneAxisEllipsoid;
37  import org.orekit.data.DataContext;
38  import org.orekit.data.DirectoryCrawler;
39  import org.orekit.errors.OrekitException;
40  import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
41  import org.orekit.forces.gravity.ThirdBodyAttraction;
42  import org.orekit.forces.gravity.potential.GravityFieldFactory;
43  import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
44  import org.orekit.frames.Frame;
45  import org.orekit.frames.FramesFactory;
46  import org.orekit.orbits.CircularOrbit;
47  import org.orekit.orbits.Orbit;
48  import org.orekit.orbits.OrbitType;
49  import org.orekit.orbits.PositionAngleType;
50  import org.orekit.propagation.Propagator;
51  import org.orekit.propagation.SpacecraftState;
52  import org.orekit.propagation.ToleranceProvider;
53  import org.orekit.propagation.numerical.NumericalPropagator;
54  import org.orekit.time.AbsoluteDate;
55  import org.orekit.time.TimeScalesFactory;
56  import org.orekit.utils.Constants;
57  import org.orekit.utils.IERSConventions;
58  import org.orekit.utils.TimeStampedPVCoordinates;
59  
60  public class RoughVisibilityEstimatorTest {
61  
62      @Test
63      public void testThreeOrbitsSpan() throws URISyntaxException {
64  
65          String path = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
66          DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(path)));
67          BodyShape  earth                                  = createEarth();
68          NormalizedSphericalHarmonicsProvider gravityField = createGravityField();
69          Orbit      orbit                                  = createOrbit(gravityField.getMu());
70          Propagator propagator                             = createPropagator(earth, gravityField, orbit);
71          final List<TimeStampedPVCoordinates> pv = new ArrayList<>();
72          propagator.getMultiplexer().add(1.0, currentState -> pv.add(currentState.getPVCoordinates()));
73          propagator.propagate(orbit.getDate().shiftedBy(3 * orbit.getKeplerianPeriod()));
74  
75          RoughVisibilityEstimator estimator = new RoughVisibilityEstimator(ellipsoid, orbit.getFrame(), pv);
76          AbsoluteDate d = estimator.estimateVisibility(new GeodeticPoint(FastMath.toRadians(-81.5),
77                                                                          FastMath.toRadians(-2.0),
78                                                                          0.0));
79          Assertions.assertEquals(0.0,
80                              new AbsoluteDate("2012-01-01T03:47:08.81412028",
81                                               TimeScalesFactory.getUTC()).durationFrom(d),
82                              1.10e-8);
83  
84      }
85  
86      @Test
87      public void testOneOrbitsSpan() throws URISyntaxException {
88  
89          String path = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
90          DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(path)));
91          BodyShape  earth                                  = createEarth();
92          NormalizedSphericalHarmonicsProvider gravityField = createGravityField();
93          Orbit      orbit                                  = createOrbit(gravityField.getMu());
94          Propagator propagator                             = createPropagator(earth, gravityField, orbit);
95          final List<TimeStampedPVCoordinates> pv = new ArrayList<>();
96          propagator.getMultiplexer().add(1.0,  currentState -> pv.add(currentState.getPVCoordinates()));
97          propagator.propagate(orbit.getDate().shiftedBy(orbit.getKeplerianPeriod()));
98  
99          RoughVisibilityEstimator estimator = new RoughVisibilityEstimator(ellipsoid, orbit.getFrame(), pv);
100         AbsoluteDate d = estimator.estimateVisibility(new GeodeticPoint(FastMath.toRadians(43.303),
101                                                                         FastMath.toRadians(-46.126),
102                                                                         0.0));
103         Assertions.assertEquals(0.0,
104                             new AbsoluteDate("2012-01-01T01:02:39.12252184",
105                                              TimeScalesFactory.getUTC()).durationFrom(d),
106                             1.0e-8);
107 
108     }
109 
110     private BodyShape createEarth() {
111         return new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
112                                     Constants.WGS84_EARTH_FLATTENING,
113                                     FramesFactory.getITRF(IERSConventions.IERS_2010, true));
114     }
115 
116     private NormalizedSphericalHarmonicsProvider createGravityField() {
117         return GravityFieldFactory.getNormalizedProvider(12, 12);
118     }
119 
120     private Orbit createOrbit(double mu) {
121         // the following orbital parameters have been computed using
122         // Orekit tutorial about phasing, using the following configuration:
123         //
124         //  orbit.date                          = 2012-01-01T00:00:00.000
125         //  phasing.orbits.number               = 143
126         //  phasing.days.number                 =  10
127         //  sun.synchronous.reference.latitude  = 0
128         //  sun.synchronous.reference.ascending = false
129         //  sun.synchronous.mean.solar.time     = 10:30:00
130         //  gravity.field.degree                = 12
131         //  gravity.field.order                 = 12
132         AbsoluteDate date = new AbsoluteDate("2012-01-01T00:00:00.000", TimeScalesFactory.getUTC());
133         Frame eme2000 = FramesFactory.getEME2000();
134         return new CircularOrbit(7173352.811913891,
135                                  -4.029194321683225E-4, 0.0013530362644647786,
136                                  FastMath.toRadians(98.63218182243709),
137                                  FastMath.toRadians(77.55565567747836),
138                                  FastMath.PI, PositionAngleType.TRUE,
139                                  eme2000, date, mu);
140     }
141 
142     private Propagator createPropagator(BodyShape earth,
143                                         NormalizedSphericalHarmonicsProvider gravityField,
144                                         Orbit orbit) {
145 
146         AttitudeProvider yawCompensation = new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth));
147         SpacecraftState state = new SpacecraftState(orbit,
148                                                     yawCompensation.getAttitude(orbit,
149                                                                                 orbit.getDate(),
150                                                                                 orbit.getFrame())).
151                                 withMass(1180.0);
152 
153         // numerical model for improving orbit
154         OrbitType type = OrbitType.CIRCULAR;
155         double[][] tolerances = ToleranceProvider.getDefaultToleranceProvider(0.1).getTolerances(orbit, type);
156         DormandPrince853Integrator integrator =
157                         new DormandPrince853Integrator(1.0e-4 * orbit.getKeplerianPeriod(),
158                                                        1.0e-1 * orbit.getKeplerianPeriod(),
159                                                        tolerances[0], tolerances[1]);
160         integrator.setInitialStepSize(1.0e-2 * orbit.getKeplerianPeriod());
161         NumericalPropagator numericalPropagator = new NumericalPropagator(integrator);
162         numericalPropagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(), gravityField));
163         numericalPropagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getSun()));
164         numericalPropagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
165         numericalPropagator.setOrbitType(type);
166         numericalPropagator.setInitialState(state);
167         numericalPropagator.setAttitudeProvider(yawCompensation);
168         return numericalPropagator;
169 
170     }
171 
172     @BeforeEach
173     public void setUp() {
174         try {
175 
176             String path = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
177             DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(path)));
178 
179             Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
180             ellipsoid = new ExtendedEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
181                                               Constants.WGS84_EARTH_FLATTENING,
182                                               itrf);
183         } catch (OrekitException | URISyntaxException e) {
184             Assertions.fail(e.getLocalizedMessage());
185         }
186     }
187 
188     @AfterEach
189     public void tearDown() {
190         ellipsoid = null;
191     }
192 
193     private ExtendedEllipsoid ellipsoid;
194 
195 }