# Class MolodenskyTransform

Object
FormattableObject
AbstractMathTransform
DatumShiftTransform
MolodenskyTransform

All Implemented Interfaces:
  `Serializable, Parameterized, LenientComparable, Printable, MathTransform`

public class MolodenskyTransform extends DatumShiftTransform
Two- or three-dimensional datum shift using the (potentially abridged) Molodensky transformation. The Molodensky transformation (EPSG:9604) and the abridged Molodensky transformation (EPSG:9605) transform geographic points from one geographic coordinate reference system to another (a datum shift). The Molodensky formulas are approximations of Geocentric translation (geographic domain) transformations (EPSG:1035 and 9603), but performed directly on geographic coordinates without Geographic/Geocentric conversions.

`MolodenskyTransform`s works conceptually on three-dimensional coordinates, but the ellipsoidal height can be omitted resulting in two-dimensional coordinates. No dimension other than 2 or 3 are allowed.

- If the height is omitted from the input coordinates (`isSource3D` = `false`), then the source dimensions is 2 and the height is assumed to be zero.
- If the height is omitted from the output coordinates (`isTarget3D` = `false`), then the target dimensions is 2 and the computed height (typically non-zero even if the input height was zero) is lost.

The transform expect coordinate values if the following order:

1. longitudes (λ) relative to the prime meridian (usually Greenwich),
2. latitudes (φ),
3. optionally heights above the ellipsoid (h).

The units of measurements depend on how the `MathTransform` has been created:

- `MolodenskyTransform` instances created directly by the constructor work with angular values in radians.
- Transforms created by the `createGeodeticTransformation(…)` static method work with angular values in degrees and heights in the same units as the source ellipsoid axes (usually metres).

## Comparison of Molodensky and geocentric translation

Compared to the Geocentric translation (geographic domain) method, the Molodensky method has errors usually within a few centimetres. The Abridged Molodensky method has more noticeable errors, of a few tenths of centimetres.

Another difference between Molodensky and geocentric translation methods is their behavior when crossing the anti-meridian. If a datum shift causes a longitude to cross the anti-meridian (e.g. 179.999° become 180.001°), the Molodensky method will keep 180.001° as-is while the geocentric translation method will wrap the longitude to -179.999°. Such wrap-around behavior may or may not be desired, depending on the applications.

Since:
  0.7
See Also:
  - Serialized Form

- ## Nested Class Summary

  ### Nested classes/interfaces inherited from class AbstractMathTransform

  `AbstractMathTransform​.Inverse`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final double`
  `eccentricitySquared`
  The square of eccentricity of the source ellipsoid.
  `protected final double`
  `semiMajor`
  Semi-major axis length (a) of the source ellipsoid.
  `protected final double`
  `tX`
  Shift along the geocentric X axis (toward prime meridian) in units of the semi-major axis of the source ellipsoid.
  `protected final double`
  `tY`
  Shift along the geocentric Y axis (toward 90°E) in units of the semi-major axis of the source ellipsoid.
  `protected final double`
  `tZ`
  Shift along the geocentric Z axis (toward north pole) in units of the semi-major axis of the source ellipsoid.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `MolodenskyTransform(Ellipsoid source, boolean isSource3D, Ellipsoid target, boolean isTarget3D, double tX, double tY, double tZ, boolean isAbridged)`
  Creates a Molodensky transform from the specified parameters.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static MathTransform`
  `createGeodeticTransformation(MathTransformFactory factory, Ellipsoid source, boolean isSource3D, Ellipsoid target, boolean isTarget3D, double tX, double tY, double tZ, boolean isAbridged)`
  Creates a transformation between two from geographic CRS.
  `ParameterDescriptorGroup`
  `getParameterDescriptors()`
  Returns a description of the internal parameters of this `MolodenskyTransform` transform.
  `ParameterValueGroup`
  `getParameterValues()`
  Returns a copy of internal parameter values of this transform.
  `final int`
  `getSourceDimensions()`
  Gets the dimension of input points.
  `final int`
  `getTargetDimensions()`
  Gets the dimension of output points.
  `MathTransform`
  `inverse()`
  Returns the inverse of this Molodensky transform.
  `boolean`
  `isIdentity()`
  Returns `true` if this transform is the identity one.
  `Matrix`
  `transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, boolean derivate)`
  Transforms the (λ,φ) or (λ,φ,h) coordinates between two geographic CRS, and optionally returns the derivative at that location.
  `void`
  `transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)`
  Transforms the (λ,φ) or (λ,φ,h) coordinates between two geographic CRS.
  `protected void`
  `tryConcatenate(TransformJoiner context)`
  If this transform expects three-dimensional inputs or outputs, and if the transform before or after this one unconditionally sets the height to zero, replaces this transform by a two-dimensional one.

  ### Methods inherited from class DatumShiftTransform

  `getContextualParameters`

  ### Methods inherited from class AbstractMathTransform

  `derivative, equals, formatTo, getDomain, hashCode, transform, transform, transform, transform`

  ### Methods inherited from class FormattableObject

  `print, toString, toString, toWKT`

  ### Methods inherited from class Object

  `clone, finalize, getClass, notify, notifyAll, wait, wait, wait`

  ### Methods inherited from interface MathTransform

  `toWKT`

