[feature] add Fill noData cells algorithm and tests

This commit is contained in:
root676 2020-01-27 22:19:56 +01:00 committed by Nyall Dawson
parent d15ce6b4c3
commit ea7167e135
13 changed files with 562 additions and 0 deletions

View File

@ -88,6 +88,7 @@
<file>themes/default/algorithms/mAlgorithmCollect.svg</file> <file>themes/default/algorithms/mAlgorithmCollect.svg</file>
<file>themes/default/algorithms/mAlgorithmConvexHull.svg</file> <file>themes/default/algorithms/mAlgorithmConvexHull.svg</file>
<file>themes/default/algorithms/mAlgorithmCreateGrid.svg</file> <file>themes/default/algorithms/mAlgorithmCreateGrid.svg</file>
<file>themes/default/algorithms/mAlgorithmFillNoData.svg</file>
<file>themes/default/algorithms/mAlgorithmFuzzifyLinear.svg</file> <file>themes/default/algorithms/mAlgorithmFuzzifyLinear.svg</file>
<file>themes/default/algorithms/mAlgorithmFuzzifyPower.svg</file> <file>themes/default/algorithms/mAlgorithmFuzzifyPower.svg</file>
<file>themes/default/algorithms/mAlgorithmFuzzifyLarge.svg</file> <file>themes/default/algorithms/mAlgorithmFuzzifyLarge.svg</file>

View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
viewBox="0 0 6.35 6.35"
version="1.1"
id="svg4582"
sodipodi:docname="mAlgorithmFillNoData.svg"
inkscape:version="0.92.4 (f8dce91, 2019-08-02)">
<metadata
id="metadata4588">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4586" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1052"
id="namedview4584"
showgrid="false"
inkscape:zoom="15.806783"
inkscape:cx="-2.374488"
inkscape:cy="7.5245181"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4582" />
<rect
style="opacity:1;fill:#7c96a8;fill-opacity:0.46320346;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617"
width="1.4848133"
height="1.4848132"
x="0.18943673"
y="0.24060294" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-1"
width="1.4848135"
height="1.4848133"
x="1.67425"
y="0.24060294" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-8"
width="1.4848135"
height="1.4848133"
x="3.1590633"
y="0.24060294" />
<rect
style="opacity:1;fill:#7c96a8;fill-opacity:0.46320346;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-5"
width="1.4848135"
height="1.4848133"
x="4.643877"
y="0.24060294" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-9"
width="1.4848135"
height="1.4848133"
x="0.18943644"
y="1.7254163" />
<rect
style="opacity:1;fill:#7c96a8;fill-opacity:0.46320346;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-1-7"
width="1.4848136"
height="1.4848135"
x="1.6742498"
y="1.7254163" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-8-5"
width="1.4848136"
height="1.4848135"
x="3.1590633"
y="1.7254163" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-5-3"
width="1.4848136"
height="1.4848135"
x="4.6438766"
y="1.7254163" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-88"
width="1.4848135"
height="1.4848133"
x="0.18943655"
y="3.2102299" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-1-3"
width="1.4848136"
height="1.4848135"
x="1.6742499"
y="3.2102299" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-8-1"
width="1.4848136"
height="1.4848135"
x="3.1590633"
y="3.2102299" />
<rect
style="opacity:1;fill:#7c96a8;fill-opacity:0.46320346;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-5-8"
width="1.4848136"
height="1.4848135"
x="4.6438766"
y="3.2102299" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-96"
width="1.4848135"
height="1.4848133"
x="0.18943644"
y="4.6950436" />
<rect
style="opacity:1;fill:#7c96a8;fill-opacity:0.46320346;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-1-4"
width="1.4848136"
height="1.4848135"
x="1.6742498"
y="4.6950436" />
<rect
style="opacity:1;fill:#7c96a8;fill-opacity:0.46320346;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-8-3"
width="1.4848136"
height="1.4848135"
x="3.1590633"
y="4.6950436" />
<rect
style="opacity:1;fill:#517083;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.14263225;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4617-5-33"
width="1.4848136"
height="1.4848135"
x="4.643877"
y="4.6950436" />
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -64,6 +64,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmextractvertices.cpp processing/qgsalgorithmextractvertices.cpp
processing/qgsalgorithmextractspecificvertices.cpp processing/qgsalgorithmextractspecificvertices.cpp
processing/qgsalgorithmfiledownloader.cpp processing/qgsalgorithmfiledownloader.cpp
processing/qgsalgorithmfillnodata.cpp
processing/qgsalgorithmfilter.cpp processing/qgsalgorithmfilter.cpp
processing/qgsalgorithmfiltervertices.cpp processing/qgsalgorithmfiltervertices.cpp
processing/qgsalgorithmfixgeometries.cpp processing/qgsalgorithmfixgeometries.cpp

