mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
[feature] add Fill noData cells algorithm and tests
This commit is contained in:
parent
d15ce6b4c3
commit
ea7167e135
@ -88,6 +88,7 @@
|
||||
<file>themes/default/algorithms/mAlgorithmCollect.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmConvexHull.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/mAlgorithmFuzzifyPower.svg</file>
|
||||
<file>themes/default/algorithms/mAlgorithmFuzzifyLarge.svg</file>
|
||||
|
162
images/themes/default/algorithms/mAlgorithmFillNoData.svg
Normal file
162
images/themes/default/algorithms/mAlgorithmFillNoData.svg
Normal 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 |
@ -64,6 +64,7 @@ SET(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmextractvertices.cpp
|
||||
processing/qgsalgorithmextractspecificvertices.cpp
|
||||
processing/qgsalgorithmfiledownloader.cpp
|
||||
processing/qgsalgorithmfillnodata.cpp
|
||||
processing/qgsalgorithmfilter.cpp
|
||||
processing/qgsalgorithmfiltervertices.cpp
|
||||
processing/qgsalgorithmfixgeometries.cpp
|
||||
|
157
src/analysis/processing/qgsalgorithmfillnodata.cpp
Normal file
157
src/analysis/processing/qgsalgorithmfillnodata.cpp
Normal 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 ¶meters, 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 ¶meters, 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
|
78
src/analysis/processing/qgsalgorithmfillnodata.h
Normal file
78
src/analysis/processing/qgsalgorithmfillnodata.h
Normal 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 ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QVariantMap processAlgorithm( const QVariantMap ¶meters,
|
||||
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
|
@ -59,6 +59,7 @@
|
||||
#include "qgsalgorithmextractspecificvertices.h"
|
||||
#include "qgsalgorithmextractzmvalues.h"
|
||||
#include "qgsalgorithmfiledownloader.h"
|
||||
#include "qgsalgorithmfillnodata.h"
|
||||
#include "qgsalgorithmfilter.h"
|
||||
#include "qgsalgorithmfiltervertices.h"
|
||||
#include "qgsalgorithmfixgeometries.h"
|
||||
@ -247,6 +248,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsExtractSpecificVerticesAlgorithm() );
|
||||
addAlgorithm( new QgsExtractZValuesAlgorithm() );
|
||||
addAlgorithm( new QgsFileDownloaderAlgorithm() );
|
||||
addAlgorithm( new QgsFillNoDataAlgorithm() );
|
||||
addAlgorithm( new QgsFilterAlgorithm() );
|
||||
addAlgorithm( new QgsFilterVerticesByM() );
|
||||
addAlgorithm( new QgsFilterVerticesByZ() );
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "qgsprocessingcontext.h"
|
||||
#include "qgsprocessingmodelalgorithm.h"
|
||||
#include "qgsnativealgorithms.h"
|
||||
#include "qgsalgorithmfillnodata.h"
|
||||
#include "qgsalgorithmlinedensity.h"
|
||||
#include "qgsalgorithmimportphotos.h"
|
||||
#include "qgsalgorithmtransform.h"
|
||||
@ -85,6 +86,8 @@ class TestQgsProcessingAlgs: public QObject
|
||||
void densifyGeometries_data();
|
||||
void densifyGeometries();
|
||||
|
||||
void fillNoData_data();
|
||||
void fillNoData();
|
||||
void lineDensity_data();
|
||||
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() );
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QTest::addColumn<QString>( "inputDataset" );
|
||||
|
BIN
tests/testdata/control_images/fillNoData/fillnodata_testcase1.tif
vendored
Normal file
BIN
tests/testdata/control_images/fillNoData/fillnodata_testcase1.tif
vendored
Normal file
Binary file not shown.
10
tests/testdata/control_images/fillNoData/fillnodata_testcase1.tif.aux.xml
vendored
Normal file
10
tests/testdata/control_images/fillNoData/fillnodata_testcase1.tif.aux.xml
vendored
Normal 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>
|
BIN
tests/testdata/control_images/fillNoData/fillnodata_testcase2.tif
vendored
Normal file
BIN
tests/testdata/control_images/fillNoData/fillnodata_testcase2.tif
vendored
Normal file
Binary file not shown.
10
tests/testdata/control_images/fillNoData/fillnodata_testcase2.tif.aux.xml
vendored
Normal file
10
tests/testdata/control_images/fillNoData/fillnodata_testcase2.tif.aux.xml
vendored
Normal 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>
|
BIN
tests/testdata/control_images/fillNoData/fillnodata_testcase3.tif
vendored
Normal file
BIN
tests/testdata/control_images/fillNoData/fillnodata_testcase3.tif
vendored
Normal file
Binary file not shown.
10
tests/testdata/control_images/fillNoData/fillnodata_testcase3.tif.aux.xml
vendored
Normal file
10
tests/testdata/control_images/fillNoData/fillnodata_testcase3.tif.aux.xml
vendored
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user