Package org.apache.sis.referencing.datum

# Class BursaWolfParameters

Object
FormattableObject
BursaWolfParameters

All Implemented Interfaces:
  `Serializable`, `Cloneable`

Direct Known Subclasses:
  `TimeDependentBWP`

public class BursaWolfParameters extends FormattableObject implements Cloneable, Serializable
Parameters for a geographic transformation between two datum having the same prime meridian. Bursa-Wolf parameters are also known as Helmert transformation parameters. For an explanation of their purpose, see the Bursa-Wolf parameters section of `DefaultGeodeticDatum` class javadoc.

The Bursa-Wolf parameters shall be applied to geocentric coordinates, where the X axis points towards the Prime Meridian (usually Greenwich), the Y axis points East, and the Z axis points North.

Note: The upper case letters are intentional. By convention, (X, Y, Z) stand for geocentric coordinates while (x, y, z) stand for projected coordinates.
The "Bursa-Wolf" formula is expressed with 7 parameters, listed in the table below. The code, name and abbreviation columns list EPSG identifiers, while the legacy column lists the identifiers used in the legacy OGC 01-009 specification (still used in some Well Known Texts).

Parameters defined by EPSG
Code | Name | Abbr. | Legacy
--- | --- | --- | ---
8605 | X-axis translation | `tX` | `dx`
8606 | Y-axis translation | `tY` | `dy`
8607 | Z-axis translation | `tZ` | `dz`
8608 | X-axis rotation | `rX` | `ex`
8609 | Y-axis rotation | `rY` | `ey`
8610 | Z-axis rotation | `rZ` | `ez`
8611 | Scale difference | `dS` | `ppm`

Geocentric coordinates transformation

from (Xs, Ys, Zs) to (Xt, Yt, Zt)
(ignoring unit conversions)

X t Y t Z t = (1+dS) ⋅ 1 -r z +r y +r z 1 -r x -r y +r x 1 × X s Y s Z s + t x t y t z

The numerical fields in this `BursaWolfParameters` class use the EPSG abbreviations with 4 additional constraints compared to the EPSG definitions:

- Unit of scale difference (`dS`) is fixed to parts per million.
- Unit of translation terms (`tX`, `tY`, `tZ`) is fixed to metres.
- Unit of rotation terms (`rX`, `rY`, `rZ`) is fixed to arc-seconds.
- Sign of rotation terms is fixed to the Position Vector convention (EPSG operation method 9606). This is the opposite sign than the Coordinate Frame Rotation (EPSG operation method 9607). The Position Vector convention is used by IAG and recommended by ISO 19111.

## Source and target geodetic datum

The source datum in above coordinates transformation is the `DefaultGeodeticDatum` instance that contain this `BursaWolfParameters`. It can be any datum, including datum that are valid only locally. The target datum is specified at construction time and is often, but not necessarily, the World Geodetic System 1984 (WGS 84) datum.

If the source and target datum does not have the same prime meridian, then it is user's responsibility to apply longitude rotation before to use the Bursa-Wolf parameters.

## When Bursa-Wolf parameters are used

`BursaWolfParameters` are used in three contexts:

1. Created as a step while creating a coordinate operation from the EPSG database.
2. Associated to a `DefaultGeodeticDatum` with the WGS 84 target datum for providing the parameter values to display in the `TOWGS84[…]` element of Well Known Text (WKT) version 1. Note that WKT version 2 does not have `TOWGS84[…]` element anymore.
3. Specified at `DefaultGeodeticDatum` construction time for arbitrary target datum. Apache SIS will ignore those Bursa-Wolf parameters, except as a fallback if no parameters can been found in the EPSG database for a given pair of source and target CRS.

Note: In EPSG terminology, Apache SIS gives precedence to the late-binding approach (case 1 above) over the early-binding approach (case 3 above).

Since:
  0.4
See Also:
  - `DefaultGeodeticDatum​.getBursaWolfParameters()`
  - Wikipedia: Helmert transformation
  - Serialized Form

