1   /* Copyright 2002-2020 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.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.geometry.euclidean.threed.Rotation;
23  import org.hipparchus.geometry.euclidean.threed.Vector3D;
24  import org.hipparchus.geometry.spherical.twod.Edge;
25  import org.hipparchus.ode.events.Action;
26  import org.hipparchus.util.FastMath;
27  import org.hipparchus.util.MathUtils;
28  import org.junit.Assert;
29  import org.junit.Before;
30  import org.junit.Test;
31  import org.orekit.Utils;
32  import org.orekit.attitudes.AttitudeProvider;
33  import org.orekit.attitudes.BodyCenterPointing;
34  import org.orekit.attitudes.NadirPointing;
35  import org.orekit.bodies.BodyShape;
36  import org.orekit.bodies.CelestialBodyFactory;
37  import org.orekit.bodies.GeodeticPoint;
38  import org.orekit.bodies.OneAxisEllipsoid;
39  import org.orekit.errors.OrekitException;
40  import org.orekit.frames.Frame;
41  import org.orekit.frames.FramesFactory;
42  import org.orekit.frames.TopocentricFrame;
43  import org.orekit.geometry.fov.CircularFieldOfView;
44  import org.orekit.geometry.fov.DoubleDihedraFieldOfView;
45  import org.orekit.geometry.fov.EllipticalFieldOfView;
46  import org.orekit.geometry.fov.FieldOfView;
47  import org.orekit.geometry.fov.PolygonalFieldOfView;
48  import org.orekit.geometry.fov.PolygonalFieldOfView.DefiningConeType;
49  import org.orekit.orbits.EquinoctialOrbit;
50  import org.orekit.orbits.KeplerianOrbit;
51  import org.orekit.orbits.Orbit;
52  import org.orekit.orbits.PositionAngle;
53  import org.orekit.propagation.Propagator;
54  import org.orekit.propagation.SpacecraftState;
55  import org.orekit.propagation.analytical.KeplerianPropagator;
56  import org.orekit.propagation.events.EventsLogger.LoggedEvent;
57  import org.orekit.propagation.events.handlers.ContinueOnEvent;
58  import org.orekit.propagation.events.handlers.EventHandler;
59  import org.orekit.time.AbsoluteDate;
60  import org.orekit.time.DateComponents;
61  import org.orekit.time.TimeComponents;
62  import org.orekit.time.TimeScale;
63  import org.orekit.time.TimeScalesFactory;
64  import org.orekit.utils.Constants;
65  import org.orekit.utils.IERSConventions;
66  import org.orekit.utils.PVCoordinates;
67  import org.orekit.utils.PVCoordinatesProvider;
68  
69  public class FieldOfViewDetectorTest {
70  
71      // Body mu
72      private double mu;
73  
74      // Computation date
75      private AbsoluteDate initDate;
76  
77      // Orbit
78      private Orbit initialOrbit;
79  
80      // WGS84 Earth model
81      private OneAxisEllipsoid earth;
82  
83      // Earth center pointing attitude provider
84      private BodyCenterPointing earthCenterAttitudeLaw;
85  
86      // UTC time scale
87      private TimeScale utc;
88  
89      @Test
90      public void testDihedralFielOfView() {
91  
92          // Definition of initial conditions with position and velocity
93          //------------------------------------------------------------
94  
95          // Extrapolator definition
96          KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);
97  
98          // Event definition : square field of view, along X axis, aperture 68°
99          final double halfAperture = FastMath.toRadians(0.5 * 68.0);
100         final double maxCheck  = 60.;
101         final double threshold = 1.0e-10;
102         final PVCoordinatesProvider sunPV = CelestialBodyFactory.getSun();
103         final Vector3D center = Vector3D.PLUS_I;
104         final Vector3D axis1  = Vector3D.PLUS_K;
105         final Vector3D axis2  = Vector3D.PLUS_J;
106         final double aperture1 = halfAperture;
107         final double aperture2 = halfAperture;
108 
109         final EventDetector sunVisi =
110                 new FieldOfViewDetector(sunPV, new DoubleDihedraFieldOfView(center, axis1, aperture1, axis2, aperture2, 0.0)).
111                 withMaxCheck(maxCheck).
112                 withThreshold(threshold).
113                 withHandler(new DihedralSunVisiHandler());
114 
115         Assert.assertSame(sunPV, ((FieldOfViewDetector) sunVisi).getPVTarget());
116         Assert.assertEquals(0, ((FieldOfViewDetector) sunVisi).getFOV().getMargin(), 1.0e-15);
117         double eta = FastMath.acos(FastMath.sin(aperture1) * FastMath.sin(aperture2));
118         double theoreticalArea = MathUtils.TWO_PI - 4 * eta;
119         Assert.assertEquals(theoreticalArea,
120                             ((PolygonalFieldOfView) ((FieldOfViewDetector) sunVisi).getFOV()).getZone().getSize(),
121                             1.0e-15);
122 
123         // Add event to be detected
124         EventsLogger logger = new EventsLogger();
125         propagator.addEventDetector(logger.monitorDetector(sunVisi));
126 
127         // Extrapolate from the initial to the final date
128         propagator.propagate(initDate.shiftedBy(6000.));
129 
130         // Sun is in dihedra 1 between tB and tC and in dihedra1 between tA and tD
131         // dihedra 1 is entered and left from same side (dihedra angle increases from < -34° to about -31.6° max
132         // and then decreases again to < -34°)
133         // dihedra 2 is completely crossed (dihedra angle increases from < -34° to > +34°
134         final AbsoluteDate tA = new AbsoluteDate("1969-08-28T00:04:50.540686", utc);
135         final AbsoluteDate tB = new AbsoluteDate("1969-08-28T00:08:08.299196", utc);
136         final AbsoluteDate tC = new AbsoluteDate("1969-08-28T00:29:58.478894", utc);
137         final AbsoluteDate tD = new AbsoluteDate("1969-08-28T00:36:13.390275", utc);
138 
139         List<LoggedEvent>  events = logger.getLoggedEvents();
140         final AbsoluteDate t0     = events.get(0).getState().getDate();
141         final AbsoluteDate t1     = events.get(1).getState().getDate();
142         Assert.assertEquals(2, events.size());
143         Assert.assertEquals(0, t0.durationFrom(tB), 1.0e-6);
144         Assert.assertEquals(0, t1.durationFrom(tC), 1.0e-6);
145 
146         for (double dt = 0; dt < 3600; dt += 10.0) {
147             AbsoluteDate t = initialOrbit.getDate().shiftedBy(dt);
148             double[] angles = dihedralAngles(center, axis1, axis2,
149                                              sunPV.getPVCoordinates(t, initialOrbit.getFrame()),
150                                              new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw).propagate(t));
151             if (t.compareTo(tA) < 0) {
152                 // before tA, we are outside of both dihedras
153                 Assert.assertTrue(angles[0] < -halfAperture);
154                 Assert.assertTrue(angles[1] < -halfAperture);
155             } else if (t.compareTo(tB) < 0) {
156                 // between tA and tB, we are inside dihedra 2 but still outside of dihedra 1
157                 Assert.assertTrue(angles[0] < -halfAperture);
158                 Assert.assertTrue(angles[1] > -halfAperture);
159                 Assert.assertTrue(angles[1] < +halfAperture);
160             } else if (t.compareTo(tC) < 0) {
161                 // between tB and tC, we are inside both dihedra 1 and dihedra 2
162                 Assert.assertTrue(angles[0] > -halfAperture);
163                 Assert.assertTrue(angles[0] < +halfAperture);
164                 Assert.assertTrue(angles[1] > -halfAperture);
165                 Assert.assertTrue(angles[1] < +halfAperture);
166             } else if (t.compareTo(tD) < 0) {
167                 // between tC and tD, we are inside dihedra 2 but again outside of dihedra 1
168                 Assert.assertTrue(angles[0] < -halfAperture);
169                 Assert.assertTrue(angles[1] > -halfAperture);
170                 Assert.assertTrue(angles[1] < +halfAperture);
171             } else {
172                 // after tD, we are outside of both dihedras
173                 Assert.assertTrue(angles[0] < -halfAperture);
174                 Assert.assertTrue(angles[1] > +halfAperture);
175             }
176         }
177         
178     }
179 
180     private double[] dihedralAngles(final Vector3D center, final Vector3D axis1, final Vector3D axis2,
181                                     final PVCoordinates target, final SpacecraftState s) {
182         final Rotation toInert     = s.getAttitude().getOrientation().getRotation().revert();
183         final Vector3D centerInert = toInert.applyTo(center);
184         final Vector3D axis1Inert  = toInert.applyTo(axis1);
185         final Vector3D axis2Inert  = toInert.applyTo(axis2);
186         final Vector3D direction   = target.getPosition().subtract(s.getPVCoordinates().getPosition()).normalize();
187         return new double[] {
188             dihedralAngle(centerInert, axis1Inert, direction),
189             dihedralAngle(centerInert, axis2Inert, direction)
190         };
191     }
192 
193     private double dihedralAngle(final Vector3D center, final Vector3D axis, final Vector3D u) {
194         final Vector3D y = Vector3D.crossProduct(axis, center).normalize();
195         final Vector3D x = Vector3D.crossProduct(y, axis).normalize();
196         return FastMath.atan2(Vector3D.dotProduct(u, y), Vector3D.dotProduct(u, x));
197     }
198 
199     /** check the default behavior to stop propagation on FoV exit. */
200     @Test
201     public void testStopOnExit() {
202         //setup
203         double pi = FastMath.PI;
204         AbsoluteDate date = AbsoluteDate.J2000_EPOCH; //arbitrary date
205         AbsoluteDate endDate = date.shiftedBy(Constants.JULIAN_DAY);
206         Frame eci = FramesFactory.getGCRF();
207         Frame ecef = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
208         BodyShape earth = new OneAxisEllipsoid(
209                 Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
210                 Constants.WGS84_EARTH_FLATTENING,
211                 ecef);
212         GeodeticPoint gp = new GeodeticPoint(
213                 FastMath.toRadians(39), FastMath.toRadians(77), 0);
214         TopocentricFrame topo = new TopocentricFrame(earth, gp, "topo");
215         //iss like orbit
216         KeplerianOrbit orbit = new KeplerianOrbit(
217                 6378137 + 400e3, 0, FastMath.toRadians(51.65), 0, 0, 0,
218                 PositionAngle.TRUE, eci, date, Constants.EGM96_EARTH_MU);
219         AttitudeProvider attitude = new NadirPointing(eci, earth);
220 
221         //action
222         FieldOfView fov =
223                 new PolygonalFieldOfView(Vector3D.PLUS_K,
224                                          DefiningConeType.INSIDE_CONE_TOUCHING_POLYGON_AT_EDGES_MIDDLE,
225                                          Vector3D.PLUS_I, pi / 3, 16, 0);
226         FieldOfViewDetector fovDetector =
227                 new FieldOfViewDetector(topo, fov)
228                         .withMaxCheck(5.0);
229         EventsLogger logger = new EventsLogger();
230 
231         Propagator prop = new KeplerianPropagator(orbit, attitude);
232         prop.addEventDetector(logger.monitorDetector(fovDetector));
233         prop.propagate(endDate);
234         List<LoggedEvent> actual = logger.getLoggedEvents();
235 
236         //verify
237         // check we have an entry and an exit event.
238         Assert.assertEquals(2, actual.size());
239     }
240 
241     @Test
242     public void testRadius() {
243 
244         // Definition of initial conditions with position and velocity
245         //------------------------------------------------------------
246 
247         // Extrapolator definition
248         KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);
249 
250         // Event definition : square field of view, along X axis, aperture 68°
251         final double halfAperture = FastMath.toRadians(0.5 * 68.0);
252         final double maxCheck  = 60.;
253         final double threshold = 1.0e-10;
254         final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
255         final Vector3D center = Vector3D.PLUS_I;
256         final Vector3D axis1  = Vector3D.PLUS_K;
257         final Vector3D axis2  = Vector3D.PLUS_J;
258         final double aperture1 = halfAperture;
259         final double aperture2 = halfAperture;
260         final FieldOfView fov  = new DoubleDihedraFieldOfView(center, axis1, aperture1, axis2, aperture2, 0.0);
261 
262         final EventDetector sunCenter =
263                         new FieldOfViewDetector(sun, fov).
264                         withMaxCheck(maxCheck).
265                         withThreshold(threshold).
266                         withHandler(new ContinueOnEvent<>());
267 
268         final EventDetector sunFull =
269                         new FieldOfViewDetector(sun, Constants.SUN_RADIUS,
270                                                 VisibilityTrigger.VISIBLE_ONLY_WHEN_FULLY_IN_FOV,
271                                                 fov).
272                         withMaxCheck(maxCheck).
273                         withThreshold(threshold).
274                         withHandler(new ContinueOnEvent<>());
275 
276         final EventDetector sunPartial =
277                         new FieldOfViewDetector(sun, Constants.SUN_RADIUS,
278                                                 VisibilityTrigger.VISIBLE_AS_SOON_AS_PARTIALLY_IN_FOV,
279                                                 fov).
280                         withMaxCheck(maxCheck).
281                         withThreshold(threshold).
282                         withHandler(new ContinueOnEvent<>());
283 
284         Assert.assertSame(sun, ((FieldOfViewDetector) sunCenter).getPVTarget());
285         Assert.assertEquals(0, ((FieldOfViewDetector) sunCenter).getFOV().getMargin(), 1.0e-15);
286         double eta = FastMath.acos(FastMath.sin(aperture1) * FastMath.sin(aperture2));
287         double theoreticalArea = MathUtils.TWO_PI - 4 * eta;
288         Assert.assertEquals(theoreticalArea,
289                             ((PolygonalFieldOfView) ((FieldOfViewDetector) sunCenter).getFOV()).getZone().getSize(),
290                             1.0e-15);
291 
292         // Add event to be detected
293         EventsLogger logger = new EventsLogger();
294         propagator.addEventDetector(logger.monitorDetector(sunCenter));
295         propagator.addEventDetector(logger.monitorDetector(sunFull));
296         propagator.addEventDetector(logger.monitorDetector(sunPartial));
297 
298         // Extrapolate from the initial to the final date
299         propagator.propagate(initDate.shiftedBy(6000.));
300 
301         List<LoggedEvent>  events = logger.getLoggedEvents();
302         Assert.assertEquals(6, events.size());
303         Assert.assertSame(sunPartial, events.get(0).getEventDetector());
304         Assert.assertEquals(460.884444, events.get(0).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
305         Assert.assertSame(sunCenter, events.get(1).getEventDetector());
306         Assert.assertEquals(488.299210, events.get(1).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
307         Assert.assertSame(sunFull, events.get(2).getEventDetector());
308         Assert.assertEquals(517.527656, events.get(2).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
309         Assert.assertSame(sunFull, events.get(3).getEventDetector());
310         Assert.assertEquals(1749.292351, events.get(3).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
311         Assert.assertSame(sunCenter, events.get(4).getEventDetector());
312         Assert.assertEquals(1798.478948, events.get(4).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
313         Assert.assertSame(sunPartial, events.get(5).getEventDetector());
314         Assert.assertEquals(1845.966183, events.get(5).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
315 
316     }
317 
318     @Test
319     public void testMatryoshka() {
320 
321         // Definition of initial conditions with position and velocity
322         //------------------------------------------------------------
323 
324         // Extrapolator definition
325         KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);
326 
327         final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
328         final double maxCheck  = 60.;
329         final double threshold = 1.0e-10;
330         EventsLogger logger = new EventsLogger();
331 
332         // largest fov: circular, along X axis, aperture 68°, no margin
333         CircularFieldOfView circFov = new CircularFieldOfView(Vector3D.PLUS_I, FastMath.toRadians(0.5 * 68.0), 0.0);
334         List<EventDetector> detectors = new ArrayList<>();
335         for (int i = 0; i < 4; ++i) {
336 
337             // outer circular detector
338             final EventDetector circDetector =
339                             new FieldOfViewDetector(sun, circFov).
340                             withMaxCheck(maxCheck).
341                             withThreshold(threshold).
342                             withHandler(new ContinueOnEvent<>());
343             detectors.add(circDetector);
344             propagator.addEventDetector(logger.monitorDetector(circDetector));
345 
346             // inner polygonal detector
347             PolygonalFieldOfView polyFov = new PolygonalFieldOfView(circFov.getCenter(),
348                                                                     DefiningConeType.OUTSIDE_CONE_TOUCHING_POLYGON_AT_VERTICES,
349                                                                     circFov.getCenter().orthogonal(),
350                                                                     circFov.getHalfAperture(), 16, 0.0);
351             final EventDetector polyDetector =
352                             new FieldOfViewDetector(sun, polyFov).
353                             withMaxCheck(maxCheck).
354                             withThreshold(threshold).
355                             withHandler(new ContinueOnEvent<>());
356             detectors.add(polyDetector);
357             propagator.addEventDetector(logger.monitorDetector(polyDetector));
358 
359             // find another inner circular fov
360             final Edge     edge   = polyFov.getZone().getBoundaryLoops().get(0).getOutgoing();
361             final Vector3D middle = edge.getPointAt(0.5 * edge.getLength());
362             final double   innerRadius = Vector3D.angle(circFov.getCenter(), middle);
363             circFov = new CircularFieldOfView(circFov.getCenter(), innerRadius, 0.0);
364             
365         }
366 
367         // Extrapolate from the initial to the final date
368         propagator.propagate(initDate.shiftedBy(6000.));
369 
370         int n = detectors.size();
371         List<LoggedEvent>  events = logger.getLoggedEvents();
372         Assert.assertEquals(2 * n, events.size());
373 
374         // series of Sun visibility start events, from outer to inner FoV
375         for (int i = 0; i < n; ++i) {
376             Assert.assertSame(detectors.get(i), events.get(i).getEventDetector());
377         }
378 
379         // series of Sun visibility end events, from inner to outer FoV
380         for (int i = 0; i < n; ++i) {
381             Assert.assertSame(detectors.get(n - 1 - i), events.get(n + i).getEventDetector());
382         }
383 
384     }
385 
386     @Test
387     public void testElliptical() {
388 
389         // Definition of initial conditions with position and velocity
390         //------------------------------------------------------------
391 
392         // Extrapolator definition
393         KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);
394 
395         final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
396         final double maxCheck  = 60.;
397         final double threshold = 1.0e-10;
398         EventsLogger logger = new EventsLogger();
399 
400         EllipticalFieldOfView fov = new EllipticalFieldOfView(Vector3D.PLUS_I, Vector3D.PLUS_J,
401                                                               FastMath.toRadians(40), FastMath.toRadians(10),
402                                                               0.0);
403         propagator.addEventDetector(logger.monitorDetector(new FieldOfViewDetector(sun, fov).
404                                                            withMaxCheck(maxCheck).
405                                                            withThreshold(threshold).
406                                                            withHandler(new ContinueOnEvent<>())));
407 
408        // Extrapolate from the initial to the final date
409         propagator.propagate(initDate.shiftedBy(6000.));
410 
411         List<LoggedEvent>  events = logger.getLoggedEvents();
412         Assert.assertEquals(2, events.size());
413 
414         Assert.assertFalse(events.get(0).isIncreasing());
415         Assert.assertEquals(881.897, events.get(0).getState().getDate().durationFrom(initDate), 1.0e-3);
416         Assert.assertTrue(events.get(1).isIncreasing());
417         Assert.assertEquals(1242.146, events.get(1).getState().getDate().durationFrom(initDate), 1.0e-3);
418 
419     }
420 
421     @Test
422     public void testDihedralFielOfViewDeprecated() {
423 
424         // Definition of initial conditions with position and velocity
425         //------------------------------------------------------------
426 
427         // Extrapolator definition
428         KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);
429 
430         // Event definition : square field of view, along X axis, aperture 68°
431         final double halfAperture = FastMath.toRadians(0.5 * 68.0);
432         final double maxCheck  = 60.;
433         final double threshold = 1.0e-10;
434         final PVCoordinatesProvider sunPV = CelestialBodyFactory.getSun();
435         final Vector3D center = Vector3D.PLUS_I;
436         final Vector3D axis1  = Vector3D.PLUS_K;
437         final Vector3D axis2  = Vector3D.PLUS_J;
438         final double aperture1 = halfAperture;
439         final double aperture2 = halfAperture;
440 
441         @SuppressWarnings("deprecation")
442         final EventDetector sunVisi =
443                 new FieldOfViewDetector(sunPV, new org.orekit.propagation.events.FieldOfView(center, axis1, aperture1, axis2, aperture2, 0.0)).
444                 withMaxCheck(maxCheck).
445                 withThreshold(threshold).
446                 withHandler(new DihedralSunVisiHandler());
447 
448         // Add event to be detected
449         EventsLogger logger = new EventsLogger();
450         propagator.addEventDetector(logger.monitorDetector(sunVisi));
451 
452         // Extrapolate from the initial to the final date
453         propagator.propagate(initDate.shiftedBy(6000.));
454 
455         // Sun is in dihedra 1 between tB and tC and in dihedra1 between tA and tD
456         // dihedra 1 is entered and left from same side (dihedra angle increases from < -34° to about -31.6° max
457         // and then decreases again to < -34°)
458         // dihedra 2 is completely crossed (dihedra angle increases from < -34° to > +34°
459         final AbsoluteDate tA = new AbsoluteDate("1969-08-28T00:04:50.540686", utc);
460         final AbsoluteDate tB = new AbsoluteDate("1969-08-28T00:08:08.299196", utc);
461         final AbsoluteDate tC = new AbsoluteDate("1969-08-28T00:29:58.478894", utc);
462         final AbsoluteDate tD = new AbsoluteDate("1969-08-28T00:36:13.390275", utc);
463 
464         List<LoggedEvent>  events = logger.getLoggedEvents();
465         final AbsoluteDate t0     = events.get(0).getState().getDate();
466         final AbsoluteDate t1     = events.get(1).getState().getDate();
467         Assert.assertEquals(2, events.size());
468         Assert.assertEquals(0, t0.durationFrom(tB), 1.0e-6);
469         Assert.assertEquals(0, t1.durationFrom(tC), 1.0e-6);
470 
471         for (double dt = 0; dt < 3600; dt += 10.0) {
472             AbsoluteDate t = initialOrbit.getDate().shiftedBy(dt);
473             double[] angles = dihedralAngles(center, axis1, axis2,
474                                              sunPV.getPVCoordinates(t, initialOrbit.getFrame()),
475                                              new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw).propagate(t));
476             if (t.compareTo(tA) < 0) {
477                 // before tA, we are outside of both dihedras
478                 Assert.assertTrue(angles[0] < -halfAperture);
479                 Assert.assertTrue(angles[1] < -halfAperture);
480             } else if (t.compareTo(tB) < 0) {
481                 // between tA and tB, we are inside dihedra 2 but still outside of dihedra 1
482                 Assert.assertTrue(angles[0] < -halfAperture);
483                 Assert.assertTrue(angles[1] > -halfAperture);
484                 Assert.assertTrue(angles[1] < +halfAperture);
485             } else if (t.compareTo(tC) < 0) {
486                 // between tB and tC, we are inside both dihedra 1 and dihedra 2
487                 Assert.assertTrue(angles[0] > -halfAperture);
488                 Assert.assertTrue(angles[0] < +halfAperture);
489                 Assert.assertTrue(angles[1] > -halfAperture);
490                 Assert.assertTrue(angles[1] < +halfAperture);
491             } else if (t.compareTo(tD) < 0) {
492                 // between tC and tD, we are inside dihedra 2 but again outside of dihedra 1
493                 Assert.assertTrue(angles[0] < -halfAperture);
494                 Assert.assertTrue(angles[1] > -halfAperture);
495                 Assert.assertTrue(angles[1] < +halfAperture);
496             } else {
497                 // after tD, we are outside of both dihedras
498                 Assert.assertTrue(angles[0] < -halfAperture);
499                 Assert.assertTrue(angles[1] > +halfAperture);
500             }
501         }
502         
503     }
504 
505     @Test
506     public void testRadiusDeprecated() {
507 
508         // Definition of initial conditions with position and velocity
509         //------------------------------------------------------------
510 
511         // Extrapolator definition
512         KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);
513 
514         // Event definition : square field of view, along X axis, aperture 68°
515         final double halfAperture = FastMath.toRadians(0.5 * 68.0);
516         final double maxCheck  = 60.;
517         final double threshold = 1.0e-10;
518         final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
519         final Vector3D center = Vector3D.PLUS_I;
520         final Vector3D axis1  = Vector3D.PLUS_K;
521         final Vector3D axis2  = Vector3D.PLUS_J;
522         final double aperture1 = halfAperture;
523         final double aperture2 = halfAperture;
524         @SuppressWarnings("deprecation")
525         final org.orekit.propagation.events.FieldOfView fov  = new org.orekit.propagation.events.FieldOfView(center, axis1, aperture1, axis2, aperture2, 0.0);
526 
527         @SuppressWarnings("deprecation")
528         final EventDetector sunCenter =
529                         new FieldOfViewDetector(sun, fov).
530                         withMaxCheck(maxCheck).
531                         withThreshold(threshold).
532                         withHandler(new ContinueOnEvent<>());
533 
534         @SuppressWarnings("deprecation")
535         final EventDetector sunFull =
536                         new FieldOfViewDetector(sun, Constants.SUN_RADIUS,
537                                                 VisibilityTrigger.VISIBLE_ONLY_WHEN_FULLY_IN_FOV,
538                                                 fov).
539                         withMaxCheck(maxCheck).
540                         withThreshold(threshold).
541                         withHandler(new ContinueOnEvent<>());
542 
543         @SuppressWarnings("deprecation")
544         final EventDetector sunPartial =
545                         new FieldOfViewDetector(sun, Constants.SUN_RADIUS,
546                                                 VisibilityTrigger.VISIBLE_AS_SOON_AS_PARTIALLY_IN_FOV,
547                                                 fov).
548                         withMaxCheck(maxCheck).
549                         withThreshold(threshold).
550                         withHandler(new ContinueOnEvent<>());
551 
552         // Add event to be detected
553         EventsLogger logger = new EventsLogger();
554         propagator.addEventDetector(logger.monitorDetector(sunCenter));
555         propagator.addEventDetector(logger.monitorDetector(sunFull));
556         propagator.addEventDetector(logger.monitorDetector(sunPartial));
557 
558         // Extrapolate from the initial to the final date
559         propagator.propagate(initDate.shiftedBy(6000.));
560 
561         List<LoggedEvent>  events = logger.getLoggedEvents();
562         Assert.assertEquals(6, events.size());
563         Assert.assertSame(sunPartial, events.get(0).getEventDetector());
564         Assert.assertEquals(460.884444, events.get(0).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
565         Assert.assertSame(sunCenter, events.get(1).getEventDetector());
566         Assert.assertEquals(488.299210, events.get(1).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
567         Assert.assertSame(sunFull, events.get(2).getEventDetector());
568         Assert.assertEquals(517.527656, events.get(2).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
569         Assert.assertSame(sunFull, events.get(3).getEventDetector());
570         Assert.assertEquals(1749.292351, events.get(3).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
571         Assert.assertSame(sunCenter, events.get(4).getEventDetector());
572         Assert.assertEquals(1798.478948, events.get(4).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
573         Assert.assertSame(sunPartial, events.get(5).getEventDetector());
574         Assert.assertEquals(1845.966183, events.get(5).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
575 
576     }
577 
578     @Before
579     public void setUp() {
580         try {
581 
582             Utils.setDataRoot("regular-data");
583 
584             utc = TimeScalesFactory.getUTC();
585 
586             // Computation date
587             // Satellite position as circular parameters
588             mu = 3.9860047e14;
589 
590             initDate = new AbsoluteDate(new DateComponents(1969, 8, 28), TimeComponents.H00, utc);
591 
592             Vector3D position = new Vector3D(7.0e6, 1.0e6, 4.0e6);
593             Vector3D velocity = new Vector3D(-500.0, 8000.0, 1000.0);
594             initialOrbit = new EquinoctialOrbit(new PVCoordinates(position, velocity),
595                                                 FramesFactory.getEME2000(), initDate, mu);
596 
597 
598             // WGS84 Earth model
599             earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
600                                          Constants.WGS84_EARTH_FLATTENING,
601                                          FramesFactory.getITRF(IERSConventions.IERS_2010, true));
602 
603             // Create earth center pointing attitude provider
604             earthCenterAttitudeLaw = new BodyCenterPointing(initialOrbit.getFrame(), earth);
605 
606         } catch (OrekitException oe) {
607             Assert.fail(oe.getMessage());
608         }
609 
610     }
611 
612 
613     /** Handler for visibility event. */
614     private static class DihedralSunVisiHandler implements EventHandler<FieldOfViewDetector> {
615 
616         public Action eventOccurred(final SpacecraftState s, final FieldOfViewDetector detector,
617                                     final boolean increasing) {
618             if (increasing) {
619                 //System.err.println(" Sun visibility starts " + s.getDate());
620                 AbsoluteDate startVisiDate = new AbsoluteDate(new DateComponents(1969, 8, 28),
621                                                               new TimeComponents(1, 19, 00.381),
622                                                               TimeScalesFactory.getUTC());
623 
624                 Assert.assertTrue(s.getDate().durationFrom(startVisiDate) <= 1);
625                 return Action.CONTINUE;
626             } else {
627                 AbsoluteDate endVisiDate = new AbsoluteDate(new DateComponents(1969, 8, 28),
628                                                               new TimeComponents(1, 39 , 42.674),
629                                                               TimeScalesFactory.getUTC());
630                 Assert.assertTrue(s.getDate().durationFrom(endVisiDate) <= 1);
631                 //System.err.println(" Sun visibility ends at " + s.getDate());
632                 return Action.CONTINUE;//STOP;
633             }
634         }
635 
636     }
637 
638 }