- ## Field Details

  - ### tX

    protected final double tX
    Shift along the geocentric X axis (toward prime meridian) in units of the semi-major axis of the source ellipsoid.
    See Also:
      - `BursaWolfParameters​.tX`

  - ### tY

    protected final double tY
    Shift along the geocentric Y axis (toward 90°E) in units of the semi-major axis of the source ellipsoid.
    See Also:
      - `BursaWolfParameters​.tY`

  - ### tZ

    protected final double tZ
    Shift along the geocentric Z axis (toward north pole) in units of the semi-major axis of the source ellipsoid.
    See Also:
      - `BursaWolfParameters​.tZ`

  - ### semiMajor

    protected final double semiMajor
    Semi-major axis length (a) of the source ellipsoid.

  - ### eccentricitySquared

    protected final double eccentricitySquared
    The square of eccentricity of the source ellipsoid. This can be computed by ℯ² = (a²-b²)/a² where a is the semi-major axis length and b is the semi-minor axis length.
    See Also:
      - `DefaultEllipsoid​.getEccentricitySquared()`

- ## Constructor Details

  - ### MolodenskyTransform

    public MolodenskyTransform(Ellipsoid source, boolean isSource3D, Ellipsoid target, boolean isTarget3D, double tX, double tY, double tZ, boolean isAbridged)
    Creates a Molodensky transform from the specified parameters. This `MolodenskyTransform` class expects coordinate values in the following order and units:
    1. longitudes in radians relative to the prime meridian (usually Greenwich),
    2. latitudes in radians,
    3. optionally heights above the ellipsoid, in same units as the source ellipsoid axes.

    #### Unit conversions

    For converting geographic coordinates in degrees, `MolodenskyTransform` instances need to be concatenated with the following affine transforms:
    - Normalization before `MolodenskyTransform`:
      - Conversion of (λ,φ) from degrees to radians.
    - Denormalization after `MolodenskyTransform`:
      - Conversion of (λ,φ) from radians to degrees.
    After `MolodenskyTransform` construction, the full conversion chain including the above affine transforms can be created by `DatumShiftTransform​.getContextualParameters().completeTransform(factory, this)}`.
    Parameters:
      `source` - the source ellipsoid.
      `isSource3D` - `true` if the source coordinates have a height.
      `target` - the target ellipsoid.
      `isTarget3D` - `true` if the target coordinates have a height.
      `tX` - the geocentric X translation in same units as the source ellipsoid axes.
      `tY` - the geocentric Y translation in same units as the source ellipsoid axes.
      `tZ` - the geocentric Z translation in same units as the source ellipsoid axes.
      `isAbridged` - `true` for the abridged formula, or `false` for the complete one.
    See Also:
      - `createGeodeticTransformation(MathTransformFactory, Ellipsoid, boolean, Ellipsoid, boolean, double, double, double, boolean)`

