# Class AbstractCoordinateOperation

Object
FormattableObject
AbstractIdentifiedObject
AbstractCoordinateOperation

All Implemented Interfaces:
  `Serializable, Formattable, Deprecable, LenientComparable, Printable, IdentifiedObject, CoordinateOperation`

Direct Known Subclasses:
  `DefaultConversion, DefaultPassThroughOperation, DefaultTransformation`

public class AbstractCoordinateOperation extends AbstractIdentifiedObject implements CoordinateOperation
Describes the operation for transforming coordinates in the source CRS to coordinates in the target CRS. Coordinate operations contain a math transform, which does the actual work of transforming coordinates, together with the following information:

- The source and target CRS.
- The interpolation CRS if a CRS other than source and target is needed for interpolating.
- In conversion and transformation subclasses, a description of the operation method together with the parameter values.
- The domain of validity.
- An estimation of the operation accuracy.

## Instantiation

This class is conceptually abstract, even if it is technically possible to instantiate it. Typical applications should create instances of the most specific subclass prefixed by `Default` instead. An exception to this rule may occur when it is not possible to identify the exact operation type.

## Immutability and thread safety

This base class is immutable and thus thread-safe if the property values (not necessarily the map itself) given to the constructor are also immutable. Most SIS subclasses and related classes are immutable under similar conditions. This means that unless otherwise noted in the javadoc, `CoordinateOperation` instances created using only SIS factories and static constants can be shared by many objects and passed between threads without synchronization.

Since:
  0.6
See Also:
  - Serialized Form

