From f9eb606bfa8252b1cf965d137cf27a396807baf4 Mon Sep 17 00:00:00 2001
From: Denis Rouzaud <denis.rouzaud@gmail.com>
Date: Wed, 8 Jan 2025 16:09:08 +0100
Subject: [PATCH] fix nodata value in virtual raster layers

---
 .../qgsvirtualrasterprovider.cpp              |   4 +-
 .../testqgsvirtualrasterprovider.cpp          |  35 ++++++++++++++++++
 tests/testdata/raster/no_data.tif             | Bin 0 -> 729 bytes
 3 files changed, 37 insertions(+), 2 deletions(-)
 create mode 100644 tests/testdata/raster/no_data.tif

diff --git a/src/providers/virtualraster/qgsvirtualrasterprovider.cpp b/src/providers/virtualraster/qgsvirtualrasterprovider.cpp
index c052e4654387..61989668b6ed 100644
--- a/src/providers/virtualraster/qgsvirtualrasterprovider.cpp
+++ b/src/providers/virtualraster/qgsvirtualrasterprovider.cpp
@@ -122,7 +122,6 @@ QgsVirtualRasterProvider::QgsVirtualRasterProvider( const QgsVirtualRasterProvid
   , mFormulaString( other.mFormulaString )
   , mLastError( other.mLastError )
   , mRasterLayers {} // see note in other constructor above
-
 {
   for ( const auto &it : other.mRasterLayers )
   {
@@ -149,6 +148,7 @@ QgsRasterBlock *QgsVirtualRasterProvider::block( int bandNo, const QgsRectangle
 {
   Q_UNUSED( bandNo );
   std::unique_ptr<QgsRasterBlock> tblock = std::make_unique<QgsRasterBlock>( Qgis::DataType::Float64, width, height );
+
   double *outputData = ( double * ) ( tblock->bits() );
 
   QMap<QString, QgsRasterBlock *> inputBlocks;
@@ -182,7 +182,7 @@ QgsRasterBlock *QgsVirtualRasterProvider::block( int bandNo, const QgsRectangle
     inputBlocks.insert( it->ref, block.release() );
   }
 
-  QgsRasterMatrix resultMatrix( width, 1, nullptr, -FLT_MAX );
+  QgsRasterMatrix resultMatrix( width, 1, nullptr, std::numeric_limits<double>::quiet_NaN() );
 
   for ( int i = 0; i < height; ++i )
   {
diff --git a/tests/src/providers/testqgsvirtualrasterprovider.cpp b/tests/src/providers/testqgsvirtualrasterprovider.cpp
index 450609c91000..592db283d8c5 100644
--- a/tests/src/providers/testqgsvirtualrasterprovider.cpp
+++ b/tests/src/providers/testqgsvirtualrasterprovider.cpp
@@ -70,11 +70,13 @@ class TestQgsVirtualRasterProvider : public QgsTest
     void testConstructor();
     void testNewCalcNodeMethods();
     void testSecondGenerationVirtualRaster();
+    void testNoData();
 
   private:
     QString mTestDataDir;
     QgsRasterLayer *mDemRasterLayer = nullptr;
     QgsRasterLayer *mLandsatRasterLayer = nullptr;
+    QgsRasterLayer *mNoDataRasterLayer = nullptr;
 };
 
 //runs before all tests
@@ -93,6 +95,10 @@ void TestQgsVirtualRasterProvider::initTestCase()
   QString landsatFileName = mTestDataDir + "landsat.tif";
   QFileInfo landsatRasterFileInfo( landsatFileName );
   mLandsatRasterLayer = new QgsRasterLayer( landsatRasterFileInfo.filePath(), landsatRasterFileInfo.completeBaseName() );
+
+  QString nodataFileName = mTestDataDir + "raster/no_data.tif";
+  QFileInfo nodataRasterFileInfo( nodataFileName );
+  mNoDataRasterLayer = new QgsRasterLayer( nodataRasterFileInfo.filePath(), nodataRasterFileInfo.completeBaseName() );
 }
 
 void TestQgsVirtualRasterProvider::validLayer()
@@ -291,5 +297,34 @@ void TestQgsVirtualRasterProvider::testSecondGenerationVirtualRaster()
   QCOMPARE( sampledValueCalc_1, sampledValue + 200. );
   QCOMPARE( layerSecond->dataProvider()->crs(), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
 }
+
+void TestQgsVirtualRasterProvider::testNoData()
+{
+  double tlx = 415780.969;
+  double tly = 759360.133;
+  double cellSize = 0.1;
+
+  // nodata
+  //  0  NaN
+  // NaN  1
+  //  2  NaN
+  QString str = QStringLiteral( "?crs=EPSG:2105&extent=415780.96899999998277053,759359.8330999999307096,415781.16899999999441206,759360.13309999997727573&width=2&height=3&formula=\"nodata@1\" ^2 / \"nodata@1\"&nodata:provider=gdal" );
+
+  QString uri = QString( "%1&%2" ).arg( str, QStringLiteral( "nodata:uri=" ) % mTestDataDir % QStringLiteral( "raster/no_data.tif" ) );
+
+  std::unique_ptr<QgsRasterLayer> layerNoData = std::make_unique<QgsRasterLayer>( uri, QStringLiteral( "no-data" ), QStringLiteral( "virtualraster" ) );
+  QVERIFY( layerNoData->dataProvider()->isValid() );
+  QVERIFY( layerNoData->isValid() );
+
+  QgsPointXY p11( tlx + .5 * cellSize, tly - .5 * cellSize );
+  QgsPointXY p12( tlx + 1.5 * cellSize, tly - .5 * cellSize );
+  QgsPointXY p31( tlx + .5 * cellSize, tly - 2.5 * cellSize );
+
+  Q_ASSERT( std::isnan( layerNoData->dataProvider()->sample( p11, 1 ) ) ); // 0^2/0
+  Q_ASSERT( std::isnan( layerNoData->dataProvider()->sample( p12, 1 ) ) ); // NaN^2/NaN
+  QCOMPARE( layerNoData->dataProvider()->sample( p31, 1 ), 2 );            // 2^2/2
+}
+
+
 QGSTEST_MAIN( TestQgsVirtualRasterProvider )
 #include "testqgsvirtualrasterprovider.moc"
diff --git a/tests/testdata/raster/no_data.tif b/tests/testdata/raster/no_data.tif
new file mode 100644
index 0000000000000000000000000000000000000000..31326849d62750f975c8720481010c9a5c7a8bb6
GIT binary patch
literal 729
zcmebD)MDUZU|<krU|?isU<9(5fS3`=W(M)0Yylvf8OjE!V?$yKGO~d6o&{<aMG_Z-
zvO(sEL)GvA*)m9Kf}w1Xy?o6)3?Q`%Ku%K&4+9&JZ2@GjZ)avu0J1ZH?2YYA45~o(
z3Lv{-2@`_@&@s1w{6-)fq+SXr4gxmrE{;CFsU?Xii6x14TnY*{o+YWd3VDgSskTbN
zA&w!Q!6BZ`!STM15uU!GzDf$kiMa(iKsf^?J0lx?kYaqgTpj&Tv=|cB;^~KBkpV$n
z!67a#u3;!v8R%IUnweOdnOYcF8kw6L6Eq{t(Z|yzKEO4|+0`!u#VAv_18nqB!;3-J
z5(pS(%>;p+_AnX}wzx_2PR9q66C@p<ty6Vr&{21UsbmDF4|WCy7GUZEK`70{vawwn
zsECncV>>5<Gy@wjF)}jrDKh|*2_u6g2Md_iRQ8K<cQG<BFi_A}@XasHD^YMwNzGFL
WiPXTPYJkRkyz%h{BQObnya51$oQ%!@

literal 0
HcmV?d00001