- ## Method Details

  - ### createGeodeticTransformation

    public static MathTransform createGeodeticTransformation(MathTransformFactory factory, Ellipsoid source, boolean isSource3D, Ellipsoid target, boolean isTarget3D, double tX, double tY, double tZ, boolean isAbridged) throws FactoryException
    Creates a transformation between two from geographic CRS. This factory method combines the `MolodenskyTransform` instance with the steps needed for converting values between degrees to radians. The transform works with input and output coordinates in the following units:
    1. longitudes in degrees relative to the prime meridian (usually Greenwich),
    2. latitudes in degrees,
    3. optionally heights above the ellipsoid, in same units as the source ellipsoids axes.
    Parameters:
      `factory` - the factory to use for creating the transform.
      `source` - the source ellipsoid.
      `isSource3D` - `true` if the source coordinates have a height.
      `target` - the target ellipsoid.
      `isTarget3D` - `true` if the target coordinates have a height.
      `tX` - the geocentric X translation in same units as the source ellipsoid axes.
      `tY` - the geocentric Y translation in same units as the source ellipsoid axes.
      `tZ` - the geocentric Z translation in same units as the source ellipsoid axes.
      `isAbridged` - `true` for the abridged formula, or `false` for the complete one.
    Returns:
      the transformation between geographic coordinates in degrees.
    Throws:
      `FactoryException` - if an error occurred while creating a transform.

  - ### tryConcatenate

    protected void tryConcatenate(TransformJoiner context) throws FactoryException
    If this transform expects three-dimensional inputs or outputs, and if the transform before or after this one unconditionally sets the height to zero, replaces this transform by a two-dimensional one.
    Overrides:
      `tryConcatenate` in class `AbstractMathTransform`
    Parameters:
      `context` - information about the neighbor transforms, and the object where to set the result.
    Throws:
      `FactoryException` - if an error occurred while combining the transforms.
    Since:
      1.5
    See Also:
      - `DefaultMathTransformFactory​.createConcatenatedTransform(MathTransform, MathTransform)`

  - ### isIdentity

    public boolean isIdentity()
    Returns `true` if this transform is the identity one. Molodensky transform is considered identity (minus rounding errors) if:
    - the X,Y,Z shift are zero,
    - difference between semi-major axis lengths (Δa) is zero,
    - difference between flattening factors (Δf) is zero,
    - the input and output dimension are the same.
    Specified by:
      `isIdentity` in interface `MathTransform`
    Overrides:
      `isIdentity` in class `AbstractMathTransform`
    Returns:
      `true` if this transform is the identity transform.

  - ### getSourceDimensions

    public final int getSourceDimensions()
    Gets the dimension of input points.
    Specified by:
      `getSourceDimensions` in interface `MathTransform`
    Specified by:
      `getSourceDimensions` in class `AbstractMathTransform`
    Returns:
      the input dimension, which is 2 or 3.
    See Also:
      - `DefaultOperationMethod​.getSourceDimensions()`

  - ### getTargetDimensions

    public final int getTargetDimensions()
    Gets the dimension of output points.
    Specified by:
      `getTargetDimensions` in interface `MathTransform`
    Specified by:
      `getTargetDimensions` in class `AbstractMathTransform`
    Returns:
      the output dimension, which is 2 or 3.
    See Also:
      - `DefaultOperationMethod​.getTargetDimensions()`

  - ### transform

    public Matrix transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, boolean derivate) throws TransformException
    Transforms the (λ,φ) or (λ,φ,h) coordinates between two geographic CRS, and optionally returns the derivative at that location.
    Specified by:
      `transform` in class `AbstractMathTransform`
    Parameters:
      `srcPts` - the array containing the source coordinates (cannot be `null`).
      `srcOff` - the offset to the point to be transformed in the source array.
      `dstPts` - the array into which the transformed coordinate is returned, or `null`.
      `dstOff` - the offset to the location of the transformed point that is stored in the destination array.
      `derivate` - `true` for computing the derivative, or `false` if not needed.
      `dstPts` - the array into which the transformed coordinates is returned.
    Returns:
      the matrix of the transform derivative at the given source position, or `null` if the `derivate` argument is `false`.
    Throws:
      `TransformException` - if the point cannot be transformed or if a problem occurred while calculating the derivative.
    See Also:
      - `AbstractMathTransform​.derivative(DirectPosition)`
      - `AbstractMathTransform​.transform(DirectPosition, DirectPosition)`
      - `MathTransforms​.derivativeAndTransform(MathTransform, double[], int, double[], int)`

  - ### transform

    public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts) throws TransformException
    Transforms the (λ,φ) or (λ,φ,h) coordinates between two geographic CRS. This method performs the same transformation as `transform(double[], int, double[], int, boolean)`, but the formulas are repeated here for performance reasons.
    Specified by:
      `transform` in interface `MathTransform`
    Overrides:
      `transform` in class `AbstractMathTransform`
    Parameters:
      `srcPts` - the array containing the source point coordinates.
      `srcOff` - the offset to the first point to be transformed in the source array.
      `dstPts` - the array into which the transformed point coordinates are returned. May be the same as `srcPts`.
      `dstOff` - the offset to the location of the first transformed point that is stored in the destination array.
      `numPts` - the number of point objects to be transformed.
    Throws:
      `TransformException` - if a point cannot be transformed.

  - ### inverse

    public MathTransform inverse()
    Returns the inverse of this Molodensky transform. The source ellipsoid of the returned transform will be the target ellipsoid of this transform, and conversely.
    Specified by:
      `inverse` in interface `MathTransform`
    Overrides:
      `inverse` in class `AbstractMathTransform`
    Returns:
      a Molodensky transform from the target ellipsoid to the source ellipsoid of this transform.

  - ### getParameterDescriptors

    @Debug public ParameterDescriptorGroup getParameterDescriptors()
    Returns a description of the internal parameters of this `MolodenskyTransform` transform. The returned group contains parameter descriptors for the number of dimensions and the eccentricity.

    #### Usage note

    This method is mostly for debugging purposes since the isolation of non-linear parameters in this class is highly implementation dependent. Most GIS applications will instead be interested in the contextual parameters.
    Specified by:
      `getParameterDescriptors` in interface `Parameterized`
    Overrides:
      `getParameterDescriptors` in class `AbstractMathTransform`
    Returns:
      a description of the internal parameters.
    See Also:
      - `DefaultOperationMethod​.getParameters()`

  - ### getParameterValues

    @Debug public ParameterValueGroup getParameterValues()
    Returns a copy of internal parameter values of this transform. The returned group contains parameters for the source ellipsoid semi-axis lengths and the differences between source and target ellipsoid parameters.

    #### Usage note

    This method is mostly for debugging purposes since the isolation of non-linear parameters in this class is highly implementation dependent. Most GIS applications will instead be interested in the contextual parameters.
    Specified by:
      `getParameterValues` in interface `Parameterized`
    Overrides:
      `getParameterValues` in class `DatumShiftTransform`
    Returns:
      a copy of the internal parameter values for this transform.
    See Also:
      - `AbstractMathTransform​.getContextualParameters()`
      - `SingleOperation​.getParameterValues()`