1   /* Copyright 2002-2022 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.geometry.fov;
18  
19  import java.util.List;
20  
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.hipparchus.random.RandomGenerator;
23  import org.hipparchus.random.UnitSphereRandomVectorGenerator;
24  import org.hipparchus.util.FastMath;
25  import org.junit.After;
26  import org.junit.Assert;
27  import org.junit.Before;
28  import org.orekit.Utils;
29  import org.orekit.attitudes.AttitudeProvider;
30  import org.orekit.bodies.GeodeticPoint;
31  import org.orekit.bodies.OneAxisEllipsoid;
32  import org.orekit.errors.OrekitException;
33  import org.orekit.errors.OrekitMessages;
34  import org.orekit.frames.FramesFactory;
35  import org.orekit.frames.TopocentricFrame;
36  import org.orekit.frames.Transform;
37  import org.orekit.orbits.KeplerianOrbit;
38  import org.orekit.orbits.Orbit;
39  import org.orekit.propagation.Propagator;
40  import org.orekit.propagation.SpacecraftState;
41  import org.orekit.propagation.analytical.KeplerianPropagator;
42  import org.orekit.propagation.events.VisibilityTrigger;
43  import org.orekit.time.AbsoluteDate;
44  import org.orekit.utils.Constants;
45  import org.orekit.utils.IERSConventions;
46  import org.orekit.utils.PVCoordinates;
47  
48  public abstract class AbstractSmoothFieldOfViewTest {
49  
50      protected void doTestFOVAwayFromEarth(final SmoothFieldOfView fov, final AttitudeProvider attitude,
51                                            final Vector3D expectedCenter) {
52          Assert.assertEquals(0.0, Vector3D.distance(expectedCenter, fov.getCenter()), 1.0e-15);
53          Propagator propagator = new KeplerianPropagator(orbit);
54          propagator.setAttitudeProvider(attitude);
55          SpacecraftState state = propagator.propagate(orbit.getDate().shiftedBy(1000.0));
56          Transform inertToBody = state.getFrame().getTransformTo(earth.getBodyFrame(), state.getDate());
57          Transform fovToBody   = new Transform(state.getDate(),
58                                                state.toTransform().getInverse(),
59                                                inertToBody);
60          List<List<GeodeticPoint>> footprint = fov.getFootprint(fovToBody, earth, FastMath.toRadians(0.1));
61          Assert.assertTrue(footprint.isEmpty());
62      }
63  
64      protected void doTestNoFootprintInside(final SmoothFieldOfView fov, final Transform fovToBody) {
65          try {
66              fov.getFootprint(fovToBody, earth, FastMath.toRadians(0.1));
67              Assert.fail("an exception should have been thrown");
68          } catch (OrekitException oe) {
69              Assert.assertEquals(OrekitMessages.POINT_INSIDE_ELLIPSOID, oe.getSpecifier());
70          }
71      }
72  
73      protected void doTestFootprint(final SmoothFieldOfView fov, final AttitudeProvider attitude,
74                                     final double expectedMinOffset, final double expectedMaxOffset,
75                                     final double expectedMinElevation, final double expectedMaxElevation,
76                                     final double expectedMinDist, final double expectedMaxDist) {
77  
78          Propagator propagator = new KeplerianPropagator(orbit);
79          propagator.setAttitudeProvider(attitude);
80          SpacecraftState state = propagator.propagate(orbit.getDate().shiftedBy(1000.0));
81          Transform inertToBody = state.getFrame().getTransformTo(earth.getBodyFrame(), state.getDate());
82          Transform fovToBody   = new Transform(state.getDate(),
83                                                state.toTransform().getInverse(),
84                                                inertToBody);
85          List<List<GeodeticPoint>> footprint = fov.getFootprint(fovToBody, earth, FastMath.toRadians(0.1));
86          Vector3D subSat = earth.projectToGround(state.getPVCoordinates(earth.getBodyFrame()).getPosition(),
87                                                  state.getDate(), earth.getBodyFrame());
88          Assert.assertEquals(1, footprint.size());
89          List<GeodeticPoint> loop = footprint.get(0);
90          double minOffset = Double.POSITIVE_INFINITY;
91          double maxOffset = 0;
92          double minEl     = Double.POSITIVE_INFINITY;
93          double maxEl     = 0;
94          double minDist   = Double.POSITIVE_INFINITY;
95          double maxDist   = 0;
96          for (int i = 0; i < loop.size(); ++i) {
97  
98              Assert.assertEquals(0.0, loop.get(i).getAltitude(), 9.0e-9);
99  
100             Vector3D los = fovToBody.getInverse().transformPosition(earth.transform(loop.get(i)));
101             double offset = Vector3D.angle(fov.getCenter(), los);
102             minOffset = FastMath.min(minOffset, offset);
103             maxOffset = FastMath.max(maxOffset, offset);
104 
105             TopocentricFrame topo = new TopocentricFrame(earth, loop.get(i), "onFootprint");
106             final double elevation = topo.getElevation(state.getPVCoordinates().getPosition(),
107                                                        state.getFrame(), state.getDate());
108             if (elevation > 0.001) {
109                 Assert.assertEquals(-fov.getMargin(),
110                                     fov.offsetFromBoundary(los, 0.0, VisibilityTrigger.VISIBLE_ONLY_WHEN_FULLY_IN_FOV),
111                                     2.0e-10);
112                 Assert.assertEquals(0.1 - fov.getMargin(),
113                                     fov.offsetFromBoundary(los, 0.1, VisibilityTrigger.VISIBLE_ONLY_WHEN_FULLY_IN_FOV),
114                                     2.0e-10);
115                 Assert.assertEquals(-0.1 - fov.getMargin(),
116                                     fov.offsetFromBoundary(los, 0.1, VisibilityTrigger.VISIBLE_AS_SOON_AS_PARTIALLY_IN_FOV),
117                                     2.0e-10);
118             }
119             minEl = FastMath.min(minEl, elevation);
120             maxEl = FastMath.max(maxEl, elevation);
121             final double dist = Vector3D.distance(subSat, earth.transform(loop.get(i)));
122             minDist = FastMath.min(minDist, dist);
123             maxDist = FastMath.max(maxDist, dist);
124 
125         }
126 
127         Assert.assertEquals(expectedMinOffset,     FastMath.toDegrees(minOffset), 0.001);
128         Assert.assertEquals(expectedMaxOffset,     FastMath.toDegrees(maxOffset), 0.001);
129         Assert.assertEquals(expectedMinElevation,  FastMath.toDegrees(minEl),     0.001);
130         Assert.assertEquals(expectedMaxElevation,  FastMath.toDegrees(maxEl),     0.001);
131         Assert.assertEquals(expectedMinDist,       minDist,                       1.0);
132         Assert.assertEquals(expectedMaxDist,       maxDist,                       1.0);
133 
134     }
135 
136     protected void doTestBoundary(final SmoothFieldOfView fov, final RandomGenerator random,
137                                   final double tol) {
138         UnitSphereRandomVectorGenerator spGenerator = new UnitSphereRandomVectorGenerator(3, random);
139         for (int i = 0; i < 1000; ++i) {
140             Vector3D queryLOS = new Vector3D(spGenerator.nextVector());
141             Vector3D closest = fov.projectToBoundary(queryLOS);
142             Assert.assertEquals(-fov.getMargin(),
143                                 fov.offsetFromBoundary(closest, 0, VisibilityTrigger.VISIBLE_ONLY_WHEN_FULLY_IN_FOV),
144                                 tol);
145         }
146     }
147 
148     @Before
149     public void setUp() {
150         Utils.setDataRoot("regular-data");
151         earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
152                                      Constants.WGS84_EARTH_FLATTENING,
153                                      FramesFactory.getITRF(IERSConventions.IERS_2010, true));
154         orbit = new KeplerianOrbit(new PVCoordinates(new Vector3D(7.0e6, 1.0e6, 4.0e6),
155                                                      new Vector3D(-500.0, 8000.0, 1000.0)),
156                                    FramesFactory.getEME2000(), AbsoluteDate.J2000_EPOCH,
157                                    Constants.EIGEN5C_EARTH_MU);
158     }
159 
160     @After
161     public void tearDown() {
162         earth = null;
163         orbit = null;
164     }
165 
166     protected OneAxisEllipsoid earth;
167     protected Orbit            orbit;
168     
169 }