QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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  mComposerMap( map ),
28  mName( name ),
29  mUuid( QUuid::createUuid().toString() ),
30  mEnabled( true ),
31  mFrameMapId( -1 ),
32  mFrameSymbol( 0 ),
33  mBlendMode( QPainter::CompositionMode_SourceOver ),
34  mInverted( false ),
35  mCentered( false )
36 {
38 }
39 
41 {
42 }
43 
45 {
46  delete mFrameSymbol;
47  QgsStringMap properties;
48  properties.insert( "color", "255,0,0,255" );
49  properties.insert( "style", "solid" );
50  properties.insert( "style_border", "no" );
52  mFrameSymbol->setAlpha( 0.3 );
53 }
54 
56 {
57  delete mFrameSymbol;
58 }
59 
60 void QgsComposerMapOverview::drawOverview( QPainter *painter ) const
61 {
62  if ( !mEnabled || mFrameMapId == -1 || !mComposerMap || !mComposerMap->composition() )
63  {
64  return;
65  }
66  if ( !painter )
67  {
68  return;
69  }
70 
71  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
72  if ( !overviewFrameMap )
73  {
74  return;
75  }
76 
77  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
78  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
79 
80  //get current map's extent as a QPolygonF
81  QPolygonF thisExtent = mComposerMap->visibleExtentPolygon();
82  //intersect the two
83  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
84 
85  //setup painter scaling to dots so that raster symbology is drawn to scale
86  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
87 
88  //setup render context
90  //context units should be in dots
91  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
93  ms.setOutputDpi( painter->device()->logicalDpiX() );
95  context.setForceVectorOutput( true );
96  context.setPainter( painter );
97 
98  painter->save();
99  painter->setCompositionMode( mBlendMode );
100  painter->translate( mComposerMap->mXOffset, mComposerMap->mYOffset );
101  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
102  painter->setRenderHint( QPainter::Antialiasing );
103 
104  mFrameSymbol->startRender( context );
105 
106  //construct a polygon corresponding to the intersecting map extent
107  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
108  QTransform mapTransform;
109  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * mComposerMap->rect().width(), dotsPerMM * mComposerMap->rect().height() ) );
110 
111  //workaround QT Bug #21329
112  thisRectPoly.pop_back();
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( "name", mName );
155  overviewFrameElem.setAttribute( "uuid", mUuid );
156  overviewFrameElem.setAttribute( "show", mEnabled );
157 
158  overviewFrameElem.setAttribute( "frameMap", mFrameMapId );
159  overviewFrameElem.setAttribute( "blendMode", QgsMapRenderer::getBlendModeEnum( mBlendMode ) );
160  overviewFrameElem.setAttribute( "inverted", mInverted );
161  overviewFrameElem.setAttribute( "centered", mCentered );
162 
163  QDomElement frameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mFrameSymbol, doc );
164  overviewFrameElem.appendChild( frameStyleElem );
165 
166  elem.appendChild( overviewFrameElem );
167  return true;
168 }
169 
170 bool QgsComposerMapOverview::readXML( const QDomElement &itemElem, const QDomDocument &doc )
171 {
172  Q_UNUSED( doc );
173  if ( itemElem.isNull() )
174  {
175  return false;
176  }
177 
178  mName = itemElem.attribute( "name" );
179  mUuid = itemElem.attribute( "uuid" );
180  mEnabled = ( itemElem.attribute( "show", "0" ) != "0" );
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 
188  QDomElement frameStyleElem = itemElem.firstChildElement( "symbol" );
189  if ( !frameStyleElem.isNull( ) )
190  {
191  delete mFrameSymbol;
192  mFrameSymbol = dynamic_cast<QgsFillSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( frameStyleElem ) );
193  }
194  return true;
195 }
196 
197 void QgsComposerMapOverview::setFrameMap( const int mapId )
198 {
199  if ( mFrameMapId == mapId )
200  {
201  //no change
202  return;
203  }
204 
205  //disconnect old map
206  if ( mFrameMapId != -1 && mComposerMap && mComposerMap->composition() )
207  {
209  if ( map )
210  {
211  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
212  }
213  }
214  mFrameMapId = mapId;
215  //connect to new map signals
216  connectSignals();
217 }
218 
220 {
221  if ( !mComposerMap )
222  {
223  return;
224  }
225 
226  if ( mFrameMapId != -1 && mComposerMap->composition() )
227  {
229  if ( map )
230  {
231  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
232  }
233  }
234 }
235 
237 {
238  delete mFrameSymbol;
239  mFrameSymbol = symbol;
240 }
241 
242 void QgsComposerMapOverview::setBlendMode( const QPainter::CompositionMode blendMode )
243 {
245 }
246 
247 void QgsComposerMapOverview::setInverted( const bool inverted )
248 {
250 }
251 
252 void QgsComposerMapOverview::setCentered( const bool centered )
253 {
256 }
257 
259 {
260  if ( !mComposerMap )
261  {
262  return;
263  }
264 
265  //if using overview centering, update the map's extent
266  if ( mComposerMap->composition() && mCentered && mFrameMapId != -1 )
267  {
269 
270  const QgsComposerMap* overviewFrameMap = mComposerMap->composition()->getComposerMapById( mFrameMapId );
271  if ( !overviewFrameMap )
272  {
273  //redraw map so that overview gets updated
274  mComposerMap->update();
275  return;
276  }
277  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
278 
279  QgsPoint center = otherExtent.center();
280  QgsRectangle movedExtent( center.x() - extent.width() / 2,
281  center.y() - extent.height() / 2,
282  center.x() - extent.width() / 2 + extent.width(),
283  center.y() - extent.height() / 2 + extent.height() );
284  *mComposerMap->currentMapExtent() = movedExtent;
285 
286  //trigger a recalculation of data defined extents, scale and rotation, since that
287  //may override the map centering
289 
290  //must invalidate cache so that map gets redrawn
291  mComposerMap->cache();
292  }
293 
294  //repaint map so that overview gets updated
295  mComposerMap->update();
296 }
void connectSignals()
Reconnects signals for overview map, so that overview correctly follows changes to source map's exten...
double mXOffset
Offset in x direction for showing map cache image.
void setForceVectorOutput(bool force)
Added in QGIS v1.5.
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 setOutputDpi(int dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
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 true if the extent is forced to center on the overview.
bool mCentered
Centering mode for overview.
virtual void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties)
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer...
double x() const
Definition: qgspoint.h:110
The QgsMapSettings class contains configuration for rendering of the map.
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void setFrameSymbol(QgsFillSymbolV2 *symbol)
void drawOverview(QPainter *painter) const
QPainter::CompositionMode blendMode() const
Returns the overview's blending mode.
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
const QgsComposition * composition() const
Returns the composition the item is attached to.
double mYOffset
Offset in y direction for showing map cache image.
void setCentered(const bool centered)
Set the overview's centering mode.
void setPainter(QPainter *p)
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
A class to represent a point geometry.
Definition: qgspoint.h:63
QPainter::CompositionMode mBlendMode
Blend mode for overview.
Object representing map window.
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 Added in 1.9.
Contains information about the context of a rendering operation.
void stopRender(QgsRenderContext &context)
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom element
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
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
void setInverted(const bool inverted)
Sets the overview's inversion mode.
void setFrameMap(const int mapId)
Sets overview frame map.
double y() const
Definition: qgspoint.h:118
static QgsSymbolV2 * loadSymbol(QDomElement &element)
static QgsMapRenderer::BlendMode getBlendModeEnum(const QPainter::CompositionMode &blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode Added in 1.9.
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:204
int mFrameMapId
Id of map which displays its extent rectangle into this composer map (overview map functionality)...
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:214
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:130
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the overview's blending mode.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:209
bool inverted() const
Returns true if the overview frame is inverted.
QgsFillSymbolV2 * mFrameSymbol
Drawing style for overview farme.