Package org.apache.sis.referencing.datum

# Class DefaultGeodeticDatum

Object
FormattableObject
AbstractIdentifiedObject
AbstractDatum
DefaultGeodeticDatum

All Implemented Interfaces:
  `Serializable`, `Formattable`, `Deprecable`, `LenientComparable`, `Datum`, `GeodeticDatum`, `IdentifiedObject`

public class DefaultGeodeticDatum extends AbstractDatum implements GeodeticDatum
Defines the location and orientation of an ellipsoid that approximates the shape of the earth. Geodetic datum are used together with ellipsoidal coordinate system, and also with Cartesian coordinate system centered in the ellipsoid (or sphere).

## Bursa-Wolf parameters

One or many `BursaWolfParameters` can optionally be associated to each `DefaultGeodeticDatum` instance. This association is not part of the ISO 19111 model, but still a common practice (especially in older standards). Associating Bursa-Wolf parameters to geodetic datum is known as the early-binding approach. A recommended alternative, discussed below, is the late-binding approach.

The Bursa-Wolf parameters serve two purposes:

1. Fallback for datum shifts
   There is different methods for transforming coordinates from one geodetic datum to an other datum, and Bursa-Wolf parameters are used with some of them. However different set of parameters may exist for the same pair of (source, target) datum, so it is often not sufficient to know those datum. The (source, target) pair of CRS are often necessary, sometime together with the geographic extent of the coordinates to transform.

   Apache SIS searches for datum shift methods (including Bursa-Wolf parameters) in the EPSG database when a `CoordinateOperation` or a `MathTransform` is requested for a pair of CRS. This is known as the late-binding approach. If a datum shift method is found in the database, it will have precedence over any `BursaWolfParameters` instance associated to this `DefaultGeodeticDatum`. Only if no datum shift method is found in the database, then the `BursaWolfParameters` associated to the datum may be used as a fallback.

2. WKT version 1 formatting
   The Bursa-Wolf parameters association serves an other purpose: when a CRS is formatted in the older Well Known Text (WKT 1) format, the formatted string may contain a `TOWGS84[…]` element with the parameter values of the transformation to the WGS 84 datum. This element is provided as a help for other Geographic Information Systems that support only the early-binding approach. Apache SIS usually does not need the `TOWGS84` element, except as a fallback for datum that do not exist in the EPSG database.

## Creating new geodetic datum instances

New instances can be created either directly by specifying all information to a factory method (choices 3 and 4 below), or indirectly by specifying the identifier of an entry in a database (choices 1 and 2 below). Choice 1 in the following list is the easiest but most restrictive way to get a geodetic datum. The other choices provide more freedom.

1. Create a `GeodeticDatum` from one of the static convenience shortcuts listed in `CommonCRS​.datum()`.
2. Create a `GeodeticDatum` from an identifier in a database by invoking `DatumAuthorityFactory​.createGeodeticDatum(String)`.
3. Create a `GeodeticDatum` by invoking the `DatumFactory​.createGeodeticDatum(…)` method (implemented for example by `GeodeticObjectFactory`).
4. Create a `DefaultGeodeticDatum` by invoking the constructor.

Example: the following code gets a World Geodetic System 1984 datum:

>     GeodeticDatum datum = CommonCRS.WGS84.datum();

## Immutability and thread safety

This class is immutable and thus thread-safe if the property values (not necessarily the map itself), the `Ellipsoid` and the `PrimeMeridian` given to the constructor are also immutable. Unless otherwise noted in the javadoc, this condition holds if all components were created using only SIS factories and static constants.

Since:
  0.4
See Also:
  - `DefaultEllipsoid`
  - `DefaultPrimeMeridian`
  - `CommonCRS​.datum()`
  - `GeodeticAuthorityFactory​.createGeodeticDatum(String)`
  - Serialized Form

