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.util.concurrent.atomic.AtomicReference;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.orekit.errors.FrameAncestorException;
23 import org.orekit.errors.OrekitMessages;
24 import org.orekit.time.AbsoluteDate;
25 import org.orekit.time.FieldAbsoluteDate;
26
27
28 /** Frame whose transform from its parent can be updated.
29 * <p>This class allows to control the relative position of two parts
30 * of the global frames tree using any two frames in each part as
31 * control handles. Consider the following simplified frames tree as an
32 * example:</p>
33 * <pre>
34 * GCRF
35 * |
36 * --------------------------------
37 * | | |
38 * Sun satellite Earth
39 * | |
40 * on-board antenna ground station
41 * |
42 * tracking antenna
43 * </pre>
44 * <p>Tracking measurements really correspond to the link between the ground
45 * and on-board antennas. This is tightly linked to the transform between
46 * these two frames, however neither frame is the direct parent frame of the
47 * other one: the path involves four intermediate frames. When we process a
48 * measurement, what we really want to update is the transform that defines
49 * the satellite frame with respect to its parent GCRF frame.</p>
50 * <p>In order to implement the above case, the satellite frame is defined
51 * as an instance of this class and its {@link #updateTransform(Frame, Frame,
52 * Transform, AbsoluteDate) updateTransform} would be called each time we want
53 * to adjust the frame, i.e. each time we get a new measurement between the
54 * two antennas.</p>
55 * @author Luc Maisonobe
56 */
57 public class UpdatableFrame extends Frame {
58
59 /** Serializable UID. */
60 private static final long serialVersionUID = -2075893064211339303L;
61
62 /** Build a non-inertial frame from its transform with respect to its parent.
63 * <p>calling this constructor is equivalent to call
64 * {@link #UpdatableFrame(Frame, Transform, String, boolean)
65 * UpdatableFrame(parent, transform, name, false)}.</p>
66 * @param parent parent frame (must be non-null)
67 * @param transform transform from parent frame to instance
68 * @param name name of the frame
69 * @exception IllegalArgumentException if the parent frame is null
70 */
71 public UpdatableFrame(final Frame parent, final Transform transform, final String name)
72 throws IllegalArgumentException {
73 this(parent, transform, name, false);
74 }
75
76 /** Build a frame from its transform with respect to its parent.
77 * <p>The convention for the transform is that it is from parent
78 * frame to instance. This means that the two following frames
79 * are similar:</p>
80 * <pre>
81 * Frame frame1 = new Frame(FramesFactory.getGCRF(), new Transform(t1, t2));
82 * Frame frame2 = new Frame(new Frame(FramesFactory.getGCRF(), t1), t2);
83 * </pre>
84 * @param parent parent frame (must be non-null)
85 * @param transform transform from parent frame to instance
86 * @param name name of the frame
87 * @param pseudoInertial true if frame is considered pseudo-inertial
88 * (i.e. suitable for propagating orbit)
89 * @exception IllegalArgumentException if the parent frame is null
90 */
91 public UpdatableFrame(final Frame parent, final Transform transform, final String name,
92 final boolean pseudoInertial)
93 throws IllegalArgumentException {
94 super(parent, new UpdatableProvider(transform), name, pseudoInertial);
95 }
96
97 /** Update the transform from parent frame implicitly according to two other
98 * frames.
99
100 * <p>This method allows to control the relative position of two parts
101 * of the global frames tree using any two frames in each part as
102 * control handles. Consider the following simplified frames tree as an
103 * example:</p>
104 * <pre>
105 * GCRF
106 * |
107 * --------------------------------
108 * | | |
109 * Sun satellite Earth
110 * | |
111 * on-board antenna ground station
112 * |
113 * tracking antenna
114 * </pre>
115 * <p>Tracking measurements really correspond to the link between the ground
116 * and on-board antennas. This is tightly linked to the transform between
117 * these two frames, however neither frame is the direct parent frame of the
118 * other one: the path involves four intermediate frames. When we process a
119 * measurement, what we really want to update is the transform that defines
120 * the satellite frame with respect to its parent GCRF frame. This
121 * is the purpose of this method. This update is done by the following call,
122 * where <code>measurementTransform</code> represents the measurement as a
123 * simple translation transform between the two antenna frames:</p>
124 * <pre><code>
125 * satellite.updateTransform(onBoardAntenna, trackingAntenna,
126 * measurementTransform, date);
127 * </code></pre>
128 * <p>One way to represent the behavior of the method is to consider the
129 * sub-tree rooted at the instance on one hand (satellite and on-board antenna
130 * in the example above) and the tree containing all the other frames on the
131 * other hand (GCRF, Sun, Earth, ground station, tracking antenna).
132 * Both tree are considered as two solid sets linked together by a flexible
133 * spring, which is the transform we want to update. The method stretches the
134 * spring to make sure the transform between the two specified frames (one in
135 * each tree part) matches the specified transform.</p>
136 * @param f1 first control frame (may be the instance itself)
137 * @param f2 second control frame (may be the instance itself)
138 * @param f1Tof2 desired transform from first to second control frame
139 * @param date date of the transform
140 */
141 public void updateTransform(final Frame f1, final Frame f2, final Transform f1Tof2,
142 final AbsoluteDate date) {
143
144 Frame fA = f1;
145 Frame fB = f2;
146 Transform fAtoB = f1Tof2;
147
148 // make sure f1 is not a child of the instance
149 if (fA.isChildOf(this) || fA == this) {
150
151 if (fB.isChildOf(this) || fB == this) {
152 throw new FrameAncestorException(OrekitMessages.FRAME_ANCESTOR_OF_BOTH_FRAMES,
153 getName(), fA.getName(), fB.getName());
154 }
155
156 // swap f1 and f2 to make sure the child is f2
157 final Frame tmp = fA;
158 fA = fB;
159 fB = tmp;
160 fAtoB = fAtoB.getInverse();
161
162 } else if (!(fB.isChildOf(this) || fB == this)) {
163 throw new FrameAncestorException(OrekitMessages.FRAME_ANCESTOR_OF_NEITHER_FRAME,
164 getName(), fA.getName(), fB.getName());
165 }
166
167 // rebuild the transform by traveling from parent to self
168 // WITHOUT using the existing provider from parent to self that will be updated
169 final Transform parentTofA = getParent().getTransformTo(fA, date);
170 final Transform fBtoSelf = fB.getTransformTo(this, date);
171 final Transform fAtoSelf = new Transform(date, fAtoB, fBtoSelf);
172 final Transform parentToSelf = new Transform(date, parentTofA, fAtoSelf);
173
174 // update the existing provider from parent to self
175 ((UpdatableProvider) getTransformProvider()).setTransform(parentToSelf);
176
177 }
178
179 /** Local provider for transforms. */
180 private static class UpdatableProvider implements TransformProvider {
181
182 /** Serializable UID. */
183 private static final long serialVersionUID = 4436954500689776331L;
184
185 /** Current transform. */
186 private AtomicReference<Transform> transform;
187
188 /** Simple constructor.
189 * @param transform initial value of the transform
190 */
191 UpdatableProvider(final Transform transform) {
192 this.transform = new AtomicReference<Transform>(transform);
193 }
194
195 /** Update the transform from the parent frame to the instance.
196 * @param transform new transform from parent frame to instance
197 */
198 public void setTransform(final Transform transform) {
199 this.transform.set(transform);
200 }
201
202 /** {@inheritDoc} */
203 public Transform getTransform(final AbsoluteDate date) {
204 return transform.get();
205 }
206
207 /** {@inheritDoc} */
208 @Override
209 public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
210 return new FieldTransform<>(date.getField(), transform.get());
211 }
212 }
213
214 }