Skip to content

Commit

Permalink
Fixed compatibility between v10.0 and v10.1.
Browse files Browse the repository at this point in the history
  • Loading branch information
BryanCazabonne committed Feb 14, 2020
1 parent e3de1f6 commit 2e50ad6
Show file tree
Hide file tree
Showing 8 changed files with 466 additions and 1 deletion.
52 changes: 52 additions & 0 deletions src/main/java/org/orekit/propagation/events/FieldOfView.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
package org.orekit.propagation.events;

import org.hipparchus.exception.LocalizedCoreFormats;
import org.hipparchus.geometry.enclosing.EnclosingBall;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.geometry.partitioning.Region;
import org.hipparchus.geometry.partitioning.RegionFactory;
import org.hipparchus.geometry.spherical.twod.S2Point;
import org.hipparchus.geometry.spherical.twod.Sphere2D;
import org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet;
import org.hipparchus.util.FastMath;
Expand Down Expand Up @@ -88,6 +90,56 @@ public FieldOfView(final Vector3D center, final Vector3D meridian,
meridian, insideRadius, n, margin);
}

/** Get the angular offset of target point with respect to the Field Of View Boundary.
* <p>
* The offset is roughly an angle with respect to the closest boundary point,
* corrected by the margin and using some approximation far from the Field Of View.
* It is positive if the target is outside of the Field Of view, negative inside,
* and zero if the point is exactly on the boundary (always taking the margin
* into account).
* </p>
* <p>
* As Field Of View can have complex shapes that may require long computation,
* when the target point can be proven to be outside of the Field Of View, a
* faster but approximate computation is done, that underestimates the offset.
* This approximation is only performed about 0.01 radians outside of the zone
* and is designed to still return a positive value if the full accurate computation
* would return a positive value. When target point is close to the zone (and
* furthermore when it is inside the zone), the full accurate computation is
* performed. This setup allows this offset to be used as a reliable way to
* detect Field Of View boundary crossings, which correspond to sign changes of
* the offset.
* </p>
* @param lineOfSight line of sight from the center of the Field Of View support
* unit sphere to the target in Field Of View canonical frame
* @return an angular offset negative if the target is visible within the Field Of
* View and positive if it is outside of the Field Of View, including the margin
* (note that this cannot take into account interposing bodies)
* @deprecated as of 10.1, replaced by {@link org.orekit.geometry.fov.FieldOfView#offsetFromBoundary(Vector3D, double, VisibilityTrigger)}
*/
@Deprecated
public double offsetFromBoundary(final Vector3D lineOfSight) {

final S2Point los = new S2Point(lineOfSight);
final SphericalPolygonsSet zone = getZone();
final EnclosingBall<Sphere2D, S2Point> cap = zone.getEnclosingCap();
final double margin = getMargin();

// for faster computation, we start using only the surrounding cap, to filter out
// far away points (which correspond to most of the points if the Field Of View is small)
final double crudeDistance = cap.getCenter().distance(los) - cap.getRadius();
if (crudeDistance - margin > FastMath.max(FastMath.abs(margin), 0.01)) {
// we know we are strictly outside of the zone,
// use the crude distance to compute the (positive) return value
return crudeDistance - margin;
}

// we are close, we need to compute carefully the exact offset;
// we project the point to the closest zone boundary
return zone.projectToBoundary(los).getOffset() - margin;

}

/** Create polygon.
* @param center Direction of the FOV center, in spacecraft frame
* @param axis1 FOV dihedral axis 1, in spacecraft frame
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ public class FieldOfViewDetector extends AbstractDetector<FieldOfViewDetector> {
* otherwise some short passes could be missed.</p>
* @param pvTarget Position/velocity provider of the considered target
* @param fov Field Of View
* @deprecated as of 10.1, replaced by {@link #FieldOfViewDetector(PVCoordinatesProvider, FieldOfView)}
*/
@Deprecated
public FieldOfViewDetector(final PVCoordinatesProvider pvTarget, final org.orekit.propagation.events.FieldOfView fov) {
this(pvTarget, 0.0, VisibilityTrigger.VISIBLE_AS_SOON_AS_PARTIALLY_IN_FOV, fov);
}

