QGIS API Documentation  2.13.0-Master
qgscomposermapoverview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposermapoverview.cpp
3  --------------------
4  begin : July 2014
5  copyright : (C) 2014 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgscomposermapoverview.h"
19 #include "qgscomposermap.h"
20 #include "qgscomposition.h"
21 #include "qgssymbollayerv2utils.h"
22 #include "qgssymbolv2.h"
23 
24 #include <QPainter>
25 
27  : QgsComposerMapItem( name, map )
28  , mFrameMapId( -1 )
29  , mFrameSymbol( nullptr )
30  , mBlendMode( QPainter::CompositionMode_SourceOver )
31  , mInverted( false )
32  , mCentered( false )
33 {
34  createDefaultFrameSymbol();
35 }
36 
38  : QgsComposerMapItem( QString(), nullptr )
39  , mFrameMapId( -1 )
40  , mFrameSymbol( nullptr )
41  , mBlendMode( QPainter::CompositionMode_SourceOver )
42  , mInverted( false )
43  , mCentered( false )
44 {
45 }
46 
47 void QgsComposerMapOverview::createDefaultFrameSymbol()
48 {
49  delete mFrameSymbol;
50  QgsStringMap properties;
51  properties.insert( "color", "255,0,0,255" );
52  properties.insert( "style", "solid" );
53  properties.insert( "style_border", "no" );
54  mFrameSymbol = QgsFillSymbolV2::createSimple( properties );
55  mFrameSymbol->setAlpha( 0.3 );
56 }
57 
59 {
60  delete mFrameSymbol;
61 }
62 
64 {
65  if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
66  {
67  return;
68  }
69  if ( !painter )
70  {
71  return;
72  }
73 
74  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
75  if ( !overviewFrameMap )
76  {
77  return;
78  }
79 
80  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
81  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
82 
83  //get current map's extent as a QPolygonF
85  //intersect the two
86  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
87 
88  //setup painter scaling to dots so that raster symbology is drawn to scale
89  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
90 
91  //setup render context
93  //context units should be in dots
94  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
96  ms.setOutputDpi( painter->device()->logicalDpiX() );
98  context.setForceVectorOutput( true );
99  context.setPainter( painter );
100  QgsExpressionContext* expressionContext = createExpressionContext();
101  context.setExpressionContext( *expressionContext );
102  delete expressionContext;
103 
104  painter->save();
105  painter->setCompositionMode( mBlendMode );
106  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
107  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
108  painter->setRenderHint( QPainter::Antialiasing );
109 
110  mFrameSymbol->startRender( context );
111 
112  //construct a polygon corresponding to the intersecting map extent
113  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
114  QTransform mapTransform;
115  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
116 
117  //workaround QT Bug #21329
118  thisRectPoly.pop_back();
119  thisExtent.pop_back();
120 
121  //create transform from map coordinates to painter coordinates
122  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
123  QPolygonF intersectPolygon;
124  intersectPolygon = mapTransform.map( intersectExtent );
125 
126  QList<QPolygonF> rings; //empty list
127  if ( !mInverted )
128  {
129  //Render the intersecting map extent
130  mFrameSymbol->renderPolygon( intersectPolygon, &rings, nullptr, context );
131  }
132  else
133  {
134  //We are inverting the overview frame (ie, shading outside the intersecting extent)
135  //Construct a polygon corresponding to the overview map extent
136  QPolygonF outerPolygon;
137  outerPolygon << QPointF( 0, 0 )
138  << QPointF( mComposerMap->rect().width() * dotsPerMM, 0 )
139  << QPointF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM )
140  << QPointF( 0, mComposerMap->rect().height() * dotsPerMM )
141  << QPointF( 0, 0 );
142 
143  //Intersecting extent is an inner ring for the shaded area
144  rings.append( intersectPolygon );
145  mFrameSymbol->renderPolygon( outerPolygon, &rings, nullptr, context );
146  }
147 
148  mFrameSymbol->stopRender( context );
149  painter->restore();
150 }
151 
153 {
154  if ( elem.isNull() )
155  {
156  return false;
157  }
158 
159  //overview map frame
160  QDomElement overviewFrameElem = doc.createElement( "ComposerMapOverview" );
161 
162  overviewFrameElem.setAttribute( "frameMap", mFrameMapId );
163  overviewFrameElem.setAttribute( "blendMode", QgsMapRenderer::getBlendModeEnum( mBlendMode ) );
164  overviewFrameElem.setAttribute( "inverted", mInverted );
165  overviewFrameElem.setAttribute( "centered", mCentered );
166 
167  QDomElement frameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mFrameSymbol, doc );
168  overviewFrameElem.appendChild( frameStyleElem );
169 
170  bool ok = QgsComposerMapItem::writeXML( overviewFrameElem, doc );
171  elem.appendChild( overviewFrameElem );
172  return ok;
173 }
174 
175 bool QgsComposerMapOverview::readXML( const QDomElement &itemElem, const QDomDocument &doc )
176 {
177  Q_UNUSED( doc );
178  if ( itemElem.isNull() )
179  {
180  return false;
181  }
182 
183  bool ok = QgsComposerMapItem::readXML( itemElem, doc );
184 
185  setFrameMap( itemElem.attribute( "frameMap", "-1" ).toInt() );
186  mBlendMode = QgsMapRenderer::getCompositionMode( static_cast< QgsMapRenderer::BlendMode >( itemElem.attribute( "blendMode", "0" ).toUInt() ) );
187  mInverted = ( itemElem.attribute( "inverted", "0" ) != "0" );
188  mCentered = ( itemElem.attribute( "centered", "0" ) != "0" );
189 
190  QDomElement frameStyleElem = itemElem.firstChildElement( "symbol" );
191  if ( !frameStyleElem.isNull() )
192  {
193  delete mFrameSymbol;
194  mFrameSymbol = QgsSymbolLayerV2Utils::loadSymbol<QgsFillSymbolV2>( frameStyleElem );
195  }
196  return ok;
197 }
198 
200 {
201  return mBlendMode != QPainter::CompositionMode_SourceOver;
202 }
203 
204 void QgsComposerMapOverview::setFrameMap( const int mapId )
205 {
206  if ( mFrameMapId == mapId )
207  {
208  //no change
209  return;
210  }
211 
212  //disconnect old map
213  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
214  {
215  const QgsComposerMap* map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
216  if ( map )
217  {
218  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
219  }
220  }
221  mFrameMapId = mapId;
222  //connect to new map signals
223  connectSignals();
224 }
225 
227 {
228  if ( !mComposerMap )
229  {
230  return;
231  }
232 
233  if ( mFrameMapId != -1 && mComposerMap->composition() )
234  {
235  const QgsComposerMap* map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
236  if ( map )
237  {
238  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
239  }
240  }
241 }
242 
244 {
245  delete mFrameSymbol;
246  mFrameSymbol = symbol;
247 }
248 
249 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
250 {
251  mBlendMode = blendMode;
252 }
253 
255 {
256  mInverted = inverted;
257 }
258 
260 {
261  mCentered = centered;
263 }
264 
266 {
267  if ( !mComposerMap )
268  {
269  return;
270  }
271 
272  //if using overview centering, update the map's extent
273  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
274  {
276 
277  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
278  if ( !overviewFrameMap )
279  {
280  //redraw map so that overview gets updated
281  mComposerMap->update();
282  return;
283  }
284  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
285 
286  QgsPoint center = otherExtent.center();
287  QgsRectangle movedExtent( center.x() - extent.width() / 2,
288  center.y() - extent.height() / 2,
289  center.x() - extent.width() / 2 + extent.width(),
290  center.y() - extent.height() / 2 + extent.height() );
291  *mComposerMap->currentMapExtent() = movedExtent;
292 
293  //trigger a recalculation of data defined extents, scale and rotation, since that
294  //may override the map centering
296 
297  //must invalidate cache so that map gets redrawn
298  mComposerMap->cache();
299  }
300 
301  //repaint map so that overview gets updated
302  mComposerMap->update();
303 }
304 
305 
306 //
307 // QgsComposerMapOverviewStack
308 //
309 
311  : QgsComposerMapItemStack( map )
312 {
313 
314 }
315 
317 {
318 
319 }
320 
322 {
324 }
325 
327 {
329 }
330 
332 {
334 }
335 
337 {
339 }
340 
342 {
344  return dynamic_cast<const QgsComposerMapOverview*>( item );
345 }
346 
348 {
350  return dynamic_cast<QgsComposerMapOverview*>( item );
351 }
352 
354 {
356  return dynamic_cast<QgsComposerMapOverview*>( item );
357 }
358 
360 {
361  QgsComposerMapItem* item = mItems.at( idx );
363  return *overview;
364 }
365 
367 {
370  for ( ; it != mItems.end(); ++it )
371  {
372  QgsComposerMapOverview* overview = dynamic_cast<QgsComposerMapOverview*>( *it );
373  if ( overview )
374  {
375  list.append( overview );
376  }
377  }
378  return list;
379 }
380 
382 {
383  removeItems();
384 
385  //read overview stack
386  QDomNodeList mapOverviewNodeList = elem.elementsByTagName( "ComposerMapOverview" );
387  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
388  {
389  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
390  QgsComposerMapOverview* mapOverview = new QgsComposerMapOverview( mapOverviewElem.attribute( "name" ), mComposerMap );
391  mapOverview->readXML( mapOverviewElem, doc );
392  mItems.append( mapOverview );
393  }
394 
395  return true;
396 }
void connectSignals()
Reconnects signals for overview map, so that overview correctly follows changes to source map&#39;s exten...
void setForceVectorOutput(bool force)
QDomNodeList elementsByTagName(const QString &tagname) const
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void setCompositionMode(CompositionMode mode)
void addItem(QgsComposerMapItem *item)
Adds a new map item to the stack and takes ownership of the item.
void setRenderHint(RenderHint hint, bool on)
QDomNode appendChild(const QDomNode &newChild)
QString attribute(const QString &name, const QString &defValue) const
void setOutputDpi(int dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
QPoint map(const QPoint &point) const
void addOverview(QgsComposerMapOverview *overview)
Adds a new map overview to the stack and takes ownership of the overview.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
QgsComposerMapItem(const QString &name, QgsComposerMap *map)
Constructor for QgsComposerMapItem.
void scale(qreal sx, qreal sy)
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
void cache()
Create cache image.
const T & at(int i) const
bool centered() const
Returns whether the extent of the map is forced to center on the overview.
void moveOverviewDown(const QString &overviewId)
Moves an overview down the stack, causing it to be rendered below other overviews.
static QgsMapRenderer::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void save()
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets overview state from a DOM document.
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
void update(const QRectF &rect)
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
An item which is drawn inside a QgsComposerMap, eg a grid or map overview.
The QgsMapSettings class contains configuration for rendering of the map.
const QgsComposerMapItem * constItem(const QString &itemId) const
Returns a const reference to an item within the stack.
QDomElement toElement() const
virtual QgsExpressionContext * createExpressionContext() const
Creates an expression context relating to the objects&#39; current state.
void append(const T &value)
void setOutputSize(QSize size)
Set the size of the resulting map image.
An individual overview which is drawn above the map content in a QgsComposerMap, and shows the extent...
void setFrameSymbol(QgsFillSymbolV2 *symbol)
Sets the fill symbol used for drawing the overview extent.
void startRender(QgsRenderContext &context, const QgsFields *fields=nullptr)
QPainter::CompositionMode blendMode() const
Retrieves the blending mode used for drawing the overview.
bool mEnabled
True if item is to be displayed on map.
QgsComposerMapOverview & operator[](int idx)
Returns a reference to an overview within the stack.
void setAttribute(const QString &name, const QString &value)
const QgsComposition * composition() const
Returns the composition the item is attached to.
void removeItem(const QString &itemId)
Removes an item from the stack and deletes the corresponding QgsComposerMapItem.
int toInt(bool *ok, int base) const
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void moveItemUp(const QString &itemId)
Moves an item up the stack, causing it to be rendered above other items.
void setCentered(const bool centered)
Sets whether the extent of the map is forced to center on the overview.
QPaintDevice * device() const
void setPainter(QPainter *p)
void removeOverview(const QString &overviewId)
Removes an overview from the stack and deletes the corresponding QgsComposerMapOverview.
QgsComposerMapOverview(const QString &name, QgsComposerMap *map)
Constructor for QgsComposerMapOverview.
void pop_back()
QgsComposerMap * mComposerMap
Associated composer map.
static QPainter::CompositionMode getCompositionMode(BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
const QgsComposerMapOverview * constOverview(const QString &overviewId) const
Returns a const reference to an overview within the stack.
A class to represent a point.
Definition: qgspoint.h:65
QgsComposerMapItem * item(const QString &itemId) const
Returns a reference to an item within the stack.
bool usesAdvancedEffects() const override
Returns true if the item is drawn using advanced effects, such as blend modes.
Object representing map window.
int logicalDpiX() const
void moveItemDown(const QString &itemId)
Moves an item up the stack, causing it to be rendered above other items.
iterator end()
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
void draw(QPainter *painter) override
Draws an overview.
bool isNull() const
QList< QgsComposerMapItem * > mItems
void restore()
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores overview state in DOM element.
bool quadToQuad(const QPolygonF &one, const QPolygonF &two, QTransform &trans)
Contains information about the context of a rendering operation.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties, const QgsExpressionContext *context=nullptr) override
QgsComposerMapOverview * overview(const QString &overviewId) const
Returns a reference to an overview within the stack.
void overviewExtentChanged()
Handles recentering of the map and redrawing of the map&#39;s overview.
qreal width() const
void stopRender(QgsRenderContext &context)
void moveOverviewUp(const QString &overviewId)
Moves an overview up the stack, causing it to be rendered above other overviews.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
A collection of map items which are drawn above the map content in a QgsComposerMap.
QList< QgsComposerMapOverview * > asList() const
Returns a list of QgsComposerMapOverviews contained by the stack.
QDomElement firstChildElement(const QString &tagName) const
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
void translate(const QPointF &offset)
QPolygonF intersected(const QPolygonF &r) const
void setInverted(const bool inverted)
Sets whether the overview frame is inverted, ie, whether the shaded area is drawn outside the extent ...
void setFrameMap(const int mapId)
Sets overview frame map.
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
virtual bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets map item state from a DOM document.
qreal height() const
iterator insert(const Key &key, const T &value)
int size() const
QDomElement createElement(const QString &tagName)
void removeItems()
Clears the item stack and deletes all QgsComposerMapItems contained by the stack. ...
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:206
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores map item state in DOM element.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QgsComposerMapOverviewStack(QgsComposerMap *map)
Constructor for QgsComposerMapOverviewStack.
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:216
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:199
iterator begin()
bool readXML(const QDomElement &elem, const QDomDocument &doc) override
Sets the overview stack&#39;s state from a DOM document.
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the blending mode used for drawing the overview.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:211
QDomNode at(int index) const
QRectF rect() const
QgsComposerMap * mComposerMap
uint toUInt(bool *ok, int base) const
bool inverted() const
Returns whether the overview frame is inverted, ie, whether the shaded area is drawn outside the exte...