When allowing for variable size RasterDataNode
s within a Product
instance, a number of existing API properties and methods are misleading, confusing and as such often wrongly used. They must be identified, revised, and possibly reinterpreted or even removed with the aim to create a clean and consistent data model API alowing for both single-size and multi-size products. Reinterpretation may be a simple property or method renaming, but must always include revision of the API documentation and all usages in code.
See also:
The Product properties to be carefully analysed are (usages include snap-engine, snap-desktop, s1tbx, s2tbx, s3tbx):
sceneRasterSize
: Common size for all RasterDataNode
s. Is always present. Defines the model coordinate system for data in satellite projection which is used by all vector data. Defines the image coordinate system for a pin's and GCP's pixelPos
attribute. 28 getter usages (no setter available).sceneRaster
Width
and sceneRaster
Height
: See sceneRasterSize
. 846 getter usages (no setter available).geoCoding
: Common geo-coding for all RasterDataNode
s. Corresponds to the scene raster size and therefore implies it. Provides the transformation from scene raster pixel positions to geographical positions. An overall scene raster size and geo-coding is needed for showing the footprint representation on the world map. 426 getter usages, 222 setter usages.preferredTileSize
: A tile size that may be used when any multi-level images are created for an associated RasterDataNode
(TiePointGrid
, Band
, VirtualBand
, Mask
). The preferred tile size relates more or less to the scene raster size (more or less, because it is currently used for the lower resolution levels of image pyramids). 46 getter usages, 41 setter usages.numResolutionsMax
: The maximum number of resolution levels for multi-level images of all raster data nodes.Taking the large number of code usages into account, it becomes obvious that these properties cannot be simply removed when switching to multi-size products. So they will have to be reinterpreted to make their use valid in the majority of cases. Anyway, all the usages in the code base have to be visited and checked for validity in the light of multi-size products.
The following RasterDataNode
properties and methods may require reinterpretation in the light of multi-size products:
rasterSize
: Refers to the actual size of the stored data hold by a raster data node. It usually equals the sceneRasterSize
with the exception of TiePointGrid
s where
it is usually a fraction of the sceneRasterSize
. 43 getter usages (no setter available)rasterWidth/Height
: See rasterSize
. 218 getter usages (no setter available)get/setRasterData
: Gets the actually stored raster data corresponing to rasterSize
. 58 getter usages, 51 setter usages.sceneRasterSize
: Refers to size of the raster's multi-level source image which may either exist or not-yet-exist. Usually the same as rasterSize with the exception of TiePointGrid
s where it is the same as Product.sceneRasterSize
. 4 getter usages (no setter available)sceneRasterWidth/Height
: See sceneRasterSize
. 187 getter usages (no setter available)getSceneRasterData
: Gets the raster data for the scene corresponing to sceneRsterSize
. 2(?) usages.geoCoding
: The raster data node's geo-coding. If it is not explicitely set, it is the same as Product
.geoCoding
. 105 getter usages, 48 setter usages.The following ImageManager
methods must be replaced, moved or otherwise refactored-out in the light of multi-size products:
getImageToModelTransform(GeoCoding)
: Calls GeoCoding.getImageToMapTransform
to check if it is affine, if so, returns it, otherwise returns identity (1). 22 usagesgetModelCrs(GeoCoding)
: Calls GeoCoding.getImageToMapTransform
to check if it is affine, if so, returns GeoCoding.mapCrs
, otherwise GeoCoding.imageCrs
. 22 usages
getMultiLevelModel(RasterDataNode)
: Used to derive a multi-level image model from a raster data node's source image, otherwise calls createMultiLevelModel
.(2) 26 usagescreateMultiLevelModel(ProductNode)
: Used to create a default multi-level image model. Calls getImageToModelTransform
, uses Product.numResolutionsMax
.(2) 9 usagesgetPreferredTileSize(Product)
Gets the preferred tile size of a product or computes a new one. 16 usages(1) Returning the identity transformation by default is probably wrong in many cases, because then images of any size would return the same transformation into a common model CRS!
(2) If (1) holds, the returned multi-level models are also wrong!
getImageToMapTransform
()
: Finds a transformation between the GeoCoding.imageCrs
and mapCrs
. 15 usages.pixelPos
: An attribute of the accociated SimpleFeatureType
. Stores the scene raster pixel coordinate. Used to store original pixel positions at which users placed a pin or GCP. For all other placemarks than GCPs the geoPos
attribute is updated from pixelPos
changes.The following is a proposal for a reinterpretation of Product properties and methods and a description of new ones:
AffineTransformation
from image pixel coordinates to model coordinatesProduct.getModelCrs()
. Either the model CRSProduct.setModelCrs(crs)
, orIllegalStateException
is thrownProduct.getSceneRasterSize()
. Note that Pin
s and GCP
s have a pixelPos
attribute that refers to the reference raster's grid. Also, TiePointGrid
s interpolate from their local raster data grid into the reference raster's grid. Either the scene raster sizeProduct.setSceneRasterSize(size)
, orIllegalStateException
is thrownProduct.getSceneImageToModelTransform()
. Either the i2m-transformProduct.setScene
Image
ToModelTransform(i2mT)
, orIllegalStateException
is thrownProduct.getSceneGeoCoding()
providing the transformation from the scene raster coordinates to geographical coordinates. Therefore, a reference geo-coding implies a valid scene raster size. Either the scene geo-codingProduct.setSceneGeoCoding(geoCoding)
, ornull
is returnedProduct.getPreferredTileSize()
. Either the preferred tile size Product.setPreferredTileSize(tw,th)
, or(512, 512)
is returned.(1) Vector data are represented by SimpleFeature
which can provide a CRS for their default geometry. Howver, in SNAP we use a common coordinate system for all vector data therefore a single model CRS is required per product. Pin
s and GCP
s also have a pixelPos
attribute. Its value must be given in reference raster coordinates.
(2) Obtaining the reference raster data node could be done as follows:
null
.(3) See implementation and review role of ImageManager.getModelCrs(GeoCoding)
method.
(4) See implementation and review role of ImageManager.getImageToModelTransform(GeoCoding)
method.
(5) A client may wish to force all images of all raster data nodes to have the same tile size regardless of their actual image size. This may or may not be useful for a particular product type instance. Also, it may make sense to force the tile cache to contain single size tiles for maximum memory reuse.
geoCoding
. Either the geo-coding isRasterDataNode.setGeoCoding(gc)
, orProduct.sceneGeoCoding
, but only if is has been explicitly set (1), ornull.
getImageToModelTransform()
that is used by it's source image or that will be used for any source image as long as it hasn't been created so far. Either the i2m-transform isRasterDataNode.setImageToModelTransform(i2m)
, orgeoCoding
and the parent product's Product.modelCrs
, or if this is not possible (2) IllegalStateException
is throwntileSize
that is used by it's source image or that will be used for any source image as long as it hasn't been created so far. Either the tile size isRasterDataNode.setTileSize(tw,th)
, orProduct.preferredTileSize
(1) Avoid infinite recursion, see reference raster data node
(2) The transformation from RasterDataNode.geoCoding.imageCrs
to the parent product's Product.modelCrs
must be defined and must be affine.
ImageManager.getModelCrs(gc)
Product.
addBand(name, ...)
and addMask(name, ...)
methods must throw an IllegalStateException
if no valid reference raster size is defined.RasterDataNode
and also Tile
(GPF); Product.addBand(name,...)
and addMask(name, ..)
methods. May may stay with scene, to minimze refactorings and maximize compatibility. Problematic are other uses of scene such as in ProductSceneView
. On the other hand, the Layer
s used in such a view all share the model CRS. We could argument, that whenever we say scene, we refer to model coordinates. RasterDataNode
currently has a rasterSize
property and also a sceneRasterSize
property which are the same in most cases, but usually different for a TiePointGrid
. Once sceneRasterSize
is reinterpreted in this new sense, then rasterSize
should refer to the actual size of the raster data in use. But since a TiePointGrid
automatically expand its data to the sceneRasterSize
, its actual raster size is the raster size. How can we avoid this ambiguity?TiePointGrid
. RasterDataNode.rasterWith/Height/Size
as well as RasterDataNode.
get/setRasterData
and RasterDataNode.
getSceneRasterData
usages. RasterDataNode.rasterWith/Height/Size
return the actual raster size with respect to a multi-size product, change context code accordingly (should only affect TiePointGrid
usages). RasterDataNode.sceneRasterWidth/Height/Size
usages by RasterDataNode.rasterWith/Height/Size
. RasterDataNode.sceneRasterWidth/Height/Size
properties. RasterDataNode.getSceneRasterData
usages by RasterDataNode.getRasterData
. RasterDataNode.sceneRasterData
method. pixelPos
attribute for Pins and GCPs? The product's model CRS is either the GeoCoding.mapCrs
or some image CRS referring to the reference raster size. Therefore there is always a linear transformation from the model CRS to the image CRS anyway.pixelPos
. If it is not too much work, remove the attribute completly, use the geometry
field instead as it seems the most generic and non-redundant information.Product.get/setModelCrs
methods. Implement getModelCrs
method according to point 3 aboveProduct.getSceneRasterSize
according to point 4 above Product.getSceneRasterWidth/Height
according to point 4 above (return zero instead of null).Product.getGeoCoding
into getSceneGeoCoding
. Implement method according to point 6 aboveImageManager.getModelCrs(gc)
by Product.getModelCrs() calls, remove ImageManager.getModelCrs
ImageManager.getImageToModelTransform(gc)
by ??? calls, remove ImageManager.getImageToModelTransform