Transform.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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.io.Serializable;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import java.util.List;

  23. import org.apache.commons.math3.RealFieldElement;
  24. import org.apache.commons.math3.geometry.euclidean.threed.FieldRotation;
  25. import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
  26. import org.apache.commons.math3.geometry.euclidean.threed.Line;
  27. import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
  28. import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
  29. import org.apache.commons.math3.util.Pair;
  30. import org.orekit.time.AbsoluteDate;
  31. import org.orekit.time.TimeInterpolable;
  32. import org.orekit.time.TimeShiftable;
  33. import org.orekit.time.TimeStamped;
  34. import org.orekit.utils.AngularCoordinates;
  35. import org.orekit.utils.PVCoordinates;
  36. import org.orekit.utils.FieldPVCoordinates;


  37. /** Transformation class in three dimensional space.
  38.  *
  39.  * <p>This class represents the transformation engine between {@link Frame frames}.
  40.  * It is used both to define the relationship between each frame and its
  41.  * parent frame and to gather all individual transforms into one
  42.  * operation when converting between frames far away from each other.</p>
  43.  * <p> The convention used in OREKIT is vectorial transformation. It means
  44.  * that a transformation is defined as a transform to apply to the
  45.  * coordinates of a vector expressed in the old frame to obtain the
  46.  * same vector expressed in the new frame. <p>
  47.  *
  48.  * <p>Instances of this class are guaranteed to be immutable.</p>
  49.  *
  50.  *  <h5> Example </h5>
  51.  *
  52.  * <pre>
  53.  *
  54.  * 1 ) Example of translation from R<sub>A</sub> to R<sub>B</sub>:
  55.  * We want to transform the {@link PVCoordinates} PV<sub>A</sub> to PV<sub>B</sub>.
  56.  *
  57.  * With :  PV<sub>A</sub> = ({1, 0, 0} , {1, 0, 0});
  58.  * and  :  PV<sub>B</sub> = ({0, 0, 0} , {0, 0, 0});
  59.  *
  60.  * The transform to apply then is defined as follows :
  61.  *
  62.  * Vector3D translation = new Vector3D(-1,0,0);
  63.  * Vector3D velocity = new Vector3D(-1,0,0);
  64.  *
  65.  * Transform R1toR2 = new Transform(translation, Velocity);
  66.  *
  67.  * PV<sub>B</sub> = R1toR2.transformPVCoordinates(PV<sub>A</sub>);
  68.  *
  69.  *
  70.  * 2 ) Example of rotation from R<sub>A</sub> to R<sub>B</sub>:
  71.  * We want to transform the {@link PVCoordinates} PV<sub>A</sub> to PV<sub>B</sub>.
  72.  *
  73.  * With :  PV<sub>A</sub> = ({1, 0, 0}, {1, 0, 0});
  74.  * and  :  PV<sub>B</sub> = ({0, 1, 0}, {-2, 1, 0});
  75.  *
  76.  * The transform to apply then is defined as follows :
  77.  *
  78.  * Rotation rotation = new Rotation(Vector3D.PLUS_K, FastMath.PI / 2);
  79.  * Vector3D rotationRate = new Vector3D(0, 0, -2);
  80.  *
  81.  * Transform R1toR2 = new Transform(rotation, rotationRate);
  82.  *
  83.  * PV<sub>B</sub> = R1toR2.transformPVCoordinates(PV<sub>A</sub>);
  84.  *
  85.  * </pre>
  86.  *
  87.  * @author Luc Maisonobe
  88.  * @author Fabien Maussion
  89.  */
  90. public class Transform
  91.     implements TimeStamped, TimeShiftable<Transform>, TimeInterpolable<Transform>, Serializable {

  92.     /** Identity transform. */
  93.     public static final Transform IDENTITY = new IdentityTransform();

  94.     /** Serializable UID. */
  95.     private static final long serialVersionUID = -8809893979516295102L;

  96.     /** Date of the transform. */
  97.     private final AbsoluteDate date;

  98.     /** Cartesian coordinates of the target frame with respect to the original frame. */
  99.     private final PVCoordinates cartesian;

  100.     /** Angular coordinates of the target frame with respect to the original frame. */
  101.     private final AngularCoordinates angular;

  102.     /** Build a transform from its primitive operations.
  103.      * @param date date of the transform
  104.      * @param cartesian Cartesian coordinates of the target frame with respect to the original frame
  105.      * @param angular angular coordinates of the target frame with respect to the original frame
  106.      */
  107.     private Transform(final AbsoluteDate date,
  108.                       final PVCoordinates cartesian, final AngularCoordinates angular) {
  109.         this.date      = date;
  110.         this.cartesian = cartesian;
  111.         this.angular   = angular;
  112.     }

  113.     /** Build a translation transform.
  114.      * @param date date of the transform
  115.      * @param translation translation to apply (i.e. coordinates of
  116.      * the transformed origin, or coordinates of the origin of the
  117.      * old frame in the new frame)
  118.      */
  119.     public Transform(final AbsoluteDate date, final Vector3D translation) {
  120.         this(date, new PVCoordinates(translation, Vector3D.ZERO), AngularCoordinates.IDENTITY);
  121.     }

  122.     /** Build a rotation transform.
  123.      * @param date date of the transform
  124.      * @param rotation rotation to apply ( i.e. rotation to apply to the
  125.      * coordinates of a vector expressed in the old frame to obtain the
  126.      * same vector expressed in the new frame )
  127.      */
  128.     public Transform(final AbsoluteDate date, final Rotation rotation) {
  129.         this(date, PVCoordinates.ZERO, new AngularCoordinates(rotation, Vector3D.ZERO));
  130.     }

  131.     /** Build a translation transform, with its first time derivative.
  132.      * @param date date of the transform
  133.      * @param translation translation to apply (i.e. coordinates of
  134.      * the transformed origin, or coordinates of the origin of the
  135.      * old frame in the new frame)
  136.      * @param velocity the velocity of the translation (i.e. origin
  137.      * of the old frame velocity in the new frame)
  138.      */
  139.     public Transform(final AbsoluteDate date, final Vector3D translation, final Vector3D velocity) {
  140.         this(date, new PVCoordinates(translation, velocity), AngularCoordinates.IDENTITY);
  141.     }

  142.     /** Build a translation transform, with its first time derivative.
  143.      * @param date date of the transform
  144.      * @param cartesian cartesian part of the transformation to apply (i.e. coordinates of
  145.      * the transformed origin, or coordinates of the origin of the
  146.      * old frame in the new frame, with their derivatives)
  147.      */
  148.     public Transform(final AbsoluteDate date, final PVCoordinates cartesian) {
  149.         this(date, cartesian, AngularCoordinates.IDENTITY);
  150.     }

  151.     /** Build a rotation transform.
  152.      * @param date date of the transform
  153.      * @param rotation rotation to apply ( i.e. rotation to apply to the
  154.      * coordinates of a vector expressed in the old frame to obtain the
  155.      * same vector expressed in the new frame )
  156.      * @param rotationRate the axis of the instant rotation
  157.      * expressed in the new frame. (norm representing angular rate)
  158.      */
  159.     public Transform(final AbsoluteDate date, final Rotation rotation, final Vector3D rotationRate) {
  160.         this(date, PVCoordinates.ZERO, new AngularCoordinates(rotation, rotationRate));
  161.     }

  162.     /** Build a rotation transform.
  163.      * @param date date of the transform
  164.      * @param angular angular part of the transformation to apply (i.e. rotation to
  165.      * apply to the coordinates of a vector expressed in the old frame to obtain the
  166.      * same vector expressed in the new frame, with its rotation rate)
  167.      */
  168.     public Transform(final AbsoluteDate date, final AngularCoordinates angular) {
  169.         this(date, PVCoordinates.ZERO, angular);
  170.     }

  171.     /** Build a transform by combining two existing ones.
  172.      * <p>
  173.      * Note that the dates of the two existing transformed are <em>ignored</em>,
  174.      * and the combined transform date is set to the date supplied in this constructor
  175.      * without any attempt to shift the raw transforms. This is a design choice allowing
  176.      * user full control of the combination.
  177.      * </p>
  178.      * @param date date of the transform
  179.      * @param first first transform applied
  180.      * @param second second transform applied
  181.      */
  182.     public Transform(final AbsoluteDate date, final Transform first, final Transform second) {
  183.         this(date,
  184.              new PVCoordinates(compositeTranslation(first, second),
  185.                                compositeVelocity(first, second)),
  186.              new AngularCoordinates(compositeRotation(first, second),
  187.                                     compositeRotationRate(first, second)));
  188.     }

  189.     /** Compute a composite translation.
  190.      * @param first first applied transform
  191.      * @param second second applied transform
  192.      * @return translation part of the composite transform
  193.      */
  194.     private static Vector3D compositeTranslation(final Transform first, final Transform second) {

  195.         final Vector3D p1 = first.cartesian.getPosition();
  196.         final Rotation r1 = first.angular.getRotation();
  197.         final Vector3D p2 = second.cartesian.getPosition();

  198.         return p1.add(r1.applyInverseTo(p2));

  199.     }

  200.     /** Compute a composite velocity.
  201.      * @param first first applied transform
  202.      * @param second second applied transform
  203.      * @return velocity part of the composite transform
  204.      */
  205.     private static Vector3D compositeVelocity(final Transform first, final Transform second) {

  206.         final Vector3D v1 = first.cartesian.getVelocity();
  207.         final Rotation r1 = first.angular.getRotation();
  208.         final Vector3D o1 = first.angular.getRotationRate();
  209.         final Vector3D p2 = second.cartesian.getPosition();
  210.         final Vector3D v2 = second.cartesian.getVelocity();

  211.         return v1.add(r1.applyInverseTo(v2.add(Vector3D.crossProduct(o1, p2))));

  212.     }

  213.     /** Compute a composite rotation.
  214.      * @param first first applied transform
  215.      * @param second second applied transform
  216.      * @return rotation part of the composite transform
  217.      */
  218.     private static Rotation compositeRotation(final Transform first, final Transform second) {

  219.         final Rotation r1 = first.angular.getRotation();
  220.         final Rotation r2 = second.angular.getRotation();

  221.         return r2.applyTo(r1);

  222.     }

  223.     /** Compute a composite rotation rate.
  224.      * @param first first applied transform
  225.      * @param second second applied transform
  226.      * @return rotation rate part of the composite transform
  227.      */
  228.     private static Vector3D compositeRotationRate(final Transform first, final Transform second) {

  229.         final Vector3D o1 = first.angular.getRotationRate();
  230.         final Rotation r2 = second.angular.getRotation();
  231.         final Vector3D o2 = second.angular.getRotationRate();

  232.         return o2.add(r2.applyTo(o1));

  233.     }

  234.     /** {@inheritDoc} */
  235.     public AbsoluteDate getDate() {
  236.         return date;
  237.     }

  238.     /** {@inheritDoc} */
  239.     public Transform shiftedBy(final double dt) {
  240.         return new Transform(date.shiftedBy(dt), cartesian.shiftedBy(dt), angular.shiftedBy(dt));
  241.     };

  242.     /** {@inheritDoc}
  243.      * <p>
  244.      * Calling this method is equivalent to call {@link #interpolate(AbsoluteDate, boolean,
  245.      * boolean, Collection)} with both {@code useVelocities} and {@code useRotationRates}
  246.      * set to true.
  247.      * </p>
  248.      */
  249.     public Transform interpolate(final AbsoluteDate interpolationDate,
  250.                                  final Collection<Transform> sample) {
  251.         return interpolate(interpolationDate, true, true, sample);
  252.     }

  253.     /** Interpolate a transform from a sample set of existing transforms.
  254.      * <p>
  255.      * Note that even if first time derivatives (velocities and rotation rates)
  256.      * from sample can be ignored, the interpolated instance always includes
  257.      * interpolated derivatives. This feature can be used explicitly to
  258.      * compute these derivatives when it would be too complex to compute them
  259.      * from an analytical formula: just compute a few sample points from the
  260.      * explicit formula and set the derivatives to zero in these sample points,
  261.      * then use interpolation to add derivatives consistent with the positions
  262.      * and rotations.
  263.      * </p>
  264.      * <p>
  265.      * As this implementation of interpolation is polynomial, it should be used only
  266.      * with small samples (about 10-20 points) in order to avoid <a
  267.      * href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a>
  268.      * and numerical problems (including NaN appearing).
  269.      * </p>
  270.      * @param date interpolation date
  271.      * @param useVelocities if true, use sample transforms velocities,
  272.      * otherwise ignore them and use only positions
  273.      * @param useRotationRates if true, use sample points rotation rates,
  274.      * otherwise ignore them and use only rotations
  275.      * @param sample sample points on which interpolation should be done
  276.      * @return a new instance, interpolated at specified date
  277.      */
  278.     public static Transform interpolate(final AbsoluteDate date,
  279.                                         final boolean useVelocities, final boolean useRotationRates,
  280.                                         final Collection<Transform> sample) {
  281.         final List<Pair<AbsoluteDate, PVCoordinates>> datedPV =
  282.                 new ArrayList<Pair<AbsoluteDate, PVCoordinates>>(sample.size());
  283.         final List<Pair<AbsoluteDate, AngularCoordinates>> datedAC =
  284.                 new ArrayList<Pair<AbsoluteDate, AngularCoordinates>>(sample.size());
  285.         for (final Transform transform : sample) {
  286.             datedPV.add(new Pair<AbsoluteDate, PVCoordinates>(transform.getDate(),
  287.                     transform.getCartesian()));
  288.             datedAC.add(new Pair<AbsoluteDate, AngularCoordinates>(transform.getDate(),
  289.                     transform.getAngular()));
  290.         }
  291.         final PVCoordinates      interpolatedPV = PVCoordinates.interpolate(date, useVelocities, datedPV);
  292.         final AngularCoordinates interpolatedAC = AngularCoordinates.interpolate(date, useRotationRates, datedAC);
  293.         return new Transform(date, interpolatedPV, interpolatedAC);
  294.     }

  295.     /** Get the inverse transform of the instance.
  296.      * @return inverse transform of the instance
  297.      */
  298.     public Transform getInverse() {

  299.         final Vector3D p = cartesian.getPosition();
  300.         final Vector3D v = cartesian.getVelocity();
  301.         final Rotation r = angular.getRotation();
  302.         final Vector3D o = angular.getRotationRate();

  303.         final Vector3D rT = r.applyTo(p);
  304.         return new Transform(date,
  305.                              new PVCoordinates(rT.negate(),
  306.                                                Vector3D.crossProduct(o, rT).subtract(r.applyTo(v))),
  307.                              angular.revert());

  308.     }

  309.     /** Get a freezed transform.
  310.      * <p>
  311.      * This method creates a copy of the instance but frozen in time,
  312.      * i.e. with velocity and rotation rate forced to zero.
  313.      * </p>
  314.      * @return a new transform, without any time-dependent parts
  315.      */
  316.     public Transform freeze() {
  317.         return new Transform(date,
  318.                              new PVCoordinates(cartesian.getPosition(), Vector3D.ZERO),
  319.                              new AngularCoordinates(angular.getRotation(), Vector3D.ZERO));
  320.     }

  321.     /** Transform a position vector (including translation effects).
  322.      * @param position vector to transform
  323.      * @return transformed position
  324.      */
  325.     public Vector3D transformPosition(final Vector3D position) {
  326.         return angular.getRotation().applyTo(cartesian.getPosition().add(position));
  327.     }

  328.     /** Transform a position vector (including translation effects).
  329.      * @param position vector to transform
  330.      * @param <T> the type of the field elements
  331.      * @return transformed position
  332.      */
  333.     public <T extends RealFieldElement<T>> FieldVector3D<T> transformPosition(final FieldVector3D<T> position) {
  334.         return FieldRotation.applyTo(angular.getRotation(), position.add(cartesian.getPosition()));
  335.     }

  336.     /** Transform a vector (ignoring translation effects).
  337.      * @param vector vector to transform
  338.      * @return transformed vector
  339.      */
  340.     public Vector3D transformVector(final Vector3D vector) {
  341.         return angular.getRotation().applyTo(vector);
  342.     }

  343.     /** Transform a vector (ignoring translation effects).
  344.      * @param vector vector to transform
  345.      * @param <T> the type of the field elements
  346.      * @return transformed vector
  347.      */
  348.     public <T extends RealFieldElement<T>> FieldVector3D<T> transformVector(final FieldVector3D<T> vector) {
  349.         return FieldRotation.applyTo(angular.getRotation(), vector);
  350.     }

  351.     /** Transform a line.
  352.      * @param line to transform
  353.      * @return transformed line
  354.      */
  355.     public Line transformLine(final Line line) {
  356.         final Vector3D transformedP0 = transformPosition(line.getOrigin());
  357.         final Vector3D transformedP1 = transformPosition(line.pointAt(1.0e6));
  358.         return new Line(transformedP0, transformedP1);
  359.     }

  360.     /** Transform {@link PVCoordinates} including kinematic effects.
  361.      * @param pv the couple position-velocity to transform.
  362.      * @return transformed position/velocity
  363.      */
  364.     public PVCoordinates transformPVCoordinates(final PVCoordinates pv) {
  365.         final Vector3D p = pv.getPosition();
  366.         final Vector3D v = pv.getVelocity();
  367.         final Vector3D transformedP = angular.getRotation().applyTo(cartesian.getPosition().add(p));
  368.         final Vector3D cross = Vector3D.crossProduct(angular.getRotationRate(), transformedP);
  369.         return new PVCoordinates(transformedP,
  370.                                  angular.getRotation().applyTo(v.add(cartesian.getVelocity())).subtract(cross));
  371.     }

  372.     /** Transform {@link FieldPVCoordinates} including kinematic effects.
  373.      * @param pv the couple position-velocity to transform.
  374.      * @param <T> the type of the field elements
  375.      * @return transformed position/velocity
  376.      */
  377.     public <T extends RealFieldElement<T>> FieldPVCoordinates<T> transformPVCoordinates(final FieldPVCoordinates<T> pv) {
  378.         final FieldVector3D<T> p = pv.getPosition();
  379.         final FieldVector3D<T> v = pv.getVelocity();
  380.         final FieldVector3D<T> transformedP = FieldRotation.applyTo(angular.getRotation(),
  381.                                                                     p.add(cartesian.getPosition()));
  382.         final FieldVector3D<T> cross = FieldVector3D.crossProduct(angular.getRotationRate(), transformedP);
  383.         return new FieldPVCoordinates<T>(transformedP,
  384.                                          FieldRotation.applyTo(angular.getRotation(),
  385.                                                                v.add(cartesian.getVelocity())).subtract(cross));
  386.     }

  387.     /** Compute the Jacobian of the {@link #transformPVCoordinates(PVCoordinates)}
  388.      * method of the transform.
  389.      * <p>
  390.      * Element {@code jacobian[i][j]} is the derivative of Cartesian coordinate i
  391.      * of the transformed {@link PVCoordinates} with respect to Cartesian coordinate j
  392.      * of the input {@link PVCoordinates} in method {@link #transformPVCoordinates(PVCoordinates)}.
  393.      * </p>
  394.      * <p>
  395.      * This definition implies that if we define position-velocity coordinates
  396.      * <pre>
  397.      * PV<sub>1</sub> = transform.transformPVCoordinates(PV<sub>0</sub>), then
  398.      * </pre>
  399.      * their differentials dPV<sub>1</sub> and dPV<sub>0</sub> will obey the following relation
  400.      * where J is the matrix computed by this method:<br/>
  401.      * <pre>
  402.      * dPV<sub>1</sub> = J &times; dPV<sub>0</sub>
  403.      * </pre>
  404.      * </p>
  405.      * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix
  406.      * is larger than 6x6, only the 6x6 upper left corner will be modified
  407.      */
  408.     public void getJacobian(final double[][] jacobian) {

  409.         // elementary matrix for rotation
  410.         final double[][] mData = angular.getRotation().getMatrix();

  411.         // dP1/dP0
  412.         System.arraycopy(mData[0], 0, jacobian[0], 0, 3);
  413.         System.arraycopy(mData[1], 0, jacobian[1], 0, 3);
  414.         System.arraycopy(mData[2], 0, jacobian[2], 0, 3);

  415.         // dP1/dV0
  416.         Arrays.fill(jacobian[0], 3, 6, 0.0);
  417.         Arrays.fill(jacobian[1], 3, 6, 0.0);
  418.         Arrays.fill(jacobian[2], 3, 6, 0.0);

  419.         // dV1/dP0
  420.         final Vector3D o = angular.getRotationRate();
  421.         final double mOx = -o.getX();
  422.         final double mOy = -o.getY();
  423.         final double mOz = -o.getZ();
  424.         for (int i = 0; i < 3; ++i) {
  425.             jacobian[3][i] = mOy * mData[2][i] - mOz * mData[1][i];
  426.             jacobian[4][i] = mOz * mData[0][i] - mOx * mData[2][i];
  427.             jacobian[5][i] = mOx * mData[1][i] - mOy * mData[0][i];
  428.         }

  429.         // dV1/dV0
  430.         System.arraycopy(mData[0], 0, jacobian[3], 3, 3);
  431.         System.arraycopy(mData[1], 0, jacobian[4], 3, 3);
  432.         System.arraycopy(mData[2], 0, jacobian[5], 3, 3);

  433.     }

  434.     /** Get the underlying elementary cartesian part.
  435.      * <p>A transform can be uniquely represented as an elementary
  436.      * translation followed by an elementary rotation. This method
  437.      * returns this unique elementary translation with its derivative.</p>
  438.      * @return underlying elementary cartesian part
  439.      * @see #getTranslation()
  440.      * @see #getVelocity()
  441.      */
  442.     public PVCoordinates getCartesian() {
  443.         return cartesian;
  444.     }

  445.     /** Get the underlying elementary translation.
  446.      * <p>A transform can be uniquely represented as an elementary
  447.      * translation followed by an elementary rotation. This method
  448.      * returns this unique elementary translation.</p>
  449.      * @return underlying elementary translation
  450.      * @see #getCartesian()
  451.      * @see #getVelocity()
  452.      */
  453.     public Vector3D getTranslation() {
  454.         return cartesian.getPosition();
  455.     }

  456.     /** Get the first time derivative of the translation.
  457.      * @return first time derivative of the translation
  458.      * @see #getCartesian()
  459.      * @see #getTranslation()
  460.      */
  461.     public Vector3D getVelocity() {
  462.         return cartesian.getVelocity();
  463.     }

  464.     /** Get the underlying elementary angular part.
  465.      * <p>A transform can be uniquely represented as an elementary
  466.      * translation followed by an elementary rotation. This method
  467.      * returns this unique elementary rotation with its derivative.</p>
  468.      * @return underlying elementary angular part
  469.      * @see #getRotation()
  470.      * @see #getRotationRate()
  471.      */
  472.     public AngularCoordinates getAngular() {
  473.         return angular;
  474.     }

  475.     /** Get the underlying elementary rotation.
  476.      * <p>A transform can be uniquely represented as an elementary
  477.      * translation followed by an elementary rotation. This method
  478.      * returns this unique elementary rotation.</p>
  479.      * @return underlying elementary rotation
  480.      * @see #getAngular()
  481.      * @see #getRotationRate()
  482.      */
  483.     public Rotation getRotation() {
  484.         return angular.getRotation();
  485.     }

  486.     /** Get the first time derivative of the rotation.
  487.      * <p>The norm represents the angular rate.</p>
  488.      * @return First time derivative of the rotation
  489.      * @see #getAngular()
  490.      * @see #getRotation()
  491.      */
  492.     public Vector3D getRotationRate() {
  493.         return angular.getRotationRate();
  494.     }

  495.     /** Specialized class for identity transform. */
  496.     private static class IdentityTransform extends Transform {

  497.         /** Serializable UID. */
  498.         private static final long serialVersionUID = -9042082036141830517L;

  499.         /** Simple constructor. */
  500.         public IdentityTransform() {
  501.             super(AbsoluteDate.J2000_EPOCH, PVCoordinates.ZERO, AngularCoordinates.IDENTITY);
  502.         }

  503.         /** {@inheritDoc} */
  504.         @Override
  505.         public Transform shiftedBy(final double dt) {
  506.             return this;
  507.         }

  508.         /** {@inheritDoc} */
  509.         @Override
  510.         public Transform getInverse() {
  511.             return this;
  512.         };

  513.         /** {@inheritDoc} */
  514.         @Override
  515.         public Vector3D transformPosition(final Vector3D position) {
  516.             return position;
  517.         }

  518.         /** {@inheritDoc} */
  519.         @Override
  520.         public Vector3D transformVector(final Vector3D vector) {
  521.             return vector;
  522.         }

  523.         /** {@inheritDoc} */
  524.         @Override
  525.         public Line transformLine(final Line line) {
  526.             return line;
  527.         }

  528.         /** {@inheritDoc} */
  529.         @Override
  530.         public PVCoordinates transformPVCoordinates(final PVCoordinates pv) {
  531.             return pv;
  532.         }

  533.         /** {@inheritDoc} */
  534.         @Override
  535.         public void getJacobian(final double[][] jacobian) {
  536.             for (int i = 0; i < 6; ++i) {
  537.                 Arrays.fill(jacobian[i], 0, 6, 0.0);
  538.                 jacobian[i][i] = 1.0;
  539.             }
  540.         }

  541.     }

  542. }