Skip to content

Commit 8729073

Browse files
committed
Unit tests for reclassification utils
1 parent c5966b4 commit 8729073

4 files changed

Lines changed: 241 additions & 43 deletions

File tree

src/analysis/processing/qgsreclassifyutils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ void QgsReclassifyUtils::reclassify( const QVector<QgsReclassifyUtils::RasterCla
3939
iter.setMaximumTileHeight( maxHeight );
4040
iter.startRasterRead( band, sourceWidthPixels, sourceHeightPixels, extent );
4141

42-
int nbBlocksWidth = std::ceil( 1.0 * sourceWidthPixels / maxWidth );
43-
int nbBlocksHeight = std::ceil( 1.0 * sourceHeightPixels / maxHeight );
42+
int nbBlocksWidth = static_cast< int >( std::ceil( 1.0 * sourceWidthPixels / maxWidth ) );
43+
int nbBlocksHeight = static_cast< int >( std::ceil( 1.0 * sourceHeightPixels / maxHeight ) );
4444
int nbBlocks = nbBlocksWidth * nbBlocksHeight;
4545

4646
int iterLeft = 0;

tests/src/analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ SET(TESTS
7373
testqgsprocessingalgs.cpp
7474
testqgszonalstatistics.cpp
7575
testqgsrastercalculator.cpp
76+
testqgsreclassifyutils.cpp
7677
testqgsalignraster.cpp
7778
testqgsnetworkanalysis.cpp
7879
testqgsninecellfilters.cpp

tests/src/analysis/testqgsprocessingalgs.cpp

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "qgsnativealgorithms.h"
2626
#include "qgsalgorithmimportphotos.h"
2727
#include "qgsalgorithmtransform.h"
28-
#include "qgsreclassifyutils.h"
2928

3029
class TestQgsProcessingAlgs: public QObject
3130
{
@@ -42,7 +41,6 @@ class TestQgsProcessingAlgs: public QObject
4241
void parseGeoTags();
4342
void featureFilterAlg();
4443
void transformAlg();
45-
void reclassifyValue();
4644

4745
private:
4846

@@ -437,45 +435,6 @@ void TestQgsProcessingAlgs::transformAlg()
437435
QVERIFY( ok );
438436
}
439437

440-
void TestQgsProcessingAlgs::reclassifyValue()
441-
{
442-
// no classes
443-
bool ok = false;
444-
QVector< QgsReclassifyUtils::RasterClass > classes;
445-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5.9, ok ), 5.9 );
446-
QVERIFY( !ok );
447-
448-
// one class
449-
classes << QgsReclassifyUtils::RasterClass( 5, 11, QgsRasterRange::IncludeMin, -99.5 );
450-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5.9, ok ), -99.5 );
451-
QVERIFY( ok );
452-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 15.9, ok ), 15.9 );
453-
QVERIFY( !ok );
454-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, -15.9, ok ), -15.9 );
455-
QVERIFY( !ok );
456-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5, ok ), -99.5 );
457-
QVERIFY( ok );
458-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 11, ok ), 11.0 );
459-
QVERIFY( !ok );
460-
461-
// second class
462-
classes << QgsReclassifyUtils::RasterClass( 11, 15, QgsRasterRange::IncludeMin, -59.5 );
463-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5.9, ok ), -99.5 );
464-
QVERIFY( ok );
465-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 11.9, ok ), -59.5 );
466-
QVERIFY( ok );
467-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 15.9, ok ), 15.9 );
468-
QVERIFY( !ok );
469-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, -15.9, ok ), -15.9 );
470-
QVERIFY( !ok );
471-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5, ok ), -99.5 );
472-
QVERIFY( ok );
473-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 11, ok ), -59.5 );
474-
QVERIFY( ok );
475-
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 15, ok ), 15.0 );
476-
QVERIFY( !ok );
477-
}
478-
479438

