A transform can be uniquely represented as an elementary + * translation followed by an elementary rotation. This method returns this + * unique elementary translation.

+ * + * @return underlying elementary translation + */ + FieldVector3D getTranslation(); + + /** + * Get the underlying elementary rotation. + *

A transform can be uniquely represented as an elementary + * translation followed by an elementary rotation. This method returns this + * unique elementary rotation.

+ * + * @return underlying elementary rotation + */ + FieldRotation getRotation(); + + /** + * Get the inverse transform of the instance. + * + * @return inverse transform of the instance + */ + FieldStaticTransform getInverse(); + + /** + * Build a transform by combining two existing ones. + *

+ * Note that the dates of the two existing transformed are ignored, + * and the combined transform date is set to the date supplied in this + * constructor without any attempt to shift the raw transforms. This is a + * design choice allowing user full control of the combination. + *

+ * + * @param type of the elements + * @param date date of the transform + * @param first first transform applied + * @param second second transform applied + * @return the newly created static transform that has the same effect as + * applying {@code first}, then {@code second}. + * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation) + */ + static > FieldStaticTransform compose(final FieldAbsoluteDate date, + final FieldStaticTransform first, + final FieldStaticTransform second) { + return of(date, + compositeTranslation(first, second), + compositeRotation(first, second)); + } + + /** + * Compute a composite translation. + * + * @param first first applied transform + * @param second second applied transform + * @param the type of the field elements + * @return translation part of the composite transform + */ + static > FieldVector3D compositeTranslation(final FieldStaticTransform first, + final FieldStaticTransform second) { + + final FieldVector3D p1 = first.getTranslation(); + final FieldRotation r1 = first.getRotation(); + final FieldVector3D p2 = second.getTranslation(); + + return p1.add(r1.applyInverseTo(p2)); + + } + + /** + * Compute a composite rotation. + * + * @param first first applied transform + * @param second second applied transform + * @param the type of the field elements + * @return rotation part of the composite transform + */ + static > FieldRotation compositeRotation(final FieldStaticTransform first, + final FieldStaticTransform second) { + final FieldRotation r1 = first.getRotation(); + final FieldRotation r2 = second.getRotation(); + return r1.compose(r2, RotationConvention.FRAME_TRANSFORM); + } + + /** + * Create a new static transform from a rotation and zero translation. + * + * @param type of the elements + * @param date of translation. + * @param rotation to apply after the translation. That is after translating + * applying this rotation produces positions expressed in + * the new frame. + * @return the newly created static transform. + * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation) + */ + static > FieldStaticTransform of(final FieldAbsoluteDate date, + final FieldRotation rotation) { + return of(date, FieldVector3D.getZero(date.getField()), rotation); + } + + /** + * Create a new static transform from a translation and rotation. + * + * @param type of the elements + * @param date of translation. + * @param translation to apply, expressed in the old frame. That is, the + * opposite of the coordinates of the new origin in the + * old frame. + * @return the newly created static transform. + * @see #of(FieldAbsoluteDate, FieldVector3D, FieldRotation) + */ + static > FieldStaticTransform of(final FieldAbsoluteDate date, + final FieldVector3D translation) { + return of(date, translation, FieldRotation.getIdentity(date.getField())); + } + + /** + * Create a new static transform from a translation and rotation. + * + * @param type of the elements + * @param date of translation. + * @param translation to apply, expressed in the old frame. That is, the + * opposite of the coordinates of the new origin in the + * old frame. + * @param rotation to apply after the translation. That is after + * translating applying this rotation produces positions + * expressed in the new frame. + * @return the newly created static transform. + * @see #compose(AbsoluteDate, StaticTransform, StaticTransform) + * @see #of(FieldAbsoluteDate, FieldRotation) + * @see #of(FieldAbsoluteDate, FieldVector3D) + */ + static > FieldStaticTransform of(final FieldAbsoluteDate date, + final FieldVector3D translation, + final FieldRotation rotation) { + return new FieldStaticTransform() { + + @Override + public FieldStaticTransform getInverse() { + final FieldRotation r = getRotation(); + final FieldVector3D rp = r.applyTo(getTranslation()); + final FieldVector3D pInv = rp.negate(); + return FieldStaticTransform.of(date, pInv, rotation.revert()); + } + + @Override + public AbsoluteDate getDate() { + return date.toAbsoluteDate(); + } + + @Override + public FieldVector3D getTranslation() { + return translation; + } + + @Override + public FieldRotation getRotation() { + return rotation; + } + + }; + } + +} diff --git a/src/main/java/org/orekit/frames/FieldTransform.java b/src/main/java/org/orekit/frames/FieldTransform.java index 0b36483a8..b4437f436 100644 --- a/src/main/java/org/orekit/frames/FieldTransform.java +++ b/src/main/java/org/orekit/frames/FieldTransform.java @@ -22,18 +22,14 @@ import java.util.Collection; import java.util.List; import java.util.stream.Stream; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.geometry.euclidean.threed.FieldLine; import org.hipparchus.geometry.euclidean.threed.FieldRotation; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; -import org.hipparchus.geometry.euclidean.threed.Line; -import org.hipparchus.geometry.euclidean.threed.RotationConvention; -import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.time.TimeShiftable; -import org.orekit.time.TimeStamped; import org.orekit.utils.AngularDerivativesFilter; import org.orekit.utils.CartesianDerivativesFilter; import org.orekit.utils.FieldAngularCoordinates; @@ -102,7 +98,7 @@ import org.orekit.utils.TimeStampedPVCoordinates; * @since 9.0 */ public class FieldTransform> - implements TimeStamped, TimeShiftable> { + implements TimeShiftable>, FieldStaticTransform { /** Date of the transform. */ private final FieldAbsoluteDate date; @@ -274,10 +270,10 @@ public class FieldTransform> final FieldTransform first, final FieldTransform second) { this(date, date.toAbsoluteDate(), - new FieldPVCoordinates<>(compositeTranslation(first, second), + new FieldPVCoordinates<>(FieldStaticTransform.compositeTranslation(first, second), compositeVelocity(first, second), compositeAcceleration(first, second)), - new FieldAngularCoordinates<>(compositeRotation(first, second), + new FieldAngularCoordinates<>(FieldStaticTransform.compositeRotation(first, second), compositeRotationRate(first, second), compositeRotationAcceleration(first, second))); } @@ -291,22 +287,6 @@ public class FieldTransform> return new FieldIdentityTransform<>(field); } - /** Compute a composite translation. - * @param first first applied transform - * @param second second applied transform - * @param the type of the field elements - * @return translation part of the composite transform - */ - private static > FieldVector3D compositeTranslation(final FieldTransform first, final FieldTransform second) { - - final FieldVector3D p1 = first.cartesian.getPosition(); - final FieldRotation r1 = first.angular.getRotation(); - final FieldVector3D p2 = second.cartesian.getPosition(); - - return p1.add(r1.applyInverseTo(p2)); - - } - /** Compute a composite velocity. * @param first first applied transform * @param second second applied transform @@ -351,21 +331,6 @@ public class FieldTransform> } - /** Compute a composite rotation. - * @param first first applied transform - * @param second second applied transform - * @param the type of the field elements - * @return rotation part of the composite transform - */ - private static > FieldRotation compositeRotation(final FieldTransform first, final FieldTransform second) { - - final FieldRotation r1 = first.angular.getRotation(); - final FieldRotation r2 = second.angular.getRotation(); - - return r1.compose(r2, RotationConvention.FRAME_TRANSFORM); - - } - /** Compute a composite rotation rate. * @param first first applied transform * @param second second applied transform @@ -429,6 +394,22 @@ public class FieldTransform> cartesian.shiftedBy(dt), angular.shiftedBy(dt)); } + /** + * Shift the transform in time considering all rates, then return only the + * translation and rotation portion of the transform. + * + * @param dt time shift in seconds. + * @return shifted transform as a static transform. It is static in the + * sense that it can only be used to transform directions and positions, but + * not velocities or accelerations. + * @see #shiftedBy(double) + */ + public FieldStaticTransform staticShiftedBy(final T dt) { + return FieldStaticTransform.of(date.shiftedBy(dt), + cartesian.positionShiftedBy(dt), + angular.rotationShiftedBy(dt)); + } + /** Interpolate a transform from a sample set of existing transforms. *

* Calling this method is equivalent to call {@link #interpolate(FieldAbsoluteDate, @@ -522,6 +503,7 @@ public class FieldTransform> /** Get the inverse transform of the instance. * @return inverse transform of the instance */ + @Override public FieldTransform getInverse() { final FieldRotation r = angular.getRotation(); @@ -563,58 +545,6 @@ public class FieldTransform> FieldVector3D.getZero(date.getField()))); } - /** Transform a position vector (including translation effects). - * @param position vector to transform - * @return transformed position - */ - public FieldVector3D transformPosition(final Vector3D position) { - return angular.getRotation().applyTo(cartesian.getPosition().add(position)); - } - - /** Transform a position vector (including translation effects). - * @param position vector to transform - * @return transformed position - */ - public FieldVector3D transformPosition(final FieldVector3D position) { - return angular.getRotation().applyTo(position.add(cartesian.getPosition())); - } - - /** Transform a vector (ignoring translation effects). - * @param vector vector to transform - * @return transformed vector - */ - public FieldVector3D transformVector(final Vector3D vector) { - return angular.getRotation().applyTo(vector); - } - - /** Transform a vector (ignoring translation effects). - * @param vector vector to transform - * @return transformed vector - */ - public FieldVector3D transformVector(final FieldVector3D vector) { - return angular.getRotation().applyTo(vector); - } - - /** Transform a line. - * @param line to transform - * @return transformed line - */ - public FieldLine transformLine(final Line line) { - final FieldVector3D transformedP0 = transformPosition(line.getOrigin()); - final FieldVector3D transformedP1 = transformPosition(line.pointAt(1.0e6)); - return new FieldLine<>(transformedP0, transformedP1, 1.0e-10); - } - - /** Transform a line. - * @param line to transform - * @return transformed line - */ - public FieldLine transformLine(final FieldLine line) { - final FieldVector3D transformedP0 = transformPosition(line.getOrigin()); - final FieldVector3D transformedP1 = transformPosition(line.pointAt(1.0e6)); - return new FieldLine<>(transformedP0, transformedP1, 1.0e-10); - } - /** Transform {@link TimeStampedPVCoordinates} including kinematic effects. *

* In order to allow the user more flexibility, this method does not check for @@ -956,6 +886,12 @@ public class FieldTransform> return pv; } + /** {@inheritDoc} */ + @Override + public FieldTransform freeze() { + return this; + } + /** {@inheritDoc} */ @Override public void getJacobian(final CartesianDerivativesFilter selector, final T[][] jacobian) { diff --git a/src/main/java/org/orekit/frames/Frame.java b/src/main/java/org/orekit/frames/Frame.java index f80bd7573..a5ced5d30 100644 --- a/src/main/java/org/orekit/frames/Frame.java +++ b/src/main/java/org/orekit/frames/Frame.java @@ -292,6 +292,32 @@ public class Frame implements Serializable { StaticTransform::getInverse); } + /** + * Get the static portion of the transform from the instance to another + * frame. The returned transform is static in the sense that it includes + * translations and rotations, but not rates. + * + *

This method is often more performant than {@link + * #getTransformTo(Frame, FieldAbsoluteDate)} when rates are not needed. + * + * @param type of the elements + * @param destination destination frame to which we want to transform + * vectors + * @param date the date (can be null if it is sure than no date + * dependent frame is used) + * @return static transform from the instance to the destination frame + * @since 11.2 + */ + public > FieldStaticTransform getStaticTransformTo(final Frame destination, + final FieldAbsoluteDate date) { + return getTransformTo( + destination, + FieldStaticTransform.getIdentity(date.getField()), + frame -> frame.getTransformProvider().getStaticTransform(date), + (t1, t2) -> FieldStaticTransform.compose(date, t1, t2), + FieldStaticTransform::getInverse); + } + /** * Generic get transform method that builds the transform from {@code this} * to {@code destination}. diff --git a/src/main/java/org/orekit/frames/GTODProvider.java b/src/main/java/org/orekit/frames/GTODProvider.java index 8f4e71231..3f278c4c7 100644 --- a/src/main/java/org/orekit/frames/GTODProvider.java +++ b/src/main/java/org/orekit/frames/GTODProvider.java @@ -159,6 +159,20 @@ public class GTODProvider implements EOPBasedTransformProvider { } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + + // compute Greenwich apparent sidereal time, in radians + final T gast = gastFunction.value(date); + + // set up the transform from parent TOD + return FieldStaticTransform.of( + date, + new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), gast, RotationConvention.FRAME_TRANSFORM)); + + } + /** Replace the instance with a data transfer object for serialization. *

* This intermediate class serializes only the frame key. diff --git a/src/main/java/org/orekit/frames/HelmertTransformation.java b/src/main/java/org/orekit/frames/HelmertTransformation.java index 28f2b80d4..27843e8ea 100644 --- a/src/main/java/org/orekit/frames/HelmertTransformation.java +++ b/src/main/java/org/orekit/frames/HelmertTransformation.java @@ -17,6 +17,7 @@ package org.orekit.frames; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.geometry.euclidean.threed.FieldRotation; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Rotation; @@ -570,4 +571,29 @@ public class HelmertTransformation implements TransformProvider { } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + + // field + final Field field = date.getField(); + + // compute parameters evolution since reference epoch + final T dt = date.durationFrom(epoch); + final FieldVector3D dR = new FieldVector3D<>(field.getOne(), rotationVector, dt, rotationRate); + + // build translation part + final FieldVector3D translation = new FieldPVCoordinates<>(date.getField(), cartesian).shiftedBy(dt).getPosition(); + + // build rotation part + final T angle = dR.getNorm(); + final FieldRotation rotation = (angle.getReal() < Precision.SAFE_MIN) ? + FieldRotation.getIdentity(field) : + new FieldRotation<>(dR, angle, RotationConvention.VECTOR_OPERATOR); + + // combine both parts + return FieldStaticTransform.of(date, translation, rotation); + + } + } diff --git a/src/main/java/org/orekit/frames/ITRFVersion.java b/src/main/java/org/orekit/frames/ITRFVersion.java index 6de23084e..de6f22f80 100644 --- a/src/main/java/org/orekit/frames/ITRFVersion.java +++ b/src/main/java/org/orekit/frames/ITRFVersion.java @@ -280,6 +280,12 @@ public enum ITRFVersion { return provider.getTransform(date); } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + return provider.getStaticTransform(date); + } + } } diff --git a/src/main/java/org/orekit/frames/L1TransformProvider.java b/src/main/java/org/orekit/frames/L1TransformProvider.java index fe7cc03d8..c2ffa7f58 100644 --- a/src/main/java/org/orekit/frames/L1TransformProvider.java +++ b/src/main/java/org/orekit/frames/L1TransformProvider.java @@ -116,6 +116,19 @@ public class L1TransformProvider implements TransformProvider { new FieldTransform<>(date, rotation)); } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + final FieldPVCoordinates pv21 = secondaryBody.getPVCoordinates(date, frame); + final FieldVector3D translation = getL1(pv21.getPosition()).negate(); + final FieldRotation rotation = new FieldRotation<>(pv21.getPosition(), pv21.getVelocity(), + FieldVector3D.getPlusI(date.getField()), FieldVector3D.getPlusJ(date.getField())); + return FieldStaticTransform.compose( + date, + FieldStaticTransform.of(date, translation), + FieldStaticTransform.of(date, rotation)); + } + /** Compute the coordinates of the L1 point. * @param primaryToSecondary relative position of secondary body with respect to primary body * @return coordinates of the L1 point given in frame: primaryBody.getInertiallyOrientedFrame() diff --git a/src/main/java/org/orekit/frames/L2TransformProvider.java b/src/main/java/org/orekit/frames/L2TransformProvider.java index 6dff16885..f40c78b2e 100644 --- a/src/main/java/org/orekit/frames/L2TransformProvider.java +++ b/src/main/java/org/orekit/frames/L2TransformProvider.java @@ -116,6 +116,19 @@ class L2TransformProvider implements TransformProvider { new FieldTransform<>(date, rotation)); } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + final FieldPVCoordinates pv21 = secondaryBody.getPVCoordinates(date, frame); + final FieldVector3D translation = getL2(pv21.getPosition()).negate(); + final FieldRotation rotation = new FieldRotation<>(pv21.getPosition(), pv21.getVelocity(), + FieldVector3D.getPlusI(date.getField()), FieldVector3D.getPlusJ(date.getField())); + return FieldStaticTransform.compose( + date, + FieldStaticTransform.of(date, translation), + FieldStaticTransform.of(date, rotation)); + } + /** Compute the coordinates of the L2 point. * @param primaryToSecondary relative position of secondary body with respect to primary body * @return coordinates of the L2 point given in frame: primaryBody.getInertiallyOrientedFrame() diff --git a/src/main/java/org/orekit/frames/ShiftingTransformProvider.java b/src/main/java/org/orekit/frames/ShiftingTransformProvider.java index 971eba9ab..be788cd11 100644 --- a/src/main/java/org/orekit/frames/ShiftingTransformProvider.java +++ b/src/main/java/org/orekit/frames/ShiftingTransformProvider.java @@ -165,6 +165,33 @@ public class ShiftingTransformProvider implements TransformProvider { return closest.shiftedBy(date.durationFrom(closest.getDate())); } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + @SuppressWarnings("unchecked") + GenericTimeStampedCache> fieldCache = + (GenericTimeStampedCache>) fieldCaches.get(date.getField()); + if (fieldCache == null) { + fieldCache = + new GenericTimeStampedCache>(cache.getNeighborsSize(), + cache.getMaxSlots(), + cache.getMaxSpan(), + cache.getNewSlotQuantumGap(), + new FieldTransformGenerator<>(date.getField(), + cache.getNeighborsSize(), + interpolatingProvider, + interpolatingProvider.getStep())); + fieldCaches.put(date.getField(), fieldCache); + } + + // retrieve a sample from the thread-safe cache + final FieldTransform closest = fieldCache.getNeighbors(date.toAbsoluteDate()).reduce((t0, t1) -> + date.durationFrom(t0.getDate()).abs().getReal() < date.durationFrom(t1.getDate()).abs().getReal() ? + t0 : t1 + ).get(); + return closest.staticShiftedBy(date.durationFrom(closest.getDate())); + } + /** Replace the instance with a data transfer object for serialization. *

* This intermediate class serializes only the data needed for generation, diff --git a/src/main/java/org/orekit/frames/TIRFProvider.java b/src/main/java/org/orekit/frames/TIRFProvider.java index f2ca1f985..56a1ba878 100644 --- a/src/main/java/org/orekit/frames/TIRFProvider.java +++ b/src/main/java/org/orekit/frames/TIRFProvider.java @@ -133,6 +133,19 @@ class TIRFProvider implements EOPBasedTransformProvider { } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + // compute proper rotation + final T correctedERA = era.value(date); + // set up the transform from parent CIRF + final FieldRotation rotation = new FieldRotation<>( + FieldVector3D.getPlusK(date.getField()), + correctedERA, + RotationConvention.FRAME_TRANSFORM); + return FieldStaticTransform.of(date, rotation); + } + /** Get the Earth Rotation Angle at the current date. * @param date the date * @return Earth Rotation Angle at the current date in radians diff --git a/src/main/java/org/orekit/frames/TopocentricFrame.java b/src/main/java/org/orekit/frames/TopocentricFrame.java index 44f396aff..277cf5bc6 100644 --- a/src/main/java/org/orekit/frames/TopocentricFrame.java +++ b/src/main/java/org/orekit/frames/TopocentricFrame.java @@ -204,7 +204,7 @@ public class TopocentricFrame extends Frame implements PVCoordinatesProvider { final FieldAbsoluteDate date) { // Transform given point from given frame to topocentric frame - final FieldTransform t = frame.getTransformTo(this, date); + final FieldStaticTransform t = frame.getStaticTransformTo(this, date); final FieldVector3D extPointTopo = t.transformPosition(extPoint); // Elevation angle is PI/2 - angle between zenith and given point direction @@ -251,7 +251,7 @@ public class TopocentricFrame extends Frame implements PVCoordinatesProvider { final FieldAbsoluteDate date) { // Transform given point from given frame to topocentric frame - final FieldTransform t = getTransformTo(frame, date).getInverse(); + final FieldStaticTransform t = frame.getStaticTransformTo(frame, date).getInverse(); final FieldVector3D extPointTopo = t.transformPosition(extPoint); // Compute azimuth @@ -293,7 +293,7 @@ public class TopocentricFrame extends Frame implements PVCoordinatesProvider { final FieldAbsoluteDate date) { // Transform given point from given frame to topocentric frame - final FieldTransform t = frame.getTransformTo(this, date); + final FieldStaticTransform t = frame.getStaticTransformTo(this, date); final FieldVector3D extPointTopo = t.transformPosition(extPoint); // Compute range diff --git a/src/main/java/org/orekit/frames/TransformProvider.java b/src/main/java/org/orekit/frames/TransformProvider.java index 95dbc8c1e..bb4c088a9 100644 --- a/src/main/java/org/orekit/frames/TransformProvider.java +++ b/src/main/java/org/orekit/frames/TransformProvider.java @@ -58,4 +58,18 @@ public interface TransformProvider extends Serializable { return getTransform(date); } + /** + * Get a transform for only rotations and translations on the specified date. + * + *

The default implementation returns {@link #getTransform(AbsoluteDate)} + * but implementations may override it for better performance. + * + * @param type of the elements + * @param date current date. + * @return the static transform. + */ + default > FieldStaticTransform getStaticTransform(FieldAbsoluteDate date) { + return getTransform(date); + } + } diff --git a/src/main/java/org/orekit/frames/TransformProviderUtils.java b/src/main/java/org/orekit/frames/TransformProviderUtils.java index 32d69ef6c..5959a9a96 100644 --- a/src/main/java/org/orekit/frames/TransformProviderUtils.java +++ b/src/main/java/org/orekit/frames/TransformProviderUtils.java @@ -95,6 +95,12 @@ public class TransformProviderUtils { return provider.getTransform(date).getInverse(); } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + return provider.getStaticTransform(date).getInverse(); + } + }; } @@ -132,6 +138,16 @@ public class TransformProviderUtils { return new FieldTransform<>(date, first.getTransform(date), second.getTransform(date)); } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + return FieldStaticTransform.compose( + date, + first.getStaticTransform(date), + second.getStaticTransform(date) + ); + } + }; } diff --git a/src/main/java/org/orekit/frames/VersionedITRFProvider.java b/src/main/java/org/orekit/frames/VersionedITRFProvider.java index 62785750b..db70b63be 100644 --- a/src/main/java/org/orekit/frames/VersionedITRFProvider.java +++ b/src/main/java/org/orekit/frames/VersionedITRFProvider.java @@ -139,6 +139,26 @@ class VersionedITRFProvider implements EOPBasedTransformProvider { } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + + // get the transform from the current EOP + final FieldStaticTransform rawTransform = rawProvider.getStaticTransform(date); + + // add the conversion layer + final ITRFVersion.Converter converterForDate = getConverter(date.toAbsoluteDate()); + if (converterForDate == null) { + return rawTransform; + } else { + return FieldStaticTransform.compose( + date, + rawTransform, + converterForDate.getStaticTransform(date)); + } + + } + /** Get a converter for the date. * @param date date to check * @return converter that should be applied for this date, or null diff --git a/src/main/java/org/orekit/models/earth/Geoid.java b/src/main/java/org/orekit/models/earth/Geoid.java index bbd38b924..609585e1b 100644 --- a/src/main/java/org/orekit/models/earth/Geoid.java +++ b/src/main/java/org/orekit/models/earth/Geoid.java @@ -16,8 +16,8 @@ */ package org.orekit.models.earth; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.analysis.CalculusFieldUnivariateFunction; import org.hipparchus.analysis.UnivariateFunction; import org.hipparchus.analysis.solvers.AllowedSolution; @@ -38,7 +38,7 @@ import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel; import org.orekit.forces.gravity.potential.GravityFields; import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider; import org.orekit.forces.gravity.potential.TideSystem; -import org.orekit.frames.FieldTransform; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; import org.orekit.time.AbsoluteDate; @@ -481,7 +481,7 @@ public class Geoid implements EarthShape { */ // transform to body frame final Frame bodyFrame = this.getBodyFrame(); - final FieldTransform frameToBody = frame.getTransformTo(bodyFrame, date); + final FieldStaticTransform frameToBody = frame.getStaticTransformTo(bodyFrame, date); final FieldVector3D close = frameToBody.transformPosition(closeInFrame); final FieldLine lineInBodyFrame = frameToBody.transformLine(lineInFrame); diff --git a/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java b/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java index d0a897339..ddbccda28 100644 --- a/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java +++ b/src/main/java/org/orekit/models/earth/atmosphere/DTM2000.java @@ -394,7 +394,7 @@ public class DTM2000 implements Atmosphere { final int day = date.getComponents(utc).getDate().getDayOfYear(); // position in ECEF so we only have to do the transform once final Frame ecef = earth.getBodyFrame(); - final FieldVector3D pEcef = frame.getTransformTo(ecef, date).transformPosition(position); + final FieldVector3D pEcef = frame.getStaticTransformTo(ecef, date).transformPosition(position); // compute geodetic position final FieldGeodeticPoint inBody = earth.transform(pEcef, ecef, date); final T alti = inBody.getAltitude(); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java index 1d902141b..3ed82625c 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/DSSTTesseral.java @@ -27,8 +27,8 @@ import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.analysis.differentiation.FieldGradient; import org.hipparchus.analysis.differentiation.Gradient; import org.hipparchus.exception.LocalizedCoreFormats; @@ -44,7 +44,7 @@ import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitInternalError; import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider; import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics; -import org.orekit.frames.FieldTransform; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; import org.orekit.orbits.FieldOrbit; @@ -1990,7 +1990,7 @@ public class DSSTTesseral implements DSSTForceModel { final FieldAuxiliaryElements auxiliaryElements = new FieldAuxiliaryElements<>(meanOrbit, I); // Central body rotation angle from equation 2.7.1-(3)(4). - final FieldTransform t = bodyFrame.getTransformTo(auxiliaryElements.getFrame(), auxiliaryElements.getDate()); + final FieldStaticTransform t = bodyFrame.getStaticTransformTo(auxiliaryElements.getFrame(), auxiliaryElements.getDate()); final FieldVector3D xB = t.transformVector(Vector3D.PLUS_I); final FieldVector3D yB = t.transformVector(Vector3D.PLUS_J); final FieldVector3D f = auxiliaryElements.getVectorF(); diff --git a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java index 8eb08d37d..d9d5a7e8f 100644 --- a/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java +++ b/src/main/java/org/orekit/propagation/semianalytical/dsst/forces/FieldDSSTTesseralContext.java @@ -16,12 +16,12 @@ */ package org.orekit.propagation.semianalytical.dsst.forces; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.geometry.euclidean.threed.FieldVector3D; import org.hipparchus.util.FastMath; import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider; -import org.orekit.frames.FieldTransform; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.Frame; import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements; @@ -136,7 +136,7 @@ public class FieldDSSTTesseralContext> extends e2 = auxiliaryElements.getEcc().multiply(auxiliaryElements.getEcc()); // Central body rotation angle from equation 2.7.1-(3)(4). - final FieldTransform t = centralBodyFrame.getTransformTo(auxiliaryElements.getFrame(), auxiliaryElements.getDate()); + final FieldStaticTransform t = centralBodyFrame.getStaticTransformTo(auxiliaryElements.getFrame(), auxiliaryElements.getDate()); final FieldVector3D xB = t.transformVector(FieldVector3D.getPlusI(field)); final FieldVector3D yB = t.transformVector(FieldVector3D.getPlusJ(field)); theta = FastMath.atan2(auxiliaryElements.getVectorF().dotProduct(yB).negate().add((auxiliaryElements.getVectorG().dotProduct(xB)).multiply(I)), diff --git a/src/main/java/org/orekit/utils/FieldAngularCoordinates.java b/src/main/java/org/orekit/utils/FieldAngularCoordinates.java index 16553b1af..3543b6c5b 100644 --- a/src/main/java/org/orekit/utils/FieldAngularCoordinates.java +++ b/src/main/java/org/orekit/utils/FieldAngularCoordinates.java @@ -557,6 +557,68 @@ public class FieldAngularCoordinates> { rotation.applyInverseTo(rotationAcceleration.negate())); } + /** Get a time-shifted rotation. Same as {@link #shiftedBy(double)} except + * only the shifted rotation is computed. + *

