UpdatableFrame.java

  1. /* Copyright 2002-2025 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. import java.util.concurrent.atomic.AtomicReference;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.orekit.errors.FrameAncestorException;
  21. import org.orekit.errors.OrekitMessages;
  22. import org.orekit.time.AbsoluteDate;
  23. import org.orekit.time.FieldAbsoluteDate;


  24. /** Frame whose transform from its parent can be updated.
  25.  * <p>This class allows to control the relative position of two parts
  26.  * of the global frames tree using any two frames in each part as
  27.  * control handles. Consider the following simplified frames tree as an
  28.  * example:</p>
  29.  * <pre>
  30.  *              GCRF
  31.  *                |
  32.  *  --------------------------------
  33.  *  |             |                |
  34.  * Sun        satellite          Earth
  35.  *                |                |
  36.  *        on-board antenna   ground station
  37.  *                                 |
  38.  *                          tracking antenna
  39.  * </pre>
  40.  * <p>Tracking measurements really correspond to the link between the ground
  41.  * and on-board antennas. This is tightly linked to the transform between
  42.  * these two frames, however neither frame is the direct parent frame of the
  43.  * other one: the path involves four intermediate frames. When we process a
  44.  * measurement, what we really want to update is the transform that defines
  45.  * the satellite frame with respect to its parent GCRF frame.</p>
  46.  * <p>In order to implement the above case, the satellite frame is defined
  47.  * as an instance of this class and its {@link #updateTransform(Frame, Frame,
  48.  * Transform, AbsoluteDate) updateTransform} would be called each time we want
  49.  * to adjust the frame, i.e. each time we get a new measurement between the
  50.  * two antennas.</p>
  51.  * @author Luc Maisonobe
  52.  */
  53. public class UpdatableFrame extends Frame {

  54.     /** Build a non-inertial frame from its transform with respect to its parent.
  55.      * <p>calling this constructor is equivalent to call
  56.      * {@link #UpdatableFrame(Frame, Transform, String, boolean)
  57.      * UpdatableFrame(parent, transform, name, false)}.</p>
  58.      * @param parent parent frame (must be non-null)
  59.      * @param transform transform from parent frame to instance
  60.      * @param name name of the frame
  61.      * @exception IllegalArgumentException if the parent frame is null
  62.      */
  63.     public UpdatableFrame(final Frame parent, final Transform transform, final String name)
  64.         throws IllegalArgumentException {
  65.         this(parent, transform, name, false);
  66.     }

  67.     /** Build a frame from its transform with respect to its parent.
  68.      * <p>The convention for the transform is that it is from parent
  69.      * frame to instance. This means that the two following frames
  70.      * are similar:</p>
  71.      * <pre>
  72.      * Frame frame1 = new Frame(FramesFactory.getGCRF(), new Transform(t1, t2));
  73.      * Frame frame2 = new Frame(new Frame(FramesFactory.getGCRF(), t1), t2);
  74.      * </pre>
  75.      * @param parent parent frame (must be non-null)
  76.      * @param transform transform from parent frame to instance
  77.      * @param name name of the frame
  78.      * @param pseudoInertial true if frame is considered pseudo-inertial
  79.      * (i.e. suitable for propagating orbit)
  80.      * @exception IllegalArgumentException if the parent frame is null
  81.      */
  82.     public UpdatableFrame(final Frame parent, final Transform transform, final String name,
  83.                           final boolean pseudoInertial)
  84.         throws IllegalArgumentException {
  85.         super(parent, new UpdatableProvider(transform), name, pseudoInertial);
  86.     }

  87.     /** Update the transform from parent frame implicitly according to two other
  88.      * frames.

  89.      * <p>This method allows to control the relative position of two parts
  90.      * of the global frames tree using any two frames in each part as
  91.      * control handles. Consider the following simplified frames tree as an
  92.      * example:</p>
  93.      * <pre>
  94.      *              GCRF
  95.      *                |
  96.      *  --------------------------------
  97.      *  |             |                |
  98.      * Sun        satellite          Earth
  99.      *                |                |
  100.      *        on-board antenna   ground station
  101.      *                                 |
  102.      *                          tracking antenna
  103.      * </pre>
  104.      * <p>Tracking measurements really correspond to the link between the ground
  105.      * and on-board antennas. This is tightly linked to the transform between
  106.      * these two frames, however neither frame is the direct parent frame of the
  107.      * other one: the path involves four intermediate frames. When we process a
  108.      * measurement, what we really want to update is the transform that defines
  109.      * the satellite frame with respect to its parent GCRF frame. This
  110.      * is the purpose of this method. This update is done by the following call,
  111.      * where <code>measurementTransform</code> represents the measurement as a
  112.      * simple translation transform between the two antenna frames:</p>
  113.      * <pre><code>
  114.      * satellite.updateTransform(onBoardAntenna, trackingAntenna,
  115.      *                           measurementTransform, date);
  116.      * </code></pre>
  117.      * <p>One way to represent the behavior of the method is to consider the
  118.      * sub-tree rooted at the instance on one hand (satellite and on-board antenna
  119.      * in the example above) and the tree containing all the other frames on the
  120.      * other hand (GCRF, Sun, Earth, ground station, tracking antenna).
  121.      * Both tree are considered as two solid sets linked together by a flexible
  122.      * spring, which is the transform we want to update. The method stretches the
  123.      * spring to make sure the transform between the two specified frames (one in
  124.      * each tree part) matches the specified transform.</p>
  125.      * @param f1 first control frame (may be the instance itself)
  126.      * @param f2 second control frame (may be the instance itself)
  127.      * @param f1Tof2 desired transform from first to second control frame
  128.      * @param date date of the transform
  129.      */
  130.     public void updateTransform(final Frame f1, final Frame f2, final Transform f1Tof2,
  131.                                 final AbsoluteDate date) {

  132.         Frame fA = f1;
  133.         Frame fB = f2;
  134.         Transform fAtoB = f1Tof2;

  135.         // make sure f1 is not a child of the instance
  136.         if (fA.isChildOf(this) || fA == this) {

  137.             if (fB.isChildOf(this) || fB == this) {
  138.                 throw new FrameAncestorException(OrekitMessages.FRAME_ANCESTOR_OF_BOTH_FRAMES,
  139.                                                  getName(), fA.getName(), fB.getName());
  140.             }

  141.             // swap f1 and f2 to make sure the child is f2
  142.             final Frame tmp = fA;
  143.             fA = fB;
  144.             fB = tmp;
  145.             fAtoB = fAtoB.getInverse();

  146.         } else  if (!(fB.isChildOf(this) || fB == this)) {
  147.             throw new FrameAncestorException(OrekitMessages.FRAME_ANCESTOR_OF_NEITHER_FRAME,
  148.                                              getName(), fA.getName(), fB.getName());
  149.         }

  150.         // rebuild the transform by traveling from parent to self
  151.         // WITHOUT using the existing provider from parent to self that will be updated
  152.         final Transform parentTofA   = getParent().getTransformTo(fA, date);
  153.         final Transform fBtoSelf     = fB.getTransformTo(this, date);
  154.         final Transform fAtoSelf     = new Transform(date, fAtoB, fBtoSelf);
  155.         final Transform parentToSelf = new Transform(date, parentTofA, fAtoSelf);

  156.         // update the existing provider from parent to self
  157.         ((UpdatableProvider) getTransformProvider()).setTransform(parentToSelf);

  158.     }

  159.     /** Local provider for transforms. */
  160.     private static class UpdatableProvider implements TransformProvider {

  161.         /** Current transform. */
  162.         private AtomicReference<Transform> transform;

  163.         /** Simple constructor.
  164.          * @param transform initial value of the transform
  165.          */
  166.         UpdatableProvider(final Transform transform) {
  167.             this.transform = new AtomicReference<>(transform);
  168.         }

  169.         /** Update the transform from the parent frame to the instance.
  170.          * @param transform new transform from parent frame to instance
  171.          */
  172.         public void setTransform(final Transform transform) {
  173.             this.transform.set(transform);
  174.         }

  175.         /** {@inheritDoc} */
  176.         public Transform getTransform(final AbsoluteDate date) {
  177.             return transform.get();
  178.         }

  179.         /** {@inheritDoc} */
  180.         @Override
  181.         public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
  182.             return new FieldTransform<>(date.getField(), transform.get());
  183.         }
  184.     }

  185. }