Skip to content

Commit 8a9cee0

Browse files
committed
[composer] Use reference map when creating render context for
draw shape/arrow/nodes/paper symbols This commit removes some more instances where changes in the canvas affect compositions. Previously the symbols drawn in shape/arrow/etc items were using the scale from the canvas. This meant that the appearance of these items in composer would change depending on canvas zoom if they used symbols with map unit sizes. Now they take their map scale from the composition's reference map. While this has the nice side effect that now map units can be used in the appearance of these items and they're guaranteed to match up with the reference map item, the main intention here is to remove more of the forced links between compositions (core) and the main canvas (app).
1 parent 8a722d2 commit 8a9cee0

10 files changed

Lines changed: 89 additions & 36 deletions

‎python/core/composer/qgscomposerutils.sip‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,11 @@ class QgsComposerUtils
243243
*/
244244
static void drawText( QPainter* painter, const QRectF& rect, const QString& text, const QFont& font, const QColor& color = QColor(), const Qt::AlignmentFlag halignment = Qt::AlignLeft, const Qt::AlignmentFlag valignment = Qt::AlignTop, const int flags = Qt::TextWordWrap );
245245

246+
/**
247+
* Creates a render context suitable for the specified composition and QPainter destination.
248+
* This method returns a new QgsRenderContext which matches the scale and settings from the composition's
249+
* QgsComposition::referenceMap().
250+
* @note added in QGIS 3.0
251+
*/
252+
static QgsRenderContext createRenderContext( QgsComposition* composition, QPainter& painter );
246253
};

‎src/core/composer/qgscomposerarrow.cpp‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,9 @@ void QgsComposerArrow::drawLine( QPainter *painter )
182182
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
183183

184184
//setup render context
185-
QgsMapSettings ms = mComposition->mapSettings();
186-
//context units should be in dots
187-
ms.setOutputDpi( painter->device()->logicalDpiX() );
188-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
185+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
189186
context.setForceVectorOutput( true );
190-
context.setPainter( painter );
187+
191188
QgsExpressionContext expressionContext = createExpressionContext();
192189
context.setExpressionContext( expressionContext );
193190

‎src/core/composer/qgscomposernodesitem.cpp‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,7 @@ void QgsComposerNodesItem::drawNodes( QPainter *painter ) const
137137
symbol.data()->setSize( rectSize );
138138
symbol.data()->setAngle( 45 );
139139

140-
QgsMapSettings ms = mComposition->mapSettings();
141-
ms.setOutputDpi( painter->device()->logicalDpiX() );
142-
143-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
144-
context.setPainter( painter );
140+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
145141
context.setForceVectorOutput( true );
146142

147143
QgsExpressionContext expressionContext = createExpressionContext();
@@ -172,11 +168,7 @@ void QgsComposerNodesItem::drawSelectedNode( QPainter *painter ) const
172168
symbol.reset( QgsMarkerSymbol::createSimple( properties ) );
173169
symbol.data()->setSize( rectSize );
174170

175-
QgsMapSettings ms = mComposition->mapSettings();
176-
ms.setOutputDpi( painter->device()->logicalDpiX() );
177-
178-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
179-
context.setPainter( painter );
171+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
180172
context.setForceVectorOutput( true );
181173

182174
QgsExpressionContext expressionContext = createExpressionContext();

‎src/core/composer/qgscomposerpolygon.cpp‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,8 @@ void QgsComposerPolygon::_draw( QPainter *painter )
7373
//setup painter scaling to dots so that raster symbology is drawn to scale
7474
const double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
7575

76-
QgsMapSettings ms = mComposition->mapSettings();
77-
ms.setOutputDpi( painter->device()->logicalDpiX() );
78-
79-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
80-
context.setPainter( painter );
76+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
8177
context.setForceVectorOutput( true );
82-
8378
context.setExpressionContext( createExpressionContext() );
8479

8580
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots

