OccultationEngine.java

  1. /* Copyright 2022-2025 Luc Maisonobe
  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.utils;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  20. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  21. import org.hipparchus.util.FastMath;
  22. import org.orekit.bodies.OneAxisEllipsoid;
  23. import org.orekit.propagation.FieldSpacecraftState;
  24. import org.orekit.propagation.SpacecraftState;

  25. /** Computation engine for occultation events.
  26.  * @author Luc Maisonobe
  27.  * @since 12.0
  28.  */
  29. public class OccultationEngine {

  30.     /** Occulting body. */
  31.     private final OneAxisEllipsoid occulting;

  32.     /** Occulted body. */
  33.     private final ExtendedPositionProvider occulted;

  34.     /** Occulted body radius (m). */
  35.     private final double occultedRadius;

  36.     /** Build a new occultation engine.
  37.      * @param occulted the body to be occulted
  38.      * @param occultedRadius the radius of the body to be occulted (m)
  39.      * @param occulting the occulting body
  40.      */
  41.     public OccultationEngine(final ExtendedPositionProvider occulted,  final double occultedRadius,
  42.                              final OneAxisEllipsoid occulting) {
  43.         this.occulted       = occulted;
  44.         this.occultedRadius = FastMath.abs(occultedRadius);
  45.         this.occulting      = occulting;
  46.     }

  47.     /** Getter for the occulting body.
  48.      * @return the occulting body
  49.      */
  50.     public OneAxisEllipsoid getOcculting() {
  51.         return occulting;
  52.     }

  53.     /** Getter for the occulted body.
  54.      * @return the occulted body
  55.      */
  56.     public ExtendedPositionProvider getOcculted() {
  57.         return occulted;
  58.     }

  59.     /** Getter for the occultedRadius.
  60.      * @return the occultedRadius
  61.      */
  62.     public double getOccultedRadius() {
  63.         return occultedRadius;
  64.     }

  65.     /** Compute the occultation angles as seen from a spacecraft.
  66.      * @param state the current state information: date, kinematics, attitude
  67.      * @return occultation angles
  68.      */
  69.     public OccultationAngles angles(final SpacecraftState state) {

  70.         final Vector3D psat  = state.getPosition(occulting.getBodyFrame());
  71.         final Vector3D pted  = occulted.getPosition(state.getDate(), occulting.getBodyFrame());
  72.         final Vector3D plimb = occulting.pointOnLimb(psat, pted);
  73.         final Vector3D ps    = psat.subtract(pted);
  74.         final Vector3D pi    = psat.subtract(plimb);
  75.         final double angle   = Vector3D.angle(ps, psat);
  76.         final double rs      = FastMath.asin(occultedRadius / ps.getNorm());
  77.         final double ro      = Vector3D.angle(pi, psat);
  78.         if (Double.isNaN(rs)) {
  79.             // we are inside the occulted body…
  80.             // set up dummy values consistent with full lighting (assuming occulted is the Sun)
  81.             return new OccultationAngles(FastMath.PI, 0.0, 0.0);
  82.         } else {
  83.             // regular case, we can compute limit angles as seen from spacecraft
  84.             return new OccultationAngles(angle, ro, rs);
  85.         }

  86.     }

  87.     /** Compute the occultation angles as seen from a spacecraft.
  88.      * @param state the current state information: date, kinematics, attitude
  89.      * @param <T> the type of the field elements
  90.      * @return occultation angles
  91.      */
  92.     public <T extends CalculusFieldElement<T>> FieldOccultationAngles<T> angles(final FieldSpacecraftState<T> state) {

  93.         final FieldVector3D<T> psat  = state.getPosition(occulting.getBodyFrame());
  94.         final FieldVector3D<T> pted  = occulted.getPosition(state.getDate(), occulting.getBodyFrame());
  95.         final FieldVector3D<T> plimb = occulting.pointOnLimb(psat, pted);
  96.         final FieldVector3D<T> ps    = psat.subtract(pted);
  97.         final FieldVector3D<T> pi    = psat.subtract(plimb);
  98.         final T                angle = FieldVector3D.angle(ps, psat);
  99.         final T                rs    = FastMath.asin(ps.getNorm().reciprocal().multiply(occultedRadius));
  100.         final T                ro    = FieldVector3D.angle(pi, psat);
  101.         if (rs.isNaN()) {
  102.             // we are inside the occulted body…
  103.             // set up dummy values consistent with full lighting (assuming occulted is the Sun)
  104.             final T zero = rs.getField().getZero();
  105.             return new FieldOccultationAngles<>(zero.newInstance(FastMath.PI), zero, zero);
  106.         } else {
  107.             // regular case, we can compute limit angles as seen from spacecraft
  108.             return new FieldOccultationAngles<>(angle, ro, rs);
  109.         }

  110.     }

  111.     /** Container for occultation angles.
  112.      * @since 12.0
  113.      */
  114.     public static class OccultationAngles {

  115.         /** Apparent separation between occulting and occulted directions. */
  116.         private final double separation;

  117.         /** Limb radius in occulting/occulted plane. */
  118.         private final double limbRadius;

  119.         /** Apparent radius of occulted body. */
  120.         private final double occultedApparentRadius;

  121.         /** Simple constructor.
  122.          * @param separation apparent separation between occulting and occulted directions (rad)
  123.          * @param limbRadius limb radius in occulting/occulted plane (rad)
  124.          * @param occultedApparentRadius apparent radius of occulted body (rad)
  125.          */
  126.         OccultationAngles(final double separation, final double limbRadius, final double occultedApparentRadius) {
  127.             this.separation             = separation;
  128.             this.limbRadius             = limbRadius;
  129.             this.occultedApparentRadius = occultedApparentRadius;
  130.         }

  131.         /** Get apparent separation between occulting and occulted directions.
  132.          * @return apparent separation between occulting and occulted directions (rad)
  133.          */
  134.         public double getSeparation() {
  135.             return separation;
  136.         }

  137.         /** Get limb radius in occulting/occulted plane.
  138.          * @return limb radius in occulting/occulted plane (rad)
  139.          */
  140.         public double getLimbRadius() {
  141.             return limbRadius;
  142.         }

  143.         /** Get apparent radius of occulted body.
  144.          * @return apparent radius of occulted body (rad)
  145.          */
  146.         public double getOccultedApparentRadius() {
  147.             return occultedApparentRadius;
  148.         }

  149.     }

  150.     /** Container for occultation angles.
  151.      * @param <T> the type of the field elements
  152.      * @since 12.0
  153.      */
  154.     public static class FieldOccultationAngles<T extends CalculusFieldElement<T>> {

  155.         /** Apparent separation between occulting and occulted directions. */
  156.         private final T separation;

  157.         /** Limb radius in occulting/occulted plane. */
  158.         private final T limbRadius;

  159.         /** Apparent radius of occulted body. */
  160.         private final T occultedApparentRadius;

  161.         /** Simple constructor.
  162.          * @param separation apparent separation between occulting and occulted directions (rad)
  163.          * @param limbRadius limb radius in occulting/occulted plane (rad)
  164.          * @param occultedApparentRadius apparent radius of occulted body (rad)
  165.          */
  166.         FieldOccultationAngles(final T separation, final T limbRadius, final T occultedApparentRadius) {
  167.             this.separation             = separation;
  168.             this.limbRadius             = limbRadius;
  169.             this.occultedApparentRadius = occultedApparentRadius;
  170.         }

  171.         /** Get apparent separation between occulting and occulted directions.
  172.          * @return apparent separation between occulting and occulted directions (rad)
  173.          */
  174.         public T getSeparation() {
  175.             return separation;
  176.         }

  177.         /** Get limb radius in occulting/occulted plane.
  178.          * @return limb radius in occulting/occulted plane (rad)
  179.          */
  180.         public T getLimbRadius() {
  181.             return limbRadius;
  182.         }

  183.         /** Get apparent radius of occulted body.
  184.          * @return apparent radius of occulted body (rad)
  185.          */
  186.         public T getOccultedApparentRadius() {
  187.             return occultedApparentRadius;
  188.         }

  189.     }

  190. }