Skip to content

Commit c282024

Browse files
committedJul 18, 2017
Partially port some layout utils for render context creation
1 parent 7a0851c commit c282024

File tree

8 files changed

+282
-0
lines changed

8 files changed

+282
-0
lines changed
 

‎python/core/layout/qgslayout.sip

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
************************************************************************/
88

99

10+
1011
class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
1112
{
1213
%Docstring
@@ -175,6 +176,13 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
175176
:rtype: list of str
176177
%End
177178

179+
QgsLayoutItemMap *referenceMap() const;
180+
%Docstring
181+
:rtype: QgsLayoutItemMap
182+
%End
183+
184+
void setReferenceMap( QgsLayoutItemMap *map );
185+
178186
signals:
179187

180188
void variablesChanged();

‎python/core/layout/qgslayoututils.sip

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99

1010

11+
1112
class QgsLayoutUtils
1213
{
1314
%Docstring
@@ -28,6 +29,25 @@ class QgsLayoutUtils
2829
:rtype: float
2930
%End
3031

32+
static QgsRenderContext createRenderContextForMap( QgsLayoutItemMap *map, QPainter *painter, double dpi = -1 );
33+
%Docstring
34+
Creates a render context suitable for the specified layout ``map`` and ``painter`` destination.
35+
This method returns a new QgsRenderContext which matches the scale and settings of the
36+
target map. If the ``dpi`` argument is not specified then the dpi will be taken from the destinatation
37+
painter device.
38+
.. seealso:: createRenderContextForLayout()
39+
:rtype: QgsRenderContext
40+
%End
41+
42+
static QgsRenderContext createRenderContextForLayout( QgsLayout *layout, QPainter *painter );
43+
%Docstring
44+
Creates a render context suitable for the specified ``layout`` and ``painter`` destination.
45+
This method returns a new QgsRenderContext which matches the scale and settings from the layout's
46+
QgsLayout.referenceMap().
47+
.. seealso:: createRenderContextForMap()
48+
:rtype: QgsRenderContext
49+
%End
50+
3151
};
3252

3353
/************************************************************************

‎src/core/layout/qgslayout.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,13 @@ QStringList QgsLayout::customProperties() const
9393
{
9494
return mCustomProperties.keys();
9595
}
96+
97+
QgsLayoutItemMap *QgsLayout::referenceMap() const
98+
{
99+
return nullptr;
100+
}
101+
102+
void QgsLayout::setReferenceMap( QgsLayoutItemMap *map )
103+
{
104+
Q_UNUSED( map );
105+
}

‎src/core/layout/qgslayout.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "qgslayoutcontext.h"
2222
#include "qgsexpressioncontextgenerator.h"
2323

24+
class QgsLayoutItemMap;
25+
2426
/**
2527
* \ingroup core
2628
* \class QgsLayout
@@ -182,6 +184,25 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
182184
*/
183185
QStringList customProperties() const;
184186

187+
/**
188+
* Returns the map item which will be used to generate corresponding world files when the
189+
* layout is exported. If no map was explicitly set via setReferenceMap(), the largest
190+
* map in the layout will be returned (or nullptr if there are no maps in the layout).
191+
* \see setReferenceMap()
192+
* \see generateWorldFile()
193+
*/
194+
//TODO
195+
QgsLayoutItemMap *referenceMap() const;
196+
197+
/**
198+
* Sets the \a map item which will be used to generate corresponding world files when the
199+
* layout is exported.
200+
* \see referenceMap()
201+
* \see setGenerateWorldFile()
202+
*/
203+
//TODO
204+
void setReferenceMap( QgsLayoutItemMap *map );
205+
185206
signals:
186207

187208
/**

‎src/core/layout/qgslayoututils.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
***************************************************************************/
1717

1818
#include "qgslayoututils.h"
19+
#include "qgslayout.h"
20+
#include "qgsrendercontext.h"
21+
#include "qgslayoutitemmap.h"
22+
#include <QPainter>
1923
#include <math.h>
2024

2125
double QgsLayoutUtils::normalizedAngle( const double angle, const bool allowNegative )
@@ -31,3 +35,51 @@ double QgsLayoutUtils::normalizedAngle( const double angle, const bool allowNega
3135
}
3236
return clippedAngle;
3337
}
38+
39+
QgsRenderContext QgsLayoutUtils::createRenderContextForMap( QgsLayoutItemMap *map, QPainter *painter, double dpi )
40+
{
41+
if ( !map )
42+
{
43+
QgsRenderContext context;
44+
context.setPainter( painter );
45+
if ( dpi < 0 && painter && painter->device() )
46+
{
47+
context.setScaleFactor( painter->device()->logicalDpiX() / 25.4 );
48+
}
49+
else if ( dpi > 0 )
50+
{
51+
context.setScaleFactor( dpi / 25.4 );
52+
}
53+
else
54+
{
55+
context.setScaleFactor( 3.465 ); //assume 88 dpi as standard value
56+
}
57+
return context;
58+
}
59+
else
60+
{
61+
// default to 88 dpi if no painter specified
62+
if ( dpi < 0 )
63+
{
64+
dpi = ( painter && painter->device() ) ? painter->device()->logicalDpiX() : 88;
65+
}
66+
#if 0
67+
double dotsPerMM = dpi / 25.4;
68+
// TODO
69+
// get map settings from reference map
70+
QgsRectangle extent = *( map->currentMapExtent() );
71+
QSizeF mapSizeMM = map->rect().size();
72+
QgsMapSettings ms = map->mapSettings( extent, mapSizeMM * dotsPerMM, dpi );
73+
#endif
74+
QgsRenderContext context; // = QgsRenderContext::fromMapSettings( ms );
75+
if ( painter )
76+
context.setPainter( painter );
77+
return context;
78+
}
79+
}
80+
81+
QgsRenderContext QgsLayoutUtils::createRenderContextForLayout( QgsLayout *layout, QPainter *painter )
82+
{
83+
QgsLayoutItemMap *referenceMap = layout ? layout->referenceMap() : nullptr;
84+
return createRenderContextForMap( referenceMap, painter );
85+
}

