FieldOfView.java

  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. import org.hipparchus.exception.LocalizedCoreFormats;
  19. import org.hipparchus.geometry.enclosing.EnclosingBall;
  20. import org.hipparchus.geometry.euclidean.threed.Rotation;
  21. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  22. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  23. import org.hipparchus.geometry.partitioning.Region;
  24. import org.hipparchus.geometry.partitioning.RegionFactory;
  25. import org.hipparchus.geometry.spherical.twod.S2Point;
  26. import org.hipparchus.geometry.spherical.twod.Sphere2D;
  27. import org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet;
  28. import org.hipparchus.util.FastMath;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.geometry.fov.PolygonalFieldOfView;

  31. /** Class representing a spacecraft sensor Field Of View.
  32.  * <p>Fields Of View are zones defined on the unit sphere centered on the
  33.  * spacecraft. They can have any shape, they can be split in several
  34.  * non-connected patches and can have holes.</p>
  35.  * @see org.orekit.propagation.events.FootprintOverlapDetector
  36.  * @author Luc Maisonobe
  37.  * @since 7.1
  38.  * @deprecated as of 10.1, replaced by {@link PolygonalFieldOfView}
  39.  */
  40. @Deprecated
  41. public class FieldOfView extends PolygonalFieldOfView {

  42.     /** Build a new instance.
  43.      * @param zone interior of the Field Of View, in spacecraft frame
  44.      * @param margin angular margin to apply to the zone (if positive,
  45.      * the Field Of View will consider points slightly outside of the
  46.      * zone are still visible)
  47.      */
  48.     public FieldOfView(final SphericalPolygonsSet zone, final double margin) {
  49.         super(zone, margin);
  50.     }

  51.     /** Build a Field Of View with dihedral shape (i.e. rectangular shape).
  52.      * @param center Direction of the FOV center, in spacecraft frame
  53.      * @param axis1 FOV dihedral axis 1, in spacecraft frame
  54.      * @param halfAperture1 FOV dihedral half aperture angle 1,
  55.      * must be less than π/2, i.e. full dihedra must be smaller then
  56.      * an hemisphere
  57.      * @param axis2 FOV dihedral axis 2, in spacecraft frame
  58.      * @param halfAperture2 FOV dihedral half aperture angle 2,
  59.      * must be less than π/2, i.e. full dihedra must be smaller then
  60.      * an hemisphere
  61.      * @param margin angular margin to apply to the zone (if positive,
  62.      * the Field Of View will consider points slightly outside of the
  63.      * zone are still visible)
  64.      */
  65.     public FieldOfView(final Vector3D center,
  66.                        final Vector3D axis1, final double halfAperture1,
  67.                        final Vector3D axis2, final double halfAperture2,
  68.                        final double margin) {
  69.         super(createPolygon(center, axis1, halfAperture1, axis2, halfAperture2), margin);
  70.     }

  71.     /** Build Field Of View with a regular polygon shape.
  72.      * @param center center of the polygon (the center is in the inside part)
  73.      * @param meridian point defining the reference meridian for middle of first edge
  74.      * @param insideRadius distance of the edges middle points to the center
  75.      * (the polygon vertices will therefore be farther away from the center)
  76.      * @param n number of sides of the polygon
  77.      * @param margin angular margin to apply to the zone (if positive,
  78.      * the Field Of View will consider points slightly outside of the
  79.      * zone are still visible)
  80.      */
  81.     public FieldOfView(final Vector3D center, final Vector3D meridian,
  82.                        final double insideRadius, final int n, final double margin) {
  83.         super(center,
  84.               PolygonalFieldOfView.DefiningConeType.INSIDE_CONE_TOUCHING_POLYGON_AT_EDGES_MIDDLE,
  85.               meridian, insideRadius, n, margin);
  86.     }

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

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

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

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

  131.     }

  132.     /** Create polygon.
  133.      * @param center Direction of the FOV center, in spacecraft frame
  134.      * @param axis1 FOV dihedral axis 1, in spacecraft frame
  135.      * @param halfAperture1 FOV dihedral half aperture angle 1,
  136.      * must be less than π/2, i.e. full dihedra must be smaller then
  137.      * an hemisphere
  138.      * @param axis2 FOV dihedral axis 2, in spacecraft frame
  139.      * @param halfAperture2 FOV dihedral half aperture angle 2,
  140.      * must be less than π/2, i.e. full dihedra must be smaller then
  141.      * an hemisphere
  142.      * @return built polygon
  143.      */
  144.     private static SphericalPolygonsSet createPolygon(final Vector3D center,
  145.                                                       final Vector3D axis1, final double halfAperture1,
  146.                                                       final Vector3D axis2, final double halfAperture2) {
  147.         final RegionFactory<Sphere2D> factory = new RegionFactory<Sphere2D>();
  148.         final double tolerance = FastMath.max(FastMath.ulp(2.0 * FastMath.PI),
  149.                                               1.0e-12 * FastMath.max(halfAperture1, halfAperture2));
  150.         final Region<Sphere2D> dihedra1 = buildDihedra(factory, tolerance, center, axis1, halfAperture1);
  151.         final Region<Sphere2D> dihedra2 = buildDihedra(factory, tolerance, center, axis2, halfAperture2);
  152.         return (SphericalPolygonsSet) factory.intersection(dihedra1, dihedra2);
  153.     }

  154.     /** Build a dihedra.
  155.      * @param factory factory for regions
  156.      * @param tolerance tolerance below which points are considered equal
  157.      * @param center Direction of the FOV center, in spacecraft frame
  158.      * @param axis FOV dihedral axis, in spacecraft frame
  159.      * @param halfAperture FOV dihedral half aperture angle,
  160.      * must be less than π/2, i.e. full dihedra must be smaller then
  161.      * an hemisphere
  162.      * @return dihedra
  163.      */
  164.     private static Region<Sphere2D> buildDihedra(final RegionFactory<Sphere2D> factory,
  165.                                                  final double tolerance, final Vector3D center,
  166.                                                  final Vector3D axis, final double halfAperture) {
  167.         if (halfAperture > 0.5 * FastMath.PI) {
  168.             throw new OrekitException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE,
  169.                                       halfAperture, 0.0, 0.5 * FastMath.PI);
  170.         }

  171.         final Rotation r = new Rotation(axis, halfAperture, RotationConvention.VECTOR_OPERATOR);
  172.         final Vector3D normalCenterPlane = Vector3D.crossProduct(axis, center);
  173.         final Vector3D normalSidePlus    = r.applyInverseTo(normalCenterPlane);
  174.         final Vector3D normalSideMinus   = r.applyTo(normalCenterPlane.negate());

  175.         return factory.intersection(new SphericalPolygonsSet(normalSidePlus,  tolerance),
  176.                                     new SphericalPolygonsSet(normalSideMinus, tolerance));

  177.     }

  178. }