Click or drag to resize

Reference Frames and Transformations

This topic builds upon the foundation of geometrical and coordinate primitives discussed in the Axes, Points, and Vectors and Coordinates topics. To begin, we define the geometrical concept of a ReferenceFrame as a location point (origin) and a set of axes. A common example of a reference frame is the Earth's fixed frame, EarthCentralBody.FixedFrame (get / set). In this frame, the Point defining the origin is at the center of mass of the Earth and the Axes are aligned such that (in Cartesian coordinates) the Z-axis is pointed North and the X-axis intersects the surface at 0 latitude, 0 longitude. The Y-axis is then defined by the right-hand rule.

Transforming Geometry

GeometryTransformer allows you to easily transform between geometry components by following the chain of relationships between them. One of the primary uses of the transformer is to allow the user to switch between two reference frames. The following example shows how to obtain an evaluator for the transformation between the Earth fixed and Earth inertial reference frames and use it to find an equivalent inertial vector for a given fixed vector:

Java
// Get the Earth central body and assign Earth Orientation Parameters loaded from
// the specified EOP data file.
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
earth.setOrientationParameters(EarthOrientationParametersFile.readData(eopPath));

// Get an evaluator to transform from the fixed to inertial frames, and evaluate it
// at 'now' to get the actual transformation.
ReferenceFrameEvaluator evaluator = 
        GeometryTransformer.getReferenceFrameTransformation(earth.getFixedFrame(), earth.getInertialFrame());
KinematicTransformation transformation = evaluator.evaluate(JulianDate.getNow(), 0);

// Use the transformation to transform a vector in the fixed frame to the inertial frame.
Cartesian fixedVectorToTransform = new Cartesian(1.0, 2.0, 3.0);
Cartesian equivalentInertialVector = transformation.transform(fixedVectorToTransform);

Each geometry component is defined relative to another geometry component. A Point is defined in a ReferenceFrame. A Vector is defined in a set of Axes. A set of Axes or a ReferenceFrame is defined in terms of another set of Axes or a ReferenceFrame, respectively. However, each Point is not necessarily defined in terms of the same ReferenceFrame all the time. For example, the Point representing a spacecraft traveling toward the Moon may initially be defined in an Earth-centered ReferenceFrame. As it gets closer to the Moon, it may switch to a Moon-centered ReferenceFrame. To handle this, the geometry components' evaluators have a property called DefinedInIntervals (get) which identifies the ReferenceFrame or Axes in which the component is defined over that interval. In the case of the interplanetary trajectory, the DefinedInIntervals (get) collection contains two TimeInterval<ReferenceFrame> objects. The first holds the Earth-centered ReferenceFrame in its Data (get) property, and the second holds the Moon-centered ReferenceFrame as its Data (get). The first interval stops at the same time the second interval starts, with the IsStartIncluded (get) and IsStopIncluded (get) properties of the TimeInterval<ReferenceFrame> indicating which system is used at that time. This allows a single geometry component to be defined in different systems at different times.

In general, it is best to use the GeometryTransformer to observe the geometry in the desired system. However, to find the Axes or ReferenceFrame in which a component is defined at a given time, call the findIntervalContainingDate method with the JulianDate used to evaluate the component. Then, get the Data (get) property of the TimeInterval<T>.

Each geometry component knows how to evaluate itself with respect to the components held in DefinedInIntervals (get). For example, if a PointEvaluator is defined in the Earth fixed frame, then calling evaluate will return the position and its derivatives with respect to the Earth fixed frame. To obtain the position, velocity, acceleration, etc. with respect to the Earth inertial frame instead, use the GeometryTransformer.observePoint method, as shown in the next example.

Java
// Get the Earth central body and assign Earth Orientation Parameters loaded from
// the specified EOP data file.
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
earth.setOrientationParameters(EarthOrientationParametersFile.readData(eopPath));

// Create a point at a fixed location with respect to the Earth fixed reference frame.
PointFixedOffset point = new PointFixedOffset(earth.getFixedFrame(), new Cartesian(8000000.0, 0.0, 0.0));

// Get an evaluator which can transform the point into the Earth inertial 
// reference frame at a given time.
PointEvaluator evaluator = GeometryTransformer.observePoint(point, earth.getInertialFrame());

// Evaluate the evaluator 'now'.  The point is stationary with respect to the fixed frame, but
// it is moving with respect to the inertial frame.
Motion1<Cartesian> positionAndVelocity = evaluator.evaluate(JulianDate.getNow(), 1);

