Class RenderingData
java.lang.Object
org.apache.sis.internal.map.coverage.RenderingData
- All Implemented Interfaces:
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:
- If the image is an instance of
BufferedImage
, then theAffineTransform
can be anything. Java2D applies interpolations efficiently. - Otherwise if the
AffineTransform
scale factors are 1 and the translations are integers, then Java2D invokesRenderedImage.getTile(int, int)
. It makes possible for us to create a very large image covering the whole data but with tiles computed only when first requested. - Otherwise Java2D invokes
RenderedImage.getData(Rectangle)
, which is more costly. We try to avoid that situation.
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 Summary
FieldsModifier and TypeFieldDescriptionprivate static final int
The 2 value, for identifying code that assume two-dimensional objects.private org.opengis.referencing.operation.CoordinateOperation
private org.opengis.referencing.operation.MathTransform
Conversion fromdata
pixel coordinates to objective CRS.Loader for reading and caching coverages at various resolutions.private static final boolean
Whether to allow the creation ofIndexColorModel
.private int
The pyramid level of data loaded by the coverageLoader.private GridExtent
The slice extent which has been used for rendering the data.private RenderedImage
The data fetched fromGridCoverage.render(GridExtent)
forcurrentSlice
.private GridGeometry
Conversion fromdata
pixel coordinates to the coverage CRS, together with geospatial area.private List
<SampleDimension> Ranges of sample values in each band ofdata
.private AffineTransform
The inverse of the objective to display transform which was active at the time resampled images have been computed.private org.opengis.referencing.operation.MathTransform
Conversion from objective CRS todata
pixel coordinates.final ImageProcessor
The processor that we use for resampling image and recoloring the image.private Statistics[]
Statistics on pixel values of currentdata
, ornull
if not yet computed.private int[]
The dimensions to select in the grid coverage for producing an image. -
Constructor Summary
ConstructorsConstructorDescriptionRenderingData
(ErrorHandler errorHandler) Creates a new instance initialized to no image. -
Method Summary
Modifier and TypeMethodDescriptionprivate 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) Conversion or transformation from objective CRS to data CRS.final void
clear()
Clears this renderer.private void
clearCRS()
Clears the cache of transforms that depend on the CRS.clone()
Creates new rendering data initialized to a copy of this instance.private static org.opengis.referencing.operation.MathTransform
concatenate
(org.opengis.referencing.datum.PixelInCell anchor, GridGeometry toCRS, GridGeometry toGrid, org.opengis.referencing.operation.MathTransform changeOfCRS) Computes the transform that represent a change of "data grid to objective" transformfinal GridCoverage
ensureCoverageLoaded
(LinearTransform objectiveToDisplay, org.opengis.geometry.DirectPosition objectivePOI) Loads a new grid coverage if data is null or if the pyramid level changed.final boolean
ensureImageLoaded
(GridCoverage coverage, GridExtent sliceExtent, boolean force) Fetches the rendered image if data is null or is for a different slice.final float
getDataPixelSize
(org.opengis.geometry.DirectPosition objectivePOI) Returns an estimation of the size of data pixels, in objective CRS.final org.opengis.referencing.operation.MathTransform
getDataToObjective
(org.opengis.referencing.datum.PixelInCell anchor) Returns the conversion fromdata
pixel coordinates to objective CRS.final RenderedImage
Returns the image which will be used as the source for rendering operations.private org.opengis.geometry.DirectPosition
Returns the position at the center of source data, ornull
if none.final AffineTransform
getTransform
(LinearTransform objectiveToDisplay) Gets the transform to use for painting the resampled image.final boolean
hasChanged
(RenderingData previous) Returns whetherdataGeometry
orobjectiveToCenter
changed since a previous rendering.private static boolean
isWraparoundNeeded
(Rectangle bounds, org.opengis.referencing.operation.MathTransform reference, org.opengis.referencing.operation.MathTransform nowrap) Tests whether wraparound step seems necessary.final Rectangle
objectiveToData
(Rectangle2D bounds) Converts the given bounds from objective coordinates to pixel coordinates in the source coverage.final RenderedImage
prefetch
(RenderedImage resampledImage, AffineTransform resampledToDisplay, Envelope2D displayBounds) Computes immediately, possibly using many threads, the tiles that are going to be displayed.private static void
Invoked when an exception occurred while computing a transform but the painting process can continue.final RenderedImage
resampleAndConvert
(RenderedImage recoloredImage, LinearTransform objectiveToDisplay, org.opengis.geometry.DirectPosition objectivePOI) Creates the resampled image, then optionally applies an index color model.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.final void
setObjectiveCRS
(org.opengis.referencing.crs.CoordinateReferenceSystem objectiveCRS) Sets the coordinate reference system of the display.Returns statistics on the source image (computed when first requested, then cached).toString()
Returns a string representation for debugging purposes.final boolean
validateCRS
(org.opengis.referencing.crs.CoordinateReferenceSystem objectiveCRS) Verifies if thisRenderingData
contains an image for the given objective CRS.
-
Field Details
-
BIDIMENSIONAL
private static final int BIDIMENSIONALThe 2 value, for identifying code that assume two-dimensional objects.- See Also:
-
CREATE_INDEX_COLOR_MODEL
Whether to allow the creation ofIndexColorModel
. This flag may be temporarily set tofalse
for testing or debugging. Iffalse
, images may be only grayscale and may be much slower to render, but should still be visible.- See Also:
-
coverageLoader
Loader for reading and caching coverages at various resolutions. Required if no image has been explicitly assigned todata
. The same instance may be shared by manyRenderingData
objects. -
currentPyramidLevel
private int currentPyramidLevelThe pyramid level of data loaded by the coverageLoader. -
currentSlice
The slice extent which has been used for rendering the data. May benull
if the grid coverage has only two dimensions with a size greater than 1 cell. -
xyDimensions
private int[] xyDimensionsThe dimensions to select in the grid coverage for producing an image. This is an array of length 2 almost always equal to {0,1}. The values are inferred fromcurrentSlice
. -
data
The data fetched fromGridCoverage.render(GridExtent)
forcurrentSlice
. This rendered image may be tiled and fetching those tiles may require computations to be performed in background threads. Pixels in thisdata
image are mapped to pixels in the displayPlanarCanvas
by the following chain of operations:dataGeometry.getGridGeometry(CELL_CENTER)
changeOfCRS.getMathTransform()
Canvas.getObjectiveToDisplay()
null
.- See Also:
-
dataGeometry
Conversion fromdata
pixel coordinates to the coverage CRS, together with geospatial area. It contains theGridGeometry.getGridToCRS(PixelInCell)
value ofGridCoverage
reduced to two dimensions and with a translation added for taking in account the requestedsliceExtent
. The coverage CRS is initially the same as the objective CRS, but may become different later if user selects a different objective CRS.- See Also:
-
dataRanges
Ranges of sample values in each band ofdata
. This is used for determining on which sample values to apply colors when user asked to apply a color ramp. May benull
.- See Also:
-
changeOfCRS
private org.opengis.referencing.operation.CoordinateOperation changeOfCRSConversion or transformation from data CRS to objective CRS, ornull
if not yet computed. This is an identity operation if the user did not selected a different CRS after the coverage has been shown. -
cornerToObjective
private org.opengis.referencing.operation.MathTransform cornerToObjectiveConversion fromdata
pixel coordinates to objective CRS. This is value ofGridGeometry.getGridToCRS(PixelInCell)
invoked ondataGeometry
, concatenated withchangeOfCRS
and potentially completed by a wraparound operation. May benull
if not yet computed. -
objectiveToCenter
private org.opengis.referencing.operation.MathTransform objectiveToCenterConversion from objective CRS todata
pixel coordinates. This is the inverse ofchangeOfCRS
(potentially with a wraparound operation) concatenated with inverse ofGridGeometry.getGridToCRS(PixelInCell)
ondataGeometry
. May benull
if not yet computed. -
displayToObjective
The inverse of the objective to display transform which was active at the time resampled images have been computed. The concatenation of this transform with the actual "objective to display" transform at the time the rendered image is drawn should be a translation. May benull
if not yet computed.- See Also:
-
statistics
Statistics on pixel values of currentdata
, ornull
if not yet computed. This is the cached value ofstatistics()
.- See Also:
-
processor
The processor that we use for resampling image and recoloring the image.
-
-
Constructor Details
-
RenderingData
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. ThedisplayToObjective
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 thisRenderingData
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
Sets the input space (domain) and output space (ranges) of the image to be rendered. Those values can be initially provided byGridCoverageResource
and replaced later by the actualGridCoverage
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, ornull
if there is no data.ranges
- descriptions of bands, ornull
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 thatcoverageLoader
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 aftersetImageSpace(GridGeometry, List, int[])
. Thecoverage
given in argument should be the value returned by a previous call toensureCoverageLoaded(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 benull
if this grid coverage has only two dimensions with a size greater than 1 cell.force
- whether to force data loading. Should betrue
ifcoverage
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 oftoCRS
to CRS oftoGrid
.- Throws:
org.opengis.referencing.operation.TransformException
-
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, ornull
if none. The coordinates are expressed in the CRS of the source coverage. -
statistics
Returns statistics on the source image (computed when first requested, then cached). There is oneStatistics
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 aStatistics[]
array."sampleDimensions"
: band descriptions as aList<SampleDimension>
.
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 clearchangeOfCRS
before to invoke this method for forcing a change of CRS.This method updates the following fields only:
changeOfCRS
processor
positional accuracy hint
- Parameters:
objectiveCRS
- value ofCanvas.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 theMathTransform
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 ofCanvas.getObjectiveToDisplay()
.objectivePOI
- value ofCanvas.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 includeWraparoundTransform
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 todataGeometry
cell coordinates.nowrap
- same asreference
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 byresampleAndConvert(…)
.resampledToDisplay
- the transform computed bygetTransform(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
Gets the transform to use for painting the resampled image. If the image to draw is an instance ofBufferedImage
, 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 fromdata
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
Returns whetherdataGeometry
orobjectiveToCenter
changed since a previous rendering. This is used for information purposes only.- Parameters:
previous
- previous instance ofRenderingData
.- Returns:
- whether this
RenderingData
does a different rendering than previousRenderingData
.
-
recoverableException
Invoked when an exception occurred while computing a transform but the painting process can continue. This method pretends that the warning come fromPlanarCanvas
class since it is the public API. -
clone
Creates new rendering data initialized to a copy of this instance. -
toString
Returns a string representation for debugging purposes. The string content may change in any future version.
-