Skip to content

Commit 74c2ed1

Browse files
committedJul 19, 2018
Nicer API for raster sampling
1 parent 54e5119 commit 74c2ed1

File tree

6 files changed

+55
-28
lines changed

6 files changed

+55
-28
lines changed
 

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,17 +277,19 @@ if point is outside data source extent.
277277
.. seealso:: :py:func:`sample`
278278
%End
279279

280-
virtual QVariant sample( const QgsPointXY &point, int band, const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 );
280+
virtual double sample( const QgsPointXY &point, int band,
281+
bool *ok /Out/ = 0,
282+
const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 );
281283
%Docstring
282284
Samples a raster value from the specified ``band`` found at the ``point`` position. The context
283285
parameters ``boundingBox``, ``width`` and ``height`` are important to identify
284286
on the same zoom level as a displayed map and to do effective
285287
caching (WCS). If context params are not specified the highest
286-
resolution is used. capabilities() may be used to test if format
287-
is supported by provider.
288+
resolution is used.
288289

289-
A null QVariant will be returned if the point is outside data source extent, or an invalid
290-
band number was specified.
290+
If ``ok`` is specified and the point is outside data source extent, or an invalid
291+
band number was specified, then ``ok`` will be set to false. In this case the function will return
292+
a NaN value.
291293

292294
.. seealso:: :py:func:`identify`
293295

‎src/core/raster/qgsrasterdataprovider.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,16 @@ QgsRasterIdentifyResult QgsRasterDataProvider::identify( const QgsPointXY &point
300300
return QgsRasterIdentifyResult( QgsRaster::IdentifyFormatValue, results );
301301
}
302302

