Skip to content

Commit

Permalink
[composer] Use reference map when creating render context for
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
nyalldawson committed Jan 16, 2017
1 parent 8a722d2 commit 8a9cee0
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 36 deletions.
7 changes: 7 additions & 0 deletions python/core/composer/qgscomposerutils.sip
Original file line number Diff line number Diff line change
Expand Up @@ -243,4 +243,11 @@ class QgsComposerUtils
*/
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 );

/**
* Creates a render context suitable for the specified composition and QPainter destination.
* This method returns a new QgsRenderContext which matches the scale and settings from the composition's
* QgsComposition::referenceMap().
* @note added in QGIS 3.0
*/
static QgsRenderContext createRenderContext( QgsComposition* composition, QPainter& painter );
};
7 changes: 2 additions & 5 deletions src/core/composer/qgscomposerarrow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,9 @@ void QgsComposerArrow::drawLine( QPainter *painter )
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots

//setup render context
QgsMapSettings ms = mComposition->mapSettings();
//context units should be in dots
ms.setOutputDpi( painter->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
context.setForceVectorOutput( true );
context.setPainter( painter );

QgsExpressionContext expressionContext = createExpressionContext();
context.setExpressionContext( expressionContext );

Expand Down
12 changes: 2 additions & 10 deletions src/core/composer/qgscomposernodesitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,7 @@ void QgsComposerNodesItem::drawNodes( QPainter *painter ) const
symbol.data()->setSize( rectSize );
symbol.data()->setAngle( 45 );

QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );

QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
context.setForceVectorOutput( true );

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

QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );

QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
context.setForceVectorOutput( true );

QgsExpressionContext expressionContext = createExpressionContext();
Expand Down
7 changes: 1 addition & 6 deletions src/core/composer/qgscomposerpolygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,8 @@ void QgsComposerPolygon::_draw( QPainter *painter )
//setup painter scaling to dots so that raster symbology is drawn to scale
const double dotsPerMM = painter->device()->logicalDpiX() / 25.4;

QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );

QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
context.setForceVectorOutput( true );

context.setExpressionContext( createExpressionContext() );

painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
Expand Down
6 changes: 1 addition & 5 deletions src/core/composer/qgscomposerpolyline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,7 @@ void QgsComposerPolyline::_draw( QPainter *painter )
{
double dotsPerMM = painter->device()->logicalDpiX() / 25.4;

QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );

QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
context.setForceVectorOutput( true );

QgsExpressionContext expressionContext = createExpressionContext();
Expand Down
7 changes: 2 additions & 5 deletions src/core/composer/qgscomposershape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "qgssymbollayerutils.h"
#include "qgscomposermodel.h"
#include "qgsmapsettings.h"
#include "qgscomposerutils.h"
#include <QPainter>

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

//setup render context
QgsMapSettings ms = mComposition->mapSettings();
//context units should be in dots
ms.setOutputDpi( p->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( p );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *p );
context.setForceVectorOutput( true );
QgsExpressionContext expressionContext = createExpressionContext();
context.setExpressionContext( expressionContext );
Expand Down
23 changes: 23 additions & 0 deletions src/core/composer/qgscomposerutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "qgscomposerutils.h"
#include "qgscomposition.h"
#include "qgsdatadefined.h"
#include "qgsmapsettings.h"
#include "qgscomposermap.h"
#include <QPainter>

#define FONT_WORKAROUND_SCALE 10 //scale factor for upscaling fontsize and downscaling painter
Expand Down Expand Up @@ -545,3 +547,24 @@ void QgsComposerUtils::drawText( QPainter *painter, const QRectF &rect, const QS
painter->drawText( scaledRect, halignment | valignment | flags, text );
painter->restore();
}