+ * The state can be slightly shifted to close dates. This shift is based on + * an approximate solution of the fixed acceleration motion. It is not + * intended as a replacement for proper attitude propagation but should be + * sufficient for either small time shifts or coarse accuracy. + *

+ * @param dt time shift in seconds + * @return a new state, shifted with respect to the instance (which is immutable) + * @see #shiftedBy(CalculusFieldElement) + * @since 11.2 + */ + public FieldRotation rotationShiftedBy(final T dt) { + + // the shiftedBy method is based on a local approximation. + // It considers separately the contribution of the constant + // rotation, the linear contribution or the rate and the + // quadratic contribution of the acceleration. The rate + // and acceleration contributions are small rotations as long + // as the time shift is small, which is the crux of the algorithm. + // Small rotations are almost commutative, so we append these small + // contributions one after the other, as if they really occurred + // successively, despite this is not what really happens. + + // compute the linear contribution first, ignoring acceleration + // BEWARE: there is really a minus sign here, because if + // the target frame rotates in one direction, the vectors in the origin + // frame seem to rotate in the opposite direction + final T rate = rotationRate.getNorm(); + final FieldRotation rateContribution = (rate.getReal() == 0.0) ? + FieldRotation.getIdentity(dt.getField()) : + new FieldRotation<>(rotationRate, rate.multiply(dt), RotationConvention.FRAME_TRANSFORM); + + // append rotation and rate contribution + final FieldRotation linearPart = + rateContribution.compose(rotation, RotationConvention.VECTOR_OPERATOR); + + final T acc = rotationAcceleration.getNorm(); + if (acc.getReal() == 0.0) { + // no acceleration, the linear part is sufficient + return linearPart; + } + + // compute the quadratic contribution, ignoring initial rotation and rotation rate + // BEWARE: there is really a minus sign here, because if + // the target frame rotates in one direction, the vectors in the origin + // frame seem to rotate in the opposite direction + final FieldRotation quadraticContribution = + new FieldRotation<>(rotationAcceleration, + acc.multiply(dt).multiply(dt).multiply(0.5), + RotationConvention.FRAME_TRANSFORM); + + // the quadratic contribution is a small rotation: + // its initial angle and angular rate are both zero. + // small rotations are almost commutative, so we append the small + // quadratic part after the linear part as a simple offset + return quadraticContribution + .compose(linearPart, RotationConvention.VECTOR_OPERATOR); + + } + /** Get a time-shifted state. *