/** Build a new instance.
* <p>The maximal interval between distance to FOV boundary checks should
* be smaller than the half duration of the minimal pass to handle,
* otherwise some short passes could be missed.</p>
* @param pvTarget Position/velocity provider of the considered target
* @param fov Field Of View
* @since 10.1
*/
public FieldOfViewDetector(final PVCoordinatesProvider pvTarget, final FieldOfView fov) {
this(pvTarget, 0.0, VisibilityTrigger.VISIBLE_AS_SOON_AS_PARTIALLY_IN_FOV, fov);
Expand All @@ -71,7 +85,7 @@ public FieldOfViewDetector(final PVCoordinatesProvider pvTarget, final FieldOfVi
* @param radiusTarget radius of the target, considered to be a spherical body (m)
* @param trigger visibility trigger for spherical bodies
* @param fov Field Of View
* @since 10.0
* @since 10.1
*/
public FieldOfViewDetector(final PVCoordinatesProvider pvTarget, final double radiusTarget,
final VisibilityTrigger trigger, final FieldOfView fov) {
Expand All @@ -80,6 +94,25 @@ public FieldOfViewDetector(final PVCoordinatesProvider pvTarget, final double ra
pvTarget, radiusTarget, trigger, fov);
}

/** Build a new instance.
* <p>The maximal interval between distance to FOV boundary checks should
* be smaller than the half duration of the minimal pass to handle,
* otherwise some short passes could be missed.</p>
* @param pvTarget Position/velocity provider of the considered target
* @param radiusTarget radius of the target, considered to be a spherical body (m)
* @param trigger visibility trigger for spherical bodies
* @param fov Field Of View
* @since 10.0
* @deprecated as of 10.1, replaced by {@link #FieldOfViewDetector(PVCoordinatesProvider, double, VisibilityTrigger, FieldOfView)}
*/
@Deprecated
public FieldOfViewDetector(final PVCoordinatesProvider pvTarget, final double radiusTarget,
final VisibilityTrigger trigger, final org.orekit.propagation.events.FieldOfView fov) {
this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, DEFAULT_MAX_ITER,
new StopOnIncreasing<FieldOfViewDetector>(),
pvTarget, radiusTarget, trigger, fov);
}

/** Private constructor with full parameters.
* <p>
* This constructor is private as users are expected to use the builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ public class FootprintOverlapDetector extends AbstractDetector<FootprintOverlapD
* @param body body on which the geographic zone is defined
* @param zone geographic zone to consider
* @param samplingStep linear step used for sampling the geographic zone (in meters)
* @deprecated as of 10.1, replaced by {@link #FootprintOverlapDetector(FieldOfView, OneAxisEllipsoid, SphericalPolygonsSet, double)}
*/
@Deprecated
public FootprintOverlapDetector(final org.orekit.propagation.events.FieldOfView fov,
final OneAxisEllipsoid body,
final SphericalPolygonsSet zone,
final double samplingStep) {
this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, DEFAULT_MAX_ITER,
new StopOnIncreasing<FootprintOverlapDetector>(),
fov, body, zone, samplingStep, sample(body, zone, samplingStep));
}