‎src/core/composer/qgscomposerpolyline.cpp‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,7 @@ void QgsComposerPolyline::_draw( QPainter *painter )
100100
{
101101
double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
102102

103-
QgsMapSettings ms = mComposition->mapSettings();
104-
ms.setOutputDpi( painter->device()->logicalDpiX() );
105-
106-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
107-
context.setPainter( painter );
103+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
108104
context.setForceVectorOutput( true );
109105

110106
QgsExpressionContext expressionContext = createExpressionContext();

‎src/core/composer/qgscomposershape.cpp‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgssymbollayerutils.h"
2222
#include "qgscomposermodel.h"
2323
#include "qgsmapsettings.h"
24+
#include "qgscomposerutils.h"
2425
#include <QPainter>
2526

2627
QgsComposerShape::QgsComposerShape( QgsComposition* composition )
@@ -178,11 +179,7 @@ void QgsComposerShape::drawShapeUsingSymbol( QPainter* p )
178179
double dotsPerMM = p->device()->logicalDpiX() / 25.4;
179180

180181
//setup render context
181-
QgsMapSettings ms = mComposition->mapSettings();
182-
//context units should be in dots
183-
ms.setOutputDpi( p->device()->logicalDpiX() );
184-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
185-
context.setPainter( p );
182+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *p );
186183
context.setForceVectorOutput( true );
187184
QgsExpressionContext expressionContext = createExpressionContext();
188185
context.setExpressionContext( expressionContext );

‎src/core/composer/qgscomposerutils.cpp‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include "qgscomposerutils.h"
1919
#include "qgscomposition.h"
2020
#include "qgsdatadefined.h"
21+
#include "qgsmapsettings.h"
22+
#include "qgscomposermap.h"
2123
#include <QPainter>
2224

2325
#define FONT_WORKAROUND_SCALE 10 //scale factor for upscaling fontsize and downscaling painter
@@ -545,3 +547,24 @@ void QgsComposerUtils::drawText( QPainter *painter, const QRectF &rect, const QS
545547
painter->drawText( scaledRect, halignment | valignment | flags, text );
546548
painter->restore();
547549
}
550+
551+
QgsRenderContext QgsComposerUtils::createRenderContext( QgsComposition* composition, QPainter &painter )
552+
{
553+
QgsComposerMap* referenceMap = composition ? composition->referenceMap() : nullptr;
554+
if ( !referenceMap )
555+
{
556+
return QgsRenderContext::fromQPainter( &painter );
557+
}
558+
559+
int dpi = painter.device()->logicalDpiX();
560+
double dotsPerMM = dpi / 25.4;
561+
562+
// get map settings from reference map
563+
QgsRectangle extent = *( referenceMap->currentMapExtent() );
564+
QSizeF mapSizeMM = referenceMap->rect().size();
565+
QgsMapSettings ms = referenceMap->mapSettings( extent, mapSizeMM * dotsPerMM, dpi );
566+
567+
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
568+
context.setPainter( &painter );
569+
return context;
570+
}

‎src/core/composer/qgscomposerutils.h‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "qgis_core.h"
2121
#include "qgscomposition.h" //for page size and orientation enums
22+
#include "qgsrendercontext.h"
2223
#include <QPointF>
2324
#include <QRectF>
2425

@@ -265,6 +266,14 @@ class CORE_EXPORT QgsComposerUtils
265266
*/
266267
static void drawText( QPainter* painter, const QRectF& rect, const QString& text, const QFont& font, const QColor& color = QColor(), const Qt::AlignmentFlag halignment = Qt::AlignLeft, const Qt::AlignmentFlag valignment = Qt::AlignTop, const int flags = Qt::TextWordWrap );
267268

269+
/**
270+
* Creates a render context suitable for the specified composition and QPainter destination.
271+
* This method returns a new QgsRenderContext which matches the scale and settings from the composition's
272+
* QgsComposition::referenceMap().
273+
* @note added in QGIS 3.0
274+
*/
275+
static QgsRenderContext createRenderContext( QgsComposition* composition, QPainter& painter );
276+
268277
};
269278

