QGIS/tests/src/core/testqgsrasterlayer.cpp
Samweli 6352d6889c added abstract temporal class
updates on tests and abstract temporal class

updates on qgsabstracttemporal sip and tests

update qgsabstracttemporal test

updated docs

moved qgsabstracttemporal class to qgstemporalrangeobject class as per review suggestions

edits per review on qgs map canvas

remove access of private members from qgstemporalrangeobject

updated render context test and fix travis tests

added new temporal property class

added tests for temporal property

added tests for temporal property

added temporal widget ui

temporal support in raster layers, from wms provider

temporal properties in raster layer properties

added abstract temporal class

updates on tests and abstract temporal class

updates on qgsabstracttemporal sip and tests

update qgsabstracttemporal test

updated docs

temporal support in raster layers, from wms provider

update qgsabstracttemporal test

updated docs

moved qgsabstracttemporal class to qgstemporalrangeobject class as per review suggestions

edits per review on qgs map canvas

updated render context test and fix travis tests

added new temporal property class

added new map layer temporal properties sub classes with tests

updates on map layers temporal properties classes

fix travis tests

add read and write xml tests

added abstract temporal class

updates on tests and abstract temporal class

updates on qgsabstracttemporal sip and tests

update qgsabstracttemporal test

updated docs

edits per review on qgs map canvas

temporal properties in raster layer properties

temporal support in raster layers, from wms provider

moved qgsabstracttemporal class to qgstemporalrangeobject class as per review suggestions

edits per review on qgs map canvas

remove access of private members from qgstemporalrangeobject

updated render context test and fix travis tests

added new temporal property class

added new map layer temporal properties sub classes with tests

updated layer times ui

added advanced options in layer time constrains ui

fix for refreshing wms layer after temporal properties update

update on wms-t temporal properties

added support for bi-temporal WMS-T
2020-03-05 18:41:35 +10:00

1046 lines
44 KiB
C++