/** Build a new instance.
* <p>The maximal interval between distance to FOV boundary checks should
* be smaller than the half duration of the minimal pass to handle,
* otherwise some short passes could be missed.</p>
* @param fov sensor field of view
* @param body body on which the geographic zone is defined
* @param zone geographic zone to consider
* @param samplingStep linear step used for sampling the geographic zone (in meters)
* @since 10.1
*/
public FootprintOverlapDetector(final FieldOfView fov,
final OneAxisEllipsoid body,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,26 @@ public class GroundFieldOfViewDetector extends AbstractDetector<GroundFieldOfVie
*
* @param frame the reference frame attached to the sensor.
* @param fov Field Of View of the sensor.
* @deprecated as of 10.1, replaced by {@link #GroundFieldOfViewDetector(Frame, FieldOfView)}
*/
@Deprecated
public GroundFieldOfViewDetector(final Frame frame,
final org.orekit.propagation.events.FieldOfView fov) {
this(DEFAULT_MAXCHECK, DEFAULT_THRESHOLD, DEFAULT_MAX_ITER,
new StopOnIncreasing<GroundFieldOfViewDetector>(),
frame, fov);
}

/**
* Build a new instance.
*
* <p>The maximal interval between distance to FOV boundary checks should be
* smaller than the half duration of the minimal pass to handle, otherwise
* some short passes could be missed.</p>
*
* @param frame the reference frame attached to the sensor.
* @param fov Field Of View of the sensor.
* @since 10.1
*/
public GroundFieldOfViewDetector(final Frame frame,
final FieldOfView fov) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,163 @@ public void testElliptical() {

}

@Test
public void testDihedralFielOfViewDeprecated() {

// Definition of initial conditions with position and velocity
//------------------------------------------------------------

// Extrapolator definition
KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);

// Event definition : square field of view, along X axis, aperture 68°
final double halfAperture = FastMath.toRadians(0.5 * 68.0);
final double maxCheck = 60.;
final double threshold = 1.0e-10;
final PVCoordinatesProvider sunPV = CelestialBodyFactory.getSun();
final Vector3D center = Vector3D.PLUS_I;
final Vector3D axis1 = Vector3D.PLUS_K;
final Vector3D axis2 = Vector3D.PLUS_J;
final double aperture1 = halfAperture;
final double aperture2 = halfAperture;

@SuppressWarnings("deprecation")
final EventDetector sunVisi =
new FieldOfViewDetector(sunPV, new org.orekit.propagation.events.FieldOfView(center, axis1, aperture1, axis2, aperture2, 0.0)).
withMaxCheck(maxCheck).
withThreshold(threshold).
withHandler(new DihedralSunVisiHandler());

// Add event to be detected
EventsLogger logger = new EventsLogger();
propagator.addEventDetector(logger.monitorDetector(sunVisi));

// Extrapolate from the initial to the final date
propagator.propagate(initDate.shiftedBy(6000.));

// Sun is in dihedra 1 between tB and tC and in dihedra1 between tA and tD
// dihedra 1 is entered and left from same side (dihedra angle increases from < -34° to about -31.6° max
// and then decreases again to < -34°)
// dihedra 2 is completely crossed (dihedra angle increases from < -34° to > +34°
final AbsoluteDate tA = new AbsoluteDate("1969-08-28T00:04:50.540686", utc);
final AbsoluteDate tB = new AbsoluteDate("1969-08-28T00:08:08.299196", utc);
final AbsoluteDate tC = new AbsoluteDate("1969-08-28T00:29:58.478894", utc);
final AbsoluteDate tD = new AbsoluteDate("1969-08-28T00:36:13.390275", utc);

List<LoggedEvent> events = logger.getLoggedEvents();
final AbsoluteDate t0 = events.get(0).getState().getDate();
final AbsoluteDate t1 = events.get(1).getState().getDate();
Assert.assertEquals(2, events.size());
Assert.assertEquals(0, t0.durationFrom(tB), 1.0e-6);
Assert.assertEquals(0, t1.durationFrom(tC), 1.0e-6);

for (double dt = 0; dt < 3600; dt += 10.0) {
AbsoluteDate t = initialOrbit.getDate().shiftedBy(dt);
double[] angles = dihedralAngles(center, axis1, axis2,
sunPV.getPVCoordinates(t, initialOrbit.getFrame()),
new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw).propagate(t));
if (t.compareTo(tA) < 0) {
// before tA, we are outside of both dihedras
Assert.assertTrue(angles[0] < -halfAperture);
Assert.assertTrue(angles[1] < -halfAperture);
} else if (t.compareTo(tB) < 0) {
// between tA and tB, we are inside dihedra 2 but still outside of dihedra 1
Assert.assertTrue(angles[0] < -halfAperture);
Assert.assertTrue(angles[1] > -halfAperture);
Assert.assertTrue(angles[1] < +halfAperture);
} else if (t.compareTo(tC) < 0) {
// between tB and tC, we are inside both dihedra 1 and dihedra 2
Assert.assertTrue(angles[0] > -halfAperture);
Assert.assertTrue(angles[0] < +halfAperture);
Assert.assertTrue(angles[1] > -halfAperture);
Assert.assertTrue(angles[1] < +halfAperture);
} else if (t.compareTo(tD) < 0) {
// between tC and tD, we are inside dihedra 2 but again outside of dihedra 1
Assert.assertTrue(angles[0] < -halfAperture);
Assert.assertTrue(angles[1] > -halfAperture);
Assert.assertTrue(angles[1] < +halfAperture);
} else {
// after tD, we are outside of both dihedras
Assert.assertTrue(angles[0] < -halfAperture);
Assert.assertTrue(angles[1] > +halfAperture);
}
}

}

