1   /* Copyright 2022-2025 Romain Serra
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 org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
21  import org.hipparchus.util.FastMath;
22  import org.orekit.propagation.FieldSpacecraftState;
23  import org.orekit.propagation.events.handlers.FieldEventHandler;
24  import org.orekit.utils.ExtendedPositionProvider;
25  
26  /**
27   * Event detector for eclipses from a single, infinitely-distant light source, occulted by a spherical central body.
28   * The shadow region is cylindrical, a model less accurate than a conical one but more computationally-performant.
29   * <p>
30   *     The so-called g function is negative in eclipse, positive otherwise.
31   * </p>
32   * @author Romain Serra
33   * @see FieldEclipseDetector
34   * @see CylindricalShadowEclipseDetector
35   * @since 12.
36   *
37   */
38  public class FieldCylindricalShadowEclipseDetector<T extends CalculusFieldElement<T>>
39      extends FieldAbstractDetector<FieldCylindricalShadowEclipseDetector<T>, T> {
40  
41      /** Direction provider for the occulted light source i.e. the Sun (whose shadow is approximated as if the body was infinitely distant). */
42      private final ExtendedPositionProvider sun;
43  
44      /** Radius of central, occulting body (approximated as spherical).
45       * Its center is assumed to be at the origin of the frame linked to the state. */
46      private final T occultingBodyRadius;
47  
48      /**
49       * Constructor.
50       * @param sun light source provider (infinitely distant)
51       * @param occultingBodyRadius occulting body radius
52       * @param eventDetectionSettings detection settings
53       * @param handler event handler
54       * @since 12.2
55       */
56      public FieldCylindricalShadowEclipseDetector(final ExtendedPositionProvider sun,
57                                                   final T occultingBodyRadius,
58                                                   final FieldEventDetectionSettings<T> eventDetectionSettings,
59                                                   final FieldEventHandler<T> handler) {
60          super(eventDetectionSettings, handler);
61          this.sun = sun;
62          this.occultingBodyRadius = FastMath.abs(occultingBodyRadius);
63      }
64  
65      /**
66       * Constructor with default detection settings.
67       * @param sun light source provider
68       * @param occultingBodyRadius occulting body radius
69       * @param handler event handler
70       */
71      public FieldCylindricalShadowEclipseDetector(final ExtendedPositionProvider sun,
72                                                   final T occultingBodyRadius, final FieldEventHandler<T> handler) {
73          this(sun, occultingBodyRadius, new FieldEventDetectionSettings<>(occultingBodyRadius.getField(),
74              EventDetectionSettings.getDefaultEventDetectionSettings()), handler);
75      }
76  
77      /**
78       * Getter for occulting body radius.
79       * @return radius
80       */
81      public T getOccultingBodyRadius() {
82          return occultingBodyRadius;
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      public T g(final FieldSpacecraftState<T> s) {
88          final FieldVector3D<T> sunDirection = sun.getPosition(s.getDate(), s.getFrame()).normalize();
89          final FieldVector3D<T> position = s.getPosition();
90          final T dotProduct = position.dotProduct(sunDirection);
91          if (dotProduct.getReal() >= 0.) {
92              return position.getNorm().divide(occultingBodyRadius);
93          } else {
94              final T distanceToCylinderAxis = (position.subtract(sunDirection.scalarMultiply(dotProduct))).getNorm();
95              return distanceToCylinderAxis.divide(occultingBodyRadius).subtract(1.);
96          }
97      }
98  
99      /** {@inheritDoc} */
100     @Override
101     protected FieldCylindricalShadowEclipseDetector<T> create(final FieldEventDetectionSettings<T> detectionSettings,
102                                                               final FieldEventHandler<T> newHandler) {
103         return new FieldCylindricalShadowEclipseDetector<>(sun, occultingBodyRadius, detectionSettings, newHandler);
104     }
105 }