Class LinearTransformBuilder

java.lang.Object
org.apache.sis.referencing.operation.builder.TransformBuilder
org.apache.sis.referencing.operation.builder.LinearTransformBuilder

public class LinearTransformBuilder extends TransformBuilder
Creates an affine transform which will map approximately the given source positions to the given target positions. In many cases, the source positions are grid indices and the target positions are geographic or projected coordinates, but this is not mandatory. If the source positions are known to be grid indices, then a builder created by the LinearTransformBuilder(int...) constructor will be more efficient. Otherwise a builder created by the LinearTransformBuilder() constructor will be able to handle randomly distributed coordinates.

Builders are not thread-safe. Builders can be used only once; points cannot be added or modified after create(MathTransformFactory) has been invoked. The transform coefficients are determined using a least squares estimation method, with the assumption that source positions are exact and all the uncertainty is in the target positions.

Linearizers

Consider the following situation (commonly found with
invalid reference
netCDF files
): the sources coordinates are pixel indices and the targets are (longitude, latitude) coordinates, but we suspect that the sources to targets transform is some undetermined map projection, maybe Mercator. A linear approximation between those coordinates will give poor results; the results would be much better if all (longitude, latitude) coordinates were converted to the right projection first. However, that map projection may not be known, but we can try to guess it by trials-and-errors using a set of plausible projections. That set can be specified by addLinearizers(Map, int...). If the create(MathTransformFactory) method finds that one of the specified projections seems a good fit, it will automatically convert all target coordinates to that projection. That selected projection is given by linearizer().
Since:
0.5
Version:
1.2
See Also:
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    private class 
    Implementation of the map returned by getControlPoints().
    private final class 
    Implementation of the map returned by getControlPoints() when no grid is used.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    If one of the linearizers have been applied, that linearizer.
    private double[]
    An estimation of the Pearson correlation coefficient for each target dimension.
    (package private) final int
    The product of all gridSize values, or 0 if none or if gridSize is null.
    private final int[]
    Number of grid columns and rows, or null if the coordinates are not distributed on a regular grid.
    If the user suspects that the transform may be linear when the target is another space than the space of targets coordinates, projections toward spaces to try.
    private int
    Number of valid positions in the sources or targets arrays.
    private double[][]
    The arrays of source coordinate values.
    private double[][]
    The arrays of target coordinate values.
    The transform created by the last call to create(MathTransformFactory).
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
     
    Creates a new linear transform builder for randomly distributed positions.
     
    LinearTransformBuilder(int... gridSize)
    Creates a new linear transform builder for source positions distributed on a regular grid.
    private
    Creates a temporary builder with all source fields from the given builder and no target arrays.
  • Method Summary

    Modifier and Type
    Method
    Description
    (package private) final void
    addLinearizers(Map<String,org.opengis.referencing.operation.MathTransform> projections, boolean compensate, int[] projToGrid)
    Implementation of addLinearizers(Map, int...) with a flag telling whether the inverse of selected projection shall be concatenated to the final transform.
    void
    addLinearizers(Map<String,org.opengis.referencing.operation.MathTransform> projections, int... projToGrid)
    Adds transforms to potentially apply on target control points before to compute the linear transform.
    private void
    allocate(int tgtDim)
    Allocates memory for a builder created for source positions distributed on a grid.
    (package private) final String
    appendTo(StringBuilder buffer, Class<?> caller, Locale locale, short resultKey)
    Appends a string representation of this builder into the given buffer.
    (package private) final ProjectedTransformTry
    Returns linearizer which has been applied, or null if none.
    approximate(org.opengis.referencing.operation.MathTransform gridToCRS, org.opengis.geometry.Envelope domain)
    Returns a linear approximation of the given transform for the specified domain.
    double[]
    Returns the Pearson correlation coefficients of the transform created by create(…).
    create(org.opengis.referencing.operation.MathTransformFactory factory)
    Creates a linear transform approximation from the source positions to the target positions.
    private void
    Throws IllegalStateException if this builder cannot be modified anymore.
    private static org.opengis.geometry.Envelope
    envelope(double[][] points, int numPoints)
    private MatrixSIS
    fit()
    Computes the matrix of the linear approximation.
    private int
    flatIndex(int[] source)
    Returns the offset where to store a target position for the given source position in the flattened array.
    private int
    flatIndex(org.opengis.geometry.DirectPosition source)
    Returns the index where to store a target position for the given source position in the flattened array.
    double[]
    getControlPoint(int[] source)
    Returns a single target coordinate for the given source coordinate, or null if none.
    Map<org.opengis.geometry.DirectPosition,org.opengis.geometry.DirectPosition>
    Returns all control points as a map.
    (package private) final void
    getControlRow(int[] source, double[] target)
    More straightforward version of getControlPoint(int[]) for the case where this LinearTransformBuilder is known to have been built for grid source coordinates.
    (package private) final int
    Returns the number of dimensions in the source grid, or -1 if this builder is not backed by a grid.
    int
    Returns the number of dimensions in source positions.
    org.opengis.geometry.Envelope
    Returns the envelope of source points (keys of the map returned by getControlPoints()).
    int
    Returns the number of dimensions in target positions.
    org.opengis.geometry.Envelope
    Returns the envelope of target points (values of the map returned by getControlPoints()).
    (package private) final Vector
    getTransect(int dimension, int[] start, int direction)
    Returns the coordinates of a single row or column in the given dimension.
    (package private) final int
    gridSize(int srcDim)
    Returns the grid size for the given dimension.
    (package private) final boolean
    Returns true if create(MathTransformFactory) has not yet been invoked.
    Optional<Map.Entry<String,org.opengis.referencing.operation.MathTransform>>
    If target coordinates have been projected to another space, returns that projection.
    private org.opengis.geometry.MismatchedDimensionException
    mismatchedDimension(String name, int expected, int actual)
    Builds the exception message for an unexpected position dimension.
    private static String
    Returns the error message to be given to IllegalStateException when there is no data.
    private static org.opengis.geometry.DirectPosition
    position(org.opengis.geometry.coordinate.Position p)
    Returns the direct position of the given position, or null if none.
    private static void
    resize(double[][] data, int capacity)
    Resize all the given arrays to the given capacity.
    (package private) final NumberRange<Double>
    resolveWraparoundAxis(int dimension, int direction, double period)
    Tries to remove discontinuities in coordinates values caused by anti-meridian crossing.
    private static double
    rms(double[] correlations, double sqrtCorrLength)
    Returns a global estimation of correlation by computing the root mean square of values.
    private int
    search(int[] source)
    Returns the offset of the given source grid coordinate, or -1 if none.
    void
    setControlPoint(int[] source, double[] target)
    Sets a single matching control point pair.
    void
    setControlPoints(Map<? extends org.opengis.geometry.coordinate.Position,? extends org.opengis.geometry.coordinate.Position> sourceToTarget)
    Sets all control point (source, target) pairs, overwriting any previous setting.
    (package private) final void
    setControlPoints(Vector[] coordinates)
    Sets all control points.
    void
    setControlPoints(org.opengis.referencing.operation.MathTransform gridToCRS)
    Sets all control point (source, target) pairs, overwriting any previous setting.
    (package private) final void
    Sets the linearizers to a copy of those of the given builder.
    (package private) final Vector[]
    Returns the vector of source coordinates.
    Returns a string representation of this builder for debugging purpose.
    (package private) final LinearTransform
    Returns the transform computed by create(MathTransformFactory), of null if that method has not yet been invoked.
    private Vector
    vector(double[] data)
    Wraps the given array in a vector of length numPoints.
    private void
    Verifies that the given number of dimensions is equal to the expected value.

    Methods inherited from class org.apache.sis.referencing.operation.builder.TransformBuilder

    nonNull

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
  • Field Details

    • gridSize

      private final int[] gridSize
      Number of grid columns and rows, or null if the coordinates are not distributed on a regular grid. If the grid size is known, then the sources coordinates do not need to be specified.
    • sources

      private double[][] sources
      The arrays of source coordinate values. Accessed with indices in that order: sources[dimension][point]. This layout allows to create only a few (typically two) large arrays instead of a multitude of small arrays. Example: {x[], y[]}.

      In the special case where gridSize is non-null, then this array does not need to be specified and can be null. In such case, the source coordinates are implicitly:

      (0,0), (1,0), (2,0), (3,0) … (gridSize[0]-1, 0),
      (0,1), (1,1), (2,1), (3,1) … (gridSize[0]-1, 1),
      (0,2), (1,2), (2,2), (3,2) … (gridSize[0]-1, 2),
      (0,gridSize[1]-1) … (gridSize[0]-1, gridSize[1]-1).
    • targets

      private double[][] targets
      The arrays of target coordinate values. Accessed with indices in that order: targets[dimension][point]. This layout allows to create only a few (typically two) large arrays instead of a multitude of small arrays. Example: {x[], y[], z[]}. This is null if not yet specified.
      Implementation note: we could use a flat array with (x₀, y₀), (x₁, y₁), (x₂, y₂), etc. coordinate tuples instead. Such flat array would be more convenient for some coordinate conversions with MathTransform. But using array of arrays is more convenient for other calculations working on one dimension at time, make data more local for CPU, and also allows handling of more points.
    • gridLength

      final int gridLength
      The product of all gridSize values, or 0 if none or if gridSize is null. If non-zero, then this is the length of targets arrays to create.
    • numPoints

      private int numPoints
      Number of valid positions in the sources or targets arrays. Note that the "valid" positions may contain Double.NaN coordinate values. This field is only indicative if this LinearTransformBuilder instance has been created by LinearTransformBuilder(int...) because we do not try to detect if user adds a new point or overwrites an existing one.
    • linearizers

      private List<ProjectedTransformTry> linearizers
      If the user suspects that the transform may be linear when the target is another space than the space of targets coordinates, projections toward spaces to try. The create(MathTransformFactory) method will try to apply those transforms on targets and check if they produce better fits.
      See Also:
    • appliedLinearizer

      private transient ProjectedTransformTry appliedLinearizer
      If one of the linearizers have been applied, that linearizer. Otherwise null.
      See Also:
    • transform

      private transient LinearTransform transform
      The transform created by the last call to create(MathTransformFactory). A non-null value means that this builder became unmodifiable.
    • correlations

      private transient double[] correlations
      An estimation of the Pearson correlation coefficient for each target dimension. This is null if not yet computed.
  • Constructor Details

    • LinearTransformBuilder

      private LinearTransformBuilder(LinearTransformBuilder original)
      Creates a temporary builder with all source fields from the given builder and no target arrays. Calculated fields, namely correlations and transform, are left uninitialized. Arrays are copied by references and their content shall not be modified. The new builder should not be made accessible to users since changes in this builder would be reflected in the source values of original builder. This constructor is reserved to create(MathTransformFactory) internal usage.
      Parameters:
      original - the builder from which to take array references of source values.
    • LinearTransformBuilder

      public LinearTransformBuilder()
      Creates a new linear transform builder for randomly distributed positions.
      Tip: if the source coordinates are grid indices, then the LinearTransformBuilder(int...) constructor will create a more efficient builder.
    • LinearTransformBuilder

      public LinearTransformBuilder(int... gridSize)
      Creates a new linear transform builder for source positions distributed on a regular grid. This constructor notifies LinearTransformBuilder that coordinate values of all source positions will be integers in the [0 … gridSize[0]-1] range for the first dimension (typically column indices), in the [0 … gridSize[1]-1] range for the second dimension (typically row indices), etc. The dimension of all source positions is the length of the given gridSize array.

      An empty array is equivalent to invoking the no-argument constructor, i.e. no restriction is put on the source coordinates.

      Parameters:
      gridSize - the number of integer coordinate values in each grid dimension.
      Throws:
      IllegalArgumentException - if a grid size is not strictly positive, or if the product of all values (∏gridSize) is greater than Integer.MAX_VALUE.
      Since:
      0.8
  • Method Details

    • approximate

      public static LinearTransform approximate(org.opengis.referencing.operation.MathTransform gridToCRS, org.opengis.geometry.Envelope domain) throws org.opengis.util.FactoryException
      Returns a linear approximation of the given transform for the specified domain. The source positions are integer coordinates included in the given envelope. The target positions are the results of transforming source coordinates with the given gridToCRS transform.
      Parameters:
      gridToCRS - the transform from source coordinates (grid indices) to target coordinates.
      domain - domain of integer source coordinates for which to get a linear approximation.
      Returns:
      a linear approximation of given transform for the specified domain.
      Throws:
      org.opengis.util.FactoryException - if the transform approximation cannot be computed.
      Since:
      1.1
      See Also:
    • gridSize

      final int gridSize(int srcDim)
      Returns the grid size for the given dimension. It is caller's responsibility to ensure that this method is invoked only on instances created by LinearTransformBuilder(int...).
      See Also:
    • allocate

      private void allocate(int tgtDim)
      Allocates memory for a builder created for source positions distributed on a grid. All target values need to be initialized to NaN because we cannot rely on numPoints.

      If this builder has been created for randomly distributed source points, then the allocation should rather be performed as below:

    • resize

      private static void resize(double[][] data, int capacity)
      Resize all the given arrays to the given capacity. This method should be invoked only for LinearTransformBuilder instances created for randomly distributed source positions.
    • search

      private int search(int[] source)
      Returns the offset of the given source grid coordinate, or -1 if none. The algorithm implemented in this method is inefficient, but should rarely be used. This is only a fallback when flatIndex(int[]) cannot be used. Callers is responsible to ensure that the number of dimensions match.
      See Also:
    • flatIndex

      private int flatIndex(int[] source)
      Returns the offset where to store a target position for the given source position in the flattened array. This method should be invoked only when this LinearTransformBuilder has been created for a grid of known size. Caller must have verified the array length before to invoke this method.
      Throws:
      IllegalArgumentException - if a coordinate value is illegal.
    • flatIndex

      private int flatIndex(org.opengis.geometry.DirectPosition source)
      Returns the index where to store a target position for the given source position in the flattened array. This method should be invoked only when this LinearTransformBuilder has been created for a grid of known size. Callers must have verified the position dimension before to invoke this method.
      Throws:
      IllegalArgumentException - if a coordinate value is illegal.
      See Also:
    • isModifiable

      final boolean isModifiable()
      Returns true if create(MathTransformFactory) has not yet been invoked.
    • ensureModifiable

      private void ensureModifiable() throws IllegalStateException
      Throws IllegalStateException if this builder cannot be modified anymore.
      Throws:
      IllegalStateException
    • verifySourceDimension

      private void verifySourceDimension(int actual) throws org.opengis.geometry.MismatchedDimensionException
      Verifies that the given number of dimensions is equal to the expected value. No verification are done if the source point is the first point of randomly distributed points.
      Throws:
      org.opengis.geometry.MismatchedDimensionException
    • mismatchedDimension

      private org.opengis.geometry.MismatchedDimensionException mismatchedDimension(String name, int expected, int actual)
      Builds the exception message for an unexpected position dimension. This method assumes that positions are stored in this builder as they are read from user-provided collection, with numPoints the index of the next point that we failed to add.
    • noData

      private static String noData()
      Returns the error message to be given to IllegalStateException when there is no data.
    • getGridDimensions

      final int getGridDimensions()
      Returns the number of dimensions in the source grid, or -1 if this builder is not backed by a grid. Contrarily to the other get*Dimensions() methods, this method does not throw exception.
      See Also:
    • getSourceDimensions

      public int getSourceDimensions()
      Returns the number of dimensions in source positions. This is the length of the source array given in argument to get/setControlPoint(int[], …) methods. This is also the number of dimensions of the DirectPosition keys in the Map exchanged by get/setControlPoints(Map) methods.
      Returns:
      the dimension of source points.
      Throws:
      IllegalStateException - if the number of source dimensions is not yet known.
      Since:
      0.8
      See Also:
      • MathTransform.getSourceDimensions()
    • getTargetDimensions

      public int getTargetDimensions()
      Returns the number of dimensions in target positions. This is the length of the target array exchanged by get/setControlPoint(…, double[]) methods. This is also the number of dimensions of the DirectPosition values in the Map exchanged by get/setControlPoints(Map) methods.
      Returns:
      the dimension of target points.
      Throws:
      IllegalStateException - if the number of target dimensions is not yet known.
      Since:
      0.8
      See Also:
      • MathTransform.getTargetDimensions()
    • getSourceEnvelope

      public org.opengis.geometry.Envelope getSourceEnvelope()
      Returns the envelope of source points (keys of the map returned by getControlPoints()). The number of dimensions is equal to getSourceDimensions(). This method returns the known minimum and maximum values (inclusive) for each dimension, not expanded to encompass full cell surfaces. In other words, the returned envelope encompasses only cell centers.

      If a grid size was specified at construction time, then those minimums and maximums are inferred from the grid size and are always integer values. Otherwise, the minimums and maximums are extracted from the control points and may be any floating point values. In any cases, the lower and upper values are inclusive.

      Returns:
      the envelope of source points (cell centers), inclusive.
      Throws:
      IllegalStateException - if the source points are not yet known.
      Since:
      1.0
    • getTargetEnvelope

      public org.opengis.geometry.Envelope getTargetEnvelope()
      Returns the envelope of target points (values of the map returned by getControlPoints()). The number of dimensions is equal to getTargetDimensions(). The lower and upper values are inclusive. If a linearizer has been applied, then coordinates of the returned envelope are projected by that linearizer.
      Returns:
      the envelope of target points.
      Throws:
      IllegalStateException - if the target points are not yet known.
      Since:
      1.0
    • envelope

      private static org.opengis.geometry.Envelope envelope(double[][] points, int numPoints)
    • position

      private static org.opengis.geometry.DirectPosition position(org.opengis.geometry.coordinate.Position p)
      Returns the direct position of the given position, or null if none.
    • setControlPoints

      public void setControlPoints(org.opengis.referencing.operation.MathTransform gridToCRS) throws org.opengis.referencing.operation.TransformException
      Sets all control point (source, target) pairs, overwriting any previous setting. The source positions are all integer coordinates in a rectangle from (0, 0, …) inclusive to gridSize exclusive where gridSize is an int[] array specified at construction time. The target positions are the results of transforming all source coordinates with the given gridToCRS transform.
      Parameters:
      gridToCRS - the transform from source coordinates (grid indices) to target coordinates.
      Throws:
      org.opengis.referencing.operation.TransformException - if a coordinate value cannot be transformed.
      Since:
      1.1
      See Also:
    • setControlPoints

      public void setControlPoints(Map<? extends org.opengis.geometry.coordinate.Position,? extends org.opengis.geometry.coordinate.Position> sourceToTarget) throws org.opengis.geometry.MismatchedDimensionException
      Sets all control point (source, target) pairs, overwriting any previous setting. The source positions are the keys in given map, and the target positions are the associated values. The map should not contain two entries with the same source position. Coordinate reference systems are ignored. Null positions are silently ignored. Positions with NaN or infinite coordinates cause an exception to be thrown.

      All source positions shall have the same number of dimensions (the source dimension), and all target positions shall have the same number of dimensions (the target dimension). However, the source dimension does not need to be the same than the target dimension. Apache SIS currently supports only one- or two-dimensional source positions, together with arbitrary target dimension.

      If this builder has been created with the LinearTransformBuilder(int...) constructor, then the coordinate values of all source positions shall be integers in the [0 … gridSize[0]-1] range for the first dimension (typically column indices), in the [0 … gridSize[1]-1] range for the second dimension (typically row indices), etc. This constraint does not apply for builders created with the LinearTransformBuilder() constructor.

      Parameters:
      sourceToTarget - a map of source positions to target positions. Source positions are assumed precise and target positions are assumed uncertain.
      Throws:
      IllegalStateException - if create(…) has already been invoked.
      IllegalArgumentException - if the given positions contain NaN or infinite coordinate values.
      IllegalArgumentException - if this builder has been created for a grid but some source coordinates are not indices in that grid.
      org.opengis.geometry.MismatchedDimensionException - if some positions do not have the expected number of dimensions.
      Since:
      0.8
    • getControlPoints

      public Map<org.opengis.geometry.DirectPosition,org.opengis.geometry.DirectPosition> getControlPoints()
      Returns all control points as a map. Values are source coordinates and keys are target coordinates. The map is unmodifiable and is guaranteed to contain only non-null keys and values. The map is a view: changes in this builder are immediately reflected in the returned map.

      If linearizer() returns a non-empty value, then the values in the returned map are projected using that linearizer. This may happen only after create(…) has been invoked.

      Returns:
      all control points in this builder.
      Since:
      1.0
    • setControlPoint

      public void setControlPoint(int[] source, double[] target)
      Sets a single matching control point pair. Source position is assumed precise and target position is assumed uncertain. If the given source position was already associated with another target position, then the old target position is discarded.
      Performance note: current implementation is efficient for builders created for a grid but inefficient for builders created for randomly distributed points. In the latter case, the setControlPoints(Map) method is a more efficient alternative.
      Parameters:
      source - the source coordinates. If this builder has been created with the LinearTransformBuilder(int...) constructor, then for every index i the source[i] value shall be in the [0 … gridSize[i]-1] range inclusive. If this builder has been created with the LinearTransformBuilder() constructor, then no constraint apply.
      target - the target coordinates, assumed uncertain.
      Throws:
      IllegalStateException - if create(…) has already been invoked.
      IllegalArgumentException - if this builder has been created for a grid but some source coordinates are out of index range, or if target contains NaN of infinite numbers.
      org.opengis.geometry.MismatchedDimensionException - if the source or target position does not have the expected number of dimensions.
      Since:
      0.8
    • getControlPoint

      public double[] getControlPoint(int[] source)
      Returns a single target coordinate for the given source coordinate, or null if none. This method can be used for retrieving points set by previous calls to setControlPoint(int[], double[]) or setControlPoints(Map).

      If linearizer() returns a non-empty value, then the returned values are projected using that linearizer. This may happen only if this method is invoked after create(…).

      Performance note: current implementation is efficient for builders created for a grid but inefficient for builders created for randomly distributed points.
      Parameters:
      source - the source coordinates. If this builder has been created with the LinearTransformBuilder(int...) constructor, then for every index i the source[i] value shall be in the [0 … gridSize[i]-1] range inclusive. If this builder has been created with the LinearTransformBuilder() constructor, then no constraint apply.
      Returns:
      the target coordinates associated to the given source, or null if none.
      Throws:
      IllegalArgumentException - if this builder has been created for a grid but some source coordinates are out of index range.
      org.opengis.geometry.MismatchedDimensionException - if the source position does not have the expected number of dimensions.
      Since:
      0.8
    • setControlPoints

      final void setControlPoints(Vector[] coordinates)
      Sets all control points. This method can be invoked only for points on a grid. The length of given vectors must be equal to the total number of cells in the grid. The first vector provides the x coordinates; the second vector provides the y coordinates, etc.. Coordinates are stored in row-major order (column index varies faster, followed by row index).
      Parameters:
      coordinates - coordinates in each target dimensions, stored in row-major order.
      Throws:
      IllegalStateException - if create(…) has already been invoked.
    • getControlRow

      final void getControlRow(int[] source, double[] target)
      More straightforward version of getControlPoint(int[]) for the case where this LinearTransformBuilder is known to have been built for grid source coordinates. This method is for LocalizationGridBuilder.create(MathTransformFactory) internal usage.
      Parameters:
      source - the source coordinates.
      target - where to store target coordinates for a full row.
    • getTransect

      final Vector getTransect(int dimension, int[] start, int direction)
      Returns the coordinates of a single row or column in the given dimension. This method can be invoked only when this LinearTransformBuilder is known to have been built for grid source coordinates.
      Note: while this method is primarily for row and columns, it can be generalized to more dimensions.
      The returned vector is a view; changes in the returned vector will be reflected in this builder.
      Parameters:
      dimension - the dimension of source point for which to get coordinate values.
      start - index of the first coordinate value to get.
      direction - 0 for getting a row, 1 for getting a column.
      Returns:
      coordinate values for specified row or column in the given dimension.
    • resolveWraparoundAxis

      final NumberRange<Double> resolveWraparoundAxis(int dimension, int direction, double period)
      Tries to remove discontinuities in coordinates values caused by anti-meridian crossing. This is the implementation of LocalizationGridBuilder.resolveWraparoundAxis(int, int, double) public method. See that method for javadoc.
      Parameters:
      dimension - the dimension to process, from 0 inclusive to getTargetDimensions() exclusive. This is 0 for longitude dimension in a (longitudes, latitudes) grid.
      direction - the direction to walk through: 0 for columns or 1 for rows (higher dimensions are also possible). Value can be from 0 inclusive to getSourceDimensions() exclusive. The recommended direction is the direction of most stable values, typically 1 (rows) for longitudes.
      period - that wraparound range (typically 360° for longitudes). Must be strictly positive.
      Returns:
      the range of coordinate values in the specified dimension after correction for wraparound values.
      Throws:
      IllegalStateException - if create(…) has already been invoked.
    • sources

      final Vector[] sources()
      Returns the vector of source coordinates. It is caller responsibility to ensure that this builder is not backed by a grid.
    • addLinearizers

      public void addLinearizers(Map<String,org.opengis.referencing.operation.MathTransform> projections, int... projToGrid)
      Adds transforms to potentially apply on target control points before to compute the linear transform. This method can be invoked when the source to target transform would possibly be more linear if target was another space than the current one. If linearizers have been specified, then the create(MathTransformFactory) method will try to apply each transform on target coordinates and check which one get the best correlation coefficients.

      Exactly one of the specified transforms will be selected. If applying no transform is an acceptable solution, then an identity transform should be included in the given projections map. The transform selected by LinearTransformBuilder will be given by linearizer().

      Linearizers are specified as a collection of MathTransforms from current target coordinates to some other spaces where sources to new targets transforms may be more linear. Keys in the map are arbitrary identifiers. Values in the map should be non-linear transforms; LinearTransforms (other than identity) should be avoided because they will consume processing power for no correlation improvement.

      Error handling

      If a TransformException occurred or if some transform results were NaN or infinite, then the MathTransform that failed will be ignored. If all transforms fail, then a FactoryException will be thrown by the create(…) method.

      Dimensions mapping

      The projToGrid argument maps projections dimensions to target dimensions of this builder. For example if projToGrid array is {2,1}, then coordinate values in target dimensions 2 and 1 of this grid will be used as source coordinates in dimensions 0 and 1 respectively for all given projections. Likewise, the projection results in dimensions 0 and 1 of all projections will be stored in target dimensions 2 and 1 respectively of this grid.

      The projToGrid argument can be omitted or null, in which case {0, 1, 2 … getTargetDimensions() - 1} is assumed. All given projections shall have a number of source and target dimensions equals to the length of the projToGrid array. It is possible to invoke this method many times with different projToGrid argument values.

      Parameters:
      projections - projections from current target coordinates to other spaces which may result in more linear transforms.
      projToGrid - the target dimensions to project, or null or omitted for projecting all target dimensions in same order.
      Throws:
      IllegalStateException - if create(…) has already been invoked.
      org.opengis.geometry.MismatchedDimensionException - if a projection does not have the expected number of dimensions.
      Since:
      1.0
      See Also:
    • addLinearizers

      final void addLinearizers(Map<String,org.opengis.referencing.operation.MathTransform> projections, boolean compensate, int[] projToGrid)
      Implementation of addLinearizers(Map, int...) with a flag telling whether the inverse of selected projection shall be concatenated to the final transform. This method is non-public because the reverseAfterLinearization flag has no purpose for this LinearTransformBuilder class; it is useful only for LocalizationGridBuilder.
      See Also:
    • setLinearizers

      final void setLinearizers(LinearTransformBuilder other)
      Sets the linearizers to a copy of those of the given builder. This is used by copy constructors.
      See Also:
    • create

      public LinearTransform create(org.opengis.referencing.operation.MathTransformFactory factory) throws org.opengis.util.FactoryException
      Creates a linear transform approximation from the source positions to the target positions. This method assumes that source positions are precise and that all uncertainties are in target positions. If linearizers have been specified, then this method will project all target coordinates using one of those linearizers in order to get a more linear transform. If such projection is applied, then linearizer() will return a non-empty value after this method call.

      If this method is invoked more than once, the previously created transform instance is returned.

      Specified by:
      create in class TransformBuilder
      Parameters:
      factory - the factory to use for creating the transform, or null for the default factory. The MathTransformFactory.createAffineTransform(Matrix) method of that factory shall return LinearTransform instances.
      Returns:
      the fitted linear transform.
      Throws:
      org.opengis.util.FactoryException - if the transform cannot be created, for example because the source or target points have not be specified.
      Since:
      0.8
    • fit

      private MatrixSIS fit() throws org.opengis.util.FactoryException
      Computes the matrix of the linear approximation. This is the implementation of create(MathTransformFactory) without the step creating the LinearTransform from a matrix. The correlations field is set as a side effect of this method call.

      In current implementation, the transform represented by the returned matrix is always affine (i.e. the last row is fixed to [0 0 … 0 1]). If this is no longer the case in a future version, some codes may not work anymore. Search for isAffine() statements for locating codes that depend on affine transform assumption.

      Throws:
      org.opengis.util.FactoryException
    • vector

      private Vector vector(double[] data)
      Wraps the given array in a vector of length numPoints. This method should be invoked only when this builder has been created by LinearTransformBuilder(). This can be identified by sources != null or gridSize == null.
    • rms

      private static double rms(double[] correlations, double sqrtCorrLength)
      Returns a global estimation of correlation by computing the root mean square of values.
    • linearizer

      public Optional<Map.Entry<String,org.opengis.referencing.operation.MathTransform>> linearizer()
      If target coordinates have been projected to another space, returns that projection. This method returns a non-empty value if addLinearizers(Map, int...) has been invoked with a non-empty map, followed by a create(MathTransformFactory) call. In such case, LinearTransformBuilder selects a linearizer identified by the returned key - value entry. The entry key is one of the keys of the maps given to addLinearizers(…). The entry value is the associated MathTransform, possibly modified as described in the axis order section below.

      The envelope returned by getTargetEnvelope() and all control points returned by getControlPoint(int[]) are projected by the selected transform. Consequently, if the target coordinates of original control points are desired, then the transform returned by create(…) needs to be concatenated with the inverse of the transform returned by this linearizer() method.

      Axis order

      The source coordinates expected by the returned transform are the control points target coordinates. The returned transform will contain an operation step performing axis filtering and swapping implied by the projToGrid argument that was given to the addLinearizers(…, projToGrid)} method. Consequently, if the projToGrid argument was not an arithmetic progression, then the transform returned by this method will not be one of the instances given to addLinearizers(…).
      Returns:
      the projection applied on target coordinates before to compute a linear transform.
      Since:
      1.1
    • appliedLinearizer

      final ProjectedTransformTry appliedLinearizer()
      Returns linearizer which has been applied, or null if none.
    • correlation

      public double[] correlation()
      Returns the Pearson correlation coefficients of the transform created by create(…). The closer those coefficients are to +1 or -1, the better the fit. This method returns null if create(…) has not yet been invoked. If non-null, the array length is equal to the number of target dimensions.
      Returns:
      estimation of Pearson correlation coefficients for each target dimension, or null if create(…) has not been invoked yet.
    • transform

      final LinearTransform transform()
      Returns the transform computed by create(MathTransformFactory), of null if that method has not yet been invoked.
    • toString

      public String toString()
      Returns a string representation of this builder for debugging purpose. Current implementation shows the following information:
      • Number of points.
      • Linearizers and their correlation coefficients (if available).
      • The linear transform (if already computed).
      The string representation may change in any future version.
      Overrides:
      toString in class Object
      Returns:
      a string representation of this builder.
    • appendTo

      final String appendTo(StringBuilder buffer, Class<?> caller, Locale locale, short resultKey) throws IOException
      Appends a string representation of this builder into the given buffer.
      Parameters:
      buffer - where to append the string representation.
      caller - the class name to report.
      locale - the locale for formatting messages and some numbers, or null for the default.
      resultKey - either Vocabulary.Keys.Result or Vocabulary.Keys.LinearTransformation.
      Returns:
      the line separator, for convenience of callers who wants to append more content.
      Throws:
      IOException - should never happen because we write in a StringBuilder.