QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgscomposermapgrid.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposermapgrid.cpp
3  ----------------------
4  begin : December 2013
5  copyright : (C) 2013 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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 "qgscomposermapgrid.h"
19 #include "qgscomposerutils.h"
20 #include "qgsclipper.h"
21 #include "qgsgeometry.h"
22 #include "qgscomposermap.h"
23 #include "qgscomposition.h"
24 #include "qgsmaprenderer.h"
25 #include "qgsrendercontext.h"
26 #include "qgssymbollayerv2utils.h"
27 #include "qgssymbolv2.h"
29 #include "qgslogger.h"
30 
31 #include <QPainter>
32 #include <QPen>
33 
34 #define MAX_GRID_LINES 1000 //maximum number of horizontal or vertical grid lines to draw
35 
38 {
39 
40 }
41 
43 {
44 }
45 
47 {
49 }
50 
51 void QgsComposerMapGridStack::removeGrid( const QString& gridId )
52 {
54 }
55 
56 void QgsComposerMapGridStack::moveGridUp( const QString& gridId )
57 {
59 }
60 
61 void QgsComposerMapGridStack::moveGridDown( const QString& gridId )
62 {
64 }
65 
66 const QgsComposerMapGrid* QgsComposerMapGridStack::constGrid( const QString& gridId ) const
67 {
69  return dynamic_cast<const QgsComposerMapGrid*>( item );
70 }
71 
72 QgsComposerMapGrid* QgsComposerMapGridStack::grid( const QString& gridId ) const
73 {
75  return dynamic_cast<QgsComposerMapGrid*>( item );
76 }
77 
79 {
81  return dynamic_cast<QgsComposerMapGrid*>( item );
82 }
83 
84 QList<QgsComposerMapGrid *> QgsComposerMapGridStack::asList() const
85 {
86  QList< QgsComposerMapGrid* > list;
87  QList< QgsComposerMapItem* >::const_iterator it = mItems.begin();
88  for ( ; it != mItems.end(); ++it )
89  {
90  QgsComposerMapGrid* grid = dynamic_cast<QgsComposerMapGrid*>( *it );
91  if ( grid )
92  {
93  list.append( grid );
94  }
95  }
96  return list;
97 }
98 
100 {
102  QgsComposerMapGrid* grid = dynamic_cast<QgsComposerMapGrid*>( item );
103  return *grid;
104 }
105 
106 bool QgsComposerMapGridStack::readXML( const QDomElement &elem, const QDomDocument &doc )
107 {
108  removeItems();
109 
110  //read grid stack
111  QDomNodeList mapGridNodeList = elem.elementsByTagName( "ComposerMapGrid" );
112  for ( int i = 0; i < mapGridNodeList.size(); ++i )
113  {
114  QDomElement mapGridElem = mapGridNodeList.at( i ).toElement();
115  QgsComposerMapGrid* mapGrid = new QgsComposerMapGrid( mapGridElem.attribute( "name" ), mComposerMap );
116  mapGrid->readXML( mapGridElem, doc );
117  mItems.append( mapGrid );
118  }
119 
120  return true;
121 }
122 
124 {
125  double maxGridExtension = 0;
126 
127  QList< QgsComposerMapItem* >::const_iterator it = mItems.constBegin();
128  for ( ; it != mItems.constEnd(); ++it )
129  {
130  QgsComposerMapGrid* grid = dynamic_cast<QgsComposerMapGrid*>( *it );
131  if ( grid )
132  {
133  maxGridExtension = qMax( maxGridExtension, grid->maxExtension() );
134  }
135  }
136 
137  return maxGridExtension;
138 }
139 
140 
141 //
142 // QgsComposerMapGrid
143 //
144 
145 
147  : QgsComposerMapItem( name, map )
148  , mTransformDirty( true )
149  , mGridStyle( QgsComposerMapGrid::Solid )
150  , mGridIntervalX( 0.0 )
151  , mGridIntervalY( 0.0 )
152  , mGridOffsetX( 0.0 )
153  , mGridOffsetY( 0.0 )
154  , mGridAnnotationFontColor( Qt::black )
155  , mGridAnnotationPrecision( 3 )
156  , mShowGridAnnotation( false )
157  , mLeftGridAnnotationDisplay( QgsComposerMapGrid::ShowAll )
158  , mRightGridAnnotationDisplay( QgsComposerMapGrid::ShowAll )
159  , mTopGridAnnotationDisplay( QgsComposerMapGrid::ShowAll )
160  , mBottomGridAnnotationDisplay( QgsComposerMapGrid::ShowAll )
161  , mLeftGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame )
162  , mRightGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame )
163  , mTopGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame )
164  , mBottomGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame )
165  , mAnnotationFrameDistance( 1.0 )
166  , mLeftGridAnnotationDirection( QgsComposerMapGrid::Horizontal )
167  , mRightGridAnnotationDirection( QgsComposerMapGrid::Horizontal )
168  , mTopGridAnnotationDirection( QgsComposerMapGrid::Horizontal )
169  , mBottomGridAnnotationDirection( QgsComposerMapGrid::Horizontal )
170  , mGridAnnotationFormat( QgsComposerMapGrid::Decimal )
171  , mGridFrameStyle( QgsComposerMapGrid::NoFrame )
172  , mGridFrameSides( QgsComposerMapGrid::FrameLeft | QgsComposerMapGrid::FrameRight |
173  QgsComposerMapGrid::FrameTop | QgsComposerMapGrid::FrameBottom )
174  , mGridFrameWidth( 2.0 )
175  , mGridFramePenThickness( 0.3 )
176  , mGridFramePenColor( QColor( 0, 0, 0 ) )
177  , mGridFrameFillColor1( Qt::white )
178  , mGridFrameFillColor2( Qt::black )
179  , mCrossLength( 3 )
180  , mLeftFrameDivisions( QgsComposerMapGrid::ShowAll )
181  , mRightFrameDivisions( QgsComposerMapGrid::ShowAll )
182  , mTopFrameDivisions( QgsComposerMapGrid::ShowAll )
183  , mBottomFrameDivisions( QgsComposerMapGrid::ShowAll )
184  , mGridLineSymbol( 0 )
185  , mGridMarkerSymbol( 0 )
186  , mGridUnit( MapUnit )
187  , mBlendMode( QPainter::CompositionMode_SourceOver )
188 {
189  //get default composer font from settings
190  QSettings settings;
191  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
192  if ( !defaultFontString.isEmpty() )
193  {
194  mGridAnnotationFont.setFamily( defaultFontString );
195  }
196 
197  createDefaultGridLineSymbol();
198  createDefaultGridMarkerSymbol();
199 }
200 
201 QgsComposerMapGrid::QgsComposerMapGrid()
202  : QgsComposerMapItem( QString(), 0 )
203 {
204 }
205 
207 {
208  delete mGridLineSymbol;
209  delete mGridMarkerSymbol;
210 }
211 
212 void QgsComposerMapGrid::createDefaultGridLineSymbol()
213 {
214  delete mGridLineSymbol;
215  QgsStringMap properties;
216  properties.insert( "color", "0,0,0,255" );
217  properties.insert( "width", "0.3" );
218  properties.insert( "capstyle", "flat" );
219  mGridLineSymbol = QgsLineSymbolV2::createSimple( properties );
220 }
221 
222 void QgsComposerMapGrid::createDefaultGridMarkerSymbol()
223 {
224  delete mGridMarkerSymbol;
225  QgsStringMap properties;
226  properties.insert( "name", "circle" );
227  properties.insert( "size", "2.0" );
228  properties.insert( "color", "0,0,0,255" );
229  mGridMarkerSymbol = QgsMarkerSymbolV2::createSimple( properties );
230 }
231 
232 void QgsComposerMapGrid::setGridLineWidth( const double width )
233 {
234  if ( mGridLineSymbol )
235  {
236  mGridLineSymbol->setWidth( width );
237  }
238 }
239 
241 {
242  if ( mGridLineSymbol )
243  {
244  mGridLineSymbol->setColor( c );
245  }
246 }
247 
248 bool QgsComposerMapGrid::writeXML( QDomElement& elem, QDomDocument& doc ) const
249 {
250  if ( elem.isNull() )
251  {
252  return false;
253  }
254 
255  QDomElement mapGridElem = doc.createElement( "ComposerMapGrid" );
256  mapGridElem.setAttribute( "gridStyle", mGridStyle );
257  mapGridElem.setAttribute( "intervalX", qgsDoubleToString( mGridIntervalX ) );
258  mapGridElem.setAttribute( "intervalY", qgsDoubleToString( mGridIntervalY ) );
259  mapGridElem.setAttribute( "offsetX", qgsDoubleToString( mGridOffsetX ) );
260  mapGridElem.setAttribute( "offsetY", qgsDoubleToString( mGridOffsetY ) );
261  mapGridElem.setAttribute( "crossLength", qgsDoubleToString( mCrossLength ) );
262 
263  QDomElement lineStyleElem = doc.createElement( "lineStyle" );
264  QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc );
265  lineStyleElem.appendChild( gridLineStyleElem );
266  mapGridElem.appendChild( lineStyleElem );
267 
268  QDomElement markerStyleElem = doc.createElement( "markerStyle" );
269  QDomElement gridMarkerStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridMarkerSymbol, doc );
270  markerStyleElem.appendChild( gridMarkerStyleElem );
271  mapGridElem.appendChild( markerStyleElem );
272 
273  mapGridElem.setAttribute( "gridFrameStyle", mGridFrameStyle );
274  mapGridElem.setAttribute( "gridFrameSideFlags", mGridFrameSides );
275  mapGridElem.setAttribute( "gridFrameWidth", qgsDoubleToString( mGridFrameWidth ) );
276  mapGridElem.setAttribute( "gridFramePenThickness", qgsDoubleToString( mGridFramePenThickness ) );
277  mapGridElem.setAttribute( "gridFramePenColor", QgsSymbolLayerV2Utils::encodeColor( mGridFramePenColor ) );
278  mapGridElem.setAttribute( "frameFillColor1", QgsSymbolLayerV2Utils::encodeColor( mGridFrameFillColor1 ) );
279  mapGridElem.setAttribute( "frameFillColor2", QgsSymbolLayerV2Utils::encodeColor( mGridFrameFillColor2 ) );
280  mapGridElem.setAttribute( "leftFrameDivisions", mLeftFrameDivisions );
281  mapGridElem.setAttribute( "rightFrameDivisions", mRightFrameDivisions );
282  mapGridElem.setAttribute( "topFrameDivisions", mTopFrameDivisions );
283  mapGridElem.setAttribute( "bottomFrameDivisions", mBottomFrameDivisions );
284  if ( mCRS.isValid() )
285  {
286  mCRS.writeXML( mapGridElem, doc );
287  }
288 
289  mapGridElem.setAttribute( "annotationFormat", mGridAnnotationFormat );
290  mapGridElem.setAttribute( "showAnnotation", mShowGridAnnotation );
291  mapGridElem.setAttribute( "leftAnnotationDisplay", mLeftGridAnnotationDisplay );
292  mapGridElem.setAttribute( "rightAnnotationDisplay", mRightGridAnnotationDisplay );
293  mapGridElem.setAttribute( "topAnnotationDisplay", mTopGridAnnotationDisplay );
294  mapGridElem.setAttribute( "bottomAnnotationDisplay", mBottomGridAnnotationDisplay );
295  mapGridElem.setAttribute( "leftAnnotationPosition", mLeftGridAnnotationPosition );
296  mapGridElem.setAttribute( "rightAnnotationPosition", mRightGridAnnotationPosition );
297  mapGridElem.setAttribute( "topAnnotationPosition", mTopGridAnnotationPosition );
298  mapGridElem.setAttribute( "bottomAnnotationPosition", mBottomGridAnnotationPosition );
299  mapGridElem.setAttribute( "leftAnnotationDirection", mLeftGridAnnotationDirection );
300  mapGridElem.setAttribute( "rightAnnotationDirection", mRightGridAnnotationDirection );
301  mapGridElem.setAttribute( "topAnnotationDirection", mTopGridAnnotationDirection );
302  mapGridElem.setAttribute( "bottomAnnotationDirection", mBottomGridAnnotationDirection );
303  mapGridElem.setAttribute( "frameAnnotationDistance", QString::number( mAnnotationFrameDistance ) );
304  mapGridElem.setAttribute( "annotationFont", mGridAnnotationFont.toString() );
305  mapGridElem.setAttribute( "annotationFontColor", QgsSymbolLayerV2Utils::encodeColor( mGridAnnotationFontColor ) );
306  mapGridElem.setAttribute( "annotationPrecision", mGridAnnotationPrecision );
307  mapGridElem.setAttribute( "unit", mGridUnit );
308  mapGridElem.setAttribute( "blendMode", mBlendMode );
309 
310  bool ok = QgsComposerMapItem::writeXML( mapGridElem, doc );
311  elem.appendChild( mapGridElem );
312  return ok;
313 }
314 
315 bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocument& doc )
316 {
317  Q_UNUSED( doc );
318  if ( itemElem.isNull() )
319  {
320  return false;
321  }
322 
323  bool ok = QgsComposerMapItem::readXML( itemElem, doc );
324 
325  //grid
326  mGridStyle = QgsComposerMapGrid::GridStyle( itemElem.attribute( "gridStyle", "0" ).toInt() );
327  mGridIntervalX = itemElem.attribute( "intervalX", "0" ).toDouble();
328  mGridIntervalY = itemElem.attribute( "intervalY", "0" ).toDouble();
329  mGridOffsetX = itemElem.attribute( "offsetX", "0" ).toDouble();
330  mGridOffsetY = itemElem.attribute( "offsetY", "0" ).toDouble();
331  mCrossLength = itemElem.attribute( "crossLength", "3" ).toDouble();
332  mGridFrameStyle = ( QgsComposerMapGrid::FrameStyle )itemElem.attribute( "gridFrameStyle", "0" ).toInt();
333  mGridFrameSides = ( QgsComposerMapGrid::FrameSideFlags )itemElem.attribute( "gridFrameSideFlags", "15" ).toInt();
334  mGridFrameWidth = itemElem.attribute( "gridFrameWidth", "2.0" ).toDouble();
335  mGridFramePenThickness = itemElem.attribute( "gridFramePenThickness", "0.3" ).toDouble();
336  mGridFramePenColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "gridFramePenColor", "0,0,0" ) );
337  mGridFrameFillColor1 = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "frameFillColor1", "255,255,255,255" ) );
338  mGridFrameFillColor2 = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "frameFillColor2", "0,0,0,255" ) );
339  mLeftFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "leftFrameDivisions", "0" ).toInt() );
340  mRightFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "rightFrameDivisions", "0" ).toInt() );
341  mTopFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "topFrameDivisions", "0" ).toInt() );
342  mBottomFrameDivisions = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "bottomFrameDivisions", "0" ).toInt() );
343 
344  QDomElement lineStyleElem = itemElem.firstChildElement( "lineStyle" );
345  if ( !lineStyleElem.isNull() )
346  {
347  QDomElement symbolElem = lineStyleElem.firstChildElement( "symbol" );
348  if ( !symbolElem.isNull() )
349  {
350  delete mGridLineSymbol;
351  mGridLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( symbolElem ) );
352  }
353  }
354  else
355  {
356  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
357  mGridLineSymbol = QgsLineSymbolV2::createSimple( QgsStringMap() );
358  mGridLineSymbol->setWidth( itemElem.attribute( "penWidth", "0" ).toDouble() );
359  mGridLineSymbol->setColor( QColor( itemElem.attribute( "penColorRed", "0" ).toInt(),
360  itemElem.attribute( "penColorGreen", "0" ).toInt(),
361  itemElem.attribute( "penColorBlue", "0" ).toInt() ) );
362  }
363 
364  QDomElement markerStyleElem = itemElem.firstChildElement( "markerStyle" );
365  if ( !markerStyleElem.isNull() )
366  {
367  QDomElement symbolElem = markerStyleElem.firstChildElement( "symbol" );
368  if ( !symbolElem.isNull() )
369  {
370  delete mGridMarkerSymbol;
371  mGridMarkerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( symbolElem ) );
372  }
373  }
374 
375 
376  QDomElement crsElem = itemElem.firstChildElement( "spatialrefsys" );
377  if ( !crsElem.isNull() )
378  {
379  mCRS.readXML( const_cast<QDomElement&>( itemElem ) ); //better would be to change argument in QgsCoordinateReferenceSystem::readXML to const
380  }
381  else
382  {
384  }
385  mBlendMode = ( QPainter::CompositionMode )( itemElem.attribute( "blendMode", "0" ).toUInt() );
386 
387  //annotation
388  mShowGridAnnotation = ( itemElem.attribute( "showAnnotation", "0" ) != "0" );
389  mGridAnnotationFormat = QgsComposerMapGrid::AnnotationFormat( itemElem.attribute( "annotationFormat", "0" ).toInt() );
390  mLeftGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "leftAnnotationPosition", "0" ).toInt() );
391  mRightGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "rightAnnotationPosition", "0" ).toInt() );
392  mTopGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "topAnnotationPosition", "0" ).toInt() );
393  mBottomGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "bottomAnnotationPosition", "0" ).toInt() );
394  mLeftGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "leftAnnotationDisplay", "0" ).toInt() );
395  mRightGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "rightAnnotationDisplay", "0" ).toInt() );
396  mTopGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "topAnnotationDisplay", "0" ).toInt() );
397  mBottomGridAnnotationDisplay = QgsComposerMapGrid::DisplayMode( itemElem.attribute( "bottomAnnotationDisplay", "0" ).toInt() );
398  //upgrade pre-2.7 projects
399  if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::Disabled )
400  {
401  mLeftGridAnnotationDisplay = QgsComposerMapGrid::HideAll;
402  mLeftGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
403  }
404  if ( mRightGridAnnotationPosition == QgsComposerMapGrid::Disabled )
405  {
406  mRightGridAnnotationDisplay = QgsComposerMapGrid::HideAll;
407  mRightGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
408  }
409  if ( mTopGridAnnotationPosition == QgsComposerMapGrid::Disabled )
410  {
411  mTopGridAnnotationDisplay = QgsComposerMapGrid::HideAll;
412  mTopGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
413  }
414  if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::Disabled )
415  {
416  mBottomGridAnnotationDisplay = QgsComposerMapGrid::HideAll;
417  mBottomGridAnnotationPosition = QgsComposerMapGrid::OutsideMapFrame;
418  }
419 
420  mLeftGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "leftAnnotationDirection", "0" ).toInt() );
421  mRightGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "rightAnnotationDirection", "0" ).toInt() );
422  mTopGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "topAnnotationDirection", "0" ).toInt() );
423  mBottomGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "bottomAnnotationDirection", "0" ).toInt() );
424  mAnnotationFrameDistance = itemElem.attribute( "frameAnnotationDistance", "0" ).toDouble();
425  mGridAnnotationFont.fromString( itemElem.attribute( "annotationFont", "" ) );
426  mGridAnnotationFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "annotationFontColor", "0,0,0,255" ) );
427  mGridAnnotationPrecision = itemElem.attribute( "annotationPrecision", "3" ).toInt();
428  int gridUnitInt = itemElem.attribute( "unit", QString::number( MapUnit ) ).toInt();
429  mGridUnit = ( gridUnitInt <= ( int )CM ) ? ( GridUnit )gridUnitInt : MapUnit;
430  return ok;
431 }
432 
434 {
435  mCRS = crs;
436  mTransformDirty = true;
437 }
438 
440 {
441  return mBlendMode == QPainter::CompositionMode_SourceOver;
442 }
443 
444 QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const double scale ) const
445 {
446  QTransform t = QTransform::fromScale( scale, scale );
447  return t.map( polygon );
448 }
449 
450 void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
451  QList< QPair< double, QLineF > > &verticalLines )
452 {
453  if ( !mComposerMap || !mEnabled )
454  {
455  return;
456  }
457 
458  //has map extent/scale changed?
459  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
460  if ( mapPolygon != mPrevMapPolygon )
461  {
462  mTransformDirty = true;
463  mPrevMapPolygon = mapPolygon;
464  }
465 
466  if ( mTransformDirty )
467  {
468  calculateCRSTransformLines();
469  }
470 
471  //draw lines
472  if ( mGridStyle == QgsComposerMapGrid::Solid )
473  {
474  QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
475  for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
476  {
477  drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
478  }
479 
480  QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
481  for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
482  {
483  drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
484  }
485  }
486  else if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
487  {
488  double maxX = mComposerMap->rect().width();
489  double maxY = mComposerMap->rect().height();
490 
491  QList< QgsPoint >::const_iterator intersectionIt = mTransformedIntersections.constBegin();
492  for ( ; intersectionIt != mTransformedIntersections.constEnd(); ++intersectionIt )
493  {
494  double x = intersectionIt->x();
495  double y = intersectionIt->y();
496  if ( mGridStyle == QgsComposerMapGrid::Cross )
497  {
498  //ensure that crosses don't overshoot the map item bounds
499  QLineF line1 = QLineF( x - mCrossLength, y, x + mCrossLength, y );
500  line1.p1().rx() = line1.p1().x() < 0 ? 0 : line1.p1().x();
501  line1.p2().rx() = line1.p2().x() > maxX ? maxX : line1.p2().x();
502  QLineF line2 = QLineF( x, y - mCrossLength, x, y + mCrossLength );
503  line2.p1().ry() = line2.p1().y() < 0 ? 0 : line2.p1().y();
504  line2.p2().ry() = line2.p2().y() > maxY ? maxY : line2.p2().y();
505 
506  //draw line using coordinates scaled to dots
507  drawGridLine( QLineF( line1.p1() * dotsPerMM, line1.p2() * dotsPerMM ), context );
508  drawGridLine( QLineF( line2.p1() * dotsPerMM, line2.p2() * dotsPerMM ), context );
509  }
510  else if ( mGridStyle == QgsComposerMapGrid::Markers )
511  {
512  drawGridMarker( QPointF( x, y ) * dotsPerMM, context );
513  }
514  }
515  }
516 
517  //convert QPolygonF to QLineF to draw grid frames and annotations
518  QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = mTransformedYLines.constBegin();
519  for ( ; yGridLineIt != mTransformedYLines.constEnd(); ++yGridLineIt )
520  {
521  verticalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
522  }
523  QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = mTransformedXLines.constBegin();
524  for ( ; xGridLineIt != mTransformedXLines.constEnd(); ++xGridLineIt )
525  {
526  horizontalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
527  }
528 }
529 
530 void QgsComposerMapGrid::calculateCRSTransformLines()
531 {
532  QgsRectangle crsBoundingRect;
533  QgsCoordinateTransform inverseTr;
534  if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
535  {
536  return;
537  }
538 
539  //calculate x grid lines
540  mTransformedXLines.clear();
541  xGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedXLines );
542 
543  //calculate y grid lines
544  mTransformedYLines.clear();
545  yGridLinesCRSTransform( crsBoundingRect, inverseTr, mTransformedYLines );
546 
547  if ( mGridStyle == QgsComposerMapGrid::Cross || mGridStyle == QgsComposerMapGrid::Markers )
548  {
549  //cross or markers style - we also need to calculate intersections of lines
550 
551  //first convert lines to QgsGeometry
552  QList< QgsGeometry* > yLines;
553  QList< QPair< double, QPolygonF > >::const_iterator yGridIt = mTransformedYLines.constBegin();
554  for ( ; yGridIt != mTransformedYLines.constEnd(); ++yGridIt )
555  {
556  QgsPolyline yLine;
557  for ( int i = 0; i < ( *yGridIt ).second.size(); ++i )
558  {
559  yLine.append( QgsPoint(( *yGridIt ).second.at( i ).x(), ( *yGridIt ).second.at( i ).y() ) );
560  }
561  yLines << QgsGeometry::fromPolyline( yLine );
562  }
563  QList< QgsGeometry* > xLines;
564  QList< QPair< double, QPolygonF > >::const_iterator xGridIt = mTransformedXLines.constBegin();
565  for ( ; xGridIt != mTransformedXLines.constEnd(); ++xGridIt )
566  {
567  QgsPolyline xLine;
568  for ( int i = 0; i < ( *xGridIt ).second.size(); ++i )
569  {
570  xLine.append( QgsPoint(( *xGridIt ).second.at( i ).x(), ( *xGridIt ).second.at( i ).y() ) );
571  }
572  xLines << QgsGeometry::fromPolyline( xLine );
573  }
574 
575  //now, loop through geometries and calculate intersection points
576  mTransformedIntersections.clear();
577  QList< QgsGeometry* >::const_iterator yLineIt = yLines.constBegin();
578  for ( ; yLineIt != yLines.constEnd(); ++yLineIt )
579  {
580  QList< QgsGeometry* >::const_iterator xLineIt = xLines.constBegin();
581  for ( ; xLineIt != xLines.constEnd(); ++xLineIt )
582  {
583  //look for intersections between lines
584  QgsGeometry* intersects = ( *yLineIt )->intersection(( *xLineIt ) );
585 
586  //go through all intersections and draw grid markers/crosses
587  int i = 0;
588  QgsPoint vertex = intersects->vertexAt( i );
589  while ( vertex != QgsPoint( 0, 0 ) )
590  {
591  mTransformedIntersections << vertex;
592  i = i + 1;
593  vertex = intersects->vertexAt( i );
594  }
595  }
596  }
597  //clean up
598  qDeleteAll( yLines );
599  yLines.clear();
600  qDeleteAll( xLines );
601  xLines.clear();
602  }
603 
604  mTransformDirty = false;
605 }
606 
607 void QgsComposerMapGrid::draw( QPainter* p )
608 {
609  if ( !mComposerMap || !mEnabled )
610  {
611  return;
612  }
613  QPaintDevice* thePaintDevice = p->device();
614  if ( !thePaintDevice )
615  {
616  return;
617  }
618 
619  p->save();
620  p->setCompositionMode( mBlendMode );
621  p->setRenderHint( QPainter::Antialiasing );
622 
623  QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
624  p->setClipRect( thisPaintRect );
625  if ( thisPaintRect != mPrevPaintRect )
626  {
627  //rect has changed, so need to recalculate transform
628  mTransformDirty = true;
629  mPrevPaintRect = thisPaintRect;
630  }
631 
632  //setup painter scaling to dots so that raster symbology is drawn to scale
633  double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
634  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
635 
636  //setup render context
638  //context units should be in dots
639  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
641  ms.setOutputDpi( p->device()->logicalDpiX() );
643  context.setForceVectorOutput( true );
644  context.setPainter( p );
645 
646  QList< QPair< double, QLineF > > verticalLines;
647  QList< QPair< double, QLineF > > horizontalLines;
648 
649  //is grid in a different crs than map?
650  if ( mGridUnit == MapUnit && mCRS.isValid() && mCRS != ms.destinationCrs() )
651  {
652  drawGridCRSTransform( context, dotsPerMM, horizontalLines, verticalLines );
653  }
654  else
655  {
656  drawGridNoTransform( context, dotsPerMM, horizontalLines, verticalLines );
657  }
658 
659  p->restore();
660  p->setClipping( false );
661 
662  if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame )
663  {
664  drawGridFrame( p, horizontalLines, verticalLines );
665  }
666 
667  if ( mShowGridAnnotation )
668  {
669  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
670  }
671 }
672 
673 void QgsComposerMapGrid::drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
674  QList< QPair< double, QLineF > > &verticalLines ) const
675 {
676  //get line positions
677  yGridLines( verticalLines );
678  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
679  xGridLines( horizontalLines );
680  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
681 
682  //simple approach: draw vertical lines first, then horizontal ones
683  if ( mGridStyle == QgsComposerMapGrid::Solid )
684  {
685  //we need to scale line coordinates to dots, rather than mm, since the painter has already been scaled to dots
686  //this is done by multiplying each line coordinate by dotsPerMM
687  QLineF line;
688  for ( ; vIt != verticalLines.constEnd(); ++vIt )
689  {
690  line = QLineF( vIt->second.p1() * dotsPerMM, vIt->second.p2() * dotsPerMM );
691  drawGridLine( line, context );
692  }
693 
694  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
695  {
696  line = QLineF( hIt->second.p1() * dotsPerMM, hIt->second.p2() * dotsPerMM );
697  drawGridLine( line, context );
698  }
699  }
700  else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers
701  {
702  QPointF intersectionPoint, crossEnd1, crossEnd2;
703  for ( ; vIt != verticalLines.constEnd(); ++vIt )
704  {
705  //test for intersection with every horizontal line
706  hIt = horizontalLines.constBegin();
707  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
708  {
709  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
710  {
711  if ( mGridStyle == QgsComposerMapGrid::Cross )
712  {
713  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
714  crossEnd1 = (( intersectionPoint - vIt->second.p1() ).manhattanLength() > 0.01 ) ?
715  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength ) : intersectionPoint;
716  crossEnd2 = (( intersectionPoint - vIt->second.p2() ).manhattanLength() > 0.01 ) ?
717  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength ) : intersectionPoint;
718  //draw line using coordinates scaled to dots
719  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
720  }
721  else if ( mGridStyle == QgsComposerMapGrid::Markers )
722  {
723  drawGridMarker( intersectionPoint * dotsPerMM, context );
724  }
725  }
726  }
727  }
728  if ( mGridStyle == QgsComposerMapGrid::Markers )
729  {
730  //markers mode, so we have no need to process horizontal lines (we've already
731  //drawn markers on the intersections between horizontal and vertical lines)
732  return;
733  }
734 
735  hIt = horizontalLines.constBegin();
736  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
737  {
738  vIt = verticalLines.constBegin();
739  for ( ; vIt != verticalLines.constEnd(); ++vIt )
740  {
741  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
742  {
743  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
744  crossEnd1 = (( intersectionPoint - hIt->second.p1() ).manhattanLength() > 0.01 ) ?
745  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength ) : intersectionPoint;
746  crossEnd2 = (( intersectionPoint - hIt->second.p2() ).manhattanLength() > 0.01 ) ?
747  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength ) : intersectionPoint;
748  //draw line using coordinates scaled to dots
749  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
750  }
751  }
752  }
753  }
754 }
755 
756 void QgsComposerMapGrid::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
757 {
758  p->save();
759  p->setRenderHint( QPainter::Antialiasing );
760 
761  //Sort the coordinate positions for each side
762  QMap< double, double > leftGridFrame;
763  QMap< double, double > rightGridFrame;
764  QMap< double, double > topGridFrame;
765  QMap< double, double > bottomGridFrame;
766 
767  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
768 
770  {
771  drawGridFrameBorder( p, leftGridFrame, QgsComposerMapGrid::Left );
772  }
774  {
775  drawGridFrameBorder( p, rightGridFrame, QgsComposerMapGrid::Right );
776  }
778  {
779  drawGridFrameBorder( p, topGridFrame, QgsComposerMapGrid::Top );
780  }
782  {
783  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMapGrid::Bottom );
784  }
785  p->restore();
786 }
787 
788 void QgsComposerMapGrid::drawGridLine( const QLineF& line, QgsRenderContext& context ) const
789 {
790  QPolygonF poly;
791  poly << line.p1() << line.p2();
792  drawGridLine( poly, context );
793 }
794 
795 void QgsComposerMapGrid::drawGridLine( const QPolygonF& line, QgsRenderContext& context ) const
796 {
797  if ( !mComposerMap || !mComposerMap->composition() || !mGridLineSymbol )
798  {
799  return;
800  }
801 
802  mGridLineSymbol->startRender( context );
803  mGridLineSymbol->renderPolyline( line, 0, context );
804  mGridLineSymbol->stopRender( context );
805 }
806 
807 void QgsComposerMapGrid::drawGridMarker( const QPointF& point, QgsRenderContext& context ) const
808 {
809  if ( !mComposerMap || !mComposerMap->composition() || !mGridMarkerSymbol )
810  {
811  return;
812  }
813 
814  mGridMarkerSymbol->startRender( context );
815  mGridMarkerSymbol->renderPoint( point, 0, context );
816  mGridMarkerSymbol->stopRender( context );
817 }
818 
819 void QgsComposerMapGrid::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
820 {
821  if ( !mComposerMap )
822  {
823  return;
824  }
825 
826  switch ( mGridFrameStyle )
827  {
829  drawGridFrameZebraBorder( p, borderPos, border );
830  break;
834  drawGridFrameTicks( p, borderPos, border );
835  break;
836 
838  drawGridFrameLineBorder( p, border );
839  break;
840 
842  break;
843  }
844 
845 }
846 
847 void QgsComposerMapGrid::drawGridFrameZebraBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
848 {
849  if ( !mComposerMap )
850  {
851  return;
852  }
853 
854  QMap< double, double > pos = borderPos;
855 
856  double currentCoord = 0;
858  {
859  currentCoord = - mGridFrameWidth;
860  pos.insert( 0, 0 );
861  }
863  {
864  currentCoord = - mGridFrameWidth;
865  pos.insert( 0, 0 );
866  }
867  bool color1 = true;
868  double x = 0;
869  double y = 0;
870  double width = 0;
871  double height = 0;
872 
873  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
874  {
875  pos.insert( mComposerMap->rect().height(), mComposerMap->rect().height() );
877  {
878  pos.insert( mComposerMap->rect().height() + mGridFrameWidth, mComposerMap->rect().height() + mGridFrameWidth );
879  }
880  }
881  else if ( border == QgsComposerMapGrid::Top || border == QgsComposerMapGrid::Bottom )
882  {
883  pos.insert( mComposerMap->rect().width(), mComposerMap->rect().width() );
885  {
886  pos.insert( mComposerMap->rect().width() + mGridFrameWidth, mComposerMap->rect().width() + mGridFrameWidth );
887  }
888  }
889 
890  //set pen to current frame pen
891  QPen framePen = QPen( mGridFramePenColor );
892  framePen.setWidthF( mGridFramePenThickness );
893  framePen.setJoinStyle( Qt::MiterJoin );
894  p->setPen( framePen );
895 
896  QMap< double, double >::const_iterator posIt = pos.constBegin();
897  for ( ; posIt != pos.constEnd(); ++posIt )
898  {
899  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
900  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
901  {
902  height = posIt.key() - currentCoord;
903  width = mGridFrameWidth;
904  x = ( border == QgsComposerMapGrid::Left ) ? -mGridFrameWidth : mComposerMap->rect().width();
905  y = currentCoord;
906  }
907  else //top or bottom
908  {
909  height = mGridFrameWidth;
910  width = posIt.key() - currentCoord;
911  x = currentCoord;
912  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
913  }
914  p->drawRect( QRectF( x, y, width, height ) );
915  currentCoord = posIt.key();
916  color1 = !color1;
917  }
918 }
919 
920 void QgsComposerMapGrid::drawGridFrameTicks( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
921 {
922  if ( !mComposerMap )
923  {
924  return;
925  }
926 
927  double x = 0;
928  double y = 0;
929  double width = 0;
930  double height = 0;
931 
932  //set pen to current frame pen
933  QPen framePen = QPen( mGridFramePenColor );
934  framePen.setWidthF( mGridFramePenThickness );
935  framePen.setCapStyle( Qt::FlatCap );
936  p->setBrush( Qt::NoBrush );
937  p->setPen( framePen );
938 
939  QMap< double, double >::const_iterator posIt = borderPos.constBegin();
940  for ( ; posIt != borderPos.constEnd(); ++posIt )
941  {
942  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
943  {
944  y = posIt.key();
945  height = 0;
946  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
947  {
948  width = mGridFrameWidth;
949  x = ( border == QgsComposerMapGrid::Left ) ? 0 : mComposerMap->rect().width() - mGridFrameWidth;
950  }
951  else if ( mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
952  {
953  width = mGridFrameWidth;
954  x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width();
955  }
956  else if ( mGridFrameStyle == QgsComposerMapGrid::InteriorExteriorTicks )
957  {
958  width = mGridFrameWidth * 2;
959  x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width() - mGridFrameWidth;
960  }
961  }
962  else //top or bottom
963  {
964  x = posIt.key();
965  width = 0;
966  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
967  {
968  height = mGridFrameWidth;
969  y = ( border == QgsComposerMapGrid::Top ) ? 0 : mComposerMap->rect().height() - mGridFrameWidth;
970  }
971  else if ( mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
972  {
973  height = mGridFrameWidth;
974  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
975  }
976  else if ( mGridFrameStyle == QgsComposerMapGrid::InteriorExteriorTicks )
977  {
978  height = mGridFrameWidth * 2;
979  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height() - mGridFrameWidth;
980  }
981  }
982  p->drawLine( QLineF( x, y, x + width, y + height ) );
983  }
984 }
985 
986 void QgsComposerMapGrid::drawGridFrameLineBorder( QPainter* p, QgsComposerMapGrid::BorderSide border ) const
987 {
988  if ( !mComposerMap )
989  {
990  return;
991  }
992 
993  //set pen to current frame pen
994  QPen framePen = QPen( mGridFramePenColor );
995  framePen.setWidthF( mGridFramePenThickness );
996  framePen.setCapStyle( Qt::SquareCap );
997  p->setBrush( Qt::NoBrush );
998  p->setPen( framePen );
999 
1000  switch ( border )
1001  {
1003  p->drawLine( QLineF( 0, 0, 0, mComposerMap->rect().height() ) );
1004  break;
1006  p->drawLine( QLineF( mComposerMap->rect().width(), 0, mComposerMap->rect().width(), mComposerMap->rect().height() ) );
1007  break;
1009  p->drawLine( QLineF( 0, 0, mComposerMap->rect().width(), 0 ) );
1010  break;
1012  p->drawLine( QLineF( 0, mComposerMap->rect().height(), mComposerMap->rect().width(), mComposerMap->rect().height() ) );
1013  break;
1014  }
1015 }
1016 
1017 void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
1018 {
1019  if ( !p )
1020  {
1021  return;
1022  }
1023 
1024  QString currentAnnotationString;
1025  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1026  for ( ; it != hLines.constEnd(); ++it )
1027  {
1028  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude );
1029  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Latitude );
1030  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Latitude );
1031  }
1032 
1033  it = vLines.constBegin();
1034  for ( ; it != vLines.constEnd(); ++it )
1035  {
1036  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Longitude );
1037  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Longitude );
1038  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Longitude );
1039  }
1040 }
1041 
1042 void QgsComposerMapGrid::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString, const AnnotationCoordinate coordinateType ) const
1043 {
1044  if ( !mComposerMap )
1045  {
1046  return;
1047  }
1048  QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( pos, coordinateType );
1049  double textWidth = QgsComposerUtils::textWidthMM( mGridAnnotationFont, annotationString );
1050  //relevant for annotations is the height of digits
1051  double textHeight = QgsComposerUtils::fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
1052  double xpos = pos.x();
1053  double ypos = pos.y();
1054  int rotation = 0;
1055 
1056  double gridFrameDistance = 0;
1057  if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame && mGridFrameStyle != QgsComposerMapGrid::LineBorder )
1058  {
1059  gridFrameDistance = mGridFrameWidth;
1060  }
1061  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::LineBorder )
1062  {
1063  gridFrameDistance += ( mGridFramePenThickness / 2.0 );
1064  }
1065 
1066  if ( frameBorder == QgsComposerMapGrid::Left )
1067  {
1068  if ( mLeftGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1069  ( coordinateType == Longitude && mLeftGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1070  ( coordinateType == Latitude && mLeftGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1071  {
1072  return;
1073  }
1075  {
1076  gridFrameDistance = 0;
1077  }
1078 
1079  if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1080  {
1081  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1082  {
1083  gridFrameDistance = 0;
1084  }
1085  if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::Vertical || mLeftGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1086  {
1087  xpos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
1088  ypos += textWidth / 2.0;
1089  rotation = 270;
1090  }
1091  else if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1092  {
1093  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1094  ypos -= textWidth / 2.0;
1095  rotation = 90;
1096  }
1097  else
1098  {
1099  xpos += mAnnotationFrameDistance + gridFrameDistance;
1100  ypos += textHeight / 2.0;
1101  }
1102  }
1103  else if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //Outside map frame
1104  {
1105  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1106  {
1107  gridFrameDistance = 0;
1108  }
1109  if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::Vertical || mLeftGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1110  {
1111  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
1112  ypos += textWidth / 2.0;
1113  rotation = 270;
1114  }
1115  else if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1116  {
1117  xpos -= textHeight + mAnnotationFrameDistance + gridFrameDistance;
1118  ypos -= textWidth / 2.0;
1119  rotation = 90;
1120  }
1121  else
1122  {
1123  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1124  ypos += textHeight / 2.0;
1125  }
1126  }
1127  else
1128  {
1129  return;
1130  }
1131 
1132  }
1133  else if ( frameBorder == QgsComposerMapGrid::Right )
1134  {
1135  if ( mRightGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1136  ( coordinateType == Longitude && mRightGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1137  ( coordinateType == Latitude && mRightGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1138  {
1139  return;
1140  }
1142  {
1143  gridFrameDistance = 0;
1144  }
1145 
1146  if ( mRightGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1147  {
1148  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1149  {
1150  gridFrameDistance = 0;
1151  }
1152  if ( mRightGridAnnotationDirection == QgsComposerMapGrid::Vertical )
1153  {
1154  xpos -= mAnnotationFrameDistance + gridFrameDistance;
1155  ypos += textWidth / 2.0;
1156  rotation = 270;
1157  }
1158  else if ( mRightGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending || mRightGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1159  {
1160  xpos -= textHeight + mAnnotationFrameDistance + gridFrameDistance;
1161  ypos -= textWidth / 2.0;
1162  rotation = 90;
1163  }
1164  else
1165  {
1166  xpos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1167  ypos += textHeight / 2.0;
1168  }
1169  }
1170  else if ( mRightGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame )//OutsideMapFrame
1171  {
1172  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1173  {
1174  gridFrameDistance = 0;
1175  }
1176  if ( mRightGridAnnotationDirection == QgsComposerMapGrid::Vertical )
1177  {
1178  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
1179  ypos += textWidth / 2.0;
1180  rotation = 270;
1181  }
1182  else if ( mRightGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending || mRightGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1183  {
1184  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1185  ypos -= textWidth / 2.0;
1186  rotation = 90;
1187  }
1188  else //Horizontal
1189  {
1190  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1191  ypos += textHeight / 2.0;
1192  }
1193  }
1194  else
1195  {
1196  return;
1197  }
1198  }
1199  else if ( frameBorder == QgsComposerMapGrid::Bottom )
1200  {
1201  if ( mBottomGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1202  ( coordinateType == Longitude && mBottomGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1203  ( coordinateType == Latitude && mBottomGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1204  {
1205  return;
1206  }
1208  {
1209  gridFrameDistance = 0;
1210  }
1211 
1212  if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1213  {
1214  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1215  {
1216  gridFrameDistance = 0;
1217  }
1218  if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mBottomGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1219  {
1220  ypos -= mAnnotationFrameDistance + gridFrameDistance;
1221  xpos -= textWidth / 2.0;
1222  }
1223  else if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1224  {
1225  xpos -= textHeight / 2.0;
1226  ypos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1227  rotation = 90;
1228  }
1229  else //Vertical
1230  {
1231  xpos += textHeight / 2.0;
1232  ypos -= mAnnotationFrameDistance + gridFrameDistance;
1233  rotation = 270;
1234  }
1235  }
1236  else if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
1237  {
1238  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1239  {
1240  gridFrameDistance = 0;
1241  }
1242  if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mBottomGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1243  {
1244  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
1245  xpos -= textWidth / 2.0;
1246  }
1247  else if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1248  {
1249  xpos -= textHeight / 2.0;
1250  ypos += gridFrameDistance + mAnnotationFrameDistance;
1251  rotation = 90;
1252  }
1253  else //Vertical
1254  {
1255  xpos += textHeight / 2.0;
1256  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1257  rotation = 270;
1258  }
1259  }
1260  else
1261  {
1262  return;
1263  }
1264  }
1265  else //top
1266  {
1267  if ( mTopGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1268  ( coordinateType == Longitude && mTopGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1269  ( coordinateType == Latitude && mTopGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1270  {
1271  return;
1272  }
1274  {
1275  gridFrameDistance = 0;
1276  }
1277 
1278  if ( mTopGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1279  {
1280  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1281  {
1282  gridFrameDistance = 0;
1283  }
1284  if ( mTopGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mTopGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1285  {
1286  xpos -= textWidth / 2.0;
1287  ypos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
1288  }
1289  else if ( mTopGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1290  {
1291  xpos -= textHeight / 2.0;
1292  ypos += mAnnotationFrameDistance + gridFrameDistance;
1293  rotation = 90;
1294  }
1295  else //Vertical
1296  {
1297  xpos += textHeight / 2.0;
1298  ypos += textWidth + mAnnotationFrameDistance + gridFrameDistance;
1299  rotation = 270;
1300  }
1301  }
1302  else if ( mTopGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
1303  {
1304  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1305  {
1306  gridFrameDistance = 0;
1307  }
1308  if ( mTopGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mTopGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1309  {
1310  xpos -= textWidth / 2.0;
1311  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1312  }
1313  else if ( mTopGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1314  {
1315  xpos -= textHeight / 2.0;
1316  ypos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1317  rotation = 90;
1318  }
1319  else //Vertical
1320  {
1321  xpos += textHeight / 2.0;
1322  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1323  rotation = 270;
1324  }
1325  }
1326  else
1327  {
1328  return;
1329  }
1330  }
1331 
1332  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
1333 }
1334 
1335 void QgsComposerMapGrid::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText ) const
1336 {
1337  if ( !mComposerMap )
1338  {
1339  return;
1340  }
1341 
1342  p->save();
1343  p->translate( pos );
1344  p->rotate( rotation );
1345  QgsComposerUtils::drawText( p, QPointF( 0, 0 ), annotationText, mGridAnnotationFont, mGridAnnotationFontColor );
1346  p->restore();
1347 }
1348 
1349 QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord ) const
1350 {
1351  if ( mGridAnnotationFormat == QgsComposerMapGrid::Decimal )
1352  {
1353  return QString::number( value, 'f', mGridAnnotationPrecision );
1354  }
1355  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DecimalWithSuffix )
1356  {
1357  QString hemisphere;
1358 
1359  //check if we are using degrees (ie, geographic crs)
1360  bool geographic = false;
1361  if ( mCRS.isValid() && mCRS.geographicFlag() )
1362  {
1363  geographic = true;
1364  }
1365  else if ( mComposerMap && mComposerMap->composition() )
1366  {
1368  }
1369 
1370  double coordRounded = qRound( value * pow( 10.0, mGridAnnotationPrecision ) ) / pow( 10.0, mGridAnnotationPrecision );
1371  if ( coord == QgsComposerMapGrid::Longitude )
1372  {
1373  //don't use E/W suffixes if ambiguous (eg 180 degrees)
1374  if ( !geographic || ( coordRounded != 180.0 && coordRounded != 0.0 ) )
1375  {
1376  hemisphere = value < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
1377  }
1378  }
1379  else
1380  {
1381  //don't use N/S suffixes if ambiguous (eg 0 degrees)
1382  if ( !geographic || coordRounded != 0.0 )
1383  {
1384  hemisphere = value < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
1385  }
1386  }
1387  if ( geographic )
1388  {
1389  //insert degree symbol for geographic coordinates
1390  return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + QChar( 176 ) + hemisphere;
1391  }
1392  else
1393  {
1394  return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
1395  }
1396  }
1397 
1398  QgsPoint p;
1399  p.setX( coord == QgsComposerMapGrid::Longitude ? value : 0 );
1400  p.setY( coord == QgsComposerMapGrid::Longitude ? 0 : value );
1401 
1402  QString annotationString;
1403  if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinute )
1404  {
1405  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
1406  }
1407  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteNoSuffix )
1408  {
1409  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, false );
1410  }
1411  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinutePadded )
1412  {
1413  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, true, true );
1414  }
1415  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecond )
1416  {
1417  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
1418  }
1419  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecondNoSuffix )
1420  {
1421  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, false );
1422  }
1423  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecondPadded )
1424  {
1425  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, true, true );
1426  }
1427 
1428  QStringList split = annotationString.split( "," );
1429  if ( coord == QgsComposerMapGrid::Longitude )
1430  {
1431  return split.at( 0 );
1432  }
1433  else
1434  {
1435  if ( split.size() < 2 )
1436  {
1437  return "";
1438  }
1439  return split.at( 1 );
1440  }
1441 }
1442 
1443 int QgsComposerMapGrid::xGridLines( QList< QPair< double, QLineF > >& lines ) const
1444 {
1445  lines.clear();
1446  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1447  {
1448  return 1;
1449  }
1450 
1451 
1452  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
1453  QRectF mapBoundingRect = mapPolygon.boundingRect();
1454  double gridIntervalY = mGridIntervalY;
1455  double gridOffsetY = mGridOffsetY;
1456  double annotationScale = 1.0;
1457  if ( mGridUnit != MapUnit )
1458  {
1459  mapBoundingRect = mComposerMap->rect();
1460  mapPolygon = QPolygonF( mComposerMap->rect() );
1461  if ( mGridUnit == CM )
1462  {
1463  annotationScale = 0.1;
1464  gridIntervalY *= 10; gridOffsetY *= 10;
1465  }
1466  }
1467 
1468  //consider to round up to the next step in case the left boundary is > 0
1469  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1470  double currentLevel = ( int )(( mapBoundingRect.top() - gridOffsetY ) / gridIntervalY + roundCorrection ) * gridIntervalY + gridOffsetY;
1471 
1472  int gridLineCount = 0;
1473  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
1474  {
1475  //no rotation. Do it 'the easy way'
1476 
1477  double yCanvasCoord;
1478  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1479  {
1480  yCanvasCoord = mComposerMap->rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1481  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( 0, yCanvasCoord, mComposerMap->rect().width(), yCanvasCoord ) ) );
1482  currentLevel += gridIntervalY;
1483  gridLineCount++;
1484  }
1485  return 0;
1486  }
1487 
1488  //the four border lines
1489  QVector<QLineF> borderLines;
1490  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1491  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1492  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1493  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1494 
1495  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1496 
1497  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1498  {
1499  intersectionList.clear();
1500  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1501 
1502  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1503  for ( ; it != borderLines.constEnd(); ++it )
1504  {
1505  QPointF intersectionPoint;
1506  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1507  {
1508  intersectionList.push_back( intersectionPoint );
1509  if ( intersectionList.size() >= 2 )
1510  {
1511  break; //we already have two intersections, skip further tests
1512  }
1513  }
1514  }
1515 
1516  if ( intersectionList.size() >= 2 )
1517  {
1518  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1519  gridLineCount++;
1520  }
1521  currentLevel += gridIntervalY;
1522  }
1523 
1524 
1525  return 0;
1526 }
1527 
1528 int QgsComposerMapGrid::yGridLines( QList< QPair< double, QLineF > >& lines ) const
1529 {
1530  lines.clear();
1531  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1532  {
1533  return 1;
1534  }
1535 
1536  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
1537  QRectF mapBoundingRect = mapPolygon.boundingRect();
1538  double gridIntervalX = mGridIntervalX;
1539  double gridOffsetX = mGridOffsetX;
1540  double annotationScale = 1.0;
1541  if ( mGridUnit != MapUnit )
1542  {
1543  mapBoundingRect = mComposerMap->rect();
1544  mapPolygon = QPolygonF( mComposerMap->rect() );
1545  if ( mGridUnit == CM )
1546  {
1547  annotationScale = 0.1;
1548  gridIntervalX *= 10; gridOffsetX *= 10;
1549  }
1550  }
1551 
1552  //consider to round up to the next step in case the left boundary is > 0
1553  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1554  double currentLevel = ( int )(( mapBoundingRect.left() - gridOffsetX ) / gridIntervalX + roundCorrection ) * gridIntervalX + gridOffsetX;
1555 
1556  int gridLineCount = 0;
1557  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
1558  {
1559  //no rotation. Do it 'the easy way'
1560  double xCanvasCoord;
1561  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1562  {
1563  xCanvasCoord = mComposerMap->rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1564  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( xCanvasCoord, 0, xCanvasCoord, mComposerMap->rect().height() ) ) );
1565  currentLevel += gridIntervalX;
1566  gridLineCount++;
1567  }
1568  return 0;
1569  }
1570 
1571  //the four border lines
1572  QVector<QLineF> borderLines;
1573  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1574  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1575  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1576  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1577 
1578  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1579 
1580  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1581  {
1582  intersectionList.clear();
1583  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1584 
1585  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1586  for ( ; it != borderLines.constEnd(); ++it )
1587  {
1588  QPointF intersectionPoint;
1589  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1590  {
1591  intersectionList.push_back( intersectionPoint );
1592  if ( intersectionList.size() >= 2 )
1593  {
1594  break; //we already have two intersections, skip further tests
1595  }
1596  }
1597  }
1598 
1599  if ( intersectionList.size() >= 2 )
1600  {
1601  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1602  gridLineCount++;
1603  }
1604  currentLevel += gridIntervalX;
1605  }
1606 
1607  return 0;
1608 }
1609 
1610 int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1611 {
1612  lines.clear();
1613  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1614  {
1615  return 1;
1616  }
1617 
1618  double roundCorrection = bbox.yMaximum() > 0 ? 1.0 : 0.0;
1619  double currentLevel = ( int )(( bbox.yMaximum() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1620 
1621  double minX = bbox.xMinimum();
1622  double maxX = bbox.xMaximum();
1623  double step = ( maxX - minX ) / 20;
1624 
1625  bool crosses180 = false;
1626  bool crossed180 = false;
1627  if ( mCRS.geographicFlag() && ( minX > maxX ) )
1628  {
1629  //handle 180 degree longitude crossover
1630  crosses180 = true;
1631  step = ( maxX + 360.0 - minX ) / 20;
1632  }
1633 
1634  int gridLineCount = 0;
1635  while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
1636  {
1637  QPolygonF gridLine;
1638  double currentX = minX;
1639  bool cont = true;
1640  while ( cont )
1641  {
1642  if (( !crosses180 || crossed180 ) && ( currentX > maxX ) )
1643  {
1644  cont = false;
1645  }
1646 
1647  try
1648  {
1649  QgsPoint mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
1650  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
1651  }
1652  catch ( QgsCsException & cse )
1653  {
1654  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
1655  }
1656 
1657  currentX += step;
1658  if ( crosses180 && currentX > 180.0 )
1659  {
1660  currentX -= 360.0;
1661  crossed180 = true;
1662  }
1663  }
1664  crossed180 = false;
1665 
1666  QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1667  QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1668  for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
1669  {
1670  if (( *lineIt ).size() > 0 )
1671  {
1672  lines.append( qMakePair( currentLevel, *lineIt ) );
1673  gridLineCount++;
1674  }
1675  }
1676  currentLevel -= mGridIntervalY;
1677  }
1678 
1679  return 0;
1680 }
1681 
1682 int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1683 {
1684  lines.clear();
1685  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1686  {
1687  return 1;
1688  }
1689 
1690  double roundCorrection = bbox.xMinimum() > 0 ? 1.0 : 0.0;
1691  double currentLevel = ( int )(( bbox.xMinimum() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1692 
1693  double minY = bbox.yMinimum();
1694  double maxY = bbox.yMaximum();
1695  double step = ( maxY - minY ) / 20;
1696 
1697  bool crosses180 = false;
1698  bool crossed180 = false;
1699  if ( mCRS.geographicFlag() && ( bbox.xMinimum() > bbox.xMaximum() ) )
1700  {
1701  //handle 180 degree longitude crossover
1702  crosses180 = true;
1703  }
1704 
1705  int gridLineCount = 0;
1706  while (( currentLevel <= bbox.xMaximum() || ( crosses180 && !crossed180 ) ) && gridLineCount < MAX_GRID_LINES )
1707  {
1708  QPolygonF gridLine;
1709  double currentY = minY;
1710  bool cont = true;
1711  while ( cont )
1712  {
1713  if ( currentY > maxY )
1714  {
1715  cont = false;
1716  }
1717  try
1718  {
1719  //transform back to map crs
1720  QgsPoint mapPoint = t.transform( currentLevel, currentY );
1721  //transform back to composer coords
1722  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) );
1723  }
1724  catch ( QgsCsException & cse )
1725  {
1726  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
1727  }
1728 
1729  currentY += step;
1730  }
1731  //clip grid line to map polygon
1732  QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1733  QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1734  for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
1735  {
1736  if (( *lineIt ).size() > 0 )
1737  {
1738  lines.append( qMakePair( currentLevel, *lineIt ) );
1739  gridLineCount++;
1740  }
1741  }
1742  currentLevel += mGridIntervalX;
1743  if ( crosses180 && currentLevel > 180.0 )
1744  {
1745  currentLevel -= 360.0;
1746  crossed180 = true;
1747  }
1748  }
1749 
1750  return 0;
1751 }
1752 
1753 void QgsComposerMapGrid::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
1754  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
1755 {
1756  QList< QgsMapAnnotation > borderPositions;
1757  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1758  for ( ; it != hLines.constEnd(); ++it )
1759  {
1760  QgsMapAnnotation p1;
1761  p1.coordinate = it->first;
1762  p1.itemPosition = it->second.p1();
1763  p1.coordinateType = QgsComposerMapGrid::Latitude;
1764  borderPositions << p1;
1765 
1766  QgsMapAnnotation p2;
1767  p2.coordinate = it->first;
1768  p2.itemPosition = it->second.p2();
1769  p2.coordinateType = QgsComposerMapGrid::Latitude;
1770  borderPositions << p2;
1771  }
1772  it = vLines.constBegin();
1773  for ( ; it != vLines.constEnd(); ++it )
1774  {
1775  QgsMapAnnotation p1;
1776  p1.coordinate = it->first;
1777  p1.itemPosition = it->second.p1();
1778  p1.coordinateType = QgsComposerMapGrid::Longitude;
1779  borderPositions << p1;
1780 
1781  QgsMapAnnotation p2;
1782  p2.coordinate = it->first;
1783  p2.itemPosition = it->second.p2();
1784  p2.coordinateType = QgsComposerMapGrid::Longitude;
1785  borderPositions << p2;
1786  }
1787 
1788  QList< QgsMapAnnotation >::const_iterator bIt = borderPositions.constBegin();
1789  for ( ; bIt != borderPositions.constEnd(); ++bIt )
1790  {
1791  QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( bIt->itemPosition, bIt->coordinateType );
1792  if ( frameBorder == QgsComposerMapGrid::Left && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Left ) )
1793  {
1794  leftFrameEntries.insert( bIt->itemPosition.y(), bIt->coordinate );
1795  }
1796  else if ( frameBorder == QgsComposerMapGrid::Right && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Right ) )
1797  {
1798  rightFrameEntries.insert( bIt->itemPosition.y(), bIt->coordinate );
1799  }
1800  else if ( frameBorder == QgsComposerMapGrid::Top && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Top ) )
1801  {
1802  topFrameEntries.insert( bIt->itemPosition.x(), bIt->coordinate );
1803  }
1804  else if ( frameBorder == QgsComposerMapGrid::Bottom && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Bottom ) )
1805  {
1806  bottomFrameEntries.insert( bIt->itemPosition.x(), bIt->coordinate );
1807  }
1808  }
1809 }
1810 
1811 bool QgsComposerMapGrid::shouldShowDivisionForSide( const QgsComposerMapGrid::AnnotationCoordinate& coordinate, const QgsComposerMapGrid::BorderSide& side ) const
1812 {
1813  switch ( side )
1814  {
1816  return shouldShowDivisionForDisplayMode( coordinate, mLeftFrameDivisions );
1818  return shouldShowDivisionForDisplayMode( coordinate, mRightFrameDivisions );
1820  return shouldShowDivisionForDisplayMode( coordinate, mTopFrameDivisions );
1822  default: //prevent warnings
1823  return shouldShowDivisionForDisplayMode( coordinate, mBottomFrameDivisions );
1824  }
1825 }
1826 
1827 bool QgsComposerMapGrid::shouldShowDivisionForDisplayMode( const QgsComposerMapGrid::AnnotationCoordinate& coordinate, const QgsComposerMapGrid::DisplayMode& mode ) const
1828 {
1829  return mode == QgsComposerMapGrid::ShowAll
1830  || ( mode == QgsComposerMapGrid::LatitudeOnly && coordinate == QgsComposerMapGrid::Latitude )
1831  || ( mode == QgsComposerMapGrid::LongitudeOnly && coordinate == QgsComposerMapGrid::Longitude );
1832 }
1833 
1834 bool sortByDistance( const QPair<double, QgsComposerMapGrid::BorderSide>& a, const QPair<double, QgsComposerMapGrid::BorderSide>& b )
1835 {
1836  return a.first < b.first;
1837 }
1838 
1839 QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPointF& p, const AnnotationCoordinate coordinateType ) const
1840 {
1841  if ( !mComposerMap )
1842  {
1843  return QgsComposerMapGrid::Left;
1844  }
1845 
1846  double tolerance = qMax( mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.0, 1.0 );
1847 
1848  //check for corner coordinates
1849  if (( p.y() <= tolerance && p.x() <= tolerance ) // top left
1850  || ( p.y() <= tolerance && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //top right
1851  || ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() <= tolerance ) //bottom left
1852  || ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //bottom right
1853  )
1854  {
1855  //coordinate is in corner - fall back to preferred side for coordinate type
1856  if ( coordinateType == QgsComposerMapGrid::Latitude )
1857  {
1858  if ( p.x() <= tolerance )
1859  {
1860  return QgsComposerMapGrid::Left;
1861  }
1862  else
1863  {
1865  }
1866  }
1867  else
1868  {
1869  if ( p.y() <= tolerance )
1870  {
1871  return QgsComposerMapGrid::Top;
1872  }
1873  else
1874  {
1876  }
1877  }
1878  }
1879 
1880  //otherwise, guess side based on closest map side to point
1881  QList< QPair<double, QgsComposerMapGrid::BorderSide > > distanceToSide;
1882  distanceToSide << qMakePair( p.x(), QgsComposerMapGrid::Left );
1883  distanceToSide << qMakePair( mComposerMap->rect().width() - p.x(), QgsComposerMapGrid::Right );
1884  distanceToSide << qMakePair( p.y(), QgsComposerMapGrid::Top );
1885  distanceToSide << qMakePair( mComposerMap->rect().height() - p.y(), QgsComposerMapGrid::Bottom );
1886 
1887  qSort( distanceToSide.begin(), distanceToSide.end(), sortByDistance );
1888  return distanceToSide.at( 0 ).second;
1889 }
1890 
1892 {
1893  delete mGridLineSymbol;
1894  mGridLineSymbol = symbol;
1895 }
1896 
1898 {
1899  delete mGridMarkerSymbol;
1900  mGridMarkerSymbol = symbol;
1901 }
1902 
1904 {
1905  switch ( border )
1906  {
1908  mLeftGridAnnotationDisplay = display;
1909  break;
1911  mRightGridAnnotationDisplay = display;
1912  break;
1914  mTopGridAnnotationDisplay = display;
1915  break;
1917  mBottomGridAnnotationDisplay = display;
1918  break;
1919  default:
1920  return;
1921  }
1922 
1923  if ( mComposerMap )
1924  {
1926  mComposerMap->update();
1927  }
1928 }
1929 
1931 {
1932  switch ( border )
1933  {
1935  return mLeftGridAnnotationDisplay;
1936  break;
1938  return mRightGridAnnotationDisplay;
1939  break;
1941  return mTopGridAnnotationDisplay;
1942  break;
1944  default:
1945  return mBottomGridAnnotationDisplay;
1946  break;
1947  }
1948 }
1949 
1951 {
1952  if ( !mComposerMap )
1953  {
1954  return 0;
1955  }
1956 
1957  if ( !mEnabled || ( mGridFrameStyle == QgsComposerMapGrid::NoFrame && ( !mShowGridAnnotation ||
1958  (( mLeftGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mLeftGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) &&
1959  ( mRightGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mRightGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) &&
1960  ( mTopGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mTopGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) &&
1961  ( mBottomGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mBottomGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) ) ) ) )
1962  {
1963  return 0;
1964  }
1965 
1967  QStringList coordStrings;
1968  if ( mCRS.isValid() && mCRS != ms.destinationCrs() )
1969  {
1970  QList< QPair< double, QPolygonF > > xGridLines;
1971  QList< QPair< double, QPolygonF > > yGridLines;
1972  QgsRectangle crsRect;
1973  QgsCoordinateTransform inverseTransform;
1974  if ( crsGridParams( crsRect, inverseTransform ) != 0 )
1975  {
1976  return 0;
1977  }
1978 
1979  int xGridReturn = xGridLinesCRSTransform( crsRect, inverseTransform, xGridLines );
1980  int yGridReturn = yGridLinesCRSTransform( crsRect, inverseTransform, yGridLines );
1981  if ( xGridReturn != 0 || yGridReturn != 0 )
1982  {
1983  return 0;
1984  }
1985 
1986  QList< QPair< double, QPolygonF > >::const_iterator it = xGridLines.constBegin();
1987  for ( ; it != xGridLines.constEnd(); ++it )
1988  {
1989  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
1990  }
1991  it = yGridLines.constBegin();
1992  for ( ; it != yGridLines.constEnd(); ++it )
1993  {
1994  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
1995  }
1996  }
1997  else
1998  {
1999  QList< QPair< double, QLineF > > xLines;
2000  QList< QPair< double, QLineF > > yLines;
2001  int xGridReturn = xGridLines( xLines );
2002  int yGridReturn = yGridLines( yLines );
2003  if ( xGridReturn != 0 && yGridReturn != 0 )
2004  {
2005  return 0;
2006  }
2007 
2008  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
2009  for ( ; it != xLines.constEnd(); ++it )
2010  {
2011  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
2012  }
2013 
2014  it = yLines.constBegin();
2015  for ( ; it != yLines.constEnd(); ++it )
2016  {
2017  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
2018  }
2019  }
2020 
2021  double maxExtension = 0;
2022  double currentExtension = 0;
2023 
2024  QStringList::const_iterator coordIt = coordStrings.constBegin();
2025  for ( ; coordIt != coordStrings.constEnd(); ++coordIt )
2026  {
2027  currentExtension = qMax( QgsComposerUtils::textWidthMM( mGridAnnotationFont, *coordIt ), QgsComposerUtils::fontAscentMM( mGridAnnotationFont ) );
2028  maxExtension = qMax( maxExtension, currentExtension );
2029  }
2030 
2031  //grid frame
2032  double gridFrameDist = ( mGridFrameStyle == QgsComposerMapGrid::NoFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
2033  return maxExtension + mAnnotationFrameDistance + gridFrameDist;
2034 }
2035 
2037 {
2038  if ( unit == mGridUnit )
2039  {
2040  return;
2041  }
2042  mGridUnit = unit;
2043  mTransformDirty = true;
2044 }
2045 
2046 void QgsComposerMapGrid::setIntervalX( const double interval )
2047 {
2048  if ( interval == mGridIntervalX )
2049  {
2050  return;
2051  }
2052  mGridIntervalX = interval;
2053  mTransformDirty = true;
2054 }
2055 
2056 void QgsComposerMapGrid::setIntervalY( const double interval )
2057 {
2058  if ( interval == mGridIntervalY )
2059  {
2060  return;
2061  }
2062  mGridIntervalY = interval;
2063  mTransformDirty = true;
2064 }
2065 
2066 void QgsComposerMapGrid::setOffsetX( const double offset )
2067 {
2068  if ( offset == mGridOffsetX )
2069  {
2070  return;
2071  }
2072  mGridOffsetX = offset;
2073  mTransformDirty = true;
2074 }
2075 
2076 void QgsComposerMapGrid::setOffsetY( const double offset )
2077 {
2078  if ( offset == mGridOffsetY )
2079  {
2080  return;
2081  }
2082  mGridOffsetY = offset;
2083  mTransformDirty = true;
2084 }
2085 
2087 {
2088  if ( style == mGridStyle )
2089  {
2090  return;
2091  }
2092  mGridStyle = style;
2093  mTransformDirty = true;
2094 }
2095 
2097 {
2098  switch ( border )
2099  {
2101  mLeftGridAnnotationDirection = direction;
2102  break;
2104  mRightGridAnnotationDirection = direction;
2105  break;
2107  mTopGridAnnotationDirection = direction;
2108  break;
2110  mBottomGridAnnotationDirection = direction;
2111  break;
2112  default:
2113  return;
2114  break;
2115  }
2116 
2117  if ( mComposerMap )
2118  {
2120  mComposerMap->update();
2121  }
2122 }
2123 
2124 void QgsComposerMapGrid::setFrameSideFlags( FrameSideFlags flags )
2125 {
2126  mGridFrameSides = flags;
2127 }
2128 
2130 {
2131  if ( on )
2132  mGridFrameSides |= flag;
2133  else
2134  mGridFrameSides &= ~flag;
2135 }
2136 
2137 QgsComposerMapGrid::FrameSideFlags QgsComposerMapGrid::frameSideFlags() const
2138 {
2139  return mGridFrameSides;
2140 }
2141 
2143 {
2144  return mGridFrameSides.testFlag( flag );
2145 }
2146 
2148 {
2149  mLeftGridAnnotationDirection = direction;
2150  mRightGridAnnotationDirection = direction;
2151  mTopGridAnnotationDirection = direction;
2152  mBottomGridAnnotationDirection = direction;
2153 }
2154 
2156 {
2157  switch ( border )
2158  {
2160  mLeftGridAnnotationPosition = position;
2161  break;
2163  mRightGridAnnotationPosition = position;
2164  break;
2166  mTopGridAnnotationPosition = position;
2167  break;
2169  mBottomGridAnnotationPosition = position;
2170  break;
2171  default:
2172  return;
2173  }
2174 
2175  if ( mComposerMap )
2176  {
2178  mComposerMap->update();
2179  }
2180 }
2181 
2183 {
2184  switch ( border )
2185  {
2187  return mLeftGridAnnotationPosition;
2188  break;
2190  return mRightGridAnnotationPosition;
2191  break;
2193  return mTopGridAnnotationPosition;
2194  break;
2196  default:
2197  return mBottomGridAnnotationPosition;
2198  break;
2199  }
2200 }
2201 
2203 {
2204  if ( !mComposerMap )
2205  {
2206  return mLeftGridAnnotationDirection;
2207  }
2208 
2209  switch ( border )
2210  {
2212  return mLeftGridAnnotationDirection;
2213  break;
2215  return mRightGridAnnotationDirection;
2216  break;
2218  return mTopGridAnnotationDirection;
2219  break;
2221  default:
2222  return mBottomGridAnnotationDirection;
2223  break;
2224  }
2225 }
2226 
2228 {
2229  switch ( border )
2230  {
2232  mLeftFrameDivisions = divisions;
2233  break;
2235  mRightFrameDivisions = divisions;
2236  break;
2238  mTopFrameDivisions = divisions;
2239  break;
2241  mBottomFrameDivisions = divisions;
2242  break;
2243  default:
2244  return;
2245  }
2246 
2247  if ( mComposerMap )
2248  {
2249  mComposerMap->update();
2250  }
2251 }
2252 
2254 {
2255  switch ( border )
2256  {
2258  return mLeftFrameDivisions;
2259  break;
2261  return mRightFrameDivisions;
2262  break;
2264  return mTopFrameDivisions;
2265  break;
2267  default:
2268  return mBottomFrameDivisions;
2269  break;
2270  }
2271 }
2272 
2273 int QgsComposerMapGrid::crsGridParams( QgsRectangle& crsRect, QgsCoordinateTransform& inverseTransform ) const
2274 {
2275  if ( !mComposerMap )
2276  {
2277  return 1;
2278  }
2279 
2280  try
2281  {
2283  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
2284  QRectF mbr = mapPolygon.boundingRect();
2285  QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
2286 
2287 
2288  if ( mCRS.geographicFlag() )
2289  {
2290  //handle crossing the 180 degree longitude line
2291  QgsPoint lowerLeft( mapBoundingRect.xMinimum(), mapBoundingRect.yMinimum() );
2292  QgsPoint upperRight( mapBoundingRect.xMaximum(), mapBoundingRect.yMaximum() );
2293 
2294  lowerLeft = tr.transform( lowerLeft.x(), lowerLeft.y() );
2295  upperRight = tr.transform( upperRight.x(), upperRight.y() );
2296 
2297  if ( lowerLeft.x() > upperRight.x() )
2298  {
2299  //we've crossed the line
2300  crsRect = tr.transformBoundingBox( mapBoundingRect, QgsCoordinateTransform::ForwardTransform, true );
2301  }
2302  else
2303  {
2304  //didn't cross the line
2305  crsRect = tr.transformBoundingBox( mapBoundingRect );
2306  }
2307  }
2308  else
2309  {
2310  crsRect = tr.transformBoundingBox( mapBoundingRect );
2311  }
2312 
2313  inverseTransform.setSourceCrs( mCRS );
2314  inverseTransform.setDestCRS( mComposerMap->composition()->mapSettings().destinationCrs() );
2315  }
2316  catch ( QgsCsException & cse )
2317  {
2318  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
2319  return 1;
2320  }
2321  return 0;
2322 }
2323 
2324 QList<QPolygonF> QgsComposerMapGrid::trimLinesToMap( const QPolygonF& line, const QgsRectangle& rect )
2325 {
2326  QgsGeometry* lineGeom = QgsGeometry::fromQPolygonF( line );
2327  QgsGeometry* rectGeom = QgsGeometry::fromRect( rect );
2328 
2329  QgsGeometry* intersected = lineGeom->intersection( rectGeom );
2330  QList<QgsGeometry*> intersectedParts = intersected->asGeometryCollection();
2331 
2332  QList<QPolygonF> trimmedLines;
2333  QList<QgsGeometry*>::const_iterator geomIt = intersectedParts.constBegin();
2334  for ( ; geomIt != intersectedParts.constEnd(); ++geomIt )
2335  {
2336  trimmedLines << ( *geomIt )->asQPolygonF();
2337  }
2338 
2339  qDeleteAll( intersectedParts );
2340  intersectedParts.clear();
2341  delete intersected;
2342  delete lineGeom;
2343  delete rectGeom;
2344  return trimmedLines;
2345 }
QgsComposerMapGrid(const QString &name, QgsComposerMap *map)
Constructor for QgsComposerMapGrid.
static QgsGeometry * fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
void setStyle(const GridStyle style)
Sets the grid style, which controls how the grid is drawn over the map's contents.
void setForceVectorOutput(bool force)
void addGrid(QgsComposerMapGrid *grid)
Adds a new map grid to the stack and takes ownership of the grid.
static unsigned index
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static QgsMarkerSymbolV2 * createSimple(const QgsStringMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
void setAnnotationDirection(const AnnotationDirection direction, const BorderSide border)
Sets the direction for drawing frame annotations.
void setFrameSideFlags(const FrameSideFlags flags)
Sets flags for grid frame sides.
void setLineSymbol(QgsLineSymbolV2 *symbol)
Sets the line symbol used for drawing grid lines.
GridStyle
Grid drawing style.
QgsComposerMapGrid * grid(const QString &gridId) const
Returns a reference to a grid within the stack.
void addItem(QgsComposerMapItem *item)
Adds a new map item to the stack and takes ownership of the item.
void draw(QPainter *painter)
Draws a grid.
void setOffsetY(const double offset)
Sets the offset for grid lines in the y-direction.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:188
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
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 setSourceCrs(const QgsCoordinateReferenceSystem &theCRS)
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
FrameStyle
Style for grid frame.
QVector< QgsPoint > QgsPolyline
polyline is represented as a vector of points
Definition: qgsgeometry.h:33
QList< QgsGeometry * > asGeometryCollection() const
return contents of the geometry as a list of geometries
static void drawText(QPainter *painter, const QPointF &pos, const QString &text, const QFont &font, const QColor &color=QColor())
Draws text on a painter at a specific position, taking care of composer specific issues (calculation ...
static QColor decodeColor(QString str)
static double fontAscentMM(const QFont &font)
Calculate font ascent in millimeters, including workarounds for QT font rendering issues...
QgsPoint transform(const QgsPoint &p, TransformDirection direction=ForwardTransform) const
QPolygonF transformedMapPolygon() const
Returns extent that considers rotation and shift with mOffsetX / mOffsetY.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets grid state from a DOM document.
bool usesAdvancedEffects() const
Returns true if the item is drawn using advanced effects, such as blend modes.
AnnotationDirection
Direction of grid annotations.
QgsPoint vertexAt(int atVertex)
Returns coordinates of a vertex.
void removeGrid(const QString &gridId)
Removes a grid from the stack and deletes the corresponding QgsComposerMapGrid.
void setGridLineColor(const QColor &color)
Sets color of grid lines.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
void setAnnotationDisplay(const DisplayMode display, const BorderSide border)
Sets what types of grid annotations should be drawn for a specified side of the map frame...
AnnotationFormat
Format for displaying grid annotations.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:325
double x() const
Definition: qgspoint.h:126
An item which is drawn inside a QgsComposerMap, eg a grid or map overview.
AnnotationPosition annotationPosition(const BorderSide border) const
Gets the position for the grid annotations on a specified side of the map frame.
void setWidth(double width)
void setFrameSideFlag(const FrameSideFlag flag, bool on=true)
Sets whether the grid frame is drawn for a certain side of the map item.
static QString encodeColor(QColor color)
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.
bool testFrameSideFlag(const FrameSideFlag flag) const
Tests whether the grid frame should be drawn on a specified side of the map item. ...
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void setColor(const QColor &color)
bool sortByDistance(const QPair< double, QgsComposerMapGrid::BorderSide > &a, const QPair< double, QgsComposerMapGrid::BorderSide > &b)
void updateBoundingRect()
Updates the bounding rect of this item.
#define MAX_GRID_LINES
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:193
const QgsComposerMapGrid * constGrid(const QString &gridId) const
Returns a const reference to a grid within the stack.
bool mEnabled
True if item is to be displayed on map.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:178
DisplayMode frameDivisions(const BorderSide border) const
Gets the type of grid divisions which are used for frames on a specified side of the map...
static double fontHeightCharacterMM(const QFont &font, const QChar &character)
Calculate font height in millimeters of a single character, including workarounds for QT font renderi...
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
static QgsLineSymbolV2 * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
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.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
DisplayMode
Display settings for grid annotations and frames.
FrameSideFlags frameSideFlags() const
Returns the flags which control which sides of the map item the grid frame is drawn on...
void moveItemUp(const QString &itemId)
Moves an item up the stack, causing it to be rendered above other items.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
AnnotationPosition
Position for grid annotations.
void setUnits(const GridUnit unit)
Sets the units to use for grid measurements such as the interval and offset for grid lines...
void setPainter(QPainter *p)
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores map item state in DOM element.
GridStyle style() const
Gets the grid's style, which controls how the grid is drawn over the map's contents.
FrameSideFlag
Flags for controlling which side of the map a frame is drawn on.
An individual grid which is drawn above the map content in a QgsComposerMap.
QgsComposerMapGrid & operator[](int idx)
Returns a reference to a grid within the stack.
QgsComposerMap * mComposerMap
Associated composer map.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the CRS for the grid.
void renderPoint(const QPointF &point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void setGridLineWidth(const double width)
Sets width of grid lines.
double mapRotation(QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the composer item.
bool readXML(const QDomElement &elem, const QDomDocument &doc)
Sets the grid stack's state from a DOM document.
QgsGeometry * intersection(QgsGeometry *geometry)
Returns a geometry representing the points shared by this geometry and other.
A class to represent a point.
Definition: qgspoint.h:63
QgsComposerMapGridStack(QgsComposerMap *map)
Constructor for QgsComposerMapGridStack.
QgsComposerMapItem * item(const QString &itemId) const
Returns a reference to an item within the stack.
Object representing map window.
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...
QList< QgsComposerMapGrid * > asList() const
Returns a list of QgsComposerMapGrids contained by the stack.
virtual QString name() const
Get friendly display name for the item.
void setX(double x)
Definition: qgspoint.h:103
BorderSide
Border sides for annotations.
QString qgsDoubleToString(const double &a, const int &precision=17)
Definition: qgis.h:317
void setAnnotationPosition(const AnnotationPosition position, const BorderSide border)
Sets the position for the grid annotations on a specified side of the map frame.
void setY(double y)
Definition: qgspoint.h:111
DisplayMode annotationDisplay(const BorderSide border) const
Gets the display mode for the grid annotations on a specified side of the map frame.
QList< QgsComposerMapItem * > mItems
static double textWidthMM(const QFont &font, const QString &text)
Calculate font width in millimeters for a string, including workarounds for QT font rendering issues...
void setDestCRS(const QgsCoordinateReferenceSystem &theCRS)
QString what() const
Definition: qgsexception.h:35
bool writeXML(QDomNode &theNode, QDomDocument &theDoc) const
Contains information about the context of a rendering operation.
double maxExtension() const
Calculates the maximum distance the grid extends beyond the QgsComposerMap's item rect...
void stopRender(QgsRenderContext &context)
void setOutputSize(const QSize &size)
Set the size of the resulting map image.
QString toDegreesMinutes(int thePrecision, const bool useSuffix=true, const bool padded=false) const
Return a string representation as degrees minutes.
Definition: qgspoint.cpp:244
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.
bool hasFrame() const
Whether this item has a frame or not.
Class for storing a coordinate reference system (CRS)
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
void setMarkerSymbol(QgsMarkerSymbolV2 *symbol)
Sets the marker symbol used for drawing grid points.
void setIntervalY(const double interval)
Sets the interval between grid lines in the y-direction.
Class for doing transforms between two map coordinate systems.
static QgsGeometry * fromRect(const QgsRectangle &rect)
construct geometry from a rectangle
void setFrameDivisions(const DisplayMode divisions, const BorderSide border)
Sets what type of grid divisions should be used for frames on a specified side of the map...
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
construct geometry from a polyline
void moveGridUp(const QString &gridId)
Moves a grid up the stack, causing it to be rendered above other grids.
double y() const
Definition: qgspoint.h:134
QString toDegreesMinutesSeconds(int thePrecision, const bool useSuffix=true, const bool padded=false) const
Return a string representation as degrees minutes seconds.
Definition: qgspoint.cpp:142
static QgsSymbolV2 * loadSymbol(QDomElement &element)
Custom exception class for Coordinate Reference System related exceptions.
double maxGridExtension() const
Calculates the maximum distance grids within the stack extend beyond the QgsComposerMap's item rect...
void moveGridDown(const QString &gridId)
Moves a grid down the stack, causing it to be rendered below other grids.
void removeItems()
Clears the item stack and deletes all QgsComposerMapItems contained by the stack. ...
QPointF mapToItemCoords(const QPointF &mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset) ...
AnnotationDirection annotationDirection(const BorderSide border) const
Gets the direction for drawing frame annotations.
static QPointF pointOnLineWithDistance(const QPointF &startPoint, const QPointF &directionPoint, double distance)
Returns a point on the line from startPoint to directionPoint that is a certain distance away from th...
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:183
QgsCoordinateReferenceSystem crs() const
Retrieves the CRS for the grid.
GridUnit
Unit for grid values.
void setIntervalX(const double interval)
Sets the interval between grid lines in the x-direction.
void setOffsetX(const double offset)
Sets the offset for grid lines in the x-direction.
AnnotationCoordinate
Annotation coordinate type.
QgsComposerMap * mComposerMap
#define tr(sourceText)
bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores grid state in DOM element.