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 theAffineTransformcan be anything. Java2D applies interpolations efficiently. - Otherwise if the
AffineTransformscale 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 intThe 2 value, for identifying code that assume two-dimensional objects.private org.opengis.referencing.operation.CoordinateOperationprivate org.opengis.referencing.operation.MathTransformConversion fromdatapixel coordinates to objective CRS.Loader for reading and caching coverages at various resolutions.private static final booleanWhether to allow the creation ofIndexColorModel.private intThe pyramid level of data loaded by the coverageLoader.private GridExtentThe slice extent which has been used for rendering the data.private RenderedImageThe data fetched fromGridCoverage.render(GridExtent)forcurrentSlice.private GridGeometryConversion fromdatapixel coordinates to the coverage CRS, together with geospatial area.private List<SampleDimension>Ranges of sample values in each band ofdata.private AffineTransformThe inverse of the objective to display transform which was active at the time resampled images have been computed.private org.opengis.referencing.operation.MathTransformConversion from objective CRS todatapixel coordinates.final ImageProcessorThe processor that we use for resampling image and recoloring the image.private Statistics[]Statistics on pixel values of currentdata, ornullif 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.MathTransformapplyWraparound(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 voidclear()Clears this renderer.private voidclearCRS()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.MathTransformconcatenate(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 GridCoverageensureCoverageLoaded(LinearTransform objectiveToDisplay, org.opengis.geometry.DirectPosition objectivePOI) Loads a new grid coverage if data is null or if the pyramid level changed.final booleanensureImageLoaded(GridCoverage coverage, GridExtent sliceExtent, boolean force) Fetches the rendered image if data is null or is for a different slice.final floatgetDataPixelSize(org.opengis.geometry.DirectPosition objectivePOI) Returns an estimation of the size of data pixels, in objective CRS.final org.opengis.referencing.operation.MathTransformgetDataToObjective(org.opengis.referencing.datum.PixelInCell anchor) Returns the conversion fromdatapixel coordinates to objective CRS.final RenderedImageReturns the image which will be used as the source for rendering operations.private org.opengis.geometry.DirectPositionReturns the position at the center of source data, ornullif none.final AffineTransformgetTransform(LinearTransform objectiveToDisplay) Gets the transform to use for painting the resampled image.final booleanhasChanged(RenderingData previous) Returns whetherdataGeometryorobjectiveToCenterchanged since a previous rendering.private static booleanisWraparoundNeeded(Rectangle bounds, org.opengis.referencing.operation.MathTransform reference, org.opengis.referencing.operation.MathTransform nowrap) Tests whether wraparound step seems necessary.final RectangleobjectiveToData(Rectangle2D bounds) Converts the given bounds from objective coordinates to pixel coordinates in the source coverage.final RenderedImageprefetch(RenderedImage resampledImage, AffineTransform resampledToDisplay, Envelope2D displayBounds) Computes immediately, possibly using many threads, the tiles that are going to be displayed.private static voidInvoked when an exception occurred while computing a transform but the painting process can continue.final RenderedImageresampleAndConvert(RenderedImage recoloredImage, LinearTransform objectiveToDisplay, org.opengis.geometry.DirectPosition objectivePOI) Creates the resampled image, then optionally applies an index color model.final voidsetImageSpace(GridGeometry domain, List<SampleDimension> ranges, int[] xyDims) Sets the input space (domain) and output space (ranges) of the image to be rendered.final voidsetObjectiveCRS(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 booleanvalidateCRS(org.opengis.referencing.crs.CoordinateReferenceSystem objectiveCRS) Verifies if thisRenderingDatacontains 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 tofalsefor 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 manyRenderingDataobjects. -
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 benullif 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 thisdataimage are mapped to pixels in the displayPlanarCanvasby the following chain of operations:dataGeometry.getGridGeometry(CELL_CENTER)changeOfCRS.getMathTransform()Canvas.getObjectiveToDisplay()
null. -
dataGeometry
Conversion fromdatapixel coordinates to the coverage CRS, together with geospatial area. It contains theGridGeometry.getGridToCRS(PixelInCell)value ofGridCoveragereduced 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. -
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. -
changeOfCRS
private org.opengis.referencing.operation.CoordinateOperation changeOfCRSConversion or transformation from data CRS to objective CRS, ornullif 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 fromdatapixel coordinates to objective CRS. This is value ofGridGeometry.getGridToCRS(PixelInCell)invoked ondataGeometry, concatenated withchangeOfCRSand potentially completed by a wraparound operation. May benullif not yet computed. -
objectiveToCenter
private org.opengis.referencing.operation.MathTransform objectiveToCenterConversion from objective CRS todatapixel coordinates. This is the inverse ofchangeOfCRS(potentially with a wraparound operation) concatenated with inverse ofGridGeometry.getGridToCRS(PixelInCell)ondataGeometry. May benullif 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 benullif not yet computed.- See Also:
-
statistics
Statistics on pixel values of currentdata, ornullif 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. ThedisplayToObjectivetransform 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 thisRenderingDatacontains 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 byGridCoverageResourceand replaced later by the actualGridCoveragevalues 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, ornullif there is no data.ranges- descriptions of bands, ornullif 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 thatcoverageLoaderhas 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
nullif 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[]). Thecoveragegiven 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 benullif this grid coverage has only two dimensions with a size greater than 1 cell.force- whether to force data loading. Should betrueifcoveragechanged 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 oftoCRSto 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, ornullif 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 oneStatisticsinstance 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>.
coverageLoaderis 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 clearchangeOfCRSbefore to invoke this method for forcing a change of CRS.This method updates the following fields only:
changeOfCRSprocessorpositional 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 theMathTransformsteps from image coordinate system to display coordinate system if those steps have not already been computed.- Parameters:
recoloredImage-dataor 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 includeWraparoundTransformsteps 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 todataGeometrycell coordinates.nowrap- same asreferencebut with a wraparound step. Used as a reference.- Returns:
trueif 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 fromdatapixel 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
nullif unknown. - Throws:
org.opengis.referencing.operation.TransformException- if the bounds cannot be transformed.
-
hasChanged
Returns whetherdataGeometryorobjectiveToCenterchanged since a previous rendering. This is used for information purposes only.- Parameters:
previous- previous instance ofRenderingData.- Returns:
- whether this
RenderingDatadoes 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 fromPlanarCanvasclass 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.
-