From 38328ccf218fa3cabe54e87dc5732b2090037608 Mon Sep 17 00:00:00 2001 From: Bryan Cazabonne Date: Wed, 30 Mar 2022 14:24:52 +0200 Subject: [PATCH] Started working on Field implementation of the static transform. --- .../orekit/attitudes/LofOffsetPointing.java | 27 +- .../org/orekit/attitudes/NadirPointing.java | 18 +- .../org/orekit/bodies/JPLCelestialBody.java | 27 ++ .../org/orekit/bodies/OneAxisEllipsoid.java | 8 +- .../EstimatedEarthFrameProvider.java | 28 ++ .../measurements/GroundStation.java | 12 +- .../gravity/LenseThirringRelativity.java | 8 +- .../CR3BPRotatingTransformProvider.java | 21 +- .../orekit/frames/FieldStaticTransform.java | 281 ++++++++++++++++++ .../org/orekit/frames/FieldTransform.java | 118 ++------ src/main/java/org/orekit/frames/Frame.java | 26 ++ .../java/org/orekit/frames/GTODProvider.java | 14 + .../orekit/frames/HelmertTransformation.java | 26 ++ .../java/org/orekit/frames/ITRFVersion.java | 6 + .../orekit/frames/L1TransformProvider.java | 13 + .../orekit/frames/L2TransformProvider.java | 13 + .../frames/ShiftingTransformProvider.java | 27 ++ .../java/org/orekit/frames/TIRFProvider.java | 13 + .../org/orekit/frames/TopocentricFrame.java | 6 +- .../org/orekit/frames/TransformProvider.java | 14 + .../orekit/frames/TransformProviderUtils.java | 16 + .../orekit/frames/VersionedITRFProvider.java | 20 ++ .../java/org/orekit/models/earth/Geoid.java | 6 +- .../models/earth/atmosphere/DTM2000.java | 2 +- .../dsst/forces/DSSTTesseral.java | 6 +- .../dsst/forces/FieldDSSTTesseralContext.java | 6 +- .../orekit/utils/FieldAngularCoordinates.java | 62 ++++ .../org/orekit/utils/FieldPVCoordinates.java | 27 +- 28 files changed, 710 insertions(+), 141 deletions(-) create mode 100644 src/main/java/org/orekit/frames/FieldStaticTransform.java diff --git a/src/main/java/org/orekit/attitudes/LofOffsetPointing.java b/src/main/java/org/orekit/attitudes/LofOffsetPointing.java index b59f4b2d7..073281b45 100644 --- a/src/main/java/org/orekit/attitudes/LofOffsetPointing.java +++ b/src/main/java/org/orekit/attitudes/LofOffsetPointing.java @@ -29,6 +29,7 @@ import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FieldTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; @@ -149,18 +150,24 @@ public class LofOffsetPointing extends GroundPointing { final FieldAbsoluteDate shifted = date.shiftedBy(i * h); // transform from specified reference frame to spacecraft frame - final FieldTransform refToSc = - new FieldTransform<>(shifted, - new FieldTransform<>(shifted, pvProv.getPVCoordinates(shifted, frame).negate()), - new FieldTransform<>(shifted, attitudeLaw.getAttitude(pvProv, shifted, frame).getOrientation())); + final FieldStaticTransform refToSc = FieldStaticTransform.compose( + shifted, + FieldStaticTransform.of( + shifted, + pvProv.getPVCoordinates(shifted, frame).getPosition().negate()), + FieldStaticTransform.of( + shifted, + attitudeLaw.getAttitude(pvProv, shifted, frame).getRotation())); // transform from specified reference frame to body frame - final FieldTransform refToBody = frame.getTransformTo(shape.getBodyFrame(), shifted); + final FieldStaticTransform refToBody; if (i == 0) { - centralRefToBody = refToBody; + refToBody = centralRefToBody = frame.getTransformTo(shape.getBodyFrame(), shifted); + } else { + refToBody = frame.getStaticTransformTo(shape.getBodyFrame(), shifted); } - sample.add(losIntersectionWithBody(new FieldTransform<>(shifted, refToSc.getInverse(), refToBody))); + sample.add(losIntersectionWithBody(FieldStaticTransform.compose(shifted, refToSc.getInverse(), refToBody))); } @@ -212,7 +219,7 @@ public class LofOffsetPointing extends GroundPointing { * @param type of the field elements * @return intersection point in body frame (only the position is set!) */ - private > TimeStampedFieldPVCoordinates losIntersectionWithBody(final FieldTransform scToBody) { + private > TimeStampedFieldPVCoordinates losIntersectionWithBody(final FieldStaticTransform scToBody) { // compute satellite pointing axis and position/velocity in body frame final FieldVector3D pointingBodyFrame = scToBody.transformVector(satPointingVector); @@ -227,7 +234,7 @@ public class LofOffsetPointing extends GroundPointing { // Intersection with body shape final FieldGeodeticPoint gpIntersection = - shape.getIntersectionPoint(pointingLine, pBodyFrame, shape.getBodyFrame(), scToBody.getFieldDate()); + shape.getIntersectionPoint(pointingLine, pBodyFrame, shape.getBodyFrame(), new FieldAbsoluteDate<>(pBodyFrame.getX().getField(), scToBody.getDate())); final FieldVector3D pIntersection = (gpIntersection == null) ? null : shape.transform(gpIntersection); @@ -237,7 +244,7 @@ public class LofOffsetPointing extends GroundPointing { throw new OrekitException(OrekitMessages.ATTITUDE_POINTING_LAW_DOES_NOT_POINT_TO_GROUND); } - final FieldVector3D zero = FieldVector3D.getZero(scToBody.getFieldDate().getField()); + final FieldVector3D zero = FieldVector3D.getZero(pBodyFrame.getX().getField()); return new TimeStampedFieldPVCoordinates<>(scToBody.getDate(), pIntersection, zero, zero); diff --git a/src/main/java/org/orekit/attitudes/NadirPointing.java b/src/main/java/org/orekit/attitudes/NadirPointing.java index 2d9d944af..29dd1e4ec 100644 --- a/src/main/java/org/orekit/attitudes/NadirPointing.java +++ b/src/main/java/org/orekit/attitudes/NadirPointing.java @@ -25,6 +25,7 @@ import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.orekit.bodies.BodyShape; import org.orekit.bodies.FieldGeodeticPoint; import org.orekit.bodies.GeodeticPoint; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FieldTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; @@ -88,8 +89,11 @@ public class NadirPointing extends GroundPointing { /** {@inheritDoc} */ public > TimeStampedFieldPVCoordinates getTargetPV(final FieldPVCoordinatesProvider pvProv, - final FieldAbsoluteDate date, - final Frame frame) { + final FieldAbsoluteDate date, + final Frame frame) { + + // zero + final T zero = date.getField().getZero(); // transform from specified reference frame to body frame final FieldTransform refToBody = frame.getTransformTo(shape.getBodyFrame(), date); @@ -97,11 +101,11 @@ public class NadirPointing extends GroundPointing { // sample intersection points in current date neighborhood final double h = 0.01; final List> sample = new ArrayList<>(); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-2 * h), frame), refToBody.shiftedBy(-2 * h))); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-h), frame), refToBody.shiftedBy(-h))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-2 * h), frame), refToBody.staticShiftedBy(zero.add(-2 * h)))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(-h), frame), refToBody.staticShiftedBy(zero.add(-h)))); sample.add(nadirRef(pvProv.getPVCoordinates(date, frame), refToBody)); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+h), frame), refToBody.shiftedBy(+h))); - sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+2 * h), frame), refToBody.shiftedBy(+2 * h))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+h), frame), refToBody.staticShiftedBy(zero.add(+h)))); + sample.add(nadirRef(pvProv.getPVCoordinates(date.shiftedBy(+2 * h), frame), refToBody.staticShiftedBy(zero.add(+2 * h)))); // use interpolation to compute properly the time-derivatives return TimeStampedFieldPVCoordinates.interpolate(date, CartesianDerivativesFilter.USE_P, sample); @@ -142,7 +146,7 @@ public class NadirPointing extends GroundPointing { * @since 9.0 */ private > TimeStampedFieldPVCoordinates nadirRef(final TimeStampedFieldPVCoordinates scRef, - final FieldTransform refToBody) { + final FieldStaticTransform refToBody) { final FieldVector3D satInBodyFrame = refToBody.transformPosition(scRef.getPosition()); diff --git a/src/main/java/org/orekit/bodies/JPLCelestialBody.java b/src/main/java/org/orekit/bodies/JPLCelestialBody.java index aa686fb54..be3a5194c 100644 --- a/src/main/java/org/orekit/bodies/JPLCelestialBody.java +++ b/src/main/java/org/orekit/bodies/JPLCelestialBody.java @@ -19,6 +19,7 @@ package org.orekit.bodies; import java.io.Serializable; 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; @@ -30,6 +31,7 @@ import org.orekit.bodies.JPLEphemeridesLoader.EphemerisType; import org.orekit.data.DataContext; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitInternalError; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FieldTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; @@ -276,6 +278,31 @@ class JPLCelestialBody implements CelestialBody { } + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + // field + final Field field = date.getField(); + // compute translation from parent frame to self + final FieldPVCoordinates pv = getPVCoordinates(date, definingFrame); + + // compute rotation from ICRF frame to self, + // as per the "Report of the IAU/IAG Working Group on Cartographic + // Coordinates and Rotational Elements of the Planets and Satellites" + // These definitions are common for all recent versions of this report + // published every three years, the precise values of pole direction + // and W angle coefficients may vary from publication year as models are + // adjusted. These coefficients are not in this class, they are in the + // specialized classes that do implement the getPole and getPrimeMeridianAngle + // methods + final FieldVector3D pole = iauPole.getPole(date); + final FieldVector3D qNode = iauPole.getNode(date); + final FieldRotation rotation = + new FieldRotation<>(pole, qNode, FieldVector3D.getPlusK(field), FieldVector3D.getPlusI(field)); + + // update transform from parent to self + return FieldStaticTransform.of(date, pv.getPosition().negate(), rotation); + } + }, frameName == null ? name + INERTIAL_FRAME_SUFFIX : frameName, true); } diff --git a/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java b/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java index d5b12a933..3a8d8bcf4 100644 --- a/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java +++ b/src/main/java/org/orekit/bodies/OneAxisEllipsoid.java @@ -29,7 +29,7 @@ import org.hipparchus.util.FastMath; import org.hipparchus.util.FieldSinCos; import org.hipparchus.util.MathArrays; import org.hipparchus.util.SinCos; -import org.orekit.frames.FieldTransform; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; import org.orekit.frames.Transform; @@ -250,8 +250,8 @@ public class OneAxisEllipsoid extends Ellipsoid implements BodyShape { final FieldAbsoluteDate date) { // transform line and close to body frame - final FieldTransform frameToBodyFrame = frame.getTransformTo(bodyFrame, date); - final FieldLine lineInBodyFrame = frameToBodyFrame.transformLine(line); + final FieldStaticTransform frameToBodyFrame = frame.getStaticTransformTo(bodyFrame, date); + final FieldLine lineInBodyFrame = frameToBodyFrame.transformLine(line); // compute some miscellaneous variables final FieldVector3D point = lineInBodyFrame.getOrigin(); @@ -547,7 +547,7 @@ public class OneAxisEllipsoid extends Ellipsoid implements BodyShape { final FieldAbsoluteDate date) { // transform point to body frame - final FieldVector3D pointInBodyFrame = frame.getTransformTo(bodyFrame, date).transformPosition(point); + final FieldVector3D pointInBodyFrame = frame.getStaticTransformTo(bodyFrame, date).transformPosition(point); final T r2 = pointInBodyFrame.getX().multiply(pointInBodyFrame.getX()). add(pointInBodyFrame.getY().multiply(pointInBodyFrame.getY())); final T r = r2.sqrt(); diff --git a/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java b/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java index 5627f880c..d5f24f223 100644 --- a/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java +++ b/src/main/java/org/orekit/estimation/measurements/EstimatedEarthFrameProvider.java @@ -30,6 +30,7 @@ import org.hipparchus.util.FastMath; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitInternalError; import org.orekit.errors.OrekitMessages; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FieldTransform; import org.orekit.frames.StaticTransform; import org.orekit.frames.Transform; @@ -290,6 +291,33 @@ public class EstimatedEarthFrameProvider implements TransformProvider { } + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + + // take parametric prime meridian shift into account + final T theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver); + final FieldStaticTransform meridianShift = FieldStaticTransform.of( + date, + new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), theta, RotationConvention.FRAME_TRANSFORM) + ); + + // take parametric pole shift into account + final T xpNeg = linearModel(date, polarOffsetXDriver, polarDriftXDriver).negate(); + final T ypNeg = linearModel(date, polarOffsetYDriver, polarDriftYDriver).negate(); + final FieldStaticTransform poleShift = FieldStaticTransform.compose( + date, + FieldStaticTransform.of( + date, + new FieldRotation<>(FieldVector3D.getPlusJ(date.getField()), xpNeg, RotationConvention.FRAME_TRANSFORM)), + FieldStaticTransform.of( + date, + new FieldRotation<>(FieldVector3D.getPlusI(date.getField()), ypNeg, RotationConvention.FRAME_TRANSFORM))); + + return FieldStaticTransform.compose(date, meridianShift, poleShift); + + } + /** Get the transform with derivatives. * @param date date of the transform * @param freeParameters total number of free parameters in the gradient diff --git a/src/main/java/org/orekit/estimation/measurements/GroundStation.java b/src/main/java/org/orekit/estimation/measurements/GroundStation.java index 111b59b1f..a024cc528 100644 --- a/src/main/java/org/orekit/estimation/measurements/GroundStation.java +++ b/src/main/java/org/orekit/estimation/measurements/GroundStation.java @@ -33,6 +33,7 @@ import org.orekit.data.FundamentalNutationArguments; import org.orekit.errors.OrekitException; import org.orekit.errors.OrekitMessages; import org.orekit.frames.EOPHistory; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.FieldTransform; import org.orekit.frames.Frame; import org.orekit.frames.FramesFactory; @@ -530,12 +531,11 @@ public class GroundStation { estimatedEarthFrameProvider.getTransform(offsetCompensatedDate, freeParameters, indices).getInverse(); // take station offsets into account - final Gradient x = eastOffsetDriver.getValue(freeParameters, indices); - final Gradient y = northOffsetDriver.getValue(freeParameters, indices); - final Gradient z = zenithOffsetDriver.getValue(freeParameters, indices); - final BodyShape baseShape = baseFrame.getParentShape(); - final StaticTransform baseToBody = baseFrame - .getStaticTransformTo(baseShape.getBodyFrame(), null); + final Gradient x = eastOffsetDriver.getValue(freeParameters, indices); + final Gradient y = northOffsetDriver.getValue(freeParameters, indices); + final Gradient z = zenithOffsetDriver.getValue(freeParameters, indices); + final BodyShape baseShape = baseFrame.getParentShape(); + final FieldStaticTransform baseToBody = baseFrame.getStaticTransformTo(baseShape.getBodyFrame(), offsetCompensatedDate); FieldVector3D origin = baseToBody.transformPosition(new FieldVector3D<>(x, y, z)); origin = origin.add(computeDisplacement(offsetCompensatedDate.toAbsoluteDate(), origin.toVector3D())); diff --git a/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java b/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java index 712b0b448..24cc1a8ef 100644 --- a/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java +++ b/src/main/java/org/orekit/forces/gravity/LenseThirringRelativity.java @@ -20,13 +20,13 @@ import java.util.Collections; 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.FieldVector3D; import org.hipparchus.geometry.euclidean.threed.Vector3D; import org.hipparchus.util.FastMath; import org.orekit.forces.AbstractForceModel; -import org.orekit.frames.FieldTransform; +import org.orekit.frames.FieldStaticTransform; import org.orekit.frames.Frame; import org.orekit.frames.StaticTransform; import org.orekit.propagation.FieldSpacecraftState; @@ -140,8 +140,8 @@ public class LenseThirringRelativity extends AbstractForceModel { final T r2 = r.multiply(r); // Earth’s angular momentum per unit mass - final FieldTransform t = bodyFrame.getTransformTo(s.getFrame(), s.getDate()); - final FieldVector3D j = t.transformVector(Vector3D.PLUS_K).scalarMultiply(J); + final FieldStaticTransform t = bodyFrame.getStaticTransformTo(s.getFrame(), s.getDate()); + final FieldVector3D j = t.transformVector(Vector3D.PLUS_K).scalarMultiply(J); return new FieldVector3D<>(p.dotProduct(j).multiply(3.0).divide(r2), p.crossProduct(v), diff --git a/src/main/java/org/orekit/frames/CR3BPRotatingTransformProvider.java b/src/main/java/org/orekit/frames/CR3BPRotatingTransformProvider.java index ce6a2e54e..ba14938ac 100644 --- a/src/main/java/org/orekit/frames/CR3BPRotatingTransformProvider.java +++ b/src/main/java/org/orekit/frames/CR3BPRotatingTransformProvider.java @@ -16,8 +16,8 @@ */ package org.orekit.frames; -import org.hipparchus.Field; import org.hipparchus.CalculusFieldElement; +import org.hipparchus.Field; import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2; import org.hipparchus.analysis.differentiation.UnivariateDerivative2; import org.hipparchus.geometry.euclidean.threed.FieldRotation; @@ -30,6 +30,7 @@ import org.orekit.bodies.CelestialBody; import org.orekit.time.AbsoluteDate; import org.orekit.time.FieldAbsoluteDate; import org.orekit.utils.FieldPVCoordinates; +import org.orekit.utils.TimeStampedFieldPVCoordinates; import org.orekit.utils.TimeStampedPVCoordinates; /** Transform provider for the rotating frame of the CR3BP System. @@ -128,4 +129,22 @@ class CR3BPRotatingTransformProvider implements TransformProvider { final FieldTransform transform2 = new FieldTransform<>(date, rotationField, rotationRate, rotationAcc); return new FieldTransform<>(date, transform2, transform1); } + + /** {@inheritDoc} */ + @Override + public > FieldStaticTransform getStaticTransform(final FieldAbsoluteDate date) { + final Field field = date.getField(); + final TimeStampedFieldPVCoordinates pv = secondaryBody.getPVCoordinates(date, frame); + final FieldVector3D translation = FieldVector3D.getPlusI(field). + scalarMultiply(pv.getPosition().getNorm().multiply(mu)).negate(); + + final FieldRotation rotation = new FieldRotation<>( + pv.getPosition(), pv.getMomentum(), + FieldVector3D.getPlusI(field), FieldVector3D.getMinusK(field)); + + final FieldStaticTransform transform1 = FieldStaticTransform.of(date, translation); + final FieldStaticTransform transform2 = FieldStaticTransform.of(date, rotation); + return FieldStaticTransform.compose(date, transform2, transform1); + } + } diff --git a/src/main/java/org/orekit/frames/FieldStaticTransform.java b/src/main/java/org/orekit/frames/FieldStaticTransform.java new file mode 100644 index 000000000..985288ac2 --- /dev/null +++ b/src/main/java/org/orekit/frames/FieldStaticTransform.java @@ -0,0 +1,281 @@ +/* Copyright 2002-2022 CS GROUP + * Licensed to CS GROUP (CS) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * CS licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.orekit.frames; + +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.TimeStamped; + +/** + * A transform that only includes translation and rotation. It is static in the + * sense that no rates thereof are included. + * + * @author Bryan Cazabonne + * @see FieldTransform + * @since 11.2 + */ +public interface FieldStaticTransform> extends TimeStamped { + + /** + * Get the identity static transform. + * + * @param type of the elements + * @param field field used by default + * @return identity transform. + */ + static > FieldStaticTransform getIdentity(final Field field) { + return FieldTransform.getIdentity(field); + } + + /** + * Transform a position vector (including translation effects). + * + * @param position vector to transform + * @return transformed position + */ + default FieldVector3D transformPosition(final Vector3D position) { + return getRotation().applyTo(getTranslation().add(position)); + } + + /** + * Transform a position vector (including translation effects). + * + * @param position vector to transform + * @return transformed position + */ + default FieldVector3D transformPosition(final FieldVector3D position) { + return getRotation().applyTo(position.add(getTranslation())); + } + + /** + * Transform a vector (ignoring translation effects). + * + * @param vector vector to transform + * @return transformed vector + */ + default FieldVector3D transformVector(final Vector3D vector) { + return getRotation().applyTo(vector); + } + + /** + * Transform a vector (ignoring translation effects). + * + * @param vector vector to transform + * @return transformed vector + */ + default FieldVector3D transformVector(final FieldVector3D vector) { + return getRotation().applyTo(vector); + } + + /** + * Transform a line. + * + * @param line to transform + * @return transformed line + */ + default FieldLine transformLine(final Line line) { + final FieldVector3D transformedP0 = transformPosition(line.getOrigin()); + final FieldVector3D transformedD = transformVector(line.getDirection()); + return new FieldLine<>(transformedP0, transformedD, line.getTolerance()); + } + + /** + * Transform a line. + * + * @param line to transform + * @return transformed line + */ + default FieldLine transformLine(final FieldLine line) { + final FieldVector3D transformedP0 = transformPosition(line.getOrigin()); + final FieldVector3D transformedD = transformVector(line.getDirection()); + return new FieldLine<>(transformedP0, transformedD, line.getTolerance()); + } + + /** + * Get the underlying elementary translation. + *

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