org.apache.sis.referencing.datum

## Class DatumShiftGrid<C extends Quantity<C>,T extends Quantity<T>>

- Object
- - DatumShiftGrid<C,T>

- Type Parameters:
    `C` - dimension of the coordinate unit (usually `Angle`).
    `T` - dimension of the translation unit (usually `Angle` or `Length`).
  All Implemented Interfaces:
    Serializable

      public abstract class DatumShiftGrid<C extends Quantity<C>,T extends Quantity<T>>
      extends Object
      implements Serializable

  Small but non-constant translations to apply on coordinates for datum shifts or other transformation process. The main purpose of this class is to encapsulate the data provided by datum shift grid files like NTv2, NADCON or RGF93. But this class could also be used for other kind of transformations, provided that the shifts are small (otherwise algorithms may not converge).

  Geodetic datum changes can be implemented by translations in geographic or geocentric coordinates. Translations given by `DatumShiftGrid` instances are often, but not always, applied directly on geographic coordinates (λ,φ). But some algorithms rather apply the translations in geocentric coordinates (X,Y,Z). This `DatumShiftGrid` class can describe both cases, but will be used with different `MathTransform` implementations.

  Steps for calculation of a translation vector:

  1. Coordinates are given in some "real world" unit. The expected unit is given by `getCoordinateUnit()`.
  2. Above coordinates are converted to grid indices including fractional parts. That conversion is given by `getCoordinateToGrid()`.
  3. Translation vectors are interpolated at the position of above grid indices. That interpolation is done by `interpolateInCell(…)`.
  4. If the above translations were given as a ratio of the real translation divided by the size of grid cells, apply the inverse of the conversion given at step 2. This information is given by `isCellValueRatio()`.
  5. The resulting translation vectors are in the unit given by `getTranslationUnit()`.
  The `interpolateAt(…)` method performs all those steps. But that method is provided only for convenience; it is not used by Apache SIS. For performance reasons SIS `MathTransform` implementations perform all the above-cited steps themselves, and apply the interpolated translations on coordinate values in their own step between above steps 3 and 4.
  Use cases:
  - Datum shift by geographic translations
    NADCON and NTv2 grids are defined with longitude (λ) and latitude (φ) inputs in angular degrees and give (Δλ, Δφ) translations in angular seconds. However SIS stores the translation values in units of grid cell rather than angular seconds. The translations will be applied by `InterpolatedTransform` directly on the given (λ,φ) coordinates.
  - Datum shift by geocentric translations
    France interpolation grid is defined with longitude (λ) and latitude (φ) inputs in angular degrees and gives (ΔX, ΔY, ΔZ) geocentric translations in metres. Those translations will not be added directly to the given (λ,φ) coordinates since there is a geographic/geocentric conversion in the middle (see `InterpolatedGeocentricTransform`).
  - Localization grid of raster data
    Some remote sensing raster data are provided with a localization grid giving pixel coordinates (e.g. latitude and longitude). This can been seen as a change from image datum to geodetic datum. The coordinate transformation process can sometime be performed by a mathematical conversion (for example an affine transform) applied as a first approximation, followed by small corrections for the residual part. `DatumShiftGrid` can describe the small corrections part.
  Implementations of this class shall be immutable and thread-safe.
  Number of dimensions
  Input coordinates and translation vectors can have any number of dimensions. However in the current implementation, only the two first dimensions are used for interpolating the translation vectors. This restriction appears in the following method signatures:
  - `interpolateInCell(double, double, double[])` where the two first `double` values are (x,y) grid indices.
  - `getCellValue(int, int, int)` where the two last `int` values are (x,y) grid indices.
  - `derivativeInCell(double, double)` where the values are (x,y) grid indices.
  Note that the above restriction does not prevent `DatumShiftGrid` to interpolate translation vectors in more than two dimensions. See the above datum shift by geocentric translations use case for an example.
  Serialization
  Serialized objects of this class are not guaranteed to be compatible with future Apache SIS releases. Serialization support is appropriate for short term storage or RMI between applications running the same version of Apache SIS. But for long term storage, an established datum shift grid format like NTv2 should be preferred.
  Since:
    0.7
  See Also:
    `DatumShiftTransform`, Serialized Form

  Defined in the `sis-referencing` module

