1   /* Copyright 2002-2021 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.attitudes;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.bodies.BodyShape;
26  import org.orekit.bodies.FieldGeodeticPoint;
27  import org.orekit.bodies.GeodeticPoint;
28  import org.orekit.frames.FieldTransform;
29  import org.orekit.frames.Frame;
30  import org.orekit.frames.Transform;
31  import org.orekit.time.AbsoluteDate;
32  import org.orekit.time.FieldAbsoluteDate;
33  import org.orekit.utils.CartesianDerivativesFilter;
34  import org.orekit.utils.FieldPVCoordinatesProvider;
35  import org.orekit.utils.PVCoordinatesProvider;
36  import org.orekit.utils.TimeStampedFieldPVCoordinates;
37  import org.orekit.utils.TimeStampedPVCoordinates;
38  
39  /**
40   * This class handles nadir pointing attitude provider.
41  
42   * <p>
43   * This class represents the attitude provider where the satellite z axis is
44   * pointing to the vertical of the ground point under satellite.</p>
45   * <p>
46   * The object <code>NadirPointing</code> is guaranteed to be immutable.
47   * </p>
48   * @see     GroundPointing
49   * @author V&eacute;ronique Pommier-Maurussane
50   */
51  public class NadirPointing extends GroundPointing {
52  
53      /** Body shape.  */
54      private final BodyShape shape;
55  
56      /** Creates new instance.
57       * @param inertialFrame frame in which orbital velocities are computed
58       * @param shape Body shape
59       * @since 7.1
60       */
61      public NadirPointing(final Frame inertialFrame, final BodyShape shape) {
62          // Call constructor of superclass
63          super(inertialFrame, shape.getBodyFrame());
64          this.shape = shape;
65      }
66  
67      /** {@inheritDoc} */
68      public TimeStampedPVCoordinates getTargetPV(final PVCoordinatesProvider pvProv,
69                                                  final AbsoluteDate date, final Frame frame) {
70  
71          // transform from specified reference frame to body frame
72          final Transform refToBody = frame.getTransformTo(shape.getBodyFrame(), date);
73  
74          // sample intersection points in current date neighborhood
75          final double h  = 0.01;
76          final List<TimeStampedPVCoordinates> sample = new ArrayList<>();
77          sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-2 * h), frame), refToBody.shiftedBy(-2 * h)));
78          sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-h),     frame), refToBody.shiftedBy(-h)));
79          sample.add(nadirRef(pvProv.getPVCoordinates(date,                   frame), refToBody));
80          sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+h),     frame), refToBody.shiftedBy(+h)));
81          sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+2 * h), frame), refToBody.shiftedBy(+2 * h)));
82  
83          // use interpolation to compute properly the time-derivatives
84          return TimeStampedPVCoordinates.interpolate(date, CartesianDerivativesFilter.USE_P, sample);
85  
86      }
87  
88      /** {@inheritDoc} */
89      public <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> getTargetPV(final FieldPVCoordinatesProvider<T> pvProv,
90                                                                                          final FieldAbsoluteDate<T> date,
91                                                                                          final Frame frame) {
92  
93          // transform from specified reference frame to body frame
94          final FieldTransform<T> refToBody = frame.getTransformTo(shape.getBodyFrame(), date);
95  
96          // sample intersection points in current date neighborhood
97          final double h  = 0.01;
98          final List<TimeStampedFieldPVCoordinates<T>> sample = new ArrayList<>();
99          sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-2 * h), frame), refToBody.shiftedBy(-2 * h)));
100         sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-h),     frame), refToBody.shiftedBy(-h)));
101         sample.add(nadirRef(pvProv.getPVCoordinates(date,                   frame), refToBody));
102         sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+h),     frame), refToBody.shiftedBy(+h)));
103         sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+2 * h), frame), refToBody.shiftedBy(+2 * h)));
104 
105         // use interpolation to compute properly the time-derivatives
106         return TimeStampedFieldPVCoordinates.interpolate(date, CartesianDerivativesFilter.USE_P, sample);
107 
108     }
109 
110     /** Compute ground point in nadir direction, in reference frame.
111      * @param scRef spacecraft coordinates in reference frame
112      * @param refToBody transform from reference frame to body frame
113      * @return intersection point in body frame (only the position is set!)
114      */
115     private TimeStampedPVCoordinates nadirRef(final TimeStampedPVCoordinates scRef, final Transform refToBody) {
116 
117         final Vector3D satInBodyFrame = refToBody.transformPosition(scRef.getPosition());
118 
119         // satellite position in geodetic coordinates
120         final GeodeticPoint gpSat = shape.transform(satInBodyFrame, getBodyFrame(), scRef.getDate());
121 
122         // nadir position in geodetic coordinates
123         final GeodeticPoint gpNadir = new GeodeticPoint(gpSat.getLatitude(), gpSat.getLongitude(), 0.0);
124 
125         // nadir point position in body frame
126         final Vector3D pNadirBody = shape.transform(gpNadir);
127 
128         // nadir point position in reference frame
129         final Vector3D pNadirRef = refToBody.getInverse().transformPosition(pNadirBody);
130 
131         return new TimeStampedPVCoordinates(scRef.getDate(), pNadirRef, Vector3D.ZERO, Vector3D.ZERO);
132 
133     }
134 
135     /** Compute ground point in nadir direction, in reference frame.
136      * @param scRef spacecraft coordinates in reference frame
137      * @param refToBody transform from reference frame to body frame
138      * @param <T> type of the field elements
139      * @return intersection point in body frame (only the position is set!)
140      * @since 9.0
141      */
142     private <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> nadirRef(final TimeStampedFieldPVCoordinates<T> scRef,
143                                                                                       final FieldTransform<T> refToBody) {
144 
145         final FieldVector3D<T> satInBodyFrame = refToBody.transformPosition(scRef.getPosition());
146 
147         // satellite position in geodetic coordinates
148         final FieldGeodeticPoint<T> gpSat = shape.transform(satInBodyFrame, getBodyFrame(), scRef.getDate());
149 
150         // nadir position in geodetic coordinates
151         final FieldGeodeticPoint<T> gpNadir = new FieldGeodeticPoint<>(gpSat.getLatitude(), gpSat.getLongitude(),
152                                                                        gpSat.getAltitude().getField().getZero());
153 
154         // nadir point position in body frame
155         final FieldVector3D<T> pNadirBody = shape.transform(gpNadir);
156 
157         // nadir point position in reference frame
158         final FieldVector3D<T> pNadirRef = refToBody.getInverse().transformPosition(pNadirBody);
159 
160         final FieldVector3D<T> zero = FieldVector3D.getZero(gpSat.getAltitude().getField());
161         return new TimeStampedFieldPVCoordinates<>(scRef.getDate(), pNadirRef, zero, zero);
162 
163     }
164 
165 }