Skip to content

Commit

Permalink
Start prepping for group-based output, shuffle tests so that some wor…
Browse files Browse the repository at this point in the history
…k on GDAL < 3
  • Loading branch information
nyalldawson committed Aug 20, 2019
1 parent 8459112 commit c8a368f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 45 deletions.
55 changes: 29 additions & 26 deletions src/core/qgsabstractgeopdfexporter.cpp
Expand Up @@ -83,15 +83,14 @@ QString QgsAbstractGeoPdfExporter::geoPDFAvailabilityExplanation()

bool QgsAbstractGeoPdfExporter::finalize( const QList<ComponentLayerDetail> &components, const QString &destinationFile, const ExportDetails &details )
{
if ( details.includeFeatures && !saveTemporaryLayers() )
return false;

#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,0,0)
Q_UNUSED( components )
Q_UNUSED( destinationFile )
Q_UNUSED( details )
return false;
#else
if ( details.includeFeatures && !saveTemporaryLayers() )
return false;

const QString composition = createCompositionXml( components, details );
QgsDebugMsg( composition );
if ( composition.isEmpty() )
Expand Down Expand Up @@ -137,48 +136,52 @@ QString QgsAbstractGeoPdfExporter::generateTemporaryFilepath( const QString &fil
}


void QgsAbstractGeoPdfExporter::pushRenderedFeature( const QString &layerId, const QgsAbstractGeoPdfExporter::RenderedFeature &feature )
void QgsAbstractGeoPdfExporter::pushRenderedFeature( const QString &layerId, const QgsAbstractGeoPdfExporter::RenderedFeature &feature, const QString &group )
{
// because map layers may be rendered in parallel, we need a mutex here
QMutexLocker locker( &mMutex );

// collate all the features which belong to the same layer, replacing their geometries with the rendered feature bounds
QgsFeature f = feature.feature;
f.setGeometry( feature.renderedBounds );
mCollatedFeatures[ layerId ].append( f );
mCollatedFeatures[ group ][ layerId ].append( f );
}

bool QgsAbstractGeoPdfExporter::saveTemporaryLayers()
{
for ( auto it = mCollatedFeatures.constBegin(); it != mCollatedFeatures.constEnd(); ++it )
for ( auto groupIt = mCollatedFeatures.constBegin(); groupIt != mCollatedFeatures.constEnd(); ++groupIt )
{
const QString filePath = generateTemporaryFilepath( it.key() + QStringLiteral( ".gpkg" ) );
for ( auto it = groupIt->constBegin(); it != groupIt->constEnd(); ++it )
{
const QString filePath = generateTemporaryFilepath( it.key() + groupIt.key() + QStringLiteral( ".gpkg" ) );

VectorComponentDetail detail = componentDetailForLayerId( it.key() );
detail.sourceVectorPath = filePath;
VectorComponentDetail detail = componentDetailForLayerId( it.key() );
detail.sourceVectorPath = filePath;
detail.group = groupIt.key();

// write out features to disk
const QgsFeatureList features = it.value();
QString layerName;
QgsVectorFileWriter writer( filePath, QString(), features.first().fields(), features.first().geometry().wkbType(), QgsCoordinateReferenceSystem(), QStringLiteral( "GPKG" ), QStringList(), QStringList(), nullptr, QgsVectorFileWriter::NoSymbology, nullptr, &layerName );
if ( writer.hasError() )
{
mErrorMessage = writer.errorMessage();
QgsDebugMsg( mErrorMessage );
return false;
}
for ( const QgsFeature &feature : features )
{
QgsFeature f = feature;
if ( !writer.addFeature( f, QgsFeatureSink::FastInsert ) )
// write out features to disk
const QgsFeatureList features = it.value();
QString layerName;
QgsVectorFileWriter writer( filePath, QString(), features.first().fields(), features.first().geometry().wkbType(), QgsCoordinateReferenceSystem(), QStringLiteral( "GPKG" ), QStringList(), QStringList(), nullptr, QgsVectorFileWriter::NoSymbology, nullptr, &layerName );
if ( writer.hasError() )
{
mErrorMessage = writer.errorMessage();
QgsDebugMsg( mErrorMessage );
return false;
}
for ( const QgsFeature &feature : features )
{
QgsFeature f = feature;
if ( !writer.addFeature( f, QgsFeatureSink::FastInsert ) )
{
mErrorMessage = writer.errorMessage();
QgsDebugMsg( mErrorMessage );
return false;
}
}
detail.sourceVectorLayer = layerName;
mVectorComponents << detail;
}
detail.sourceVectorLayer = layerName;
mVectorComponents << detail;
}
return true;
}
Expand Down
10 changes: 8 additions & 2 deletions src/core/qgsabstractgeopdfexporter.h
Expand Up @@ -167,8 +167,11 @@ class CORE_EXPORT QgsAbstractGeoPdfExporter
/**
* Called multiple times during the rendering operation, whenever a \a feature associated with the specified
* \a layerId is rendered.
*
* The optional \a group argument can be used to differentiate features from the same layer exported
* multiple times as part of different layer groups.
*/
void pushRenderedFeature( const QString &layerId, const QgsAbstractGeoPdfExporter::RenderedFeature &feature );
void pushRenderedFeature( const QString &layerId, const QgsAbstractGeoPdfExporter::RenderedFeature &feature, const QString &group = QString() );

struct ExportDetails
{
Expand Down Expand Up @@ -264,6 +267,9 @@ class CORE_EXPORT QgsAbstractGeoPdfExporter
//! Associated map layer ID
QString mapLayerId;

//! Optional layer group name
QString group;

//! Field name for display
QString displayAttribute;

Expand All @@ -278,7 +284,7 @@ class CORE_EXPORT QgsAbstractGeoPdfExporter
private:

QMutex mMutex;
QMap< QString, QgsFeatureList > mCollatedFeatures;
QMap< QString, QMap< QString, QgsFeatureList > > mCollatedFeatures;

/**
* Returns the PDF output component details for the layer with given \a layerId.
Expand Down
53 changes: 36 additions & 17 deletions tests/src/core/testqgslayoutgeopdfexport.cpp
Expand Up @@ -23,6 +23,8 @@
#include "qgsproject.h"
#include "qgslayoutexporter.h"
#include "qgslayoutgeopdfexporter.h"
#include <gdal.h>

#include <QObject>
#include "qgstest.h"

Expand Down Expand Up @@ -77,11 +79,6 @@ void TestQgsLayoutGeoPdfExport::cleanup()

void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
{
if ( !QgsAbstractGeoPdfExporter::geoPDFCreationAvailable() )
{
QSKIP( "This test requires GeoPDF creation abilities", SkipSingle );
}

QgsVectorLayer *linesLayer = new QgsVectorLayer( TEST_DATA_DIR + QStringLiteral( "/lines.shp" ),
QStringLiteral( "lines" ), QStringLiteral( "ogr" ) );
QVERIFY( linesLayer->isValid() );
Expand Down Expand Up @@ -133,7 +130,7 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
exporter.exportToPdf( outputFile, settings );

// check that features were collected
QgsFeatureList lineFeatures = geoPdfExporter.mCollatedFeatures.value( linesLayer->id() );
QgsFeatureList lineFeatures = geoPdfExporter.mCollatedFeatures.value( QString() ).value( linesLayer->id() );
QCOMPARE( lineFeatures.count(), 6 );

QgsFeature lineFeature1;
Expand All @@ -149,10 +146,10 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
QVERIFY( lineFeature1.isValid() );
QCOMPARE( lineFeature1.attribute( 0 ).toString(), QStringLiteral( "Highway" ) );
QCOMPARE( lineFeature1.attribute( 1 ).toDouble(), 1.0 );
QgsDebugMsg( lineGeometry1.asWkt( 1 ) );
QCOMPARE( lineGeometry1.asWkt( 1 ), QStringLiteral( "MultiLineString ((281.2 537.3, 283.3 532.1, 284.3 530.1, 285.3 528.5, 289 525.4, 299.3 520.2, 310.2 515.6, 313.3 513, 318.5 507.8, 319 506.8, 320 500.6, 320.5 497.5, 322.1 492.8, 322.6 490.8, 323.1 485.6, 324.1 484, 325.7 480.9, 327.2 477.8, 330.9 473.7, 331.4 472.7, 331.9 469.6, 331.9 464.9, 331.9 462.9, 332.9 458.7, 334 456.6, 338.1 453.5, 341.7 451.5, 345.4 449.4, 349 447.9, 349.5 444.8, 349.5 442.7, 347.4 439.1, 346.4 438, 344.8 434.9, 343.3 432.9, 341.7 431.3, 341.2 430.3, 340.7 427.7, 340.2 425.6, 340.2 423.6, 341.7 419.9, 342.8 417.9, 342.8 417.9, 347.9 406.5, 345.4 401.3, 343.3 399.3, 339.7 393.1, 339.7 388.9, 335 384.8, 333.5 382.2, 330.9 378.1, 330.9 376, 330.9 373.4, 330.9 371.3, 330.9 368.8, 332.4 366.7, 332.9 364.1, 334 362, 336 360, 338.1 356.9, 341.2 353.3, 346.4 343.4, 346.9 342.9, 350.5 339.3, 352.1 337.7, 355.7 332.6, 358.3 330.5, 362.9 327.4, 366 324.8, 369.7 321.2, 372.2 319.6, 375.9 316.5, 380.5 314, 384.1 311.4, 389.8 307.2, 391.9 305.2, 393.5 301.6, 393.5 298.5, 393.5 295.3, 392.9 294.3, 390.9 291.2, 387.8 286.6, 385.7 284.5, 385.2 282.4, 385.2 279.8, 385.7 277.8, 387.3 273.6, 387.8 271.6, 390.9 267.9, 392.4 266.4, 394.5 263.3, 397.6 258.6, 405.9 255))" ) );
QgsDebugMsg( lineGeometry1.asWkt( 0 ) );
QCOMPARE( lineGeometry1.asWkt( 0 ), QStringLiteral( "MultiLineString ((281 538, 283 532, 284 530, 285 529, 289 526, 299 520, 310 516, 313 513, 318 508, 319 507, 320 501, 320 498, 322 493, 323 491, 323 486, 324 484, 326 481, 327 478, 331 474, 331 473, 332 470, 332 465, 332 463, 333 459, 334 457, 338 454, 342 452, 345 450, 349 448, 349 445, 349 443, 347 439, 346 438, 345 435, 343 433, 342 432, 341 430, 341 428, 340 426, 340 424, 342 420, 343 418, 343 418, 348 407, 345 402, 343 399, 340 393, 340 389, 335 385, 333 382, 331 378, 331 376, 331 374, 331 372, 331 369, 332 367, 333 364, 334 362, 336 360, 338 357, 341 353, 346 344, 347 343, 350 339, 352 338, 356 333, 358 331, 363 328, 366 325, 370 321, 372 320, 376 317, 380 314, 384 312, 390 307, 392 305, 393 302, 393 299, 393 295, 393 294, 391 291, 388 287, 386 285, 385 283, 385 280, 386 278, 387 274, 388 272, 391 268, 392 267, 394 263, 398 259, 406 255))" ) );

QgsFeatureList pointFeatures = geoPdfExporter.mCollatedFeatures.value( pointsLayer->id() );
QgsFeatureList pointFeatures = geoPdfExporter.mCollatedFeatures.value( QString() ).value( pointsLayer->id() );
QCOMPARE( pointFeatures.count(), 32 );

QgsFeature pointFeature3;
Expand All @@ -172,10 +169,10 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
QCOMPARE( pointFeature3.attribute( 3 ).toInt(), 1 );
QCOMPARE( pointFeature3.attribute( 4 ).toInt(), 1 );
QCOMPARE( pointFeature3.attribute( 5 ).toInt(), 2 );
QCOMPARE( pointGeometry3.asWkt( 1 ), QStringLiteral( "MultiPolygon (((473.4 305.9, 505.3 305.9, 505.3 274.1, 473.4 274.1, 473.4 305.9)))" ) );
QCOMPARE( pointGeometry3.asWkt( 0 ), QStringLiteral( "MultiPolygon (((473 306, 505 306, 505 274, 473 274, 473 306)))" ) );

// check second map
QgsFeatureList polyFeatures = geoPdfExporter.mCollatedFeatures.value( polygonLayer->id() );
QgsFeatureList polyFeatures = geoPdfExporter.mCollatedFeatures.value( QString() ).value( polygonLayer->id() );
QCOMPARE( polyFeatures.count(), 10 );

QgsFeature polyFeature3b;
Expand All @@ -191,24 +188,46 @@ void TestQgsLayoutGeoPdfExport::testCollectingFeatures()
QVERIFY( polyFeature3b.isValid() );
QCOMPARE( polyFeature3b.attribute( 0 ).toString(), QStringLiteral( "Dam" ) );
QCOMPARE( polyFeature3b.attribute( 1 ).toInt(), 8 );
QgsDebugMsg( polyGeometry3b.asWkt( 1 ) );
QCOMPARE( polyGeometry3b.asWkt( 1 ), QStringLiteral( "MultiPolygon (((468.8 306.3, 468.8 305.2, 468.4 305, 467.8 305, 467.1 305, 466.4 304.2, 466.4 303.8, 466.2 303.3, 466.7 302.6, 467.2 302, 467.7 301.6, 468.6 301.5, 469.6 302.1, 470.4 302.5, 470.9 302.7, 472.1 302.7, 472.8 302.9, 473.6 302.7, 474.2 303, 474.9 303.3, 475.7 303.3, 476.5 303, 478 300.3, 478.1 299.3, 478.1 298.7, 477.8 297.5, 477.7 296.3, 477.5 296.1, 476.3 294.8, 475.6 294.4, 475.4 294.3, 473.9 294, 473.7 294.1, 473 294.4, 472.2 295, 471.6 295.6, 470.8 296.4, 469.6 297, 469.5 297.1, 467.8 296.7, 466 296.3, 463.9 296.1, 463.2 296.1, 462.3 296.7, 461.8 297.7, 461.6 298.1, 460.9 298.5, 459.8 299.3, 459.2 299.5, 458.5 300.1, 458.2 300.5, 458.3 301.2, 458.5 301.6, 458.7 302.4, 458.7 302.8, 458.3 303.6, 457.8 304.1, 457.7 305.1, 458 306, 458.2 306.6, 458.5 307.6, 458.5 307.6, 459.4 308.9, 459.7 309.2, 460.5 310, 461.1 310.4, 461.9 311, 462.4 311.4, 463.2 311.6, 464 311.7, 464.6 311.7, 465.3 311.1, 466.6 309.9, 467.3 309.1, 468.3 307.8, 468.9 306.7, 468.8 306.3)))" ) );
QgsDebugMsg( polyGeometry3b.asWkt( 0 ) );
QCOMPARE( polyGeometry3b.asWkt( 0 ), QStringLiteral( "MultiPolygon (((469 306, 469 305, 468 305, 468 305, 467 305, 466 304, 466 304, 466 303, 467 303, 467 302, 468 302, 469 302, 470 302, 470 303, 471 303, 472 303, 473 303, 474 303, 474 303, 475 303, 476 303, 476 303, 478 300, 478 299, 478 299, 478 298, 478 296, 477 296, 476 295, 476 295, 475 294, 474 294, 474 294, 473 295, 472 295, 472 296, 471 296, 470 297, 469 297, 468 297, 466 296, 464 296, 463 296, 462 297, 462 298, 462 298, 461 299, 460 299, 459 300, 458 300, 458 301, 458 301, 458 302, 459 303, 459 303, 458 304, 458 304, 458 305, 458 306, 458 307, 458 308, 458 308, 459 309, 460 309, 460 310, 461 311, 462 311, 462 312, 463 312, 464 312, 465 312, 465 311, 467 310, 467 309, 468 308, 469 307, 469 306)))" ) );

// finalize and test collation
QgsAbstractGeoPdfExporter::ExportDetails details;
QVERIFY( geoPdfExporter.finalize( QList<QgsAbstractGeoPdfExporter::ComponentLayerDetail>(), outputFile, details ) );
#if GDAL_VERSION_NUM < GDAL_COMPUTE_VERSION(3,0,0)
bool expected = false;
#else
bool expected = true;
#endif
QCOMPARE( geoPdfExporter.finalize( QList<QgsAbstractGeoPdfExporter::ComponentLayerDetail>(), outputFile, details ), expected );
QVERIFY( geoPdfExporter.errorMessage().isEmpty() );

QgsAbstractGeoPdfExporter::VectorComponentDetail vectorDetail;
for ( const auto &it : geoPdfExporter.mVectorComponents )
{
if ( it.mapLayerId == linesLayer->id() )
vectorDetail = it;
}

// read in as vector
std::unique_ptr< QgsVectorLayer > layer1 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=lines" ).arg( outputFile ),
std::unique_ptr< QgsVectorLayer > layer1 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=%2" ).arg( vectorDetail.sourceVectorPath, vectorDetail.sourceVectorLayer ),
QStringLiteral( "lines" ), QStringLiteral( "ogr" ) );
QVERIFY( layer1->isValid() );
QCOMPARE( layer1->featureCount(), 6L );
std::unique_ptr< QgsVectorLayer > layer2 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=points" ).arg( outputFile ),
for ( const auto &it : geoPdfExporter.mVectorComponents )
{
if ( it.mapLayerId == pointsLayer->id() )
vectorDetail = it;
}
std::unique_ptr< QgsVectorLayer > layer2 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=%2" ).arg( vectorDetail.sourceVectorPath, vectorDetail.sourceVectorLayer ),
QStringLiteral( "lines" ), QStringLiteral( "ogr" ) );
QVERIFY( layer2->isValid() );
QCOMPARE( layer2->featureCount(), 32L );
std::unique_ptr< QgsVectorLayer > layer3 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=polys" ).arg( outputFile ),
for ( const auto &it : geoPdfExporter.mVectorComponents )
{
if ( it.mapLayerId == polygonLayer->id() )
vectorDetail = it;
}
std::unique_ptr< QgsVectorLayer > layer3 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "%1|layername=%2" ).arg( vectorDetail.sourceVectorPath, vectorDetail.sourceVectorLayer ),
QStringLiteral( "lines" ), QStringLiteral( "ogr" ) );
QVERIFY( layer3->isValid() );
QCOMPARE( layer3->featureCount(), 10L );
Expand Down

0 comments on commit c8a368f

Please sign in to comment.