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