Defined in the `sis-referencing` module

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final String`
  `BURSA_WOLF_KEY`
  The `"bursaWolf"` property for Bursa-Wolf parameters.

  ### Fields inherited from class AbstractIdentifiedObject

  `DEPRECATED_KEY, LOCALE_KEY`

  ### Fields inherited from interface Datum

  `ANCHOR_POINT_KEY, DOMAIN_OF_VALIDITY_KEY, REALIZATION_EPOCH_KEY, SCOPE_KEY`

  ### Fields inherited from interface IdentifiedObject

  `ALIAS_KEY, IDENTIFIERS_KEY, NAME_KEY, REMARKS_KEY`

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  ``
  `DefaultGeodeticDatum(Map<String,?> properties, Ellipsoid ellipsoid, PrimeMeridian primeMeridian)`
  Creates a geodetic datum from the given properties.
  `protected`
  `DefaultGeodeticDatum(GeodeticDatum datum)`
  Creates a new datum with the same values than the specified one.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static DefaultGeodeticDatum`
  `castOrCopy(GeodeticDatum object)`
  Returns a SIS datum implementation with the same values than the given arbitrary implementation.
  `protected long`
  `computeHashCode()`
  Invoked by `hashCode()` for computing the hash code when first needed.
  `boolean`
  `equals(Object object, ComparisonMode mode)`
  Compare this datum with the specified object for equality.
  `protected String`
  `formatTo(Formatter formatter)`
  Formats this datum as a Well Known Text `Datum[…]` element.
  `BursaWolfParameters[]`
  `getBursaWolfParameters()`
  Returns all Bursa-Wolf parameters specified in the `properties` map at construction time.
  `Ellipsoid`
  `getEllipsoid()`
  Returns the ellipsoid given at construction time.
  `Class<? extends GeodeticDatum>`
  `getInterface()`
  Returns the GeoAPI interface implemented by this class.
  `Matrix`
  `getPositionVectorTransformation(GeodeticDatum targetDatum, Extent areaOfInterest)`
  Returns the position vector transformation (geocentric domain) to the specified datum.
  `PrimeMeridian`
  `getPrimeMeridian()`
  Returns the prime meridian given at construction time.
  `boolean`
  `isHeuristicMatchForName(String name)`
  Returns `true` if either the primary name or at least one alias matches the given string according heuristic rules.

  ### Methods inherited from class AbstractDatum

  `castOrCopy, getAnchorPoint, getDomainOfValidity, getRealizationEpoch, getScope`

  ### Methods inherited from class AbstractIdentifiedObject

  `castOrCopy, equals, formatTo, getAlias, getDescription, getIdentifiers, getName, getRemarks, hashCode, isDeprecated`

  ### 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 Datum

  `getAnchorPoint, getDomainOfValidity, getRealizationEpoch, getScope`

  ### Methods inherited from interface IdentifiedObject

  `getAlias, getIdentifiers, getName, getRemarks, toWKT`

- ## Field Details

  - ### BURSA_WOLF_KEY

    public static final String BURSA_WOLF_KEY
    The `"bursaWolf"` property for Bursa-Wolf parameters.
    See Also:
      - Constant Field Values

- ## Constructor Details

  - ### DefaultGeodeticDatum

    public DefaultGeodeticDatum(Map<String,?> properties, Ellipsoid ellipsoid, PrimeMeridian primeMeridian)
    Creates a geodetic datum from the given properties. The properties map is given unchanged to the super-class constructor. In addition to the properties documented in the parent constructor, the following properties are understood by this constructor:

    Recognized properties (non exhaustive list)
    Property name | Value type | Returned by
    --- | --- | ---
    "bursaWolf" | `BursaWolfParameters` (optionally as array) | `getBursaWolfParameters()`
    Defined in parent classes (reminder)
    "name" | `ReferenceIdentifier` or `String` | `AbstractIdentifiedObject.getName()`
    "alias" | `GenericName` or `CharSequence` (optionally as array) | `AbstractIdentifiedObject.getAlias()`
    "identifiers" | `ReferenceIdentifier` (optionally as array) | `AbstractIdentifiedObject.getIdentifiers()`
    "remarks" | `InternationalString` or `String` | `AbstractIdentifiedObject.getRemarks()`
    "anchorPoint" | `InternationalString` or `String` | `AbstractDatum.getAnchorPoint()`
    "realizationEpoch" | `Date` | `AbstractDatum.getRealizationEpoch()`
    "domainOfValidity" | `Extent` | `AbstractDatum.getDomainOfValidity()`
    "scope" | `InternationalString` or `String` | `AbstractDatum.getScope()`

    If Bursa-Wolf parameters are specified, then the prime meridian of their target datum shall be either the same than the `primeMeridian` given to this constructor, or Greenwich. This restriction is for avoiding ambiguity about whether the longitude rotation shall be applied before or after the datum shift. If the target prime meridian is Greenwich, then the datum shift will be applied in a coordinate system having Greenwich as the prime meridian.
    Parameters:
      `properties` - the properties to be given to the identified object.
      `ellipsoid` - the ellipsoid.
      `primeMeridian` - the prime meridian.
    See Also:
      - `GeodeticObjectFactory​.createGeodeticDatum(Map, Ellipsoid, PrimeMeridian)`

  - ### DefaultGeodeticDatum

    protected DefaultGeodeticDatum(GeodeticDatum datum)
    Creates a new datum with the same values than the specified one. This copy constructor provides a way to convert an arbitrary implementation into a SIS one or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API.

    This constructor performs a shallow copy, i.e. the properties are not cloned.

    Parameters:
      `datum` - the datum to copy.
    See Also:
      - `castOrCopy(GeodeticDatum)`