View File

@ -0,0 +1,157 @@
/***************************************************************************
qgsalgorithmfillnodata.cpp
---------------------
begin : January 2020
copyright : (C) 2020 by Clemens Raffler
email : clemens dot raffler at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsalgorithmfillnodata.h"
#include "qgsrasterfilewriter.h"
///@cond PRIVATE
QString QgsFillNoDataAlgorithm::name() const
{
return QStringLiteral( "fillnodata" );
}
QString QgsFillNoDataAlgorithm::displayName() const
{
return QObject::tr( "Fill noData cells" );
}
QStringList QgsFillNoDataAlgorithm::tags() const
{
return QObject::tr( "noData,nodata,data,cells,fill,set" ).split( ',' );
}
QString QgsFillNoDataAlgorithm::group() const
{
return QObject::tr( "Raster tools" );
}
QString QgsFillNoDataAlgorithm::groupId() const
{
return QStringLiteral( "rastertools" );
}
void QgsFillNoDataAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterRasterLayer( QStringLiteral( "INPUT" ), QStringLiteral( "Raster input" ) ) );
addParameter( new QgsProcessingParameterBand( QStringLiteral( "BAND" ), QObject::tr( "Band Number" ), 1, QStringLiteral( "INPUT" ) ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "FILL_VALUE" ), QObject::tr( "Fill value" ), QgsProcessingParameterNumber::Double, 1, false, 1, 10000000 ) );
addParameter( new QgsProcessingParameterRasterDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Output raster" ) ) );
}
QString QgsFillNoDataAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm resets the noData values in the input raster "
"to a chosen value. This value can be set by the user or "
"evaluated as an expression." );
}
QgsFillNoDataAlgorithm *QgsFillNoDataAlgorithm::createInstance() const
{
return new QgsFillNoDataAlgorithm();
}
bool QgsFillNoDataAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
Q_UNUSED( feedback );
mInputRaster = parameterAsRasterLayer( parameters, QStringLiteral( "INPUT" ), context );
mFillValue = parameterAsDouble( parameters, QStringLiteral( "FILL_VALUE" ), context );
if ( !mInputRaster )
throw QgsProcessingException( invalidRasterError( parameters, QStringLiteral( "INPUT" ) ) );
mBand = parameterAsInt( parameters, QStringLiteral( "BAND" ), context );
if ( mBand < 1 || mBand > mInputRaster->bandCount() )
throw QgsProcessingException( QObject::tr( "Invalid band number for BAND (%1): Valid values for input raster are 1 to %2" ).arg( mBand ).arg( mInputRaster->bandCount() ) );
mInterface.reset( mInputRaster->dataProvider()->clone() );
mInputNoDataValue = mInputRaster->dataProvider()->sourceNoDataValue( mBand );
mExtent = mInputRaster->extent();
mLayerWidth = mInputRaster->width();
mLayerHeight = mInputRaster->height();
mCrs = mInputRaster->crs();
mNbCellsXProvider = mInterface->xSize();
mNbCellsYProvider = mInterface->ySize();
return true;
}
QVariantMap QgsFillNoDataAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
//test if input dataset has NoData
if ( !mInputRaster->dataProvider()->sourceHasNoDataValue( mBand ) )
throw QgsProcessingException( QObject::tr( "Input raster has no NoData values. There exist no NoData cells to fill." ) );
//prepare output dataset
const QString outputFile = parameterAsOutputLayer( parameters, QStringLiteral( "OUTPUT" ), context );
QFileInfo fi( outputFile );
const QString outputFormat = QgsRasterFileWriter::driverForExtension( fi.suffix() );
std::unique_ptr< QgsRasterFileWriter > writer = qgis::make_unique< QgsRasterFileWriter >( outputFile );
writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
writer->setOutputFormat( outputFormat );
std::unique_ptr<QgsRasterDataProvider > provider( writer->createOneBandRaster( mInterface->dataType( mBand ), mNbCellsXProvider, mNbCellsYProvider, mExtent, mCrs ) );
if ( !provider )
throw QgsProcessingException( QObject::tr( "Could not create raster output: %1" ).arg( outputFile ) );
if ( !provider->isValid() )
throw QgsProcessingException( QObject::tr( "Could not create raster output %1: %2" ).arg( outputFile, provider->error().message( QgsErrorMessage::Text ) ) );
//prepare output provider
mDestinationRasterProvider = provider.get();
mDestinationRasterProvider->setNoDataValue( 1, -9999 );
mDestinationRasterProvider->setEditable( true );
int maxWidth = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_WIDTH;
int maxHeight = QgsRasterIterator::DEFAULT_MAXIMUM_TILE_HEIGHT;
int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * mLayerWidth / maxWidth ) );
int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * mLayerHeight / maxHeight ) );
int nbBlocks = nbBlocksWidth * nbBlocksHeight;
QgsRasterIterator iter( mInterface.get() );
iter.startRasterRead( mBand, mLayerWidth, mLayerHeight, mExtent );
int iterLeft = 0;
int iterTop = 0;
int iterCols = 0;
int iterRows = 0;
std::unique_ptr< QgsRasterBlock > filledRasterBlock;
while ( iter.readNextRasterPart( mBand, iterCols, iterRows, filledRasterBlock, iterLeft, iterTop ) )
{
if ( feedback )
feedback->setProgress( 100 * ( ( iterTop / maxHeight * nbBlocksWidth ) + iterLeft / maxWidth ) / nbBlocks );
if ( !filledRasterBlock->hasNoDataValue() )
continue;
for ( int row = 0; row < iterRows; row++ )
{
if ( feedback && feedback->isCanceled() )
break;
for ( int column = 0; column < iterCols; column++ )
{
if ( feedback && feedback->isCanceled() )
break;
if ( filledRasterBlock->isNoData( row, column ) )
filledRasterBlock->setValue( row, column, mFillValue );
}
}
mDestinationRasterProvider->writeBlock( filledRasterBlock.get(), mBand, iterLeft, iterTop );
}
mDestinationRasterProvider->setEditable( false );
QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
return outputs;
}
///@endcond

View File

@ -0,0 +1,78 @@
/***************************************************************************
qgsalgorithmfillnodata.h
---------------------
begin : January 2020
copyright : (C) 2020 by Clemens Raffler
email : clemens dot raffler at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSALGORITHMFILLNODATA_H
#define QGSALGORITHMFILLNODATA_H
#define SIP_NO_FILE
#include "qgis_sip.h"
#include "qgsprocessingalgorithm.h"
#include "qgsapplication.h"
///@cond PRIVATE
/**
* Fill NoData algorithm:
* This is an algorithm that fills the NoDataValues in a raster dataset
* based on a dynamic input parameter
*/
class QgsFillNoDataAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsFillNoDataAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmFillNoData.svg" ) ); }
QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmFillNoData.svg" ) ); }
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QgsFillNoDataAlgorithm *createInstance() const override SIP_FACTORY;
protected:
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context,
QgsProcessingFeedback *feedback ) override;
private:
QgsRasterLayer *mInputRaster;
double mFillValue = 0;
int mBand;
std::unique_ptr< QgsRasterInterface > mInterface;
QgsRectangle mExtent;
QgsCoordinateReferenceSystem mCrs;
int mLayerWidth;
int mLayerHeight;
int mNbCellsXProvider = 0;
int mNbCellsYProvider = 0;
double mInputNoDataValue;
QgsRasterDataProvider *mDestinationRasterProvider;
bool mDynamicFillValue = false;
QgsProperty mDynamicFillValueProperty;
};
///@endcond PRIVATE
#endif // QGSALGORITHMFILLNODATA_H

