1   /* Copyright 2002-2024 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.frames;
18  
19  import java.io.Serializable;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.List;
23  
24  import org.orekit.errors.OrekitException;
25  import org.orekit.errors.OrekitMessages;
26  
27  
28  /** Prototype frame that can be built from leaf to roots and later attached to a tree.
29   *
30   * <p>Regular {@link Frame} instances can be built only from a parent frame, i.e.
31   * the frames tree can be built only from root to leafs. In some cases, it may
32   * desirable to build a subset tree and attach it to the main tree after build
33   * time, which means the tree is built from leafs to root. This class allows
34   * building this subtree.</p>
35   * <p>
36   * During the build process, the {@link Frame} associated with each {@link OrphanFrame}
37   * is not available. It becomes available only once the {@link OrphanFrame} has been
38   * attached to the main tree, and at this time it can be used to compute
39   * {@link Transform transforms}.
40   * </p>
41   *
42   * @author Luc Maisonobe
43   * @since 6.0
44   */
45  public class OrphanFrame implements Serializable {
46  
47      /** Serializable UID. */
48      private static final long serialVersionUID = 20130409L;
49  
50      /** Instance name. */
51      private final String name;
52  
53      /** Children of the frame. */
54      private final List<OrphanFrame> children;
55  
56      /** Parent orphan frame. */
57      private OrphanFrame orphanParent;
58  
59      /** Provider for transform from parent frame to instance. */
60      private TransformProvider provider;
61  
62      /** Indicator for pseudo-inertial frames. */
63      private boolean pseudoInertial;
64  
65      /** Associated frame (available only once attached to the main frames tree). */
66      private Frame frame;
67  
68      /** Simple constructor.
69       * @param name name of the frame
70       */
71      public OrphanFrame(final String name) {
72          children  = new ArrayList<OrphanFrame>();
73          this.name = name;
74      }
75  
76      /** Add a child.
77       * <p>
78       * If a child is added after the instance has been attached, the child and
79       * all its tree will be attached immediately too.
80       * </p>
81       * @param child child to add
82       * @param transform transform from instance to child
83       * @param isPseudoInertial true if child is considered pseudo-inertial
84       * (i.e. suitable for propagating orbit)
85       */
86      public void addChild(final OrphanFrame child, final Transform transform,
87                           final boolean isPseudoInertial) {
88          addChild(child, new FixedTransformProvider(transform), isPseudoInertial);
89      }
90  
91      /** Add a child.
92       * <p>
93       * If a child is added after the instance has been attached, the child and
94       * all its tree will be attached immediately too.
95       * </p>
96       * @param child child to add
97       * @param transformProvider provider for transform from instance to child
98       * @param isPseudoInertial true if child is considered pseudo-inertial
99       * (i.e. suitable for propagating orbit)
100      */
101     public void addChild(final OrphanFrame child, final TransformProvider transformProvider,
102                          final boolean isPseudoInertial) {
103 
104         // safety check
105         if (child.orphanParent != null) {
106             throw new OrekitException(OrekitMessages.FRAME_ALREADY_ATTACHED,
107                                       child.name, child.orphanParent.name);
108         }
109 
110         children.add(child);
111         child.orphanParent   = this;
112         child.provider       = transformProvider;
113         child.pseudoInertial = isPseudoInertial;
114 
115         if (frame != null) {
116             // we are attaching a child after having attached the instance,
117             // we process the tree immediately
118             buildTree();
119         }
120 
121     }
122 
123     /** Attach the instance (and all its children down to leafs) to the main tree.
124      * @param parent parent frame to attach to
125      * @param transform transform from parent frame to instance
126      * @param isPseudoInertial true if frame is considered pseudo-inertial
127      * (i.e. suitable for propagating orbit)
128      */
129     public void attachTo(final Frame parent, final Transform transform,
130                          final boolean isPseudoInertial) {
131         attachTo(parent, new FixedTransformProvider(transform), isPseudoInertial);
132     }
133 
134     /** Attach the instance (and all its children down to leafs) to the main tree.
135      * @param parent parent frame to attach to
136      * @param transformProvider provider for transform from parent frame to instance
137      * @param isPseudoInertial true if frame is considered pseudo-inertial
138      * (i.e. suitable for propagating orbit)
139      */
140     public void attachTo(final Frame parent, final TransformProvider transformProvider,
141                          final boolean isPseudoInertial) {
142 
143         // safety check
144         if (orphanParent != null) {
145             throw new OrekitException(OrekitMessages.FRAME_ALREADY_ATTACHED,
146                                       name, orphanParent.name);
147         }
148 
149         // set up the attach point
150         final OrphanFrame op = new OrphanFrame(parent.getName());
151         op.frame = parent;
152         op.addChild(this, transformProvider, isPseudoInertial);
153 
154     }
155 
156     /** Get all children of the instance.
157      * @return unmodifiable list of children
158      */
159     public List<OrphanFrame> getChildren() {
160         return Collections.unmodifiableList(children);
161     }
162 
163     /** Get the associated {@link Frame frame}.
164      * @return associated frame
165      */
166     public Frame getFrame() {
167 
168         // safety check
169         if (frame == null) {
170             throw new OrekitException(OrekitMessages.FRAME_NOT_ATTACHED, name);
171         }
172 
173         return frame;
174 
175     }
176 
177     /** Recursively build the frames tree starting at instance, which is already associated.
178      */
179     private void buildTree() {
180         for (final OrphanFrame child : children) {
181 
182             if (child.frame == null) {
183 
184                 // associate the child with a regular frame
185                 child.frame = new Frame(frame, child.provider, child.name, child.pseudoInertial);
186 
187                 // recursively build the rest of the tree
188                 child.buildTree();
189 
190             }
191 
192         }
193     }
194 
195     /** {@inheritDoc} */
196     @Override
197     public String toString() {
198         return this.name;
199     }
200 
201 }