# Class DimensionalityReduction

Object
DimensionalityReduction

All Implemented Interfaces:
  `Serializable`, `Function<GridCoverage, GridCoverage>`, `UnaryOperator<GridCoverage>`

public class DimensionalityReduction extends Object implements UnaryOperator<GridCoverage>, Serializable
Description about how to reduce the number of dimensions of the domain of a grid coverage. This is a reduction in the number of dimensions of the grid extent, which usually implies a reduction in the number of dimensions of the CRS but not necessarily at the same indices (the relationship between grid dimensions and CRS dimensions is not necessarily straightforward). The sample dimensions (coverage range) are unmodified.

`DimensionalityReduction` specifies which dimensions to keep, and which grid values to use for the omitted dimensions. This information allows the conversion from a source `GridGeometry` to a reduced grid geometry, and conversely.

Instances of `DimensionalityReduction` are immutable and thread-safe.

## Assumptions

The current implementation assumes that removing n dimensions in the grid extent causes the removal of exactly n dimensions in the Coordinate Reference System. However, the removed dimensions do not need to be at the same indices or in same order.

Since:
  1.4
See Also:
  - Serialized Form

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `DimensionalityReduction(GridGeometry source, BitSet gridAxes, MathTransformFactory factory)`
  Reduces the dimension of the specified grid geometry by retaining the axes specified in the given bitset.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `GridCoverage`
  `apply(GridCoverage source)`
  Returns a grid coverage on which dimensionality reduction of the domain has been applied.
  `GridExtent`
  `apply(GridExtent source)`
  Returns a grid extent on which dimensionality reduction has been applied.
  `GridGeometry`
  `apply(GridGeometry source)`
  Returns a grid geometry on which dimensionality reduction of the grid extent has been applied.
  `DirectPosition`
  `apply(DirectPosition source)`
  Returns a coordinate tuple on which dimensionality reduction has been applied.
  `GridGeometry`
  `getReducedGridGeometry()`
  Returns the grid geometry with only the retained grid axis dimension.
  `int[]`
  `getSelectedDimensions()`
  Returns the indices of the source dimensions that are kept in the reduced grid geometry.
  `Map<Integer,Long>`
  `getSliceCoordinates()`
  Returns the grid coordinates used in `reverse(…)` method calls for reconstituting some removed dimensions.
  `GridGeometry`
  `getSourceGridGeometry()`
  Returns the grid geometry with all grid axis dimension.
  `boolean`
  `isIdentity()`
  Returns `true` if this object does not reduce any dimension.
  `boolean`
  `isReduced(GridGeometry candidate)`
  Returns `true` if the given grid geometry is likely to be already reduced.
  `boolean`
  `isSlice()`
  Returns `true` if this dimensionality reduction is a slice in the source coverage.
  `static DimensionalityReduction`
  `reduce(GridGeometry source)`
  Automatically reduces a grid geometry by removing all grid dimensions with an extent size of 1.
  `static DimensionalityReduction`
  `remove(GridGeometry source, int... gridAxesToRemove)`
  Reduces the dimension of the specified grid geometry by removing the specified axes.
  `GridExtent`
  `reverse(GridExtent reduced)`
  Returns a grid extent on which dimensionality reduction has been reverted.
  `GridGeometry`
  `reverse(GridGeometry reduced)`
  Returns a grid geometry on which dimensionality reduction has been reverted.
  `static DimensionalityReduction`
  `select(GridGeometry source, int... gridAxesToPass)`
  Reduces the dimension of the specified grid geometry by retaining only the specified axes.
  `static DimensionalityReduction`
  `select2D(GridGeometry source)`
  A convenience method for selecting the two first dimensions of the specified grid geometry.
  `DimensionalityReduction`
  `withSliceByRatio(double ratio)`
  Returns a dimensional reduction with a relative slice position for every grid dimensions that have been removed.
  `DimensionalityReduction`
  `withSlicePoint(long[] point)`
  Returns a dimensional reduction which will use the given source grid indices for `reverse(…)` operations.

  ### Methods inherited from class Object

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

  ### Methods inherited from interface Function

  `andThen, compose`

