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