round width and height to the nearest integer in native raster creation

Processing algorithms to match behaviour of gdal_rasterize (fix #43547)
This commit is contained in:
Alexander Bruy 2025-02-12 13:36:00 +00:00 committed by Nyall Dawson
parent 6de7612345
commit bf2a6df16a
5 changed files with 99 additions and 6 deletions

View File

@ -161,8 +161,10 @@ QVariantMap QgsConstantRasterAlgorithm::processAlgorithm( const QVariantMap &par
const QFileInfo fi( outputFile );
const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
const int rows = std::max( std::ceil( extent.height() / pixelSize ), 1.0 );
const int cols = std::max( std::ceil( extent.width() / pixelSize ), 1.0 );
// round up width and height to the nearest integer as GDAL does (e.g. in gdal_rasterize)
// see https://github.com/qgis/QGIS/issues/43547
const int rows = static_cast<int>( 0.5 + extent.height() / pixelSize );
const int cols = static_cast<int>( 0.5 + extent.width() / pixelSize );
//build new raster extent based on number of columns and cellsize
//this prevents output cellsize being calculated too small

View File

@ -136,8 +136,10 @@ QVariantMap QgsLineDensityAlgorithm::processAlgorithm( const QVariantMap &parame
const QFileInfo fi( outputFile );
const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
const int rows = std::max( std::ceil( mExtent.height() / mPixelSize ), 1.0 );
const int cols = std::max( std::ceil( mExtent.width() / mPixelSize ), 1.0 );
// round up width and height to the nearest integer as GDAL does (e.g. in gdal_rasterize)
// see https://github.com/qgis/QGIS/issues/43547
const int rows = static_cast<int>( 0.5 + mExtent.height() / mPixelSize );
const int cols = static_cast<int>( 0.5 + mExtent.width() / mPixelSize );
//build new raster extent based on number of columns and cellsize
//this prevents output cellsize being calculated too small

View File

@ -83,8 +83,10 @@ QVariantMap QgsRandomRasterAlgorithmBase::processAlgorithm( const QVariantMap &p
const QFileInfo fi( outputFile );
const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
const int rows = std::max( std::ceil( mExtent.height() / mPixelSize ), 1.0 );
const int cols = std::max( std::ceil( mExtent.width() / mPixelSize ), 1.0 );
// round up width and height to the nearest integer as GDAL does (e.g. in gdal_rasterize)
// see https://github.com/qgis/QGIS/issues/43547
const int rows = static_cast<int>( 0.5 + mExtent.height() / mPixelSize );
const int cols = static_cast<int>( 0.5 + mExtent.width() / mPixelSize );
//build new raster extent based on number of columns and cellsize
//this prevents output cellsize being calculated too small

View File

@ -111,6 +111,8 @@ class TestQgsProcessingAlgsPt2 : public QgsTest
void updateMetadata();
void setMetadataFields();
void nativeAlgsRasterSize();
private:
QString mPointLayerPath;
QgsVectorLayer *mPointsLayer = nullptr;
@ -2154,5 +2156,90 @@ void TestQgsProcessingAlgsPt2::setMetadataFields()
QCOMPARE( layer->metadata().crs().authid(), QStringLiteral( "EPSG:4326" ) );
}
void TestQgsProcessingAlgsPt2::nativeAlgsRasterSize()
{
auto layer = std::make_unique<QgsVectorLayer>( QStringLiteral( "LineString?crs=epsg:32633" ), QStringLiteral( "input" ), QStringLiteral( "memory" ) );
QVERIFY( layer->isValid() );
QgsFeature f;
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString(656000 4551184, 656184 4551000)" ) ) );
layer->dataProvider()->addFeature( f );
const QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
// reference raster was generated by gdal_rasterize algorithm using following parameters
// UNITS: Georeferenced units
// WIDTH: 10
// HEIGHT: 10
// EXTENT: 656000,656184,4551000,4551184 [EPSG:32633]
auto gdalRasterLayer = std::make_unique<QgsRasterLayer>( dataDir + QStringLiteral( "/raster/gdal_rasterize.tif" ), "gdal_rasterize", "gdal" );
// create constant raster
std::unique_ptr<QgsProcessingAlgorithm> alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:createconstantrasterlayer" ) ) );
QVERIFY( alg != nullptr );
QVariantMap parameters;
parameters.clear();
parameters.insert( QStringLiteral( "EXTENT" ), QStringLiteral( "656000,656184,4551000,4551184 [EPSG:32633]" ) );
parameters.insert( QStringLiteral( "NUMBER" ), 1 );
parameters.insert( QStringLiteral( "OUTPUT_TYPE" ), 0 );
parameters.insert( QStringLiteral( "PIXEL_SIZE" ), 10 );
parameters.insert( QStringLiteral( "TARGET_CRS" ), QgsCoordinateReferenceSystem( "EPSG:32633" ) );
parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT );
bool ok = false;
auto context = std::make_unique<QgsProcessingContext>();
QgsProcessingFeedback feedback;
QVariantMap results;
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );
auto constantRasterLayer = std::make_unique<QgsRasterLayer>( results.value( QStringLiteral( "OUTPUT" ) ).toString(), "constant", "gdal" );
QCOMPARE( constantRasterLayer->extent(), gdalRasterLayer->extent() );
QCOMPARE( constantRasterLayer->height(), gdalRasterLayer->height() );
QCOMPARE( constantRasterLayer->width(), gdalRasterLayer->width() );
// create random raster (it is enough to check only one alg here as they have same base class)
alg.reset( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:createrandomuniformrasterlayer" ) ) );
QVERIFY( alg != nullptr );
parameters.clear();
parameters.insert( QStringLiteral( "EXTENT" ), QStringLiteral( "656000,656184,4551000,4551184 [EPSG:32633]" ) );
parameters.insert( QStringLiteral( "OUTPUT_TYPE" ), 0 );
parameters.insert( QStringLiteral( "PIXEL_SIZE" ), 10 );
parameters.insert( QStringLiteral( "TARGET_CRS" ), QgsCoordinateReferenceSystem( "EPSG:32633" ) );
parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT );
ok = false;
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );
auto randomRasterLayer = std::make_unique<QgsRasterLayer>( results.value( QStringLiteral( "OUTPUT" ) ).toString(), "random", "gdal" );
QCOMPARE( randomRasterLayer->extent(), gdalRasterLayer->extent() );
QCOMPARE( randomRasterLayer->height(), gdalRasterLayer->height() );
QCOMPARE( randomRasterLayer->width(), gdalRasterLayer->width() );
// line density
alg.reset( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:linedensity" ) ) );
QVERIFY( alg != nullptr );
parameters.clear();
parameters.insert( QStringLiteral( "INPUT" ), QVariant::fromValue( layer.get() ) );
parameters.insert( QStringLiteral( "PIXEL_SIZE" ), 10 );
parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT );
ok = false;
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );
auto densityRasterLayer = std::make_unique<QgsRasterLayer>( results.value( QStringLiteral( "OUTPUT" ) ).toString(), "density", "gdal" );
QCOMPARE( densityRasterLayer->extent(), gdalRasterLayer->extent() );
QCOMPARE( densityRasterLayer->height(), gdalRasterLayer->height() );
QCOMPARE( densityRasterLayer->width(), gdalRasterLayer->width() );
}
QGSTEST_MAIN( TestQgsProcessingAlgsPt2 )
#include "testqgsprocessingalgspt2.moc"

BIN
tests/testdata/raster/gdal_rasterize.tif vendored Normal file

Binary file not shown.