TimeStampedAngularCoordinates.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.utils;

  18. import org.hipparchus.analysis.differentiation.Derivative;
  19. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  20. import org.hipparchus.geometry.euclidean.threed.Rotation;
  21. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  22. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  23. import org.orekit.time.AbsoluteDate;
  24. import org.orekit.time.TimeOffset;
  25. import org.orekit.time.TimeStamped;

  26. /** {@link TimeStamped time-stamped} version of {@link AngularCoordinates}.
  27.  * <p>Instances of this class are guaranteed to be immutable.</p>
  28.  * @author Luc Maisonobe
  29.  * @since 7.0
  30.  */
  31. public class TimeStampedAngularCoordinates extends AngularCoordinates implements TimeStamped {

  32.     /** Serializable UID. */
  33.     private static final long serialVersionUID = 20140723L;

  34.     /** The date. */
  35.     private final AbsoluteDate date;

  36.     /** Builds a rotation/rotation rate pair.
  37.      * @param date coordinates date
  38.      * @param rotation rotation
  39.      * @param rotationRate rotation rate Ω (rad/s)
  40.      * @param rotationAcceleration rotation acceleration dΩ/dt (rad²/s²)
  41.      */
  42.     public TimeStampedAngularCoordinates(final AbsoluteDate date,
  43.                                          final Rotation rotation,
  44.                                          final Vector3D rotationRate,
  45.                                          final Vector3D rotationAcceleration) {
  46.         super(rotation, rotationRate, rotationAcceleration);
  47.         this.date = date;
  48.     }

  49.     /** Build the rotation that transforms a pair of pv coordinates into another pair.

  50.      * <p><em>WARNING</em>! This method requires much more stringent assumptions on
  51.      * its parameters than the similar {@link Rotation#Rotation(Vector3D, Vector3D,
  52.      * Vector3D, Vector3D) constructor} from the {@link Rotation Rotation} class.
  53.      * As far as the Rotation constructor is concerned, the {@code v₂} vector from
  54.      * the second pair can be slightly misaligned. The Rotation constructor will
  55.      * compensate for this misalignment and create a rotation that ensure {@code
  56.      * v₁ = r(u₁)} and {@code v₂ ∈ plane (r(u₁), r(u₂))}. <em>THIS IS NOT
  57.      * TRUE ANYMORE IN THIS CLASS</em>! As derivatives are involved and must be
  58.      * preserved, this constructor works <em>only</em> if the two pairs are fully
  59.      * consistent, i.e. if a rotation exists that fulfill all the requirements: {@code
  60.      * v₁ = r(u₁)}, {@code v₂ = r(u₂)}, {@code dv₁/dt = dr(u₁)/dt}, {@code dv₂/dt
  61.      * = dr(u₂)/dt}, {@code d²v₁/dt² = d²r(u₁)/dt²}, {@code d²v₂/dt² = d²r(u₂)/dt²}.</p>

  62.      * @param date coordinates date
  63.      * @param u1 first vector of the origin pair
  64.      * @param u2 second vector of the origin pair
  65.      * @param v1 desired image of u1 by the rotation
  66.      * @param v2 desired image of u2 by the rotation
  67.      * @param tolerance relative tolerance factor used to check singularities
  68.      */
  69.     public TimeStampedAngularCoordinates(final AbsoluteDate date,
  70.                                          final PVCoordinates u1, final PVCoordinates u2,
  71.                                          final PVCoordinates v1, final PVCoordinates v2,
  72.                                          final double tolerance) {
  73.         super(u1, u2, v1, v2, tolerance);
  74.         this.date = date;
  75.     }

  76.     /** Build one of the rotations that transform one pv coordinates into another one.

  77.      * <p>Except for a possible scale factor, if the instance were
  78.      * applied to the vector u it will produce the vector v. There is an
  79.      * infinite number of such rotations, this constructor choose the
  80.      * one with the smallest associated angle (i.e. the one whose axis
  81.      * is orthogonal to the (u, v) plane). If u and v are collinear, an
  82.      * arbitrary rotation axis is chosen.</p>

  83.      * @param date coordinates date
  84.      * @param u origin vector
  85.      * @param v desired image of u by the rotation
  86.      */
  87.     public TimeStampedAngularCoordinates(final AbsoluteDate date,
  88.                                          final PVCoordinates u, final PVCoordinates v) {
  89.         super(u, v);
  90.         this.date = date;
  91.     }

  92.     /** Builds a TimeStampedAngularCoordinates from  a {@link FieldRotation}&lt;{@link Derivative}&gt;.
  93.      * <p>
  94.      * The rotation components must have time as their only derivation parameter and
  95.      * have consistent derivation orders.
  96.      * </p>
  97.      * @param date coordinates date
  98.      * @param r rotation with time-derivatives embedded within the coordinates
  99.      * @param <U> type of the derivative
  100.      */
  101.     public <U extends Derivative<U>>TimeStampedAngularCoordinates(final AbsoluteDate date,
  102.                                                                   final FieldRotation<U> r) {
  103.         super(r);
  104.         this.date = date;
  105.     }

  106.     /** {@inheritDoc} */
  107.     public AbsoluteDate getDate() {
  108.         return date;
  109.     }

  110.     /** Revert a rotation/rotation rate pair.
  111.      * Build a pair which reverse the effect of another pair.
  112.      * @return a new pair whose effect is the reverse of the effect
  113.      * of the instance
  114.      */
  115.     public TimeStampedAngularCoordinates revert() {
  116.         return new TimeStampedAngularCoordinates(date,
  117.                                                  getRotation().revert(),
  118.                                                  getRotation().applyInverseTo(getRotationRate().negate()),
  119.                                                  getRotation().applyInverseTo(getRotationAcceleration().negate()));
  120.     }

  121.     /** Get a time-shifted state.
  122.      * <p>
  123.      * The state can be slightly shifted to close dates. This shift is based on
  124.      * a simple linear model. It is <em>not</em> intended as a replacement for
  125.      * proper attitude propagation but should be sufficient for either small
  126.      * time shifts or coarse accuracy.
  127.      * </p>
  128.      * @param dt time shift in seconds
  129.      * @return a new state, shifted with respect to the instance (which is immutable)
  130.      */
  131.     public TimeStampedAngularCoordinates shiftedBy(final double dt) {
  132.         final AngularCoordinates sac = super.shiftedBy(dt);
  133.         return new TimeStampedAngularCoordinates(date.shiftedBy(dt),
  134.                                                  sac.getRotation(), sac.getRotationRate(), sac.getRotationAcceleration());

  135.     }

  136.     /** Get a time-shifted state.
  137.      * <p>
  138.      * The state can be slightly shifted to close dates. This shift is based on
  139.      * a simple linear model. It is <em>not</em> intended as a replacement for
  140.      * proper attitude propagation but should be sufficient for either small
  141.      * time shifts or coarse accuracy.
  142.      * </p>
  143.      * @param dt time shift in seconds
  144.      * @return a new state, shifted with respect to the instance (which is immutable)
  145.      * @since 13.0
  146.      */
  147.     public TimeStampedAngularCoordinates shiftedBy(final TimeOffset dt) {
  148.         final AngularCoordinates sac = super.shiftedBy(dt);
  149.         return new TimeStampedAngularCoordinates(date.shiftedBy(dt),
  150.                                                  sac.getRotation(), sac.getRotationRate(), sac.getRotationAcceleration());

  151.     }

  152.     /** Add an offset from the instance.
  153.      * <p>
  154.      * We consider here that the offset rotation is applied first and the
  155.      * instance is applied afterward. Note that angular coordinates do <em>not</em>
  156.      * commute under this operation, i.e. {@code a.addOffset(b)} and {@code
  157.      * b.addOffset(a)} lead to <em>different</em> results in most cases.
  158.      * </p>
  159.      * <p>
  160.      * The two methods {@link #addOffset(AngularCoordinates) addOffset} and
  161.      * {@link #subtractOffset(AngularCoordinates) subtractOffset} are designed
  162.      * so that round trip applications are possible. This means that both {@code
  163.      * ac1.subtractOffset(ac2).addOffset(ac2)} and {@code
  164.      * ac1.addOffset(ac2).subtractOffset(ac2)} return angular coordinates equal to ac1.
  165.      * </p>
  166.      * @param offset offset to subtract
  167.      * @return new instance, with offset subtracted
  168.      * @see #subtractOffset(AngularCoordinates)
  169.      */
  170.     @Override
  171.     public TimeStampedAngularCoordinates addOffset(final AngularCoordinates offset) {
  172.         final Vector3D rOmega    = getRotation().applyTo(offset.getRotationRate());
  173.         final Vector3D rOmegaDot = getRotation().applyTo(offset.getRotationAcceleration());
  174.         return new TimeStampedAngularCoordinates(date,
  175.                                                  getRotation().compose(offset.getRotation(), RotationConvention.VECTOR_OPERATOR),
  176.                                                  getRotationRate().add(rOmega),
  177.                                                  new Vector3D( 1.0, getRotationAcceleration(),
  178.                                                                1.0, rOmegaDot,
  179.                                                               -1.0, Vector3D.crossProduct(getRotationRate(), rOmega)));
  180.     }

  181.     /** Subtract an offset from the instance.
  182.      * <p>
  183.      * We consider here that the offset rotation is applied first and the
  184.      * instance is applied afterward. Note that angular coordinates do <em>not</em>
  185.      * commute under this operation, i.e. {@code a.subtractOffset(b)} and {@code
  186.      * b.subtractOffset(a)} lead to <em>different</em> results in most cases.
  187.      * </p>
  188.      * <p>
  189.      * The two methods {@link #addOffset(AngularCoordinates) addOffset} and
  190.      * {@link #subtractOffset(AngularCoordinates) subtractOffset} are designed
  191.      * so that round trip applications are possible. This means that both {@code
  192.      * ac1.subtractOffset(ac2).addOffset(ac2)} and {@code
  193.      * ac1.addOffset(ac2).subtractOffset(ac2)} return angular coordinates equal to ac1.
  194.      * </p>
  195.      * @param offset offset to subtract
  196.      * @return new instance, with offset subtracted
  197.      * @see #addOffset(AngularCoordinates)
  198.      */
  199.     @Override
  200.     public TimeStampedAngularCoordinates subtractOffset(final AngularCoordinates offset) {
  201.         return addOffset(offset.revert());
  202.     }

  203. }