Package org.apache.sis.referencing.operation.transform

# Class WraparoundTransform

Object
FormattableObject
AbstractMathTransform
WraparoundTransform

All Implemented Interfaces:
  `Serializable`, `Parameterized`, `LenientComparable`, `MathTransform`

public class WraparoundTransform extends AbstractMathTransform implements Serializable
Enforces coordinate values in the range of a wraparound axis (typically longitude). For example this transform can shift longitudes from the [0 … 360]° range to the [-180 … +180]° range. The destination range is centered at 0 with a minimal value of −`period`/2 and a maximal value of `period`/2. For a range centered on a different value, a translation can be applied before and after the `WraparoundTransform`.

## Instantiation

`WraparoundTransform`s are not created automatically by `CRS​.findOperation(…)` because they introduce discontinuities in coordinate transformations. Such discontinuities are hurtless when transforming only a cloud of points, but produce undesirable artifacts when transforming envelopes or geometries. Callers need to create `WraparoundTransform` instances explicitly if discontinuities are acceptable.

## Subclassing

In order to control the discontinuity problem, it may be necessary to subclass `WraparoundTransform` and override the `shift(double)` method. For example a subclass may control the wraparounds in a way to prevent the lower corner of an envelope to become greater than the upper corner.

## Inverse transform

The `inverse()` method can return another `WraparoundTransform` with the same period but centered on a different value, which must be specified at construction time. For example if this transform is converting from something to [-180 … +180]° range, then inverse transform is possible only if "something" has been specified (it may be the [0 … 360]° range, but not necessarily).

Since:
  1.1
See Also:
  - Serialized Form

Defined in the `sis-referencing` module

- ## Nested Class Summary

  ## Nested classes/interfaces inherited from class AbstractMathTransform

  `AbstractMathTransform​.Inverse`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `final double`
  `period`
  Period on wraparound axis, always greater than zero.
  `final double`
  `sourceMedian`
  Coordinate in the wraparound dimension which is at the center of the range of valid source coordinates.
  `final int`
  `wraparoundDimension`
  The dimension where to apply wraparound.

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `WraparoundTransform(int dimension, int wraparoundDimension, double period, double sourceMedian)`
  Creates a new transform with a wraparound behavior in the given dimension.
  `protected`
  `WraparoundTransform(WraparoundTransform other)`
  Creates a new transform with the same parameters than the given transform.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `protected int`
  `computeHashCode()`
  Computes a hash code value for this transform.
  `static MathTransform`
  `create(int dimension, int wraparoundDimension, double period, double sourceMedian, double targetMedian)`
  Returns a transform with a wraparound behavior in the given dimension.
  `Matrix`
  `derivative(DirectPosition point)`
  Gets the derivative of this transform at a point.
  `boolean`
  `equals(Object object, ComparisonMode mode)`
  Compares this transform with the given object for equality.
  `ParameterDescriptorGroup`
  `getParameterDescriptors()`
  Returns the parameter descriptors for this math transform.
  `ParameterValueGroup`
  `getParameterValues()`
  Returns the parameter values for this math transform.
  `final int`
  `getSourceDimensions()`
  Gets the dimension of input points.
  `final int`
  `getTargetDimensions()`
  Gets the dimension of output points.
  `MathTransform`
  `inverse()`
  Returns a wraparound transform producing values in the range of source coordinate values.
  `static MathTransform`
  `replace(MathTransform transform, Function<? super WraparoundTransform,? extends WraparoundTransform> replacement)`
  Replaces all `WraparoundTransform` instances in a chain of transform steps.
  `protected double`
  `shift(double x)`
  Applies the wraparound on the given coordinate value.
  `Matrix`
  `transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, boolean derivate)`
  Applies wraparounds on a single point and optionally computes the transform derivative at that location.
  `void`
  `transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)`
  Transforms many coordinates in a list of ordinal values.
  `void`
  `transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)`
  Transforms many coordinates in a list of ordinal values.
  `protected MathTransform`
  `tryConcatenate(boolean applyOtherFirst, MathTransform other, MathTransformFactory factory)`
  Concatenates in an optimized way this math transform with the given one, if possible.

  ### Methods inherited from class AbstractMathTransform

  `equals, formatTo, getContextualParameters, hashCode, isIdentity, transform, transform, transform`

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

  `toWKT`

