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 }