@Test
public void testRadiusDeprecated() {

// Definition of initial conditions with position and velocity
//------------------------------------------------------------

// Extrapolator definition
KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, earthCenterAttitudeLaw);

// Event definition : square field of view, along X axis, aperture 68°
final double halfAperture = FastMath.toRadians(0.5 * 68.0);
final double maxCheck = 60.;
final double threshold = 1.0e-10;
final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
final Vector3D center = Vector3D.PLUS_I;
final Vector3D axis1 = Vector3D.PLUS_K;
final Vector3D axis2 = Vector3D.PLUS_J;
final double aperture1 = halfAperture;
final double aperture2 = halfAperture;
@SuppressWarnings("deprecation")
final org.orekit.propagation.events.FieldOfView fov = new org.orekit.propagation.events.FieldOfView(center, axis1, aperture1, axis2, aperture2, 0.0);

@SuppressWarnings("deprecation")
final EventDetector sunCenter =
new FieldOfViewDetector(sun, fov).
withMaxCheck(maxCheck).
withThreshold(threshold).
withHandler(new ContinueOnEvent<>());

@SuppressWarnings("deprecation")
final EventDetector sunFull =
new FieldOfViewDetector(sun, Constants.SUN_RADIUS,
VisibilityTrigger.VISIBLE_ONLY_WHEN_FULLY_IN_FOV,
fov).
withMaxCheck(maxCheck).
withThreshold(threshold).
withHandler(new ContinueOnEvent<>());

@SuppressWarnings("deprecation")
final EventDetector sunPartial =
new FieldOfViewDetector(sun, Constants.SUN_RADIUS,
VisibilityTrigger.VISIBLE_AS_SOON_AS_PARTIALLY_IN_FOV,
fov).
withMaxCheck(maxCheck).
withThreshold(threshold).
withHandler(new ContinueOnEvent<>());

// Add event to be detected
EventsLogger logger = new EventsLogger();
propagator.addEventDetector(logger.monitorDetector(sunCenter));
propagator.addEventDetector(logger.monitorDetector(sunFull));
propagator.addEventDetector(logger.monitorDetector(sunPartial));

// Extrapolate from the initial to the final date
propagator.propagate(initDate.shiftedBy(6000.));

List<LoggedEvent> events = logger.getLoggedEvents();
Assert.assertEquals(6, events.size());
Assert.assertSame(sunPartial, events.get(0).getEventDetector());
Assert.assertEquals(460.884444, events.get(0).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
Assert.assertSame(sunCenter, events.get(1).getEventDetector());
Assert.assertEquals(488.299210, events.get(1).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
Assert.assertSame(sunFull, events.get(2).getEventDetector());
Assert.assertEquals(517.527656, events.get(2).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
Assert.assertSame(sunFull, events.get(3).getEventDetector());
Assert.assertEquals(1749.292351, events.get(3).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
Assert.assertSame(sunCenter, events.get(4).getEventDetector());
Assert.assertEquals(1798.478948, events.get(4).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);
Assert.assertSame(sunPartial, events.get(5).getEventDetector());
Assert.assertEquals(1845.966183, events.get(5).getState().getDate().durationFrom(initialOrbit.getDate()), 1.0e-6);

}

@Before
public void setUp() {
try {
Expand Down
Loading

0 comments on commit 2e50ad6

Please sign in to comment.