KinematicTransform.java

  1. /* Copyright 2022-2024 Romain Serra
  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 org.hipparchus.geometry.euclidean.threed.Vector3D;
  19. import org.hipparchus.geometry.euclidean.threed.Rotation;
  20. import org.orekit.time.AbsoluteDate;
  21. import org.orekit.utils.PVCoordinates;
  22. import org.orekit.utils.TimeStampedPVCoordinates;

  23. /**
  24.  * A transform that only includes translation and rotation as well as their respective rates.
  25.  * It is kinematic in the sense that it cannot transform an acceleration vector.
  26.  *
  27.  * @author Romain Serra
  28.  * @see StaticTransform
  29.  * @see Transform
  30.  * @since 12.1
  31.  */
  32. public interface KinematicTransform extends StaticTransform {

  33.     /**
  34.      * Get the identity kinematic transform.
  35.      *
  36.      * @return identity transform.
  37.      */
  38.     static KinematicTransform getIdentity() {
  39.         return Transform.IDENTITY;
  40.     }

  41.     /** Compute a composite velocity.
  42.      * @param first first applied transform
  43.      * @param second second applied transform
  44.      * @return velocity part of the composite transform
  45.      */
  46.     static Vector3D compositeVelocity(final KinematicTransform first, final KinematicTransform second) {

  47.         final Vector3D v1 = first.getVelocity();
  48.         final Rotation r1 = first.getRotation();
  49.         final Vector3D o1 = first.getRotationRate();
  50.         final Vector3D p2 = second.getTranslation();
  51.         final Vector3D v2 = second.getVelocity();

  52.         final Vector3D crossP = Vector3D.crossProduct(o1, p2);

  53.         return v1.add(r1.applyInverseTo(v2.add(crossP)));
  54.     }

  55.     /** Compute a composite rotation rate.
  56.      * @param first first applied transform
  57.      * @param second second applied transform
  58.      * @return rotation rate part of the composite transform
  59.      */
  60.     static Vector3D compositeRotationRate(final KinematicTransform first, final KinematicTransform second) {

  61.         final Vector3D o1 = first.getRotationRate();
  62.         final Rotation r2 = second.getRotation();
  63.         final Vector3D o2 = second.getRotationRate();

  64.         return o2.add(r2.applyTo(o1));
  65.     }

  66.     /** Transform {@link PVCoordinates}, without the acceleration vector.
  67.      * @param pv the position-velocity couple to transform.
  68.      * @return transformed position-velocity
  69.      */
  70.     default PVCoordinates transformOnlyPV(final PVCoordinates pv) {
  71.         final Vector3D transformedP = transformPosition(pv.getPosition());
  72.         final Vector3D crossP       = Vector3D.crossProduct(getRotationRate(), transformedP);
  73.         final Vector3D transformedV = getRotation().applyTo(pv.getVelocity().add(getVelocity())).subtract(crossP);
  74.         return new PVCoordinates(transformedP, transformedV);
  75.     }

  76.     /** Transform {@link TimeStampedPVCoordinates}, without the acceleration vector.
  77.      * <p>
  78.      * In order to allow the user more flexibility, this method does <em>not</em> check for
  79.      * consistency between the transform {@link #getDate() date} and the time-stamped
  80.      * position-velocity {@link TimeStampedPVCoordinates#getDate() date}. The returned
  81.      * value will always have the same {@link TimeStampedPVCoordinates#getDate() date} as
  82.      * the input argument, regardless of the instance {@link #getDate() date}.
  83.      * </p>
  84.      * @param pv the position-velocity couple to transform.
  85.      * @return transformed position-velocity
  86.      */
  87.     default TimeStampedPVCoordinates transformOnlyPV(final TimeStampedPVCoordinates pv) {
  88.         final Vector3D transformedP = transformPosition(pv.getPosition());
  89.         final Vector3D crossP       = Vector3D.crossProduct(getRotationRate(), transformedP);
  90.         final Vector3D transformedV = getRotation().applyTo(pv.getVelocity().add(getVelocity())).subtract(crossP);
  91.         return new TimeStampedPVCoordinates(pv.getDate(), transformedP, transformedV);
  92.     }

  93.     /** Get the first time derivative of the translation.
  94.      * @return first time derivative of the translation
  95.      * @see #getTranslation()
  96.      */
  97.     Vector3D getVelocity();

  98.     /** Get the first time derivative of the rotation.
  99.      * <p>The norm represents the angular rate.</p>
  100.      * @return First time derivative of the rotation
  101.      * @see #getRotation()
  102.      */
  103.     Vector3D getRotationRate();

  104.     /**
  105.      * Get the inverse transform of the instance.
  106.      *
  107.      * @return inverse transform of the instance
  108.      */
  109.     KinematicTransform getInverse();

  110.     /**
  111.      * Build a transform by combining two existing ones.
  112.      * <p>
  113.      * Note that the dates of the two existing transformed are <em>ignored</em>,
  114.      * and the combined transform date is set to the date supplied in this
  115.      * constructor without any attempt to shift the raw transforms. This is a
  116.      * design choice allowing user full control of the combination.
  117.      * </p>
  118.      *
  119.      * @param date   date of the transform
  120.      * @param first  first transform applied
  121.      * @param second second transform applied
  122.      * @return the newly created kinematic transform that has the same effect as
  123.      * applying {@code first}, then {@code second}.
  124.      * @see #of(AbsoluteDate, PVCoordinates, Rotation, Vector3D)
  125.      */
  126.     static KinematicTransform compose(final AbsoluteDate date,
  127.                                       final KinematicTransform first,
  128.                                       final KinematicTransform second) {
  129.         final Vector3D composedTranslation = StaticTransform.compositeTranslation(first, second);
  130.         final Vector3D composedTranslationRate = KinematicTransform.compositeVelocity(first, second);
  131.         return of(date, new PVCoordinates(composedTranslation, composedTranslationRate),
  132.                 StaticTransform.compositeRotation(first, second),
  133.                 KinematicTransform.compositeRotationRate(first, second));
  134.     }

  135.     /**
  136.      * Create a new kinematic transform from a rotation and zero, constant translation.
  137.      *
  138.      * @param date     of translation.
  139.      * @param rotation to apply after the translation. That is after translating
  140.      *                 applying this rotation produces positions expressed in
  141.      *                 the new frame.
  142.      * @param rotationRate rate of rotation
  143.      * @return the newly created kinematic transform.
  144.      * @see #of(AbsoluteDate, PVCoordinates, Rotation, Vector3D)
  145.      */
  146.     static KinematicTransform of(final AbsoluteDate date,
  147.                                  final Rotation rotation,
  148.                                  final Vector3D rotationRate) {
  149.         return of(date, PVCoordinates.ZERO, rotation, rotationRate);
  150.     }

  151.     /**
  152.      * Create a new kinematic transform from a translation and its rate.
  153.      *
  154.      * @param date        of translation.
  155.      * @param pvCoordinates translation (with rate) to apply, expressed in the old frame. That is, the
  156.      *                    opposite of the coordinates of the new origin in the
  157.      *                    old frame.
  158.      * @return the newly created kinematic transform.
  159.      * @see #of(AbsoluteDate, PVCoordinates, Rotation, Vector3D)
  160.      */
  161.     static KinematicTransform of(final AbsoluteDate date,
  162.                                  final PVCoordinates pvCoordinates) {
  163.         return of(date, pvCoordinates, Rotation.IDENTITY, Vector3D.ZERO);
  164.     }

  165.     /**
  166.      * Create a new kinematic transform from a translation and rotation.
  167.      *
  168.      * @param date        of translation.
  169.      * @param pvCoordinates translation (with rate) to apply, expressed in the old frame. That is, the
  170.      *                    opposite of the coordinates of the new origin in the
  171.      *                    old frame.
  172.      * @param rotation    to apply after the translation. That is after
  173.      *                    translating applying this rotation produces positions
  174.      *                    expressed in the new frame.
  175.      * @param rotationRate rate of rotation
  176.      * @return the newly created kinematic transform.
  177.      * @see #compose(AbsoluteDate, KinematicTransform, KinematicTransform)
  178.      * @see #of(AbsoluteDate, PVCoordinates, Rotation, Vector3D)
  179.      * @see #of(AbsoluteDate, PVCoordinates, Rotation, Vector3D)
  180.      */
  181.     static KinematicTransform of(final AbsoluteDate date, final PVCoordinates pvCoordinates,
  182.                                  final Rotation rotation, final Vector3D rotationRate) {
  183.         return new KinematicTransform() {

  184.             @Override
  185.             public KinematicTransform getInverse() {
  186.                 final Rotation r = getRotation();
  187.                 final Vector3D rp = r.applyTo(getTranslation());
  188.                 final Vector3D pInv = rp.negate();
  189.                 final Vector3D crossP      = Vector3D.crossProduct(getRotationRate(), rp);
  190.                 final Vector3D vInv        = crossP.subtract(getRotation().applyTo(getVelocity()));
  191.                 final Rotation rInv = r.revert();
  192.                 return KinematicTransform.of(getDate(), new PVCoordinates(pInv, vInv),
  193.                         rInv, rInv.applyTo(getRotationRate()).negate());
  194.             }

  195.             @Override
  196.             public AbsoluteDate getDate() {
  197.                 return date;
  198.             }

  199.             @Override
  200.             public Vector3D getTranslation() {
  201.                 return pvCoordinates.getPosition();
  202.             }

  203.             @Override
  204.             public Rotation getRotation() {
  205.                 return rotation;
  206.             }

  207.             @Override
  208.             public Vector3D getVelocity() {
  209.                 return pvCoordinates.getVelocity();
  210.             }

  211.             @Override
  212.             public Vector3D getRotationRate() {
  213.                 return rotationRate;
  214.             }
  215.         };
  216.     }

  217. }