- - ### Constructor Summary

    Constructors
    Modifier | Constructor and Description
    --- | ---
    `protected` | `DatumShiftGrid(DatumShiftGrid<C,T> other)` Creates a new datum shift grid with the same grid geometry (size and units) than the given grid.
    `protected` | `DatumShiftGrid(Unit<C> coordinateUnit, LinearTransform coordinateToGrid, int[] gridSize, boolean isCellValueRatio, Unit<T> translationUnit)` Creates a new datum shift grid for the given size and units.

  - ### Method Summary

    All Methods Instance Methods Abstract Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `Matrix` | `derivativeInCell(double gridX, double gridY)` Returns the derivative at the given grid indices.
    `boolean` | `equals(Object other)` Returns `true` if the given object is a grid containing the same data than this grid.
    `double` | `getCellMean(int dim)` Returns an average translation value for the given dimension.
    `abstract double` | `getCellPrecision()` Returns an estimation of cell value precision (not to be confused with accuracy).
    `abstract double` | `getCellValue(int dim, int gridX, int gridY)` Returns the translation stored at the given two-dimensional grid indices for the given dimension.
    `LinearTransform` | `getCoordinateToGrid()` Conversion from the "real world" coordinates to grid indices including fractional parts.
    `Unit<C>` | `getCoordinateUnit()` Returns the unit of measurement of input values, before conversion to grid indices.
    `Envelope` | `getDomainOfValidity()` Returns the domain of validity of input coordinates that can be specified to the `interpolateAt(…)` method.
    `int[]` | `getGridSize()` Returns the number of cells along each axis in the grid.
    `abstract int` | `getTranslationDimensions()` Returns the number of dimensions of the translation vectors interpolated by this datum shift grid.
    `Unit<T>` | `getTranslationUnit()` Returns the unit of measurement of output values, as interpolated by the `interpolateAt(…)` method.
    `int` | `hashCode()` Returns a hash code value for this datum shift grid.
    `double[]` | `interpolateAt(double... ordinates)` Interpolates the translation to apply for the given coordinate.
    `void` | `interpolateInCell(double gridX, double gridY, double[] vector)` Interpolates the translation to apply for the given two-dimensional grid indices.
    `boolean` | `isCellValueRatio()` Returns `true` if the translation values in the cells are divided by the cell size.
    `double` | `normalizedToGridX(double x)` Converts the given normalized x ordinate to grid index.
    `double` | `normalizedToGridY(double y)` Converts the given normalized x ordinate to grid index.

    - ### Methods inherited from class Object

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

