Add QgsRasterDataProvider::transformCoordinates()

This is useful when client needs to find out image space coordinates of a point
in map layer coordinates or vice versa. For warped VRT rasters this can't be
simply done by using geotransform matrix because the transform may be more complex.

This may be also useful functionality for identify tool to show source raster
image coordinates.
This commit is contained in:
Martin Dobias 2020-05-15 23:09:40 +02:00 committed by Nyall Dawson
parent 6358baafcd
commit 68bbf46ebb
5 changed files with 75 additions and 0 deletions

View File

@ -495,6 +495,26 @@ Returns true if the extents reported by the data provider are not reliable
and it's possible that there is renderable content outside of these extents.
.. versionadded:: 3.10.0
%End
enum TransformType
{
TransformImageToLayer,
TransformLayerToImage,
};
virtual QgsPoint transformCoordinates( const QgsPoint &point, TransformType type );
%Docstring
Transforms coordinates between source image coordinate space [0..width]x[0..height] and
layer coordinate space (georeferenced coordinates). Often this transformation is a simple
2D affine transformation (offset and scaling), but rasters with different georeferencing
methods like GCPs (ground control points) or RPCs (rational polynomial coefficients) may
require a more complex transform.
If the transform fails (input coordinates are outside of the valid range or data provider
does not support this functionality), an empty point is returned.
.. versionadded:: 3.14
%End
signals:

View File

@ -457,6 +457,9 @@ QgsGdalProvider::~QgsGdalProvider()
{
QMutexLocker locker( sGdalProviderMutex() );
if ( mGdalTransformerArg )
GDALDestroyTransformer( mGdalTransformerArg );
int lightRefCounter = -- ( *mpLightRefCounter );
int refCounter = -- ( *mpRefCounter );
if ( refCounter == 0 )
@ -2686,6 +2689,8 @@ void QgsGdalProvider::initBaseDataset()
mGdalDataset = mGdalBaseDataset;
}
mGdalTransformerArg = GDALCreateGenImgProjTransformer( mGdalBaseDataset, nullptr, nullptr, nullptr, TRUE, 1.0, 0 );
if ( !hasGeoTransform )
{
// Initialize the affine transform matrix
@ -3156,6 +3161,20 @@ QString QgsGdalProvider::validatePyramidsConfigOptions( QgsRaster::RasterPyramid
return QString();
}
QgsPoint QgsGdalProvider::transformCoordinates( const QgsPoint &point, QgsRasterDataProvider::TransformType type )
{
if ( !mGdalTransformerArg )
return QgsPoint();
int success;
double x = point.x(), y = point.y(), z = point.is3D() ? point.z() : 0;
GDALUseTransformer( mGdalTransformerArg, type == TransformLayerToImage, 1, &x, &y, &z, &success );
if ( !success )
return QgsPoint();
return QgsPoint( x, y, z );
}
bool QgsGdalProvider::isEditable() const
{
return mUpdate;

View File

@ -203,6 +203,8 @@ class QgsGdalProvider final: public QgsRasterDataProvider, QgsGdalProviderBase
QString validatePyramidsConfigOptions( QgsRaster::RasterPyramidsFormat pyramidsFormat,
const QStringList &configOptions, const QString &fileFormat ) override;
QgsPoint transformCoordinates( const QgsPoint &point, TransformType type ) override;
private:
QgsGdalProvider( const QgsGdalProvider &other );
@ -338,6 +340,9 @@ class QgsGdalProvider final: public QgsRasterDataProvider, QgsGdalProviderBase
* Closes and reinits dataset
*/
void reloadProviderData() override;
//! Instance of GDAL transformer function used in transformCoordinates() for conversion between image and layer coordinates
void *mGdalTransformerArg = nullptr;
};
/**

View File

@ -512,6 +512,13 @@ bool QgsRasterDataProvider::ignoreExtents() const
return false;
}
QgsPoint QgsRasterDataProvider::transformCoordinates( const QgsPoint &point, QgsRasterDataProvider::TransformType type )
{
Q_UNUSED( point )
Q_UNUSED( type )
return QgsPoint();
}
bool QgsRasterDataProvider::userNoDataValuesContains( int bandNo, double value ) const
{
QgsRasterRangeList rangeList = mUserNoDataValue.value( bandNo - 1 );

View File

@ -557,6 +557,30 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
*/
virtual bool ignoreExtents() const;
/**
* Types of transformation in transformCoordinates() function.
* \since QGIS 3.14
*/
enum TransformType
{
TransformImageToLayer, //!< Transforms image coordinates to layer (georeferenced) coordinates
TransformLayerToImage, //!< Transforms layer (georeferenced) coordinates to image coordinates
};
/**
* Transforms coordinates between source image coordinate space [0..width]x[0..height] and
* layer coordinate space (georeferenced coordinates). Often this transformation is a simple
* 2D affine transformation (offset and scaling), but rasters with different georeferencing
* methods like GCPs (ground control points) or RPCs (rational polynomial coefficients) may
* require a more complex transform.
*
* If the transform fails (input coordinates are outside of the valid range or data provider
* does not support this functionality), an empty point is returned.
*
* \since QGIS 3.14
*/
virtual QgsPoint transformCoordinates( const QgsPoint &point, TransformType type );
signals:
/**