QGIS API Documentation  2.99.0-Master (40f86b2)
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 "qgssymbollayerutils.h"
22 #include "qgssymbol.h"
23 #include "qgsmapsettings.h"
24 #include "qgspainting.h"
25 #include "qgscomposerutils.h"
26 
27 #include <QPainter>
28 
30  : QgsComposerMapItem( name, map )
31  , mFrameMapId( -1 )
32  , mFrameSymbol( nullptr )
33  , mBlendMode( QPainter::CompositionMode_SourceOver )
34  , mInverted( false )
35  , mCentered( false )
36 {
37  createDefaultFrameSymbol();
38 }
39 
41  : QgsComposerMapItem( QString(), nullptr )
42  , mFrameMapId( -1 )
43  , mFrameSymbol( nullptr )
44  , mBlendMode( QPainter::CompositionMode_SourceOver )
45  , mInverted( false )
46  , mCentered( false )
47 {
48 }
49 
50 void QgsComposerMapOverview::createDefaultFrameSymbol()
51 {
52  delete mFrameSymbol;
53  QgsStringMap properties;
54  properties.insert( QStringLiteral( "color" ), QStringLiteral( "255,0,0,255" ) );
55  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
56  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
57  mFrameSymbol = QgsFillSymbol::createSimple( properties );
58  mFrameSymbol->setAlpha( 0.3 );
59 }
60 
62 {
63  delete mFrameSymbol;
64 }
65 
66 void QgsComposerMapOverview::draw( QPainter *painter )
67 {
68  if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
69  {
70  return;
71  }
72  if ( !painter )
73  {
74  return;
75  }
76 
77  const QgsComposerMap *overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
78  if ( !overviewFrameMap )
79  {
80  return;
81  }
82 
83  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
84  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
85 
86  //get current map's extent as a QPolygonF
87  QPolygonF thisExtent = mComposerMap->visibleExtentPolygon();
88  //intersect the two
89  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
90 
91  //setup painter scaling to dots so that raster symbology is drawn to scale
92  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
93 
94  //setup render context
96  context.setForceVectorOutput( true );
97  QgsExpressionContext expressionContext = createExpressionContext();
98  context.setExpressionContext( expressionContext );
99 
100  painter->save();
101  painter->setCompositionMode( mBlendMode );
102  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
103  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
104  painter->setRenderHint( QPainter::Antialiasing );
105 
106  mFrameSymbol->startRender( context );
107 
108  //construct a polygon corresponding to the intersecting map extent
109  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
110  QTransform mapTransform;
111  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
112 
113  //workaround QT Bug #21329
114  thisRectPoly.pop_back();
115  thisExtent.pop_back();
116 
117  //create transform from map coordinates to painter coordinates
118  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
119  QPolygonF intersectPolygon;
120  intersectPolygon = mapTransform.map( intersectExtent );
121 
122  QList<QPolygonF> rings; //empty list
123  if ( !mInverted )
124  {
125  //Render the intersecting map extent
126  mFrameSymbol->renderPolygon( intersectPolygon, &rings, nullptr, context );
127  }
128  else
129  {
130  //We are inverting the overview frame (ie, shading outside the intersecting extent)
131  //Construct a polygon corresponding to the overview map extent
132  QPolygonF outerPolygon;
133  outerPolygon << QPointF( 0, 0 )
134  << QPointF( mComposerMap->rect().width() * dotsPerMM, 0 )
135  << QPointF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM )
136  << QPointF( 0, mComposerMap->rect().height() * dotsPerMM )
137  << QPointF( 0, 0 );
138 
139  //Intersecting extent is an inner ring for the shaded area
140  rings.append( intersectPolygon );
141  mFrameSymbol->renderPolygon( outerPolygon, &rings, nullptr, context );
142  }
143 
144  mFrameSymbol->stopRender( context );
145  painter->restore();
146 }
147 
148 bool QgsComposerMapOverview::writeXml( QDomElement &elem, QDomDocument &doc ) const
149 {
150  if ( elem.isNull() )
151  {
152  return false;
153  }
154 
155  //overview map frame
156  QDomElement overviewFrameElem = doc.createElement( QStringLiteral( "ComposerMapOverview" ) );
157 
158  overviewFrameElem.setAttribute( QStringLiteral( "frameMap" ), mFrameMapId );
159  overviewFrameElem.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( mBlendMode ) );
160  overviewFrameElem.setAttribute( QStringLiteral( "inverted" ), mInverted );
161  overviewFrameElem.setAttribute( QStringLiteral( "centered" ), mCentered );
162 
163  QDomElement frameStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mFrameSymbol, doc );
164  overviewFrameElem.appendChild( frameStyleElem );
165 
166  bool ok = QgsComposerMapItem::writeXml( overviewFrameElem, doc );
167  elem.appendChild( overviewFrameElem );
168  return ok;
169 }
170 
171 bool QgsComposerMapOverview::readXml( const QDomElement &itemElem, const QDomDocument &doc )
172 {
173  Q_UNUSED( doc );
174  if ( itemElem.isNull() )
175  {
176  return false;
177  }
178 
179  bool ok = QgsComposerMapItem::readXml( itemElem, doc );
180 
181  setFrameMap( itemElem.attribute( QStringLiteral( "frameMap" ), QStringLiteral( "-1" ) ).toInt() );
182  mBlendMode = QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) );
183  mInverted = ( itemElem.attribute( QStringLiteral( "inverted" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
184  mCentered = ( itemElem.attribute( QStringLiteral( "centered" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
185 
186  QDomElement frameStyleElem = itemElem.firstChildElement( QStringLiteral( "symbol" ) );
187  if ( !frameStyleElem.isNull() )
188  {
189  delete mFrameSymbol;
190  mFrameSymbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( frameStyleElem );
191  }
192  return ok;
193 }
194 
196 {
197  return mBlendMode != QPainter::CompositionMode_SourceOver;
198 }
199 
200 void QgsComposerMapOverview::setFrameMap( const int mapId )
201 {
202  if ( mFrameMapId == mapId )
203  {
204  //no change
205  return;
206  }
207 
208  //disconnect old map
209  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
210  {
211  const QgsComposerMap *map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
212  if ( map )
213  {
215  }
216  }
217  mFrameMapId = mapId;
218  //connect to new map signals
219  connectSignals();
220 }
221 
223 {
224  if ( !mComposerMap )
225  {
226  return;
227  }
228 
229  if ( mFrameMapId != -1 && mComposerMap->composition() )
230  {
231  const QgsComposerMap *map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
232  if ( map )
233  {
235  }
236  }
237 }
238 
240 {
241  delete mFrameSymbol;
242  mFrameSymbol = symbol;
243 }
244 
245 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
246 {
247  mBlendMode = blendMode;
248 }
249 
251 {
252  mInverted = inverted;
253 }
254 
256 {
257  mCentered = centered;
259 }
260 
262 {
263  if ( !mComposerMap )
264  {
265  return;
266  }
267 
268  //if using overview centering, update the map's extent
269  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
270  {
272 
273  const QgsComposerMap *overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
274  if ( !overviewFrameMap )
275  {
276  //redraw map so that overview gets updated
277  mComposerMap->update();
278  return;
279  }
280  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
281 
282  QgsPoint center = otherExtent.center();
283  QgsRectangle movedExtent( center.x() - extent.width() / 2,
284  center.y() - extent.height() / 2,
285  center.x() - extent.width() / 2 + extent.width(),
286  center.y() - extent.height() / 2 + extent.height() );
287  *mComposerMap->currentMapExtent() = movedExtent;
288 
289  //trigger a recalculation of data defined extents, scale and rotation, since that
290  //may override the map centering
292 
293  //must invalidate cache so that map gets redrawn
294  mComposerMap->cache();
295  }
296 
297  //repaint map so that overview gets updated
298  mComposerMap->update();
299 }
300 
301 
302 //
303 // QgsComposerMapOverviewStack
304 //
305 
307  : QgsComposerMapItemStack( map )
308 {
309 
310 }
311 
313 {
315 }
316 
317 void QgsComposerMapOverviewStack::removeOverview( const QString &overviewId )
318 {
320 }
321 
322 void QgsComposerMapOverviewStack::moveOverviewUp( const QString &overviewId )
323 {
325 }
326 
327 void QgsComposerMapOverviewStack::moveOverviewDown( const QString &overviewId )
328 {
330 }
331 
333 {
335  return dynamic_cast<const QgsComposerMapOverview *>( item );
336 }
337 
339 {
341  return dynamic_cast<QgsComposerMapOverview *>( item );
342 }
343 
345 {
347  return dynamic_cast<QgsComposerMapOverview *>( item );
348 }
349 
351 {
352  QgsComposerMapItem *item = mItems.at( idx );
354  return *overview;
355 }
356 
357 QList<QgsComposerMapOverview *> QgsComposerMapOverviewStack::asList() const
358 {
359  QList< QgsComposerMapOverview * > list;
360  QList< QgsComposerMapItem * >::const_iterator it = mItems.begin();
361  for ( ; it != mItems.end(); ++it )
362  {
363  QgsComposerMapOverview *overview = dynamic_cast<QgsComposerMapOverview *>( *it );
364  if ( overview )
365  {
366  list.append( overview );
367  }
368  }
369  return list;
370 }
371 
372 bool QgsComposerMapOverviewStack::readXml( const QDomElement &elem, const QDomDocument &doc )
373 {
374  removeItems();
375 
376  //read overview stack
377  QDomNodeList mapOverviewNodeList = elem.elementsByTagName( QStringLiteral( "ComposerMapOverview" ) );
378  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
379  {
380  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
381  QgsComposerMapOverview *mapOverview = new QgsComposerMapOverview( mapOverviewElem.attribute( QStringLiteral( "name" ) ), mComposerMap );
382  mapOverview->readXml( mapOverviewElem, doc );
383  mItems.append( mapOverview );
384  }
385 
386  return true;
387 }
QgsComposerMapItem * item(const QString &itemId) const
Returns a reference to an item within the stack.
void connectSignals()
Reconnects signals for overview map, so that overview correctly follows changes to source map&#39;s exten...
bool centered() const
Returns whether the extent of the map is forced to center on the overview.
void setForceVectorOutput(bool force)
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:36
double y
Definition: qgspoint.h:42
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:225
bool readXml(const QDomElement &itemElem, const QDomDocument &doc) override
Sets overview state from a DOM document.
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
virtual bool readXml(const QDomElement &itemElem, const QDomDocument &doc) override
Sets map item state from a DOM document.
virtual QgsExpressionContext createExpressionContext() const
Creates an expression context relating to the objects&#39; current state.
void addItem(QgsComposerMapItem *item)
Adds a new map item to the stack and takes ownership of the item.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc)
void setFrameSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for drawing the overview extent.
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbol.h:231
void addOverview(QgsComposerMapOverview *overview)
Adds a new map overview to the stack and takes ownership of the overview.
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1052
QgsComposerMapItem(const QString &name, QgsComposerMap *map)
Constructor for QgsComposerMapItem.
void cache()
Create cache image.
void moveOverviewDown(const QString &overviewId)
Moves an overview down the stack, causing it to be rendered below other overviews.
QList< QgsComposerMapItem *> mItems
static BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:66
virtual bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores map item state in DOM element.
const QgsComposerMapOverview * constOverview(const QString &overviewId) const
Returns a const reference to an overview within the stack.
static QPainter::CompositionMode getCompositionMode(BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:6
QMap< QString, QString > QgsStringMap
Definition: qgis.h:341
An item which is drawn inside a QgsComposerMap, e.g., a grid or map overview.
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:378
bool readXml(const QDomElement &elem, const QDomDocument &doc) override
Sets the overview stack&#39;s state from a DOM document.
An individual overview which is drawn above the map content in a QgsComposerMap, and shows the extent...
bool mEnabled
True if item is to be displayed on map.
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1710
QgsComposerMapOverview & operator[](int idx)
Returns a reference to an overview within the stack.
void removeItem(const QString &itemId)
Removes an item from the stack and deletes the corresponding QgsComposerMapItem.
const QgsComposerMapItem * constItem(const QString &itemId) const
Returns a const reference to an item within the stack.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:215
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.
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.
QgsComposerMap * mComposerMap
Associated composer map.
A class to represent a point.
Definition: qgspoint.h:37
bool usesAdvancedEffects() const override
Returns true if the item is drawn using advanced effects, such as blend modes.
Object representing map window.
void moveItemDown(const QString &itemId)
Moves an item up the stack, causing it to be rendered above other items.
void draw(QPainter *painter) override
Draws an overview.
QgsComposerMapOverview * overview(const QString &overviewId) const
Returns a reference to an overview within the stack.
QgsComposition * mComposition
Contains information about the context of a rendering operation.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties, const QgsExpressionContext *context=nullptr) override
void overviewExtentChanged()
Handles recentering of the map and redrawing of the map&#39;s overview.
const QgsComposition * composition() const
Returns the composition the item is attached to.
void moveOverviewUp(const QString &overviewId)
Moves an overview up the stack, causing it to be rendered above other overviews.
QList< QgsComposerMapOverview *> asList() const
Returns a list of QgsComposerMapOverviews contained by the stack.
bool inverted() const
Returns whether the overview frame is inverted, ie, whether the shaded area is drawn outside the exte...
A collection of map items which are drawn above the map content in a QgsComposerMap.
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.
bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores overview state in DOM element.
void extentChanged()
void removeItems()
Clears the item stack and deletes all QgsComposerMapItems contained by the stack. ...
QgsComposerMapOverviewStack(QgsComposerMap *map)
Constructor for QgsComposerMapOverviewStack.
static QgsRenderContext createRenderContextForComposition(QgsComposition *composition, QPainter *painter)
Creates a render context suitable for the specified composition and painter destination.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:399
const QgsRectangle * currentMapExtent() const
Returns a pointer to the current map extent, which is either the original user specified extent or th...
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the blending mode used for drawing the overview.
QPainter::CompositionMode blendMode() const
Retrieves 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:220
QgsComposerMap * mComposerMap
double x
Definition: qgspoint.h:41