View File

@ -59,6 +59,7 @@
#include "qgsalgorithmextractspecificvertices.h" #include "qgsalgorithmextractspecificvertices.h"
#include "qgsalgorithmextractzmvalues.h" #include "qgsalgorithmextractzmvalues.h"
#include "qgsalgorithmfiledownloader.h" #include "qgsalgorithmfiledownloader.h"
#include "qgsalgorithmfillnodata.h"
#include "qgsalgorithmfilter.h" #include "qgsalgorithmfilter.h"
#include "qgsalgorithmfiltervertices.h" #include "qgsalgorithmfiltervertices.h"
#include "qgsalgorithmfixgeometries.h" #include "qgsalgorithmfixgeometries.h"
@ -247,6 +248,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsExtractSpecificVerticesAlgorithm() ); addAlgorithm( new QgsExtractSpecificVerticesAlgorithm() );
addAlgorithm( new QgsExtractZValuesAlgorithm() ); addAlgorithm( new QgsExtractZValuesAlgorithm() );
addAlgorithm( new QgsFileDownloaderAlgorithm() ); addAlgorithm( new QgsFileDownloaderAlgorithm() );
addAlgorithm( new QgsFillNoDataAlgorithm() );
addAlgorithm( new QgsFilterAlgorithm() ); addAlgorithm( new QgsFilterAlgorithm() );
addAlgorithm( new QgsFilterVerticesByM() ); addAlgorithm( new QgsFilterVerticesByM() );
addAlgorithm( new QgsFilterVerticesByZ() ); addAlgorithm( new QgsFilterVerticesByZ() );