Defined in the `sis-referencing` module

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `double`
  `dS`
  The scale difference in parts per million (EPSG:8611).
  `double`
  `rX`
  X-axis rotation in arc-seconds (EPSG:8608), sign following the Position Vector convention.
  `double`
  `rY`
  Y-axis rotation in arc-seconds (EPSG:8609), sign following the Position Vector convention.
  `double`
  `rZ`
  Z-axis rotation in arc-seconds (EPSG:8610), sign following the Position Vector convention.
  `double`
  `tX`
  X-axis translation in metres (EPSG:8605).
  `double`
  `tY`
  Y-axis translation in metres (EPSG:8606).
  `double`
  `tZ`
  Z-axis translation in metres (EPSG:8607).

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `BursaWolfParameters(GeodeticDatum targetDatum, Extent domainOfValidity)`
  Creates a new instance for the given target datum and domain of validity.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `BursaWolfParameters`
  `clone()`
  Returns a copy of this object.
  `boolean`
  `equals(Object object)`
  Compares the specified object with this object for equality.
  `protected String`
  `formatTo(Formatter formatter)`
  Formats this object as a Well Known Text `ToWGS84[…]` element.
  `Extent`
  `getDomainOfValidity()`
  Returns the region or timeframe in which a coordinate transformation based on those Bursa-Wolf parameters is valid, or `null` if unspecified.
  `Matrix`
  `getPositionVectorTransformation(Date time)`
  Returns the position vector transformation (geocentric domain) as an affine transform.
  `GeodeticDatum`
  `getTargetDatum()`
  Returns the target datum for this set of parameters, or `null` if unknown.
  `double[]`
  `getValues()`
  Returns the parameter values.
  `int`
  `hashCode()`
  Returns a hash value for this object.
  `void`
  `invert()`
  Inverts in-place the transformation by inverting the sign of all numerical parameters.
  `boolean`
  `isIdentity()`
  Returns `true` if a transformation built from this set of parameters would perform no operation.
  `boolean`
  `isTranslation()`
  Returns `true` if a transformation built from this set of parameters would perform only a translation.
  `void`
  `reverseRotation()`
  Inverts in-place the sign of rotation terms (`rX`, `rY`, `rZ`).
  `void`
  `setPositionVectorTransformation(Matrix matrix, double tolerance)`
  Sets all Bursa-Wolf parameters from the given Position Vector transformation matrix.
  `void`
  `setValues(double... elements)`
  Sets the parameters to the given values.

  ### Methods inherited from class FormattableObject

  `print, toString, toString, toWKT`

  ### Methods inherited from class Object

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

- ## Field Details

  - ### tX

    public double tX
    X-axis translation in metres (EPSG:8605). The legacy OGC parameter name is `"dx"`.

  - ### tY

    public double tY
    Y-axis translation in metres (EPSG:8606). The legacy OGC parameter name is `"dy"`.

  - ### tZ

    public double tZ
    Z-axis translation in metres (EPSG:8607). The legacy OGC parameter name is `"dz"`.

  - ### rX

    public double rX
    X-axis rotation in arc-seconds (EPSG:8608), sign following the Position Vector convention. The legacy OGC parameter name is `"ex"`.

  - ### rY

    public double rY
    Y-axis rotation in arc-seconds (EPSG:8609), sign following the Position Vector convention. The legacy OGC parameter name is `"ey"`.

  - ### rZ

    public double rZ
    Z-axis rotation in arc-seconds (EPSG:8610), sign following the Position Vector convention. The legacy OGC parameter name is `"ez"`.

  - ### dS

    public double dS
    The scale difference in parts per million (EPSG:8611). The legacy OGC parameter name is `"ppm"`.
    Example: If a distance of 100 km in the source coordinate reference system translates into a distance of 100.001 km in the target coordinate reference system, the scale difference is 1 ppm (the ratio being 1.000001).

