UpdatableFrame.java
- /* Copyright 2002-2024 CS GROUP
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.frames;
- import java.util.concurrent.atomic.AtomicReference;
- import org.hipparchus.CalculusFieldElement;
- import org.orekit.errors.FrameAncestorException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.FieldAbsoluteDate;
- /** Frame whose transform from its parent can be updated.
- * <p>This class allows to control the relative position of two parts
- * of the global frames tree using any two frames in each part as
- * control handles. Consider the following simplified frames tree as an
- * example:</p>
- * <pre>
- * GCRF
- * |
- * --------------------------------
- * | | |
- * Sun satellite Earth
- * | |
- * on-board antenna ground station
- * |
- * tracking antenna
- * </pre>
- * <p>Tracking measurements really correspond to the link between the ground
- * and on-board antennas. This is tightly linked to the transform between
- * these two frames, however neither frame is the direct parent frame of the
- * other one: the path involves four intermediate frames. When we process a
- * measurement, what we really want to update is the transform that defines
- * the satellite frame with respect to its parent GCRF frame.</p>
- * <p>In order to implement the above case, the satellite frame is defined
- * as an instance of this class and its {@link #updateTransform(Frame, Frame,
- * Transform, AbsoluteDate) updateTransform} would be called each time we want
- * to adjust the frame, i.e. each time we get a new measurement between the
- * two antennas.</p>
- * @author Luc Maisonobe
- */
- public class UpdatableFrame extends Frame {
- /** Serializable UID. */
- private static final long serialVersionUID = -2075893064211339303L;
- /** Build a non-inertial frame from its transform with respect to its parent.
- * <p>calling this constructor is equivalent to call
- * {@link #UpdatableFrame(Frame, Transform, String, boolean)
- * UpdatableFrame(parent, transform, name, false)}.</p>
- * @param parent parent frame (must be non-null)
- * @param transform transform from parent frame to instance
- * @param name name of the frame
- * @exception IllegalArgumentException if the parent frame is null
- */
- public UpdatableFrame(final Frame parent, final Transform transform, final String name)
- throws IllegalArgumentException {
- this(parent, transform, name, false);
- }
- /** Build a frame from its transform with respect to its parent.
- * <p>The convention for the transform is that it is from parent
- * frame to instance. This means that the two following frames
- * are similar:</p>
- * <pre>
- * Frame frame1 = new Frame(FramesFactory.getGCRF(), new Transform(t1, t2));
- * Frame frame2 = new Frame(new Frame(FramesFactory.getGCRF(), t1), t2);
- * </pre>
- * @param parent parent frame (must be non-null)
- * @param transform transform from parent frame to instance
- * @param name name of the frame
- * @param pseudoInertial true if frame is considered pseudo-inertial
- * (i.e. suitable for propagating orbit)
- * @exception IllegalArgumentException if the parent frame is null
- */
- public UpdatableFrame(final Frame parent, final Transform transform, final String name,
- final boolean pseudoInertial)
- throws IllegalArgumentException {
- super(parent, new UpdatableProvider(transform), name, pseudoInertial);
- }
- /** Update the transform from parent frame implicitly according to two other
- * frames.
- * <p>This method allows to control the relative position of two parts
- * of the global frames tree using any two frames in each part as
- * control handles. Consider the following simplified frames tree as an
- * example:</p>
- * <pre>
- * GCRF
- * |
- * --------------------------------
- * | | |
- * Sun satellite Earth
- * | |
- * on-board antenna ground station
- * |
- * tracking antenna
- * </pre>
- * <p>Tracking measurements really correspond to the link between the ground
- * and on-board antennas. This is tightly linked to the transform between
- * these two frames, however neither frame is the direct parent frame of the
- * other one: the path involves four intermediate frames. When we process a
- * measurement, what we really want to update is the transform that defines
- * the satellite frame with respect to its parent GCRF frame. This
- * is the purpose of this method. This update is done by the following call,
- * where <code>measurementTransform</code> represents the measurement as a
- * simple translation transform between the two antenna frames:</p>
- * <pre><code>
- * satellite.updateTransform(onBoardAntenna, trackingAntenna,
- * measurementTransform, date);
- * </code></pre>
- * <p>One way to represent the behavior of the method is to consider the
- * sub-tree rooted at the instance on one hand (satellite and on-board antenna
- * in the example above) and the tree containing all the other frames on the
- * other hand (GCRF, Sun, Earth, ground station, tracking antenna).
- * Both tree are considered as two solid sets linked together by a flexible
- * spring, which is the transform we want to update. The method stretches the
- * spring to make sure the transform between the two specified frames (one in
- * each tree part) matches the specified transform.</p>
- * @param f1 first control frame (may be the instance itself)
- * @param f2 second control frame (may be the instance itself)
- * @param f1Tof2 desired transform from first to second control frame
- * @param date date of the transform
- */
- public void updateTransform(final Frame f1, final Frame f2, final Transform f1Tof2,
- final AbsoluteDate date) {
- Frame fA = f1;
- Frame fB = f2;
- Transform fAtoB = f1Tof2;
- // make sure f1 is not a child of the instance
- if (fA.isChildOf(this) || fA == this) {
- if (fB.isChildOf(this) || fB == this) {
- throw new FrameAncestorException(OrekitMessages.FRAME_ANCESTOR_OF_BOTH_FRAMES,
- getName(), fA.getName(), fB.getName());
- }
- // swap f1 and f2 to make sure the child is f2
- final Frame tmp = fA;
- fA = fB;
- fB = tmp;
- fAtoB = fAtoB.getInverse();
- } else if (!(fB.isChildOf(this) || fB == this)) {
- throw new FrameAncestorException(OrekitMessages.FRAME_ANCESTOR_OF_NEITHER_FRAME,
- getName(), fA.getName(), fB.getName());
- }
- // rebuild the transform by traveling from parent to self
- // WITHOUT using the existing provider from parent to self that will be updated
- final Transform parentTofA = getParent().getTransformTo(fA, date);
- final Transform fBtoSelf = fB.getTransformTo(this, date);
- final Transform fAtoSelf = new Transform(date, fAtoB, fBtoSelf);
- final Transform parentToSelf = new Transform(date, parentTofA, fAtoSelf);
- // update the existing provider from parent to self
- ((UpdatableProvider) getTransformProvider()).setTransform(parentToSelf);
- }
- /** Local provider for transforms. */
- private static class UpdatableProvider implements TransformProvider {
- /** Serializable UID. */
- private static final long serialVersionUID = 4436954500689776331L;
- /** Current transform. */
- private AtomicReference<Transform> transform;
- /** Simple constructor.
- * @param transform initial value of the transform
- */
- UpdatableProvider(final Transform transform) {
- this.transform = new AtomicReference<Transform>(transform);
- }
- /** Update the transform from the parent frame to the instance.
- * @param transform new transform from parent frame to instance
- */
- public void setTransform(final Transform transform) {
- this.transform.set(transform);
- }
- /** {@inheritDoc} */
- public Transform getTransform(final AbsoluteDate date) {
- return transform.get();
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
- return new FieldTransform<>(date.getField(), transform.get());
- }
- }
- }