Skip to content

Commit

Permalink
Port current geometry from atlas to layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 5, 2018
1 parent 92003c8 commit 2ef3a5f
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 0 deletions.
14 changes: 14 additions & 0 deletions python/core/layout/qgslayoutcontext.sip
Expand Up @@ -104,7 +104,21 @@ Returns the current feature for evaluating the layout. This feature may
be used for altering an item's content and appearance for a report
or atlas layout.

.. seealso:: :py:func:`currentGeometry()`

.. seealso:: :py:func:`setFeature()`
%End

QgsGeometry currentGeometry( const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const;
%Docstring
Returns the current feature() geometry in the given ``crs``.
If no CRS is specified, the original feature geometry is returned.

Reprojection only works if a valid layer is set for layer().

.. seealso:: :py:func:`feature()`

.. seealso:: :py:func:`layer()`
%End

QgsVectorLayer *layer() const;
Expand Down
33 changes: 33 additions & 0 deletions src/core/layout/qgslayoutcontext.cpp
Expand Up @@ -74,9 +74,42 @@ QgsRenderContext::Flags QgsLayoutContext::renderContextFlags() const
void QgsLayoutContext::setFeature( const QgsFeature &feature )
{
mFeature = feature;
mGeometryCache.clear();
emit changed();
}

QgsGeometry QgsLayoutContext::currentGeometry( const QgsCoordinateReferenceSystem &crs ) const
{
if ( !crs.isValid() )
{
// no projection, return the native geometry
return mFeature.geometry();
}

if ( !mLayer || !mFeature.isValid() || !mFeature.hasGeometry() )
{
return QgsGeometry();
}

if ( mLayer->crs() == crs )
{
// no projection, return the native geometry
return mFeature.geometry();
}

auto it = mGeometryCache.constFind( crs.srsid() );
if ( it != mGeometryCache.constEnd() )
{
// we have it in cache, return it
return it.value();
}

QgsGeometry transformed = mFeature.geometry();
transformed.transform( QgsCoordinateTransform( mLayer->crs(), crs, mLayout->project() ) );
mGeometryCache[crs.srsid()] = transformed;
return transformed;
}

QgsVectorLayer *QgsLayoutContext::layer() const
{
return mLayer;
Expand Down
15 changes: 15 additions & 0 deletions src/core/layout/qgslayoutcontext.h
Expand Up @@ -107,10 +107,22 @@ class CORE_EXPORT QgsLayoutContext : public QObject
* Returns the current feature for evaluating the layout. This feature may
* be used for altering an item's content and appearance for a report
* or atlas layout.
* \see currentGeometry()
* \see setFeature()
*/
QgsFeature feature() const { return mFeature; }

/**
* Returns the current feature() geometry in the given \a crs.
* If no CRS is specified, the original feature geometry is returned.
*
* Reprojection only works if a valid layer is set for layer().
*
* \see feature()
* \see layer()
*/
QgsGeometry currentGeometry( const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) const;

/**
* Returns the vector layer associated with the layout's context.
* \see setLayer()
Expand Down Expand Up @@ -262,6 +274,9 @@ class CORE_EXPORT QgsLayoutContext : public QObject
bool mBoundingBoxesVisible = true;
bool mPagesVisible = true;

// projected geometry cache
mutable QMap<long, QgsGeometry> mGeometryCache;

friend class QgsLayoutExporter;
friend class TestQgsLayout;
friend class LayoutContextPreviewSettingRestorer;
Expand Down
44 changes: 44 additions & 0 deletions tests/src/core/testqgslayoutcontext.cpp
Expand Up @@ -19,6 +19,9 @@
#include "qgis.h"
#include "qgsfeature.h"
#include "qgsvectorlayer.h"
#include "qgsgeometry.h"
#include "qgsproject.h"
#include "qgslayout.h"
#include <QObject>
#include "qgstest.h"
#include <QtTest/QSignalSpy>
Expand All @@ -40,6 +43,7 @@ class TestQgsLayoutContext: public QObject
void renderContextFlags();
void boundingBoxes();
void exportLayer();
void geometry();

private:
QString mReport;
Expand Down Expand Up @@ -198,5 +202,45 @@ void TestQgsLayoutContext::exportLayer()
QCOMPARE( context.currentExportLayer(), 1 );
}

void TestQgsLayoutContext::geometry()
{
QgsProject p;
QgsLayout l( &p );
QgsLayoutContext context( &l );

// no feature set
QVERIFY( context.currentGeometry().isNull() );
QVERIFY( context.currentGeometry( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ).isNull() );

// no layer set
QgsFeature f;
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineString( 144 -38, 145 -39 )" ) ) );
context.setFeature( f );
QCOMPARE( context.currentGeometry().asWkt(), f.geometry().asWkt() );
QVERIFY( context.currentGeometry( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ).isNull() );

//with layer
QgsVectorLayer *layer = new QgsVectorLayer( QStringLiteral( "Point?crs=EPSG:4326&field=id_a:integer" ), QStringLiteral( "A" ), QStringLiteral( "memory" ) );
context.setLayer( layer );

QCOMPARE( context.currentGeometry().asWkt(), f.geometry().asWkt() );
QVERIFY( !context.currentGeometry( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ).isNull() );
QCOMPARE( context.currentGeometry( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ).asWkt( 0 ), QStringLiteral( "LineString (2412169 2388563, 2500000 2277996)" ) );

// should be cached
QCOMPARE( context.currentGeometry( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ).asWkt( 0 ), QStringLiteral( "LineString (2412169 2388563, 2500000 2277996)" ) );

// layer crs
QCOMPARE( context.currentGeometry( layer->crs() ).asWkt(), f.geometry().asWkt() );

// clear cache
QgsFeature f2;
context.setFeature( f2 );
QVERIFY( context.currentGeometry().isNull() );
QVERIFY( context.currentGeometry( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) ).isNull() );

delete layer;
}

QGSTEST_MAIN( TestQgsLayoutContext )
#include "testqgslayoutcontext.moc"

0 comments on commit 2ef3a5f

Please sign in to comment.