Skip to content

Commit 54e5119

Browse files
committedJul 19, 2018
More heavily optimised sample method for gdal provider
1 parent db8e536 commit 54e5119

File tree

5 files changed

+34
-54
lines changed

5 files changed

+34
-54
lines changed
 

‎python/core/auto_generated/raster/qgsrasterdataprovider.sip.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,8 @@ caching (WCS). If context params are not specified the highest
286286
resolution is used. capabilities() may be used to test if format
287287
is supported by provider.
288288

289-
A null QVariant will be returned if the point is outside data source extent.
289+
A null QVariant will be returned if the point is outside data source extent, or an invalid
290+
band number was specified.
290291

291292
.. seealso:: :py:func:`identify`
292293

‎src/core/raster/qgsrasterdataprovider.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
367367
* resolution is used. capabilities() may be used to test if format
368368
* is supported by provider.
369369
*
370-
* A null QVariant will be returned if the point is outside data source extent.
370+
* A null QVariant will be returned if the point is outside data source extent, or an invalid
371+
* band number was specified.
371372
*
372373
* \see identify(), which is much more flexible but considerably less efficient.
373374
* \since QGIS 3.4

‎src/providers/gdal/qgsgdalprovider.cpp

Lines changed: 26 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,19 @@ QgsRasterIdentifyResult QgsGdalProvider::identify( const QgsPointXY &point, QgsR
10891089
return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results );
10901090
}
10911091

1092-
QVariant QgsGdalProvider::sample( const QgsPointXY &point, int band, const QgsRectangle &boundingBox, int width, int height, int )
1092+
bool QgsGdalProvider::worldToPixel( double x, double y, int &col, int &row ) const
1093+
{
1094+
double div = ( mGeoTransform[2] * mGeoTransform[4] - mGeoTransform[1] * mGeoTransform[5] );
1095+
if ( div < 2 * std::numeric_limits<double>::epsilon() )
1096+
return false;
1097+
double doubleCol = -( mGeoTransform[2] * ( mGeoTransform[3] - y ) + mGeoTransform[5] * x - mGeoTransform[0] * mGeoTransform[5] ) / div;
1098+
double doubleRow = ( mGeoTransform[1] * ( mGeoTransform[3] - y ) + mGeoTransform[4] * x - mGeoTransform[0] * mGeoTransform[4] ) / div;
1099+
col = static_cast< int >( doubleCol );
1100+
row = static_cast< int >( doubleRow );
1101+
return true;
1102+
};
1103+
1104+
QVariant QgsGdalProvider::sample( const QgsPointXY &point, int band, const QgsRectangle &, int, int, int )
10931105
{
10941106
QMutexLocker locker( mpMutex );
10951107
if ( !initIfNeeded() )
@@ -1101,60 +1113,22 @@ QVariant QgsGdalProvider::sample( const QgsPointXY &point, int band, const QgsRe
11011113
return QVariant();
11021114
}
11031115

1104-
QgsRectangle finalExtent = boundingBox;
1105-
if ( finalExtent.isEmpty() )
1106-
finalExtent = extent();
1107-
1108-
if ( width == 0 )
1109-
width = xSize();
1110-
if ( height == 0 )
1111-
height = ySize();
1112-
1113-
// Calculate the row / column where the point falls
1114-
double xres = ( finalExtent.width() ) / width;
1115-
double yres = ( finalExtent.height() ) / height;
1116-
1117-
// Offset, not the cell index -> std::floor
1118-
int col = static_cast< int >( std::floor( ( point.x() - finalExtent.xMinimum() ) / xres ) );
1119-
int row = static_cast< int >( std::floor( ( finalExtent.yMaximum() - point.y() ) / yres ) );
1120-
1121-
int r = 0;
1122-
int c = 0;
1123-
int w = 1;
1124-
int h = 1;
1125-
1126-
double xMin = finalExtent.xMinimum() + col * xres;
1127-
double xMax = xMin + xres * w;
1128-
double yMax = finalExtent.yMaximum() - row * yres;
1129-
double yMin = yMax - yres * h;
1130-
QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
1131-
1132-
std::unique_ptr< QgsRasterBlock > bandBlock( block( band, pixelExtent, w, h ) );
1116+
GDALRasterBandH hBand = GDALGetRasterBand( mGdalDataset, band );
1117+
if ( !hBand )
1118+
return QVariant();
11331119

1134-
if ( !bandBlock )
1135-
{
1136-
return tr( "Cannot read data" );
1137-
}
1120+
int row;
1121+
int col;
1122+
if ( !worldToPixel( point.x(), point.y(), col, row ) )
1123+
return QVariant();
11381124

1139-
double value = bandBlock->value( r, c );
1125+
float value = 0;
1126+
CPLErr err = GDALRasterIO( hBand, GF_Read, col, row, 1, 1,
1127+
&value, 1, 1, GDT_Float32, 0, 0 );
1128+
if ( err != CE_None )
1129+
return QVariant();
11401130

1141-
if ( ( sourceHasNoDataValue( band ) && useSourceNoDataValue( band ) &&
1142-
( std::isnan( value ) || qgsDoubleNear( value, sourceNoDataValue( band ) ) ) ) ||
1143-
( QgsRasterRange::contains( value, userNoDataValues( band ) ) ) )
1144-
{
1145-
return QVariant(); // null QVariant represents no data
1146-
}
1147-
else
1148-
{
1149-
if ( sourceDataType( band ) == Qgis::Float32 )
1150-
{
1151-
// Insert a float QVariant so that QgsMapToolIdentify::identifyRasterLayer()
1152-
// can print a string without an excessive precision
1153-
return static_cast<float>( value );
1154-
}
1155-
else
1156-
return value;
1157-
}
1131+
return static_cast< double >( value ) * bandScale( band ) + bandOffset( band );
11581132
}
11591133

11601134
int QgsGdalProvider::capabilities() const

‎src/providers/gdal/qgsgdalprovider.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
292292
//! Close all cached dataset for the specified provider.
293293
static void closeCachedGdalHandlesFor( QgsGdalProvider *provider );
294294

295+
bool worldToPixel( double x, double y, int &col, int &row ) const;
295296
};
296297

297298
#endif

‎tests/src/core/testqgsrasterlayer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,9 @@ void TestQgsRasterLayer::sample()
731731
QVERIFY( rl->isValid() );
732732
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ).isValid() );
733733
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 1 ).toInt(), 125 );
734+
// bad bands
735+
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 0 ).isValid() );
736+
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 10 ).isValid() );
734737

735738
fileName = mTestDataDir + "landsat_4326.tif";
736739
rasterFileInfo = QFileInfo( fileName );

0 commit comments

Comments
 (0)
Please sign in to comment.