‎src/core/layout/qgslayoututils.h

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

2020
#include "qgis_core.h"
2121

22+
class QgsRenderContext;
23+
class QgsLayout;
24+
class QgsLayoutItemMap;
25+
class QPainter;
26+
2227
/**
2328
* \ingroup core
2429
* Utilities for layouts.
@@ -35,6 +40,23 @@ class CORE_EXPORT QgsLayoutUtils
3540
*/
3641
static double normalizedAngle( const double angle, const bool allowNegative = false );
3742

43+
/**
44+
* Creates a render context suitable for the specified layout \a map and \a painter destination.
45+
* This method returns a new QgsRenderContext which matches the scale and settings of the
46+
* target map. If the \a dpi argument is not specified then the dpi will be taken from the destinatation
47+
* painter device.
48+
* \see createRenderContextForLayout()
49+
*/
50+
static QgsRenderContext createRenderContextForMap( QgsLayoutItemMap *map, QPainter *painter, double dpi = -1 );
51+
52+
/**
53+
* Creates a render context suitable for the specified \a layout and \a painter destination.
54+
* This method returns a new QgsRenderContext which matches the scale and settings from the layout's
55+
* QgsLayout::referenceMap().
56+
* \see createRenderContextForMap()
57+
*/
58+
static QgsRenderContext createRenderContextForLayout( QgsLayout *layout, QPainter *painter );
59+
3860
};
3961

4062
#endif //QGSLAYOUTUTILS_H

‎tests/src/core/testqgslayout.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "qgslayout.h"
1919
#include "qgstest.h"
2020
#include "qgsproject.h"
21+
#include "qgslayoutitemmap.h"
2122

2223
class TestQgsLayout: public QObject
2324
{
@@ -34,6 +35,7 @@ class TestQgsLayout: public QObject
3435
void customProperties();
3536
void variablesEdited();
3637
void scope();
38+
void referenceMap();
3739

3840
private:
3941
QString mReport;
@@ -213,6 +215,37 @@ void TestQgsLayout::scope()
213215

214216
}
215217

218+
void TestQgsLayout::referenceMap()
219+
{
220+
QgsRectangle extent( 2000, 2800, 2500, 2900 );
221+
QgsProject p;
222+
QgsLayout l( &p );
223+
224+
// no maps
225+
QVERIFY( !l.referenceMap() );
226+
#if 0
227+
228+
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
229+
map->setNewExtent( extent );
230+
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
231+
l.addComposerMap( map );
232+
QCOMPARE( l.referenceMap(), map );
233+
#endif
234+
#if 0 // TODO
235+
236+
// add a larger map
237+
QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );
238+
map2->setNewExtent( extent );
239+
map2->setSceneRect( QRectF( 30, 60, 250, 150 ) );
240+
l.addComposerMap( map2 );
241+
QCOMPARE( l.referenceMap(), map2 );
242+
// explicitly set reference map
243+
l.setReferenceMap( map );
244+
QCOMPARE( l.referenceMap(), map );
245+
#endif
246+
247+
}
248+
216249

217250
QGSTEST_MAIN( TestQgsLayout )
218251
#include "testqgslayout.moc"

‎tests/src/core/testqgslayoututils.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
#include "qgslayout.h"
1919
#include "qgstest.h"
2020
#include "qgslayoututils.h"
21+
#include "qgstestutils.h"
22+
#include "qgsproject.h"
23+
#include "qgslayoutitemmap.h"
2124

2225
class TestQgsLayoutUtils: public QObject
2326
{
@@ -29,6 +32,8 @@ class TestQgsLayoutUtils: public QObject
2932
void init();// will be called before each testfunction is executed.
3033
void cleanup();// will be called after every testfunction.
3134
void normalizedAngle(); //test normalised angle function
35+
void createRenderContextFromLayout();
36+
void createRenderContextFromMap();
3237

3338
private:
3439
QString mReport;
@@ -112,5 +117,116 @@ void TestQgsLayoutUtils::normalizedAngle()
112117
}
113118

