mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-11 00:04:27 -04:00
Because 3D coordinates should be the default. References https://github.com/qgis/qgis3.0_api/issues/36
340 lines
12 KiB
C++
340 lines
12 KiB
C++
/***************************************************************************
|
|
testqgsvectorfilewriter.cpp
|
|
--------------------------------------
|
|
Date : Sun Sep 16 12:22:54 AKDT 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 <QPainter>
|
|
#include <QTime>
|
|
#include <QApplication>
|
|
#include <QDesktopServices>
|
|
|
|
//qgis includes...
|
|
#include <qgsvectorlayer.h> //defines QgsFieldMap
|
|
#include <qgsvectorfilewriter.h> //logic for writing shpfiles
|
|
#include <qgsfeature.h> //we will need to pass a bunch of these for each rec
|
|
#include <qgsgeometry.h> //each feature needs a geometry
|
|
#include <qgspoint.h> //we will use point geometry
|
|
#include <qgscoordinatereferencesystem.h> //needed for creating a srs
|
|
#include <qgsapplication.h> //search path for srs.db
|
|
#include <qgsfield.h>
|
|
#include <qgis.h> //defines GEOWkt
|
|
#include "qgsmaprenderersequentialjob.h"
|
|
#include <qgsmaplayer.h>
|
|
#include <qgsreadwritecontext.h>
|
|
#include <qgsvectorlayer.h>
|
|
#include <qgsapplication.h>
|
|
#include <qgsproviderregistry.h>
|
|
#include <qgsproject.h>
|
|
|
|
//qgs unit test utility class
|
|
#include "qgsrenderchecker.h"
|
|
|
|
/** \ingroup UnitTests
|
|
* This is a unit test for the QgsMapRendererJob class.
|
|
* It will do some performance testing too
|
|
*
|
|
*/
|
|
class TestQgsMapRendererJob : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
TestQgsMapRendererJob()
|
|
: mError( QgsVectorFileWriter::NoError )
|
|
, mMapSettings( 0 )
|
|
, mpPolysLayer( 0 )
|
|
{
|
|
}
|
|
|
|
~TestQgsMapRendererJob()
|
|
{
|
|
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.
|
|
|
|
//! This method tests render performance
|
|
void performanceTest();
|
|
|
|
/** This unit test checks if rendering of adjacent tiles (e.g. to render images for tile caches)
|
|
* does not result in border effects
|
|
*/
|
|
void testFourAdjacentTiles_data();
|
|
void testFourAdjacentTiles();
|
|
|
|
private:
|
|
QString mEncoding;
|
|
QgsVectorFileWriter::WriterError mError;
|
|
QgsCoordinateReferenceSystem mCRS;
|
|
QgsFields mFields;
|
|
QgsMapSettings *mMapSettings = nullptr;
|
|
QgsMapLayer *mpPolysLayer = nullptr;
|
|
QString mReport;
|
|
};
|
|
|
|
|
|
void TestQgsMapRendererJob::initTestCase()
|
|
{
|
|
//
|
|
// Runs once before any tests are run
|
|
//
|
|
QgsApplication::init();
|
|
QgsApplication::initQgis();
|
|
QgsApplication::showSettings();
|
|
|
|
mMapSettings = new QgsMapSettings();
|
|
|
|
//create some objects that will be used in all tests...
|
|
mEncoding = QStringLiteral( "UTF-8" );
|
|
QgsField myField1( QStringLiteral( "Value" ), QVariant::Int, QStringLiteral( "int" ), 10, 0, QStringLiteral( "Value on lon" ) );
|
|
mFields.append( myField1 );
|
|
mCRS = QgsCoordinateReferenceSystem( GEOWKT );
|
|
//
|
|
// Create the test dataset if it doesn't exist
|
|
//
|
|
QString myDataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
|
|
QString myTestDataDir = myDataDir + '/';
|
|
QString myTmpDir = QDir::tempPath() + '/';
|
|
QString myFileName = myTmpDir + "maprender_testdata.shp";
|
|
//copy over the default qml for our generated layer
|
|
QString myQmlFileName = myTestDataDir + "maprender_testdata.qml";
|
|
QFile::remove( myTmpDir + "maprender_testdata.qml" );
|
|
QVERIFY( QFile::copy( myQmlFileName, myTmpDir + "maprender_testdata.qml" ) );
|
|
qDebug( "Checking test dataset exists...\n%s", myFileName.toLocal8Bit().constData() );
|
|
if ( !QFile::exists( myFileName ) )
|
|
{
|
|
qDebug( "Creating test dataset: " );
|
|
|
|
QgsVectorFileWriter myWriter( myFileName,
|
|
mEncoding,
|
|
mFields,
|
|
QgsWkbTypes::Polygon,
|
|
mCRS );
|
|
double myInterval = 0.5;
|
|
for ( double i = -180.0; i <= 180.0; i += myInterval )
|
|
{
|
|
for ( double j = -90.0; j <= 90.0; j += myInterval )
|
|
{
|
|
//
|
|
// Create a polygon feature
|
|
//
|
|
QgsPolyline myPolyline;
|
|
QgsPointXY myPoint1 = QgsPointXY( i, j );
|
|
QgsPointXY myPoint2 = QgsPointXY( i + myInterval, j );
|
|
QgsPointXY myPoint3 = QgsPointXY( i + myInterval, j + myInterval );
|
|
QgsPointXY myPoint4 = QgsPointXY( i, j + myInterval );
|
|
myPolyline << myPoint1 << myPoint2 << myPoint3 << myPoint4 << myPoint1;
|
|
QgsPolygon myPolygon;
|
|
myPolygon << myPolyline;
|
|
//polygon: first item of the list is outer ring,
|
|
// inner rings (if any) start from second item
|
|
//
|
|
// NOTE: don't delete this pointer again -
|
|
// ownership is passed to the feature which will
|
|
// delete it in its dtor!
|
|
QgsGeometry mypPolygonGeometry = QgsGeometry::fromPolygon( myPolygon );
|
|
QgsFeature myFeature;
|
|
myFeature.setGeometry( mypPolygonGeometry );
|
|
myFeature.initAttributes( 1 );
|
|
myFeature.setAttribute( 0, i );
|
|
//
|
|
// Write the feature to the filewriter
|
|
// and check for errors
|
|
//
|
|
QVERIFY( myWriter.addFeature( myFeature ) );
|
|
mError = myWriter.hasError();
|
|
if ( mError == QgsVectorFileWriter::ErrDriverNotFound )
|
|
{
|
|
std::cout << "Driver not found error" << std::endl;
|
|
}
|
|
else if ( mError == QgsVectorFileWriter::ErrCreateDataSource )
|
|
{
|
|
std::cout << "Create data source error" << std::endl;
|
|
}
|
|
else if ( mError == QgsVectorFileWriter::ErrCreateLayer )
|
|
{
|
|
std::cout << "Create layer error" << std::endl;
|
|
}
|
|
QVERIFY( mError == QgsVectorFileWriter::NoError );
|
|
}
|
|
}
|
|
} //file exists
|
|
//
|
|
//create a poly layer that will be used in all tests...
|
|
//
|
|
QFileInfo myPolyFileInfo( myFileName );
|
|
mpPolysLayer = new QgsVectorLayer( myPolyFileInfo.filePath(),
|
|
myPolyFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
|
|
QVERIFY( mpPolysLayer->isValid() );
|
|
// Register the layer with the registry
|
|
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mpPolysLayer );
|
|
// add the test layer to the maprender
|
|
mMapSettings->setLayers( QList<QgsMapLayer *>() << mpPolysLayer );
|
|
mReport += QLatin1String( "<h1>Map Render Tests</h1>\n" );
|
|
}
|
|
|
|
void TestQgsMapRendererJob::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 TestQgsMapRendererJob::performanceTest()
|
|
{
|
|
mMapSettings->setExtent( mpPolysLayer->extent() );
|
|
QgsRenderChecker myChecker;
|
|
myChecker.setControlName( QStringLiteral( "expected_maprender" ) );
|
|
mMapSettings->setFlag( QgsMapSettings::Antialiasing );
|
|
myChecker.setMapSettings( *mMapSettings );
|
|
myChecker.setColorTolerance( 5 );
|
|
bool myResultFlag = myChecker.runTest( QStringLiteral( "maprender" ) );
|
|
mReport += myChecker.report();
|
|
QVERIFY( myResultFlag );
|
|
}
|
|
|
|
void TestQgsMapRendererJob::testFourAdjacentTiles_data()
|
|
{
|
|
QTest::addColumn<QStringList>( "bboxList" );
|
|
QTest::addColumn<QString>( "controlName" );
|
|
QTest::addColumn<QString>( "shapeFile" );
|
|
QTest::addColumn<QString>( "qmlFile" );
|
|
|
|
QString shapeFile = TEST_DATA_DIR + QStringLiteral( "/france_parts.shp" );
|
|
QString qmlFile = TEST_DATA_DIR + QStringLiteral( "/adjacent_tiles/line_pattern_30_degree.qml" );
|
|
QString controlName = QStringLiteral( "expected_adjacent_line_fill" );
|
|
|
|
QStringList bboxList1;
|
|
bboxList1 << QStringLiteral( "-1.5,48,-0.5,49" );
|
|
bboxList1 << QStringLiteral( "-0.5,48,0.5,49" );
|
|
bboxList1 << QStringLiteral( "-1.5,47,-0.5,48" );
|
|
bboxList1 << QStringLiteral( "-0.5,47,0.5,48" );
|
|
|
|
QTest::newRow( "adjacent_line_fill" ) << bboxList1 << controlName << shapeFile << qmlFile;
|
|
|
|
qmlFile = TEST_DATA_DIR + QStringLiteral( "/adjacent_tiles/point_pattern_simple_marker.qml" );
|
|
controlName = QStringLiteral( "expected_adjacent_marker_fill" );
|
|
|
|
QTest::newRow( "adjacent_marker_fill" ) << bboxList1 << controlName << shapeFile << qmlFile;
|
|
|
|
shapeFile = TEST_DATA_DIR + QStringLiteral( "/lines.shp" );
|
|
qmlFile = TEST_DATA_DIR + QStringLiteral( "/adjacent_tiles/simple_line_dashed.qml" );
|
|
controlName = QStringLiteral( "expected_adjacent_dashed_line" );
|
|
|
|
QStringList bboxList2;
|
|
bboxList2 << QStringLiteral( "-105,35,-95,45" );
|
|
bboxList2 << QStringLiteral( "-95,35,-85,45" );
|
|
bboxList2 << QStringLiteral( "-105,25,-95,35" );
|
|
bboxList2 << QStringLiteral( "-95,25,-85,35" );
|
|
|
|
QTest::newRow( "adjacent_dashed_line" ) << bboxList2 << controlName << shapeFile << qmlFile;
|
|
}
|
|
|
|
void TestQgsMapRendererJob::testFourAdjacentTiles()
|
|
{
|
|
QFETCH( QStringList, bboxList );
|
|
QFETCH( QString, controlName );
|
|
QFETCH( QString, shapeFile );
|
|
QFETCH( QString, qmlFile );
|
|
|
|
QVERIFY( bboxList.size() == 4 );
|
|
|
|
//create maplayer, set QML and add to maplayer registry
|
|
QgsVectorLayer *vectorLayer = new QgsVectorLayer( shapeFile, QStringLiteral( "testshape" ), QStringLiteral( "ogr" ) );
|
|
|
|
//todo: read QML
|
|
QFile symbologyFile( qmlFile );
|
|
if ( !symbologyFile.open( QIODevice::ReadOnly ) )
|
|
{
|
|
QFAIL( "Open symbology file failed" );
|
|
}
|
|
|
|
QDomDocument qmlDoc;
|
|
if ( !qmlDoc.setContent( &symbologyFile ) )
|
|
{
|
|
QFAIL( "QML file not valid" );
|
|
}
|
|
|
|
QString errorMsg;
|
|
if ( !vectorLayer->readSymbology( qmlDoc.documentElement(), errorMsg, QgsReadWriteContext() ) )
|
|
{
|
|
QFAIL( errorMsg.toLocal8Bit().data() );
|
|
}
|
|
|
|
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << vectorLayer );
|
|
|
|
QImage globalImage( 512, 512, QImage::Format_ARGB32_Premultiplied );
|
|
globalImage.fill( Qt::white );
|
|
QPainter globalPainter( &globalImage );
|
|
|
|
for ( int i = 0; i < 4; ++i )
|
|
{
|
|
QgsMapSettings mapSettings;
|
|
|
|
//extent
|
|
QStringList rectCoords = bboxList.at( i ).split( QStringLiteral( "," ) );
|
|
if ( rectCoords.size() != 4 )
|
|
{
|
|
QFAIL( "bbox string invalid" );
|
|
}
|
|
QgsRectangle rect( rectCoords[0].toDouble(), rectCoords[1].toDouble(), rectCoords[2].toDouble(), rectCoords[3].toDouble() );
|
|
mapSettings.setExtent( rect );
|
|
mapSettings.setOutputSize( QSize( 256, 256 ) );
|
|
mapSettings.setLayers( QList<QgsMapLayer *>() << vectorLayer );
|
|
mapSettings.setFlags( QgsMapSettings::RenderMapTile );
|
|
mapSettings.setOutputDpi( 96 );
|
|
|
|
QgsMapRendererSequentialJob renderJob( mapSettings );
|
|
renderJob.start();
|
|
renderJob.waitForFinished();
|
|
QImage img = renderJob.renderedImage();
|
|
int globalImageX = ( i % 2 ) * 256;
|
|
int globalImageY = ( i < 2 ) ? 0 : 256;
|
|
globalPainter.drawImage( globalImageX, globalImageY, img );
|
|
}
|
|
|
|
QgsProject::instance()->removeMapLayers( QStringList() << vectorLayer->id() );
|
|
|
|
QString renderedImagePath = QDir::tempPath() + "/" + QTest::currentDataTag() + QStringLiteral( ".png" );
|
|
globalImage.save( renderedImagePath );
|
|
|
|
QgsRenderChecker checker;
|
|
|
|
checker.setControlPathPrefix( QStringLiteral( "adjacent_tiles" ) );
|
|
checker.setControlName( controlName );
|
|
bool result = checker.compareImages( QTest::currentDataTag(), 100, renderedImagePath );
|
|
mReport += checker.report();
|
|
QVERIFY( result );
|
|
}
|
|
|
|
|
|
QGSTEST_MAIN( TestQgsMapRendererJob )
|
|
#include "testqgsmaprendererjob.moc"
|
|
|
|
|