- ## Constructor Details

  - ### DimensionalityReduction

    protected DimensionalityReduction(GridGeometry source, BitSet gridAxes, MathTransformFactory factory) throws FactoryException
    Reduces the dimension of the specified grid geometry by retaining the axes specified in the given bitset. Axes in the reduced grid geometry will be in the same order as in the source geometry:
    Parameters:
      `source` - the grid geometry on which to select a subset of its grid dimensions.
      `gridAxes` - bitmask of indices of source grid dimensions to keep in the reduced grid. Will be modified by this constructor for internal purpose.
      `factory` - the factory to use for creating new math transforms, or `null` for the default.
    Throws:
      `FactoryException` - if the dimensions to keep cannot be separated from the dimensions to omit.

- ## Method Details

  - ### select

    public static DimensionalityReduction select(GridGeometry source, int... gridAxesToPass)
    Reduces the dimension of the specified grid geometry by retaining only the specified axes. Axes in the reduced grid geometry will be in the same order as in the source geometry: change of axis order and duplicated values in the `gridAxesToPass` argument are ignored.
    Parameters:
      `source` - the grid geometry to reduce.
      `gridAxesToPass` - the grid axes to retain, ignoring order and duplicated values.
    Returns:
      reduced grid geometry together with other information.
    Throws:
      `IndexOutOfBoundsException` - if a grid axis index is out of bounds.
      `IllegalGridGeometryException` - if the dimensions to keep cannot be separated from the dimensions to omit.

  - ### select2D

    public static DimensionalityReduction select2D(GridGeometry source)
    A convenience method for selecting the two first dimensions of the specified grid geometry. This method can be used as a lambda function in resources query. Example:

        CoverageQuery query = new CoverageQuery();
        query.setAxisSelection(DimensionalityReduction::select2D);

    Parameters:
      `source` - the grid geometry to reduce.
    Returns:
      reduced grid geometry together with other information.
    Throws:
      `IndexOutOfBoundsException` - if the grid geometry does not have at least two dimensions.
      `IllegalGridGeometryException` - if the dimensions to keep cannot be separated from the dimensions to omit.
    See Also:
      - `CoverageQuery​.setAxisSelection(Function)`

  - ### remove

    public static DimensionalityReduction remove(GridGeometry source, int... gridAxesToRemove)
    Reduces the dimension of the specified grid geometry by removing the specified axes. Axes in the reduced grid geometry will be in the same order as in the source geometry: axis order and duplicated values in the `gridAxesToRemove` argument are not significant.
    Parameters:
      `source` - the grid geometry to reduce.
      `gridAxesToRemove` - the grid axes to remove, ignoring order and duplicated values.
    Returns:
      reduced grid geometry together with other information.
    Throws:
      `IndexOutOfBoundsException` - if a grid axis index is out of bounds.
      `IllegalGridGeometryException` - if the dimensions to keep cannot be separated from the dimensions to omit.

  - ### reduce

    public static DimensionalityReduction reduce(GridGeometry source)
    Automatically reduces a grid geometry by removing all grid dimensions with an extent size of 1. Axes in the reduced grid geometry will be in the same order as in the source geometry.
    Parameters:
      `source` - the grid geometry to reduce.
    Returns:
      reduced grid geometry together with other information.
    Throws:
      `IncompleteGridGeometryException` - if the grid geometry has no extent.
      `IllegalGridGeometryException` - if the dimensions to keep cannot be separated from the dimensions to omit.
    See Also:
      - `select2D(GridGeometry)`

  - ### isIdentity

    public boolean isIdentity()
    Returns `true` if this object does not reduce any dimension. It may happen if `select(…)` has been invoked with all axes to keep, or if `remove(…)` has been invoked with no axis to remove.
    Returns:
      whether this `DimensionalityReduction` does nothing.

  - ### isSlice

    public boolean isSlice()
    Returns `true` if this dimensionality reduction is a slice in the source coverage. This is true if all removed dimensions either have a grid size of one cell, or have a slice coordinate specified.

    If this method returns `false`, then the results of `reverse(…)` method calls are potentially ambiguous and may cause a `SubspaceNotSpecifiedException` to be thrown at rendering time.

    Returns:
      whether this dimensionality reduction is a slice in the source coverage.
    See Also:
      - `getSliceCoordinates()`
      - `withSlicePoint(long[])`
      - `withSliceByRatio(double)`

  - ### isReduced

    public boolean isReduced(GridGeometry candidate)
    Returns `true` if the given grid geometry is likely to be already reduced. Current implementation checks only the number of dimensions.
    Parameters:
      `candidate` - the grid geometry to test.
    Returns:
      whether the given grid geometry is likely to be already reduced.

  - ### getReducedGridGeometry

    public GridGeometry getReducedGridGeometry()
    Returns the grid geometry with only the retained grid axis dimension. The number of CRS dimensions should be reduced as well, but not necessarily in a one-to-one relationship.
    Returns:
      the grid geometry with retained grid dimensions.

  - ### getSourceGridGeometry

    public GridGeometry getSourceGridGeometry()
    Returns the grid geometry with all grid axis dimension. This is the `source` argument given to factory methods.
    Returns:
      the grid geometry with all grid dimensions.

  - ### getSelectedDimensions

    public int[] getSelectedDimensions()
    Returns the indices of the source dimensions that are kept in the reduced grid geometry.
    Returns:
      indices of source grid dimensions that are retained in the reduced grid geometry.

  - ### getSliceCoordinates

    public Map<Integer,Long> getSliceCoordinates()
    Returns the grid coordinates used in `reverse(…)` method calls for reconstituting some removed dimensions. Keys are indices of grid dimensions in the source that are not retained in the reduced grid geometry. Values are grid coordinates to assign to those dimensions when a `reverse(…)` method is executed.

    This map does not need to contain an entry for all removed dimensions. If no slice point is specified for a given dimension, then the `reverse(…)` methods will use the full range of grid coordinates specified in the source geometry. Often, those ranges have a size of 1, in which case methods such as `GridCoverage​.render(GridExtent)` will work anyway. If a removed source grid dimension had a size greater than 1 and no slice coordinates is specified; then the `reverse(…)` methods in this class will still work but an `SubspaceNotSpecifiedException` may be thrown later by other classes.

    This map is initially empty. Slice coordinates can be specified by calls to `withSlicePoint(long[])` or `withSliceByRatio(double)`.

    Returns:
      source grid coordinates of the slice point used in `reverse(…)` method calls.
    See Also:
      - `withSlicePoint(long[])`
      - `withSliceByRatio(double)`
      - `GridExtent​.getSliceCoordinates()`
      - `GridCoverage​.Evaluator​.setDefaultSlice(Map)`

  - ### apply

    public DirectPosition apply(DirectPosition source)
    Returns a coordinate tuple on which dimensionality reduction has been applied.

    #### Precondition

    The coordinate reference system of the given `source` should be either null or equal (ignoring metadata) to the CRS of the source grid geometry. For performance reason, this condition is not verified unless Java assertions are enabled.
    Parameters:
      `source` - the source coordinate tuple, or `null`.
    Returns:
      the reduced coordinate tuple, or `null` if the given source was null.

  - ### apply

    public GridExtent apply(GridExtent source)
    Returns a grid extent on which dimensionality reduction has been applied. If the given source is `null`, then this method returns `null`. Nulls are accepted because they are valid argument values in calls to `GridCoverage​.render(GridExtent)`.
    Parameters:
      `source` - the grid extent to reduce, or `null`.
    Returns:
      the reduced grid extent. May be `source`, which may be null.
    Throws:
      `MismatchedDimensionException` - if the given source does not have the expected number of dimensions.
      `IllegalArgumentException` - if axis types are specified but inconsistent in at least one dimension.
    See Also:
      - `GridExtent​.selectDimensions(int...)`

  - ### apply

    public GridGeometry apply(GridGeometry source)
    Returns a grid geometry on which dimensionality reduction of the grid extent has been applied. It usually implies a reduction in the number of dimensions of the CRS as well, but not necessarily in same order.

    If the given source is `null`, then this method returns `null`. Nulls are accepted because they are valid argument values in calls to `GridCoverageResource​.read(GridGeometry, int...)`.

    Parameters:
      `source` - the grid geometry to reduce, or `null`.
    Returns:
      the reduced grid geometry. May be `source`, which may be null.
    Throws:
      `MismatchedDimensionException` - if the given source does not have the expected number of dimensions.
      `IllegalArgumentException` - if axis types are specified but inconsistent in at least one dimension.
    See Also:
      - `GridGeometry​.selectDimensions(int...)`

  - ### apply

    public GridCoverage apply(GridCoverage source)
    Returns a grid coverage on which dimensionality reduction of the domain has been applied. This is a reduction in the number of dimensions of the grid extent. It usually implies a reduction in the number of dimensions of the CRS as well, but not necessarily in same order. The sample dimensions (coverage range) are unmodified.

    The returned coverage is a view: changes in the source coverage are reflected immediately in the reduced coverage, and conversely.

    #### Reversibility

    If `isSlice()` returns `false`, then the results of `reverse(GridExtent)` are ambiguous and calls to `GridCoverage​.render(GridExtent)` may cause an `SubspaceNotSpecifiedException` to be thrown. Unless the specified `source` grid coverage knows how to handle those cases.
    Specified by:
      `apply` in interface `Function<GridCoverage, GridCoverage>`
    Parameters:
      `source` - the grid coverage to reduce.
    Returns:
      the reduced grid coverage, or `source` if this object is identity.
    Throws:
      `MismatchedDimensionException` - if the given source does not have the expected number of dimensions.
      `IllegalArgumentException` - if axis types are specified but inconsistent in at least one dimension.
    See Also:
      - `GridCoverageProcessor​.selectGridDimensions(GridCoverage, int...)`

  - ### reverse

    public GridExtent reverse(GridExtent reduced)
    Returns a grid extent on which dimensionality reduction has been reverted. For all dimensions that were removed, grid coordinates will be set to the slice coordinates if specified, or to the original source grid coordinates otherwise. In the latter case, the reconstituted grid coordinates will be a single value if `isSlice()` returns `true` (in which case the returned extent is unambiguous), or may be a (potentially ambiguous) range of values otherwise.

    #### Handling of null grid geometry

    If the given extent is `null`, then this method returns an extent with slice coordinates if they are known. If no slice coordinate has been specified, then this method returns `null`. Nulls are accepted because they are valid argument values in calls to `GridCoverage​.render(GridExtent)`.
    Parameters:
      `reduced` - the reduced grid extent to revert, or `null`.
    Returns:
      the source grid extent. May be `reduced`, which may be null.
    Throws:
      `IncompleteGridGeometryException` - if the source grid geometry has no extent.
      `MismatchedDimensionException` - if the given extent does not have the expected number of dimensions.
      `IllegalArgumentException` - if axis types are specified but inconsistent in at least one dimension.

  - ### reverse

    public GridGeometry reverse(GridGeometry reduced)
    Returns a grid geometry on which dimensionality reduction has been reverted. For all dimensions that were removed, grid coordinates will be set to the slice coordinates if specified, or to the original source grid coordinates otherwise. In the latter case, the reconstituted dimensions will map a single coordinate value if `isSlice()` returns `true` (in which case the returned grid geometry is unambiguous), or may map a (potentially ambiguous) range of grid coordinate values otherwise.

    #### Handling of null grid geometry

    If the given geometry is `null`, then this method returns a grid geometry with the slice coordinates if they are known. If no slice coordinate has been specified, then this method returns `null`. Nulls are accepted because they are valid argument values in calls to `GridCoverageResource​.read(GridGeometry, int...)`.
    Parameters:
      `reduced` - the reduced grid geometry to revert, or `null`.
    Returns:
      the source grid geometry. May be `reduced`, which may be null.
    Throws:
      `IncompleteGridGeometryException` - if the source grid geometry has no extent.
      `MismatchedDimensionException` - if the given geometry does not have the expected number of dimensions.
      `IllegalArgumentException` - if axis types are specified but inconsistent in at least one dimension.

  - ### withSlicePoint

    public DimensionalityReduction withSlicePoint(long[] point)
    Returns a dimensional reduction which will use the given source grid indices for `reverse(…)` operations. The length of the given `slicePoint` array shall be the number of dimensions of the source grid geometry. All given coordinate values shall be inside the source grid extent.
    Parameters:
      `point` - grid coordinates of a point located on the slice.
    Returns:
      the dimensionality reduction with the given slice point used for reverse operations.
    Throws:
      `IncompleteGridGeometryException` - if the source grid geometry has no extent.
      `MismatchedDimensionException` - if the given point does not have the expected number of dimensions.
      `PointOutsideCoverageException` - if the given point is outside the source grid extent.

  - ### withSliceByRatio

    public DimensionalityReduction withSliceByRatio(double ratio)
    Returns a dimensional reduction with a relative slice position for every grid dimensions that have been removed. The relative position is specified by a ratio between 0 and 1 where 0 maps to low grid coordinates, 1 maps to high grid coordinates and 0.5 maps to the median position.
    Parameters:
      `ratio` - the ratio to apply on all removed grid dimensions.
    Returns:
      the dimensionality reduction with the given slice ratio applied.
    Throws:
      `IncompleteGridGeometryException` - if the source grid geometry has no extent.
      `IllegalArgumentException` - if the given ratio is not between 0 and 1 inclusive.
    See Also:
      - `GridExtent​.getRelative(int, double)`
      - `GridDerivation​.sliceByRatio(double, int...)`