|
QGIS API Documentation
master-6227475
|
00001 /*************************************************************************** 00002 qgsrasterchecker.cpp 00003 -------------------------------------- 00004 Date : 5 Sep 2012 00005 Copyright : (C) 2012 by Radim Blazek 00006 Email : radim dot blazek at gmail dot com 00007 *************************************************************************** 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 ***************************************************************************/ 00015 00016 #include "qgsproviderregistry.h" 00017 #include "qgsrasterchecker.h" 00018 #include "qgsrasterdataprovider.h" 00019 #include "qgsrasterlayer.h" 00020 00021 #include <qmath.h> 00022 #include <QColor> 00023 #include <QPainter> 00024 #include <QImage> 00025 #include <QTime> 00026 #include <QCryptographicHash> 00027 #include <QByteArray> 00028 #include <QDebug> 00029 #include <QBuffer> 00030 00031 QgsRasterChecker::QgsRasterChecker( ) : 00032 mReport( "" ) 00033 { 00034 mTabStyle = "border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid;"; 00035 mCellStyle = "border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center;"; 00036 mOkStyle = "background: #00ff00;"; 00037 mErrStyle = "background: #ff0000;"; 00038 mErrMsgStyle = "color: #ff0000;"; 00039 } 00040 00041 bool QgsRasterChecker::runTest( QString theVerifiedKey, QString theVerifiedUri, 00042 QString theExpectedKey, QString theExpectedUri ) 00043 { 00044 bool ok = true; 00045 mReport += "\n\n"; 00046 00047 //QgsRasterDataProvider* verifiedProvider = QgsRasterLayer::loadProvider( theVerifiedKey, theVerifiedUri ); 00048 QgsRasterDataProvider* verifiedProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( theVerifiedKey, theVerifiedUri ); 00049 if ( !verifiedProvider || !verifiedProvider->isValid() ) 00050 { 00051 error( QString( "Cannot load provider %1 with URI: %2" ).arg( theVerifiedKey ).arg( theVerifiedUri ), mReport ); 00052 ok = false; 00053 } 00054 00055 //QgsRasterDataProvider* expectedProvider = QgsRasterLayer::loadProvider( theExpectedKey, theExpectedUri ); 00056 QgsRasterDataProvider* expectedProvider = ( QgsRasterDataProvider* ) QgsProviderRegistry::instance()->provider( theExpectedKey, theExpectedUri ); 00057 if ( !expectedProvider || !expectedProvider->isValid() ) 00058 { 00059 error( QString( "Cannot load provider %1 with URI: %2" ).arg( theExpectedKey ).arg( theExpectedUri ), mReport ); 00060 ok = false; 00061 } 00062 00063 if ( !ok ) return false; 00064 00065 mReport += QString( "Verified URI: %1<br>" ).arg( theVerifiedUri.replace( "&", "&" ) ); 00066 mReport += QString( "Expected URI: %1<br>" ).arg( theExpectedUri.replace( "&", "&" ) ); 00067 00068 mReport += "<br>"; 00069 mReport += QString( "<table style='%1'>\n" ).arg( mTabStyle ); 00070 mReport += compareHead(); 00071 00072 compare( "Band count", verifiedProvider->bandCount(), expectedProvider->bandCount(), mReport, ok ); 00073 00074 compare( "Width", verifiedProvider->xSize(), expectedProvider->xSize(), mReport, ok ); 00075 compare( "Height", verifiedProvider->ySize(), expectedProvider->ySize(), mReport, ok ); 00076 00077 compareRow( "Extent", verifiedProvider->extent().toString(), expectedProvider->extent().toString(), mReport, verifiedProvider->extent() == expectedProvider->extent() ); 00078 00079 if ( verifiedProvider->extent() != expectedProvider->extent() ) ok = false; 00080 00081 00082 mReport += "</table>\n"; 00083 00084 if ( !ok ) return false; 00085 00086 bool allOk = true; 00087 for ( int band = 1; band <= expectedProvider->bandCount(); band++ ) 00088 { 00089 bool bandOk = true; 00090 mReport += QString( "<h3>Band %1</h3>\n" ).arg( band ); 00091 mReport += QString( "<table style='%1'>\n" ).arg( mTabStyle ); 00092 mReport += compareHead(); 00093 00094 // Data types may differ (?) 00095 bool typesOk = true; 00096 compare( "Source data type", verifiedProvider->srcDataType( band ), expectedProvider->srcDataType( band ), mReport, typesOk ); 00097 compare( "Data type", verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk ) ; 00098 00099 // TODO: not yet sure if noDataValue() should exist at all 00100 //compare( "No data (NULL) value", verifiedProvider->noDataValue( band ), expectedProvider->noDataValue( band ), mReport, typesOk ); 00101 00102 bool statsOk = true; 00103 QgsRasterBandStats verifiedStats = verifiedProvider->bandStatistics( band ); 00104 QgsRasterBandStats expectedStats = expectedProvider->bandStatistics( band ); 00105 00106 // Min/max may 'slightly' differ, for big numbers however, the difference may 00107 // be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24 00108 double tol = tolerance( expectedStats.minimumValue ); 00109 compare( "Minimum value", verifiedStats.minimumValue, expectedStats.minimumValue, mReport, statsOk, tol ); 00110 tol = tolerance( expectedStats.maximumValue ); 00111 compare( "Maximum value", verifiedStats.maximumValue, expectedStats.maximumValue, mReport, statsOk, tol ); 00112 00113 // TODO: enable once fixed (WCS excludes nulls but GDAL does not) 00114 //compare( "Cells count", verifiedStats.elementCount, expectedStats.elementCount, mReport, statsOk ); 00115 00116 tol = tolerance( expectedStats.mean ); 00117 compare( "Mean", verifiedStats.mean, expectedStats.mean, mReport, statsOk, tol ); 00118 00119 // stdDev usually differ significantly 00120 tol = tolerance( expectedStats.stdDev, 1 ); 00121 compare( "Standard deviation", verifiedStats.stdDev, expectedStats.stdDev, mReport, statsOk, tol ); 00122 00123 mReport += "</table>"; 00124 mReport += "<br>"; 00125 00126 if ( !bandOk ) 00127 { 00128 allOk = false; 00129 continue; 00130 } 00131 00132 if ( !statsOk || !typesOk ) 00133 { 00134 allOk = false; 00135 // create values table anyway so that values are available 00136 } 00137 00138 mReport += "<table><tr>"; 00139 mReport += "<td>Data comparison</td>"; 00140 mReport += QString( "<td style='%1 %2 border: 1px solid'>correct value</td>" ).arg( mCellStyle ).arg( mOkStyle ); 00141 mReport += "<td></td>"; 00142 mReport += QString( "<td style='%1 %2 border: 1px solid'>wrong value<br>expected value</td></tr>" ).arg( mCellStyle ).arg( mErrStyle ); 00143 mReport += "</tr></table>"; 00144 mReport += "<br>"; 00145 00146 int width = expectedProvider->xSize(); 00147 int height = expectedProvider->ySize(); 00148 QgsRasterBlock *expectedBlock = expectedProvider->block( band, expectedProvider->extent(), width, height ); 00149 QgsRasterBlock *verifiedBlock = verifiedProvider->block( band, expectedProvider->extent(), width, height ); 00150 00151 if ( !expectedBlock || !expectedBlock->isValid() || 00152 !verifiedBlock || !verifiedBlock->isValid() ) 00153 { 00154 allOk = false; 00155 mReport += "cannot read raster block"; 00156 continue; 00157 } 00158 00159 // compare data values 00160 QString htmlTable = QString( "<table style='%1'>" ).arg( mTabStyle ); 00161 for ( int row = 0; row < height; row ++ ) 00162 { 00163 htmlTable += "<tr>"; 00164 for ( int col = 0; col < width; col ++ ) 00165 { 00166 bool cellOk = true; 00167 double verifiedVal = verifiedBlock->value( row, col ); 00168 double expectedVal = expectedBlock->value( row, col ); 00169 00170 QString valStr; 00171 if ( compare( verifiedVal, expectedVal, 0 ) ) 00172 { 00173 valStr = QString( "%1" ).arg( verifiedVal ); 00174 } 00175 else 00176 { 00177 cellOk = false; 00178 allOk = false; 00179 valStr = QString( "%1<br>%2" ).arg( verifiedVal ).arg( expectedVal ); 00180 } 00181 htmlTable += QString( "<td style='%1 %2'>%3</td>" ).arg( mCellStyle ).arg( cellOk ? mOkStyle : mErrStyle ).arg( valStr ); 00182 } 00183 htmlTable += "</tr>"; 00184 } 00185 htmlTable += "</table>"; 00186 00187 mReport += htmlTable; 00188 00189 delete expectedBlock; 00190 delete verifiedBlock; 00191 } 00192 delete verifiedProvider; 00193 delete expectedProvider; 00194 return allOk; 00195 } 00196 00197 void QgsRasterChecker::error( QString theMessage, QString &theReport ) 00198 { 00199 theReport += QString( "<font style='%1'>Error: " ).arg( mErrMsgStyle ); 00200 theReport += theMessage; 00201 theReport += "</font>"; 00202 } 00203 00204 double QgsRasterChecker::tolerance( double val, int places ) 00205 { 00206 // float precision is about 7 decimal digits, double about 16 00207 // default places = 6 00208 return 1. * qPow( 10, qRound( log10( qAbs( val ) ) - places ) ); 00209 } 00210 00211 QString QgsRasterChecker::compareHead() 00212 { 00213 QString html; 00214 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 ); 00215 return html; 00216 } 00217 00218 void QgsRasterChecker::compare( QString theParamName, int verifiedVal, int expectedVal, QString &theReport, bool &theOk ) 00219 { 00220 bool ok = verifiedVal == expectedVal; 00221 compareRow( theParamName, QString::number( verifiedVal ), QString::number( expectedVal ), theReport, ok, QString::number( verifiedVal - expectedVal ) ); 00222 if ( !ok ) theOk = false; 00223 } 00224 00225 bool QgsRasterChecker::compare( double verifiedVal, double expectedVal, double theTolerance ) 00226 { 00227 // values may be nan 00228 return ( qIsNaN( verifiedVal ) && qIsNaN( expectedVal ) ) || ( qAbs( verifiedVal - expectedVal ) <= theTolerance ); 00229 } 00230 00231 void QgsRasterChecker::compare( QString theParamName, double verifiedVal, double expectedVal, QString &theReport, bool &theOk, double theTolerance ) 00232 { 00233 bool ok = compare( verifiedVal, expectedVal, theTolerance ); 00234 compareRow( theParamName, QString::number( verifiedVal ), QString::number( expectedVal ), theReport, ok, QString::number( verifiedVal - expectedVal ), QString::number( theTolerance ) ); 00235 if ( !ok ) theOk = false; 00236 } 00237 00238 void QgsRasterChecker::compareRow( QString theParamName, QString verifiedVal, QString expectedVal, QString &theReport, bool theOk, QString theDifference, QString theTolerance ) 00239 { 00240 theReport += "<tr>\n"; 00241 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 ); 00242 theReport += QString( "<td style='%1'>%2</td>\n" ).arg( mCellStyle ).arg( theDifference ); 00243 theReport += QString( "<td style='%1'>%2</td>\n" ).arg( mCellStyle ).arg( theTolerance ); 00244 theReport += "</tr>"; 00245 }