/***************************************************************************
testqgsvectorfilewriter.cpp
--------------------------------------
Date : Frida Nov 23 2007
Copyright : (C) 2007 by Tim Sutton
Email : tim@linfiniti.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 "qgstest.h"
#include <QObject>
#include <QString>
#include <QStringList>
#include <QApplication>
#include <QFileInfo>
#include <QDir>
#include <QPainter>
#include <QTime>
#include <QDesktopServices>
#include "cpl_conv.h"
#include "gdal.h"
//qgis includes...
#include <qgsrasterlayer.h>
#include <qgsrasterpyramid.h>
#include <qgsrasterbandstats.h>
#include <qgsrasteridentifyresult.h>
#include <qgsproject.h>
#include <qgsapplication.h>
#include <qgssinglebandgrayrenderer.h>
#include <qgssinglebandpseudocolorrenderer.h>
#include <qgsmultibandcolorrenderer.h>
#include <qgscolorramp.h>
#include <qgscptcityarchive.h>
#include "qgscolorrampshader.h"
#include "qgsrasterdataprovider.h"
#include "qgsrastershader.h"
#include "qgsrastertransparency.h"
#include "qgspalettedrasterrenderer.h"
#include "qgsrasterlayertemporalproperties.h"
//qgis unit test includes
#include <qgsrenderchecker.h>
/**
* \ingroup UnitTests
* This is a unit test for the QgsRasterLayer class.
*/
class TestQgsRasterLayer : public QObject
{
Q_OBJECT
public:
TestQgsRasterLayer() = default;
~TestQgsRasterLayer() override
{
delete mMapSettings;
}
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 isValid();
void isSpatial();
void pseudoColor();
void colorRamp1();
void colorRamp2();
void colorRamp3();
void colorRamp4();
void landsatBasic();
void landsatBasic875Qml();
void checkDimensions();
void checkStats();
void checkScaleOffset();
void buildExternalOverviews();
void registry();
void transparency();
void multiBandColorRenderer();
void multiBandColorRendererNoData();
void multiBandColorRendererNoDataColor();
void palettedRendererNoData();
void palettedRendererNoDataColor();
void singleBandGrayRendererNoData();
void singleBandGrayRendererNoDataColor();
void singleBandPseudoRendererNoData();
void singleBandPseudoRendererNoDataColor();
void setRenderer();
void regression992(); //test for issue #992 - GeoJP2 images improperly displayed as all black
void testRefreshRendererIfNeeded();
void sample();
void testTemporalProperties();
private:
bool render( const QString &fileName, int mismatchCount = 0 );
bool setQml( const QString &type, QString &msg );
void populateColorRampShader( QgsColorRampShader *colorRampShader,
QgsColorRamp *colorRamp,
int numberOfEntries );
bool testColorRamp( const QString &name, QgsColorRamp *colorRamp,
QgsColorRampShader::Type type, int numberOfEntries );
QString mTestDataDir;
QgsRasterLayer *mpRasterLayer = nullptr;
QgsRasterLayer *mpLandsatRasterLayer = nullptr;
QgsRasterLayer *mpFloat32RasterLayer = nullptr;
QgsRasterLayer *mPngRasterLayer = nullptr;
QgsRasterLayer *mGeoJp2RasterLayer = nullptr;
QgsRasterLayerTemporalProperties *temporalProperties = nullptr;
QgsMapSettings *mMapSettings = nullptr;
QString mReport;
};
class TestSignalReceiver : public QObject
{
Q_OBJECT
public:
TestSignalReceiver()
: QObject( nullptr )
{}
bool rendererChanged = false ;
public slots:
void onRendererChanged()
{
rendererChanged = true;
}
};
//runs before all tests
void TestQgsRasterLayer::initTestCase()
{
std::cout << "CTEST_FULL_OUTPUT" << std::endl;
// init QGIS's paths - true means that all path will be inited from prefix
QgsApplication::init();
QgsApplication::initQgis();
mMapSettings = new QgsMapSettings();
// disable any PAM stuff to make sure stats are consistent
CPLSetConfigOption( "GDAL_PAM_ENABLED", "NO" );
QString mySettings = QgsApplication::showSettings();
mySettings = mySettings.replace( '\n', QLatin1String( "<br />" ) );
//create some objects that will be used in all tests...
//create a raster layer that will be used in all tests...
mTestDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
QString myFileName = mTestDataDir + "tenbytenraster.asc";
QString myLandsatFileName = mTestDataDir + "landsat.tif";
QString myFloat32FileName = mTestDataDir + "/raster/band1_float32_noct_epsg4326.tif";
QString pngRasterFileName = mTestDataDir + "rgb256x256.png";
QString geoJp2RasterFileName = mTestDataDir + "rgbwcmyk01_YeGeo.jp2";
QFileInfo myRasterFileInfo( myFileName );
mpRasterLayer = new QgsRasterLayer( myRasterFileInfo.filePath(),
myRasterFileInfo.completeBaseName() );
qDebug() << "tenbyteraster metadata: " << mpRasterLayer->dataProvider()->htmlMetadata();
QFileInfo myLandsatRasterFileInfo( myLandsatFileName );
mpLandsatRasterLayer = new QgsRasterLayer( myLandsatRasterFileInfo.filePath(),
myLandsatRasterFileInfo.completeBaseName() );
qDebug() << "landsat metadata: " << mpLandsatRasterLayer->dataProvider()->htmlMetadata();
QFileInfo myFloat32RasterFileInfo( myFloat32FileName );
mpFloat32RasterLayer = new QgsRasterLayer( myFloat32RasterFileInfo.filePath(),
myFloat32RasterFileInfo.completeBaseName() );
qDebug() << "float32raster metadata: " << mpFloat32RasterLayer->dataProvider()->htmlMetadata();
QFileInfo pngRasterFileInfo( pngRasterFileName );
mPngRasterLayer = new QgsRasterLayer( pngRasterFileInfo.filePath(),
pngRasterFileInfo.completeBaseName() );
QFileInfo geoJp2RasterFileInfo( geoJp2RasterFileName );
mGeoJp2RasterLayer = new QgsRasterLayer( geoJp2RasterFileInfo.filePath(),
geoJp2RasterFileInfo.completeBaseName() );
// Register the layer with the registry
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mpRasterLayer
<< mpLandsatRasterLayer
<< mpFloat32RasterLayer
<< mPngRasterLayer
<< mGeoJp2RasterLayer );
// add the test layer to the maprender
mMapSettings->setLayers( QList<QgsMapLayer *>() << mpRasterLayer );
mReport += QLatin1String( "<h1>Raster Layer Tests</h1>\n" );
mReport += "<p>" + mySettings + "</p>";
}
//runs after all tests
void TestQgsRasterLayer::cleanupTestCase()
{
QgsApplication::exitQgis();
QString myReportFile = QDir::tempPath() + "/qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
//QDesktopServices::openUrl( "file:///" + myReportFile );
}
}
void TestQgsRasterLayer::isValid()
{
QVERIFY( mpRasterLayer->isValid() );
mpRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
mMapSettings->setExtent( mpRasterLayer->extent() );
QVERIFY( render( "raster" ) );
}
void TestQgsRasterLayer::isSpatial()
{
QVERIFY( mpRasterLayer->isSpatial() );
}
void TestQgsRasterLayer::pseudoColor()
{
QgsRasterShader *rasterShader = new QgsRasterShader();
QgsColorRampShader *colorRampShader = new QgsColorRampShader();
colorRampShader->setColorRampType( QgsColorRampShader::Interpolated );
//items to imitate old pseudo color renderer
QList<QgsColorRampShader::ColorRampItem> colorRampItems;
QgsColorRampShader::ColorRampItem firstItem;
firstItem.value = 0.0;
firstItem.color = QColor( 0, 0, 255 );
colorRampItems.append( firstItem );
QgsColorRampShader::ColorRampItem secondItem;
secondItem.value = 3.0;
secondItem.color = QColor( 0, 255, 255 );
colorRampItems.append( secondItem );
QgsColorRampShader::ColorRampItem thirdItem;
thirdItem.value = 6.0;
thirdItem.color = QColor( 255, 255, 0 );
colorRampItems.append( thirdItem );
QgsColorRampShader::ColorRampItem fourthItem;
fourthItem.value = 9.0;
fourthItem.color = QColor( 255, 0, 0 );
colorRampItems.append( fourthItem );
colorRampShader->setColorRampItemList( colorRampItems );
rasterShader->setRasterShaderFunction( colorRampShader );
QgsSingleBandPseudoColorRenderer *r = new QgsSingleBandPseudoColorRenderer( mpRasterLayer->dataProvider(), 1, rasterShader );
mpRasterLayer->setRenderer( r );
mMapSettings->setExtent( mpRasterLayer->extent() );
QVERIFY( render( "raster_pseudo" ) );
}
void TestQgsRasterLayer::populateColorRampShader( QgsColorRampShader *colorRampShader,
QgsColorRamp *colorRamp,
int numberOfEntries )
{
// adapted from QgsSingleBandPseudoColorRendererWidget::on_mClassifyButton_clicked()
// and TestQgsRasterLayer::pseudoColor()
// would be better to add a more generic function to api that does this
int bandNr = 1;
QgsRasterBandStats myRasterBandStats = mpRasterLayer->dataProvider()->bandStatistics( bandNr );
QList<double> entryValues;
QVector<QColor> entryColors;
double currentValue = myRasterBandStats.minimumValue;
double intervalDiff;
if ( numberOfEntries > 1 )
{
//because the highest value is also an entry, there are (numberOfEntries - 1)
//intervals
intervalDiff = ( myRasterBandStats.maximumValue - myRasterBandStats.minimumValue ) /
( numberOfEntries - 1 );
}
else
{
intervalDiff = myRasterBandStats.maximumValue - myRasterBandStats.minimumValue;
}
for ( int i = 0; i < numberOfEntries; ++i )
{
entryValues.push_back( currentValue );
currentValue += intervalDiff;
entryColors.push_back( colorRamp->color( ( ( double ) i ) / numberOfEntries ) );
}
//items to imitate old pseudo color renderer
QList<QgsColorRampShader::ColorRampItem> colorRampItems;
QList<double>::const_iterator value_it = entryValues.constBegin();
QVector<QColor>::const_iterator color_it = entryColors.constBegin();
for ( ; value_it != entryValues.constEnd(); ++value_it, ++color_it )
{
colorRampItems.append( QgsColorRampShader::ColorRampItem( *value_it, *color_it ) );
}
colorRampShader->setColorRampItemList( colorRampItems );
}
bool TestQgsRasterLayer::testColorRamp( const QString &name, QgsColorRamp *colorRamp,
QgsColorRampShader::Type type, int numberOfEntries )
{
QgsRasterShader *rasterShader = new QgsRasterShader();
QgsColorRampShader *colorRampShader = new QgsColorRampShader();
colorRampShader->setColorRampType( type );
populateColorRampShader( colorRampShader, colorRamp, numberOfEntries );
rasterShader->setRasterShaderFunction( colorRampShader );
QgsSingleBandPseudoColorRenderer *r = new QgsSingleBandPseudoColorRenderer( mpRasterLayer->dataProvider(), 1, rasterShader );
mpRasterLayer->setRenderer( r );
mMapSettings->setExtent( mpRasterLayer->extent() );
return render( name );
}
void TestQgsRasterLayer::colorRamp1()
{
// gradient ramp
QgsGradientColorRamp *colorRamp = new QgsGradientColorRamp( QColor( Qt::red ), QColor( Qt::black ) );
QgsGradientStopsList stops;
stops.append( QgsGradientStop( 0.5, QColor( Qt::white ) ) );
colorRamp->setStops( stops );
// QVERIFY( testColorRamp( "raster_colorRamp1", colorRamp, QgsColorRampShader::Interpolated, 5 ) );
QVERIFY( testColorRamp( "raster_colorRamp1", colorRamp, QgsColorRampShader::Discrete, 10 ) );
delete colorRamp;
}
void TestQgsRasterLayer::colorRamp2()
{
QgsColorBrewerColorRamp ramp( QStringLiteral( "BrBG" ), 10 );
// ColorBrewer ramp
QVERIFY( testColorRamp( "raster_colorRamp2",
&ramp,
QgsColorRampShader::Discrete, 10 ) );
}
void TestQgsRasterLayer::colorRamp3()
{
// cpt-city ramp, discrete
QgsCptCityArchive::initArchives();
QgsCptCityColorRamp ramp( QStringLiteral( "cb/div/BrBG" ), QStringLiteral( "_10" ) );
QVERIFY( testColorRamp( "raster_colorRamp3",
&ramp,
QgsColorRampShader::Discrete, 10 ) );
QgsCptCityArchive::clearArchives();
}
void TestQgsRasterLayer::colorRamp4()
{
// cpt-city ramp, continuous
QgsCptCityColorRamp ramp( QStringLiteral( "grass/elevation" ), QString() );
QVERIFY( testColorRamp( "raster_colorRamp4",
&ramp,
QgsColorRampShader::Discrete, 10 ) );
}
void TestQgsRasterLayer::landsatBasic()
{
QVERIFY2( mpLandsatRasterLayer->isValid(), "landsat.tif layer is not valid!" );
mpLandsatRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mpLandsatRasterLayer );
mMapSettings->setDestinationCrs( mpLandsatRasterLayer->crs() );
mMapSettings->setExtent( mpLandsatRasterLayer->extent() );
QVERIFY( render( "landsat_basic" ) );
}
void TestQgsRasterLayer::landsatBasic875Qml()
{
QVERIFY2( mpLandsatRasterLayer->isValid(), "landsat.tif layer is not valid!" );
//a qml that orders the rgb bands as 8,7,5
mMapSettings->setLayers( QList<QgsMapLayer *>() << mpLandsatRasterLayer );
mMapSettings->setExtent( mpLandsatRasterLayer->extent() );
QString msg;
bool result = setQml( QStringLiteral( "875" ), msg );
QVERIFY2( result, msg.toLocal8Bit().constData() );
QVERIFY( render( "landsat_875" ) );
}
void TestQgsRasterLayer::checkDimensions()
{
mReport += QLatin1String( "<h2>Check Dimensions</h2>\n" );
QVERIFY( mpRasterLayer->width() == 10 );
QVERIFY( mpRasterLayer->height() == 10 );
// regression check for ticket #832
// note bandStatistics call is base 1
// TODO: elementCount is not collected by GDAL, use other stats.
//QVERIFY( mpRasterLayer->dataProvider()->bandStatistics( 1 ).elementCount == 100 );
mReport += QLatin1String( "<p>Passed</p>" );
}
void TestQgsRasterLayer::checkStats()
{
mReport += QLatin1String( "<h2>Check Stats</h2>\n" );
QgsRasterBandStats myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev );
QCOMPARE( mpRasterLayer->width(), 10 );
QCOMPARE( mpRasterLayer->height(), 10 );
//QCOMPARE( myStatistics.elementCount, 100 );
QCOMPARE( myStatistics.minimumValue, 0.0 );
QCOMPARE( myStatistics.maximumValue, 9.0 );
QGSCOMPARENEAR( myStatistics.mean, 4.5, 4 * std::numeric_limits<double>::epsilon() );
double stdDev = 2.87228132326901431;
// TODO: verify why GDAL stdDev is so different from generic (2.88675)
mReport += QStringLiteral( "stdDev = %1 expected = %2<br>\n" ).arg( myStatistics.stdDev ).arg( stdDev );
QGSCOMPARENEAR( myStatistics.stdDev, stdDev, 0.00000000000001 );
mReport += QLatin1String( "<p>Passed</p>" );
// limited extent
myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, QgsRectangle( 1535400, 5083280, 1535450, 5083320 ) );
QCOMPARE( myStatistics.minimumValue, 2.0 );
QCOMPARE( myStatistics.maximumValue, 7.0 );
QGSCOMPARENEAR( myStatistics.mean, 4.5, 4 * std::numeric_limits<double>::epsilon() );
QGSCOMPARENEAR( myStatistics.stdDev, 1.507557, 0.00001 );
// with sample size
myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, QgsRectangle( 1535400, 5083280, 1535450, 5083320 ), 10 );
QCOMPARE( myStatistics.minimumValue, 2.0 );
QCOMPARE( myStatistics.maximumValue, 7.0 );
QCOMPARE( myStatistics.elementCount, 12ULL );
QGSCOMPARENEAR( myStatistics.mean, 4.5, 4 * std::numeric_limits<double>::epsilon() );
QGSCOMPARENEAR( myStatistics.stdDev, 2.153222, 0.00001 );
// extremely limited extent - ~1 px size
myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, QgsRectangle( 1535400, 5083280, 1535412, 5083288 ) );
QCOMPARE( myStatistics.minimumValue, 2.0 );
QCOMPARE( myStatistics.maximumValue, 3.0 );
QGSCOMPARENEAR( myStatistics.mean, 2.600000, 4 * std::numeric_limits<double>::epsilon() );
QGSCOMPARENEAR( myStatistics.stdDev, 0.492366, 0.00001 );
// extremely limited extent - ~1 px size - with sample size
myStatistics = mpRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev, QgsRectangle( 1535400, 5083280, 1535412, 5083288 ), 6 );
QCOMPARE( myStatistics.minimumValue, 2.0 );
QCOMPARE( myStatistics.maximumValue, 3.0 );
QCOMPARE( myStatistics.elementCount, 2ULL );
QGSCOMPARENEAR( myStatistics.mean, 2.500000, 4 * std::numeric_limits<double>::epsilon() );
QGSCOMPARENEAR( myStatistics.stdDev, 0.707107, 0.00001 );
}
// test scale_factor and offset - uses netcdf file which may not be supported
// see https://github.com/qgis/QGIS/issues/17186
void TestQgsRasterLayer::checkScaleOffset()
{
mReport += QLatin1String( "<h2>Check Stats with scale/offset</h2>\n" );
QFileInfo myRasterFileInfo( mTestDataDir + "scaleoffset.tif" );
QgsRasterLayer *myRasterLayer = nullptr;
myRasterLayer = new QgsRasterLayer( myRasterFileInfo.filePath(),
myRasterFileInfo.completeBaseName() );
QVERIFY( myRasterLayer );
if ( ! myRasterLayer->isValid() )
{
qDebug() << QStringLiteral( "raster layer %1 invalid" ).arg( myRasterFileInfo.filePath() );
mReport += QStringLiteral( "raster layer %1 invalid" ).arg( myRasterFileInfo.filePath() );
delete myRasterLayer;
QVERIFY( false );
return;
}
QFile::remove( myRasterFileInfo.filePath() + ".aux.xml" ); // remove cached stats
QgsRasterBandStats myStatistics = myRasterLayer->dataProvider()->bandStatistics( 1,
QgsRasterBandStats::Min | QgsRasterBandStats::Max |
QgsRasterBandStats::Mean | QgsRasterBandStats::StdDev );
mReport += QStringLiteral( "raster min: %1 max: %2 mean: %3" ).arg( myStatistics.minimumValue ).arg( myStatistics.maximumValue ).arg( myStatistics.mean );
QVERIFY( myRasterLayer->width() == 10 );
QVERIFY( myRasterLayer->height() == 10 );
//QVERIFY( myStatistics.elementCount == 100 );
double minVal = 0.0;
mReport += QStringLiteral( "min = %1 expected = %2 diff = %3<br>\n" ).arg( myStatistics.minimumValue ).arg( minVal ).arg( std::fabs( myStatistics.minimumValue - minVal ) );
double maxVal = 9.0;
mReport += QStringLiteral( "max = %1 expected = %2 diff = %3<br>\n" ).arg( myStatistics.maximumValue ).arg( maxVal ).arg( std::fabs( myStatistics.maximumValue - maxVal ) );
double meanVal = 4.5;
mReport += QStringLiteral( "min = %1 expected = %2 diff = %3<br>\n" ).arg( myStatistics.mean ).arg( meanVal ).arg( std::fabs( myStatistics.mean - meanVal ) );
QVERIFY( std::fabs( myStatistics.minimumValue - minVal ) < 0.0000001 );
QVERIFY( std::fabs( myStatistics.maximumValue - maxVal ) < 0.0000001 );
QVERIFY( std::fabs( myStatistics.mean - meanVal ) < 0.0000001 );
double stdDev = 2.87228615;
// TODO: verify why GDAL stdDev is so different from generic (2.88675)
mReport += QStringLiteral( "stdDev = %1 expected = %2 diff = %3<br>\n" ).arg( myStatistics.stdDev ).arg( stdDev ).arg( std::fabs( myStatistics.stdDev - stdDev ) );
QVERIFY( std::fabs( myStatistics.stdDev - stdDev ) < 0.0000001 );
QgsRasterDataProvider *myProvider = myRasterLayer->dataProvider();
QgsPointXY myPoint( 1535030, 5083350 );
QgsRectangle myRect( 1535030 - 5, 5083350 - 5, 1535030 + 5, 5083350 + 5 );
QgsRasterIdentifyResult identifyResult = myProvider->identify( myPoint, QgsRaster::IdentifyFormatValue, myRect, 1, 1 );
if ( identifyResult.isValid() )
{
QMap<int, QVariant> values = identifyResult.results();
Q_FOREACH ( int bandNo, values.keys() )
{
QString valueString;
if ( values.value( bandNo ).isNull() )
{
valueString = tr( "no data" );
mReport += QStringLiteral( " %1 = %2 <br>\n" ).arg( myProvider->generateBandName( bandNo ), valueString );
delete myRasterLayer;
QVERIFY( false );
return;
}
else
{
double expected = 0.99995432;
double value = values.value( bandNo ).toDouble();
valueString = QgsRasterBlock::printValue( value );
mReport += QStringLiteral( " %1 = %2 <br>\n" ).arg( myProvider->generateBandName( bandNo ), valueString );
mReport += QStringLiteral( " value = %1 expected = %2 diff = %3 <br>\n" ).arg( value ).arg( expected ).arg( std::fabs( value - expected ) );
QVERIFY( std::fabs( value - expected ) < 0.0000001 );
}
}
}
else
{
delete myRasterLayer;
QVERIFY( false );
return;
}
mReport += QLatin1String( "<p>Passed</p>" );
delete myRasterLayer;
}
void TestQgsRasterLayer::buildExternalOverviews()
{
//before we begin delete any old ovr file (if it exists)
//and make a copy of the landsat raster into the temp dir
QString myTempPath = QDir::tempPath() + '/';
QFile::remove( myTempPath + "landsat.tif.ovr" );
QFile::remove( myTempPath + "landsat.tif" );
QVERIFY( QFile::copy( mTestDataDir + "landsat.tif", myTempPath + "landsat.tif" ) );
QFileInfo myRasterFileInfo( myTempPath + "landsat.tif" );
QgsRasterLayer *mypLayer = new QgsRasterLayer( myRasterFileInfo.filePath(),
myRasterFileInfo.completeBaseName() );
QVERIFY( mypLayer->isValid() );
//
// OK now we can go on to test
//
QgsRaster::RasterPyramidsFormat myFormatFlag = QgsRaster::PyramidsGTiff;
QList< QgsRasterPyramid > myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided
myPyramidList[myCounterInt].build = true;
}
//now actually make the pyramids
QString myResult =
mypLayer->dataProvider()->buildPyramids( myPyramidList, QStringLiteral( "NEAREST" ), myFormatFlag );
qDebug( "%s", myResult.toLocal8Bit().constData() );
QVERIFY( myResult.isEmpty() );
//
// Lets verify we have pyramids now...
//
myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided
QVERIFY( myPyramidList.at( myCounterInt ).exists );
}
//
// And that they were indeed in an external file...
//
QVERIFY( QFile::exists( myTempPath + "landsat.tif.ovr" ) );
//cleanup
delete mypLayer;
QFile::remove( myTempPath + "landsat.tif.ovr" );
mypLayer = new QgsRasterLayer( myRasterFileInfo.filePath(),
myRasterFileInfo.completeBaseName() );
myPyramidList = mypLayer->dataProvider()->buildPyramidList();
for ( int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
{
//mark to be pyramided
myPyramidList[myCounterInt].build = true;
}
// Test with options
QStringList optionList;
optionList << QStringLiteral( "COMPRESS_OVERVIEW=DEFLATE" );
optionList << QStringLiteral( "invalid" );
myResult =
mypLayer->dataProvider()->buildPyramids( myPyramidList, QStringLiteral( "NEAREST" ), myFormatFlag, optionList );
qDebug( "%s", myResult.toLocal8Bit().constData() );
QVERIFY( myResult.isEmpty() );
QVERIFY( QFile::exists( myTempPath + "landsat.tif.ovr" ) );
//cleanup
delete mypLayer;
// Check that the overview is Deflate compressed
QString ovrFilename( myTempPath + "landsat.tif.ovr" );
GDALDatasetH hDS = GDALOpen( ovrFilename.toLocal8Bit().constData(), GA_ReadOnly );
QVERIFY( hDS );
const char *pszCompression = GDALGetMetadataItem( hDS, "COMPRESSION", "IMAGE_STRUCTURE" );
QVERIFY( pszCompression && EQUAL( pszCompression, "DEFLATE" ) );
GDALClose( hDS );
mReport += QLatin1String( "<h2>Check Overviews</h2>\n" );
mReport += QLatin1String( "<p>Passed</p>" );
}
void TestQgsRasterLayer::registry()
{
QString myTempPath = QDir::tempPath() + '/';
QFile::remove( myTempPath + "landsat.tif.ovr" );
QFile::remove( myTempPath + "landsat.tif" );
QVERIFY( QFile::copy( mTestDataDir + "landsat.tif", myTempPath + "landsat.tif" ) );
QFileInfo myRasterFileInfo( myTempPath + "landsat.tif" );
QgsRasterLayer *mypLayer = new QgsRasterLayer( myRasterFileInfo.filePath(),
myRasterFileInfo.completeBaseName() );
QVERIFY( mypLayer->isValid() );
QgsProject::instance()->addMapLayers(
QList<QgsMapLayer *>() << mypLayer, false );
QgsProject::instance()->removeMapLayers(
QStringList() << mypLayer->id() );
}
//
// Helper methods
//
bool TestQgsRasterLayer::render( const QString &testType, int mismatchCount )
{
mReport += "<h2>" + testType + "</h2>\n";
QgsRenderChecker myChecker;
myChecker.setControlName( "expected_" + testType );
myChecker.setMapSettings( *mMapSettings );
bool myResultFlag = myChecker.runTest( testType, mismatchCount );
mReport += "\n\n\n" + myChecker.report();
return myResultFlag;
}
bool TestQgsRasterLayer::setQml( const QString &type, QString &msg )
{
//load a qml style and apply to our layer
if ( !mpLandsatRasterLayer->isValid() )
{
msg = QStringLiteral( " **** setQml -> mpLandsatRasterLayer is invalid" );
return false;
}
QString myFileName = mTestDataDir + "landsat_" + type + ".qml";
bool myStyleFlag = false;
QString loadStyleMsg;
loadStyleMsg = mpLandsatRasterLayer->loadNamedStyle( myFileName, myStyleFlag );
if ( !myStyleFlag )
{
msg = QStringLiteral( "Loading QML %1 failed: %2" ).arg( myFileName, loadStyleMsg );
return false;
}
return true;
}
void TestQgsRasterLayer::transparency()
{
QVERIFY( mpFloat32RasterLayer->isValid() );
QgsSingleBandGrayRenderer *renderer = new QgsSingleBandGrayRenderer( mpRasterLayer->dataProvider(), 1 );
mpFloat32RasterLayer->setRenderer( renderer );
mpFloat32RasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
qDebug( "contrastEnhancement.minimumValue = %.17g", renderer->contrastEnhancement()->minimumValue() );
qDebug( "contrastEnhancement.maximumValue = %.17g", renderer->contrastEnhancement()->maximumValue() );
QList<QgsRasterTransparency::TransparentSingleValuePixel> myTransparentSingleValuePixelList;
QgsRasterTransparency *rasterTransparency = new QgsRasterTransparency();
QgsRasterTransparency::TransparentSingleValuePixel myTransparentPixel;
myTransparentPixel.min = -2.5840000772112106e+38;
myTransparentPixel.max = -1.0879999684602689e+38;
myTransparentPixel.percentTransparent = 50;
myTransparentSingleValuePixelList.append( myTransparentPixel );
myTransparentPixel.min = 1.359999960575336e+37;
myTransparentPixel.max = 9.520000231087593e+37;
myTransparentPixel.percentTransparent = 70;
myTransparentSingleValuePixelList.append( myTransparentPixel );
rasterTransparency->setTransparentSingleValuePixelList( myTransparentSingleValuePixelList );
QgsRasterRenderer *rasterRenderer = mpFloat32RasterLayer->renderer();
QVERIFY( rasterRenderer != nullptr );
rasterRenderer->setRasterTransparency( rasterTransparency );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mpFloat32RasterLayer );
mMapSettings->setDestinationCrs( mpFloat32RasterLayer->crs() );
mMapSettings->setExtent( mpFloat32RasterLayer->extent() );
QVERIFY( render( "raster_transparency" ) );
}
void TestQgsRasterLayer::multiBandColorRenderer()
{
QgsMultiBandColorRenderer *rasterRenderer = new QgsMultiBandColorRenderer( mPngRasterLayer->dataProvider(), 1, 2, 3 );
mPngRasterLayer->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mPngRasterLayer );
mMapSettings->setDestinationCrs( mPngRasterLayer->crs() );
mMapSettings->setExtent( mPngRasterLayer->extent() );
QVERIFY( render( QStringLiteral( "raster_multibandrenderer" ) ) );
}
void TestQgsRasterLayer::multiBandColorRendererNoData()
{
QgsMultiBandColorRenderer *rasterRenderer = new QgsMultiBandColorRenderer( mPngRasterLayer->dataProvider(), 1, 2, 3 );
mPngRasterLayer->dataProvider()->setNoDataValue( 3, 255 );
mPngRasterLayer->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mPngRasterLayer );
mMapSettings->setDestinationCrs( mPngRasterLayer->crs() );
mMapSettings->setExtent( mPngRasterLayer->extent() );
QVERIFY( render( QStringLiteral( "raster_multibandrenderer_nodata" ) ) );
mPngRasterLayer->dataProvider()->setNoDataValue( 3, -999 );
}
void TestQgsRasterLayer::multiBandColorRendererNoDataColor()
{
QgsMultiBandColorRenderer *rasterRenderer = new QgsMultiBandColorRenderer( mPngRasterLayer->dataProvider(), 1, 2, 3 );
rasterRenderer->setNodataColor( QColor( 255, 0, 255 ) );
mPngRasterLayer->dataProvider()->setNoDataValue( 3, 255 );
mPngRasterLayer->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mPngRasterLayer );
mMapSettings->setDestinationCrs( mPngRasterLayer->crs() );
mMapSettings->setExtent( mPngRasterLayer->extent() );
QVERIFY( render( QStringLiteral( "raster_multibandrenderer_nodata_color" ) ) );
mPngRasterLayer->dataProvider()->setNoDataValue( 3, -999 );
}
void TestQgsRasterLayer::palettedRendererNoData()
{
const QString rasterFileName = mTestDataDir + "raster/with_color_table.tif";
std::unique_ptr< QgsRasterLayer> rl = qgis::make_unique< QgsRasterLayer >( rasterFileName,
QStringLiteral( "rl" ) );
QVERIFY( rl->isValid() );
QgsPalettedRasterRenderer *rasterRenderer = new QgsPalettedRasterRenderer( rl->dataProvider(), 1, QList< QgsPalettedRasterRenderer::Class >()
<< QgsPalettedRasterRenderer::Class( 1, QColor( 0, 255, 0 ), QStringLiteral( "class 2" ) )
<< QgsPalettedRasterRenderer::Class( 3, QColor( 255, 0, 0 ), QStringLiteral( "class 1" ) ) );
rl->dataProvider()->setNoDataValue( 1, 2 );
rl->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << rl.get() );
mMapSettings->setDestinationCrs( rl->crs() );
mMapSettings->setExtent( rl->extent() );
QVERIFY( render( QStringLiteral( "raster_palettedrenderer_nodata" ) ) );
}
void TestQgsRasterLayer::palettedRendererNoDataColor()
{
const QString rasterFileName = mTestDataDir + "raster/with_color_table.tif";
std::unique_ptr< QgsRasterLayer> rl = qgis::make_unique< QgsRasterLayer >( rasterFileName,
QStringLiteral( "rl" ) );
QVERIFY( rl->isValid() );
QgsPalettedRasterRenderer *rasterRenderer = new QgsPalettedRasterRenderer( rl->dataProvider(), 1, QList< QgsPalettedRasterRenderer::Class >()
<< QgsPalettedRasterRenderer::Class( 1, QColor( 0, 255, 0 ), QStringLiteral( "class 2" ) )
<< QgsPalettedRasterRenderer::Class( 3, QColor( 255, 0, 0 ), QStringLiteral( "class 1" ) ) );
rasterRenderer->setNodataColor( QColor( 255, 0, 255 ) );
rl->dataProvider()->setNoDataValue( 1, 2 );
rl->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << rl.get() );
mMapSettings->setDestinationCrs( rl->crs() );
mMapSettings->setExtent( rl->extent() );
QVERIFY( render( QStringLiteral( "raster_palettedrenderer_nodata_color" ) ) );
}
void TestQgsRasterLayer::singleBandGrayRendererNoData()
{
const QString rasterFileName = mTestDataDir + "landsat.tif";
std::unique_ptr< QgsRasterLayer> rl = qgis::make_unique< QgsRasterLayer >( rasterFileName,
QStringLiteral( "rl" ) );
QVERIFY( rl->isValid() );
QgsSingleBandGrayRenderer *rasterRenderer = new QgsSingleBandGrayRenderer( rl->dataProvider(), 1 );
rl->dataProvider()->setNoDataValue( 1, 126 );
rl->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << rl.get() );
mMapSettings->setDestinationCrs( rl->crs() );
mMapSettings->setExtent( rl->extent() );
QVERIFY( render( QStringLiteral( "raster_singlebandgrey_nodata" ) ) );
}
void TestQgsRasterLayer::singleBandGrayRendererNoDataColor()
{
const QString rasterFileName = mTestDataDir + "landsat.tif";
std::unique_ptr< QgsRasterLayer> rl = qgis::make_unique< QgsRasterLayer >( rasterFileName,
QStringLiteral( "rl" ) );
QVERIFY( rl->isValid() );
QgsSingleBandGrayRenderer *rasterRenderer = new QgsSingleBandGrayRenderer( rl->dataProvider(), 1 );
rl->dataProvider()->setNoDataValue( 1, 126 );
rasterRenderer->setNodataColor( QColor( 255, 0, 255 ) );
rl->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << rl.get() );
mMapSettings->setDestinationCrs( rl->crs() );
mMapSettings->setExtent( rl->extent() );
QVERIFY( render( QStringLiteral( "raster_singlebandgrey_nodata_color" ) ) );
}
void TestQgsRasterLayer::singleBandPseudoRendererNoData()
{
const QString rasterFileName = mTestDataDir + "landsat.tif";
std::unique_ptr< QgsRasterLayer> rl = qgis::make_unique< QgsRasterLayer >( rasterFileName,
QStringLiteral( "rl" ) );
QVERIFY( rl->isValid() );
QgsRasterShader *rasterShader = new QgsRasterShader();
QgsColorRampShader *colorRampShader = new QgsColorRampShader();
colorRampShader->setColorRampType( QgsColorRampShader::Interpolated );
//items to imitate old pseudo color renderer
QList<QgsColorRampShader::ColorRampItem> colorRampItems;
QgsColorRampShader::ColorRampItem firstItem;
firstItem.value = 0.0;
firstItem.color = QColor( 0, 0, 255 );
colorRampItems.append( firstItem );
QgsColorRampShader::ColorRampItem secondItem;
secondItem.value = 3.0;
secondItem.color = QColor( 0, 255, 255 );
colorRampItems.append( secondItem );
QgsColorRampShader::ColorRampItem thirdItem;
thirdItem.value = 6.0;
thirdItem.color = QColor( 255, 255, 0 );
colorRampItems.append( thirdItem );
QgsColorRampShader::ColorRampItem fourthItem;
fourthItem.value = 9.0;
fourthItem.color = QColor( 255, 0, 0 );
colorRampItems.append( fourthItem );
colorRampShader->setColorRampItemList( colorRampItems );
rasterShader->setRasterShaderFunction( colorRampShader );
QgsSingleBandPseudoColorRenderer *rasterRenderer = new QgsSingleBandPseudoColorRenderer( rl->dataProvider(), 1, rasterShader );
rl->dataProvider()->setNoDataValue( 1, 126 );
rl->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << rl.get() );
mMapSettings->setDestinationCrs( rl->crs() );
mMapSettings->setExtent( rl->extent() );
QVERIFY( render( QStringLiteral( "raster_singlebandpseudo_nodata" ) ) );
}
void TestQgsRasterLayer::singleBandPseudoRendererNoDataColor()
{
const QString rasterFileName = mTestDataDir + "landsat.tif";
std::unique_ptr< QgsRasterLayer> rl = qgis::make_unique< QgsRasterLayer >( rasterFileName,
QStringLiteral( "rl" ) );
QVERIFY( rl->isValid() );
QgsRasterShader *rasterShader = new QgsRasterShader();
QgsColorRampShader *colorRampShader = new QgsColorRampShader();
colorRampShader->setColorRampType( QgsColorRampShader::Interpolated );
//items to imitate old pseudo color renderer
QList<QgsColorRampShader::ColorRampItem> colorRampItems;
QgsColorRampShader::ColorRampItem firstItem;
firstItem.value = 0.0;
firstItem.color = QColor( 0, 0, 255 );
colorRampItems.append( firstItem );
QgsColorRampShader::ColorRampItem secondItem;
secondItem.value = 3.0;
secondItem.color = QColor( 0, 255, 255 );
colorRampItems.append( secondItem );
QgsColorRampShader::ColorRampItem thirdItem;
thirdItem.value = 6.0;
thirdItem.color = QColor( 255, 255, 0 );
colorRampItems.append( thirdItem );
QgsColorRampShader::ColorRampItem fourthItem;
fourthItem.value = 9.0;
fourthItem.color = QColor( 255, 0, 0 );
colorRampItems.append( fourthItem );
colorRampShader->setColorRampItemList( colorRampItems );
rasterShader->setRasterShaderFunction( colorRampShader );
QgsSingleBandPseudoColorRenderer *rasterRenderer = new QgsSingleBandPseudoColorRenderer( rl->dataProvider(), 1, rasterShader );
rl->dataProvider()->setNoDataValue( 1, 126 );
rasterRenderer->setNodataColor( QColor( 255, 0, 255 ) );
rl->setRenderer( rasterRenderer );
mMapSettings->setLayers( QList<QgsMapLayer *>() << rl.get() );
mMapSettings->setDestinationCrs( rl->crs() );
mMapSettings->setExtent( rl->extent() );
QVERIFY( render( QStringLiteral( "raster_singlebandpseudo_nodata_color" ) ) );
}
void TestQgsRasterLayer::setRenderer()
{
TestSignalReceiver receiver;
QObject::connect( mpRasterLayer, SIGNAL( rendererChanged() ),
&receiver, SLOT( onRendererChanged() ) );
QgsRasterRenderer *renderer = ( QgsRasterRenderer * ) mpRasterLayer->renderer()->clone();
QCOMPARE( receiver.rendererChanged, false );
mpRasterLayer->setRenderer( renderer );
QCOMPARE( receiver.rendererChanged, true );
QCOMPARE( mpRasterLayer->renderer(), renderer );
}
void TestQgsRasterLayer::regression992()
{
if ( ! mGeoJp2RasterLayer->isValid() )
{
QSKIP( "This test requires the JPEG2000 GDAL driver", SkipAll );
}
mMapSettings->setDestinationCrs( mGeoJp2RasterLayer->crs() );
mMapSettings->setExtent( mGeoJp2RasterLayer->extent() );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mGeoJp2RasterLayer );
QVERIFY( render( "raster_geojp2", 400 ) );
}
void TestQgsRasterLayer::testRefreshRendererIfNeeded()
{
QVERIFY2( mpLandsatRasterLayer->isValid(), "landsat.tif layer is not valid!" );
mpLandsatRasterLayer->setContrastEnhancement( QgsContrastEnhancement::StretchToMinimumMaximum, QgsRasterMinMaxOrigin::MinMax );
QVERIFY( dynamic_cast<QgsMultiBandColorRenderer *>( mpLandsatRasterLayer->renderer() ) );
mMapSettings->setLayers( QList<QgsMapLayer *>() << mpLandsatRasterLayer );
mMapSettings->setExtent( mpLandsatRasterLayer->extent() );
double initMinVal = static_cast<QgsMultiBandColorRenderer *>( mpLandsatRasterLayer->renderer() )->redContrastEnhancement()->minimumValue();
// Should do nothing
QgsRectangle newExtent = QgsRectangle( 785000, 3340000, 785100, 3340100 );
mpLandsatRasterLayer->refreshRendererIfNeeded( mpLandsatRasterLayer->renderer(), newExtent );
QCOMPARE( mpLandsatRasterLayer->renderer()->minMaxOrigin().limits(), QgsRasterMinMaxOrigin::MinMax );
double minVal = static_cast<QgsMultiBandColorRenderer *>( mpLandsatRasterLayer->renderer() )->redContrastEnhancement()->minimumValue();
QGSCOMPARENEAR( initMinVal, minVal, 1e-5 );
// Change to UpdatedCanvas
QgsRasterMinMaxOrigin mmo = mpLandsatRasterLayer->renderer()->minMaxOrigin();
mmo.setExtent( QgsRasterMinMaxOrigin::UpdatedCanvas );
mmo.setStatAccuracy( QgsRasterMinMaxOrigin::Exact );
mpLandsatRasterLayer->renderer()->setMinMaxOrigin( mmo );
QCOMPARE( mpLandsatRasterLayer->renderer()->minMaxOrigin().extent(), QgsRasterMinMaxOrigin::UpdatedCanvas );
mpLandsatRasterLayer->refreshRendererIfNeeded( mpLandsatRasterLayer->renderer(), newExtent );
double newMinVal = static_cast<QgsMultiBandColorRenderer *>( mpLandsatRasterLayer->renderer() )->redContrastEnhancement()->minimumValue();
QGSCOMPARENOTNEAR( initMinVal, newMinVal, 1e-5 );
}
void TestQgsRasterLayer::sample()
{
QString fileName = mTestDataDir + "landsat-f32-b1.tif";
QFileInfo rasterFileInfo( fileName );
std::unique_ptr< QgsRasterLayer > rl = qgis::make_unique< QgsRasterLayer> ( rasterFileInfo.filePath(),
rasterFileInfo.completeBaseName() );
QVERIFY( rl->isValid() );
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ) ) );
bool ok = false;
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1, &ok ) ) );
QVERIFY( !ok );
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 1 ), 125.0 );
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 1, &ok ), 125.0 );
QVERIFY( ok );
// bad bands
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 0 ) ) );
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 0, &ok ) ) );
QVERIFY( !ok );
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 788461, 3344957 ), 10, &ok ) ) );
QVERIFY( !ok );
fileName = mTestDataDir + "landsat_4326.tif";
rasterFileInfo = QFileInfo( fileName );
rl = qgis::make_unique< QgsRasterLayer> ( rasterFileInfo.filePath(),
rasterFileInfo.completeBaseName() );
QVERIFY( rl->isValid() );
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1 ) ) );
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 0, 0 ), 1, &ok ) ) );
QVERIFY( !ok );
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 1, &ok ), 125.0 );
QVERIFY( ok );
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 2 ), 139.0 );
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 3 ), 111.0 );
// src no data
rl->dataProvider()->setNoDataValue( 3, 111.0 );
ok = false;
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 3, &ok ) ) );
QVERIFY( !ok );
rl->dataProvider()->setUseSourceNoDataValue( 3, false );
QCOMPARE( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 3 ), 111.0 );
rl->dataProvider()->setUserNoDataValue( 2, QgsRasterRangeList() << QgsRasterRange( 130, 140 ) );
QVERIFY( std::isnan( rl->dataProvider()->sample( QgsPointXY( 17.943731, 30.230791 ), 2, &ok ) ) );
QVERIFY( !ok );
}
void TestQgsRasterLayer::testTemporalProperties()
{
QgsRasterLayerTemporalProperties *temporalProperties = mpRasterLayer->temporalProperties();
QVERIFY( !mpRasterLayer->temporalProperties()->isActive() );
QgsDateTimeRange dateTimeRange = QgsDateTimeRange( QDateTime( QDate( 2020, 1, 1 ) ),
QDateTime( QDate( 2020, 12, 31 ) ) );
temporalProperties->setFixedTemporalRange( dateTimeRange );
QCOMPARE( mpRasterLayer->temporalProperties()->fixedTemporalRange(), dateTimeRange );
// writing and reading from xml
QDomDocument document;
QDomElement elementRoot = document.createElement( "qgis" );
document.appendChild( elementRoot );
QCOMPARE( temporalProperties->mode(), QgsRasterLayerTemporalProperties::TemporalMode::ModeFixedTemporalRange );
QDomElement element = temporalProperties->writeXml( elementRoot, document, QgsReadWriteContext() );
QVERIFY( temporalProperties->readXml( element, QgsReadWriteContext() ) );
QCOMPARE( temporalProperties->mode(), QgsRasterLayerTemporalProperties::TemporalMode::ModeFixedTemporalRange );
// Change temporal properties, save the xml
temporalProperties->setMode( QgsRasterLayerTemporalProperties::TemporalMode::ModeTemporalRangesList );
element = temporalProperties->writeXml( elementRoot, document, QgsReadWriteContext() );
// set mode without saving to xml
temporalProperties->setMode( QgsRasterLayerTemporalProperties::TemporalMode::ModeFixedTemporalRange );
QCOMPARE( temporalProperties->mode(), QgsRasterLayerTemporalProperties::TemporalMode::ModeFixedTemporalRange );
// Read the xml and test if the old saved mode is restored
QVERIFY( temporalProperties->readXml( element, QgsReadWriteContext() ) );
QCOMPARE( temporalProperties->mode(), QgsRasterLayerTemporalProperties::TemporalMode::ModeTemporalRangesList );
}
QGSTEST_MAIN( TestQgsRasterLayer )
#include "testqgsrasterlayer.moc"