- ## Field Details

  - ### wraparoundDimension

    public final int wraparoundDimension
    The dimension where to apply wraparound.

  - ### period

    public final double period
    Period on wraparound axis, always greater than zero. This is 360° for the longitude axis. Coordinates will be normalized in the [−period/2 … +period/2] range.

  - ### sourceMedian

    public final double sourceMedian
    Coordinate in the wraparound dimension which is at the center of the range of valid source coordinates. For example if this transform wraps coordinates from the [0 … 360]° range to the [-180 … +180]° range, then `sourceMedian` should be 180° (the value at the center of [0 … 360]° range). The value may be `Double​.NaN` if unknown.

    This field is used for inverse transforms only; it has no effect on the forward transforms. If not NaN, this value is used for building the transform returned by `inverse()`.

    Note: there is no `targetMedian` field because the target median is fixed to 0 in `WraparoundTransform`. Non-zero target medians are implemented by translations applied before and after `WraparoundTransform`. Because of this translation, the value of this field is related to the arguments given to the `create(…)` method by `this​.sourceMeridian = sourceMeridian - targetMeridian`.

- ## Constructor Details

  - ### WraparoundTransform

    protected WraparoundTransform(int dimension, int wraparoundDimension, double period, double sourceMedian)
    Creates a new transform with a wraparound behavior in the given dimension. Output values in the wraparound dimension will be in the [−p/2 … +p/2] range where p is the period (e.g. 360°).
    Parameters:
      `dimension` - number of dimensions of source and target coordinates.
      `wraparoundDimension` - the dimension where to apply wraparound.
      `period` - period on wraparound axis.
      `sourceMedian` - coordinate at the center of the range of valid source coordinates, or NaN if unknown. This argument is used for inverse transforms only (ignored in forward transforms).
    See Also:
      - `create(int, int, double, double, double)`

  - ### WraparoundTransform

    protected WraparoundTransform(WraparoundTransform other)
    Creates a new transform with the same parameters than the given transform. This constructor can be used by subclasses applying the same wraparound than an existing transform but with a different `shift(double)` implementation.
    Parameters:
      `other` - the other transform from which to copy the parameters.

