mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
New QgsRasterChecker class for raster comparison in tests.
New test for raster file writer.
This commit is contained in:
parent
8cb578f698
commit
e1091013af
@ -169,6 +169,7 @@ SET(QGIS_CORE_SRCS
|
||||
raster/qgslinearminmaxenhancement.cpp
|
||||
raster/qgslinearminmaxenhancementwithclip.cpp
|
||||
raster/qgspseudocolorshader.cpp
|
||||
raster/qgsrasterchecker.cpp
|
||||
raster/qgsrasterinterface.cpp
|
||||
raster/qgsrasteriterator.cpp
|
||||
raster/qgsrasterlayer.cpp
|
||||
@ -411,6 +412,7 @@ SET(QGIS_CORE_HDRS
|
||||
raster/qgslinearminmaxenhancement.h
|
||||
raster/qgslinearminmaxenhancementwithclip.h
|
||||
raster/qgspseudocolorshader.h
|
||||
raster/qgsrasterchecker.h
|
||||
raster/qgsrasterpyramid.h
|
||||
raster/qgsrasterbandstats.h
|
||||
raster/qgsrasterhistogram.h
|
||||
|
236
src/core/raster/qgsrasterchecker.cpp
Normal file
236
src/core/raster/qgsrasterchecker.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
/***************************************************************************
|
||||
qgsrasterchecker.cpp
|
||||
--------------------------------------
|
||||
Date : 5 Sep 2012
|
||||
Copyright : (C) 2012 by Radim Blazek
|
||||
Email : radim dot blazek 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 "qgsrasterchecker.h"
|
||||
#include "qgsrasterdataprovider.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
|
||||
#include <qmath.h>
|
||||
#include <QColor>
|
||||
#include <QPainter>
|
||||
#include <QImage>
|
||||
#include <QTime>
|
||||
#include <QCryptographicHash>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QBuffer>
|
||||
|
||||
QgsRasterChecker::QgsRasterChecker( ) :
|
||||
mReport( "" )
|
||||
{
|
||||
mTabStyle = "border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid;";
|
||||
mCellStyle = "border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center;";
|
||||
mOkStyle = "background: #00ff00;";
|
||||
mErrStyle = "background: #ff0000;";
|
||||
mErrMsgStyle = "color: #ff0000;";
|
||||
}
|
||||
|
||||
bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri,
|
||||
QString theExpectedKey, QString theExpectedUri )
|
||||
{
|
||||
bool ok = true;
|
||||
mReport += "\n\n";
|
||||
|
||||
QgsRasterDataProvider* verifiedProvider = QgsRasterLayer::loadProvider( theVerifiedKey, theVerifiedUri );
|
||||
if ( !verifiedProvider || !verifiedProvider->isValid() )
|
||||
{
|
||||
error( QString( "Cannot load provider %1 with URI: %2" ).arg( theVerifiedKey).arg( theVerifiedUri), mReport );
|
||||
ok = false;
|
||||
}
|
||||
|
||||
QgsRasterDataProvider* expectedProvider = QgsRasterLayer::loadProvider( theExpectedKey, theExpectedUri );
|
||||
if ( !expectedProvider || !expectedProvider->isValid() )
|
||||
{
|
||||
error( QString( "Cannot load provider %1 with URI: %2" ).arg( theExpectedKey).arg( theExpectedUri ), mReport );
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if ( !ok ) return false;
|
||||
|
||||
mReport += QString( "Verified URI: %1<br>" ).arg( theVerifiedUri.replace( "&", "&" ) );
|
||||
mReport += QString( "Expected URI: %1<br>" ).arg( theExpectedUri.replace( "&", "&" ) );
|
||||
|
||||
mReport += "<br>";
|
||||
mReport += QString("<table style='%1'>\n").arg( mTabStyle );
|
||||
mReport += compareHead();
|
||||
|
||||
compare( "Band count", verifiedProvider->bandCount(), expectedProvider->bandCount(), mReport, ok );
|
||||
|
||||
compare( "Width", verifiedProvider->xSize(), expectedProvider->xSize(), mReport, ok );
|
||||
compare( "Height", verifiedProvider->ySize(), expectedProvider->ySize(), mReport, ok );
|
||||
|
||||
compareRow( "Extent", verifiedProvider->extent().toString(), expectedProvider->extent().toString(), mReport, verifiedProvider->extent() == expectedProvider->extent() );
|
||||
|
||||
if ( verifiedProvider->extent() != expectedProvider->extent() ) ok = false;
|
||||
|
||||
compare( "No data (NULL) value", verifiedProvider->noDataValue(), expectedProvider->noDataValue(), mReport, ok );
|
||||
|
||||
mReport += "</table>\n";
|
||||
|
||||
if ( !ok ) return false;
|
||||
|
||||
bool allOk = true;
|
||||
for ( int band = 1; band <= expectedProvider->bandCount(); band++ )
|
||||
{
|
||||
bool bandOk = true;
|
||||
mReport += QString( "<h3>Band %1</h3>\n" ).arg( band );
|
||||
mReport += QString("<table style='%1'>\n").arg( mTabStyle );
|
||||
mReport += compareHead();
|
||||
|
||||
// Data types may differ (?)
|
||||
bool typesOk = true;
|
||||
compare( "Source data type", verifiedProvider->srcDataType( band ), expectedProvider->srcDataType( band ), mReport, typesOk );
|
||||
compare( "Data type", verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk ) ;
|
||||
|
||||
bool statsOk = true;
|
||||
QgsRasterBandStats verifiedStats = verifiedProvider->bandStatistics( band );
|
||||
QgsRasterBandStats expectedStats = expectedProvider->bandStatistics( band );
|
||||
|
||||
// Min/max may 'slightly' differ, for big numbers however, the difference may
|
||||
// be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24
|
||||
double tol = tolerance( expectedStats.minimumValue );
|
||||
compare( "Minimum value", verifiedStats.minimumValue, expectedStats.minimumValue, mReport, statsOk, tol );
|
||||
tol = tolerance( expectedStats.maximumValue );
|
||||
compare( "Maximum value", verifiedStats.maximumValue, expectedStats.maximumValue, mReport, statsOk, tol );
|
||||
|
||||
// TODO: enable once fixed (WCS excludes nulls but GDAL does not)
|
||||
//compare( "Cells count", verifiedStats.elementCount, expectedStats.elementCount, mReport, statsOk );
|
||||
|
||||
tol = tolerance( expectedStats.mean );
|
||||
compare( "Mean", verifiedStats.mean, expectedStats.mean, mReport, statsOk, tol );
|
||||
|
||||
// stdDev usually differ significantly
|
||||
tol = tolerance( expectedStats.stdDev, 1 );
|
||||
compare( "Standard deviation", verifiedStats.stdDev, expectedStats.stdDev, mReport, statsOk, tol );
|
||||
|
||||
mReport += "</table>";
|
||||
mReport += "<br>";
|
||||
|
||||
if ( !bandOk )
|
||||
{
|
||||
allOk = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !statsOk || !typesOk )
|
||||
{
|
||||
allOk = false;
|
||||
// create values table anyway so that values are available
|
||||
}
|
||||
|
||||
mReport += "<table><tr>";
|
||||
mReport += "<td>Data comparison</td>";
|
||||
mReport += QString( "<td style='%1 %2 border: 1px solid'>correct value</td>" ).arg( mCellStyle).arg( mOkStyle );
|
||||
mReport += "<td></td>";
|
||||
mReport += QString( "<td style='%1 %2 border: 1px solid'>wrong value<br>expected value</td></tr>").arg( mCellStyle).arg( mErrStyle );
|
||||
mReport += "</tr></table>";
|
||||
mReport += "<br>";
|
||||
|
||||
int width = expectedProvider->xSize();
|
||||
int height = expectedProvider->ySize();
|
||||
int blockSize = width * height * expectedProvider->typeSize( expectedProvider->dataType( band ) ) ;
|
||||
void * expectedData = malloc( blockSize );
|
||||
void * verifiedData = malloc( blockSize );
|
||||
|
||||
expectedProvider->readBlock( band, expectedProvider->extent(), width, height, expectedData );
|
||||
verifiedProvider->readBlock( band, expectedProvider->extent(), width, height, verifiedData );
|
||||
|
||||
// compare data values
|
||||
QString htmlTable = QString("<table style='%1'>").arg( mTabStyle );
|
||||
for ( int row = 0; row < height; row ++ )
|
||||
{
|
||||
htmlTable += "<tr>";
|
||||
for ( int col = 0; col < width; col ++ )
|
||||
{
|
||||
bool cellOk = true;
|
||||
double verifiedVal = verifiedProvider->readValue( verifiedData, verifiedProvider->dataType( band ), row * width + col );
|
||||
double expectedVal = expectedProvider->readValue( expectedData, expectedProvider->dataType( band ), row * width + col );
|
||||
|
||||
QString valStr;
|
||||
if ( compare( verifiedVal, expectedVal, 0 ) )
|
||||
{
|
||||
valStr = QString( "%1" ).arg( verifiedVal );
|
||||
}
|
||||
else
|
||||
{
|
||||
cellOk = false;
|
||||
allOk = false;
|
||||
valStr = QString( "%1<br>%2" ).arg( verifiedVal ).arg( expectedVal );
|
||||
}
|
||||
htmlTable += QString( "<td style='%1 %2'>%3</td>" ).arg( mCellStyle).arg( cellOk ? mOkStyle : mErrStyle ).arg( valStr );
|
||||
}
|
||||
htmlTable += "</tr>";
|
||||
}
|
||||
htmlTable += "</table>";
|
||||
|
||||
mReport += htmlTable;
|
||||
|
||||
free( expectedData );
|
||||
free( verifiedData );
|
||||
}
|
||||
delete verifiedProvider;
|
||||
delete expectedProvider;
|
||||
return allOk;
|
||||
}
|
||||
|
||||
void QgsRasterChecker::error( QString theMessage, QString &theReport )
|
||||
{
|
||||
theReport += QString( "<font style='%1'>Error: ").arg(mErrMsgStyle);
|
||||
theReport += theMessage;
|
||||
theReport += "</font>";
|
||||
}
|
||||
|
||||
double QgsRasterChecker::tolerance( double val, int places )
|
||||
{
|
||||
// float precision is about 7 decimal digits, double about 16
|
||||
// default places = 6
|
||||
return 1. * qPow( 10, qRound( log10( qAbs( val ) ) - places ) );
|
||||
}
|
||||
|
||||
QString QgsRasterChecker::compareHead()
|
||||
{
|
||||
QString html;
|
||||
html += QString( "<tr><th style='%1'>Param name</th><th style='%1'>Verified value</th><th style='%1'>Eexpected value</th><th style='%1'>Difference</th><th style='%1'>Tolerance</th></tr>").arg( mCellStyle );
|
||||
return html;
|
||||
}
|
||||
|
||||
void QgsRasterChecker::compare( QString theParamName, int verifiedVal, int expectedVal, QString &theReport, bool &theOk )
|
||||
{
|
||||
bool ok = verifiedVal == expectedVal;
|
||||
compareRow( theParamName, QString::number( verifiedVal ), QString::number( expectedVal ), theReport, ok, QString::number( verifiedVal - expectedVal ) );
|
||||
if ( !ok ) theOk = false;
|
||||
}
|
||||
|
||||
bool QgsRasterChecker::compare( double verifiedVal, double expectedVal, double theTolerance )
|
||||
{
|
||||
// values may be nan
|
||||
return ( qIsNaN( verifiedVal ) && qIsNaN( expectedVal ) ) || ( qAbs( verifiedVal - expectedVal ) <= theTolerance );
|
||||
}
|
||||
|
||||
void QgsRasterChecker::compare( QString theParamName, double verifiedVal, double expectedVal, QString &theReport, bool &theOk, double theTolerance )
|
||||
{
|
||||
bool ok = compare( verifiedVal, expectedVal, theTolerance );
|
||||
compareRow( theParamName, QString::number( verifiedVal ), QString::number( expectedVal ), theReport, ok, QString::number( verifiedVal - expectedVal ), QString::number( theTolerance ) );
|
||||
if ( !ok ) theOk = false;
|
||||
}
|
||||
|
||||
void QgsRasterChecker::compareRow( QString theParamName, QString verifiedVal, QString expectedVal, QString &theReport, bool theOk, QString theDifference, QString theTolerance )
|
||||
{
|
||||
theReport += "<tr>\n";
|
||||
theReport += QString( "<td style='%1'>%2</td><td style='%1 %3'>%4</td><td style='%1'>%5</td>\n" ).arg(mCellStyle).arg( theParamName ).arg( theOk ? mOkStyle : mErrStyle ).arg( verifiedVal ).arg( expectedVal );
|
||||
theReport += QString( "<td style='%1'>%2</td>\n" ).arg(mCellStyle).arg( theDifference );
|
||||
theReport += QString( "<td style='%1'>%2</td>\n" ).arg(mCellStyle).arg( theTolerance );
|
||||
theReport += "</tr>";
|
||||
}
|
71
src/core/raster/qgsrasterchecker.h
Normal file
71
src/core/raster/qgsrasterchecker.h
Normal file
@ -0,0 +1,71 @@
|
||||
/***************************************************************************
|
||||
qgsrasterchecker.h - compare two rasters
|
||||
--------------------------------------
|
||||
Date : 5 Sep 2012
|
||||
Copyright : (C) 2012 by Radim Blazek
|
||||
email : radim dot blazek 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 QGSRASTERCHECKER_H
|
||||
#define QGSRASTERCHECKER_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <qgsmaprenderer.h>
|
||||
class QImage;
|
||||
|
||||
/** \ingroup UnitTests
|
||||
* This is a helper class for unit tests that need to
|
||||
* write an image and compare it to an expected result
|
||||
* or render time.
|
||||
*/
|
||||
class CORE_EXPORT QgsRasterChecker
|
||||
{
|
||||
public:
|
||||
|
||||
QgsRasterChecker();
|
||||
|
||||
//! Destructor
|
||||
~QgsRasterChecker() {};
|
||||
|
||||
QString controlImagePath() const;
|
||||
|
||||
QString report() { return mReport; };
|
||||
/**
|
||||
* Test using renderer to generate the image to be compared.
|
||||
* @param theVerifiedKey verified provider key
|
||||
* @param theVerifiedUri URI of the raster to be verified
|
||||
* @param theExpectedKey expected provider key
|
||||
* @param theExpectedUri URI of the expected (control) raster
|
||||
*/
|
||||
bool runTest( QString theVerifiedKey, QString theVerifiedUri,
|
||||
QString theExpectedKey, QString theExpectedUri );
|
||||
private:
|
||||
QString mReport;
|
||||
QString mExpectedUri;
|
||||
QString mCheckedUri;
|
||||
QString mTabStyle;
|
||||
QString mCellStyle;
|
||||
QString mOkStyle;
|
||||
QString mErrStyle;
|
||||
QString mErrMsgStyle;
|
||||
|
||||
// Log error in html
|
||||
void error( QString theMessage, QString &theReport );
|
||||
// compare values and add table row in html report, set ok to false if not equal
|
||||
QString compareHead();
|
||||
bool compare( double verifiedVal, double expectedVal, double theTolerance );
|
||||
void compare( QString theParamName, int verifiedVal, int expectedVal, QString &theReport, bool &theOk );
|
||||
void compare( QString theParamName, double verifiedVal, double expectedVal, QString &theReport, bool &theOk, double theTolerance = 0 );
|
||||
void compareRow( QString theParamName, QString verifiedVal, QString expectedVal, QString &theReport, bool theOk, QString theDifference = "", QString theTolerance = "" );
|
||||
double tolerance( double val, int places = 6 );
|
||||
}; // class QgsRasterChecker
|
||||
|
||||
#endif
|
@ -85,6 +85,7 @@ ADD_QGIS_TEST(filewritertest testqgsvectorfilewriter.cpp)
|
||||
ADD_QGIS_TEST(regression992 regression992.cpp)
|
||||
ADD_QGIS_TEST(regression1141 regression1141.cpp)
|
||||
ADD_QGIS_TEST(rasterlayertest testqgsrasterlayer.cpp)
|
||||
ADD_QGIS_TEST(rasterfilewritertest testqgsrasterfilewriter.cpp)
|
||||
ADD_QGIS_TEST(contrastenhancementtest testcontrastenhancements.cpp)
|
||||
ADD_QGIS_TEST(maplayertest testqgsmaplayer.cpp)
|
||||
ADD_QGIS_TEST(rendererstest testqgsrenderers.cpp)
|
||||
|
184
tests/src/core/testqgsrasterfilewriter.cpp
Normal file
184
tests/src/core/testqgsrasterfilewriter.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/***************************************************************************
|
||||
testqgsrasterfilewriter.cpp
|
||||
--------------------------------------
|
||||
Date : 5 Sep 2012
|
||||
Copyright : (C) 2012 by Radim Blazek
|
||||
Email : radim dot blazek 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 <QtTest>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QObject>
|
||||
#include <iostream>
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QPainter>
|
||||
#include <QTime>
|
||||
#include <QDesktopServices>
|
||||
|
||||
//qgis includes...
|
||||
#include <qgsrasterchecker.h>
|
||||
#include <qgsrasterlayer.h>
|
||||
#include <qgsrasterfilewriter.h>
|
||||
#include <qgsrasternuller.h>
|
||||
#include <qgsapplication.h>
|
||||
|
||||
/** \ingroup UnitTests
|
||||
* This is a unit test for the QgsRasterFileWriter class.
|
||||
*/
|
||||
class TestQgsRasterFileWriter: public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init() {};// will be called before each testfunction is executed.
|
||||
void cleanup() {};// will be called after every testfunction.
|
||||
|
||||
void writeTest();
|
||||
private:
|
||||
bool writeTest( QString rasterName );
|
||||
void log ( QString msg );
|
||||
void logError ( QString msg );
|
||||
QString mTestDataDir;
|
||||
QString mReport;
|
||||
};
|
||||
|
||||
//runs before all tests
|
||||
void TestQgsRasterFileWriter::initTestCase()
|
||||
{
|
||||
// init QGIS's paths - true means that all path will be inited from prefix
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
// disable any PAM stuff to make sure stats are consistent
|
||||
CPLSetConfigOption( "GDAL_PAM_ENABLED", "NO" );
|
||||
QString mySettings = QgsApplication::showSettings();
|
||||
mySettings = mySettings.replace( "\n", "<br />" );
|
||||
//create some objects that will be used in all tests...
|
||||
//create a raster layer that will be used in all tests...
|
||||
mTestDataDir = QString( TEST_DATA_DIR ) + QDir::separator(); //defined in CmakeLists.txt
|
||||
mReport += "<h1>Raster File Writer Tests</h1>\n";
|
||||
mReport += "<p>" + mySettings + "</p>";
|
||||
}
|
||||
//runs after all tests
|
||||
void TestQgsRasterFileWriter::cleanupTestCase()
|
||||
{
|
||||
QString myReportFile = QDir::tempPath() + QDir::separator() + "qgistest.html";
|
||||
QFile myFile( myReportFile );
|
||||
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
{
|
||||
QTextStream myQTextStream( &myFile );
|
||||
myQTextStream << mReport;
|
||||
myFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsRasterFileWriter::writeTest()
|
||||
{
|
||||
QDir dir( mTestDataDir + "/raster" );
|
||||
|
||||
QStringList filters;
|
||||
filters << "*.tif";
|
||||
QStringList rasterNames = dir.entryList( filters, QDir::Files );
|
||||
bool allOK = true;
|
||||
foreach ( QString rasterName, rasterNames )
|
||||
{
|
||||
bool ok = writeTest( "raster/" + rasterName );
|
||||
if ( !ok ) allOK = false;
|
||||
}
|
||||
|
||||
QVERIFY( allOK );
|
||||
}
|
||||
|
||||
bool TestQgsRasterFileWriter::writeTest( QString theRasterName )
|
||||
{
|
||||
mReport += "<h2>" + theRasterName + "</h2>\n";
|
||||
|
||||
QString myFileName = mTestDataDir + "/" + theRasterName;
|
||||
qDebug() << myFileName;
|
||||
QFileInfo myRasterFileInfo( myFileName );
|
||||
|
||||
QgsRasterLayer * mpRasterLayer = new QgsRasterLayer( myRasterFileInfo.filePath(),
|
||||
myRasterFileInfo.completeBaseName() );
|
||||
qDebug() << theRasterName << " metadata: " << mpRasterLayer->dataProvider()->metadata();
|
||||
|
||||
if ( !mpRasterLayer->isValid() ) return false;
|
||||
|
||||
// Open provider only (avoid layer)?
|
||||
QgsRasterDataProvider * provider = mpRasterLayer->dataProvider();
|
||||
|
||||
// I don't see any method to get only a name without opening file
|
||||
QTemporaryFile tmpFile;
|
||||
tmpFile.open(); // fileName is no avialable until open
|
||||
QString tmpName = tmpFile.fileName();
|
||||
tmpFile.close();
|
||||
// do not remove when class is destroyd so that we can read the file and see difference
|
||||
tmpFile.setAutoRemove ( false );
|
||||
qDebug() << "temporary output file: " << tmpName;
|
||||
mReport += "temporary output file: " + tmpName + "<br>";
|
||||
|
||||
QgsRasterFileWriter fileWriter( tmpName );
|
||||
QgsRasterPipe* pipe = new QgsRasterPipe();
|
||||
if ( !pipe->set( provider->clone() ) )
|
||||
{
|
||||
logError ( "Cannot set pipe provider" );
|
||||
return false;
|
||||
}
|
||||
qDebug() << "provider set";
|
||||
|
||||
// Nuller currently is not really used
|
||||
QgsRasterNuller *nuller = new QgsRasterNuller();
|
||||
//nuller->setNoData( ... );
|
||||
if ( !pipe->insert( 1, nuller ) )
|
||||
{
|
||||
logError( "Cannot set pipe nuller" );
|
||||
return false;
|
||||
}
|
||||
qDebug() << "nuller set";
|
||||
|
||||
// Reprojection not really done
|
||||
QgsRasterProjector *projector = new QgsRasterProjector;
|
||||
projector->setCRS( provider->crs(), provider->crs() );
|
||||
if ( !pipe->insert( 2, projector ) )
|
||||
{
|
||||
logError( "Cannot set pipe projector" );
|
||||
return false;
|
||||
}
|
||||
qDebug() << "projector set";
|
||||
|
||||
fileWriter.writeRaster( pipe, provider->xSize() + 1, provider->ySize(), provider->extent(), provider->crs() );
|
||||
|
||||
delete pipe;
|
||||
|
||||
QgsRasterChecker checker;
|
||||
bool ok = checker.runTest( "gdal", tmpName, "gdal", myRasterFileInfo.filePath() );
|
||||
mReport += checker.report();
|
||||
|
||||
// All OK, we can delete the file
|
||||
tmpFile.setAutoRemove ( ok );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TestQgsRasterFileWriter::log ( QString msg )
|
||||
{
|
||||
mReport += msg + "<br>";
|
||||
}
|
||||
|
||||
void TestQgsRasterFileWriter::logError ( QString msg )
|
||||
{
|
||||
mReport += "Error:<font color='red'>" + msg + "</font><br>";
|
||||
qDebug() << msg;
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsRasterFileWriter )
|
||||
#include "moc_testqgsrasterfilewriter.cxx"
|
@ -24,6 +24,7 @@
|
||||
#include <qgsdatasourceuri.h>
|
||||
#include <qgsrasterlayer.h>
|
||||
#include <qgsrasterdataprovider.h>
|
||||
#include <qgsrasterchecker.h>
|
||||
#include <qgsproviderregistry.h>
|
||||
#include <qgsapplication.h>
|
||||
|
||||
@ -44,15 +45,6 @@ class TestQgsWcsProvider: public QObject
|
||||
void read();
|
||||
private:
|
||||
bool read( QString theIdentifier, QString theWcsUri, QString theFilePath, QString & theReport );
|
||||
// Log error in html
|
||||
void error( QString theMessage, QString &theReport );
|
||||
// compare values and add table row in html report, set ok to false if not equal
|
||||
QString compareHead();
|
||||
bool compare( double wcsVal, double gdalVal, double theTolerance );
|
||||
void compare( QString theParamName, int wcsVal, int gdalVal, QString &theReport, bool &theOk );
|
||||
void compare( QString theParamName, double wcsVal, double gdalVal, QString &theReport, bool &theOk, double theTolerance = 0 );
|
||||
void compareRow( QString theParamName, QString wcsVal, QString gdalVal, QString &theReport, bool theOk, QString theDifference = "", QString theTolerance = "" );
|
||||
double tolerance( double val, int places = 6 );
|
||||
QString mTestDataDir;
|
||||
QString mReport;
|
||||
QString mUrl;
|
||||
@ -68,7 +60,8 @@ void TestQgsWcsProvider::initTestCase()
|
||||
mySettings = mySettings.replace( "\n", "<br />" );
|
||||
mReport += "<h1>WCS provider tests</h1>\n";
|
||||
mReport += "<p>" + mySettings + "</p>";
|
||||
|
||||
// Style is now inlined by QgsRasterChecker
|
||||
#if 0
|
||||
mReport += "<style>";
|
||||
mReport += ".tab { border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid; }";
|
||||
mReport += ".cell { border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center}";
|
||||
@ -76,8 +69,7 @@ void TestQgsWcsProvider::initTestCase()
|
||||
mReport += ".err { background: #ff0000; }";
|
||||
mReport += ".errmsg { color: #ff0000; }";
|
||||
mReport += "</style>";
|
||||
|
||||
|
||||
#endif
|
||||
//create some objects that will be used in all tests...
|
||||
//create a raster layer that will be used in all tests...
|
||||
mTestDataDir = QString( TEST_DATA_DIR ) + "/raster";
|
||||
@ -89,10 +81,9 @@ void TestQgsWcsProvider::initTestCase()
|
||||
//runs after all tests
|
||||
void TestQgsWcsProvider::cleanupTestCase()
|
||||
{
|
||||
QString myReportFile = QDir::tempPath() + "/qgiswcstest.html";
|
||||
QString myReportFile = QDir::tempPath() + "/qgistest.html";
|
||||
QFile myFile( myReportFile );
|
||||
//if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
if ( myFile.open( QIODevice::WriteOnly ) )
|
||||
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
{
|
||||
QTextStream myQTextStream( &myFile );
|
||||
myQTextStream << mReport;
|
||||
@ -141,198 +132,13 @@ void TestQgsWcsProvider::read( )
|
||||
|
||||
bool TestQgsWcsProvider::read( QString theIdentifier, QString theWcsUri, QString theFilePath, QString & theReport )
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
theReport += QString( "<h2>Identifier (coverage): %1</h2>" ).arg( theIdentifier );
|
||||
|
||||
QgsRasterDataProvider* wcsProvider = QgsRasterLayer::loadProvider( "wcs", theWcsUri );
|
||||
if ( !wcsProvider || !wcsProvider->isValid() )
|
||||
{
|
||||
error( QString( "Cannot load WCS provider with URI: %1" ).arg( QString( theWcsUri ) ), theReport );
|
||||
ok = false;
|
||||
}
|
||||
QgsRasterChecker checker;
|
||||
bool ok = checker.runTest( "wcs", theWcsUri, "gdal", theFilePath );
|
||||
|
||||
QgsRasterDataProvider* gdalProvider = QgsRasterLayer::loadProvider( "gdal", theFilePath );
|
||||
if ( !gdalProvider || !gdalProvider->isValid() )
|
||||
{
|
||||
error( QString( "Cannot load GDAL provider with URI: %1" ).arg( theFilePath ), theReport );
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if ( !ok ) return false;
|
||||
|
||||
theReport += QString( "WCS URI: %1<br>" ).arg( theWcsUri.replace( "&", "&" ) );
|
||||
theReport += QString( "GDAL URI: %1<br>" ).arg( theFilePath );
|
||||
|
||||
theReport += "<br>";
|
||||
theReport += "<table class='tab'>";
|
||||
theReport += compareHead();
|
||||
|
||||
compare( "Band count", wcsProvider->bandCount(), gdalProvider->bandCount(), theReport, ok );
|
||||
|
||||
compare( "Width", wcsProvider->xSize(), gdalProvider->xSize(), theReport, ok );
|
||||
compare( "Height", wcsProvider->ySize(), gdalProvider->ySize(), theReport, ok );
|
||||
|
||||
compareRow( "Extent", wcsProvider->extent().toString(), gdalProvider->extent().toString(), theReport, wcsProvider->extent() == gdalProvider->extent() );
|
||||
if ( wcsProvider->extent() != gdalProvider->extent() ) ok = false;
|
||||
|
||||
if ( !ok ) return false;
|
||||
|
||||
compare( "No data (NULL) value", wcsProvider->noDataValue(), gdalProvider->noDataValue(), theReport, ok );
|
||||
|
||||
theReport += "</table>";
|
||||
|
||||
|
||||
bool allOk = true;
|
||||
for ( int band = 1; band <= gdalProvider->bandCount(); band++ )
|
||||
{
|
||||
bool bandOk = true;
|
||||
theReport += QString( "<h3>Band %1</h3>" ).arg( band );
|
||||
theReport += "<table class='tab'>";
|
||||
theReport += compareHead();
|
||||
|
||||
// Data types may differ (?)
|
||||
bool typesOk = true;
|
||||
compare( "Source data type", wcsProvider->srcDataType( band ), gdalProvider->srcDataType( band ), theReport, typesOk );
|
||||
compare( "Data type", wcsProvider->dataType( band ), gdalProvider->dataType( band ), theReport, typesOk ) ;
|
||||
|
||||
bool statsOk = true;
|
||||
QgsRasterBandStats wcsStats = wcsProvider->bandStatistics( band );
|
||||
QgsRasterBandStats gdalStats = gdalProvider->bandStatistics( band );
|
||||
|
||||
// Min/max may 'slightly' differ, for big numbers however, the difference may
|
||||
// be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24
|
||||
double tol = tolerance( gdalStats.minimumValue );
|
||||
compare( "Minimum value", wcsStats.minimumValue, gdalStats.minimumValue, theReport, statsOk, tol );
|
||||
tol = tolerance( gdalStats.maximumValue );
|
||||
compare( "Maximum value", wcsStats.maximumValue, gdalStats.maximumValue, theReport, statsOk, tol );
|
||||
|
||||
// TODO: enable once fixed (WCS excludes nulls but GDAL does not)
|
||||
//compare( "Cells count", wcsStats.elementCount, gdalStats.elementCount, theReport, statsOk );
|
||||
|
||||
tol = tolerance( gdalStats.mean );
|
||||
compare( "Mean", wcsStats.mean, gdalStats.mean, theReport, statsOk, tol );
|
||||
|
||||
// stdDev usually differ significantly
|
||||
tol = tolerance( gdalStats.stdDev, 1 );
|
||||
compare( "Standard deviation", wcsStats.stdDev, gdalStats.stdDev, theReport, statsOk, tol );
|
||||
|
||||
theReport += "</table>";
|
||||
theReport += "<br>";
|
||||
|
||||
if ( !bandOk )
|
||||
{
|
||||
allOk = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !statsOk || !typesOk )
|
||||
{
|
||||
allOk = false;
|
||||
// create values table anyway so that values are available
|
||||
}
|
||||
|
||||
theReport += "<table><tr>";
|
||||
theReport += "<td>Data comparison</td>";
|
||||
theReport += "<td class='cell ok' style='border: 1px solid'>correct value</td>";
|
||||
theReport += "<td></td>";
|
||||
theReport += "<td class='cell err' style='border: 1px solid'>wrong value<br>expected value</td></tr>";
|
||||
theReport += "</tr></table>";
|
||||
theReport += "<br>";
|
||||
|
||||
int width = gdalProvider->xSize();
|
||||
int height = gdalProvider->ySize();
|
||||
int blockSize = width * height * gdalProvider->typeSize( gdalProvider->dataType( band ) ) ;
|
||||
void * gdalData = malloc( blockSize );
|
||||
void * wcsData = malloc( blockSize );
|
||||
|
||||
gdalProvider->readBlock( band, gdalProvider->extent(), width, height, gdalData );
|
||||
wcsProvider->readBlock( band, gdalProvider->extent(), width, height, wcsData );
|
||||
|
||||
// compare data values
|
||||
QString htmlTable = "<table class='tab'>";
|
||||
for ( int row = 0; row < height; row ++ )
|
||||
{
|
||||
htmlTable += "<tr>";
|
||||
for ( int col = 0; col < width; col ++ )
|
||||
{
|
||||
bool cellOk = true;
|
||||
double wcsVal = wcsProvider->readValue( wcsData, wcsProvider->dataType( band ), row * width + col );
|
||||
double gdalVal = gdalProvider->readValue( gdalData, gdalProvider->dataType( band ), row * width + col );
|
||||
|
||||
QString valStr;
|
||||
if ( compare( wcsVal, gdalVal, 0 ) )
|
||||
{
|
||||
valStr = QString( "%1" ).arg( wcsVal );
|
||||
}
|
||||
else
|
||||
{
|
||||
cellOk = false;
|
||||
allOk = false;
|
||||
valStr = QString( "%1<br>%2" ).arg( wcsVal ).arg( gdalVal );
|
||||
}
|
||||
htmlTable += QString( "<td class='cell %1'>%2</td>" ).arg( cellOk ? "ok" : "err" ).arg( valStr );
|
||||
}
|
||||
htmlTable += "</tr>";
|
||||
}
|
||||
htmlTable += "</table>";
|
||||
|
||||
theReport += htmlTable;
|
||||
|
||||
free( gdalData );
|
||||
free( wcsData );
|
||||
}
|
||||
delete wcsProvider;
|
||||
delete gdalProvider;
|
||||
return allOk;
|
||||
}
|
||||
|
||||
void TestQgsWcsProvider::error( QString theMessage, QString &theReport )
|
||||
{
|
||||
theReport += "<font class='errmsg'>Error: ";
|
||||
theReport += theMessage;
|
||||
theReport += "</font>";
|
||||
}
|
||||
|
||||
double TestQgsWcsProvider::tolerance( double val, int places )
|
||||
{
|
||||
// float precision is about 7 decimal digits, double about 16
|
||||
// default places = 6
|
||||
return 1. * qPow( 10, qRound( log10( qAbs( val ) ) - places ) );
|
||||
}
|
||||
|
||||
QString TestQgsWcsProvider::compareHead()
|
||||
{
|
||||
return "<tr><th class='cell'>Param name</th><th class='cell'>WCS (tested) value</th><th class='cell'>GDAL (expected) value</th><th class='cell'>Difference</th><th class='cell'>Tolerance</th></tr>";
|
||||
}
|
||||
|
||||
void TestQgsWcsProvider::compare( QString theParamName, int wcsVal, int gdalVal, QString &theReport, bool &theOk )
|
||||
{
|
||||
bool ok = wcsVal == gdalVal;
|
||||
compareRow( theParamName, QString::number( wcsVal ), QString::number( gdalVal ), theReport, ok, QString::number( wcsVal - gdalVal ) );
|
||||
if ( !ok ) theOk = false;
|
||||
}
|
||||
|
||||
bool TestQgsWcsProvider::compare( double wcsVal, double gdalVal, double theTolerance )
|
||||
{
|
||||
// values may be nan
|
||||
return ( qIsNaN( wcsVal ) && qIsNaN( gdalVal ) ) || ( qAbs( wcsVal - gdalVal ) <= theTolerance );
|
||||
}
|
||||
|
||||
void TestQgsWcsProvider::compare( QString theParamName, double wcsVal, double gdalVal, QString &theReport, bool &theOk, double theTolerance )
|
||||
{
|
||||
bool ok = compare( wcsVal, gdalVal, theTolerance );
|
||||
compareRow( theParamName, QString::number( wcsVal ), QString::number( gdalVal ), theReport, ok, QString::number( wcsVal - gdalVal ), QString::number( theTolerance ) );
|
||||
if ( !ok ) theOk = false;
|
||||
}
|
||||
|
||||
void TestQgsWcsProvider::compareRow( QString theParamName, QString wcsVal, QString gdalVal, QString &theReport, bool theOk, QString theDifference, QString theTolerance )
|
||||
{
|
||||
theReport += "<tr>";
|
||||
theReport += QString( "<td class='cell'>%1</td><td class='cell %2'>%3</td><td class='cell'>%4</td>" ).arg( theParamName ).arg( theOk ? "ok" : "err" ).arg( wcsVal ).arg( gdalVal );
|
||||
theReport += QString( "<td class='cell'>%1</td>" ).arg( theDifference );
|
||||
theReport += QString( "<td class='cell'>%1</td>" ).arg( theTolerance );
|
||||
theReport += "</tr>";
|
||||
theReport += checker.report();
|
||||
return ok;
|
||||
}
|
||||
|
||||
QTEST_MAIN( TestQgsWcsProvider )
|
||||
|
Loading…
x
Reference in New Issue
Block a user