- ## Method Details

  - ### castOrCopy

    public static DefaultGeodeticDatum castOrCopy(GeodeticDatum object)
    Returns a SIS datum implementation with the same values than the given arbitrary implementation. If the given object is `null`, then this method returns `null`. Otherwise if the given object is already a SIS implementation, then the given object is returned unchanged. Otherwise a new SIS implementation is created and initialized to the attribute values of the given object.
    Parameters:
      `object` - the object to get as a SIS implementation, or `null` if none.
    Returns:
      a SIS implementation containing the values of the given object (may be the given object itself), or `null` if the argument was null.

  - ### getInterface

    public Class<? extends GeodeticDatum> getInterface()
    Returns the GeoAPI interface implemented by this class. The SIS implementation returns `GeodeticDatum​.class`.
    Note for implementers: Subclasses usually do not need to override this method since GeoAPI does not define `GeodeticDatum` sub-interface. Overriding possibility is left mostly for implementers who wish to extend GeoAPI with their own set of interfaces.
    Overrides:
      `getInterface` in class `AbstractDatum`
    Returns:
      `GeodeticDatum​.class` or a user-defined sub-interface.

  - ### getEllipsoid

    public Ellipsoid getEllipsoid()
    Returns the ellipsoid given at construction time.
    Specified by:
      `getEllipsoid` in interface `GeodeticDatum`
    Returns:
      the ellipsoid.

  - ### getPrimeMeridian

    public PrimeMeridian getPrimeMeridian()
    Returns the prime meridian given at construction time.
    Specified by:
      `getPrimeMeridian` in interface `GeodeticDatum`
    Returns:
      the prime meridian.

  - ### getBursaWolfParameters

    public BursaWolfParameters[] getBursaWolfParameters()
    Returns all Bursa-Wolf parameters specified in the `properties` map at construction time. See class javadoc for a discussion about Bursa-Wolf parameters.
    Returns:
      the Bursa-Wolf parameters, or an empty array if none.

  - ### getPositionVectorTransformation

    public Matrix getPositionVectorTransformation(GeodeticDatum targetDatum, Extent areaOfInterest)
    Returns the position vector transformation (geocentric domain) to the specified datum. If the returned matrix is non-null, then the transformation is represented by an affine transform which can be applied on geocentric coordinates. This is identified in the EPSG database as operation method 1033 – Position Vector transformation (geocentric domain), or 1053 – Time-dependent Position Vector transformation.

    If this datum and the given `targetDatum` 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. The target prime meridian should be Greenwich (see constructor javadoc), in which case the datum shift should be applied in a geocentric coordinate system having Greenwich as the prime meridian.

    Note: in EPSG dataset version 8.9, all datum shifts that can be represented by this method use Greenwich as the prime meridian, both in source and target datum.

    #### Search criteria

    If the given `areaOfInterest` is non-null and contains at least one geographic bounding box, then this method ignores any Bursa-Wolf parameters having a domain of validity that does not intersect the given geographic extent. This method performs the search among the remaining parameters in the following order:
    1. If this `GeodeticDatum` contains `BursaWolfParameters` having the given target datum (ignoring metadata), then the matrix will be built from those parameters.
    2. Otherwise if the other datum contains `BursaWolfParameters` having this datum as their target (ignoring metadata), then the matrix will be built from those parameters and inverted.

    #### Multi-occurrences resolution

    If more than one `BursaWolfParameters` instance is found in any of the above steps, then the one having the largest intersection between its domain of validity and the given extent will be selected. If more than one instance have the same intersection, then the first occurrence is selected.

    #### Time-dependent parameters

    If the given extent contains a temporal extent, then the instant located midway between start and end time will be taken as the date where to evaluate the Bursa-Wolf parameters. This is relevant only to time-dependent parameters.
    Parameters:
      `targetDatum` - the target datum.
      `areaOfInterest` - the geographic and temporal extent where the transformation should be valid, or `null`.
    Returns:
      an affine transform from `this` to `target` in geocentric space, or `null` if none.
    See Also:
      - `BursaWolfParameters​.getPositionVectorTransformation(Date)`

  - ### isHeuristicMatchForName

    public boolean isHeuristicMatchForName(String name)
    Returns `true` if either the primary name or at least one alias matches the given string according heuristic rules. This method implements the flexibility documented in the super-class. In particular, this method ignores the prime meridian name if that name is found between parenthesis in the datum name. The meridian can be safely ignored in the datum name because the `PrimeMeridian` object is already compared by the `AbstractIdentifiedObject​.equals(Object)` method.
    Example: if the datum name is "Nouvelle Triangulation Française (Paris)" and the prime meridian name is "Paris", then this method compares only the "Nouvelle Triangulation Française" part.

    #### Future evolutions

    This method implements heuristic rules learned from experience while trying to provide inter-operability with different data producers. Those rules may be adjusted in any future SIS version according experience gained while working with more data producers.
    Overrides:
      `isHeuristicMatchForName` in class `AbstractDatum`
    Parameters:
      `name` - the name to compare.
    Returns:
      `true` if the primary name or at least one alias matches the specified `name`.
    Since:
      0.7
    See Also:
      - `IdentifiedObjects​.isHeuristicMatchForName(IdentifiedObject, String)`
      - `Characters​.Filter​.LETTERS_AND_DIGITS`

  - ### equals

    public boolean equals(Object object, ComparisonMode mode)
    Compare this datum with the specified object for equality.
    Specified by:
      `equals` in interface `LenientComparable`
    Overrides:
      `equals` in class `AbstractDatum`
    Parameters:
      `object` - the object to compare to `this`.
      `mode` - `STRICT` for performing a strict comparison, or `IGNORE_METADATA` for comparing only properties relevant to coordinate transformations.
    Returns:
      `true` if both objects are equal.
    See Also:
      - `AbstractIdentifiedObject​.computeHashCode()`
      - `Utilities​.deepEquals(Object, Object, ComparisonMode)`

  - ### computeHashCode

    protected long computeHashCode()
    Invoked by `hashCode()` for computing the hash code when first needed. See `AbstractIdentifiedObject​.computeHashCode()` for more information.
    Overrides:
      `computeHashCode` in class `AbstractDatum`
    Returns:
      the hash code value. This value may change in any future Apache SIS version.

  - ### formatTo

    protected String formatTo(Formatter formatter)
    Formats this datum as a Well Known Text `Datum[…]` element.
    Example: Well-Known Text of a WGS 84 datum.

    >     Datum["World Geodetic System 1984",
    >       Ellipsoid["WGS84", 6378137.0, 298.257223563, LengthUnit["metre", 1]],
    >     Id["EPSG", 6326, Citation["IOGP"], URI["urn:ogc:def:datum:EPSG::6326"]]]

    Same datum using WKT 1.

    >     DATUM["World Geodetic System 1984"
    >       SPHEROID["WGS84", 6378137.0, 298.257223563],
    >     AUTHORITY["EPSG", "6326"]]

    Note that the prime meridian shall be formatted by the caller as a separated element after the geodetic datum (for compatibility with WKT 1).
    Overrides:
      `formatTo` in class `AbstractDatum`
    Parameters:
      `formatter` - the formatter where to format the inner content of this WKT element.
    Returns:
      `"Datum"` or `"GeodeticDatum"`.
    See Also:
      - WKT 2 specification §8.2