270279
#endif

‎src/core/composer/qgspaperitem.cpp‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "qgsstyle.h"
2121
#include "qgslogger.h"
2222
#include "qgsmapsettings.h"
23+
#include "qgscomposerutils.h"
2324
#include <QGraphicsRectItem>
2425
#include <QGraphicsView>
2526
#include <QPainter>
@@ -155,12 +156,9 @@ void QgsPaperItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* ite
155156
double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
156157

157158
//setup render context
158-
QgsMapSettings ms = mComposition->mapSettings();
159-
//context units should be in dots
160-
ms.setOutputDpi( painter->device()->logicalDpiX() );
161-
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
162-
context.setPainter( painter );
159+
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
163160
context.setForceVectorOutput( true );
161+
164162
QgsExpressionContext expressionContext = createExpressionContext();
165163
context.setExpressionContext( expressionContext );
166164

‎tests/src/core/testqgscomposerutils.cpp‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#include "qgsapplication.h" //for standard test font
1919
#include "qgscomposerutils.h"
2020
#include "qgscomposition.h"
21+
#include "qgscomposermap.h"
2122
#include "qgsmultirenderchecker.h"
2223
#include "qgsdatadefined.h"
2324
#include "qgsfontutils.h"
2425
#include "qgsproject.h"
26+
#include "qgstestutils.h"
2527
#include <QObject>
2628
#include "qgstest.h"
2729
#include <QMap>
@@ -61,6 +63,7 @@ class TestQgsComposerUtils : public QObject
6163
void textHeightMM(); //test calculating text height in mm
6264
void drawTextPos(); //test drawing text at a pos
6365
void drawTextRect(); //test drawing text in a rect
66+
void createRenderContext();
6467

6568
private:
6669
bool renderCheck( const QString& testName, QImage &image, int mismatchCount = 0 );
@@ -701,6 +704,42 @@ void TestQgsComposerUtils::drawTextRect()
701704
QVERIFY( renderCheck( "composerutils_drawtext_rectflag", testImage, 100 ) );
702705
}
703706

707+
void TestQgsComposerUtils::createRenderContext()
708+
{
709+
QImage testImage = QImage( 250, 250, QImage::Format_RGB32 );
710+
testImage.setDotsPerMeterX( 150 / 25.4 * 1000 );
711+
testImage.setDotsPerMeterY( 150 / 25.4 * 1000 );
712+
QPainter p( &testImage );
713+
714+
// no composition
715+
QgsRenderContext rc = QgsComposerUtils::createRenderContext( nullptr, p );
716+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
717+
QCOMPARE( rc.painter(), &p );
718+
719+
//create composition with no reference map
720+
QgsRectangle extent( 2000, 2800, 2500, 2900 );
721+
QgsMapSettings ms;
722+
ms.setExtent( extent );
723+
QgsComposition* composition = new QgsComposition( ms, QgsProject::instance() );
724+
rc = QgsComposerUtils::createRenderContext( composition, p );
725+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
726+
QCOMPARE( rc.painter(), &p );
727+
728+
// add a reference map
729+
QgsComposerMap* map = new QgsComposerMap( composition );
730+
map->setNewExtent( extent );
731+
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
732+
composition->addComposerMap( map );
733+
composition->setReferenceMap( map );
734+
735+
rc = QgsComposerUtils::createRenderContext( composition, p );
736+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
737+
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 100000 );
738+
QCOMPARE( rc.painter(), &p );
739+
740+
p.end();
741+
}
742+
704743
bool TestQgsComposerUtils::renderCheck( const QString& testName, QImage &image, int mismatchCount )
705744
{
706745
mReport += "<h2>" + testName + "</h2>\n";

0 commit comments

Comments
 (0)