- - ### Constructor Detail

    - #### DatumShiftGrid

          protected DatumShiftGrid(Unit<C> coordinateUnit,
                                   LinearTransform coordinateToGrid,
                                   int[] gridSize,
                                   boolean isCellValueRatio,
                                   Unit<T> translationUnit)

      Creates a new datum shift grid for the given size and units. The actual cell values need to be provided by subclasses.

      Meaning of argument values is documented more extensively in `getCoordinateUnit()`, `getCoordinateToGrid()`, `isCellValueRatio()` and `getTranslationUnit()` methods. The argument order is roughly the order in which they are used in the process of interpolating translation vectors.

      Parameters:
        `coordinateUnit` - the unit of measurement of input values, before conversion to grid indices by `coordinateToGrid`.
        `coordinateToGrid` - conversion from the "real world" coordinates to grid indices including fractional parts.
        `gridSize` - number of cells along each axis in the grid. The length of this array shall be equal to `coordinateToGrid` target dimensions.
        `isCellValueRatio` - `true` if results of `interpolateInCell(…)` are divided by grid cell size.
        `translationUnit` - the unit of measurement of output values.

    - #### DatumShiftGrid

          protected DatumShiftGrid(DatumShiftGrid<C,T> other)

      Creates a new datum shift grid with the same grid geometry (size and units) than the given grid.
      Parameters:
        `other` - the other datum shift grid from which to copy the grid geometry.

  - ### Method Detail

    - #### getGridSize

          public int[] getGridSize()

      Returns the number of cells along each axis in the grid. The length of this array is equal to `coordinateToGrid` target dimensions.
      Returns:
        the number of cells along each axis in the grid.

    - #### getDomainOfValidity

          public Envelope getDomainOfValidity()
                                       throws TransformException

      Returns the domain of validity of input coordinates that can be specified to the `interpolateAt(…)` method. Coordinates outside that domain of validity will still be accepted, but the extrapolated results may be very wrong.

      The unit of measurement for the coordinate values in the returned envelope is given by `getCoordinateUnit()`. The envelope CRS is undefined.

      Returns:
        the domain covered by this grid.
      Throws:
        `TransformException` - if an error occurred while computing the envelope.

    - #### getCoordinateUnit

          public Unit<C> getCoordinateUnit()

      Returns the unit of measurement of input values, before conversion to grid indices. The coordinate unit is usually `Units​.DEGREE`, but other units are allowed.
      Returns:
        the unit of measurement of input values before conversion to grid indices.
      See Also:
        `getTranslationUnit()`, `AbstractCoordinateOperation​.getInterpolationCRS()`

    - #### getCoordinateToGrid

          public LinearTransform getCoordinateToGrid()

      Conversion from the "real world" coordinates to grid indices including fractional parts. The input points given to the `MathTransform` shall be in the unit of measurement given by `getCoordinateUnit()`. The output points are grid indices with integer values in the center of grid cells.

      This transform is usually two-dimensional, in which case conversions from (x,y) coordinates to (`gridX`, `gridY`) indices can be done with the following formulas:

      - gridX = (x - x₀) / Δx
      - gridY = (y - y₀) / Δy
      where:
      - (x₀, y₀) is the coordinate of the center of the cell at grid index (0,0).
      - Δx and Δy are the distances between two cells on the x and y axes respectively, in the unit of measurement given by `getCoordinateUnit()`.
      The `coordinateToGrid` transform for the above formulas can be represented by the following matrix:

          ┌                      ┐
          │ 1/Δx      0   -x₀/Δx │
          │    0   1/Δy   -y₀/Δy │
          │    0      0        1 │
          └                      ┘

      Returns:
        conversion from the "real world" coordinates to grid indices including fractional parts.

    - #### normalizedToGridX

          public final double normalizedToGridX(double x)

      Converts the given normalized x ordinate to grid index. "Normalized coordinates" are coordinates in the unit of measurement given by `Unit​.getSystemUnit()`. For angular coordinates, this is radians. For linear coordinates, this is metres.
      Parameters:
        `x` - the "real world" ordinate (often longitude in radians) of the point for which to get the translation.
      Returns:
        the grid index for the given ordinate. May be out of bounds.

    - #### normalizedToGridY

          public final double normalizedToGridY(double y)

      Converts the given normalized x ordinate to grid index. "Normalized coordinates" are coordinates in the unit of measurement given by `Unit​.getSystemUnit()`. For angular coordinates, this is radians. For linear coordinates, this is metres.
      Parameters:
        `y` - the "real world" ordinate (often latitude in radians) of the point for which to get the translation.
      Returns:
        the grid index for the given ordinate. May be out of bounds.

    - #### getTranslationDimensions

          public abstract int getTranslationDimensions()

      Returns the number of dimensions of the translation vectors interpolated by this datum shift grid. This number of dimensions is not necessarily equals to the number of source or target dimensions of the "coordinate to grid" transform. The number of translation dimensions is usually 2 or 3, but other values are allowed.
      Returns:
        number of dimensions of translation vectors.

    - #### getTranslationUnit

          public Unit<T> getTranslationUnit()

      Returns the unit of measurement of output values, as interpolated by the `interpolateAt(…)` method. Apache SIS `MathTransform` implementations restrict the translation units to the following values:
      - For `InterpolatedTransform`, the translation unit shall be the same than the coordinate unit.
      - For `InterpolatedGeocentricTransform`, the translation unit shall be the same than the unit of source ellipsoid axis lengths.
      Returns:
        the unit of measurement of output values interpolated by `interpolateAt(…)`.
      See Also:
        `getCoordinateUnit()`, `interpolateAt(double...)`

    - #### interpolateAt

          public double[] interpolateAt(double... ordinates)
                                 throws TransformException

      Interpolates the translation to apply for the given coordinate. The input values are in the unit given by `getCoordinateUnit()`. The output values are in the unit given by `getTranslationUnit()`. The length of the returned array is given by `getTranslationDimensions()`.
      Default implementation
      The default implementation performs the following steps:
      1. Convert the given coordinate into grid indices using the transform given by `getCoordinateToGrid()`.
      2. Interpolate the translation vector at the above grid indices with a call to `interpolateInCell(double, double, double[])`.
      3. If `isCellValueRatio()` returns `true`, delta transform the translation vector by the inverse of the conversion given at step 1.
      Parameters:
        `ordinates` - the "real world" ordinate (often longitude and latitude, but not necessarily) of the point for which to get the translation.
      Returns:
        the translation vector at the given position.
      Throws:
        `TransformException` - if an error occurred while computing the translation vector.

    - #### interpolateInCell

          public void interpolateInCell(double gridX,
                                        double gridY,
                                        double[] vector)

      Interpolates the translation to apply for the given two-dimensional grid indices. The result is stored in the given `vector` array, which shall have a length of at least `getTranslationDimensions()`. The output unit of measurement is the same than the one documented in `getCellValue(int, int, int)`.
      Default implementation
      The default implementation performs the following steps for each dimension dim, where the number of dimension is determined by `getTranslationDimensions()`.
      1. Clamp the `gridX` index into the [0 … `gridSize[0]` - 2] range, inclusive.
      2. Clamp the `gridY` index into the [0 … `gridSize[1]` - 2] range, inclusive.
      3. Using `getCellValue(int, int, int)`, get the cell values around the given indices.
      4. Apply a bilinear interpolation and store the result in `vector[dim]`.
      Parameters:
        `gridX` - first grid ordinate of the point for which to get the translation.
        `gridY` - second grid ordinate of the point for which to get the translation.
        `vector` - a pre-allocated array where to write the translation vector.

    - #### derivativeInCell

          public Matrix derivativeInCell(double gridX,
                                         double gridY)

      Returns the derivative at the given grid indices.
      Default implementation
      The current implementation assumes that the derivative is constant everywhere in the cell at the given indices. It does not yet take in account the fractional part of `gridX` and `gridY`, because empirical tests suggest that the accuracy of such interpolation is uncertain.
      Parameters:
        `gridX` - first grid ordinate of the point for which to get the translation.
        `gridY` - second grid ordinate of the point for which to get the translation.
      Returns:
        the derivative at the given location.

    - #### getCellValue

          public abstract double getCellValue(int dim,
                                              int gridX,
                                              int gridY)

      Returns the translation stored at the given two-dimensional grid indices for the given dimension. The returned value is considered representative of the value in the center of the grid cell. The output unit of measurement depends on the `isCellValueRatio()` boolean:
      - If `false`, the value returned by this method shall be in the unit of measurement given by `getTranslationUnit()`.
      - If `true`, the value returned by this method is the ratio of the translation divided by the distance between grid cells in the dim dimension (Δx or Δy in the constructor javadoc).
      Parameters:
        `dim` - the dimension of the translation vector component to get, from 0 inclusive to `getTranslationDimensions()` exclusive.
        `gridX` - the grid index on the x axis, from 0 inclusive to `gridSize[0]` exclusive.
        `gridY` - the grid index on the y axis, from 0 inclusive to `gridSize[1]` exclusive.
      Returns:
        the translation for the given dimension in the grid cell at the given index.

    - #### getCellMean

          public double getCellMean(int dim)

      Returns an average translation value for the given dimension. Those average values shall provide a good "first guess" before to interpolate the actual translation value at the (x,y) coordinate. This "first guess" is needed for inverse transform.
      Default implementation
      The default implementation computes the average of all values returned by `getCellValue(dim, …)`, but subclasses may override with more specific values.
      Example: In the "France geocentric interpolation" (ESPG:9655) operation method, those "average" values are fixed by definition to -168, -60 and +320 metres for dimensions 0, 1 and 2 respectively (geocentric X, Y and Z).
      Parameters:
        `dim` - the dimension for which to get an average translation value, from 0 inclusive to `getTranslationDimensions()` exclusive.
      Returns:
        a translation value close to the average for the given dimension.

    - #### getCellPrecision

          public abstract double getCellPrecision()

      Returns an estimation of cell value precision (not to be confused with accuracy). This information can be determined in different ways:
      - If the data are read from an ASCII file with a fixed number of digits, then a suggested value is half the precision of the last digit (i.e. 0.5 × 10⁻ⁿ where n is the number of digits after the comma).
      - If there is no indication about precision, then this method should return a value smaller than the best accuracy found in the grid. Accuracy are often specified on a cell-by-cell basis in grid files.
      The output unit of measurement is the same than the one documented in `getCellValue(int, int, int)`. In particular if `isCellValueRatio()` returns `true`, then the accuracy is in units of grid cell size.

      This information is used for determining a tolerance threshold in iterative calculation.

      Returns:
        an estimation of cell value precision.

    - #### isCellValueRatio

          public boolean isCellValueRatio()

      Returns `true` if the translation values in the cells are divided by the cell size. If `true`, then the values returned by `getCellValue(…)`, `getCellMean(…)` and `interpolateInCell(…)` methods are the ratio of the translation divided by the distance between grid cells in the requested dimension (Δx or Δy in the constructor javadoc).
      Returns:
        `true` if the translation values in the cells are divided by the cell size.

    - #### equals

          public boolean equals(Object other)

      Returns `true` if the given object is a grid containing the same data than this grid.
      Overrides:
        `equals` in class `Object`
      Parameters:
        `other` - the other object to compare with this datum shift grid.
      Returns:
        `true` if the given object is non-null, of the same class than this `DatumShiftGrid` and contains the same data.

    - #### hashCode

          public int hashCode()

      Returns a hash code value for this datum shift grid. This method does not need to compute a hash code from all grid values. Comparing some metadata like the grid filename is considered sufficient
      Overrides:
        `hashCode` in class `Object`
      Returns:
        a hash code based on metadata.

Copyright © 2010–2017 The Apache Software Foundation. All rights reserved.