QgsRenderContext QgsComposerUtils::createRenderContext( QgsComposition* composition, QPainter &painter )
{
QgsComposerMap* referenceMap = composition ? composition->referenceMap() : nullptr;
if ( !referenceMap )
{
return QgsRenderContext::fromQPainter( &painter );
}

int dpi = painter.device()->logicalDpiX();
double dotsPerMM = dpi / 25.4;

// get map settings from reference map
QgsRectangle extent = *( referenceMap->currentMapExtent() );
QSizeF mapSizeMM = referenceMap->rect().size();
QgsMapSettings ms = referenceMap->mapSettings( extent, mapSizeMM * dotsPerMM, dpi );

QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( &painter );
return context;
}
9 changes: 9 additions & 0 deletions src/core/composer/qgscomposerutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "qgis_core.h"
#include "qgscomposition.h" //for page size and orientation enums
#include "qgsrendercontext.h"
#include <QPointF>
#include <QRectF>

Expand Down Expand Up @@ -265,6 +266,14 @@ class CORE_EXPORT QgsComposerUtils
*/
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 );

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

};

#endif
8 changes: 3 additions & 5 deletions src/core/composer/qgspaperitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "qgsstyle.h"
#include "qgslogger.h"
#include "qgsmapsettings.h"
#include "qgscomposerutils.h"
#include <QGraphicsRectItem>
#include <QGraphicsView>
#include <QPainter>
Expand Down Expand Up @@ -155,12 +156,9 @@ void QgsPaperItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* ite
double dotsPerMM = painter->device()->logicalDpiX() / 25.4;

//setup render context
QgsMapSettings ms = mComposition->mapSettings();
//context units should be in dots
ms.setOutputDpi( painter->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
QgsRenderContext context = QgsComposerUtils::createRenderContext( mComposition, *painter );
context.setForceVectorOutput( true );

QgsExpressionContext expressionContext = createExpressionContext();
context.setExpressionContext( expressionContext );

Expand Down
39 changes: 39 additions & 0 deletions tests/src/core/testqgscomposerutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
#include "qgsapplication.h" //for standard test font
#include "qgscomposerutils.h"
#include "qgscomposition.h"
#include "qgscomposermap.h"
#include "qgsmultirenderchecker.h"
#include "qgsdatadefined.h"
#include "qgsfontutils.h"
#include "qgsproject.h"
#include "qgstestutils.h"
#include <QObject>
#include "qgstest.h"
#include <QMap>
Expand Down Expand Up @@ -61,6 +63,7 @@ class TestQgsComposerUtils : public QObject
void textHeightMM(); //test calculating text height in mm
void drawTextPos(); //test drawing text at a pos
void drawTextRect(); //test drawing text in a rect
void createRenderContext();

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

void TestQgsComposerUtils::createRenderContext()
{
QImage testImage = QImage( 250, 250, QImage::Format_RGB32 );
testImage.setDotsPerMeterX( 150 / 25.4 * 1000 );
testImage.setDotsPerMeterY( 150 / 25.4 * 1000 );
QPainter p( &testImage );

// no composition
QgsRenderContext rc = QgsComposerUtils::createRenderContext( nullptr, p );
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
QCOMPARE( rc.painter(), &p );

//create composition with no reference map
QgsRectangle extent( 2000, 2800, 2500, 2900 );
QgsMapSettings ms;
ms.setExtent( extent );
QgsComposition* composition = new QgsComposition( ms, QgsProject::instance() );
rc = QgsComposerUtils::createRenderContext( composition, p );
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
QCOMPARE( rc.painter(), &p );

// add a reference map
QgsComposerMap* map = new QgsComposerMap( composition );
map->setNewExtent( extent );
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
composition->addComposerMap( map );
composition->setReferenceMap( map );

rc = QgsComposerUtils::createRenderContext( composition, p );
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 100000 );
QCOMPARE( rc.painter(), &p );

p.end();
}

bool TestQgsComposerUtils::renderCheck( const QString& testName, QImage &image, int mismatchCount )
{
mReport += "<h2>" + testName + "</h2>\n";
Expand Down

0 comments on commit 8a9cee0

Please sign in to comment.