SpacecraftToObservedBody.java

  1. /* Copyright 2013-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.rugged.utils;

  18. import java.io.Serializable;
  19. import java.util.ArrayList;
  20. import java.util.List;
  21. import java.util.stream.Collectors;

  22. import org.hipparchus.geometry.euclidean.threed.Rotation;
  23. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  24. import org.hipparchus.util.FastMath;
  25. import org.orekit.frames.FactoryManagedFrame;
  26. import org.orekit.frames.Frame;
  27. import org.orekit.frames.FramesFactory;
  28. import org.orekit.frames.Predefined;
  29. import org.orekit.frames.Transform;
  30. import org.orekit.rugged.errors.DumpManager;
  31. import org.orekit.rugged.errors.RuggedException;
  32. import org.orekit.rugged.errors.RuggedMessages;
  33. import org.orekit.time.AbsoluteDate;
  34. import org.orekit.time.TimeInterpolator;
  35. import org.orekit.time.TimeOffset;
  36. import org.orekit.utils.AngularCoordinates;
  37. import org.orekit.utils.AngularDerivativesFilter;
  38. import org.orekit.utils.CartesianDerivativesFilter;
  39. import org.orekit.utils.ImmutableTimeStampedCache;
  40. import org.orekit.utils.PVCoordinates;
  41. import org.orekit.utils.TimeStampedAngularCoordinates;
  42. import org.orekit.utils.TimeStampedAngularCoordinatesHermiteInterpolator;
  43. import org.orekit.utils.TimeStampedCache;
  44. import org.orekit.utils.TimeStampedPVCoordinates;
  45. import org.orekit.utils.TimeStampedPVCoordinatesHermiteInterpolator;

  46. /** Provider for observation transforms.
  47.  * @author Luc Maisonobe
  48.  * @author Guylaine Prat
  49.  */
  50. public class SpacecraftToObservedBody implements Serializable {

  51.     /** Serializable UID. */
  52.     private static final long serialVersionUID = 20250427L;

  53.     /** Inertial frame. */
  54.     private final Frame inertialFrame;

  55.     /** Body frame. */
  56.     private final Frame bodyFrame;

  57.     /** Start of search time span. */
  58.     private final AbsoluteDate minDate;

  59.     /** End of search time span. */
  60.     private final AbsoluteDate maxDate;

  61.     /** Step to use for inertial frame to body frame transforms cache computations. */
  62.     private final double tStep;

  63.     /** Tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting. */
  64.     private final double overshootTolerance;

  65.     /** Transforms sample from observed body frame to inertial frame. */
  66.     private final List<Transform> bodyToInertial;

  67.     /** Transforms sample from inertial frame to observed body frame. */
  68.     private final List<Transform> inertialToBody;

  69.     /** Transforms sample from spacecraft frame to inertial frame. */
  70.     private final List<Transform> scToInertial;

  71.     /** Simple constructor.
  72.      * @param inertialFrame inertial frame
  73.      * @param bodyFrame observed body frame
  74.      * @param minDate start of search time span
  75.      * @param maxDate end of search time span
  76.      * @param tStep step to use for inertial frame to body frame transforms cache computations
  77.      * @param overshootTolerance tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting
  78.      * slightly the position, velocity and quaternions ephemerides
  79.      * @param positionsVelocities satellite position and velocity
  80.      * @param pvInterpolationNumber number of points to use for position/velocity interpolation
  81.      * @param pvFilter filter for derivatives from the sample to use in position/velocity interpolation
  82.      * @param quaternions satellite quaternions
  83.      * @param aInterpolationNumber number of points to use for attitude interpolation
  84.      * @param aFilter filter for derivatives from the sample to use in attitude interpolation
  85.      */
  86.     public SpacecraftToObservedBody(final Frame inertialFrame, final Frame bodyFrame,
  87.                                     final AbsoluteDate minDate, final AbsoluteDate maxDate, final double tStep,
  88.                                     final double overshootTolerance,
  89.                                     final List<TimeStampedPVCoordinates> positionsVelocities, final int pvInterpolationNumber,
  90.                                     final CartesianDerivativesFilter pvFilter,
  91.                                     final List<TimeStampedAngularCoordinates> quaternions, final int aInterpolationNumber,
  92.                                     final AngularDerivativesFilter aFilter) {

  93.         this.inertialFrame      = inertialFrame;
  94.         this.bodyFrame          = bodyFrame;
  95.         this.minDate            = minDate;
  96.         this.maxDate            = maxDate;
  97.         this.overshootTolerance = overshootTolerance;

  98.         // safety checks
  99.         final AbsoluteDate minPVDate = positionsVelocities.get(0).getDate();
  100.         final AbsoluteDate maxPVDate = positionsVelocities.get(positionsVelocities.size() - 1).getDate();
  101.         if (minPVDate.durationFrom(minDate) > overshootTolerance) {
  102.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, minDate, minPVDate, maxPVDate);
  103.         }
  104.         if (maxDate.durationFrom(maxPVDate) > overshootTolerance) {
  105.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, maxDate, minPVDate, maxPVDate);
  106.         }

  107.         final AbsoluteDate minQDate  = quaternions.get(0).getDate();
  108.         final AbsoluteDate maxQDate  = quaternions.get(quaternions.size() - 1).getDate();
  109.         if (minQDate.durationFrom(minDate) > overshootTolerance) {
  110.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, minDate, minQDate, maxQDate);
  111.         }
  112.         if (maxDate.durationFrom(maxQDate) > overshootTolerance) {
  113.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, maxDate, minQDate, maxQDate);
  114.         }

  115.         // set up the cache for position-velocities
  116.         final TimeStampedCache<TimeStampedPVCoordinates> pvCache =
  117.                 new ImmutableTimeStampedCache<>(pvInterpolationNumber, positionsVelocities);

  118.         // set up the TimeStampedPVCoordinates interpolator
  119.         final TimeInterpolator<TimeStampedPVCoordinates> pvInterpolator =
  120.                 new TimeStampedPVCoordinatesHermiteInterpolator(pvInterpolationNumber, pvFilter);

  121.         // set up the cache for attitudes
  122.         final TimeStampedCache<TimeStampedAngularCoordinates> aCache =
  123.                 new ImmutableTimeStampedCache<>(aInterpolationNumber, quaternions);

  124.         // set up the TimeStampedAngularCoordinates Hermite interpolator
  125.         final TimeInterpolator<TimeStampedAngularCoordinates> angularInterpolator =
  126.                 new TimeStampedAngularCoordinatesHermiteInterpolator(aInterpolationNumber, aFilter);

  127.         final int n = (int) FastMath.ceil(maxDate.durationFrom(minDate) / tStep);
  128.         this.tStep          = tStep;
  129.         this.bodyToInertial = new ArrayList<>(n);
  130.         this.inertialToBody = new ArrayList<>(n);
  131.         this.scToInertial   = new ArrayList<>(n);
  132.         for (AbsoluteDate date = minDate; bodyToInertial.size() < n; date = date.shiftedBy(tStep)) {

  133.             // interpolate position-velocity, allowing slight extrapolation near the boundaries
  134.             final AbsoluteDate pvInterpolationDate;
  135.             if (date.compareTo(pvCache.getEarliest().getDate()) < 0) {
  136.                 pvInterpolationDate = pvCache.getEarliest().getDate();
  137.             } else if (date.compareTo(pvCache.getLatest().getDate()) > 0) {
  138.                 pvInterpolationDate = pvCache.getLatest().getDate();
  139.             } else {
  140.                 pvInterpolationDate = date;
  141.             }
  142.             final TimeStampedPVCoordinates interpolatedPV =
  143.                     pvInterpolator.interpolate(pvInterpolationDate,
  144.                             pvCache.getNeighbors(pvInterpolationDate));
  145.             final TimeStampedPVCoordinates pv = interpolatedPV.shiftedBy(date.durationFrom(pvInterpolationDate));

  146.             // interpolate attitude, allowing slight extrapolation near the boundaries
  147.             final AbsoluteDate aInterpolationDate;
  148.             if (date.compareTo(aCache.getEarliest().getDate()) < 0) {
  149.                 aInterpolationDate = aCache.getEarliest().getDate();
  150.             } else if (date.compareTo(aCache.getLatest().getDate()) > 0) {
  151.                 aInterpolationDate = aCache.getLatest().getDate();
  152.             } else {
  153.                 aInterpolationDate = date;
  154.             }
  155.             final TimeStampedAngularCoordinates interpolatedQuaternion =
  156.                     angularInterpolator.interpolate(aInterpolationDate,
  157.                             aCache.getNeighbors(aInterpolationDate).collect(Collectors.toList()));
  158.             final TimeStampedAngularCoordinates quaternion = interpolatedQuaternion.shiftedBy(date.durationFrom(aInterpolationDate));

  159.             // store transform from spacecraft frame to inertial frame
  160.             scToInertial.add(new Transform(date,
  161.                     new Transform(date, quaternion.revert()),
  162.                     new Transform(date, pv)));

  163.             // store transform from body frame to inertial frame
  164.             final Transform b2i = bodyFrame.getTransformTo(inertialFrame, date);
  165.             bodyToInertial.add(b2i);
  166.             inertialToBody.add(b2i.getInverse());

  167.         }
  168.     }

  169.     /** Simple constructor.
  170.      * @param inertialFrame inertial frame
  171.      * @param bodyFrame observed body frame
  172.      * @param minDate start of search time span
  173.      * @param maxDate end of search time span
  174.      * @param tStep step to use for inertial frame to body frame transforms cache computations
  175.      * @param overshootTolerance tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting
  176.      * slightly the position, velocity and quaternions ephemerides
  177.      * @param bodyToInertial transforms sample from observed body frame to inertial frame
  178.      * @param scToInertial transforms sample from spacecraft frame to inertial frame
  179.      */
  180.     public SpacecraftToObservedBody(final Frame inertialFrame, final Frame bodyFrame,
  181.                                     final AbsoluteDate minDate, final AbsoluteDate maxDate, final double tStep,
  182.                                     final double overshootTolerance,
  183.                                     final List<Transform> bodyToInertial, final List<Transform> scToInertial) {

  184.         this.inertialFrame      = inertialFrame;
  185.         this.bodyFrame          = bodyFrame;
  186.         this.minDate            = minDate;
  187.         this.maxDate            = maxDate;
  188.         this.tStep              = tStep;
  189.         this.overshootTolerance = overshootTolerance;
  190.         this.bodyToInertial     = bodyToInertial;
  191.         this.scToInertial       = scToInertial;

  192.         this.inertialToBody = new ArrayList<>(bodyToInertial.size());
  193.         for (final Transform b2i : bodyToInertial) {
  194.             inertialToBody.add(b2i.getInverse());
  195.         }

  196.     }

  197.     /** Get the inertial frame.
  198.      * @return inertial frame
  199.      */
  200.     public Frame getInertialFrame() {
  201.         return inertialFrame;
  202.     }

  203.     /** Get the body frame.
  204.      * @return body frame
  205.      */
  206.     public Frame getBodyFrame() {
  207.         return bodyFrame;
  208.     }

  209.     /** Get the start of search time span.
  210.      * @return start of search time span
  211.      */
  212.     public AbsoluteDate getMinDate() {
  213.         return minDate;
  214.     }

  215.     /** Get the end of search time span.
  216.      * @return end of search time span
  217.      */
  218.     public AbsoluteDate getMaxDate() {
  219.         return maxDate;
  220.     }

  221.     /** Get the step to use for inertial frame to body frame transforms cache computations.
  222.      * @return step to use for inertial frame to body frame transforms cache computations
  223.      */
  224.     public double getTStep() {
  225.         return tStep;
  226.     }

  227.     /** Get the tolerance in seconds allowed for {@link #getMinDate()} and {@link #getMaxDate()} overshooting.
  228.      * @return tolerance in seconds allowed for {@link #getMinDate()} and {@link #getMaxDate()} overshooting
  229.      */
  230.     public double getOvershootTolerance() {
  231.         return overshootTolerance;
  232.     }

  233.     /** Get transform from spacecraft to inertial frame.
  234.      * @param date date of the transform
  235.      * @return transform from spacecraft to inertial frame
  236.      */
  237.     public Transform getScToInertial(final AbsoluteDate date) {
  238.         return interpolate(date, scToInertial);
  239.     }

  240.     /** Get transform from inertial frame to observed body frame.
  241.      * @param date date of the transform
  242.      * @return transform from inertial frame to observed body frame
  243.      */
  244.     public Transform getInertialToBody(final AbsoluteDate date) {
  245.         return interpolate(date, inertialToBody);
  246.     }

  247.     /** Get transform from observed body frame to inertial frame.
  248.      * @param date date of the transform
  249.      * @return transform from observed body frame to inertial frame
  250.      */
  251.     public Transform getBodyToInertial(final AbsoluteDate date) {
  252.         return interpolate(date, bodyToInertial);
  253.     }

  254.     /** Interpolate transform.
  255.      * @param date date of the transform
  256.      * @param list transforms list to interpolate from
  257.      * @return interpolated transform
  258.      */
  259.     private Transform interpolate(final AbsoluteDate date, final List<Transform> list) {

  260.         // check date range
  261.         if (!isInRange(date)) {
  262.             throw new RuggedException(RuggedMessages.OUT_OF_TIME_RANGE, date, minDate, maxDate);
  263.         }

  264.         final double    s     = date.durationFrom(list.get(0).getDate()) / tStep;
  265.         final int       index = FastMath.max(0, FastMath.min(list.size() - 1, (int) FastMath.rint(s)));

  266.         DumpManager.dumpTransform(this, index, bodyToInertial.get(index), scToInertial.get(index));

  267.         final Transform close = list.get(index);
  268.         return close.shiftedBy(date.durationFrom(close.getDate()));

  269.     }

  270.     /** Check if a date is in the supported range.
  271.      * @param date date to check
  272.      * @return true if date is in the supported range
  273.      */
  274.     public boolean isInRange(final AbsoluteDate date) {
  275.         return minDate.durationFrom(date) <= overshootTolerance &&
  276.                date.durationFrom(maxDate) <= overshootTolerance;
  277.     }

  278.     /** Replace the instance with a data transfer object for serialization.
  279.      * @return data transfer object that will be serialized
  280.      */
  281.     private Object writeReplace() {
  282.         return new DataTransferObject(((FactoryManagedFrame) inertialFrame).getFactoryKey(),
  283.                                       ((FactoryManagedFrame) bodyFrame).getFactoryKey(),
  284.                                       minDate, maxDate, tStep, overshootTolerance,
  285.                                       extractTimeOffsets(bodyToInertial),
  286.                                       extractCoordinates(bodyToInertial),
  287.                                       extractTimeOffsets(scToInertial),
  288.                                       extractCoordinates(scToInertial));
  289.     }

  290.     /** Extract time offsets from a transforms list.
  291.      * @param transforms transforms to convert
  292.      * @return time offsets
  293.      * @since 4.0
  294.      */
  295.     private long[] extractTimeOffsets(final List<Transform> transforms) {

  296.         final long[] offsets = new long[2 * transforms.size()];

  297.         for (int i = 0; i < transforms.size(); ++i) {
  298.             final Transform ti = transforms.get(i);
  299.             offsets[2 * i]     = ti.getDate().getSeconds();
  300.             offsets[2 * i + 1] = ti.getDate().getAttoSeconds();
  301.         }

  302.         return offsets;

  303.     }

  304.     /** Extract coordinates from a transforms list.
  305.      * @param transforms transforms to convert
  306.      * @return time offsets
  307.      * @since 4.0
  308.      */
  309.     private double[] extractCoordinates(final List<Transform> transforms) {

  310.         final double[] coordinates = new double[19 * transforms.size()];

  311.         for (int i = 0; i < transforms.size(); ++i) {

  312.             final PVCoordinates      pv = transforms.get(i).getCartesian();
  313.             final AngularCoordinates ag = transforms.get(i).getAngular();

  314.             coordinates[19 * i]      = pv.getPosition().getX();
  315.             coordinates[19 * i +  1] = pv.getPosition().getY();
  316.             coordinates[19 * i +  2] = pv.getPosition().getZ();

  317.             coordinates[19 * i +  3] = pv.getVelocity().getX();
  318.             coordinates[19 * i +  4] = pv.getVelocity().getY();
  319.             coordinates[19 * i +  5] = pv.getVelocity().getZ();

  320.             coordinates[19 * i +  6] = pv.getAcceleration().getX();
  321.             coordinates[19 * i +  7] = pv.getAcceleration().getY();
  322.             coordinates[19 * i +  8] = pv.getAcceleration().getZ();

  323.             coordinates[19 * i +  9] = ag.getRotation().getQ0();
  324.             coordinates[19 * i + 10] = ag.getRotation().getQ1();
  325.             coordinates[19 * i + 11] = ag.getRotation().getQ2();
  326.             coordinates[19 * i + 12] = ag.getRotation().getQ3();

  327.             coordinates[19 * i + 13] = ag.getRotationRate().getX();
  328.             coordinates[19 * i + 14] = ag.getRotationRate().getY();
  329.             coordinates[19 * i + 15] = ag.getRotationRate().getZ();

  330.             coordinates[19 * i + 16] = ag.getRotationAcceleration().getX();
  331.             coordinates[19 * i + 17] = ag.getRotationAcceleration().getY();
  332.             coordinates[19 * i + 18] = ag.getRotationAcceleration().getZ();

  333.         }

  334.         return coordinates;

  335.     }

  336.     /** Internal class used only for serialization.
  337.      * @since 4.0
  338.      */
  339.     private static class DataTransferObject implements Serializable {

  340.         /** Serializable UID. */
  341.         private static final long serialVersionUID = 20250427L;

  342.         /** Inertial frame. */
  343.         private final Predefined inertialFrame;

  344.         /** Body frame. */
  345.         private final Predefined bodyFrame;

  346.         /** Start of search time span. */
  347.         private final AbsoluteDate minDate;

  348.         /** End of search time span. */
  349.         private final AbsoluteDate maxDate;

  350.         /** Step to use for inertial frame to body frame transforms cache computations. */
  351.         private final double tStep;

  352.         /** Tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting. */
  353.         private final double overshootTolerance;

  354.         /** Transforms sample from observed body frame to inertial frame. */
  355.         private final long[] bodyToInertialTimeOffset;

  356.         /** Transforms sample from observed body frame to inertial frame. */
  357.         private final double[] bodyToInertialCoordinates;

  358.         /** Transforms sample from spacecraft frame to inertial frame. */
  359.         private final long[] scToInertialTimOffset;

  360.         /** Transforms sample from spacecraft frame to inertial frame. */
  361.         private final double[] scToInertialCoordinates;

  362.         /** Simple constructor.
  363.          * @param inertialFrame inertial frame
  364.          * @param bodyFrame observed body frame
  365.          * @param minDate start of search time span
  366.          * @param maxDate end of search time span
  367.          * @param tStep step to use for inertial frame to body frame transforms cache computations
  368.          * @param overshootTolerance tolerance in seconds allowed for {@code minDate} and {@code maxDate} overshooting
  369.          * slightly the position, velocity and quaternions ephemerides
  370.          * @param bodyToInertialTimeOffset time offsets of transforms sample from observed body frame to inertial frame
  371.          * @param bodyToInertialCoordinates coordinates of transforms sample from observed body frame to inertial frame
  372.          * @param scToInertialTimOffset time offsets transforms sample from spacecraft frame to inertial frame
  373.          * @param scToInertialCoordinates coordinates transforms sample from spacecraft frame to inertial frame
  374.          */
  375.         DataTransferObject(final Predefined inertialFrame, final Predefined bodyFrame,
  376.                            final AbsoluteDate minDate, final AbsoluteDate maxDate, final double tStep,
  377.                            final double overshootTolerance,
  378.                            final long[] bodyToInertialTimeOffset, final double[] bodyToInertialCoordinates,
  379.                            final long[] scToInertialTimOffset, final double[] scToInertialCoordinates) {
  380.             this.inertialFrame             = inertialFrame;
  381.             this.bodyFrame                 = bodyFrame;
  382.             this.minDate                   = minDate;
  383.             this.maxDate                   = maxDate;
  384.             this.tStep                     = tStep;
  385.             this.overshootTolerance        = overshootTolerance;
  386.             this.bodyToInertialTimeOffset  = bodyToInertialTimeOffset;
  387.             this.bodyToInertialCoordinates = bodyToInertialCoordinates;
  388.             this.scToInertialTimOffset     = scToInertialTimOffset;
  389.             this.scToInertialCoordinates   = scToInertialCoordinates;
  390.         }

  391.         /** Create a transform.
  392.          * @param i index of the transfor
  393.          * @param timeOffsets time offsets array
  394.          * @param coordinates coordinates array
  395.          * @return transform
  396.          */
  397.         private Transform createTransform(final int i,
  398.                                           final long[] timeOffsets,
  399.                                           final double[] coordinates) {
  400.             final AbsoluteDate date = new AbsoluteDate(new TimeOffset(timeOffsets[2 * i],
  401.                                                                       timeOffsets[2 * i + 1]));
  402.             final PVCoordinates pv = new PVCoordinates(new Vector3D(coordinates[19 * i],
  403.                                                                     coordinates[19 * i +  1],
  404.                                                                     coordinates[19 * i +  2]),
  405.                                                        new Vector3D(coordinates[19 * i +  3],
  406.                                                                     coordinates[19 * i +  4],
  407.                                                                     coordinates[19 * i +  5]),
  408.                                                        new Vector3D(coordinates[19 * i +  6],
  409.                                                                     coordinates[19 * i +  7],
  410.                                                                     coordinates[19 * i +  8]));
  411.             final AngularCoordinates ag = new AngularCoordinates(new Rotation(coordinates[19 * i +  9],
  412.                                                                               coordinates[19 * i + 10],
  413.                                                                               coordinates[19 * i + 11],
  414.                                                                               coordinates[19 * i + 12],
  415.                                                                               false),
  416.                                                                  new Vector3D(coordinates[19 * i + 13],
  417.                                                                               coordinates[19 * i + 14],
  418.                                                                               coordinates[19 * i + 15]),
  419.                                                                  new Vector3D(coordinates[19 * i + 16],
  420.                                                                               coordinates[19 * i + 17],
  421.                                                                               coordinates[19 * i + 18]));
  422.             return new Transform(date, pv, ag);
  423.         }

  424.         /** Create all transforms.
  425.          * @param timeOffsets time offsets array
  426.          * @param coordinates coordinates array
  427.          * @return all transforms
  428.          */
  429.         private List<Transform> createAllTransforms(final long[] timeOffsets,
  430.                                                     final double[] coordinates) {
  431.             final List<Transform> transforms = new ArrayList<>(timeOffsets.length / 2);
  432.             for (int i = 0; i < timeOffsets.length / 2; ++i) {
  433.                 transforms.add(createTransform(i, timeOffsets, coordinates));
  434.             }
  435.             return transforms;
  436.         }

  437.         /** Replace the deserialized data transfer object with a
  438.          * {@link SpacecraftToObservedBody}.
  439.          * @return replacement {@link SpacecraftToObservedBody}
  440.          */
  441.         private Object readResolve() {
  442.             return new SpacecraftToObservedBody(FramesFactory.getFrame(inertialFrame),
  443.                                                 FramesFactory.getFrame(bodyFrame),
  444.                                                 minDate, maxDate, tStep, overshootTolerance,
  445.                                                 createAllTransforms(bodyToInertialTimeOffset,
  446.                                                                     bodyToInertialCoordinates),
  447.                                                 createAllTransforms(scToInertialTimOffset,
  448.                                                                     scToInertialCoordinates));
  449.         }

  450.     }

  451. }