Class WraparoundTransform

All Implemented Interfaces:
Serializable, Parameterized, LenientComparable, org.opengis.referencing.operation.MathTransform
Direct Known Subclasses:
WraparoundInEnvelope

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

WraparoundTransforms 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
Version:
1.1
See Also:
  • Nested Class Summary

    Nested classes/interfaces inherited from class org.apache.sis.referencing.operation.transform.AbstractMathTransform

    AbstractMathTransform.Inverse
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final int
    Number of dimensions of source and target coordinates.
    private org.opengis.referencing.operation.MathTransform
    Inverse of this transform, computed when first needed.
    final double
    Period on wraparound axis, always greater than zero.
    private static final long
    For cross-version compatibility.
    final double
    Coordinate in the wraparound dimension which is at the center of the range of valid source coordinates.
    final int
    The dimension where to apply wraparound.

    Fields inherited from class org.apache.sis.referencing.operation.transform.AbstractMathTransform

    MAXIMUM_BUFFER_SIZE, MAXIMUM_FAILURES
  • 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
    Creates a new transform with the same parameters than the given transform.
  • Method Summary

    Modifier and Type
    Method
    Description
    protected int
    Computes a hash code value for this transform.
    static org.opengis.referencing.operation.MathTransform
    create(int dimension, int wraparoundDimension, double period, double sourceMedian, double targetMedian)
    Returns a transform with a wraparound behavior in the given dimension.
    org.opengis.referencing.operation.Matrix
    derivative(org.opengis.geometry.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.
    private boolean
    Returns true if this transform is equal to the given transform, comparing only the parameters required for forward conversions.
    org.opengis.parameter.ParameterDescriptorGroup
    Returns the parameter descriptors for this math transform.
    org.opengis.parameter.ParameterValueGroup
    Returns the parameter values for this math transform.
    final int
    Gets the dimension of input points.
    final int
    Gets the dimension of output points.
    org.opengis.referencing.operation.MathTransform
    Returns a wraparound transform producing values in the range of source coordinate values.
    private org.opengis.referencing.operation.MathTransform
    movable(org.opengis.referencing.operation.MathTransform tr, org.opengis.referencing.operation.Matrix matrix, MathTransformsOrFactory factory)
    Returns a transform based on the given matrix but converting only coordinates in dimensions that can be processed indifferently before or after this WraparoundTransform.
    redim(boolean applyOtherFirst, org.opengis.referencing.operation.Matrix other)
    Returns an instance with the number of dimensions compatible with the given matrix, while keeping wraparoundDimension, period and sourceMedian unchanged.
    private static org.opengis.referencing.operation.Matrix
    remaining(boolean reverse, org.opengis.referencing.operation.MathTransform move, org.opengis.referencing.operation.Matrix middle)
    Returns a matrix equivalent to applying the inverse of move first, followed by middle.
    static org.opengis.referencing.operation.MathTransform
    replace(org.opengis.referencing.operation.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.
    org.opengis.referencing.operation.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 positions in a list of coordinate values.
    void
    transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int numPts)
    Transforms many positions in a list of coordinate values.
    protected org.opengis.referencing.operation.MathTransform
    tryConcatenate(boolean applyOtherFirst, org.opengis.referencing.operation.MathTransform other, org.opengis.referencing.operation.MathTransformFactory factory)
    Concatenates in an optimized way this math transform with the given one, if possible.

    Methods inherited from class org.apache.sis.io.wkt.FormattableObject

    print, toString, toString, toWKT

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait

    Methods inherited from interface org.opengis.referencing.operation.MathTransform

    toWKT
  • Field Details

    • serialVersionUID

      private static final long serialVersionUID
      For cross-version compatibility.
      See Also:
    • dimension

      private final int dimension
      Number of dimensions of source and target coordinates.
    • 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.
    • inverse

      private transient volatile org.opengis.referencing.operation.MathTransform inverse
      Inverse of this transform, computed when first needed.
      See Also:
  • 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:
    • 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

    • redim

      private WraparoundTransform redim(boolean applyOtherFirst, org.opengis.referencing.operation.Matrix other)
      Returns an instance with the number of dimensions compatible with the given matrix, while keeping wraparoundDimension, period and sourceMedian unchanged. If no instance can be created for the given number of dimensions, then this method returns null.
      Parameters:
      other - matrix defining a transform which will be applied before or after this.
      applyOtherFirst - whether the transform defined by the matrix will be applied before this.
    • create

      public static org.opengis.referencing.operation.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 org.opengis.referencing.operation.MathTransform replace(org.opengis.referencing.operation.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 org.opengis.referencing.operation.MathTransform
      Specified by:
      getSourceDimensions in class AbstractMathTransform
      Returns:
      the dimension of input points.
      See Also:
    • getTargetDimensions

      public final int getTargetDimensions()
      Gets the dimension of output points.
      Specified by:
      getTargetDimensions in interface org.opengis.referencing.operation.MathTransform
      Specified by:
      getTargetDimensions in class AbstractMathTransform
      Returns:
      the dimension of output points.
      See Also:
    • 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: 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:
    • transform

      public org.opengis.referencing.operation.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 coordinates (cannot be null).
      srcOff - the offset to the point to be transformed in the source array.
      dstPts - the array into which the transformed coordinates 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:
    • transform

      public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int numPts)
      Transforms many positions in a list of coordinate values. The default implementation delegates to shift(double) for each point.
      Specified by:
      transform in interface org.opengis.referencing.operation.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 positions in a list of coordinate values. The default implementation delegates to shift(double) for each point.
      Specified by:
      transform in interface org.opengis.referencing.operation.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 org.opengis.referencing.operation.Matrix derivative(org.opengis.geometry.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 org.opengis.referencing.operation.MathTransform
      Overrides:
      derivative in class AbstractMathTransform
      Parameters:
      point - the position where to evaluate the derivative (ignored in default implementation, may be null).
      Returns:
      transform derivative (identity matrix in default implementation).
    • inverse

      public org.opengis.referencing.operation.MathTransform inverse() throws org.opengis.referencing.operation.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 org.opengis.referencing.operation.MathTransform
      Overrides:
      inverse in class AbstractMathTransform
      Returns:
      wraparound transform producing values in the range of source coordinate values.
      Throws:
      org.opengis.referencing.operation.NoninvertibleTransformException - if sourceMedian is NaN or infinite.
    • tryConcatenate

      protected org.opengis.referencing.operation.MathTransform tryConcatenate(boolean applyOtherFirst, org.opengis.referencing.operation.MathTransform other, org.opengis.referencing.operation.MathTransformFactory factory) throws org.opengis.util.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:
      org.opengis.util.FactoryException - if an error occurred while combining the transforms.
      See Also:
    • movable

      private org.opengis.referencing.operation.MathTransform movable(org.opengis.referencing.operation.MathTransform tr, org.opengis.referencing.operation.Matrix matrix, MathTransformsOrFactory factory) throws org.opengis.util.FactoryException
      Returns a transform based on the given matrix but converting only coordinates in dimensions that can be processed indifferently before or after this WraparoundTransform.
      Parameters:
      tr - the transform of the matrix to analyze, or null if none.
      matrix - the matrix to analyze.
      factory - wrapper of the factory given to tryConcatenate(…).
      Returns:
      a transform processing only the movable parts, or null if identity.
      Throws:
      org.opengis.util.FactoryException
    • remaining

      private static org.opengis.referencing.operation.Matrix remaining(boolean reverse, org.opengis.referencing.operation.MathTransform move, org.opengis.referencing.operation.Matrix middle) throws org.opengis.referencing.operation.NoninvertibleTransformException
      Returns a matrix equivalent to applying the inverse of move first, followed by middle. This is appropriate if the move transform is going to be applied first, followed by remaining.

      If reverse is true then this method performs the concatenation in reverse order. This is appropriate if the remaining matrix is going to be applied first, followed by move.

      Throws:
      org.opengis.referencing.operation.NoninvertibleTransformException
    • getParameterDescriptors

      public org.opengis.parameter.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:
    • getParameterValues

      public org.opengis.parameter.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:
    • equalsIgnoreInverse

      private boolean equalsIgnoreInverse(WraparoundTransform other)
      Returns true if this transform is equal to the given transform, comparing only the parameters required for forward conversions.
    • 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:
    • computeHashCode

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