* The state can be slightly shifted to close dates. This shift is based on diff --git a/src/main/java/org/orekit/utils/FieldPVCoordinates.java b/src/main/java/org/orekit/utils/FieldPVCoordinates.java index f9352619a..edc8b4bb6 100644 --- a/src/main/java/org/orekit/utils/FieldPVCoordinates.java +++ b/src/main/java/org/orekit/utils/FieldPVCoordinates.java @@ -642,14 +642,31 @@ public class FieldPVCoordinates> */ public FieldPVCoordinates shiftedBy(final T dt) { final T one = dt.getField().getOne(); - return new FieldPVCoordinates<>(new FieldVector3D<>(one, position, - dt, velocity, - dt.multiply(dt).multiply(0.5), acceleration), - new FieldVector3D<>(one, velocity, - dt, acceleration), + return new FieldPVCoordinates<>(positionShiftedBy(dt), + new FieldVector3D<>(one, velocity, dt, acceleration), acceleration); } + /** + * Get a time-shifted position. Same as {@link #shiftedBy(CalculusFieldElement)} except + * that only the sifted position is returned. + *

+ * The state can be slightly shifted to close dates. This shift is based on + * a simple Taylor expansion. It is not intended as a replacement + * for proper orbit propagation (it is not even Keplerian!) but should be + * sufficient for either small time shifts or coarse accuracy. + *

+ * + * @param dt time shift in seconds + * @return a new state, shifted with respect to the instance (which is + * immutable) + * @since 11.2 + */ + public FieldVector3D positionShiftedBy(final T dt) { + final T one = dt.getField().getOne(); + return new FieldVector3D<>(one, position, dt, velocity, dt.multiply(dt).multiply(0.5), acceleration); + } + /** Gets the position. * @return the position vector (m). */ -- GitLab