Class RenderingData

java.lang.Object
org.apache.sis.internal.map.coverage.RenderingData
All Implemented Interfaces:
Cloneable

public class RenderingData extends Object implements Cloneable
The RenderedImage to draw in a PlanarCanvas together with transforms from pixel coordinates to display coordinates. This is a helper class for implementations of stateful renderer. All grid geometries and transforms managed by this class are two-dimensional. If the source data have more dimensions, a two-dimensional slice will be taken.

Note on Java2D optimizations

Graphics2D.drawRenderedImage(RenderedImage, AffineTransform) implementation has the following optimizations: Consequently, our strategy is to prepare a resampled image for the whole data when the zoom level changed and rely on tiling for reducing actual computations to required tiles. Since pan gestures are expressed in pixel coordinates, the translation terms in resampledToDisplay transform should stay integers.

Current version of this class does not perform a special case for BufferedImage. It may not be desirable because interpolations would not be applied in the same way, except when SIS ImageProcessor would have interpolated RGB color values anyway like Java2D. We wait to see if this class works well in the general case before doing special cases.

Since:
1.1
Version:
1.3
  • Field Details

  • Constructor Details

    • RenderingData

      public RenderingData(ErrorHandler errorHandler)
      Creates a new instance initialized to no image.
      Parameters:
      errorHandler - where to report errors during tile computations.
  • Method Details

    • clear

      public final void clear()
      Clears this renderer. This method should be invoked when the source of data (resource or coverage) changed. The displayToObjective transform will be recomputed from scratch when first needed.
    • clearCRS

      private void clearCRS()
      Clears the cache of transforms that depend on the CRS.
    • validateCRS

      public final boolean validateCRS(org.opengis.referencing.crs.CoordinateReferenceSystem objectiveCRS)
      Verifies if this RenderingData contains an image for the given objective CRS. If this is not the case, the cached resampled images will need to be discarded.
      Parameters:
      objectiveCRS - the coordinate reference system to use for rendering.
      Returns:
      whether the data are valid for the given objective CRS.
    • setImageSpace

      public final void setImageSpace(GridGeometry domain, List<SampleDimension> ranges, int[] xyDims)
      Sets the input space (domain) and output space (ranges) of the image to be rendered. Those values can be initially provided by GridCoverageResource and replaced later by the actual GridCoverage values after coverage loading is completed. It is caller's responsibility to reduce n-dimensional domain to two dimensions.
      Parameters:
      domain - the two-dimensional grid geometry, or null if there is no data.
      ranges - descriptions of bands, or null if there is no data.
      xyDims - the dimensions to select in the grid coverage for producing an image. This is an array of length 2 almost always equal to {0,1}.
    • ensureCoverageLoaded

      public final GridCoverage ensureCoverageLoaded(LinearTransform objectiveToDisplay, org.opengis.geometry.DirectPosition objectivePOI) throws org.opengis.referencing.operation.TransformException, DataStoreException
      Loads a new grid coverage if data is null or if the pyramid level changed. It is caller's responsibility to ensure that coverageLoader has a non-null value and is using the right resource before to invoke this method.

      Caller should invoke ensureImageLoaded(GridCoverage, GridExtent, boolean) after this method (this is not done automatically).

      Parameters:
      objectiveToDisplay - transform used for rendering the coverage on screen.
      objectivePOI - point where to compute resolution, in coordinates of objective CRS.
      Returns:
      the loaded grid coverage, or null if no loading has been done (which means that the coverage is unchanged, not that it does not exist).
      Throws:
      org.opengis.referencing.operation.TransformException - if an error occurred while computing resolution from given transforms.
      DataStoreException - if an error occurred while loading the coverage.
      See Also:
    • ensureImageLoaded

      public final boolean ensureImageLoaded(GridCoverage coverage, GridExtent sliceExtent, boolean force) throws org.opengis.util.FactoryException, org.opengis.referencing.operation.TransformException
      Fetches the rendered image if data is null or is for a different slice. This method needs to be invoked at least once after setImageSpace(GridGeometry, List, int[]). The coverage given in argument should be the value returned by a previous call to ensureCoverageLoaded(LinearTransform, DirectPosition), except that it shall not be null.
      Parameters:
      coverage - the coverage from which to read data. Shall not be null.
      sliceExtent - a subspace of the grid coverage extent where all dimensions except two have a size of 1 cell. May be null if this grid coverage has only two dimensions with a size greater than 1 cell.
      force - whether to force data loading. Should be true if coverage changed since last call.
      Returns:
      whether the changed.
      Throws:
      org.opengis.util.FactoryException - if the CRS changed but the transform from old to new CRS cannot be determined.
      org.opengis.referencing.operation.TransformException - if an error occurred while transforming coordinates from old to new CRS.
    • concatenate

      private static org.opengis.referencing.operation.MathTransform concatenate(org.opengis.referencing.datum.PixelInCell anchor, GridGeometry toCRS, GridGeometry toGrid, org.opengis.referencing.operation.MathTransform changeOfCRS) throws org.opengis.referencing.operation.TransformException
      Computes the transform that represent a change of "data grid to objective" transform
      Parameters:
      anchor - the cell part to map (center or corner).
      toCRS - the grid geometry for which to use the "grid to CRS" transform.
      toGrid - the grid geometry for which to use the "CRS to grid" transform.
      changeOfCRS - transform from CRS of toCRS to CRS of toGrid.
      Throws:
      org.opengis.referencing.operation.TransformException
    • getSourceImage

      public final RenderedImage getSourceImage()
      Returns the image which will be used as the source for rendering operations.
      Returns:
      the image loaded be ensureImageLoaded(GridCoverage, GridExtent, boolean).
    • getSourceMedian

      private org.opengis.geometry.DirectPosition getSourceMedian()
      Returns the position at the center of source data, or null if none. The coordinates are expressed in the CRS of the source coverage.
    • statistics

      protected final Map<String,Object> statistics() throws DataStoreException
      Returns statistics on the source image (computed when first requested, then cached). There is one Statistics instance per band. This is an information for dynamic stretching of image color ramp. Such recoloring operation should use statistics on the source image instead of statistics on the shown image in order to have stable colors during pans or zooms.

      The returned map is suitable for use with ImageProcessor.stretchColorRamp(RenderedImage, Map). The map content is:

      • "statistics": the statistics as a Statistics[] array.
      • "sampleDimensions": band descriptions as a List<SampleDimension>.
      This operation may be costly since it causes the loading of full image. If coverageLoader is non-null, statistics will be computed on the image with coarsest resolution.
      Returns:
      statistics on sample values for each band, in a modifiable map.
      Throws:
      DataStoreException - if an error occurred while reading the image at coarsest resolution.
    • setObjectiveCRS

      public final void setObjectiveCRS(org.opengis.referencing.crs.CoordinateReferenceSystem objectiveCRS) throws org.opengis.referencing.operation.TransformException
      Sets the coordinate reference system of the display. This method does nothing if the CRS was already set. It does not verify if CRS is the same, it is caller responsibility to clear changeOfCRS before to invoke this method for forcing a change of CRS.

      This method updates the following fields only:

      Parameters:
      objectiveCRS - value of Canvas.getObjectiveCRS().
      Throws:
      org.opengis.referencing.operation.TransformException - if an error occurred while transforming coordinates from grid to new CRS.
    • resampleAndConvert

      public final RenderedImage resampleAndConvert(RenderedImage recoloredImage, LinearTransform objectiveToDisplay, org.opengis.geometry.DirectPosition objectivePOI) throws org.opengis.referencing.operation.TransformException
      Creates the resampled image, then optionally applies an index color model. This method will compute the MathTransform steps from image coordinate system to display coordinate system if those steps have not already been computed.
      Parameters:
      recoloredImage - data or a derived (typically recolored) image.
      objectiveToDisplay - value of Canvas.getObjectiveToDisplay().
      objectivePOI - value of Canvas.getPointOfInterest(boolean) in objective CRS.
      Returns:
      image with operation applied and color ramp stretched.
      Throws:
      org.opengis.referencing.operation.TransformException - if an error occurred in the use of "grid to CRS" transforms.
    • applyWraparound

      private static org.opengis.referencing.operation.MathTransform applyWraparound(org.opengis.referencing.operation.MathTransform transform, org.opengis.geometry.DirectPosition sourceMedian, org.opengis.geometry.DirectPosition targetMedian, org.opengis.referencing.crs.CoordinateReferenceSystem targetCRS) throws org.opengis.referencing.operation.TransformException
      Conversion or transformation from objective CRS to data CRS. This transform will include WraparoundTransform steps if needed.
      Parameters:
      transform - the transform to concatenate with a "wraparound" operation.
      sourceMedian - point of interest in the source CRS of given transform.
      targetMedian - point of interest after wraparound.
      targetCRS - the target CRS of the given transform.
      Throws:
      org.opengis.referencing.operation.TransformException
    • isWraparoundNeeded

      private static boolean isWraparoundNeeded(Rectangle bounds, org.opengis.referencing.operation.MathTransform reference, org.opengis.referencing.operation.MathTransform nowrap) throws org.opengis.referencing.operation.TransformException
      Tests whether wraparound step seems necessary. This method transforms all corners and all centers of the given rectangle using the two specified transform. If the results differ by one pixel or more, the wraparound step is considered necessary.
      Parameters:
      bounds - rectangular coordinates of the display device, in pixels.
      reference - transform from display coordinates to dataGeometry cell coordinates.
      nowrap - same as reference but with a wraparound step. Used as a reference.
      Returns:
      true if at least one coordinate is distant from the reference coordinate by at least one pixel.
      Throws:
      org.opengis.referencing.operation.TransformException
      See Also:
    • prefetch

      public final RenderedImage prefetch(RenderedImage resampledImage, AffineTransform resampledToDisplay, Envelope2D displayBounds)
      Computes immediately, possibly using many threads, the tiles that are going to be displayed. The returned instance should be used only for current rendering event; it should not be cached.
      Parameters:
      resampledImage - the image computed by resampleAndConvert(…).
      resampledToDisplay - the transform computed by getTransform(LinearTransform).
      displayBounds - size and location of the display device (plus margin), in pixel units.
      Returns:
      a temporary image with tiles intersecting the display region already computed.
    • getTransform

      public final AffineTransform getTransform(LinearTransform objectiveToDisplay)
      Gets the transform to use for painting the resampled image. If the image to draw is an instance of BufferedImage, then it is okay to have any transform. However for other kinds of image, it is important that the transform has scale factors of 1 and integer translations because Java2D has an optimization which avoid to copy the whole data only for that case.
      Parameters:
      objectiveToDisplay - the transform from objective CRS to canvas coordinates.
      Returns:
      transform from resampled image to canvas (display) coordinates.
    • getDataPixelSize

      public final float getDataPixelSize(org.opengis.geometry.DirectPosition objectivePOI)
      Returns an estimation of the size of data pixels, in objective CRS.
      Parameters:
      objectivePOI - point of interest in objective CRS.
      Returns:
      an estimation of the source pixel size at the given location.
    • getDataToObjective

      public final org.opengis.referencing.operation.MathTransform getDataToObjective(org.opengis.referencing.datum.PixelInCell anchor)
      Returns the conversion from data pixel coordinates to objective CRS.
      Parameters:
      anchor - whether the conversion should start from pixel corner or pixel center.
      Returns:
      conversion from data pixel coordinates to objective CRS.
    • objectiveToData

      public final Rectangle objectiveToData(Rectangle2D bounds) throws org.opengis.referencing.operation.TransformException
      Converts the given bounds from objective coordinates to pixel coordinates in the source coverage.
      Parameters:
      bounds - objective coordinates.
      Returns:
      data coverage cell coordinates (in pixels), or null if unknown.
      Throws:
      org.opengis.referencing.operation.TransformException - if the bounds cannot be transformed.
    • hasChanged

      public final boolean hasChanged(RenderingData previous)
      Returns whether dataGeometry or objectiveToCenter changed since a previous rendering. This is used for information purposes only.
      Parameters:
      previous - previous instance of RenderingData.
      Returns:
      whether this RenderingData does a different rendering than previous RenderingData.
    • recoverableException

      private static void recoverableException(Exception e)
      Invoked when an exception occurred while computing a transform but the painting process can continue. This method pretends that the warning come from PlanarCanvas class since it is the public API.
    • clone

      public RenderingData clone()
      Creates new rendering data initialized to a copy of this instance.
      Overrides:
      clone in class Object
    • toString

      public String toString()
      Returns a string representation for debugging purposes. The string content may change in any future version.
      Overrides:
      toString in class Object