QGIS API Documentation  2.99.0-Master (7d4f81d)
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  , mFrameMapId( -1 )
35  , mFrameSymbol( nullptr )
36  , mBlendMode( QPainter::CompositionMode_SourceOver )
37  , mInverted( false )
38  , mCentered( false )
39 {
40  createDefaultFrameSymbol();
41 }
42 
44  : QgsComposerMapItem( QString(), nullptr )
45  , mFrameMapId( -1 )
46  , mFrameSymbol( nullptr )
47  , mBlendMode( QPainter::CompositionMode_SourceOver )
48  , mInverted( false )
49  , mCentered( false )
50 {
51 }
52 
53 void QgsComposerMapOverview::createDefaultFrameSymbol()
54 {
55  delete mFrameSymbol;
56  QgsStringMap properties;
57  properties.insert( QStringLiteral( "color" ), QStringLiteral( "255,0,0,255" ) );
58  properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) );
59  properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "no" ) );
60  mFrameSymbol = QgsFillSymbol::createSimple( properties );
61  mFrameSymbol->setOpacity( 0.3 );
62 }
63 
65 {
66  delete mFrameSymbol;
67 }
68 
69 void QgsComposerMapOverview::draw( QPainter *painter )
70 {
71  if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
72  {
73  return;
74  }
75  if ( !painter )
76  {
77  return;
78  }
79 
80  const QgsComposerMap *overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
81  if ( !overviewFrameMap )
82  {
83  return;
84  }
85 
86  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
87  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
88  if ( overviewFrameMap->crs() !=
89  mComposerMap->crs() )
90  {
91  QgsGeometry g = QgsGeometry::fromQPolygonF( otherExtent );
92 
93  // reproject extent
94  QgsCoordinateTransform ct( overviewFrameMap->crs(),
95  mComposerMap->crs() );
96  g = g.densifyByCount( 20 );
97  try
98  {
99  g.transform( ct );
100  }
101  catch ( QgsCsException & )
102  {
103  }
104 
105  otherExtent = g.asQPolygonF();
106  }
107 
108  //get current map's extent as a QPolygonF
109  QPolygonF thisExtent = mComposerMap->visibleExtentPolygon();
110  //intersect the two
111  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
112 
113  //setup painter scaling to dots so that raster symbology is drawn to scale
114  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
115 
116  //setup render context
118  context.setForceVectorOutput( true );
119  QgsExpressionContext expressionContext = createExpressionContext();
120  context.setExpressionContext( expressionContext );
121 
122  painter->save();
123  painter->setCompositionMode( mBlendMode );
124  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
125  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
126  painter->setRenderHint( QPainter::Antialiasing );
127 
128  mFrameSymbol->startRender( context );
129 
130  //construct a polygon corresponding to the intersecting map extent
131  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
132  QTransform mapTransform;
133  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
134 
135  //workaround QT Bug #21329
136  thisRectPoly.pop_back();
137  thisExtent.pop_back();
138 
139  //create transform from map coordinates to painter coordinates
140  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
141  QPolygonF intersectPolygon;
142  intersectPolygon = mapTransform.map( intersectExtent );
143 
144  QList<QPolygonF> rings; //empty list
145  if ( !mInverted )
146  {
147  //Render the intersecting map extent
148  mFrameSymbol->renderPolygon( intersectPolygon, &rings, nullptr, context );
149  }
150  else
151  {
152  //We are inverting the overview frame (ie, shading outside the intersecting extent)
153  //Construct a polygon corresponding to the overview map extent
154  QPolygonF outerPolygon;
155  outerPolygon << QPointF( 0, 0 )
156  << QPointF( mComposerMap->rect().width() * dotsPerMM, 0 )
157  << QPointF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM )
158  << QPointF( 0, mComposerMap->rect().height() * dotsPerMM )
159  << QPointF( 0, 0 );
160 
161  //Intersecting extent is an inner ring for the shaded area
162  rings.append( intersectPolygon );
163  mFrameSymbol->renderPolygon( outerPolygon, &rings, nullptr, context );
164  }
165 
166  mFrameSymbol->stopRender( context );
167  painter->restore();
168 }
169 
170 bool QgsComposerMapOverview::writeXml( QDomElement &elem, QDomDocument &doc ) const
171 {
172  if ( elem.isNull() )
173  {
174  return false;
175  }
176 
177  //overview map frame
178  QDomElement overviewFrameElem = doc.createElement( QStringLiteral( "ComposerMapOverview" ) );
179 
180  overviewFrameElem.setAttribute( QStringLiteral( "frameMap" ), mFrameMapId );
181  overviewFrameElem.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( mBlendMode ) );
182  overviewFrameElem.setAttribute( QStringLiteral( "inverted" ), mInverted );
183  overviewFrameElem.setAttribute( QStringLiteral( "centered" ), mCentered );
184 
185  QgsReadWriteContext context;
187 
188  QDomElement frameStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mFrameSymbol, doc, context );
189  overviewFrameElem.appendChild( frameStyleElem );
190 
191  bool ok = QgsComposerMapItem::writeXml( overviewFrameElem, doc );
192  elem.appendChild( overviewFrameElem );
193  return ok;
194 }
195 
196 bool QgsComposerMapOverview::readXml( const QDomElement &itemElem, const QDomDocument &doc )
197 {
198  Q_UNUSED( doc );
199  if ( itemElem.isNull() )
200  {
201  return false;
202  }
203 
204  bool ok = QgsComposerMapItem::readXml( itemElem, doc );
205 
206  setFrameMap( itemElem.attribute( QStringLiteral( "frameMap" ), QStringLiteral( "-1" ) ).toInt() );
207  mBlendMode = QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( itemElem.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) );
208  mInverted = ( itemElem.attribute( QStringLiteral( "inverted" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
209  mCentered = ( itemElem.attribute( QStringLiteral( "centered" ), QStringLiteral( "0" ) ) != QLatin1String( "0" ) );
210 
211  QgsReadWriteContext context;
213 
214  QDomElement frameStyleElem = itemElem.firstChildElement( QStringLiteral( "symbol" ) );
215  if ( !frameStyleElem.isNull() )
216  {
217  delete mFrameSymbol;
218  mFrameSymbol = QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( frameStyleElem, context );
219  }
220  return ok;
221 }
222 
224 {
225  return mBlendMode != QPainter::CompositionMode_SourceOver;
226 }
227 
228 void QgsComposerMapOverview::setFrameMap( const int mapId )
229 {
230  if ( mFrameMapId == mapId )
231  {
232  //no change
233  return;
234  }
235 
236  //disconnect old map
237  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
238  {
239  const QgsComposerMap *map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
240  if ( map )
241  {
243  }
244  }
245  mFrameMapId = mapId;
246  //connect to new map signals
247  connectSignals();
248 }
249 
251 {
252  if ( !mComposerMap )
253  {
254  return;
255  }
256 
257  if ( mFrameMapId != -1 && mComposerMap->composition() )
258  {
259  const QgsComposerMap *map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
260  if ( map )
261  {
263  }
264  }
265 }
266 
268 {
269  delete mFrameSymbol;
270  mFrameSymbol = symbol;
271 }
272 
273 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
274 {
275  mBlendMode = blendMode;
276 }
277 
279 {
280  mInverted = inverted;
281 }
282 
284 {
285  mCentered = centered;
287 }
288 
290 {
291  if ( !mComposerMap )
292  {
293  return;
294  }
295 
296  //if using overview centering, update the map's extent
297  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
298  {
300 
301  const QgsComposerMap *overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
302  if ( !overviewFrameMap )
303  {
304  //redraw map so that overview gets updated
305  mComposerMap->update();
306  return;
307  }
308  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
309 
310  QgsPointXY center = otherExtent.center();
311  QgsRectangle movedExtent( center.x() - extent.width() / 2,
312  center.y() - extent.height() / 2,
313  center.x() - extent.width() / 2 + extent.width(),
314  center.y() - extent.height() / 2 + extent.height() );
315  *mComposerMap->currentMapExtent() = movedExtent;
316 
317  //trigger a recalculation of data defined extents, scale and rotation, since that
318  //may override the map centering
320 
321  //must invalidate cache so that map gets redrawn
323  }
324 
325  //repaint map so that overview gets updated
327 }
328 
329 
330 //
331 // QgsComposerMapOverviewStack
332 //
333 
335  : QgsComposerMapItemStack( map )
336 {
337 
338 }
339 
341 {
343 }
344 
345 void QgsComposerMapOverviewStack::removeOverview( const QString &overviewId )
346 {
348 }
349 
350 void QgsComposerMapOverviewStack::moveOverviewUp( const QString &overviewId )
351 {
353 }
354 
355 void QgsComposerMapOverviewStack::moveOverviewDown( const QString &overviewId )
356 {
358 }
359 
361 {
363  return dynamic_cast<const QgsComposerMapOverview *>( item );
364 }
365 
367 {
369  return dynamic_cast<QgsComposerMapOverview *>( item );
370 }
371 
373 {
375  return dynamic_cast<QgsComposerMapOverview *>( item );
376 }
377 
379 {
380  QgsComposerMapItem *item = mItems.at( idx );
382  return *overview;
383 }
384 
385 QList<QgsComposerMapOverview *> QgsComposerMapOverviewStack::asList() const
386 {
387  QList< QgsComposerMapOverview * > list;
388  QList< QgsComposerMapItem * >::const_iterator it = mItems.begin();
389  for ( ; it != mItems.end(); ++it )
390  {
391  QgsComposerMapOverview *overview = dynamic_cast<QgsComposerMapOverview *>( *it );
392  if ( overview )
393  {
394  list.append( overview );
395  }
396  }
397  return list;
398 }
399 
400 bool QgsComposerMapOverviewStack::readXml( const QDomElement &elem, const QDomDocument &doc )
401 {
402  removeItems();
403 
404  //read overview stack
405  QDomNodeList mapOverviewNodeList = elem.elementsByTagName( QStringLiteral( "ComposerMapOverview" ) );
406  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
407  {
408  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
409  QgsComposerMapOverview *mapOverview = new QgsComposerMapOverview( mapOverviewElem.attribute( QStringLiteral( "name" ) ), mComposerMap );
410  mapOverview->readXml( mapOverviewElem, doc );
411  mItems.append( mapOverview );
412  }
413 
414  return true;
415 }
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:38
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:47
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
Definition: qgssymbol.cpp:1081
A class to represent a 2D point.
Definition: qgspointxy.h:42
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:96
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:347
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:384
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:1739
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:253
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:118
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:46
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:64
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:146
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:406
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:125
QgsComposerMap * mComposerMap