- ## Field Summary

  ### Fields inherited from class AbstractIdentifiedObject

  `DEPRECATED_KEY, DOMAINS_KEY, LOCALE_KEY`

  ### Fields inherited from interface CoordinateOperation

  `COORDINATE_OPERATION_ACCURACY_KEY, DOMAIN_OF_VALIDITY_KEY, OPERATION_VERSION_KEY, SCOPE_KEY`

  ### Fields inherited from interface IdentifiedObject

  `ALIAS_KEY, IDENTIFIERS_KEY, NAME_KEY, REMARKS_KEY`

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  ``
  `AbstractCoordinateOperation(Map<String,?> properties, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, CoordinateReferenceSystem interpolationCRS, MathTransform transform)`
  Creates a coordinate operation from the given properties.
  `protected`
  `AbstractCoordinateOperation(CoordinateOperation operation)`
  Creates a new coordinate operation with the same values as the specified one.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static AbstractCoordinateOperation`
  `castOrCopy(CoordinateOperation object)`
  Returns a SIS coordinate operation implementation with the values of the given arbitrary implementation.
  `boolean`
  `equals(Object object, ComparisonMode mode)`
  Compares this coordinate operation with the specified object for equality.
  `protected String`
  `formatTo(Formatter formatter)`
  Formats this coordinate operation in Well Known Text (WKT) version 2 format.
  `Collection<PositionalAccuracy>`
  `getCoordinateOperationAccuracy()`
  Returns an estimation of the impact of this operation on point accuracy.
  `Extent`
  `getDomainOfValidity()`
  Deprecated.
  Replaced by `AbstractIdentifiedObject​.getDomains()` as of ISO 19111:2019.
  `Class<? extends CoordinateOperation>`
  `getInterface()`
  Returns the GeoAPI interface implemented by this class.
  `Optional<CoordinateReferenceSystem>`
  `getInterpolationCRS()`
  Returns the CRS to be used for interpolations in a grid.
  `double`
  `getLinearAccuracy()`
  Returns an estimation of positional accuracy in metres, or `NaN` if unknown.
  `MathTransform`
  `getMathTransform()`
  Returns the object for transforming coordinates in the source CRS to coordinates in the target CRS.
  `String`
  `getOperationVersion()`
  Returns the version of the coordinate operation.
  `InternationalString`
  `getScope()`
  Deprecated.
  Replaced by `AbstractIdentifiedObject​.getDomains()` as of ISO 19111:2019.
  `CoordinateReferenceSystem`
  `getSourceCRS()`
  Returns the source CRS, or `null` if unspecified.
  `Optional<Temporal>`
  `getSourceEpoch()`
  Returns the date at which source coordinate tuples are valid.
  `CoordinateReferenceSystem`
  `getTargetCRS()`
  Returns the target CRS, or `null` if unspecified.
  `Optional<Temporal>`
  `getTargetEpoch()`
  Returns the date at which target coordinate tuples are valid.
  `Set<Integer>`
  `getWrapAroundChanges()`
  Returns the indices of target dimensions where "wrap around" may happen as a result of this coordinate operation.
  `boolean`
  `isDefiningConversion()`
  Returns whether this coordinate operation is for the definition of a derived or projected CRS.
  `AbstractCoordinateSet`
  `transform(AbstractCoordinateSet data)`
  Changes coordinates from being referenced to the source CRS and/or epoch to being referenced to the target CRS and/or epoch.

  ### Methods inherited from class AbstractIdentifiedObject

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

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

  `getAlias, getIdentifiers, getName, getRemarks, toWKT`

- ## Constructor Details

  - ### AbstractCoordinateOperation

    public AbstractCoordinateOperation(Map<String,?> properties, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, CoordinateReferenceSystem interpolationCRS, MathTransform transform)
    Creates a coordinate operation from the given properties. The properties given in argument follow the same rules as for the super-class constructor. Additionally, the following properties are understood by this constructor:

    Recognized properties (non exhaustive list)
    Property name | Value type | Returned by
    --- | --- | ---
    "operationVersion" | `String` | `getOperationVersion()`
    "coordinateOperationAccuracy" | `PositionalAccuracy` (optionally as array) | `getCoordinateOperationAccuracy()`
    Defined in parent class (reminder)
    "name" | `Identifier` or `String` | `AbstractIdentifiedObject.getName()`
    "alias" | `GenericName` or `CharSequence` (optionally as array) | `AbstractIdentifiedObject.getAlias()`
    "identifiers" | `Identifier` (optionally as array) | `AbstractIdentifiedObject.getIdentifiers()`
    "domains" | `DefaultObjectDomain` (optionally as array) | `AbstractIdentifiedObject.getDomains()`
    "remarks" | `InternationalString` or `String` | `AbstractIdentifiedObject.getRemarks()`

    #### Constraints

    All arguments except `properties` can be `null`. If non-null, the dimension of CRS arguments shall be related to the `transform` argument as below:
    - Dimension of `sourceCRS` shall be equal to the transform source dimension minus the dimension of the `interpolationCRS` (if any).
    - Dimension of `targetCRS` shall be equal to the transform target dimension, minus the dimension of the `interpolationCRS` (if any).
    If the `interpolationCRS` is non-null, then the given `transform` shall expect input coordinates in the following order:
    1. Coordinates of the interpolation CRS. Example: (x,y) in a vertical transform.
    2. Coordinates of the source CRS. Example: (z) in a vertical transform.
    The math transform shall let the interpolation coordinates pass through the operation.
    Parameters:
      `properties` - the properties to be given to the identified object.
      `sourceCRS` - the source CRS, or `null` if unspecified.
      `targetCRS` - the target CRS, or `null` if unspecified.
      `interpolationCRS` - the CRS of additional coordinates needed for the operation, or `null` if none.
      `transform` - transform from positions in the source CRS to positions in the target CRS, or `null` if unspecified.

  - ### AbstractCoordinateOperation

    protected AbstractCoordinateOperation(CoordinateOperation operation)
    Creates a new coordinate operation with the same values as 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:
      `operation` - the coordinate operation to copy.
    See Also:
      - `castOrCopy(CoordinateOperation)`

- ## Method Details

  - ### castOrCopy

    public static AbstractCoordinateOperation castOrCopy(CoordinateOperation object)
    Returns a SIS coordinate operation implementation with the values of the given arbitrary implementation. This method performs the first applicable action in the following choices:
    - If the given object is `null`, then this method returns `null`.
    - Otherwise if the given object is an instance of `Conversion`, `Transformation`,
      invalid reference

          org​.opengis​.referencing​.operation​.PointMotionOperation

      , `PassThroughOperation` or `ConcatenatedOperation`, then this method delegates to the `castOrCopy(…)` method of the corresponding SIS subclass. Note that if the given object implements more than one of the above-cited interfaces, then the `castOrCopy(…)` method to be used is unspecified.
    - Otherwise if the given object is already an instance of `AbstractCoordinateOperation`, then it is returned unchanged.
    - Otherwise a new `AbstractCoordinateOperation` instance is created using the copy constructor and returned. Note that this is a shallow copy operation, because the other properties contained in the given object are not recursively copied.
    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 CoordinateOperation> getInterface()
    Returns the GeoAPI interface implemented by this class. The default implementation returns `CoordinateOperation​.class`. Subclasses implementing a more specific GeoAPI interface shall override this method.
    Overrides:
      `getInterface` in class `AbstractIdentifiedObject`
    Returns:
      the coordinate operation interface implemented by this class.

  - ### isDefiningConversion

    public boolean isDefiningConversion()
    Returns whether this coordinate operation is for the definition of a derived or projected CRS. The ISO 19111 approach constructs defining conversion as an operation of type `Conversion` with null source and target CRS. But SIS supports also defining conversions with non-null CRS provided that:
    - `GeneralDerivedCRS​.getBaseCRS()` is the source CRS of this operation, and
    - `GeneralDerivedCRS​.getConversionFromBase()` is this operation instance.
    When this method returns `true`, the source and target CRS are not marshalled in XML documents.
    Returns:
      `true` if this coordinate operation is for the definition of a derived or projected CRS.

  - ### getSourceCRS

    public CoordinateReferenceSystem getSourceCRS()
    Returns the source CRS, or `null` if unspecified. The source CRS is mandatory for transformations only. This information is optional for conversions according the ISO 19111 standard, but Apache SIS tries to provide that CRS in most cases anyway.
    Specified by:
      `getSourceCRS` in interface `CoordinateOperation`
    Returns:
      the source CRS, or `null` if not available.
    See Also:
      - `Conversion​.getSourceCRS()`
      - `Transformation​.getSourceCRS()`

  - ### getTargetCRS

    public CoordinateReferenceSystem getTargetCRS()
    Returns the target CRS, or `null` if unspecified. The target CRS is mandatory for transformations only. This information is optional for conversions according the ISO 19111 standard, but Apache SIS tries to provide that CRS in most cases anyway.
    Specified by:
      `getTargetCRS` in interface `CoordinateOperation`
    Returns:
      the target CRS, or `null` if not available.
    See Also:
      - `Conversion​.getTargetCRS()`
      - `Transformation​.getTargetCRS()`

  - ### getInterpolationCRS

    public Optional<CoordinateReferenceSystem> getInterpolationCRS()
    Returns the CRS to be used for interpolations in a grid. Some single coordinate operations employ methods which include interpolation within a grid to derive the values of operation parameters. The CRS to be used for the interpolation may be different from either the source CRS or the target CRS.

    #### Example

    Some transformations of vertical coordinates (h) require the horizontal coordinates (φ,λ) in order to interpolate in a grid. This method returns the CRS of the grid where such interpolations are performed.
    Returns:
      the CRS required for interpolating the values.

  - ### getSourceEpoch

    @UML(identifier="sourceCoordinateEpoch", obligation=CONDITIONAL, specification=ISO_19111) public Optional<Temporal> getSourceEpoch()
    Returns the date at which source coordinate tuples are valid. This is mandatory if the CRS is dynamic.
    Returns:
      epoch at which source coordinate tuples are valid.
    Since:
      1.5

  - ### getTargetEpoch

    @UML(identifier="targetCoordinateEpoch", obligation=CONDITIONAL, specification=ISO_19111) public Optional<Temporal> getTargetEpoch()
    Returns the date at which target coordinate tuples are valid. This is mandatory if the CRS is dynamic.
    Returns:
      epoch at which target coordinate tuples are valid.
    Since:
      1.5

  - ### getOperationVersion

    public String getOperationVersion()
    Returns the version of the coordinate operation. Different versions of a coordinate transformation may exist because of the stochastic nature of the parameters. In principle this property is irrelevant to coordinate conversions, but Apache SIS accepts it anyway.
    Specified by:
      `getOperationVersion` in interface `CoordinateOperation`
    Returns:
      the coordinate operation version, or `null` if none.

  - ### getCoordinateOperationAccuracy

    public Collection<PositionalAccuracy> getCoordinateOperationAccuracy()
    Returns an estimation of the impact of this operation on point accuracy. The positional accuracy gives position error estimates for target coordinates of this coordinate operation, assuming no errors in source coordinates.
    Specified by:
      `getCoordinateOperationAccuracy` in interface `CoordinateOperation`
    Returns:
      the position error estimations, or an empty collection if not available.
    See Also:
      - `getLinearAccuracy()`

  - ### getLinearAccuracy

    public double getLinearAccuracy()
    Returns an estimation of positional accuracy in metres, or `NaN` if unknown. The default implementation tries to infer a value from the metadata returned by `getCoordinateOperationAccuracy()` using SIS-specific heuristics.

    #### Current implementation

    The current implementation uses the heuristic rules listed below. Note that those rules may change in any future SIS version.
    - If at least one quantitative result is found with a linear unit, then returns the largest result value converted to metres.
    - Otherwise if the operation is a conversion, then returns 0 since a conversion is by definition accurate up to rounding errors.
    - Otherwise if the operation is a transformation, then checks if the datum shift were applied with the help of Bursa-Wolf parameters. If a datum shift has been applied, returns 25 meters. If a datum shift should have been applied but has been omitted, returns 3000 meters.
      Note: the 3000 meters value is higher than the highest value (999 meters) found in the EPSG database version 6.7. The 25 meters value is the next highest value found in the EPSG database for a significant number of transformations.
    - Otherwise if the operation is a concatenated operation, returns the sum of the accuracy of all components. This is a conservative scenario where we assume that errors cumulate linearly.
      Note: this is not necessarily the "worst case" scenario since the accuracy could be worst if the math transforms are highly non-linear.
    Returns:
      the accuracy estimation (always in meters), or NaN if unknown.
    See Also:
      - `CRS​.getLinearAccuracy(CoordinateOperation)`

  - ### getDomainOfValidity

    @Deprecated(since="1.4") public Extent getDomainOfValidity()
    Deprecated.
    Replaced by `AbstractIdentifiedObject​.getDomains()` as of ISO 19111:2019.
    Returns the area or region or timeframe in which this coordinate operation is valid.
    Specified by:
      `getDomainOfValidity` in interface `CoordinateOperation`
    Returns:
      the coordinate operation valid domain, or `null` if not available.

  - ### getScope

    @Deprecated(since="1.4") public InternationalString getScope()
    Deprecated.
    Replaced by `AbstractIdentifiedObject​.getDomains()` as of ISO 19111:2019.
    Returns a description of domain of usage, or limitations of usage, for which this operation is valid.
    Specified by:
      `getScope` in interface `CoordinateOperation`
    Returns:
      a description of domain of usage, or `null` if none.

  - ### getMathTransform

    public MathTransform getMathTransform()
    Returns the object for transforming coordinates in the source CRS to coordinates in the target CRS. The transform may be `null` if this coordinate operation is a defining conversion.
    Specified by:
      `getMathTransform` in interface `CoordinateOperation`
    Returns:
      the transform from source to target CRS, or `null` if not applicable.

  - ### transform

    public AbstractCoordinateSet transform(AbstractCoordinateSet data) throws TransformException
    Changes coordinates from being referenced to the source CRS and/or epoch to being referenced to the target CRS and/or epoch. This method operates on coordinate tuples and does not deal with interpolation of geometry types.

    #### Implementation specific behavior

    The default implementation has the following characteristics. Those characteristics are not guaranteed to be met by all implementations of the `CoordinateOperation` interface:
    - If the CRS and/or epoch of the given data are not equivalent to the source CRS and/or epoch of this coordinate operation, this method will automatically prepend an additional operation step.
    - The coordinate tuples are not transformed immediately, but instead will be computed on-the-fly in the stream returned by `AbstractCoordinateSet​.stream()`.
    - If a `TransformException` occurs during on-the-fly coordinate operation, it will be wrapped in an unchecked `BackingStoreException`.
    - The returned coordinate set is serializable if the given data and the math transform are also serializable.
    Parameters:
      `data` - the coordinates to change.
    Returns:
      the result of changing coordinates.
    Throws:
      `TransformException` - if some coordinates cannot be changed. Note that an absence of exception during this method call is not a guarantee that the coordinate changes succeeded, because other errors can occur during the stream execution.
    Since:
      1.5

  - ### getWrapAroundChanges

    public Set<Integer> getWrapAroundChanges()
    Returns the indices of target dimensions where "wrap around" may happen as a result of this coordinate operation. If such change exists, then this is usually the longitude axis when the source CRS uses the [-180 … +180]° range and the target CRS uses the [0 … 360]° range, or the converse. If there is no change, then this is an empty set.

    #### Inverse relationship

    sometimes the target dimensions returned by this method can be mapped directly to wraparound axes in source CRS, but this is not always the case. For example, consider the following operation chain:
    source projected CRS ⟶ base CRS ⟶ target geographic CRS
    In this example, a wraparound axis in the target CRS (the longitude) can be mapped to a wraparound axis in the base CRS. But there is no corresponding wraparound axis in the source CRS because the easting axis in projected CRS does not have a wraparound range meaning. We could argue that axis directions match, but such matching is not guaranteed to exist since `ProjectedCRS` is a special case of `GeneralDerivedCRS` and derived CRS can have rotations.

    #### Default implementation

    The default implementation infers this set by inspecting the source and target coordinate system axes. It returns the indices of all target axes having `RangeMeaning​.WRAPAROUND` and for which the following condition holds: a colinear source axis exists with compatible unit of measurement, and the range (taking unit conversions in account) or range meaning of those source and target axes are not the same.
    Returns:
      indices of target dimensions where "wrap around" may happen as a result of this coordinate operation.
    Since:
      0.8

  - ### equals

    public boolean equals(Object object, ComparisonMode mode)
    Compares this coordinate operation with the specified object for equality. If the `mode` argument is `ComparisonMode​.STRICT` or `BY_CONTRACT`, then all available properties are compared including the domains and the accuracy.
    Specified by:
      `equals` in interface `LenientComparable`
    Overrides:
      `equals` in class `AbstractIdentifiedObject`
    Parameters:
      `object` - the object to compare to `this`.
      `mode` - the strictness level of the comparison.
    Returns:
      `true` if both objects are equal for the given comparison mode.
    See Also:
      - `AbstractIdentifiedObject​.computeHashCode()`
      - `Utilities​.deepEquals(Object, Object, ComparisonMode)`

  - ### formatTo

    protected String formatTo(Formatter formatter)
    Formats this coordinate operation in Well Known Text (WKT) version 2 format.

    #### ESRI extension

    Coordinate operations cannot be formatted in standard WKT 1 format, but an ESRI variant of WKT 1 allows a subset of coordinate operations with the ESRI-specific `GEOGTRAN` keyword. To enabled this variant, `WKTFormat` can be configured as below:

        format = new WKTFormat();
        format.setConvention(Convention.WKT1_IGNORE_AXES);
        format.setNameAuthority(Citations.ESRI);

    Overrides:
      `formatTo` in class `AbstractIdentifiedObject`
    Parameters:
      `formatter` - the formatter to use.
    Returns:
      `"CoordinateOperation"`.
    See Also:
      - `FormattableObject​.toWKT()`
      - `FormattableObject​.toString()`