LCOV - code coverage report
Current view: top level - core/raster - qgsrasterchecker.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 134 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :      qgsrasterchecker.cpp
       3                 :            :      --------------------------------------
       4                 :            :     Date                 : 5 Sep 2012
       5                 :            :     Copyright            : (C) 2012 by Radim Blazek
       6                 :            :     Email                : radim dot blazek at gmail dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : #include "qgsproviderregistry.h"
      17                 :            : #include "qgsrasterchecker.h"
      18                 :            : #include "qgsrasterdataprovider.h"
      19                 :            : #include "qgsrasterlayer.h"
      20                 :            : 
      21                 :            : #include <QColor>
      22                 :            : #include <QPainter>
      23                 :            : #include <QImage>
      24                 :            : #include <QTime>
      25                 :            : #include <QCryptographicHash>
      26                 :            : #include <QByteArray>
      27                 :            : #include <QDebug>
      28                 :            : #include <QBuffer>
      29                 :            : 
      30                 :          0 : QgsRasterChecker::QgsRasterChecker()
      31                 :            : {
      32                 :          0 :   mTabStyle = QStringLiteral( "border-spacing: 0px; border-width: 1px 1px 0 0; border-style: solid;" );
      33                 :          0 :   mCellStyle = QStringLiteral( "border-width: 0 0 1px 1px; border-style: solid; font-size: smaller; text-align: center;" );
      34                 :          0 :   mOkStyle = QStringLiteral( "background: #00ff00;" );
      35                 :          0 :   mErrStyle = QStringLiteral( "background: #ff0000;" );
      36                 :          0 :   mErrMsgStyle = QStringLiteral( "color: #ff0000;" );
      37                 :          0 : }
      38                 :            : 
      39                 :          0 : bool QgsRasterChecker::runTest( const QString &verifiedKey, QString verifiedUri,
      40                 :            :                                 const QString &expectedKey, QString expectedUri )
      41                 :            : {
      42                 :          0 :   bool ok = true;
      43                 :          0 :   mReport += QLatin1String( "\n\n" );
      44                 :            : 
      45                 :            :   //QgsRasterDataProvider* verifiedProvider = QgsRasterLayer::loadProvider( verifiedKey, verifiedUri );
      46                 :          0 :   QgsDataProvider::ProviderOptions options;
      47                 :          0 :   QgsRasterDataProvider *verifiedProvider = qobject_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( verifiedKey, verifiedUri, options ) );
      48                 :          0 :   if ( !verifiedProvider || !verifiedProvider->isValid() )
      49                 :            :   {
      50                 :          0 :     error( QStringLiteral( "Cannot load provider %1 with URI: %2" ).arg( verifiedKey, verifiedUri ), mReport );
      51                 :          0 :     return false;
      52                 :            :   }
      53                 :            : 
      54                 :            :   //QgsRasterDataProvider* expectedProvider = QgsRasterLayer::loadProvider( expectedKey, expectedUri );
      55                 :          0 :   QgsRasterDataProvider *expectedProvider = qobject_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( expectedKey, expectedUri, options ) );
      56                 :          0 :   if ( !expectedProvider || !expectedProvider->isValid() )
      57                 :            :   {
      58                 :          0 :     error( QStringLiteral( "Cannot load provider %1 with URI: %2" ).arg( expectedKey, expectedUri ), mReport );
      59                 :          0 :     return false;
      60                 :            :   }
      61                 :            : 
      62                 :          0 :   mReport += QStringLiteral( "Verified URI: %1<br>" ).arg( verifiedUri.replace( '&', QLatin1String( "&amp;" ) ) );
      63                 :          0 :   mReport += QStringLiteral( "Expected URI: %1<br>" ).arg( expectedUri.replace( '&', QLatin1String( "&amp;" ) ) );
      64                 :            : 
      65                 :          0 :   mReport += QLatin1String( "<br>" );
      66                 :          0 :   mReport += QStringLiteral( "<table style='%1'>\n" ).arg( mTabStyle );
      67                 :          0 :   mReport += compareHead();
      68                 :            : 
      69                 :          0 :   compare( QStringLiteral( "Band count" ), verifiedProvider->bandCount(), expectedProvider->bandCount(), mReport, ok );
      70                 :            : 
      71                 :          0 :   compare( QStringLiteral( "Width" ), verifiedProvider->xSize(), expectedProvider->xSize(), mReport, ok );
      72                 :          0 :   compare( QStringLiteral( "Height" ), verifiedProvider->ySize(), expectedProvider->ySize(), mReport, ok );
      73                 :            : 
      74                 :          0 :   compareRow( QStringLiteral( "Extent" ), verifiedProvider->extent().toString(), expectedProvider->extent().toString(), mReport, verifiedProvider->extent() == expectedProvider->extent() );
      75                 :            : 
      76                 :          0 :   if ( verifiedProvider->extent() != expectedProvider->extent() ) ok = false;
      77                 :            : 
      78                 :            : 
      79                 :          0 :   mReport += QLatin1String( "</table>\n" );
      80                 :            : 
      81                 :          0 :   if ( !ok ) return false;
      82                 :            : 
      83                 :          0 :   bool allOk = true;
      84                 :          0 :   for ( int band = 1; band <= expectedProvider->bandCount(); band++ )
      85                 :            :   {
      86                 :          0 :     mReport += QStringLiteral( "<h3>Band %1</h3>\n" ).arg( band );
      87                 :          0 :     mReport += QStringLiteral( "<table style='%1'>\n" ).arg( mTabStyle );
      88                 :          0 :     mReport += compareHead();
      89                 :            : 
      90                 :            :     // Data types may differ (?)
      91                 :          0 :     bool typesOk = true;
      92                 :          0 :     compare( QStringLiteral( "Source data type" ), verifiedProvider->sourceDataType( band ), expectedProvider->sourceDataType( band ), mReport, typesOk );
      93                 :          0 :     compare( QStringLiteral( "Data type" ), verifiedProvider->dataType( band ), expectedProvider->dataType( band ), mReport, typesOk );
      94                 :            : 
      95                 :            :     // Check nodata
      96                 :          0 :     bool noDataOk = true;
      97                 :          0 :     compare( QStringLiteral( "No data (NULL) value existence flag" ), verifiedProvider->sourceHasNoDataValue( band ), expectedProvider->sourceHasNoDataValue( band ), mReport, noDataOk );
      98                 :          0 :     if ( verifiedProvider->sourceHasNoDataValue( band ) && expectedProvider->sourceHasNoDataValue( band ) )
      99                 :            :     {
     100                 :          0 :       compare( QStringLiteral( "No data (NULL) value" ), verifiedProvider->sourceNoDataValue( band ), expectedProvider->sourceNoDataValue( band ), mReport, noDataOk );
     101                 :          0 :     }
     102                 :            : 
     103                 :          0 :     bool statsOk = true;
     104                 :          0 :     QgsRasterBandStats verifiedStats = verifiedProvider->bandStatistics( band );
     105                 :          0 :     QgsRasterBandStats expectedStats = expectedProvider->bandStatistics( band );
     106                 :            : 
     107                 :            :     // Min/max may 'slightly' differ, for big numbers however, the difference may
     108                 :            :     // be quite big, for example for Float32 with max -3.332e+38, the difference is 1.47338e+24
     109                 :          0 :     double tol = tolerance( expectedStats.minimumValue );
     110                 :          0 :     compare( QStringLiteral( "Minimum value" ), verifiedStats.minimumValue, expectedStats.minimumValue, mReport, statsOk, tol );
     111                 :          0 :     tol = tolerance( expectedStats.maximumValue );
     112                 :          0 :     compare( QStringLiteral( "Maximum value" ), verifiedStats.maximumValue, expectedStats.maximumValue, mReport, statsOk, tol );
     113                 :            : 
     114                 :            :     // TODO: enable once fixed (WCS excludes nulls but GDAL does not)
     115                 :            :     //compare( "Cells count", verifiedStats.elementCount, expectedStats.elementCount, mReport, statsOk );
     116                 :            : 
     117                 :          0 :     tol = tolerance( expectedStats.mean );
     118                 :          0 :     compare( QStringLiteral( "Mean" ), verifiedStats.mean, expectedStats.mean, mReport, statsOk, tol );
     119                 :            : 
     120                 :            :     // stdDev usually differ significantly
     121                 :          0 :     tol = tolerance( expectedStats.stdDev, 1 );
     122                 :          0 :     compare( QStringLiteral( "Standard deviation" ), verifiedStats.stdDev, expectedStats.stdDev, mReport, statsOk, tol );
     123                 :            : 
     124                 :          0 :     mReport += QLatin1String( "</table>" );
     125                 :          0 :     mReport += QLatin1String( "<br>" );
     126                 :            : 
     127                 :          0 :     if ( !statsOk || !typesOk || !noDataOk )
     128                 :            :     {
     129                 :          0 :       allOk = false;
     130                 :            :       // create values table anyway so that values are available
     131                 :          0 :     }
     132                 :            : 
     133                 :          0 :     mReport += QLatin1String( "<table><tr>" );
     134                 :          0 :     mReport += QLatin1String( "<td>Data comparison</td>" );
     135                 :          0 :     mReport += QStringLiteral( "<td style='%1 %2 border: 1px solid'>correct&nbsp;value</td>" ).arg( mCellStyle, mOkStyle );
     136                 :          0 :     mReport += QLatin1String( "<td></td>" );
     137                 :          0 :     mReport += QStringLiteral( "<td style='%1 %2 border: 1px solid'>wrong&nbsp;value<br>expected value</td></tr>" ).arg( mCellStyle, mErrStyle );
     138                 :          0 :     mReport += QLatin1String( "</tr></table>" );
     139                 :          0 :     mReport += QLatin1String( "<br>" );
     140                 :            : 
     141                 :          0 :     int width = expectedProvider->xSize();
     142                 :          0 :     int height = expectedProvider->ySize();
     143                 :          0 :     std::unique_ptr< QgsRasterBlock > expectedBlock( expectedProvider->block( band, expectedProvider->extent(), width, height ) );
     144                 :          0 :     std::unique_ptr< QgsRasterBlock > verifiedBlock( verifiedProvider->block( band, expectedProvider->extent(), width, height ) );
     145                 :            : 
     146                 :          0 :     if ( !expectedBlock || !expectedBlock->isValid() ||
     147                 :          0 :          !verifiedBlock || !verifiedBlock->isValid() )
     148                 :            :     {
     149                 :          0 :       allOk = false;
     150                 :          0 :       mReport += QLatin1String( "cannot read raster block" );
     151                 :          0 :       continue;
     152                 :            :     }
     153                 :            : 
     154                 :            :     // compare data values
     155                 :          0 :     QString htmlTable = QStringLiteral( "<table style='%1'>" ).arg( mTabStyle );
     156                 :          0 :     for ( int row = 0; row < height; row ++ )
     157                 :            :     {
     158                 :          0 :       htmlTable += QLatin1String( "<tr>" );
     159                 :          0 :       for ( int col = 0; col < width; col ++ )
     160                 :            :       {
     161                 :          0 :         bool cellOk = true;
     162                 :          0 :         double verifiedVal = verifiedBlock->value( row, col );
     163                 :          0 :         double expectedVal = expectedBlock->value( row, col );
     164                 :            : 
     165                 :          0 :         QString valStr;
     166                 :          0 :         if ( compare( verifiedVal, expectedVal, 0 ) )
     167                 :            :         {
     168                 :          0 :           valStr = QString::number( verifiedVal );
     169                 :          0 :         }
     170                 :            :         else
     171                 :            :         {
     172                 :          0 :           cellOk = false;
     173                 :          0 :           allOk = false;
     174                 :          0 :           valStr = QStringLiteral( "%1<br>%2" ).arg( verifiedVal ).arg( expectedVal );
     175                 :            :         }
     176                 :          0 :         htmlTable += QStringLiteral( "<td style='%1 %2'>%3</td>" ).arg( mCellStyle, cellOk ? mOkStyle : mErrStyle, valStr );
     177                 :          0 :       }
     178                 :          0 :       htmlTable += QLatin1String( "</tr>" );
     179                 :          0 :     }
     180                 :          0 :     htmlTable += QLatin1String( "</table>" );
     181                 :            : 
     182                 :          0 :     mReport += htmlTable;
     183                 :          0 :   }
     184                 :          0 :   delete verifiedProvider;
     185                 :          0 :   delete expectedProvider;
     186                 :          0 :   return allOk;
     187                 :          0 : }
     188                 :            : 
     189                 :          0 : void QgsRasterChecker::error( const QString &message, QString &report )
     190                 :            : {
     191                 :          0 :   report += QStringLiteral( "<font style='%1'>Error: " ).arg( mErrMsgStyle );
     192                 :          0 :   report += message;
     193                 :          0 :   report += QLatin1String( "</font>" );
     194                 :          0 : }
     195                 :            : 
     196                 :          0 : double QgsRasterChecker::tolerance( double val, int places )
     197                 :            : {
     198                 :            :   // float precision is about 7 decimal digits, double about 16
     199                 :            :   // default places = 6
     200                 :          0 :   return 1. * std::pow( 10, std::round( std::log10( std::fabs( val ) ) - places ) );
     201                 :            : }
     202                 :            : 
     203                 :          0 : QString QgsRasterChecker::compareHead()
     204                 :            : {
     205                 :          0 :   QString html;
     206                 :          0 :   html += QStringLiteral( "<tr><th style='%1'>Param name</th><th style='%1'>Verified value</th><th style='%1'>Expected value</th><th style='%1'>Difference</th><th style='%1'>Tolerance</th></tr>" ).arg( mCellStyle );
     207                 :          0 :   return html;
     208                 :          0 : }
     209                 :            : 
     210                 :          0 : void QgsRasterChecker::compare( const QString &paramName, int verifiedVal, int expectedVal, QString &report, bool &ok )
     211                 :            : {
     212                 :          0 :   bool isEqual = verifiedVal == expectedVal;
     213                 :          0 :   compareRow( paramName, QString::number( verifiedVal ), QString::number( expectedVal ), report, isEqual, QString::number( verifiedVal - expectedVal ) );
     214                 :          0 :   if ( !isEqual )
     215                 :          0 :     ok = false;
     216                 :          0 : }
     217                 :            : 
     218                 :          0 : bool QgsRasterChecker::compare( double verifiedVal, double expectedVal, double tolerance )
     219                 :            : {
     220                 :            :   // values may be nan
     221                 :          0 :   return ( std::isnan( verifiedVal ) && std::isnan( expectedVal ) ) || ( std::fabs( verifiedVal - expectedVal ) <= tolerance );
     222                 :            : }
     223                 :            : 
     224                 :          0 : void QgsRasterChecker::compare( const QString &paramName, double verifiedVal, double expectedVal, QString &report, bool &ok, double tolerance )
     225                 :            : {
     226                 :          0 :   bool isNearEqual = compare( verifiedVal, expectedVal, tolerance );
     227                 :          0 :   compareRow( paramName, QString::number( verifiedVal ), QString::number( expectedVal ), report, isNearEqual, QString::number( verifiedVal - expectedVal ), QString::number( tolerance ) );
     228                 :          0 :   if ( !isNearEqual )
     229                 :          0 :     ok = false;
     230                 :          0 : }
     231                 :            : 
     232                 :          0 : void QgsRasterChecker::compareRow( const QString &paramName, const QString &verifiedVal, const QString &expectedVal, QString &report, bool ok, const QString &difference, const QString &tolerance )
     233                 :            : {
     234                 :          0 :   report += QLatin1String( "<tr>\n" );
     235                 :          0 :   report += QStringLiteral( "<td style='%1'>%2</td><td style='%1 %3'>%4</td><td style='%1'>%5</td>\n" ).arg( mCellStyle, paramName, ok ? mOkStyle : mErrStyle, verifiedVal, expectedVal );
     236                 :          0 :   report += QStringLiteral( "<td style='%1'>%2</td>\n" ).arg( mCellStyle, difference );
     237                 :          0 :   report += QStringLiteral( "<td style='%1'>%2</td>\n" ).arg( mCellStyle, tolerance );
     238                 :          0 :   report += QLatin1String( "</tr>" );
     239                 :          0 : }

Generated by: LCOV version 1.14