UpdatableFrame.java

  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. 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.     /** Serializable UID. */
  55.     private static final long serialVersionUID = -2075893064211339303L;

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

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

  89.     /** Update the transform from parent frame implicitly according to two other
  90.      * frames.

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

  134.         Frame fA = f1;
  135.         Frame fB = f2;
  136.         Transform fAtoB = f1Tof2;

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

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

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

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

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

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

  160.     }

  161.     /** Local provider for transforms. */
  162.     private static class UpdatableProvider implements TransformProvider {

  163.         /** Serializable UID. */
  164.         private static final long serialVersionUID = 4436954500689776331L;

  165.         /** Current transform. */
  166.         private AtomicReference<Transform> transform;

  167.         /** Simple constructor.
  168.          * @param transform initial value of the transform
  169.          */
  170.         UpdatableProvider(final Transform transform) {
  171.             this.transform = new AtomicReference<Transform>(transform);
  172.         }

  173.         /** Update the transform from the parent frame to the instance.
  174.          * @param transform new transform from parent frame to instance
  175.          */
  176.         public void setTransform(final Transform transform) {
  177.             this.transform.set(transform);
  178.         }

  179.         /** {@inheritDoc} */
  180.         public Transform getTransform(final AbsoluteDate date) {
  181.             return transform.get();
  182.         }

  183.         /** {@inheritDoc} */
  184.         @Override
  185.         public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
  186.             return new FieldTransform<>(date.getField(), transform.get());
  187.         }
  188.     }

  189. }