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.
void draw(QPainter *painter) override
Draws a 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 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.
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.
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...
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores grid state in DOM element.
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.
bool readXML(const QDomElement &elem, const QDomDocument &doc) override
Sets the grid stack's state from a DOM document.
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)
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.
bool usesAdvancedEffects() const override
Returns true if the item is drawn using advanced effects, such as blend modes.
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.
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
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets grid state from a DOM document.
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
virtual bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets map item state from a DOM document.
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) ...
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores map item state in DOM element.
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)