Skip to content

Commit

Permalink
[api] Add method to retrieve labeling results for layout maps
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 9, 2021
1 parent c95fed5 commit 643e468
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 0 deletions.
9 changes: 9 additions & 0 deletions python/core/auto_generated/layout/qgslayoutitemmap.sip.in
Expand Up @@ -870,6 +870,15 @@ in the area of the map item covered by the item.
Returns map rendering errors

:return: list of errors
%End

QgsLabelingResults *previewLabelingResults() const;
%Docstring
Returns the labeling results of the most recent preview map render. May be ``None`` if no map preview has been rendered in the item.

The map item retains ownership of the returned results.

.. versionadded:: 3.20
%End

virtual bool accept( QgsStyleEntityVisitorInterface *visitor ) const;
Expand Down
12 changes: 12 additions & 0 deletions src/core/layout/qgslayoutitemmap.cpp
Expand Up @@ -36,6 +36,7 @@
#include "qgsannotationlayer.h"
#include "qgscoordinatereferencesystemregistry.h"
#include "qgsprojoperation.h"
#include "qgslabelingresults.h"

#include <QPainter>
#include <QStyleOptionGraphicsItem>
Expand Down Expand Up @@ -1138,7 +1139,10 @@ bool QgsLayoutItemMap::nextExportPart()
if ( mStagedRendererJob->nextPart() )
return true;
else
{
mExportLabelingResults.reset( mStagedRendererJob->takeLabelingResults() );
mStagedRendererJob.reset(); // no more map layer parts
}
}

if ( mExportThemeIt != mExportThemes.end() && ++mExportThemeIt != mExportThemes.end() )
Expand Down Expand Up @@ -1358,6 +1362,8 @@ void QgsLayoutItemMap::drawMap( QPainter *painter, const QgsRectangle &extent, Q
// Raster images were not displayed - see #10599
job.renderSynchronously();

mExportLabelingResults.reset( job.takeLabelingResults() );

mRenderingErrors = job.errors();
}

Expand Down Expand Up @@ -1754,6 +1760,11 @@ bool QgsLayoutItemMap::isLabelBlockingItem( QgsLayoutItem *item ) const
return mBlockingLabelItems.contains( item );
}

QgsLabelingResults *QgsLayoutItemMap::previewLabelingResults() const
{
return mPreviewLabelingResults.get();
}