303-
QVariant QgsRasterDataProvider::sample( const QgsPointXY &point, int band, const QgsRectangle &boundingBox, int width, int height, int )
303+
double QgsRasterDataProvider::sample( const QgsPointXY &point, int band,
304+
bool *ok, const QgsRectangle &boundingBox, int width, int height, int )
304305
{
306+
if ( ok )
307+
*ok = false;
308+
305309
if ( !extent().contains( point ) )
306310
{
307311
// Outside the raster
308-
return QVariant();
312+
return std::numeric_limits<double>::quiet_NaN();
309313
}
310314

311315
QgsRectangle finalExtent = boundingBox;
@@ -335,8 +339,10 @@ QVariant QgsRasterDataProvider::sample( const QgsPointXY &point, int band, const
335339
QgsRectangle pixelExtent( xMin, yMin, xMax, yMax );
336340

337341
std::unique_ptr< QgsRasterBlock > bandBlock( block( band, pixelExtent, 1, 1 ) );
342+
if ( bandBlock && ok )
343+
*ok = true;
338344

339-
return bandBlock ? bandBlock->value( 0 ) : QVariant();
345+
return bandBlock ? bandBlock->value( 0 ) : std::numeric_limits<double>::quiet_NaN();
340346
}
341347

342348
QString QgsRasterDataProvider::lastErrorFormat()

‎src/core/raster/qgsrasterdataprovider.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,16 +364,18 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
364364
* parameters \a boundingBox, \a width and \a height are important to identify
365365
* on the same zoom level as a displayed map and to do effective
366366
* caching (WCS). If context params are not specified the highest
367-
* resolution is used. capabilities() may be used to test if format
368-
* is supported by provider.
367+
* resolution is used.
369368
*
370-
* A null QVariant will be returned if the point is outside data source extent, or an invalid
371-
* band number was specified.
369+
* If \a ok is specified and the point is outside data source extent, or an invalid
370+
* band number was specified, then \a ok will be set to false. In this case the function will return
371+
* a NaN value.
372372
*
373373
* \see identify(), which is much more flexible but considerably less efficient.
374374
* \since QGIS 3.4
375375
*/
376-
virtual QVariant sample( const QgsPointXY &point, int band, const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 );
376+
virtual double sample( const QgsPointXY &point, int band,
377+
bool *ok SIP_OUT = nullptr,
378+
const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 );
377379

378380
/**
379381
* \brief Returns the caption error text for the last error in this provider

‎src/providers/gdal/qgsgdalprovider.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,32 +1101,38 @@ bool QgsGdalProvider::worldToPixel( double x, double y, int &col, int &row ) con
11011101
return true;
11021102
};
11031103

1104-
QVariant QgsGdalProvider::sample( const QgsPointXY &point, int band, const QgsRectangle &, int, int, int )
1104+
double QgsGdalProvider::sample( const QgsPointXY &point, int band, bool *ok, const QgsRectangle &, int, int, int )
11051105
{
1106+
if ( ok )
1107+
*ok = false;
1108+
11061109
QMutexLocker locker( mpMutex );
11071110
if ( !initIfNeeded() )
1108-
return tr( "Cannot read data" );
1111+
return std::numeric_limits<double>::quiet_NaN();
11091112

11101113
if ( !extent().contains( point ) )
11111114
{
11121115
// Outside the raster
1113-
return QVariant();
1116+
return std::numeric_limits<double>::quiet_NaN();
11141117
}
11151118

11161119
GDALRasterBandH hBand = GDALGetRasterBand( mGdalDataset, band );
11171120
if ( !hBand )
1118-
return QVariant();
1121+
return std::numeric_limits<double>::quiet_NaN();
11191122

11201123
int row;
11211124
int col;
11221125
if ( !worldToPixel( point.x(), point.y(), col, row ) )
1123-
return QVariant();
1126+
return std::numeric_limits<double>::quiet_NaN();
11241127

11251128
float value = 0;
11261129
CPLErr err = GDALRasterIO( hBand, GF_Read, col, row, 1, 1,
11271130
&value, 1, 1, GDT_Float32, 0, 0 );
11281131
if ( err != CE_None )
1129-
return QVariant();
1132+
return std::numeric_limits<double>::quiet_NaN();
1133+
1134+
if ( ok )
1135+
*ok = true;
11301136

11311137
return static_cast< double >( value ) * bandScale( band ) + bandOffset( band );
11321138
}

‎src/providers/gdal/qgsgdalprovider.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class QgsGdalProvider : public QgsRasterDataProvider, QgsGdalProviderBase
103103
QgsRectangle extent() const override;
104104
bool isValid() const override;
105105
QgsRasterIdentifyResult identify( const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 ) override;
106-
QVariant sample( const QgsPointXY &point, int band, const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 );
106+
double sample( const QgsPointXY &point, int band, bool *ok = nullptr, const QgsRectangle &boundingBox = QgsRectangle(), int width = 0, int height = 0, int dpi = 96 );
107107
QString lastErrorTitle() override;
108108
QString lastError() override;
109109
int capabilities() const override;

‎tests/src/core/testqgsrasterlayer.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -729,21 +729,32 @@ void TestQgsRasterLayer::sample()
729729
std::unique_ptr< QgsRasterLayer > rl = qgis::make_unique< QgsRasterLayer> ( rasterFileInfo.filePath(),
730730
rasterFileInfo.completeBaseName() );
731731
QVERIFY( rl->isValid() );
732-
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ).isValid() );
733-
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 1 ).toInt(), 125 );
732+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ) ) );
733+
bool ok = false;
734+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1, &ok ) ) );
735+
QVERIFY( !ok );
736+
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 1 ), 125.0 );
737+
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 1, &ok ), 125.0 );
738+
QVERIFY( ok );
734739
// bad bands
735-
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 0 ).isValid() );
736-
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 10 ).isValid() );
740+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 0 ) ) );
741+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 0, &ok ) ) );
742+
QVERIFY( !ok );
743+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 10, &ok ) ) );
744+
QVERIFY( !ok );
737745

738746
fileName = mTestDataDir + "landsat_4326.tif";
739747
rasterFileInfo = QFileInfo( fileName );
740748
rl = qgis::make_unique< QgsRasterLayer> ( rasterFileInfo.filePath(),
741749
rasterFileInfo.completeBaseName() );
742750
QVERIFY( rl->isValid() );
743-
QVERIFY( !rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ).isValid() );
744-
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 1 ).toInt(), 125 );
745-
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 2 ).toInt(), 139 );
746-
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 3 ).toInt(), 111 );
751+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ) ) );
752+
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1, &ok ) ) );
753+
QVERIFY( !ok );
754+
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 1, &ok ), 125.0 );
755+
QVERIFY( ok );
756+
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 2 ), 139.0 );
757+
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 3 ), 111.0 );
747758
}
748759

749760
QGSTEST_MAIN( TestQgsRasterLayer )

0 commit comments

Comments
 (0)
Please sign in to comment.