1   /* Copyright 2002-2018 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (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.frames;
18  
19  import org.hipparchus.Field;
20  import org.hipparchus.RealFieldElement;
21  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
22  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
23  import org.hipparchus.geometry.euclidean.threed.Rotation;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.time.AbsoluteDate;
26  import org.orekit.time.FieldAbsoluteDate;
27  import org.orekit.utils.FieldPVCoordinates;
28  import org.orekit.utils.PVCoordinates;
29  
30  /** Enumerate for different types of Local Orbital Frames.
31   * @author Luc Maisonobe
32   */
33  public enum LOFType {
34  
35      /** Constant for TNW frame
36       * (X axis aligned with velocity, Z axis aligned with orbital momentum).
37       * <p>
38       * The axes of this frame are parallel to the axes of the {@link #VNC} frame:
39       * <ul>
40       *   <li>X<sub>TNW</sub> =  X<sub>VNC</sub></li>
41       *   <li>Y<sub>TNW</sub> = -Z<sub>VNC</sub></li>
42       *   <li>Z<sub>TNW</sub> =  Y<sub>VNC</sub></li>
43       * </ul>
44       *
45       * @see #VNC
46       */
47      TNW {
48  
49          /** {@inheritDoc} */
50          public Rotation rotationFromInertial(final PVCoordinates pv) {
51              return new Rotation(pv.getVelocity(), pv.getMomentum(),
52                                  Vector3D.PLUS_I, Vector3D.PLUS_K);
53          }
54  
55          /** {@inheritDoc} */
56          public <T extends RealFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
57                                                                                       final FieldPVCoordinates<T> pv) {
58              return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(),
59                                         new FieldVector3D<>(field, Vector3D.PLUS_I),
60                                         new FieldVector3D<>(field, Vector3D.PLUS_K));
61          }
62  
63      },
64  
65      /** Constant for QSW frame
66       * (X axis aligned with position, Z axis aligned with orbital momentum).
67       * <p>
68       * This frame is also known as the {@link #LVLH} frame, both constants are equivalent.
69       * </p>
70       * <p>
71       * The axes of these frames are parallel to the axes of the {@link #VVLH} frame:
72       * <ul>
73       *   <li>X<sub>QSW/LVLH</sub> = -Z<sub>VVLH</sub></li>
74       *   <li>Y<sub>QSW/LVLH</sub> =  X<sub>VVLH</sub></li>
75       *   <li>Z<sub>QSW/LVLH</sub> = -Y<sub>VVLH</sub></li>
76       * </ul>
77       *
78       * @see #LVLH
79       * @see #VVLH
80       */
81      QSW {
82  
83          /** {@inheritDoc} */
84          public Rotation rotationFromInertial(final PVCoordinates pv) {
85              return new Rotation(pv.getPosition(), pv.getMomentum(),
86                                  Vector3D.PLUS_I, Vector3D.PLUS_K);
87          }
88  
89          /** {@inheritDoc} */
90          public <T extends RealFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
91                                                                                       final FieldPVCoordinates<T> pv) {
92              return new FieldRotation<>(pv.getPosition(), pv.getMomentum(),
93                                         new FieldVector3D<>(field, Vector3D.PLUS_I),
94                                         new FieldVector3D<>(field, Vector3D.PLUS_K));
95          }
96  
97      },
98  
99      /** Constant for Local Vertical, Local Horizontal frame
100      * (X axis aligned with position, Z axis aligned with orbital momentum).
101      * <p>
102      * This frame is also known as the {@link #QSW} frame, both constants are equivalent.
103      * </p>
104      * <p>
105      * The axes of these frames are parallel to the axes of the {@link #VVLH} frame:
106      * <ul>
107      *   <li>X<sub>LVLH/QSW</sub> = -Z<sub>VVLH</sub></li>
108      *   <li>Y<sub>LVLH/QSW</sub> =  X<sub>VVLH</sub></li>
109      *   <li>Z<sub>LVLH/QSW</sub> = -Y<sub>VVLH</sub></li>
110      * </ul>
111      *
112      * @see #QSW
113      * @see #VVLH
114      */
115     LVLH {
116 
117         /** {@inheritDoc} */
118         public Rotation rotationFromInertial(final PVCoordinates pv) {
119             return new Rotation(pv.getPosition(), pv.getMomentum(),
120                                 Vector3D.PLUS_I, Vector3D.PLUS_K);
121         }
122 
123         /** {@inheritDoc} */
124         public <T extends RealFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
125                                                                                      final FieldPVCoordinates<T> pv) {
126             return new FieldRotation<>(pv.getPosition(), pv.getMomentum(),
127                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
128                                        new FieldVector3D<>(field, Vector3D.PLUS_K));
129         }
130 
131     },
132 
133     /** Constant for Vehicle Velocity, Local Horizontal frame
134      * (Z axis aligned with opposite of position, Y axis aligned with opposite of orbital momentum).
135      * <p>
136      * The axes of this frame are parallel to the axes of both the {@link #QSW} and {@link #LVLH} frames:
137      * <ul>
138      *   <li>X<sub>VVLH</sub> =  Y<sub>QSW/LVLH</sub></li>
139      *   <li>Y<sub>VVLH</sub> = -Z<sub>QSW/LVLH</sub></li>
140      *   <li>Z<sub>VVLH</sub> = -X<sub>QSW/LVLH</sub></li>
141      * </ul>
142      *
143      * @see #QSW
144      * @see #LVLH
145      */
146     VVLH {
147 
148         /** {@inheritDoc} */
149         public Rotation rotationFromInertial(final PVCoordinates pv) {
150             return new Rotation(pv.getPosition(), pv.getMomentum(),
151                                 Vector3D.MINUS_K, Vector3D.MINUS_J);
152         }
153 
154         /** {@inheritDoc} */
155         public <T extends RealFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
156                                                                                      final FieldPVCoordinates<T> pv) {
157             return new FieldRotation<>(pv.getPosition(), pv.getMomentum(),
158                                        new FieldVector3D<>(field, Vector3D.MINUS_K),
159                                        new FieldVector3D<>(field, Vector3D.MINUS_J));
160         }
161 
162     },
163 
164     /** Constant for Velocity - Normal - Co-normal frame
165      * (X axis aligned with velocity, Y axis aligned with orbital momentum).
166      * <p>
167      * The axes of this frame are parallel to the axes of the {@link #TNW} frame:
168      * <ul>
169      *   <li>X<sub>VNC</sub> =  X<sub>TNW</sub></li>
170      *   <li>Y<sub>VNC</sub> =  Z<sub>TNW</sub></li>
171      *   <li>Z<sub>VNC</sub> = -Y<sub>TNW</sub></li>
172      * </ul>
173      *
174      * @see #TNW
175      */
176     VNC {
177 
178         /** {@inheritDoc} */
179         public Rotation rotationFromInertial(final PVCoordinates pv) {
180             return new Rotation(pv.getVelocity(), pv.getMomentum(),
181                                 Vector3D.PLUS_I, Vector3D.PLUS_J);
182         }
183 
184         @Override
185         public <T extends RealFieldElement<T>> FieldRotation<T> rotationFromInertial(final Field<T> field,
186                                                                                      final FieldPVCoordinates<T> pv) {
187             return new FieldRotation<>(pv.getVelocity(), pv.getMomentum(),
188                                        new FieldVector3D<>(field, Vector3D.PLUS_I),
189                                        new FieldVector3D<>(field, Vector3D.PLUS_J));
190         }
191 
192     };
193 
194     /** Get the transform from an inertial frame defining position-velocity and the local orbital frame.
195      * @param date current date
196      * @param pv position-velocity of the spacecraft in some inertial frame
197      * @return transform from the frame where position-velocity are defined to local orbital frame
198      */
199     public Transform transformFromInertial(final AbsoluteDate date, final PVCoordinates pv) {
200 
201         // compute the translation part of the transform
202         final Transform translation = new Transform(date, pv.negate());
203 
204         // compute the rotation part of the transform
205         final Rotation r = rotationFromInertial(pv);
206         final Vector3D p = pv.getPosition();
207         final Vector3D momentum = pv.getMomentum();
208         final Transform rotation =
209                 new Transform(date, r, new Vector3D(1.0 / p.getNormSq(), r.applyTo(momentum)));
210 
211         return new Transform(date, translation, rotation);
212 
213     }
214 
215     /** Get the transform from an inertial frame defining position-velocity and the local orbital frame.
216      * @param date current date
217      * @param pv position-velocity of the spacecraft in some inertial frame
218      * @param <T> type of the fiels elements
219      * @return transform from the frame where position-velocity are defined to local orbital frame
220      * @since 9.0
221      */
222     public <T extends RealFieldElement<T>> FieldTransform<T> transformFromInertial(final FieldAbsoluteDate<T> date,
223                                                                                    final FieldPVCoordinates<T> pv) {
224 
225         // compute the translation part of the transform
226         final FieldTransform<T> translation = new FieldTransform<>(date, pv.negate());
227 
228         // compute the rotation part of the transform
229         final FieldRotation<T> r = rotationFromInertial(date.getField(), pv);
230         final FieldVector3D<T> p = pv.getPosition();
231         final FieldVector3D<T> momentum = pv.getMomentum();
232         final FieldTransform<T> rotation =
233                 new FieldTransform<T>(date, r, new FieldVector3D<>(p.getNormSq().reciprocal(), r.applyTo(momentum)));
234 
235         return new FieldTransform<>(date, translation, rotation);
236 
237     }
238 
239     /** Get the rotation from inertial frame to local orbital frame.
240      * <p>
241      * This rotation does not include any time derivatives. If first
242      * time derivatives (i.e. rotation rate) is needed as well, the full
243      * {@link #transformFromInertial(AbsoluteDate, PVCoordinates) transformFromInertial}
244      * method must be called and the complete rotation transform must be extracted
245      * from it.
246      * </p>
247      * @param pv position-velocity of the spacecraft in some inertial frame
248      * @return rotation from inertial frame to local orbital frame
249      */
250     public abstract Rotation rotationFromInertial(PVCoordinates pv);
251 
252     /** Get the rotation from inertial frame to local orbital frame.
253      * <p>
254      * This rotation does not include any time derivatives. If first
255      * time derivatives (i.e. rotation rate) is needed as well, the full
256      * {@link #transformFromInertial(FieldAbsoluteDate, FieldPVCoordinates) transformFromInertial}
257      * method must be called and the complete rotation transform must be extracted
258      * from it.
259      * </p>
260      * @param field field to which the elements belong
261      * @param pv position-velocity of the spacecraft in some inertial frame
262      * @param <T> type of the field elements
263      * @return rotation from inertial frame to local orbital frame
264      * @since 9.0
265      */
266     public abstract <T extends RealFieldElement<T>> FieldRotation<T> rotationFromInertial(Field<T> field,
267                                                                                           FieldPVCoordinates<T> pv);
268 
269 }