QGIS API Documentation  2.99.0-Master (19b062c)
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 "qgspathresolver.h"
26 #include "qgsreadwritecontext.h"
27 #include "qgscomposerutils.h"
28 #include "qgsexception.h"
29 
30 #include <QPainter>
31 
33  : QgsComposerMapItem( name, map )
34 {
35  createDefaultFrameSymbol();
36 }
37 
39  : QgsComposerMapItem( QString(), nullptr )
40 {
41 }
42 
43 void QgsComposerMapOverview::createDefaultFrameSymbol()
44 {
45  delete mFrameSymbol;
46  QgsStringMap properties;
47  properties.insert( QStringLiteral( "color" ), QStringLiteral( "255,0,0,255" ) );
48  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
49  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
50  mFrameSymbol = QgsFillSymbol::createSimple( properties );
51  mFrameSymbol->setOpacity( 0.3 );
52 }
53 
55 {
56  delete mFrameSymbol;
57 }
58 
59 void QgsComposerMapOverview::draw( QPainter *painter )
60 {
61  if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
62  {
63  return;
64  }
65  if ( !painter )
66  {
67  return;
68  }
69 
70  const QgsComposerMap *overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
71  if ( !overviewFrameMap )
72  {
73  return;
74  }
75 
76  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
77  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
78  if ( overviewFrameMap->crs() !=
79  mComposerMap->crs() )
80  {
81  QgsGeometry g = QgsGeometry::fromQPolygonF( otherExtent );
82 
83  // reproject extent
84  QgsCoordinateTransform ct( overviewFrameMap->crs(),
85  mComposerMap->crs() );
86  g = g.densifyByCount( 20 );
87  try
88  {
89  g.transform( ct );
90  }
91  catch ( QgsCsException & )
92  {
93  }
94 
95  otherExtent = g.asQPolygonF();
96  }
97 
98  //get current map's extent as a QPolygonF
99  QPolygonF thisExtent = mComposerMap->visibleExtentPolygon();
100  //intersect the two
101  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
102 
103  //setup painter scaling to dots so that raster symbology is drawn to scale
104  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
105 
106  //setup render context
108  context.setForceVectorOutput( true );
109  QgsExpressionContext expressionContext = createExpressionContext();
110  context.setExpressionContext( expressionContext );
111 
112  painter->save();
113  painter->setCompositionMode( mBlendMode );
114  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
115  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
116  painter->setRenderHint( QPainter::Antialiasing );
117 
118  mFrameSymbol->startRender( context );
119 
120  //construct a polygon corresponding to the intersecting map extent
121  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
122  QTransform mapTransform;
123  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
124 
125  //workaround QT Bug #21329
126  thisRectPoly.pop_back();
127  thisExtent.pop_back();
128 
129  //create transform from map coordinates to painter coordinates
130  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
131  QPolygonF intersectPolygon;
132  intersectPolygon = mapTransform.map( intersectExtent );
133 
134  QList<QPolygonF> rings; //empty list
135  if ( !mInverted )
136  {
137  //Render the intersecting map extent
138  mFrameSymbol->renderPolygon( intersectPolygon, &rings, nullptr, context );
139  }
140  else
141  {
142  //We are inverting the overview frame (ie, shading outside the intersecting extent)
143  //Construct a polygon corresponding to the overview map extent
144  QPolygonF outerPolygon;
145  outerPolygon << QPointF( 0, 0 )
146  << QPointF( mComposerMap->rect().width() * dotsPerMM, 0 )
147  << QPointF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM )
148  << QPointF( 0, mComposerMap->rect().height() * dotsPerMM )
149  << QPointF( 0, 0 );
150 
151  //Intersecting extent is an inner ring for the shaded area
152  rings.append( intersectPolygon );
153  mFrameSymbol->renderPolygon( outerPolygon, &rings, nullptr, context );
154  }
155 
156  mFrameSymbol->stopRender( context );
157  painter->restore();
158 }
159 
160 bool QgsComposerMapOverview::writeXml( QDomElement &elem, QDomDocument &doc ) const
161 {
162  if ( elem.isNull() )
163  {
164  return false;
165  }
166 
167  //overview map frame
168  QDomElement overviewFrameElem = doc.createElement( QStringLiteral( "ComposerMapOverview" ) );
169 
170  overviewFrameElem.setAttribute( QStringLiteral( "frameMap" ), mFrameMapId );
171  overviewFrameElem.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( mBlendMode ) );
172  overviewFrameElem.setAttribute( QStringLiteral( "inverted" ), mInverted );
173  overviewFrameElem.setAttribute( QStringLiteral( "centered" ), mCentered );
174 
175  QgsReadWriteContext context;
177 
178  QDomElement frameStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mFrameSymbol, doc, context );
179  overviewFrameElem.appendChild( frameStyleElem );
180 
181  bool ok = QgsComposerMapItem::writeXml( overviewFrameElem, doc );
182  elem.appendChild( overviewFrameElem );
183  return ok;
184 }
185 
186 bool QgsComposerMapOverview::readXml( const QDomElement &itemElem, const QDomDocument &doc )
187 {
188  Q_UNUSED( doc );
189  if ( itemElem.isNull() )
190  {
191  return false;
192  }
193 
194  bool ok = QgsComposerMapItem::readXml( itemElem, doc );
195 
196  setFrameMap( itemElem.attribute( QStringLiteral( "frameMap" ), QStringLiteral( "-1" ) ).toInt() );
197  mBlendMode = QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) );
198  mInverted = ( itemElem.attribute( QStringLiteral( "inverted" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
199  mCentered = ( itemElem.attribute( QStringLiteral( "centered" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
200 
201  QgsReadWriteContext context;
203 
204  QDomElement frameStyleElem = itemElem.firstChildElement( QStringLiteral( "symbol" ) );
205  if ( !frameStyleElem.isNull() )
206  {
207  delete mFrameSymbol;
208  mFrameSymbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( frameStyleElem, context );
209  }
210  return ok;
211 }
212 
214 {
215  return mBlendMode != QPainter::CompositionMode_SourceOver;
216 }
217 
218 void QgsComposerMapOverview::setFrameMap( const int mapId )
219 {
220  if ( mFrameMapId == mapId )
221  {
222  //no change
223  return;
224  }
225 
226  //disconnect old map
227  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
228  {
229  const QgsComposerMap *map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
230  if ( map )
231  {
233  }
234  }
235  mFrameMapId = mapId;
236  //connect to new map signals
237  connectSignals();
238 }
239 
241 {
242  if ( !mComposerMap )
243  {
244  return;
245  }
246 
247  if ( mFrameMapId != -1 && mComposerMap->composition() )
248  {
249  const QgsComposerMap *map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
250  if ( map )
251  {
253  }
254  }
255 }
256 
258 {
259  delete mFrameSymbol;
260  mFrameSymbol = symbol;
261 }
262 
263 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
264 {
265  mBlendMode = blendMode;
266 }
267 
269 {
270  mInverted = inverted;
271 }
272 
274 {
275  mCentered = centered;
277 }
278 
280 {
281  if ( !mComposerMap )
282  {
283  return;
284  }
285 
286  //if using overview centering, update the map's extent
287  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
288  {
290 
291  const QgsComposerMap *overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
292  if ( !overviewFrameMap )
293  {
294  //redraw map so that overview gets updated
295  mComposerMap->update();
296  return;
297  }
298  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
299 
300  QgsPointXY center = otherExtent.center();
301  QgsRectangle movedExtent( center.x() - extent.width() / 2,
302  center.y() - extent.height() / 2,
303  center.x() - extent.width() / 2 + extent.width(),
304  center.y() - extent.height() / 2 + extent.height() );
305  *mComposerMap->currentMapExtent() = movedExtent;
306 
307  //trigger a recalculation of data defined extents, scale and rotation, since that
308  //may override the map centering
310 
311  //must invalidate cache so that map gets redrawn
313  }
314 
315  //repaint map so that overview gets updated
317 }
318 
319 
320 //
321 // QgsComposerMapOverviewStack
322 //
323 
325  : QgsComposerMapItemStack( map )
326 {
327 
328 }
329 
331 {
333 }
334 
335 void QgsComposerMapOverviewStack::removeOverview( const QString &overviewId )
336 {
338 }
339 
340 void QgsComposerMapOverviewStack::moveOverviewUp( const QString &overviewId )
341 {
343 }
344 
345 void QgsComposerMapOverviewStack::moveOverviewDown( const QString &overviewId )
346 {
348 }
349 
351 {
353  return dynamic_cast<const QgsComposerMapOverview *>( item );
354 }
355 
357 {
359  return dynamic_cast<QgsComposerMapOverview *>( item );
360 }
361 
363 {
365  return dynamic_cast<QgsComposerMapOverview *>( item );
366 }
367 
369 {
370  QgsComposerMapItem *item = mItems.at( idx );
372  return *overview;
373 }
374 
375 QList<QgsComposerMapOverview *> QgsComposerMapOverviewStack::asList() const
376 {
377  QList< QgsComposerMapOverview * > list;
378  QList< QgsComposerMapItem * >::const_iterator it = mItems.begin();
379  for ( ; it != mItems.end(); ++it )
380  {
381  QgsComposerMapOverview *overview = dynamic_cast<QgsComposerMapOverview *>( *it );
382  if ( overview )
383  {
384  list.append( overview );
385  }
386  }
387  return list;
388 }
389 
390 bool QgsComposerMapOverviewStack::readXml( const QDomElement &elem, const QDomDocument &doc )
391 {
392  removeItems();
393 
394  //read overview stack
395  QDomNodeList mapOverviewNodeList = elem.elementsByTagName( QStringLiteral( "ComposerMapOverview" ) );
396  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
397  {
398  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
399  QgsComposerMapOverview *mapOverview = new QgsComposerMapOverview( mapOverviewElem.attribute( QStringLiteral( "name" ) ), mComposerMap );
400  mapOverview->readXml( mapOverviewElem, doc );
401  mItems.append( mapOverview );
402  }
403 
404  return true;
405 }
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)
The class is used as a container of context for various read/write operations on other objects...
A rectangle specified with double values.
Definition: qgsrectangle.h:39
bool readXml(const QDomElement &itemElem, const QDomDocument &doc) override
Sets overview state from a DOM document.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
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.
void setFrameSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used for drawing the overview extent.
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...
double y
Definition: qgspointxy.h:48
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1084
A class to represent a 2D point.
Definition: qgspointxy.h:43
QgsComposerMapItem(const QString &name, QgsComposerMap *map)
Constructor for QgsComposerMapItem.
void moveOverviewDown(const QString &overviewId)
Moves an overview down the stack, causing it to be rendered below other overviews.
QList< QgsComposerMapItem *> mItems
static QgsPainting::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.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:6
const QgsComposerMapOverview * constOverview(const QString &overviewId) const
Returns a const reference to an overview within the stack.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:443
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:383
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.
QgsPathResolver pathResolver() const
Return path resolver object with considering whether the project uses absolute or relative paths and ...
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1742
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:264
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
Returns the width of the rectangle.
Definition: qgsrectangle.h:138
QgsGeometry densifyByCount(int extraNodesPerSegment) const
Returns a copy of the geometry which has been densified by adding the specified number of extra nodes...
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.
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.
double x
Definition: qgspointxy.h:47
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.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
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.
OperationResult transform(const QgsCoordinateTransform &ct)
Transforms this geometry as described by CoordinateTransform ct.
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.
QgsProject * project() const
The project associated with the composition.
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.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Class for doing transforms between two map coordinate systems.
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.
virtual void updateItem()
Updates (redraws) the item, with the possibility to do custom update for subclasses.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores overview state in DOM element.
void extentChanged()
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:166
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:405
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.
void invalidateCache()
Forces a deferred update of the cached map image on next paint.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:145
QgsComposerMap * mComposerMap