1 /* Copyright 2002-2019 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 java.io.Serializable;
20
21 import org.hipparchus.RealFieldElement;
22 import org.orekit.errors.OrekitIllegalArgumentException;
23 import org.orekit.errors.OrekitMessages;
24 import org.orekit.time.AbsoluteDate;
25 import org.orekit.time.FieldAbsoluteDate;
26
27
28 /** Tridimensional references frames class.
29 *
30 * <h1> Frame Presentation </h1>
31 * <p>This class is the base class for all frames in OREKIT. The frames are
32 * linked together in a tree with some specific frame chosen as the root of the tree.
33 * Each frame is defined by {@link Transform transforms} combining any number
34 * of translations and rotations from a reference frame which is its
35 * parent frame in the tree structure.</p>
36 * <p>When we say a {@link Transform transform} t is <em>from frame<sub>A</sub>
37 * to frame<sub>B</sub></em>, we mean that if the coordinates of some absolute
38 * vector (say the direction of a distant star for example) has coordinates
39 * u<sub>A</sub> in frame<sub>A</sub> and u<sub>B</sub> in frame<sub>B</sub>,
40 * then u<sub>B</sub>={@link
41 * Transform#transformVector(org.hipparchus.geometry.euclidean.threed.Vector3D)
42 * t.transformVector(u<sub>A</sub>)}.
43 * <p>The transforms may be constant or varying, depending on the implementation of
44 * the {@link TransformProvider transform provider} used to define the frame. For simple
45 * fixed transforms, using {@link FixedTransformProvider} is sufficient. For varying
46 * transforms (time-dependent or telemetry-based for example), it may be useful to define
47 * specific implementations of {@link TransformProvider transform provider}.</p>
48 *
49 * @author Guylaine Prat
50 * @author Luc Maisonobe
51 * @author Pascal Parraud
52 */
53 public class Frame implements Serializable {
54
55 /** Serializable UID. */
56 private static final long serialVersionUID = -6981146543760234087L;
57
58 /** Parent frame (only the root frame doesn't have a parent). */
59 private final Frame parent;
60
61 /** Depth of the frame with respect to tree root. */
62 private final int depth;
63
64 /** Provider for transform from parent frame to instance. */
65 private final TransformProvider transformProvider;
66
67 /** Instance name. */
68 private final String name;
69
70 /** Indicator for pseudo-inertial frames. */
71 private final boolean pseudoInertial;
72
73 /** Private constructor used only for the root frame.
74 * @param name name of the frame
75 * @param pseudoInertial true if frame is considered pseudo-inertial
76 * (i.e. suitable for propagating orbit)
77 */
78 private Frame(final String name, final boolean pseudoInertial) {
79 parent = null;
80 depth = 0;
81 transformProvider = new FixedTransformProvider(Transform.IDENTITY);
82 this.name = name;
83 this.pseudoInertial = pseudoInertial;
84 }
85
86 /** Build a non-inertial frame from its transform with respect to its parent.
87 * <p>calling this constructor is equivalent to call
88 * <code>{link {@link #Frame(Frame, Transform, String, boolean)
89 * Frame(parent, transform, name, false)}</code>.</p>
90 * @param parent parent frame (must be non-null)
91 * @param transform transform from parent frame to instance
92 * @param name name of the frame
93 * @exception IllegalArgumentException if the parent frame is null
94 */
95 public Frame.html#Frame">Frame(final Frame parent, final Transform transform, final String name)
96 throws IllegalArgumentException {
97 this(parent, transform, name, false);
98 }
99
100 /** Build a non-inertial frame from its transform with respect to its parent.
101 * <p>calling this constructor is equivalent to call
102 * <code>{link {@link #Frame(Frame, Transform, String, boolean)
103 * Frame(parent, transform, name, false)}</code>.</p>
104 * @param parent parent frame (must be non-null)
105 * @param transformProvider provider for transform from parent frame to instance
106 * @param name name of the frame
107 * @exception IllegalArgumentException if the parent frame is null
108 */
109 public Frame.html#Frame">Frame(final Frame parent, final TransformProvider transformProvider, final String name)
110 throws IllegalArgumentException {
111 this(parent, transformProvider, name, false);
112 }
113
114 /** Build a frame from its transform with respect to its parent.
115 * <p>The convention for the transform is that it is from parent
116 * frame to instance. This means that the two following frames
117 * are similar:</p>
118 * <pre>
119 * Frame frame1 = new Frame(FramesFactory.getGCRF(), new Transform(t1, t2));
120 * Frame frame2 = new Frame(new Frame(FramesFactory.getGCRF(), t1), t2);
121 * </pre>
122 * @param parent parent frame (must be non-null)
123 * @param transform transform from parent frame to instance
124 * @param name name of the frame
125 * @param pseudoInertial true if frame is considered pseudo-inertial
126 * (i.e. suitable for propagating orbit)
127 * @exception IllegalArgumentException if the parent frame is null
128 */
129 public Frame.html#Frame">Frame(final Frame parent, final Transform transform, final String name,
130 final boolean pseudoInertial)
131 throws IllegalArgumentException {
132 this(parent, new FixedTransformProvider(transform), name, pseudoInertial);
133 }
134
135 /** Build a frame from its transform with respect to its parent.
136 * <p>The convention for the transform is that it is from parent
137 * frame to instance. This means that the two following frames
138 * are similar:</p>
139 * <pre>
140 * Frame frame1 = new Frame(FramesFactory.getGCRF(), new Transform(t1, t2));
141 * Frame frame2 = new Frame(new Frame(FramesFactory.getGCRF(), t1), t2);
142 * </pre>
143 * @param parent parent frame (must be non-null)
144 * @param transformProvider provider for transform from parent frame to instance
145 * @param name name of the frame
146 * @param pseudoInertial true if frame is considered pseudo-inertial
147 * (i.e. suitable for propagating orbit)
148 * @exception IllegalArgumentException if the parent frame is null
149 */
150 public Frame.html#Frame">Frame(final Frame parent, final TransformProvider transformProvider, final String name,
151 final boolean pseudoInertial)
152 throws IllegalArgumentException {
153
154 if (parent == null) {
155 throw new OrekitIllegalArgumentException(OrekitMessages.NULL_PARENT_FOR_FRAME, name);
156 }
157 this.parent = parent;
158 this.depth = parent.depth + 1;
159 this.transformProvider = transformProvider;
160 this.name = name;
161 this.pseudoInertial = pseudoInertial;
162
163 }
164
165 /** Get the name.
166 * @return the name
167 */
168 public String getName() {
169 return this.name;
170 }
171
172 /** Check if the frame is pseudo-inertial.
173 * <p>Pseudo-inertial frames are frames that do have a linear motion and
174 * either do not rotate or rotate at a very low rate resulting in
175 * neglectible inertial forces. This means they are suitable for orbit
176 * definition and propagation using Newtonian mechanics. Frames that are
177 * <em>not</em> pseudo-inertial are <em>not</em> suitable for orbit
178 * definition and propagation.</p>
179 * @return true if frame is pseudo-inertial
180 */
181 public boolean isPseudoInertial() {
182 return pseudoInertial;
183 }
184
185 /** New definition of the java.util toString() method.
186 * @return the name
187 */
188 public String toString() {
189 return this.name;
190 }
191
192 /** Get the parent frame.
193 * @return parent frame
194 */
195 public Frame getParent() {
196 return parent;
197 }
198
199 /** Get the depth of the frame.
200 * <p>
201 * The depth of a frame is the number of parents frame between
202 * it and the frames tree root. It is 0 for the root frame, and
203 * the depth of a frame is the depth of its parent frame plus one.
204 * </p>
205 * @return depth of the frame
206 */
207 public int getDepth() {
208 return depth;
209 }
210
211 /** Get the n<sup>th</sup> ancestor of the frame.
212 * @param n index of the ancestor (0 is the instance, 1 is its parent,
213 * 2 is the parent of its parent...)
214 * @return n<sup>th</sup> ancestor of the frame (must be between 0
215 * and the depth of the frame)
216 * @exception IllegalArgumentException if n is larger than the depth
217 * of the instance
218 */
219 public Frame getAncestor(final int n) throws IllegalArgumentException {
220
221 // safety check
222 if (n > depth) {
223 throw new OrekitIllegalArgumentException(OrekitMessages.FRAME_NO_NTH_ANCESTOR,
224 name, depth, n);
225 }
226
227 // go upward to find ancestor
228 Frame current = this;
229 for (int i = 0; i < n; ++i) {
230 current = current.parent;
231 }
232
233 return current;
234
235 }
236
237 /** Get the transform from the instance to another frame.
238 * @param destination destination frame to which we want to transform vectors
239 * @param date the date (can be null if it is sure than no date dependent frame is used)
240 * @return transform from the instance to the destination frame
241 */
242 public Transform getTransformTo(final Frame destination, final AbsoluteDate date) {
243
244 if (this == destination) {
245 // shortcut for special case that may be frequent
246 return Transform.IDENTITY;
247 }
248
249 // common ancestor to both frames in the frames tree
250 final Frame common = findCommon(this, destination);
251
252 // transform from common to instance
253 Transform commonToInstance = Transform.IDENTITY;
254 for (Frame frame = this; frame != common; frame = frame.parent) {
255 commonToInstance =
256 new Transform(date, frame.transformProvider.getTransform(date), commonToInstance);
257 }
258
259 // transform from destination up to common
260 Transform commonToDestination = Transform.IDENTITY;
261 for (Frame frame = destination; frame != common; frame = frame.parent) {
262 commonToDestination =
263 new Transform(date, frame.transformProvider.getTransform(date), commonToDestination);
264 }
265
266 // transform from instance to destination via common
267 return new Transform(date, commonToInstance.getInverse(), commonToDestination);
268
269 }
270
271 /** Get the transform from the instance to another frame.
272 * @param destination destination frame to which we want to transform vectors
273 * @param date the date (can be null if it is sure than no date dependent frame is used)
274 * @param <T> the type of the field elements
275 * @return transform from the instance to the destination frame
276 */
277 public <T extends RealFieldElement<T>> FieldTransform<T> getTransformTo(final Frame destination, final FieldAbsoluteDate<T> date) {
278
279 if (this == destination) {
280 // shortcut for special case that may be frequent
281 return FieldTransform.getIdentity(date.getField());
282 }
283
284 // common ancestor to both frames in the frames tree
285 final Frame common = findCommon(this, destination);
286
287 // transform from common to instance
288 FieldTransform<T> commonToInstance = FieldTransform.getIdentity(date.getField());
289 for (Frame frame = this; frame != common; frame = frame.parent) {
290 commonToInstance =
291 new FieldTransform<>(date, frame.transformProvider.getTransform(date), commonToInstance);
292 }
293
294 // transform from destination up to common
295 FieldTransform<T> commonToDestination = FieldTransform.getIdentity(date.getField());
296 for (Frame frame = destination; frame != common; frame = frame.parent) {
297 commonToDestination =
298 new FieldTransform<>(date, frame.transformProvider.getTransform(date), commonToDestination);
299 }
300
301 // transform from instance to destination via common
302 return new FieldTransform<>(date, commonToInstance.getInverse(), commonToDestination);
303
304 }
305
306 /** Get the provider for transform from parent frame to instance.
307 * @return provider for transform from parent frame to instance
308 */
309 public TransformProvider getTransformProvider() {
310 return transformProvider;
311 }
312
313 /** Find the deepest common ancestor of two frames in the frames tree.
314 * @param from origin frame
315 * @param to destination frame
316 * @return an ancestor frame of both <code>from</code> and <code>to</code>
317 */
318 private static FrameFrame">Frame">Frame findCommon(final FrameFrame">Frame from, final Frame to) {
319
320 // select deepest frames that could be the common ancestor
321 Frame currentF = from.depth > to.depth ? from.getAncestor(from.depth - to.depth) : from;
322 Frame currentT = from.depth > to.depth ? to : to.getAncestor(to.depth - from.depth);
323
324 // go upward until we find a match
325 while (currentF != currentT) {
326 currentF = currentF.parent;
327 currentT = currentT.parent;
328 }
329
330 return currentF;
331
332 }
333
334 /** Determine if a Frame is a child of another one.
335 * @param potentialAncestor supposed ancestor frame
336 * @return true if the potentialAncestor belongs to the
337 * path from instance to the root frame, excluding itself
338 */
339 public boolean isChildOf(final Frame potentialAncestor) {
340 if (depth <= potentialAncestor.depth) {
341 return false;
342 }
343 return getAncestor(depth - potentialAncestor.depth) == potentialAncestor;
344 }
345
346 /** Get the unique root frame.
347 * @return the unique instance of the root frame
348 */
349 protected static Frame getRoot() {
350 return LazyRootHolder.INSTANCE;
351 }
352
353 /** Get a new version of the instance, frozen with respect to a reference frame.
354 * <p>
355 * Freezing a frame consist in computing its position and orientation with respect
356 * to another frame at some freezing date and fixing them so they do not depend
357 * on time anymore. This means the frozen frame is fixed with respect to the
358 * reference frame.
359 * </p>
360 * <p>
361 * One typical use of this method is to compute an inertial launch reference frame
362 * by freezing a {@link TopocentricFrame topocentric frame} at launch date
363 * with respect to an inertial frame. Another use is to freeze an equinox-related
364 * celestial frame at a reference epoch date.
365 * </p>
366 * <p>
367 * Only the frame returned by this method is frozen, the instance by itself
368 * is not affected by calling this method and still moves freely.
369 * </p>
370 * @param reference frame with respect to which the instance will be frozen
371 * @param freezingDate freezing date
372 * @param frozenName name of the frozen frame
373 * @return a frozen version of the instance
374 */
375 public Frameame getFrozenFrame(final Frame reference, final AbsoluteDate freezingDate,
376 final String frozenName) {
377 return new Frame(reference, reference.getTransformTo(this, freezingDate).freeze(),
378 frozenName, reference.isPseudoInertial());
379 }
380
381 // We use the Initialization on demand holder idiom to store
382 // the singletons, as it is both thread-safe, efficient (no
383 // synchronization) and works with all versions of java.
384
385 /** Holder for the root frame singleton. */
386 private static class LazyRootHolder {
387
388 /** Unique instance. */
389 private static final Frameme">Frame INSTANCE = new Frame(Predefined.GCRF.getName(), true) {
390
391 /** Serializable UID. */
392 private static final long serialVersionUID = -2654403496396721543L;
393
394 /** Replace the instance with a data transfer object for serialization.
395 * <p>
396 * This intermediate class serializes nothing.
397 * </p>
398 * @return data transfer object that will be serialized
399 */
400 private Object writeReplace() {
401 return new DataTransferObject();
402 }
403
404 };
405
406 /** Private constructor.
407 * <p>This class is a utility class, it should neither have a public
408 * nor a default constructor. This private constructor prevents
409 * the compiler from generating one automatically.</p>
410 */
411 private LazyRootHolder() {
412 }
413
414 }
415
416 /** Internal class used only for serialization. */
417 private static class DataTransferObject implements Serializable {
418
419 /** Serializable UID. */
420 private static final long serialVersionUID = 4067764035816491212L;
421
422 /** Simple constructor.
423 */
424 private DataTransferObject() {
425 }
426
427 /** Replace the deserialized data transfer object with a {@link FactoryManagedFrame}.
428 * @return replacement {@link FactoryManagedFrame}
429 */
430 private Object readResolve() {
431 return getRoot();
432 }
433
434 }
435
436 }