diff --git a/src/providers/postgres/raster/qgspostgresrasterprovider.cpp b/src/providers/postgres/raster/qgspostgresrasterprovider.cpp index 7ce77660734..ce8a93dec64 100644 --- a/src/providers/postgres/raster/qgspostgresrasterprovider.cpp +++ b/src/providers/postgres/raster/qgspostgresrasterprovider.cpp @@ -521,7 +521,7 @@ bool QgsPostgresRasterProvider::readBlock( int bandNo, const QgsRectangle &viewE GDALGetRasterStatistics( GDALGetRasterBand( dstDS.get(), 1 ), 0, 1, &pdfMin, &pdfMax, &pdfMean, &pdfStdDev ); qDebug() << pdfMin << pdfMax << pdfMean << pdfStdDev; - // Spit it out float data + // Spit it out float 32 data for ( int i = 0; i < width * height; ++i ) { qDebug() << reinterpret_cast( data )[ i * 4 ]; diff --git a/src/providers/postgres/raster/qgspostgresrastershareddata.cpp b/src/providers/postgres/raster/qgspostgresrastershareddata.cpp index 4099259898d..86a23f946f5 100644 --- a/src/providers/postgres/raster/qgspostgresrastershareddata.cpp +++ b/src/providers/postgres/raster/qgspostgresrastershareddata.cpp @@ -242,6 +242,8 @@ bool QgsPostgresRasterSharedData::fetchTilesIndex( const QgsGeometry &requestPol mLoadedIndexBounds[ cacheKey ] = mLoadedIndexBounds[ cacheKey ].combine( requestPolygon ); } + QgsRectangle overallExtent; + for ( int i = 0; i < result.PQntuples(); ++i ) { // rid | upperleftx | upperlefty | width | height | scalex | scaley | skewx | skewy | srid | numbands @@ -259,14 +261,23 @@ bool QgsPostgresRasterSharedData::fetchTilesIndex( const QgsGeometry &requestPol const double skewy { result.PQgetvalue( i, 8 ).toDouble( ) }; const int srid {result.PQgetvalue( i, 9 ).toInt() }; const int numbands {result.PQgetvalue( i, 10 ).toInt() }; - const QgsRectangle extent( upperleftx, upperlefty - tileHeight * std::abs( scaley ), upperleftx + tileWidth * scalex, upperlefty ); + double minY { upperlefty + tileHeight * scaley }; + double maxY { upperlefty }; + // Southing Y? + if ( scaley > 0 ) + { + std::swap( minY, maxY ); + } + const QgsRectangle extent( upperleftx, minY, upperleftx + tileWidth * scalex, maxY ); + + overallExtent.combineExtentWith( extent ); std::unique_ptr tile = qgis::make_unique( tileId, srid, extent, upperleftx, - upperlefty, + maxY, tileWidth, tileHeight, scalex, @@ -289,6 +300,10 @@ bool QgsPostgresRasterSharedData::fetchTilesIndex( const QgsGeometry &requestPol .arg( tileId ), 3 ); } } + + // Include actual bounds + mLoadedIndexBounds[ cacheKey ] = requestPolygon.combine( QgsGeometry::fromWkt( overallExtent.asWktPolygon() ) ); + return true; } @@ -316,8 +331,6 @@ QgsPostgresRasterSharedData::TilesResponse QgsPostgresRasterSharedData::fetchTil const QString cacheKey { keyFromRequest( request ) }; - mLoadedIndexBounds[ cacheKey ] = requestPolygon; - for ( int row = 0; row < dataResult.PQntuples(); ++row ) { // rid | upperleftx | upperlefty | width | height | scalex | scaley | skewx | skewy | srid | numbands | data @@ -336,7 +349,14 @@ QgsPostgresRasterSharedData::TilesResponse QgsPostgresRasterSharedData::fetchTil const int srid {dataResult.PQgetvalue( row, 9 ).toInt() }; const int numbands {dataResult.PQgetvalue( row, 10 ).toInt() }; - const QgsRectangle extent( upperleftx, upperlefty - tileHeight * std::abs( scaley ), upperleftx + tileWidth * scalex, upperlefty ); + double minY { upperlefty + tileHeight * scaley }; + double maxY { upperlefty }; + // Southing Y? + if ( scaley > 0 ) + { + std::swap( minY, maxY ); + } + const QgsRectangle extent( upperleftx, minY, upperleftx + tileWidth * scalex, maxY ); std::unique_ptr tile = qgis::make_unique( tileId, @@ -394,6 +414,10 @@ QgsPostgresRasterSharedData::TilesResponse QgsPostgresRasterSharedData::fetchTil .arg( tileId ), 2 ); } } + + // Include actual bounds + mLoadedIndexBounds[ cacheKey ] = requestPolygon.combine( QgsGeometry::fromWkt( response.extent.asWktPolygon() ) ); + return response; } diff --git a/src/providers/postgres/raster/qgspostgresrasterutils.cpp b/src/providers/postgres/raster/qgspostgresrasterutils.cpp index 6492a05316e..d49fba95223 100644 --- a/src/providers/postgres/raster/qgspostgresrasterutils.cpp +++ b/src/providers/postgres/raster/qgspostgresrasterutils.cpp @@ -150,6 +150,19 @@ QVariantMap QgsPostgresRasterUtils::parseWkb( const QByteArray &wkb, int bandNo if ( bandNo == 0 || static_cast( bandNo ) == bandCnt ) { result[ QStringLiteral( "band%1" ).arg( bandCnt )] = wkb.mid( offset, result[ QStringLiteral( "dataSize" ) ].toUInt() ); + // Invert rows? + if ( result[ QStringLiteral( "scaleY" ) ].toDouble( ) > 0 ) + { + const unsigned int numRows { result[ QStringLiteral( "height" ) ].toUInt() }; + const auto rowSize { result[ QStringLiteral( "dataSize" ) ].toUInt() / numRows }; + const QByteArray &oldBa { result[ QStringLiteral( "band%1" ).arg( bandCnt )].toByteArray() }; + QByteArray ba; + for ( qlonglong rowOffset = ( numRows - 1 ) * rowSize; rowOffset >= 0; rowOffset -= rowSize ) + { + ba.append( oldBa.mid( rowOffset, rowSize ) ); + } + result[ QStringLiteral( "band%1" ).arg( bandCnt )] = ba; + } } else { diff --git a/tests/src/python/test_provider_postgresraster.py b/tests/src/python/test_provider_postgresraster.py index 0b92e093446..bb5d46b3fa4 100644 --- a/tests/src/python/test_provider_postgresraster.py +++ b/tests/src/python/test_provider_postgresraster.py @@ -77,7 +77,9 @@ class TestPyQgsPostgresRasterProvider(unittest.TestCase): cls._load_test_table('public', 'raster_3035_tiled_composite_pk') cls._load_test_table('public', 'raster_3035_untiled_multiple_rows') cls._load_test_table('idro', 'cosmo_i5_snow', 'bug_34823_pg_raster') - cls._load_test_table('public', 'int16_regression_36689', 'bug_36689_pg_raster') + cls._load_test_table( + 'public', 'int16_regression_36689', 'bug_36689_pg_raster') + cls._load_test_table('public', 'bug_37968_dem_linear_cdn_extract') # Fix timing issues in backend # time.sleep(1) @@ -481,6 +483,26 @@ class TestPyQgsPostgresRasterProvider(unittest.TestCase): self.assertEqual(data, [55, 52, 46, 39, 33, 30, 58, 54, 49, 45, 41, 37, 58, 54, 50, 47, 45, 43, 54, 51, 49, 47, 46, 44, 47, 47, 47, 47, 46, 45, 41, 43, 45, 48, 49, 46]) + def testNegativeScaleY(self): + """Test regression https://github.com/qgis/QGIS/issues/37968 + Y is growing south + """ + + rl = QgsRasterLayer( + self.dbconn + " sslmode=disable table={table} schema={schema}".format( + table='bug_37968_dem_linear_cdn_extract', schema='public'), 'pg_layer', 'postgresraster') + + self.assertTrue(rl.isValid()) + compareWkt(rl.extent().asWktPolygon( + ), 'POLYGON((-40953.223387096 170588, -40873.21532258 170588, -40873.21532258 170668, -40953.223387096 170668, -40953.23387096))') + block = rl.dataProvider().block(1, rl.extent(), 6, 6) + data = [] + for i in range(6): + for j in range(6): + data.append(int(block.value(i, j))) + + self.assertEqual(data, [52, 52, 52, 52, 44, 43, 52, 52, 52, 48, 44, 44, 49, 52, 49, 44, 44, 44, 43, 47, 46, 44, 44, 44, 42, 42, 43, 44, 44, 48, 42, 43, 43, 44, 44, 47]) + if __name__ == '__main__': unittest.main() diff --git a/tests/testdata/provider/postgresraster/bug_37968_dem_linear_cdn_extract.sql b/tests/testdata/provider/postgresraster/bug_37968_dem_linear_cdn_extract.sql new file mode 100644 index 00000000000..d95f84fbef5 --- /dev/null +++ b/tests/testdata/provider/postgresraster/bug_37968_dem_linear_cdn_extract.sql @@ -0,0 +1,6 @@ +BEGIN; +DROP TABLE IF EXISTS "bug_37968_dem_linear_cdn_extract"; +CREATE TABLE "bug_37968_dem_linear_cdn_extract" ("rid" serial PRIMARY KEY,"rast" raster); +INSERT INTO "bug_37968_dem_linear_cdn_extract" ("rast") VALUES ('0100000100409B06B469001040000000000000104060B2FC2527FFE3C000000000E0D2044100000000000000000000000000000000B30E0000140014000A00000000370E2942FE0C2B4274E32C42F3942E42F4F12F420000304200003042000030420000304200003042000030420000304200003042000030420000304200003042000030423E593042BC5D364213473C42000028422AEB284219C82A42367F2C42F1AC2D42E9642E42DBCD2E4223302F42939A2F4285FE2F42000030420000304200003042000030420000304200003042B77F3042D2C038425FCF3F42F529464200002842000028420FD52842F88A2A42A8BB2B42BA862C42A2DB2C42F6352D4235B02D4200003042000030420000304200003042000030420000304200003042F4FA3542D64A3E42524346420000484297202A420000284200002842AAB528425F0D2A428AA82A425AE82A42E6612B42CE202E4200003042000030420000304200003042000030420000304200003042C87834425C163D42000048420000484216842B42234F294200002842000028422F2F28425BCA28422DE5284201D72A429BA02F420000304200003042000030420000304200003042000030420000304200003042417D38422237404200004842F5512C42B4562A427C84284200002842000028420000284200002842CE562C42000030420000304200003042000030420000304200003042000030420000304200003042927B3342DA993B420000484206CF2C42DEFF2A4273202A42000028420000284251E02942F4862E429051324200003042000030420000304200003042000030420000304200003042000030420000304200003042233A3742C7733E42E08F2D4267022D42ED742C42EAEE2B42D7B92D4211CE324273DC3842CBB73C425ACD3542000030420000304200003042000030420000304200003042000030420000304200003042FB6D32422F4D3A425AE42F42E0562F4248302F42599232422EEB3742DCC33C42BA9E4342475F42422AE43A421EC931420000304200003042000030420000304200003042000030420000304200003042000030422D043642000030422CD13142980C374273F63B4296494142B89B464200004842CB7E454256424042EA2E3742000030420000304200003042000030420000304200003042000030420000304200003042D47B314289203642A8103B42C8B53F42D483454211DA4A429F414D420000504209A147427B264342CA133D42ECF8334200003042000030420000304200003042000030420000304200003042000030420000304230C83E42F731444273044A420000504200005042000050420000504200005042D2184642868A41421670394242AD304200003042000030420000304200003042000030420000304200003042000030424DC14842547F4E420000504200005042000050420000504200005042000050420000504229844442D5BB3F4291FB35420000304200003042000030420000304200003042000030420000304200003042000050420000504200005042000050420000504200005042000050420000504200005042238C4742F1E2424234023C427DA3324200003042000030420000304200003042000030420000304200003042000050420000504200005042000050420000504200005042000050420000504200005042000050422DF7454254384142331C3842000030420000304200003042000030420000304200003042000030420000504200005042000050420000504200005042000050420000504200005042000050420000504200005042B182444289CD3E42A3B134420000304200003042000030420000304200003042EE292F4200005042000050420000504200005042000050420000504200005042000050420000504200005042000050421348484236DC4242FBCD3A423C3031420000304200003042B78E2F42831E2E4250AE2C4200005042000050420000504200005042000050420000504200005042000050420000504200005042000050420000504256984642F3F74042D0DA364280F32F425FA12E424B892D4273702C4293442B42000050420000504200005042000050420000504200005042000050420000504200005042000050420000504200005042663D4F42C4E64442E8413D42B63C324264142F4299E42D423DCE2C42F2B22B420000504200005042000050420000504200005042000050420000504200005042000050420000504200005042475C4D42CED14942D7F94242C0A73A4264A3314292AC2E42E8692D423D272C4293E42A42'::raster); +SELECT AddRasterConstraints('','bug_37968_dem_linear_cdn_extract','rast',TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE); +END;