- ## Constructor Details

  - ### BursaWolfParameters

    public BursaWolfParameters(GeodeticDatum targetDatum, Extent domainOfValidity)
    Creates a new instance for the given target datum and domain of validity. All numerical parameters are initialized to 0, which correspond to an identity transform. Callers can assign numerical values to the public fields of interest after construction. For example, many coordinate transformations will provide values only for the translation terms (`tX`, `tY`, `tZ`).

    Alternatively, numerical fields can also be initialized by a call to `setPositionVectorTransformation(Matrix, double)`.

    Parameters:
      `targetDatum` - the target datum (usually WGS 84) for this set of parameters, or `null` if unknown.
      `domainOfValidity` - area or region in which a coordinate transformation based on those Bursa-Wolf parameters is valid, or `null` is unspecified.

- ## Method Details

  - ### getTargetDatum

    public GeodeticDatum getTargetDatum()
    Returns the target datum for this set of parameters, or `null` if unknown. This is usually the WGS 84 datum, but other targets are allowed.

    The source datum is the `DefaultGeodeticDatum` that contain this `BursaWolfParameters` instance.

    Returns:
      the target datum for this set of parameters, or `null` if unknown.

  - ### getValues

    public double[] getValues()
    Returns the parameter values. The length of the returned array depends on the values:
    - If this instance is an `TimeDependentBWP`, then the array length will be 14.
    - Otherwise if this instance contains a non-zero `dS` value, then the array length will be 7 with `tX`, `tY`, `tZ`, `rX`, `rY`, `rZ` and `dS` values in that order.
    - Otherwise if this instance contains non-zero rotation terms, then this method returns the first 6 of the above-cited values.
    - Otherwise (i.e. this instance is a translation), this method returns only the first 3 of the above-cited values.
    Note: the rules about the arrays of length 3, 6 or 7 are derived from the Well Known Text (WKT) version 1 specification. The rule about the array of length 14 is an extension.
    Returns:
      the parameter values as an array of length 3, 6, 7 or 14.
    Since:
      0.6

  - ### setValues

    public void setValues(double... elements)
    Sets the parameters to the given values. The given array can have any length. The first array elements will be assigned to the `tX`, `tY`, `tZ`, `rX`, `rY`, `rZ` and `dS` fields in that order.
    - If the length of the given array is not sufficient for assigning a value to every fields, then the remaining fields are left unchanged (they are not reset to zero, but this is not a problem if this `BursaWolfParameters` is a new instance).
    - If the length of the given array is greater than necessary, then extra elements are ignored by this base class. Note however that those extra elements may be used by subclasses like `TimeDependentBWP`.
    Parameters:
      `elements` - the new parameter values, as an array of any length.
    Since:
      0.6

  - ### isIdentity

    public boolean isIdentity()
    Returns `true` if a transformation built from this set of parameters would perform no operation. This is true when the value of all parameters is zero.
    Returns:
      `true` if the parameters describe no operation.

  - ### isTranslation

    public boolean isTranslation()
    Returns `true` if a transformation built from this set of parameters would perform only a translation.
    Returns:
      `true` if the parameters describe a translation only.

  - ### reverseRotation

    public void reverseRotation()
    Inverts in-place the sign of rotation terms (`rX`, `rY`, `rZ`). This method can be invoked for converting a Coordinate Frame Rotation transformation (EPSG operation method 9607) to a Position Vector transformation (EPSG operation method 9606). The later convention is used by IAG and recommended by ISO 19111.

  - ### invert

    public void invert()
    Inverts in-place the transformation by inverting the sign of all numerical parameters. The position vector transformation matrix created from inverted Bursa-Wolf parameters will be approximately equals to the inverse of the matrix created from the original parameters. The equality holds approximately only because the parameter values are very small (parts per millions and arc-seconds).

  - ### getPositionVectorTransformation

    public Matrix getPositionVectorTransformation(Date time)
    Returns the position vector transformation (geocentric domain) as an affine transform. For transformations that do not depend on time, the formula is as below where `R` is a conversion factor from arc-seconds to radians:

    >      R = toRadians(1″)
    >      S = 1 + dS/1000000
    >      ┌    ┐    ┌                               ┐  ┌   ┐
    >      │ X' │    │      S   -rZ*RS   +rY*RS   tX │  │ X │
    >      │ Y' │  = │ +rZ*RS        S   -rX*RS   tY │  │ Y │
    >      │ Z' │    │ -rY*RS   +rX*RS        S   tZ │  │ Z │
    >      │ 1  │    │      0        0        0    1 │  │ 1 │
    >      └    ┘    └                               ┘  └   ┘

    This affine transform can be applied on geocentric coordinates. This is identified as operation method 1033 in the EPSG database. Those geocentric coordinates are typically converted from geographic coordinates in the region or timeframe given by `getDomainOfValidity()`.

    If the source datum and the target datum do not use the same prime meridian, then it is caller's responsibility to apply longitude rotation before to use the matrix returned by this method.

    #### Time-dependent transformation

    Some transformations use parameters that vary with time (e.g. operation method EPSG:1053). Users can optionally specify a date for which the transformation is desired. For transformations that do not depends on time, this date is ignored and can be null. For time-dependent transformations, `null` values default to the transformation's reference time.

    #### Inverse transformation

    The inverse transformation can be approximated by reversing the sign of the 7 parameters before to use them in the above matrix. This is often considered sufficient since position vector transformations are themselves approximations. However Apache SIS will rather use `MatrixSIS​.inverse()` in order to increase the chances that concatenation of transformations A → B followed by B → A gives back the identity transform.
    Parameters:
      `time` - date for which the transformation is desired, or `null` for the transformation's reference time.
    Returns:
      an affine transform in geocentric space created from this Bursa-Wolf parameters and the given time.
    See Also:
      - `DefaultGeodeticDatum​.getPositionVectorTransformation(GeodeticDatum, Extent)`

  - ### setPositionVectorTransformation

    public void setPositionVectorTransformation(Matrix matrix, double tolerance) throws IllegalArgumentException
    Sets all Bursa-Wolf parameters from the given Position Vector transformation matrix. The matrix shall comply to the following constraints:
    - The matrix shall be affine.
    - The sub-matrix defined by `matrix` without the last row and last column shall be skew-symmetric (a.k.a. antisymmetric).
    Parameters:
      `matrix` - the matrix from which to get Bursa-Wolf parameters.
      `tolerance` - the tolerance error for the skew-symmetric matrix test, in units of PPM or arc-seconds (e.g. 1E-8).
    Throws:
      `IllegalArgumentException` - if the specified matrix does not met the conditions.
    See Also:
      - `getPositionVectorTransformation(Date)`

  - ### getDomainOfValidity

    public Extent getDomainOfValidity()
    Returns the region or timeframe in which a coordinate transformation based on those Bursa-Wolf parameters is valid, or `null` if unspecified. If an extent was specified at construction time, then that extent is returned. Otherwise the datum domain of validity (which may be `null`) is returned.
    Returns:
      area or region or timeframe in which the coordinate transformation is valid, or `null`.
    See Also:
      - `DefaultExtent`

  - ### clone

    public BursaWolfParameters clone()
    Returns a copy of this object.
    Overrides:
      `clone` in class `Object`
    Returns:
      a copy of all parameters.

  - ### equals

    public boolean equals(Object object)
    Compares the specified object with this object for equality.
    Overrides:
      `equals` in class `Object`
    Parameters:
      `object` - the object to compare with the parameters.
    Returns:
      `true` if the given object is equal to this `BursaWolfParameters`.

  - ### hashCode

    public int hashCode()
    Returns a hash value for this object.
    Overrides:
      `hashCode` in class `Object`
    Returns:
      the hash code value. This value does not need to be the same in past or future versions of this class.

  - ### formatTo

    protected String formatTo(Formatter formatter)
    Formats this object as a Well Known Text `ToWGS84[…]` element. The WKT contains the parameters in translation, rotation, scale order, like below:

    > `TOWGS84[tX, tY, tZ, rX, rY, rZ, dS]`

    Compatibility note: `TOWGS84` is defined in the WKT 1 specification only.
    The element name is `"ToWGS84"` in the common case where the target datum is WGS 84. For other targets, the element name will be derived from the datum name.
    Specified by:
      `formatTo` in class `FormattableObject`
    Parameters:
      `formatter` - The formatter where to format the inner content of this WKT element.
    Returns:
      Usually `"ToWGS84"`.
    See Also:
      - `FormattableObject​.toWKT()`
      - `FormattableObject​.toString()`