- ## Method Details

  - ### create

    public static MathTransform create(int dimension, int wraparoundDimension, double period, double sourceMedian, double targetMedian)
    Returns a transform with a wraparound behavior in the given dimension. Output values in the wraparound dimension will be in the [t−p/2 … t+p/2] range where t is the target median and p is the period (typically 360° for longitude axis).

    The `sourceMedian` argument is optional (can be `Double​.NaN` if unknown) and has no effect on the forward transform. This argument is used only for creating the inverse transform.

    Examples:
    - Wraparound longitudes in (φ,λ) coordinates from [-180 … +180]° range to [0 … 360]° range: `create(2, 0, 360, 0, 180)`.
    - Wraparound longitudes in (φ,λ,h) coordinates from unknown range to [-180 … +180]° range: `create(3, 0, 360, Double​.NaN, 0)` (non-invertible).
    Parameters:
      `dimension` - number of dimensions of the transform to create.
      `wraparoundDimension` - dimension where wraparound happens.
      `period` - period on wraparound axis.
      `sourceMedian` - coordinate at the center of the range of valid source coordinates, or NaN if unknown.
      `targetMedian` - coordinate at the center of the range of valid target coordinates.
    Returns:
      the wraparound transform.

  - ### replace

    public static MathTransform replace(MathTransform transform, Function<? super WraparoundTransform,? extends WraparoundTransform> replacement)
    Replaces all `WraparoundTransform` instances in a chain of transform steps. For each instance found in the list of transform steps, the given function is invoked with the `WraparoundTransform` instance found. If that function returns a different instance, then this method creates a new chain of transforms with the same steps than the given `transform`, except for the `WraparoundTransform` steps that are replaced by the steps returned by the `replacement` function.

    This method allows injection of a specialized type of `WraparoundTransform`, for example in order to override the `shift(double)` method with finer control of wraparound operations.

    Parameters:
      `transform` - the transform in which to replace `WraparoundTransform` steps.
      `replacement` - function providing replacements for `WraparoundTransform` steps.
    Returns:
      chain of transforms with `WraparoundTransform` steps replaced (if any).

  - ### getSourceDimensions

    public final int getSourceDimensions()
    Gets the dimension of input points.
    Specified by:
      `getSourceDimensions` in interface `MathTransform`
    Specified by:
      `getSourceDimensions` in class `AbstractMathTransform`
    Returns:
      the dimension of input points.
    See Also:
      - `DefaultOperationMethod​.getSourceDimensions()`

  - ### getTargetDimensions

    public final int getTargetDimensions()
    Gets the dimension of output points.
    Specified by:
      `getTargetDimensions` in interface `MathTransform`
    Specified by:
      `getTargetDimensions` in class `AbstractMathTransform`
    Returns:
      the dimension of output points.
    See Also:
      - `DefaultOperationMethod​.getTargetDimensions()`

  - ### shift

    protected double shift(double x)
    Applies the wraparound on the given coordinate value. This method is invoked by default implementation of all `transform(…)` methods defined in this `WraparoundTransform` class. It provides a single method to override if a different wraparound strategy is desired. The default implementation is:

    >     return Math.IEEEremainder(x, period);

    Subclasses may override this method for applying wraparound only under some conditions, in order to reduce discontinuities.
    Parameters:
      `x` - the value on which to apply wraparound.
    Returns:
      the value after wraparound.
    See Also:
      - `Math​.IEEEremainder(double, double)`

  - ### transform

    public Matrix transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, boolean derivate)
    Applies wraparounds on a single point and optionally computes the transform derivative at that location. The default implementation delegates to `shift(double)` and `derivative(DirectPosition)`.
    Specified by:
      `transform` in class `AbstractMathTransform`
    Parameters:
      `srcPts` - the array containing the source coordinate (can not be `null`).
      `srcOff` - the offset to the point to be transformed in the source array.
      `dstPts` - the array into which the transformed coordinate is returned. May be the same than `srcPts`. May be `null` if only the derivative matrix is desired.
      `dstOff` - the offset to the location of the transformed point that is stored in the destination array.
      `derivate` - `true` for computing the derivative, or `false` if not needed.
    Returns:
      the matrix of the transform derivative at the given source position, or `null` if the `derivate` argument is `false`.
    See Also:
      - `AbstractMathTransform​.derivative(DirectPosition)`
      - `AbstractMathTransform​.transform(DirectPosition, DirectPosition)`
      - `MathTransforms​.derivativeAndTransform(MathTransform, double[], int, double[], int)`

  - ### transform

    public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)
    Transforms many coordinates in a list of ordinal values. The default implementation delegates to `shift(double)` for each point.
    Specified by:
      `transform` in interface `MathTransform`
    Overrides:
      `transform` in class `AbstractMathTransform`
    Parameters:
      `srcPts` - the array containing the source point coordinates.
      `srcOff` - the offset to the first point to be transformed in the source array.
      `dstPts` - the array into which the transformed point coordinates are returned. May be the same than `srcPts`.
      `dstOff` - the offset to the location of the first transformed point that is stored in the destination array.
      `numPts` - the number of point objects to be transformed.

  - ### transform

    public void transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)
    Transforms many coordinates in a list of ordinal values. The default implementation delegates to `shift(double)` for each point.
    Specified by:
      `transform` in interface `MathTransform`
    Overrides:
      `transform` in class `AbstractMathTransform`
    Parameters:
      `srcPts` - the array containing the source point coordinates.
      `srcOff` - the offset to the first point to be transformed in the source array.
      `dstPts` - the array into which the transformed point coordinates are returned. May be the same than `srcPts`.
      `dstOff` - the offset to the location of the first transformed point that is stored in the destination array.
      `numPts` - the number of point objects to be transformed.

  - ### derivative

    public Matrix derivative(DirectPosition point)
    Gets the derivative of this transform at a point.
    Mathematical note: strictly speaking the derivative at (n + 0.5) × `period` where n is an integer should be infinite because the coordinate value jumps "instantaneously" from any value to ±`period`/2. However in practice we use derivatives as linear approximations around small regions, not for calculations requiring strict mathematical values. An infinite value goes against the approximation goal. Furthermore whether a source coordinate is an integer value or not is subject to rounding errors, which may cause unpredictable behavior if infinite values were returned.
    Specified by:
      `derivative` in interface `MathTransform`
    Overrides:
      `derivative` in class `AbstractMathTransform`
    Parameters:
      `point` - the coordinate point where to evaluate the derivative (ignored in default implementation, may be `null`).
    Returns:
      transform derivative (identity matrix in default implementation).

  - ### inverse

    public MathTransform inverse() throws NoninvertibleTransformException
    Returns a wraparound transform producing values in the range of source coordinate values. Output values in the wraparound dimension will be in the [s−p/2 … s+p/2] range where s is `sourceMedian` and p is `period`.
    Specified by:
      `inverse` in interface `MathTransform`
    Overrides:
      `inverse` in class `AbstractMathTransform`
    Returns:
      wraparound transform producing values in the range of source coordinate values.
    Throws:
      `NoninvertibleTransformException` - if `sourceMedian` is NaN or infinite.

  - ### tryConcatenate

    protected MathTransform tryConcatenate(boolean applyOtherFirst, MathTransform other, MathTransformFactory factory) throws FactoryException
    Concatenates in an optimized way this math transform with the given one, if possible. If this method detects a chain of operations like below:

    > [wraparound] ⇄ [affine] ⇄ [wraparound or something else]

    Then this method tries to move some dimensions of the [affine] step before or after the [wraparound] step in order to simplify (or ideally remove) the [affine] step in the middle. This move increases the chances that [affine] step is combined with other affine operations. Only dimensions that do not depend on `wraparoundDimension` can be moved.
    Overrides:
      `tryConcatenate` in class `AbstractMathTransform`
    Parameters:
      `applyOtherFirst` - `true` if the transformation order is `other` followed by `this`, or `false` if the transformation order is `this` followed by `other`.
      `other` - the other math transform to (pre-)concatenate with this transform.
      `factory` - the factory which is (indirectly) invoking this method, or `null` if none.
    Returns:
      the math transforms combined in an optimized way, or `null` if no such optimization is available.
    Throws:
      `FactoryException` - if an error occurred while combining the transforms.
    See Also:
      - `DefaultMathTransformFactory​.createConcatenatedTransform(MathTransform, MathTransform)`

  - ### getParameterDescriptors

    public ParameterDescriptorGroup getParameterDescriptors()
    Returns the parameter descriptors for this math transform.
    Specified by:
      `getParameterDescriptors` in interface `Parameterized`
    Overrides:
      `getParameterDescriptors` in class `AbstractMathTransform`
    Returns:
      the parameter descriptors for this math transform.
    See Also:
      - `DefaultOperationMethod​.getParameters()`

  - ### getParameterValues

    public ParameterValueGroup getParameterValues()
    Returns the parameter values for this math transform. The set of parameters include the number of dimensions, the wraparound dimension and the period values. The default implementation does not include the source median because that parameter has no effect on forward transforms (it is used for creating the inverse transform).
    Specified by:
      `getParameterValues` in interface `Parameterized`
    Overrides:
      `getParameterValues` in class `AbstractMathTransform`
    Returns:
      the parameter values for this math transform.
    See Also:
      - `AbstractMathTransform​.getContextualParameters()`
      - `SingleOperation​.getParameterValues()`

  - ### equals

    public boolean equals(Object object, ComparisonMode mode)
    Compares this transform with the given object for equality.
    Specified by:
      `equals` in interface `LenientComparable`
    Overrides:
      `equals` in class `AbstractMathTransform`
    Parameters:
      `object` - the object to compare with this transform.
      `mode` - ignored, can be `null`.
    Returns:
      `true` if the given object is considered equals to this math transform.
    See Also:
      - `Utilities​.deepEquals(Object, Object, ComparisonMode)`

  - ### computeHashCode

    protected int computeHashCode()
    Computes a hash code value for this transform.
    Overrides:
      `computeHashCode` in class `AbstractMathTransform`
    Returns:
      the hash code value.