bool QgsLayoutItemMap::accept( QgsStyleEntityVisitorInterface *visitor ) const
{
// NOTE: if visitEnter returns false it means "don't visit the item", not "abort all further visitations"
Expand Down Expand Up @@ -1951,6 +1962,7 @@ void QgsLayoutItemMap::layersAboutToBeRemoved( const QList<QgsMapLayer *> &layer
void QgsLayoutItemMap::painterJobFinished()
{
mPainter->end();
mPreviewLabelingResults.reset( mPainterJob->takeLabelingResults() );
mPainterJob.reset( nullptr );
mPainter.reset( nullptr );
mCacheFinalImage = std::move( mCacheRenderingImage );
Expand Down
13 changes: 13 additions & 0 deletions src/core/layout/qgslayoutitemmap.h
Expand Up @@ -811,6 +811,15 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan
*/
QgsMapRendererJob::Errors renderingErrors() const { return mRenderingErrors; }

/**
* Returns the labeling results of the most recent preview map render. May be NULLPTR if no map preview has been rendered in the item.
*
* The map item retains ownership of the returned results.
*
* \since QGIS 3.20
*/
QgsLabelingResults *previewLabelingResults() const;

bool accept( QgsStyleEntityVisitorInterface *visitor ) const override;

/**
Expand Down Expand Up @@ -1099,6 +1108,9 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan

std::unique_ptr< QgsMapRendererStagedRenderJob > mStagedRendererJob;

std::unique_ptr< QgsLabelingResults > mPreviewLabelingResults;
std::unique_ptr< QgsLabelingResults > mExportLabelingResults;

void init();

//! Resets the item tooltip to reflect current map id
Expand Down Expand Up @@ -1172,6 +1184,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem, public QgsTemporalRan
friend class TestQgsLayoutMap;
friend class QgsCompositionConverter;
friend class QgsGeoPdfRenderedFeatureHandler;
friend class QgsLayoutExporter;

};

Expand Down
67 changes: 67 additions & 0 deletions tests/src/core/testqgslayoutmap.cpp
Expand Up @@ -37,6 +37,7 @@
#include "qgsfontutils.h"
#include "qgsannotationlayer.h"
#include "qgsannotationmarkeritem.h"
#include "qgslabelingresults.h"

#include <QObject>
#include "qgstest.h"
Expand Down Expand Up @@ -75,6 +76,7 @@ class TestQgsLayoutMap : public QObject
void testLayeredExport();
void testLayeredExportLabelsByLayer();
void testTemporal();
void testLabelResults();

private:
QgsRasterLayer *mRasterLayer = nullptr;
Expand Down Expand Up @@ -1944,5 +1946,70 @@ void TestQgsLayoutMap::testTemporal()
QCOMPARE( renderContext.temporalRange(), QgsDateTimeRange( begin, end, true, false ) );
}

void TestQgsLayoutMap::testLabelResults()
{
QgsProject p;
QgsLayout l( &p );
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );

// test retrieval of labeling results
QgsPalLayerSettings settings;

settings.fieldName = QStringLiteral( "\"id\"" );
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::OverPoint;
settings.priority = 10;
settings.displayAll = true;

QgsVectorLayer *vl2 = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );

QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
f.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( -6.250851540391068, 53.335006994584944 ) ) );
QVERIFY( vl2->dataProvider()->addFeature( f ) );
f.setAttributes( QgsAttributes() << 8888 );
f.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( -21.950014487179544, 64.150023619739216 ) ) );
QVERIFY( vl2->dataProvider()->addFeature( f ) );
f.setAttributes( QgsAttributes() << 33333 );
f.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( -0.118667702475932, 51.5019405883275 ) ) );
QVERIFY( vl2->dataProvider()->addFeature( f ) );
vl2->updateExtents();

p.addMapLayer( vl2 );

vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
vl2->setLabelsEnabled( true );

map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) );
map->setFrameEnabled( false );
map->setBackgroundEnabled( false );
map->setCrs( vl2->crs() );
map->zoomToExtent( vl2->extent() );
map->setLayers( QList<QgsMapLayer *>() << vl2 );
l.addLayoutItem( map );

l.renderContext().mIsPreviewRender = false;
QImage im( 600, 600, QImage::Format_ARGB32_Premultiplied );
QPainter painter( &im );
map->paint( &painter, nullptr, nullptr );
painter.end();

// retrieve label results
std::unique_ptr< QgsLabelingResults > results = std::move( map->mExportLabelingResults );
QVERIFY( results );
QList<QgsLabelPosition> labels = results->allLabels();
QCOMPARE( labels.count(), 3 );
std::sort( labels.begin(), labels.end(), []( const QgsLabelPosition & a, const QgsLabelPosition & b )
{
return a.labelText.compare( b.labelText ) < 0;
} );
QCOMPARE( labels.at( 0 ).labelText, QStringLiteral( "1" ) );
QVERIFY( !labels.at( 0 ).isUnplaced );
QCOMPARE( labels.at( 1 ).labelText, QStringLiteral( "33333" ) );
QVERIFY( !labels.at( 1 ).isUnplaced );
QCOMPARE( labels.at( 2 ).labelText, QStringLiteral( "8888" ) );
QVERIFY( !labels.at( 2 ).isUnplaced );
}

QGSTEST_MAIN( TestQgsLayoutMap )
#include "testqgslayoutmap.moc"

0 comments on commit 643e468

Please sign in to comment.