QGIS API Documentation  2.7.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 {
40 }
41 
42 void QgsComposerMapOverview::createDefaultFrameSymbol()
43 {
44  delete mFrameSymbol;
45  QgsStringMap properties;
46  properties.insert( "color", "255,0,0,255" );
47  properties.insert( "style", "solid" );
48  properties.insert( "style_border", "no" );
49  mFrameSymbol = QgsFillSymbolV2::createSimple( properties );
50  mFrameSymbol->setAlpha( 0.3 );
51 }
52 
54 {
55  delete mFrameSymbol;
56 }
57 
58 void QgsComposerMapOverview::draw( QPainter *painter )
59 {
60  if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
61  {
62  return;
63  }
64  if ( !painter )
65  {
66  return;
67  }
68 
69  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
70  if ( !overviewFrameMap )
71  {
72  return;
73  }
74 
75  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
76  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
77 
78  //get current map's extent as a QPolygonF
79  QPolygonF thisExtent = mComposerMap->visibleExtentPolygon();
80  //intersect the two
81  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
82 
83  //setup painter scaling to dots so that raster symbology is drawn to scale
84  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
85 
86  //setup render context
88  //context units should be in dots
89  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
91  ms.setOutputDpi( painter->device()->logicalDpiX() );
93  context.setForceVectorOutput( true );
94  context.setPainter( painter );
95 
96  painter->save();
97  painter->setCompositionMode( mBlendMode );
98  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
99  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
100  painter->setRenderHint( QPainter::Antialiasing );
101 
102  mFrameSymbol->startRender( context );
103 
104  //construct a polygon corresponding to the intersecting map extent
105  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
106  QTransform mapTransform;
107  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
108 
109  //workaround QT Bug #21329
110  thisRectPoly.pop_back();
111  thisExtent.pop_back();
112 
113  //create transform from map coordinates to painter coordinates
114  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
115  QPolygonF intersectPolygon;
116  intersectPolygon = mapTransform.map( intersectExtent );
117 
118  QList<QPolygonF> rings; //empty list
119  if ( !mInverted )
120  {
121  //Render the intersecting map extent
122  mFrameSymbol->renderPolygon( intersectPolygon, &rings, 0, context );;
123  }
124  else
125  {
126  //We are inverting the overview frame (ie, shading outside the intersecting extent)
127  //Construct a polygon corresponding to the overview map extent
128  QPolygonF outerPolygon;
129  outerPolygon << QPointF( 0, 0 )
130  << QPointF( mComposerMap->rect().width() * dotsPerMM, 0 )
131  << QPointF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM )
132  << QPointF( 0, mComposerMap->rect().height() * dotsPerMM )
133  << QPointF( 0, 0 );
134 
135  //Intersecting extent is an inner ring for the shaded area
136  rings.append( intersectPolygon );
137  mFrameSymbol->renderPolygon( outerPolygon, &rings, 0, context );
138  }
139 
140  mFrameSymbol->stopRender( context );
141  painter->restore();
142 }
143 
144 bool QgsComposerMapOverview::writeXML( QDomElement &elem, QDomDocument &doc ) const
145 {
146  if ( elem.isNull() )
147  {
148  return false;
149  }
150 
151  //overview map frame
152  QDomElement overviewFrameElem = doc.createElement( "ComposerMapOverview" );
153 
154  overviewFrameElem.setAttribute( "frameMap", mFrameMapId );
155  overviewFrameElem.setAttribute( "blendMode", QgsMapRenderer::getBlendModeEnum( mBlendMode ) );
156  overviewFrameElem.setAttribute( "inverted", mInverted );
157  overviewFrameElem.setAttribute( "centered", mCentered );
158 
159  QDomElement frameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mFrameSymbol, doc );
160  overviewFrameElem.appendChild( frameStyleElem );
161 
162  bool ok = QgsComposerMapItem::writeXML( overviewFrameElem, doc );
163  elem.appendChild( overviewFrameElem );
164  return ok;
165 }
166 
167 bool QgsComposerMapOverview::readXML( const QDomElement &itemElem, const QDomDocument &doc )
168 {
169  Q_UNUSED( doc );
170  if ( itemElem.isNull() )
171  {
172  return false;
173  }
174 
175  bool ok = QgsComposerMapItem::readXML( itemElem, doc );
176 
177  setFrameMap( itemElem.attribute( "frameMap", "-1" ).toInt() );
178  mBlendMode = QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) itemElem.attribute( "blendMode", "0" ).toUInt() );
179  mInverted = ( itemElem.attribute( "inverted", "0" ) != "0" );
180  mCentered = ( itemElem.attribute( "centered", "0" ) != "0" );
181 
182  QDomElement frameStyleElem = itemElem.firstChildElement( "symbol" );
183  if ( !frameStyleElem.isNull() )
184  {
185  delete mFrameSymbol;
186  mFrameSymbol = dynamic_cast<QgsFillSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( frameStyleElem ) );
187  }
188  return ok;
189 }
190 
192 {
193  return mBlendMode != QPainter::CompositionMode_SourceOver;
194 }
195 
196 void QgsComposerMapOverview::setFrameMap( const int mapId )
197 {
198  if ( mFrameMapId == mapId )
199  {
200  //no change
201  return;
202  }
203 
204  //disconnect old map
205  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
206  {
207  const QgsComposerMap* map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
208  if ( map )
209  {
210  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
211  }
212  }
213  mFrameMapId = mapId;
214  //connect to new map signals
215  connectSignals();
216 }
217 
219 {
220  if ( !mComposerMap )
221  {
222  return;
223  }
224 
225  if ( mFrameMapId != -1 && mComposerMap->composition() )
226  {
227  const QgsComposerMap* map = mComposerMap->composition()->getComposerMapById( mFrameMapId );
228  if ( map )
229  {
230  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
231  }
232  }
233 }
234 
236 {
237  delete mFrameSymbol;
238  mFrameSymbol = symbol;
239 }
240 
241 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
242 {
243  mBlendMode = blendMode;
244 }
245 
246 void QgsComposerMapOverview::setInverted( const bool inverted )
247 {
248  mInverted = inverted;
249 }
250 
251 void QgsComposerMapOverview::setCentered( const bool centered )
252 {
253  mCentered = centered;
255 }
256 
258 {
259  if ( !mComposerMap )
260  {
261  return;
262  }
263 
264  //if using overview centering, update the map's extent
265  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
266  {
268 
269  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
270  if ( !overviewFrameMap )
271  {
272  //redraw map so that overview gets updated
273  mComposerMap->update();
274  return;
275  }
276  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
277 
278  QgsPoint center = otherExtent.center();
279  QgsRectangle movedExtent( center.x() - extent.width() / 2,
280  center.y() - extent.height() / 2,
281  center.x() - extent.width() / 2 + extent.width(),
282  center.y() - extent.height() / 2 + extent.height() );
283  *mComposerMap->currentMapExtent() = movedExtent;
284 
285  //trigger a recalculation of data defined extents, scale and rotation, since that
286  //may override the map centering
288 
289  //must invalidate cache so that map gets redrawn
290  mComposerMap->cache();
291  }
292 
293  //repaint map so that overview gets updated
294  mComposerMap->update();
295 }
296 
297 
298 //
299 // QgsComposerMapOverviewStack
300 //
301 
303  : QgsComposerMapItemStack( map )
304 {
305 
306 }
307 
309 {
310 
311 }
312 
314 {
316 }
317 
318 void QgsComposerMapOverviewStack::removeOverview( const QString &overviewId )
319 {
321 }
322 
323 void QgsComposerMapOverviewStack::moveOverviewUp( const QString &overviewId )
324 {
326 }
327 
328 void QgsComposerMapOverviewStack::moveOverviewDown( const QString &overviewId )
329 {
331 }
332 
334 {
336  return dynamic_cast<const QgsComposerMapOverview*>( item );
337 }
338 
340 {
342  return dynamic_cast<QgsComposerMapOverview*>( item );
343 }
344 
346 {
348  return dynamic_cast<QgsComposerMapOverview*>( item );
349 }
350 
352 {
355  return *overview;
356 }
357 
358 QList<QgsComposerMapOverview *> QgsComposerMapOverviewStack::asList() const
359 {
360  QList< QgsComposerMapOverview* > list;
361  QList< QgsComposerMapItem* >::const_iterator it = mItems.begin();
362  for ( ; it != mItems.end(); ++it )
363  {
364  QgsComposerMapOverview* overview = dynamic_cast<QgsComposerMapOverview*>( *it );
365  if ( overview )
366  {
367  list.append( overview );
368  }
369  }
370  return list;
371 }
372 
373 bool QgsComposerMapOverviewStack::readXML( const QDomElement &elem, const QDomDocument &doc )
374 {
375  removeItems();
376 
377  //read overview stack
378  QDomNodeList mapOverviewNodeList = elem.elementsByTagName( "ComposerMapOverview" );
379  for ( int i = 0; i < mapOverviewNodeList.size(); ++i )
380  {
381  QDomElement mapOverviewElem = mapOverviewNodeList.at( i ).toElement();
382  QgsComposerMapOverview* mapOverview = new QgsComposerMapOverview( mapOverviewElem.attribute( "name" ), mComposerMap );
383  mapOverview->readXML( mapOverviewElem, doc );
384  mItems.append( mapOverview );
385  }
386 
387  return true;
388 }
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.
virtual bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets map item state from a DOM document.
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 &elem, const QDomDocument &doc)
Sets the overview stack's state from a DOM document.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
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)
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores map item state in DOM element.
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.
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...
static QPainter::CompositionMode getCompositionMode(const QgsMapRenderer::BlendMode &blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
QList< QgsComposerMapItem * > mItems
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)
bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores overview state in DOM element.
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.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets overview state from a DOM document.
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
void draw(QPainter *painter)
Draws an overview.
static QgsSymbolV2 * loadSymbol(QDomElement &element)
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
bool usesAdvancedEffects() const
Returns true if the item is drawn using advanced effects, such as blend modes.
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:153
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...