114119

120+
void TestQgsLayoutUtils::createRenderContextFromLayout()
121+
{
122+
QImage testImage = QImage( 250, 250, QImage::Format_RGB32 );
123+
testImage.setDotsPerMeterX( 150 / 25.4 * 1000 );
124+
testImage.setDotsPerMeterY( 150 / 25.4 * 1000 );
125+
QPainter p( &testImage );
126+
127+
// no composition
128+
QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( nullptr, &p );
129+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
130+
QCOMPARE( rc.painter(), &p );
131+
132+
// no composition, no painter
133+
rc = QgsLayoutUtils::createRenderContextForLayout( nullptr, nullptr );
134+
QGSCOMPARENEAR( rc.scaleFactor(), 88 / 25.4, 0.001 );
135+
QVERIFY( !rc.painter() );
136+
137+
//create composition with no reference map
138+
QgsRectangle extent( 2000, 2800, 2500, 2900 );
139+
QgsProject project;
140+
QgsLayout l( &project );
141+
rc = QgsLayoutUtils::createRenderContextForLayout( &l, &p );
142+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
143+
QCOMPARE( rc.painter(), &p );
144+
145+
// layout, no map, no painter
146+
rc = QgsLayoutUtils::createRenderContextForLayout( &l, nullptr );
147+
QGSCOMPARENEAR( rc.scaleFactor(), 88 / 25.4, 0.001 );
148+
QVERIFY( !rc.painter() );
149+
150+
// add a reference map
151+
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
152+
#if 0 // TODO
153+
map->setNewExtent( extent );
154+
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
155+
composition->addComposerMap( map );
156+
#endif
157+
l.setReferenceMap( map );
158+
159+
rc = QgsLayoutUtils::createRenderContextForLayout( &l, &p );
160+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
161+
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 1000000 );
162+
QCOMPARE( rc.painter(), &p );
163+
164+
// layout, reference map, no painter
165+
rc = QgsLayoutUtils::createRenderContextForLayout( &l, nullptr );
166+
QGSCOMPARENEAR( rc.scaleFactor(), 88 / 25.4, 0.001 );
167+
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 1000000 );
168+
QVERIFY( !rc.painter() );
169+
170+
p.end();
171+
}
172+
173+
void TestQgsLayoutUtils::createRenderContextFromMap()
174+
{
175+
QImage testImage = QImage( 250, 250, QImage::Format_RGB32 );
176+
testImage.setDotsPerMeterX( 150 / 25.4 * 1000 );
177+
testImage.setDotsPerMeterY( 150 / 25.4 * 1000 );
178+
QPainter p( &testImage );
179+
180+
// no map
181+
QgsRenderContext rc = QgsLayoutUtils::createRenderContextForMap( nullptr, &p );
182+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
183+
QCOMPARE( rc.painter(), &p );
184+
185+
// no map, no painter
186+
rc = QgsLayoutUtils::createRenderContextForMap( nullptr, nullptr );
187+
QGSCOMPARENEAR( rc.scaleFactor(), 88 / 25.4, 0.001 );
188+
QVERIFY( !rc.painter() );
189+
190+
//create composition with no reference map
191+
QgsRectangle extent( 2000, 2800, 2500, 2900 );
192+
QgsProject project;
193+
QgsLayout l( &project );
194+
195+
#if 0 // TODO
196+
// add a map
197+
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
198+
199+
map->setNewExtent( extent );
200+
map->setSceneRect( QRectF( 30, 60, 200, 100 ) );
201+
l.addComposerMap( map );
202+
#endif
203+
204+
#if 0 //TODO
205+
rc = QgsLayoutUtils::createRenderContextForMap( map, &p );
206+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
207+
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 1000000 );
208+
QCOMPARE( rc.painter(), &p );
209+
210+
// map, no painter
211+
rc = QgsLayoutUtils::createRenderContextForMap( map, nullptr );
212+
QGSCOMPARENEAR( rc.scaleFactor(), 88 / 25.4, 0.001 );
213+
QGSCOMPARENEAR( rc.rendererScale(), map->scale(), 1000000 );
214+
QVERIFY( !rc.painter() );
215+
216+
// secondary map
217+
QgsLayoutItemMap *map2 = new QgsLayoutItemMap( &l );
218+
219+
map2->setNewExtent( extent );
220+
map2->setSceneRect( QRectF( 30, 60, 100, 50 ) );
221+
composition->addComposerMap( map2 );
222+
223+
rc = QgsLayoutUtils::createRenderContextForMap( map2, &p );
224+
QGSCOMPARENEAR( rc.scaleFactor(), 150 / 25.4, 0.001 );
225+
QGSCOMPARENEAR( rc.rendererScale(), map2->scale(), 1000000 );
226+
QVERIFY( rc.painter() );
227+
#endif
228+
p.end();
229+
}
230+
115231
QGSTEST_MAIN( TestQgsLayoutUtils )
116232
#include "testqgslayoututils.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.