View File

@ -23,6 +23,7 @@
#include "qgsprocessingcontext.h" #include "qgsprocessingcontext.h"
#include "qgsprocessingmodelalgorithm.h" #include "qgsprocessingmodelalgorithm.h"
#include "qgsnativealgorithms.h" #include "qgsnativealgorithms.h"
#include "qgsalgorithmfillnodata.h"
#include "qgsalgorithmlinedensity.h" #include "qgsalgorithmlinedensity.h"
#include "qgsalgorithmimportphotos.h" #include "qgsalgorithmimportphotos.h"
#include "qgsalgorithmtransform.h" #include "qgsalgorithmtransform.h"
@ -85,6 +86,8 @@ class TestQgsProcessingAlgs: public QObject
void densifyGeometries_data(); void densifyGeometries_data();
void densifyGeometries(); void densifyGeometries();
void fillNoData_data();
void fillNoData();
void lineDensity_data(); void lineDensity_data();
void lineDensity(); void lineDensity();
@ -923,6 +926,134 @@ void TestQgsProcessingAlgs::densifyGeometries()
QVERIFY2( result.geometry().equals( expectedGeometry ), QStringLiteral( "Result: %1, Expected: %2" ).arg( result.geometry().asWkt(), expectedGeometry.asWkt() ).toUtf8().constData() ); QVERIFY2( result.geometry().equals( expectedGeometry ), QStringLiteral( "Result: %1, Expected: %2" ).arg( result.geometry().asWkt(), expectedGeometry.asWkt() ).toUtf8().constData() );
} }
void TestQgsProcessingAlgs::fillNoData_data()
{
QTest::addColumn<QString>( "inputRaster" );
QTest::addColumn<QString>( "expectedRaster" );
QTest::addColumn<int>( "inputBand" );
QTest::addColumn<double>( "fillValue" );
/*
* Testcase 1
*
* NoData raster layer
* band = 1
* fillValue = 2.0
*/
QTest::newRow( "testcase 1" )
<< "/raster/band1_int16_noct_epsg4326.tif"
<< QStringLiteral( "/fillnodata_testcase1.tif" )
<< 1
<< 2.0;
/*
* Testcase 2
*
* WGS84 data without weights
* searchRadius = 3
* pixelSize = 1.8
*/
QTest::newRow( "testcase 2" )
<< "/raster/band1_int16_noct_epsg4326.tif"
<< QStringLiteral( "/fillnodata_testcase2.tif" )
<< 1
<< 1.8;
/*
* Testcase 3
*
* WGS84 data without weights
* searchRadius = 3
* pixelSize = 1.8
*/
QTest::newRow( "testcase 2" )
<< "/raster/band1_float32_noct_epsg4326.tif"
<< QStringLiteral( "/fillnodata_testcase3.tif" )
<< 1
<< 1.8;
}
void TestQgsProcessingAlgs::fillNoData()
{
QFETCH( QString, inputRaster );
QFETCH( QString, expectedRaster );
QFETCH( int, inputBand );
QFETCH( double, fillValue );
//prepare input params
QgsProject p;
std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:fillnodata" ) ) );
QString myDataPath( TEST_DATA_DIR ); //defined in CmakeLists.txt
std::unique_ptr<QgsRasterLayer> inputRasterLayer = qgis::make_unique< QgsRasterLayer >( myDataPath + inputRaster, "inputDataset", "gdal" );
//set project crs and ellipsoid from input layer
p.setCrs( inputRasterLayer->crs(), true );
//set project after layer has been added so that transform context/ellipsoid from crs is also set
std::unique_ptr< QgsProcessingContext > context = qgis::make_unique< QgsProcessingContext >();
context->setProject( &p );
QVariantMap parameters;
parameters.insert( QStringLiteral( "INPUT" ), myDataPath + inputRaster );
parameters.insert( QStringLiteral( "BAND" ), inputBand );
parameters.insert( QStringLiteral( "FILL_VALUE" ), fillValue );
parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT );
//prepare expectedRaster
std::unique_ptr<QgsRasterLayer> expectedRasterLayer = qgis::make_unique< QgsRasterLayer >( myDataPath + "/control_images/fillNoData/" + expectedRaster, "expectedDataset", "gdal" );
std::unique_ptr< QgsRasterInterface > expectedInterface( expectedRasterLayer->dataProvider()->clone() );
QgsRasterIterator expectedIter( expectedInterface.get() );
expectedIter.startRasterRead( 1, expectedRasterLayer->width(), expectedRasterLayer->height(), expectedInterface->extent() );
//run alg...
bool ok = false;
QgsProcessingFeedback feedback;
QVariantMap results;
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );
//...and check results with expected datasets
std::unique_ptr<QgsRasterLayer> outputRaster = qgis::make_unique< QgsRasterLayer >( results.value( QStringLiteral( "OUTPUT" ) ).toString(), "output", "gdal" );
std::unique_ptr< QgsRasterInterface > outputInterface( outputRaster->dataProvider()->clone() );
QCOMPARE( outputRaster->width(), expectedRasterLayer->width() );
QCOMPARE( outputRaster->height(), expectedRasterLayer->height() );
QgsRasterIterator outputIter( outputInterface.get() );
outputIter.startRasterRead( 1, outputRaster->width(), outputRaster->height(), outputInterface->extent() );
int outputIterLeft = 0;
int outputIterTop = 0;
int outputIterCols = 0;
int outputIterRows = 0;
int expectedIterLeft = 0;
int expectedIterTop = 0;
int expectedIterCols = 0;
int expectedIterRows = 0;
std::unique_ptr< QgsRasterBlock > outputRasterBlock;
std::unique_ptr< QgsRasterBlock > expectedRasterBlock;
while ( outputIter.readNextRasterPart( 1, outputIterCols, outputIterRows, outputRasterBlock, outputIterLeft, outputIterTop ) &&
expectedIter.readNextRasterPart( 1, expectedIterCols, expectedIterRows, expectedRasterBlock, expectedIterLeft, expectedIterTop ) )
{
for ( int row = 0; row < expectedIterRows; row++ )
{
for ( int column = 0; column < expectedIterCols; column++ )
{
double expectedValue = expectedRasterBlock->value( row, column );
double outputValue = outputRasterBlock->value( row, column );
QCOMPARE( outputValue, expectedValue );
}
}
}
}
void TestQgsProcessingAlgs::lineDensity_data() void TestQgsProcessingAlgs::lineDensity_data()
{ {
QTest::addColumn<QString>( "inputDataset" ); QTest::addColumn<QString>( "inputDataset" );

Binary file not shown.

View File

@ -0,0 +1,10 @@
<PAMDataset>
<PAMRasterBand band="1">
<Metadata>
<MDI key="STATISTICS_MAXIMUM">32767</MDI>
<MDI key="STATISTICS_MEAN">1887.7</MDI>
<MDI key="STATISTICS_MINIMUM">-32111</MDI>
<MDI key="STATISTICS_STDDEV">17198.274992278</MDI>
</Metadata>
</PAMRasterBand>
</PAMDataset>

Binary file not shown.

View File

@ -0,0 +1,10 @@
<PAMDataset>
<PAMRasterBand band="1">
<Metadata>
<MDI key="STATISTICS_MAXIMUM">32767</MDI>
<MDI key="STATISTICS_MEAN">1887.51</MDI>
<MDI key="STATISTICS_MINIMUM">-32111</MDI>
<MDI key="STATISTICS_STDDEV">17198.295829236</MDI>
</Metadata>
</PAMRasterBand>
</PAMDataset>

Binary file not shown.

View File

@ -0,0 +1,10 @@
<PAMDataset>
<PAMRasterBand band="1">
<Metadata>
<MDI key="STATISTICS_MAXIMUM">3.3999999521444e+38</MDI>
<MDI key="STATISTICS_MEAN">1.9584000167522e+37</MDI>
<MDI key="STATISTICS_MINIMUM">-3.3319999287626e+38</MDI>
<MDI key="STATISTICS_STDDEV">1.7845894905146e+38</MDI>
</Metadata>
</PAMRasterBand>
</PAMDataset>