QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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( 0 )
30  , mBlendMode( QPainter::CompositionMode_SourceOver )
31  , mInverted( false )
32  , mCentered( false )
33 {
34  createDefaultFrameSymbol();
35 }
36 
37 QgsComposerMapOverview::QgsComposerMapOverview()
38  : QgsComposerMapItem( QString(), 0 )
39  , mFrameMapId( -1 )
40  , mFrameSymbol( 0 )
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 
63 void QgsComposerMapOverview::draw( QPainter *painter )
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
84  QPolygonF thisExtent = mComposerMap->visibleExtentPolygon();
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 
101  painter->save();
102  painter->setCompositionMode( mBlendMode );
103  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
104  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
105  painter->setRenderHint( QPainter::Antialiasing );
106 
107  mFrameSymbol->startRender( context );
108 
109  //construct a polygon corresponding to the intersecting map extent
110  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
111  QTransform mapTransform;
112  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
113 
114  //workaround QT Bug #21329
115  thisRectPoly.pop_back();
116  thisExtent.pop_back();
117 
118  //create transform from map coordinates to painter coordinates
119  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
120  QPolygonF intersectPolygon;
121  intersectPolygon = mapTransform.map( intersectExtent );
122 
123  QList<QPolygonF> rings; //empty list
124  if ( !mInverted )
125  {
126  //Render the intersecting map extent
127  mFrameSymbol->renderPolygon( intersectPolygon, &rings, 0, context );;
128  }
129  else
130  {
131  //We are inverting the overview frame (ie, shading outside the intersecting extent)
132  //Construct a polygon corresponding to the overview map extent
133  QPolygonF outerPolygon;
134  outerPolygon << QPointF( 0, 0 )
135  << QPointF( mComposerMap->rect().width() * dotsPerMM, 0 )
136  << QPointF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM )
137  << QPointF( 0, mComposerMap->rect().height() * dotsPerMM )
138  << QPointF( 0, 0 );
139 
140  //Intersecting extent is an inner ring for the shaded area
141  rings.append( intersectPolygon );
142  mFrameSymbol->renderPolygon( outerPolygon, &rings, 0, context );
143  }
144 
145  mFrameSymbol->stopRender( context );
146  painter->restore();
147 }
148 
149 bool QgsComposerMapOverview::writeXML( QDomElement &elem, QDomDocument &doc ) const
150 {
151  if ( elem.isNull() )
152  {
153  return false;
154  }
155 
156  //overview map frame
157  QDomElement overviewFrameElem = doc.createElement( "ComposerMapOverview" );
158 
159  overviewFrameElem.setAttribute( "frameMap", mFrameMapId );
160  overviewFrameElem.setAttribute( "blendMode", QgsMapRenderer::getBlendModeEnum( mBlendMode ) );
161  overviewFrameElem.setAttribute( "inverted", mInverted );
162  overviewFrameElem.setAttribute( "centered", mCentered );
163 
164  QDomElement frameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mFrameSymbol, doc );
165  overviewFrameElem.appendChild( frameStyleElem );
166 
167  bool ok = QgsComposerMapItem::writeXML( overviewFrameElem, doc );
168  elem.appendChild( overviewFrameElem );
169  return ok;
170 }
171 
172 bool QgsComposerMapOverview::readXML( const QDomElement &itemElem, const QDomDocument &doc )
173 {
174  Q_UNUSED( doc );
175  if ( itemElem.isNull() )
176  {
177  return false;
178  }
179 
180  bool ok = QgsComposerMapItem::readXML( itemElem, doc );
181 
182  setFrameMap( itemElem.attribute( "frameMap", "-1" ).toInt() );
183  mBlendMode = QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) itemElem.attribute( "blendMode", "0" ).toUInt() );
184  mInverted = ( itemElem.attribute( "inverted", "0" ) != "0" );
185  mCentered = ( itemElem.attribute( "centered", "0" ) != "0" );
186 
187  QDomElement frameStyleElem = itemElem.firstChildElement( "symbol" );
188  if ( !frameStyleElem.isNull() )
189  {
190  delete mFrameSymbol;
191  mFrameSymbol = QgsSymbolLayerV2Utils::loadSymbol<QgsFillSymbolV2>( frameStyleElem );
192  }
193  return ok;
194 }
195 
197 {
198  return mBlendMode != QPainter::CompositionMode_SourceOver;
199 }
200 
201 void QgsComposerMapOverview::setFrameMap( const int mapId )
202 {
203  if ( mFrameMapId == mapId )
204  {
205  //no change
206  return;
207  }
208 
209  //disconnect old map
210  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
211  {
212  const QgsComposerMap* map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
213  if ( map )
214  {
215  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
216  }
217  }
218  mFrameMapId = mapId;
219  //connect to new map signals
220  connectSignals();
221 }
222 
224 {
225  if ( !mComposerMap )
226  {
227  return;
228  }
229 
230  if ( mFrameMapId != -1 && mComposerMap->composition() )
231  {
232  const QgsComposerMap* map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
233  if ( map )
234  {
235  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
236  }
237  }
238 }
239 
241 {
242  delete mFrameSymbol;
243  mFrameSymbol = symbol;
244 }
245 
246 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
247 {
248  mBlendMode = blendMode;
249 }
250 
251 void QgsComposerMapOverview::setInverted( const bool inverted )
252 {
253  mInverted = inverted;
254 }
255 
256 void QgsComposerMapOverview::setCentered( const bool centered )
257 {
258  mCentered = centered;
260 }
261 
263 {
264  if ( !mComposerMap )
265  {
266  return;
267  }
268 
269  //if using overview centering, update the map's extent
270  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
271  {
273 
274  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
275  if ( !overviewFrameMap )
276  {
277  //redraw map so that overview gets updated
278  mComposerMap->update();
279  return;
280  }
281  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
282 
283  QgsPoint center = otherExtent.center();
284  QgsRectangle movedExtent( center.x() - extent.width() / 2,
285  center.y() - extent.height() / 2,
286  center.x() - extent.width() / 2 + extent.width(),
287  center.y() - extent.height() / 2 + extent.height() );
288  *mComposerMap->currentMapExtent() = movedExtent;
289 
290  //trigger a recalculation of data defined extents, scale and rotation, since that
291  //may override the map centering
293 
294  //must invalidate cache so that map gets redrawn
295  mComposerMap->cache();
296  }
297 
298  //repaint map so that overview gets updated
299  mComposerMap->update();
300 }
301 
302 
303 //
304 // QgsComposerMapOverviewStack
305 //
306 
308  : QgsComposerMapItemStack( map )
309 {
310 
311 }
312 
314 {
315 
316 }
317 
319 {
321 }
322 
323 void QgsComposerMapOverviewStack::removeOverview( const QString &overviewId )
324 {
326 }
327 
328 void QgsComposerMapOverviewStack::moveOverviewUp( const QString &overviewId )
329 {
331 }
332 
333 void QgsComposerMapOverviewStack::moveOverviewDown( const QString &overviewId )
334 {
336 }
337 
339 {
341  return dynamic_cast<const QgsComposerMapOverview*>( item );
342 }
343 
345 {
347  return dynamic_cast<QgsComposerMapOverview*>( item );
348 }
349 
351 {
353  return dynamic_cast<QgsComposerMapOverview*>( item );
354 }
355 
357 {
360  return *overview;
361 }
362 
363 QList<QgsComposerMapOverview *> QgsComposerMapOverviewStack::asList() const
364 {
365  QList< QgsComposerMapOverview* > list;
366  QList< QgsComposerMapItem* >::const_iterator it = mItems.begin();
367  for ( ; it != mItems.end(); ++it )
368  {
369  QgsComposerMapOverview* overview = dynamic_cast<QgsComposerMapOverview*>( *it );
370  if ( overview )
371  {
372  list.append( overview );
373  }
374  }
375  return list;
376 }
377 
378 bool QgsComposerMapOverviewStack::readXML( const QDomElement &elem, const QDomDocument &doc )
379 {
380  removeItems();
381 
382  //read overview stack
383  QDomNodeList mapOverviewNodeList = elem.elementsByTagName( "ComposerMapOverview" );
384  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
385  {
386  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
387  QgsComposerMapOverview* mapOverview = new QgsComposerMapOverview( mapOverviewElem.attribute( "name" ), mComposerMap );
388  mapOverview->readXML( mapOverviewElem, doc );
389  mItems.append( mapOverview );
390  }
391 
392  return true;
393 }
void connectSignals()
Reconnects signals for overview map, so that overview correctly follows changes to source map's exten...
void setForceVectorOutput(bool force)
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 addItem(QgsComposerMapItem *item)
Adds a new map item to the stack and takes ownership of the item.
void setOutputDpi(int dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
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.
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
void cache()
Create cache image.
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.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets overview state from a DOM document.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:438
double x() const
Definition: qgspoint.h:126
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.
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
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.
QPainter::CompositionMode blendMode() const
Retrieves the blending mode used for drawing the overview.
bool mEnabled
True if item is to be displayed on map.
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
QgsComposerMapOverview & operator[](int idx)
Returns a reference to an overview within the stack.
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.
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 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.
QgsComposerMap * mComposerMap
Associated composer map.
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:63
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.
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer...
void moveItemDown(const QString &itemId)
Moves an item up the stack, causing it to be rendered above other items.
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.
static QPainter::CompositionMode getCompositionMode(const QgsMapRenderer::BlendMode &blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
QList< QgsComposerMapItem * > mItems
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores overview state in DOM element.
Contains information about the context of a rendering operation.
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's overview.
void stopRender(QgsRenderContext &context)
void moveOverviewUp(const QString &overviewId)
Moves an overview up the stack, causing it to be rendered above other overviews.
void setOutputSize(const QSize &size)
Set the size of the resulting map image.
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.
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
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
Definition: qgspoint.h:134
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties) override
virtual bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets map item state from a DOM document.
static QgsMapRenderer::BlendMode getBlendModeEnum(const QPainter::CompositionMode &blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
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:198
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores map item state in DOM element.
QgsComposerMapOverviewStack(QgsComposerMap *map)
Constructor for QgsComposerMapOverviewStack.
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:208
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:159
bool readXML(const QDomElement &elem, const QDomDocument &doc) override
Sets the overview stack's state from a DOM document.
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the blending mode used for drawing the overview.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:203
QgsComposerMap * mComposerMap
bool inverted() const
Returns whether the overview frame is inverted, ie, whether the shaded area is drawn outside the exte...