Skip to content
Permalink
Browse files

[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).
  • Loading branch information
nyalldawson committed Jan 16, 2017
1 parent 8a722d2 commit 8a9cee0fb657e5c8fffe4accce6795044b164b78
@@ -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 );
};
@@ -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 );

@@ -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();
@@ -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();
@@ -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
@@ -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();
@@ -21,6 +21,7 @@
#include "qgssymbollayerutils.h"
#include "qgscomposermodel.h"
#include "qgsmapsettings.h"
#include "qgscomposerutils.h"
#include <QPainter>

QgsComposerShape::QgsComposerShape( QgsComposition* composition )
@@ -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 );
@@ -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
@@ -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;
}
@@ -19,6 +19,7 @@

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

@@ -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
@@ -20,6 +20,7 @@
#include "qgsstyle.h"
#include "qgslogger.h"
#include "qgsmapsettings.h"
#include "qgscomposerutils.h"
#include <QGraphicsRectItem>
#include <QGraphicsView>
#include <QPainter>
@@ -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 );

@@ -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>
@@ -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 );
@@ -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";

0 comments on commit 8a9cee0

Please sign in to comment.
You can’t perform that action at this time.