For a Point, the GeometryTransformer follows the chains created by the ReferenceFrame in the DefinedInIntervals (get) to determine the shortest sequence of transformations between any two geometry components. In general, whenever creating an evaluator to evaluate vector geometry, it is best to get the evaluator through the GeometryTransformer rather than calling getEvaluator on a particular geometry component itself. This ensures that the evaluator computes the geometry in the expected reference system.

Lastly, new geometry components can be easily added by deriving from Axes, Point, or Vector and creating the corresponding AxesEvaluator, PointEvaluator, or VectorEvaluator respectively. These user-defined components can then participate in GeometryTransformer transformations and other geometry types just like the existing components included with DME Component Libraries.

The geometry components can be found in the agi.foundation.geometry package.

International Terrestrial Reference Frames

International Terrestrial Reference Frames (ITRFs) are realizations of the fixed frame of the Earth that are updated periodically by the International Earth Rotation and Reference Systems Service (IERS) to account for plate tectonics and other geophysical phenomena. Because ITRFs have different transformation rules than other ReferenceFrames, converting between ITRFs requires the use of InternationalTerrestrialReferenceFrameTransformers. These transformers require the correct configuration of updated EarthOrientationParameters.

Java
EarthCentralBody earth = CentralBodiesFacet.getFromContext().getEarth();
EarthOrientationParameters eop = EarthOrientationParametersFile.readData(new File(dataPath, "EOP-v1.1.txt").getPath());
earth.setOrientationParameters(eop);

// The EarthOrientationParameters of the EarthCentralBody
// determine which ITRF is the same as the FixedFrame of the
// Earth. By default, this will be the ITRF2020 unless the EarthOrientationParameters
// specify otherwise.
String nativeItrfFrame = eop.getNativeItrfFrame();
ReferenceFrame itrf2020Frame = earth.getFixedFrame();

There are a number of ways of using ITRF transformers. A possible use case could be the following. Let's say that we have a collection of data in the ITRF2014 frame and we want to transform the collection into the ITRF2020 frame.

Java
// First, get the available transformation definitions.
List<InternationalTerrestrialReferenceFrameTransformer> itrfList =
        InternationalTerrestrialReferenceFrameTransformer.getItrfDefinitions();

// Second, get the ITRF2014 to ITRF2020 frame transformation.
InternationalTerrestrialReferenceFrameTransformer itrf2014ToItrf2020 =
        InternationalTerrestrialReferenceFrameTransformer.getFirstFromList(itrfList, "ITRF2014", "ITRF2020");

// Third, transform the collection.
DateMotionCollection1<Cartesian> itrf2020Collection = itrf2014ToItrf2020.transformCollection(itrf2014Collection);

Let's say that instead of transforming the data to create a new collection, we want to create a PointInterpolator from the data. The only ITRF that is also a ReferenceFrame is ITRF2020, which is the fixed frame for the loaded EOP file. createPointInterpolatorInFixedFrame internally transforms the data into the ITRF2020 frame and then creates a point interpolator in the ITRF2020/fixed frame.

Java
final int interpolationDegree = 5;
PointInterpolator pointInterpolator =
        InternationalTerrestrialReferenceFrameTransformer.createPointInterpolatorInFixedFrame(earth,
                                                                                              itrf2014ToItrf2020,
                                                                                              "ITRF2014",
                                                                                              new LagrangePolynomialApproximation(),
                                                                                              interpolationDegree,
                                                                                              itrf2014Collection);

Points can only be defined in reference frames and the only ITRF frame that is also a ReferenceFrame is the one that is equivalent to the FixedFrame (get / set) of the Earth, which is currently ITRF2020 by default. convertPoint can be used to apply ITRF transformations to convert a point from the ITRF2020 to another ITRF.

Java
Point pointItrf2014 =
        InternationalTerrestrialReferenceFrameTransformer.convertPoint(earth, pointItrf2020, "ITRF2014");

// The converted point can be used to create a collection of ephemeris in the
// ITRF2014 frame. The point still needs to be observed in the ITRF2020 frame,
// but any data it provides will be correctly transformed into the ITRF2014 frame.
EvaluatorGroup group = new EvaluatorGroup();
PointEvaluator evaluator = GeometryTransformer.observePoint(pointItrf2014, itrf2020Frame, group);
DateMotionCollection1<Cartesian> newItrf2014Collection = new DateMotionCollection1<Cartesian>();

for (JulianDate date : dates) {
    Motion1<Cartesian> convertedData = evaluator.evaluate(date, 1);
    newItrf2014Collection.add(date, convertedData);
}