480439
QGSTEST_MAIN( TestQgsProcessingAlgs )
481440
#include "testqgsprocessingalgs.moc"
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/***************************************************************************
2+
testqgsreclassifyutils.cpp
3+
---------------------
4+
begin : June 2018
5+
copyright : (C) 2018 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgstest.h"
19+
#include "qgsreclassifyutils.h"
20+
#include "qgsrasterdataprovider.h"
21+
#include "qgsrasterfilewriter.h"
22+
23+
class TestQgsReclassifyUtils: public QObject
24+
{
25+
Q_OBJECT
26+
27+
private slots:
28+
void initTestCase();// will be called before the first testfunction is executed.
29+
void cleanupTestCase(); // will be called after the last testfunction was executed.
30+
void init() {} // will be called before each testfunction is executed.
31+
void cleanup() {} // will be called after every testfunction.
32+
void reclassifyValue();
33+
void testReclassify_data();
34+
void testReclassify();
35+
36+
private:
37+
38+
QVector<double> reclassifyBlock( const QVector<double> &input, int nRows, int nCols,
39+
const QVector< QgsReclassifyUtils::RasterClass > &classes,
40+
double destNoDataValue, bool useNoDataForMissing );
41+
42+
};
43+
44+
void TestQgsReclassifyUtils::initTestCase()
45+
{
46+
QgsApplication::init();
47+
QgsApplication::initQgis();
48+
}
49+
50+
void TestQgsReclassifyUtils::cleanupTestCase()
51+
{
52+
QgsApplication::exitQgis();
53+
}
54+
55+
void TestQgsReclassifyUtils::reclassifyValue()
56+
{
57+
// no classes
58+
bool ok = false;
59+
QVector< QgsReclassifyUtils::RasterClass > classes;
60+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5.9, ok ), 5.9 );
61+
QVERIFY( !ok );
62+
63+
// one class
64+
classes << QgsReclassifyUtils::RasterClass( 5, 11, QgsRasterRange::IncludeMin, -99.5 );
65+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5.9, ok ), -99.5 );
66+
QVERIFY( ok );
67+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 15.9, ok ), 15.9 );
68+
QVERIFY( !ok );
69+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, -15.9, ok ), -15.9 );
70+
QVERIFY( !ok );
71+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5, ok ), -99.5 );
72+
QVERIFY( ok );
73+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 11, ok ), 11.0 );
74+
QVERIFY( !ok );
75+
76+
// second class
77+
classes << QgsReclassifyUtils::RasterClass( 11, 15, QgsRasterRange::IncludeMin, -59.5 );
78+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5.9, ok ), -99.5 );
79+
QVERIFY( ok );
80+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 11.9, ok ), -59.5 );
81+
QVERIFY( ok );
82+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 15.9, ok ), 15.9 );
83+
QVERIFY( !ok );
84+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, -15.9, ok ), -15.9 );
85+
QVERIFY( !ok );
86+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 5, ok ), -99.5 );
87+
QVERIFY( ok );
88+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 11, ok ), -59.5 );
89+
QVERIFY( ok );
90+
QCOMPARE( QgsReclassifyUtils::reclassifyValue( classes, 15, ok ), 15.0 );
91+
QVERIFY( !ok );
92+
}
93+
94+
Q_DECLARE_METATYPE( QgsReclassifyUtils::RasterClass );
95+
96+
void TestQgsReclassifyUtils::testReclassify_data()
97+
{
98+
QTest::addColumn<QVector< double >>( "input" );
99+
QTest::addColumn<int>( "rows" );
100+
QTest::addColumn<int>( "cols" );
101+
QTest::addColumn<QVector< QgsReclassifyUtils::RasterClass >>( "classes" );
102+
QTest::addColumn<double>( "destNoDataValue" );
103+
QTest::addColumn<bool>( "useNoDataForMissing" );
104+
QTest::addColumn<QVector< double >>( "expected" );
105+
106+
QTest::newRow( "no change" ) << QVector< double > { 1, 2, 3, 4, 5, 6 }
107+
<< 3 << 2
108+
<< QVector< QgsReclassifyUtils::RasterClass >()
109+
<< -9999.0 << false
110+
<< QVector< double > { 1, 2, 3, 4, 5, 6 };
111+
112+
QTest::newRow( "one class" ) << QVector< double > { 1, 2, 3, 4, 5, 6 }
113+
<< 3 << 2
114+
<< ( QVector< QgsReclassifyUtils::RasterClass >()
115+
<< QgsReclassifyUtils::RasterClass( 3, 5, QgsRasterRange::IncludeMax, 8 ) )
116+
<< -9999.0 << false
117+
<< QVector< double > { 1, 2, 3, 8, 8, 6 };
118+
119+
QTest::newRow( "two class" ) << QVector< double > { 1, 2, 3, 4, 5, 6 }
120+
<< 3 << 2
121+
<< ( QVector< QgsReclassifyUtils::RasterClass >()
122+
<< QgsReclassifyUtils::RasterClass( 3, 5, QgsRasterRange::IncludeMax, 8 )
123+
<< QgsReclassifyUtils::RasterClass( 1, 3, QgsRasterRange::IncludeMin, -7 ) )
124+
<< -9999.0 << false
125+
<< QVector< double > { -7, -7, 3, 8, 8, 6 };
126+
127+
QTest::newRow( "with source no data" ) << QVector< double > { 1, 2, -9999, 4, 5, 6 }
128+
<< 3 << 2
129+
<< ( QVector< QgsReclassifyUtils::RasterClass >()
130+
<< QgsReclassifyUtils::RasterClass( 3, 5, QgsRasterRange::IncludeMinAndMax, 8 ) )
131+
<< -9999.0 << false
132+
<< QVector< double > { 1, 2, -9999, 8, 8, 6 };
133+
134+
QTest::newRow( "with dest no data" ) << QVector< double > { 1, 2, -9999, 4, 5, 6 }
135+
<< 3 << 2
136+
<< ( QVector< QgsReclassifyUtils::RasterClass >()
137+
<< QgsReclassifyUtils::RasterClass( 3, 5, QgsRasterRange::IncludeMinAndMax, 8 ) )
138+
<< -99.0 << false
139+
<< QVector< double > { 1, 2, -99, 8, 8, 6 };
140+
141+
QTest::newRow( "use no data for missing" ) << QVector< double > { 1, 2, -9999, 4, 5, 6 }
142+
<< 3 << 2
143+
<< ( QVector< QgsReclassifyUtils::RasterClass >()
144+
<< QgsReclassifyUtils::RasterClass( 3, 5, QgsRasterRange::IncludeMinAndMax, 8 ) )
145+
<< -9999.0 << true
146+
<< QVector< double > { -9999, -9999, -9999, 8, 8, -9999 };
147+
}
148+
149+
void TestQgsReclassifyUtils::testReclassify()
150+
{
151+
QFETCH( QVector< double >, input );
152+
QFETCH( int, rows );
153+
QFETCH( int, cols );
154+
QFETCH( QVector< QgsReclassifyUtils::RasterClass >, classes );
155+
QFETCH( double, destNoDataValue );
156+
QFETCH( bool, useNoDataForMissing );
157+
QFETCH( QVector< double >, expected );
158+
159+
QVector< double > res = reclassifyBlock( input, 2, 3, classes, destNoDataValue, useNoDataForMissing );
160+
for ( int row = 0; row < rows; row++ )
161+
{
162+
for ( int col = 0; col < cols; col++ )
163+
{
164+
QCOMPARE( res[row * cols + col], expected[row * cols + col] );
165+
}
166+
}
167+
}
168+
169+
QVector< double > TestQgsReclassifyUtils::reclassifyBlock( const QVector< double > &input, int nRows, int nCols,
170+
const QVector< QgsReclassifyUtils::RasterClass > &classes,
171+
double destNoDataValue, bool useNoDataForMissing )
172+
{
173+
QgsRectangle extent = QgsRectangle( 0, 0, nRows, nCols );
174+
QgsCoordinateReferenceSystem crs( 3857 );
175+
double tform[] =
176+
{
177+
extent.xMinimum(), extent.width() / nCols, 0.0,
178+
extent.yMaximum(), 0.0, -extent.height() / nRows
179+
};
180+
181+
// generate unique filename (need to open the file first to generate it)
182+
QTemporaryFile tmpFile;
183+
tmpFile.open();
184+
tmpFile.close();
185+
186+
// create a GeoTIFF - this will create data provider in editable mode
187+
QString filename = tmpFile.fileName();
188+
189+
std::unique_ptr< QgsRasterFileWriter > writer = qgis::make_unique< QgsRasterFileWriter >( filename );
190+
writer->setOutputProviderKey( QStringLiteral( "gdal" ) );
191+
writer->setOutputFormat( QStringLiteral( "GTiff" ) );
192+
std::unique_ptr<QgsRasterDataProvider > dp( writer->createOneBandRaster( Qgis::Float32, nCols, nRows, extent, crs ) );
193+
dp->setNoDataValue( 1, -9999 );
194+
std::unique_ptr< QgsRasterBlock > block( dp->block( 1, extent, nCols, nRows ) );
195+
dp->setEditable( true );
196+
int i = 0;
197+
for ( int row = 0; row < nRows; row++ )
198+
{
199+
for ( int col = 0; col < nCols; col++ )
200+
{
201+
block->setValue( row, col, input[i++] );
202+
}
203+
}
204+
Q_ASSERT( dp->writeBlock( block.get(), 1 ) );
205+
dp->setEditable( false );
206+
207+
// make destination raster
208+
QTemporaryFile tmpFile2;
209+
tmpFile2.open();
210+
tmpFile2.close();
211+
212+
// create a GeoTIFF - this will create data provider in editable mode
213+
filename = tmpFile2.fileName();
214+
std::unique_ptr< QgsRasterDataProvider > dp2( QgsRasterDataProvider::create( QStringLiteral( "gdal" ), filename, QStringLiteral( "GTiff" ), 1, Qgis::Float32, 10, 10, tform, crs ) );
215+
216+
// reclassify
217+
dp2->setEditable( true );
218+
QgsReclassifyUtils::reclassify( classes, dp.get(), 1, extent, nCols, nRows, dp2.get(), destNoDataValue, useNoDataForMissing );
219+
dp2->setEditable( false );
220+
221+
// read back in values
222+
block.reset( dp2->block( 1, extent, nCols, nRows ) );
223+
QVector< double > res( nCols * nRows );
224+
i = 0;
225+
for ( int row = 0; row < nRows; row++ )
226+
{
227+
for ( int col = 0; col < nCols; col++ )
228+
{
229+
res[i++] = block->value( row, col );
230+
}
231+
}
232+
233+
return res;
234+
}
235+
236+
237+
QGSTEST_MAIN( TestQgsReclassifyUtils )
238+
#include "testqgsreclassifyutils.moc"

0 commit comments

Comments
 (0)