Class CoordinateOperationFinder

java.lang.Object
org.apache.sis.coverage.grid.CoordinateOperationFinder
All Implemented Interfaces:
Supplier<double[]>

final class CoordinateOperationFinder extends Object implements Supplier<double[]>
Finds a transform from grid cells in a source coverage to geospatial positions in the CRS of a target coverage. This class differs from CRS#findOperation(…) because of the gridded aspect of inputs. grid geometries give more information about how referencing is applied on datasets. With them, this class provides three additional benefits:
  • Detect dimensions where target coordinates are constrained to constant values because the grid size is only one cell in those dimensions. This is an important because it makes possible to find operations normally impossible: we can still produce an operation to a target CRS even if some dimensions have no corresponding source CRS.
  • Detect how to handle wraparound axes. For example if a raster spans 150° to 200° of longitude, this class understands that -170° of longitude should be translated to 190° for thar particular raster. This will work even if the minimum and maximum values declared in the longitude axis do not match that range.
  • Use the area of interest and grid resolution for refining the coordinate operation between two CRS.
Note: except for the gridToGrid() convenience method, this class does not provide the complete chain of operations from grid to grid. It provides only the operation from cell indices in source grid to coordinates in the CRS of destination grid. Callers must add the last step (conversion from target CRS to cell indices) themselves.
Since:
1.1
Version:
1.2
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private org.opengis.referencing.datum.PixelInCell
    Whether the operation is between cell centers or cell corners.
    private org.opengis.referencing.operation.CoordinateOperation
    The coordinate operation from source to target CRS, computed when first needed.
    private double[]
    The target coordinate values, computed only if needed.
    private org.opengis.referencing.operation.MathTransform
    Transform from the target CRS to the source grid, with WraparoundTransform applied if needed.
    private org.opengis.referencing.operation.MathTransform
    The changeOfCRS transform together with WraparoundTransform if needed.
    private org.opengis.referencing.operation.MathTransform
    Transform from “grid coordinates of the source” to “geospatial coordinates of the target”.
    private org.opengis.referencing.operation.MathTransform
    Inverse of changeOfCRS transform together with WraparoundTransform if needed.
    private boolean
    Whether WraparoundTransform has been applied on inverseChangeOfCRS.
    private boolean
    Whether to disable completely all wraparounds checks.
    private boolean
    Whether inverseChangeOfCRS needs to include a WraparoundTransform step.
    private boolean
    Whether the isWraparoundNeeded value has been determined.
    private boolean
    Whether the changeOfCRS operation has been determined.
    private final GridGeometry
    The grid geometry which is the source/target of the coordinate operation to find.
    private final GridGeometry
    The grid geometry which is the source/target of the coordinate operation to find.
  • Constructor Summary

    Constructors
    Constructor
    Description
    Creates a new finder initialized to PixelInCell.CELL_CORNER anchor.
  • Method Summary

    Modifier and Type
    Method
    Description
    private boolean
    applyWraparound(org.opengis.referencing.operation.MathTransform sourceCrsToGrid)
    Inserts WraparoundTransform steps into inverseChangeOfCRS transform if possible.
    private org.opengis.referencing.operation.CoordinateOperation
    Returns the coordinate operation from source CRS to target CRS.
    double[]
    get()
    Invoked when the target CRS has some dimensions that the source CRS does not have.
    (package private) final org.opengis.referencing.crs.CoordinateReferenceSystem
    Returns the target of the "corner to CRS" transform.
    (package private) final org.opengis.referencing.operation.MathTransform
    Computes the transform from “grid coordinates of the source” to “geospatial coordinates of the target”.
    (package private) final org.opengis.referencing.operation.MathTransform
    Computes the transform from “grid coordinates of the source” to “grid coordinates of the target”.
    (package private) final org.opengis.referencing.operation.MathTransform
    Computes the transform from “geospatial coordinates of the target” to “grid coordinates of the source”.
    private boolean
    isWraparoundNeeded(GridExtent extent, org.opengis.referencing.operation.MathTransform extentToCRS, org.opengis.referencing.operation.MathTransform crsToGridNoWrap, org.opengis.referencing.operation.MathTransform sourceCrsToGrid)
    Verifies whether wraparound is needed for a "CRS to grid" transform.
    private static org.opengis.geometry.DirectPosition
    median(GridGeometry grid, org.opengis.referencing.operation.MathTransform changeOfCRS)
    Returns the point of interest converted to the Coordinate Reference System.
    (package private) final void
    Disables completely all wraparounds operation.
    private static void
    Invoked when an ignorable exception occurred.
    (package private) final void
    Configures the accuracy hints on the given processor.
    (package private) final void
    setAnchor(org.opengis.referencing.datum.PixelInCell newValue)
    Sets whether operations will be between cell centers or cell corners.
    (package private) final void
    verifyPresenceOfCRS(boolean rs)
    Verifies whether the presence of a CRS considered mandatory, unless the CRS of opposite grid is also missing.

    Methods inherited from class java.lang.Object

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

    • anchor

      private org.opengis.referencing.datum.PixelInCell anchor
      Whether the operation is between cell centers or cell corners.
      See Also:
    • source

      private final GridGeometry source
      The grid geometry which is the source/target of the coordinate operation to find.
    • target

      private final GridGeometry target
      The grid geometry which is the source/target of the coordinate operation to find.
    • coordinates

      private double[] coordinates
      The target coordinate values, computed only if needed. This is computed by get(), which is itself invoked indirectly by CoordinateOperationFinder. The value is cached in case get() is invoked many times during the same finder execution.
      See Also:
    • changeOfCRS

      private org.opengis.referencing.operation.CoordinateOperation changeOfCRS
      The coordinate operation from source to target CRS, computed when first needed. May be null if there is no information about the source and target CRS. Note that identity operation is not equivalent to null because identity operation will still be checked for wraparound axes (because the CRS is known), while null operation will have no check.
      See Also:
    • knowChangeOfCRS

      private boolean knowChangeOfCRS
      Whether the changeOfCRS operation has been determined. Note that result of determining that operation may be null, which is why we need this flag.
    • forwardChangeOfCRS

      private org.opengis.referencing.operation.MathTransform forwardChangeOfCRS
      The changeOfCRS transform together with WraparoundTransform if needed. The wraparound is used for handling images crossing the anti-meridian.
      See Also:
    • inverseChangeOfCRS

      private org.opengis.referencing.operation.MathTransform inverseChangeOfCRS
      Inverse of changeOfCRS transform together with WraparoundTransform if needed. The wraparound is used for handling images crossing the anti-meridian.

      Contrarily to forwardChangeOfCRS, the process that determine this inverseChangeOfCRS transform should check if wraparound is really needed. This is because inverseChangeOfCRS will be used much more extensively (for every pixels) than other transforms.

      See Also:
    • gridToCRS

      private org.opengis.referencing.operation.MathTransform gridToCRS
      Transform from “grid coordinates of the source” to “geospatial coordinates of the target”. This is the concatenation of source "grid to CRS" with forwardChangeOfCRS, possibly with wraparound handling and cached for reuse by inverse():
      See Also:
    • crsToGrid

      private org.opengis.referencing.operation.MathTransform crsToGrid
      Transform from the target CRS to the source grid, with WraparoundTransform applied if needed. This is the concatenation of inverseChangeOfCRS with inverse of source "grid to CRS", possibly with wraparound handling:
      See Also:
    • isWraparoundNeedVerified

      private boolean isWraparoundNeedVerified
      Whether the isWraparoundNeeded value has been determined. This flag controls whether to perform a more extensive check of wraparound occurrence. This flag should be false the first time that inverse() is invoked and true the next time.
    • isWraparoundNeeded

      private boolean isWraparoundNeeded
      Whether inverseChangeOfCRS needs to include a WraparoundTransform step. We do this check only for inverseChangeOfCRS because it is the transform which will be executed for every pixels. By contrast, forwardChangeOfCRS will systematically contain a WraparoundTransform step because we use it only for transforming envelopes and for the test that determines the value of this isWraparoundNeeded flag.
    • isWraparoundApplied

      private boolean isWraparoundApplied
      Whether WraparoundTransform has been applied on inverseChangeOfCRS. This field complements isWraparoundNeeded because a delay may exist between the time we detected that wraparound is needed and the time we applied the necessary operation steps.

      Note that despite this field name, a true value does not imply that inverseChangeOfCRS and crsToGrid transforms really contain some WraparoundTransform steps. It only means that the WraparoundApplicator.forDomainOfUse(…) method has been invoked. That method may have decided to not insert any wraparound steps.

      See Also:
    • isWraparoundDisabled

      private boolean isWraparoundDisabled
      Whether to disable completely all wraparounds checks. If true, then calculation done in this class should be equivalent to following code: Tip: searching usage of this field should help to identify code doing wraparound handling.
      See Also:
  • Constructor Details

    • CoordinateOperationFinder

      CoordinateOperationFinder(GridGeometry source, GridGeometry target)
      Creates a new finder initialized to PixelInCell.CELL_CORNER anchor.
      Parameters:
      source - the grid geometry which is the source of the coordinate operation to find.
      target - the grid geometry which is the target of the coordinate operation to find.
  • Method Details

    • verifyPresenceOfCRS

      final void verifyPresenceOfCRS(boolean rs)
      Verifies whether the presence of a CRS considered mandatory, unless the CRS of opposite grid is also missing.
      Parameters:
      rs - true is source CRS is mandatory, false if target CRS is mandatory.
    • setAnchor

      final void setAnchor(org.opengis.referencing.datum.PixelInCell newValue)
      Sets whether operations will be between cell centers or cell corners. This method must be invoked before any other method in this class. The PixelInCell.CELL_CORNER value should be used first in order to cache values computed relative to pixel corners.
      Parameters:
      newValue - whether operations will be between cell centers or cell corners.
    • nowraparound

      final void nowraparound()
      Disables completely all wraparounds operation.
      See Also:
    • getTargetCRS

      final org.opengis.referencing.crs.CoordinateReferenceSystem getTargetCRS()
      Returns the target of the "corner to CRS" transform. May be null if the neither the source and target grid geometry define a CRS.
    • changeOfCRS

      private org.opengis.referencing.operation.CoordinateOperation changeOfCRS() throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Returns the coordinate operation from source CRS to target CRS. It may be the identity operation. We try to take envelopes in account because the operation choice may depend on the geographic area.
      Returns:
      operation from source CRS to target CRS, or null if a CRS is not specified.
      Throws:
      org.opengis.util.FactoryException - if no operation can be found between the source and target CRS.
      org.opengis.referencing.operation.TransformException - if some coordinates cannot be transformed to the specified target.
    • gridToGrid

      final org.opengis.referencing.operation.MathTransform gridToGrid() throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Computes the transform from “grid coordinates of the source” to “grid coordinates of the target”. This is a concatenation of gridToCRS() with target "CRS to grid" transform.
      Returns:
      operation from source grid indices to target grid indices.
      Throws:
      org.opengis.util.FactoryException - if no operation can be found between the source and target CRS.
      org.opengis.referencing.operation.TransformException - if some coordinates cannot be transformed to the specified target.
      IncompleteGridGeometryException - if required CRS or a "grid to CRS" information is missing.
    • gridToCRS

      final org.opengis.referencing.operation.MathTransform gridToCRS() throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Computes the transform from “grid coordinates of the source” to “geospatial coordinates of the target”. It may be the identity operation. We try to take envelopes in account because the operation choice may depend on the geographic area.

      The transform returned by this method applies wraparound checks systematically on every axes having wraparound range. This method does not verify whether those checks are needed (i.e. whether wraparound can possibly happen). This is okay because this transform is used only for transforming envelopes; it is not used for transforming pixel coordinates.

      Implementation note

      After invocation of this method, the following fields are valid:
      Returns:
      operation from source grid indices to target geospatial coordinates.
      Throws:
      org.opengis.util.FactoryException - if no operation can be found between the source and target CRS.
      org.opengis.referencing.operation.TransformException - if some coordinates cannot be transformed to the specified target.
      IncompleteGridGeometryException - if required CRS or a "grid to CRS" information is missing.
    • inverse

      final org.opengis.referencing.operation.MathTransform inverse() throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Computes the transform from “geospatial coordinates of the target” to “grid coordinates of the source”. This is similar to invoking MathTransform.inverse() on gridToCRS(), except in the way wraparounds are handled.
      Returns:
      operation from target geospatial coordinates to source grid indices.
      Throws:
      org.opengis.util.FactoryException - if no operation can be found between the source and target CRS.
      org.opengis.referencing.operation.TransformException - if some coordinates cannot be transformed.
    • isWraparoundNeeded

      private boolean isWraparoundNeeded(GridExtent extent, org.opengis.referencing.operation.MathTransform extentToCRS, org.opengis.referencing.operation.MathTransform crsToGridNoWrap, org.opengis.referencing.operation.MathTransform sourceCrsToGrid) throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Verifies whether wraparound is needed for a "CRS to grid" transform. This method converts coordinates of all corners of a grid (source or target) to the target CRS, then (potentially back) to the source grid. This method uses one transform applying wraparounds and another transform without wraparounds. By checking whether grid coordinates are equal with both transforms, we determine if wraparound is necessary or not.
      Parameters:
      extent - the grid extent which is providing all corners to project.
      extentToCRS - transform from extent to target CRS.
      crsToGridNoWrap - inverse of gridToCRS but without handling of wraparound axes.
      sourceCrsToGrid - if extent is target extent, shall be null. If extent is source extent, shall be the transform to concatenate with inverseChangeOfCRS for creating crsToGrid.
      Returns:
      whether wraparound transform seems needed.
      Throws:
      org.opengis.referencing.operation.TransformException - if an error occurred while transforming coordinates.
      org.opengis.util.FactoryException
    • applyWraparound

      private boolean applyWraparound(org.opengis.referencing.operation.MathTransform sourceCrsToGrid) throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Inserts WraparoundTransform steps into inverseChangeOfCRS transform if possible. IF this method returns true, then the inverseChangeOfCRS and crsToGrid fields have been updated to transforms applying wraparound.
      Parameters:
      sourceCrsToGrid - value of source.getGridToCRS(anchor).inverse().
      Returns:
      whether at least one wraparound step has been added.
      Throws:
      org.opengis.referencing.operation.TransformException - if some coordinates cannot be transformed.
      org.opengis.util.FactoryException
    • median

      private static org.opengis.geometry.DirectPosition median(GridGeometry grid, org.opengis.referencing.operation.MathTransform changeOfCRS) throws org.opengis.referencing.operation.TransformException
      Returns the point of interest converted to the Coordinate Reference System. If the grid does not define a point of interest or does not define a CRS, then this method returns null.
      Parameters:
      grid - the source or target grid providing the point of interest.
      changeOfCRS - transform from source CRS to target CRS, or null if none.
      Throws:
      org.opengis.referencing.operation.TransformException
    • get

      public double[] get()
      Invoked when the target CRS has some dimensions that the source CRS does not have. For example, this is invoked during the conversion from (x, y) coordinates to (x, y, t). If constant values can be given to the missing dimensions, than those values are returned. Otherwise this method returns null.

      The returned array has a length equals to the number of dimensions in the target CRS. Only coordinates in dimensions without source (t in above example) will be used. All other coordinate values will be ignored.

      Specified by:
      get in interface Supplier<double[]>
      See Also:
    • setAccuracyOf

      final void setAccuracyOf(ImageProcessor processor)
      Configures the accuracy hints on the given processor.

      Prerequisite

      This method assumes that gridToCRS() or inverse() has already been invoked before this method.
    • recoverableException

      private static void recoverableException(String caller, Exception e)
      Invoked when an ignorable exception occurred.
      Parameters:
      caller - the method where the exception occurred.
      e - the ignorable exception.