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  QgsExpressionContext* expressionContext = createExpressionContext();
660  context.setExpressionContext( *expressionContext );
661  delete expressionContext;
662 
663  QList< QPair< double, QLineF > > verticalLines;
664  QList< QPair< double, QLineF > > horizontalLines;
665 
666  //is grid in a different crs than map?
667  if ( mGridUnit == MapUnit && mCRS.isValid() && mCRS != ms.destinationCrs() )
668  {
669  drawGridCRSTransform( context, dotsPerMM, horizontalLines, verticalLines );
670  }
671  else
672  {
673  drawGridNoTransform( context, dotsPerMM, horizontalLines, verticalLines );
674  }
675 
676  p->restore();
677 
678  p->setClipping( false );
679 #ifdef Q_OS_MAC
680  //QPainter::setClipping(false) seems to be broken on OSX (#12747). So we hack around it by
681  //setting a larger clip rect
682  p->setClipRect( mComposerMap->mapRectFromScene( mComposerMap->sceneBoundingRect() ).adjusted( -10, -10, 10, 10 ) );
683 #endif
684 
685  if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame )
686  {
687  drawGridFrame( p, horizontalLines, verticalLines );
688  }
689 
690  if ( mShowGridAnnotation )
691  {
692  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
693  }
694 }
695 
696 void QgsComposerMapGrid::drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
697  QList< QPair< double, QLineF > > &verticalLines ) const
698 {
699  //get line positions
700  yGridLines( verticalLines );
701  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
702  xGridLines( horizontalLines );
703  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
704 
705  //simple approach: draw vertical lines first, then horizontal ones
706  if ( mGridStyle == QgsComposerMapGrid::Solid )
707  {
708  //we need to scale line coordinates to dots, rather than mm, since the painter has already been scaled to dots
709  //this is done by multiplying each line coordinate by dotsPerMM
710  QLineF line;
711  for ( ; vIt != verticalLines.constEnd(); ++vIt )
712  {
713  line = QLineF( vIt->second.p1() * dotsPerMM, vIt->second.p2() * dotsPerMM );
714  drawGridLine( line, context );
715  }
716 
717  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
718  {
719  line = QLineF( hIt->second.p1() * dotsPerMM, hIt->second.p2() * dotsPerMM );
720  drawGridLine( line, context );
721  }
722  }
723  else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers
724  {
725  QPointF intersectionPoint, crossEnd1, crossEnd2;
726  for ( ; vIt != verticalLines.constEnd(); ++vIt )
727  {
728  //test for intersection with every horizontal line
729  hIt = horizontalLines.constBegin();
730  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
731  {
732  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
733  {
734  if ( mGridStyle == QgsComposerMapGrid::Cross )
735  {
736  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
737  crossEnd1 = (( intersectionPoint - vIt->second.p1() ).manhattanLength() > 0.01 ) ?
738  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength ) : intersectionPoint;
739  crossEnd2 = (( intersectionPoint - vIt->second.p2() ).manhattanLength() > 0.01 ) ?
740  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength ) : intersectionPoint;
741  //draw line using coordinates scaled to dots
742  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
743  }
744  else if ( mGridStyle == QgsComposerMapGrid::Markers )
745  {
746  drawGridMarker( intersectionPoint * dotsPerMM, context );
747  }
748  }
749  }
750  }
751  if ( mGridStyle == QgsComposerMapGrid::Markers )
752  {
753  //markers mode, so we have no need to process horizontal lines (we've already
754  //drawn markers on the intersections between horizontal and vertical lines)
755  return;
756  }
757 
758  hIt = horizontalLines.constBegin();
759  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
760  {
761  vIt = verticalLines.constBegin();
762  for ( ; vIt != verticalLines.constEnd(); ++vIt )
763  {
764  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
765  {
766  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
767  crossEnd1 = (( intersectionPoint - hIt->second.p1() ).manhattanLength() > 0.01 ) ?
768  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength ) : intersectionPoint;
769  crossEnd2 = (( intersectionPoint - hIt->second.p2() ).manhattanLength() > 0.01 ) ?
770  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength ) : intersectionPoint;
771  //draw line using coordinates scaled to dots
772  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
773  }
774  }
775  }
776  }
777 }
778 
779 void QgsComposerMapGrid::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
780 {
781  p->save();
782  p->setRenderHint( QPainter::Antialiasing );
783 
784  //Sort the coordinate positions for each side
785  QMap< double, double > leftGridFrame;
786  QMap< double, double > rightGridFrame;
787  QMap< double, double > topGridFrame;
788  QMap< double, double > bottomGridFrame;
789 
790  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
791 
793  {
794  drawGridFrameBorder( p, leftGridFrame, QgsComposerMapGrid::Left );
795  }
797  {
798  drawGridFrameBorder( p, rightGridFrame, QgsComposerMapGrid::Right );
799  }
801  {
802  drawGridFrameBorder( p, topGridFrame, QgsComposerMapGrid::Top );
803  }
805  {
806  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMapGrid::Bottom );
807  }
808  p->restore();
809 }
810 
811 void QgsComposerMapGrid::drawGridLine( const QLineF& line, QgsRenderContext& context ) const
812 {
813  QPolygonF poly;
814  poly << line.p1() << line.p2();
815  drawGridLine( poly, context );
816 }
817 
818 void QgsComposerMapGrid::drawGridLine( const QPolygonF& line, QgsRenderContext& context ) const
819 {
820  if ( !mComposerMap || !mComposerMap->composition() || !mGridLineSymbol )
821  {
822  return;
823  }
824 
825  mGridLineSymbol->startRender( context );
826  mGridLineSymbol->renderPolyline( line, 0, context );
827  mGridLineSymbol->stopRender( context );
828 }
829 
830 void QgsComposerMapGrid::drawGridMarker( const QPointF& point, QgsRenderContext& context ) const
831 {
832  if ( !mComposerMap || !mComposerMap->composition() || !mGridMarkerSymbol )
833  {
834  return;
835  }
836 
837  mGridMarkerSymbol->startRender( context );
838  mGridMarkerSymbol->renderPoint( point, 0, context );
839  mGridMarkerSymbol->stopRender( context );
840 }
841 
842 void QgsComposerMapGrid::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
843 {
844  if ( !mComposerMap )
845  {
846  return;
847  }
848 
849  switch ( mGridFrameStyle )
850  {
852  drawGridFrameZebraBorder( p, borderPos, border );
853  break;
857  drawGridFrameTicks( p, borderPos, border );
858  break;
859 
861  drawGridFrameLineBorder( p, border );
862  break;
863 
865  break;
866  }
867 
868 }
869 
870 void QgsComposerMapGrid::drawGridFrameZebraBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
871 {
872  if ( !mComposerMap )
873  {
874  return;
875  }
876 
877  QMap< double, double > pos = borderPos;
878 
879  double currentCoord = 0;
881  {
882  currentCoord = - mGridFrameWidth;
883  pos.insert( 0, 0 );
884  }
886  {
887  currentCoord = - mGridFrameWidth;
888  pos.insert( 0, 0 );
889  }
890  bool color1 = true;
891  double x = 0;
892  double y = 0;
893  double width = 0;
894  double height = 0;
895 
896  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
897  {
900  {
901  pos.insert( mComposerMap->rect().height() + mGridFrameWidth, mComposerMap->rect().height() + mGridFrameWidth );
902  }
903  }
904  else if ( border == QgsComposerMapGrid::Top || border == QgsComposerMapGrid::Bottom )
905  {
906  pos.insert( mComposerMap->rect().width(), mComposerMap->rect().width() );
908  {
909  pos.insert( mComposerMap->rect().width() + mGridFrameWidth, mComposerMap->rect().width() + mGridFrameWidth );
910  }
911  }
912 
913  //set pen to current frame pen
914  QPen framePen = QPen( mGridFramePenColor );
915  framePen.setWidthF( mGridFramePenThickness );
916  framePen.setJoinStyle( Qt::MiterJoin );
917  p->setPen( framePen );
918 
920  for ( ; posIt != pos.constEnd(); ++posIt )
921  {
922  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
923  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
924  {
925  height = posIt.key() - currentCoord;
926  width = mGridFrameWidth;
927  x = ( border == QgsComposerMapGrid::Left ) ? -mGridFrameWidth : mComposerMap->rect().width();
928  y = currentCoord;
929  }
930  else //top or bottom
931  {
932  height = mGridFrameWidth;
933  width = posIt.key() - currentCoord;
934  x = currentCoord;
935  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
936  }
937  p->drawRect( QRectF( x, y, width, height ) );
938  currentCoord = posIt.key();
939  color1 = !color1;
940  }
941 }
942 
943 void QgsComposerMapGrid::drawGridFrameTicks( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
944 {
945  if ( !mComposerMap )
946  {
947  return;
948  }
949 
950  double x = 0;
951  double y = 0;
952  double width = 0;
953  double height = 0;
954 
955  //set pen to current frame pen
956  QPen framePen = QPen( mGridFramePenColor );
957  framePen.setWidthF( mGridFramePenThickness );
958  framePen.setCapStyle( Qt::FlatCap );
959  p->setBrush( Qt::NoBrush );
960  p->setPen( framePen );
961 
963  for ( ; posIt != borderPos.constEnd(); ++posIt )
964  {
965  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
966  {
967  y = posIt.key();
968  height = 0;
969  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
970  {
971  width = mGridFrameWidth;
972  x = ( border == QgsComposerMapGrid::Left ) ? 0 : mComposerMap->rect().width() - mGridFrameWidth;
973  }
974  else if ( mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
975  {
976  width = mGridFrameWidth;
977  x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width();
978  }
979  else if ( mGridFrameStyle == QgsComposerMapGrid::InteriorExteriorTicks )
980  {
981  width = mGridFrameWidth * 2;
982  x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width() - mGridFrameWidth;
983  }
984  }
985  else //top or bottom
986  {
987  x = posIt.key();
988  width = 0;
989  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
990  {
991  height = mGridFrameWidth;
992  y = ( border == QgsComposerMapGrid::Top ) ? 0 : mComposerMap->rect().height() - mGridFrameWidth;
993  }
994  else if ( mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
995  {
996  height = mGridFrameWidth;
997  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
998  }
999  else if ( mGridFrameStyle == QgsComposerMapGrid::InteriorExteriorTicks )
1000  {
1001  height = mGridFrameWidth * 2;
1002  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height() - mGridFrameWidth;
1003  }
1004  }
1005  p->drawLine( QLineF( x, y, x + width, y + height ) );
1006  }
1007 }
1008 
1009 void QgsComposerMapGrid::drawGridFrameLineBorder( QPainter* p, QgsComposerMapGrid::BorderSide border ) const
1010 {
1011  if ( !mComposerMap )
1012  {
1013  return;
1014  }
1015 
1016  //set pen to current frame pen
1017  QPen framePen = QPen( mGridFramePenColor );
1018  framePen.setWidthF( mGridFramePenThickness );
1019  framePen.setCapStyle( Qt::SquareCap );
1020  p->setBrush( Qt::NoBrush );
1021  p->setPen( framePen );
1022 
1023  switch ( border )
1024  {
1026  p->drawLine( QLineF( 0, 0, 0, mComposerMap->rect().height() ) );
1027  break;
1030  break;
1032  p->drawLine( QLineF( 0, 0, mComposerMap->rect().width(), 0 ) );
1033  break;
1036  break;
1037  }
1038 }
1039 
1040 void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
1041 {
1042  if ( !p )
1043  {
1044  return;
1045  }
1046 
1047  QString currentAnnotationString;
1048  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1049  for ( ; it != hLines.constEnd(); ++it )
1050  {
1051  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude );
1052  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Latitude );
1053  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Latitude );
1054  }
1055 
1056  it = vLines.constBegin();
1057  for ( ; it != vLines.constEnd(); ++it )
1058  {
1059  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Longitude );
1060  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString, QgsComposerMapGrid::Longitude );
1061  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString, QgsComposerMapGrid::Longitude );
1062  }
1063 }
1064 
1065 void QgsComposerMapGrid::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString, const AnnotationCoordinate coordinateType ) const
1066 {
1067  if ( !mComposerMap )
1068  {
1069  return;
1070  }
1071  QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( pos, coordinateType );
1072  double textWidth = QgsComposerUtils::textWidthMM( mGridAnnotationFont, annotationString );
1073  //relevant for annotations is the height of digits
1074  double textHeight = QgsComposerUtils::fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
1075  double xpos = pos.x();
1076  double ypos = pos.y();
1077  int rotation = 0;
1078 
1079  double gridFrameDistance = 0;
1080  if ( mGridFrameStyle != QgsComposerMapGrid::NoFrame && mGridFrameStyle != QgsComposerMapGrid::LineBorder )
1081  {
1082  gridFrameDistance = mGridFrameWidth;
1083  }
1084  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::LineBorder )
1085  {
1086  gridFrameDistance += ( mGridFramePenThickness / 2.0 );
1087  }
1088 
1089  if ( frameBorder == QgsComposerMapGrid::Left )
1090  {
1091  if ( mLeftGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1092  ( coordinateType == Longitude && mLeftGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1093  ( coordinateType == Latitude && mLeftGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1094  {
1095  return;
1096  }
1098  {
1099  gridFrameDistance = 0;
1100  }
1101 
1102  if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1103  {
1104  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1105  {
1106  gridFrameDistance = 0;
1107  }
1108  if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::Vertical || mLeftGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1109  {
1110  xpos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
1111  ypos += textWidth / 2.0;
1112  rotation = 270;
1113  }
1114  else if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1115  {
1116  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1117  ypos -= textWidth / 2.0;
1118  rotation = 90;
1119  }
1120  else
1121  {
1122  xpos += mAnnotationFrameDistance + gridFrameDistance;
1123  ypos += textHeight / 2.0;
1124  }
1125  }
1126  else if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //Outside map frame
1127  {
1128  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1129  {
1130  gridFrameDistance = 0;
1131  }
1132  if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::Vertical || mLeftGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1133  {
1134  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
1135  ypos += textWidth / 2.0;
1136  rotation = 270;
1137  }
1138  else if ( mLeftGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1139  {
1140  xpos -= textHeight + mAnnotationFrameDistance + gridFrameDistance;
1141  ypos -= textWidth / 2.0;
1142  rotation = 90;
1143  }
1144  else
1145  {
1146  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1147  ypos += textHeight / 2.0;
1148  }
1149  }
1150  else
1151  {
1152  return;
1153  }
1154 
1155  }
1156  else if ( frameBorder == QgsComposerMapGrid::Right )
1157  {
1158  if ( mRightGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1159  ( coordinateType == Longitude && mRightGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1160  ( coordinateType == Latitude && mRightGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1161  {
1162  return;
1163  }
1165  {
1166  gridFrameDistance = 0;
1167  }
1168 
1169  if ( mRightGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1170  {
1171  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1172  {
1173  gridFrameDistance = 0;
1174  }
1175  if ( mRightGridAnnotationDirection == QgsComposerMapGrid::Vertical )
1176  {
1177  xpos -= mAnnotationFrameDistance + gridFrameDistance;
1178  ypos += textWidth / 2.0;
1179  rotation = 270;
1180  }
1181  else if ( mRightGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending || mRightGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1182  {
1183  xpos -= textHeight + mAnnotationFrameDistance + gridFrameDistance;
1184  ypos -= textWidth / 2.0;
1185  rotation = 90;
1186  }
1187  else
1188  {
1189  xpos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1190  ypos += textHeight / 2.0;
1191  }
1192  }
1193  else if ( mRightGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame )//OutsideMapFrame
1194  {
1195  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1196  {
1197  gridFrameDistance = 0;
1198  }
1199  if ( mRightGridAnnotationDirection == QgsComposerMapGrid::Vertical )
1200  {
1201  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
1202  ypos += textWidth / 2.0;
1203  rotation = 270;
1204  }
1205  else if ( mRightGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending || mRightGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1206  {
1207  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1208  ypos -= textWidth / 2.0;
1209  rotation = 90;
1210  }
1211  else //Horizontal
1212  {
1213  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1214  ypos += textHeight / 2.0;
1215  }
1216  }
1217  else
1218  {
1219  return;
1220  }
1221  }
1222  else if ( frameBorder == QgsComposerMapGrid::Bottom )
1223  {
1224  if ( mBottomGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1225  ( coordinateType == Longitude && mBottomGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1226  ( coordinateType == Latitude && mBottomGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1227  {
1228  return;
1229  }
1231  {
1232  gridFrameDistance = 0;
1233  }
1234 
1235  if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1236  {
1237  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1238  {
1239  gridFrameDistance = 0;
1240  }
1241  if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mBottomGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1242  {
1243  ypos -= mAnnotationFrameDistance + gridFrameDistance;
1244  xpos -= textWidth / 2.0;
1245  }
1246  else if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1247  {
1248  xpos -= textHeight / 2.0;
1249  ypos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1250  rotation = 90;
1251  }
1252  else //Vertical
1253  {
1254  xpos += textHeight / 2.0;
1255  ypos -= mAnnotationFrameDistance + gridFrameDistance;
1256  rotation = 270;
1257  }
1258  }
1259  else if ( mBottomGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
1260  {
1261  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1262  {
1263  gridFrameDistance = 0;
1264  }
1265  if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mBottomGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1266  {
1267  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
1268  xpos -= textWidth / 2.0;
1269  }
1270  else if ( mBottomGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1271  {
1272  xpos -= textHeight / 2.0;
1273  ypos += gridFrameDistance + mAnnotationFrameDistance;
1274  rotation = 90;
1275  }
1276  else //Vertical
1277  {
1278  xpos += textHeight / 2.0;
1279  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1280  rotation = 270;
1281  }
1282  }
1283  else
1284  {
1285  return;
1286  }
1287  }
1288  else //top
1289  {
1290  if ( mTopGridAnnotationDisplay == QgsComposerMapGrid::HideAll ||
1291  ( coordinateType == Longitude && mTopGridAnnotationDisplay == QgsComposerMapGrid::LatitudeOnly ) ||
1292  ( coordinateType == Latitude && mTopGridAnnotationDisplay == QgsComposerMapGrid::LongitudeOnly ) )
1293  {
1294  return;
1295  }
1297  {
1298  gridFrameDistance = 0;
1299  }
1300 
1301  if ( mTopGridAnnotationPosition == QgsComposerMapGrid::InsideMapFrame )
1302  {
1303  if ( mGridFrameStyle == QgsComposerMapGrid::Zebra || mGridFrameStyle == QgsComposerMapGrid::ExteriorTicks )
1304  {
1305  gridFrameDistance = 0;
1306  }
1307  if ( mTopGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mTopGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1308  {
1309  xpos -= textWidth / 2.0;
1310  ypos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
1311  }
1312  else if ( mTopGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1313  {
1314  xpos -= textHeight / 2.0;
1315  ypos += mAnnotationFrameDistance + gridFrameDistance;
1316  rotation = 90;
1317  }
1318  else //Vertical
1319  {
1320  xpos += textHeight / 2.0;
1321  ypos += textWidth + mAnnotationFrameDistance + gridFrameDistance;
1322  rotation = 270;
1323  }
1324  }
1325  else if ( mTopGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
1326  {
1327  if ( mGridFrameStyle == QgsComposerMapGrid::InteriorTicks )
1328  {
1329  gridFrameDistance = 0;
1330  }
1331  if ( mTopGridAnnotationDirection == QgsComposerMapGrid::Horizontal || mTopGridAnnotationDirection == QgsComposerMapGrid::BoundaryDirection )
1332  {
1333  xpos -= textWidth / 2.0;
1334  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1335  }
1336  else if ( mTopGridAnnotationDirection == QgsComposerMapGrid::VerticalDescending )
1337  {
1338  xpos -= textHeight / 2.0;
1339  ypos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1340  rotation = 90;
1341  }
1342  else //Vertical
1343  {
1344  xpos += textHeight / 2.0;
1345  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1346  rotation = 270;
1347  }
1348  }
1349  else
1350  {
1351  return;
1352  }
1353  }
1354 
1355  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
1356 }
1357 
1358 void QgsComposerMapGrid::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText ) const
1359 {
1360  if ( !mComposerMap )
1361  {
1362  return;
1363  }
1364 
1365  p->save();
1366  p->translate( pos );
1367  p->rotate( rotation );
1368  QgsComposerUtils::drawText( p, QPointF( 0, 0 ), annotationText, mGridAnnotationFont, mGridAnnotationFontColor );
1369  p->restore();
1370 }
1371 
1372 QString QgsComposerMapGrid::gridAnnotationString( double value, QgsComposerMapGrid::AnnotationCoordinate coord ) const
1373 {
1374  //check if we are using degrees (ie, geographic crs)
1375  bool geographic = false;
1376  if ( mCRS.isValid() && mCRS.geographicFlag() )
1377  {
1378  geographic = true;
1379  }
1380  else if ( mComposerMap && mComposerMap->composition() )
1381  {
1383  }
1384 
1385  if ( geographic && coord == QgsComposerMapGrid::Longitude &&
1386  ( mGridAnnotationFormat == QgsComposerMapGrid::Decimal || mGridAnnotationFormat == QgsComposerMapGrid::DecimalWithSuffix ) )
1387  {
1388  // wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
1389  double wrappedX = fmod( value, 360.0 );
1390  if ( wrappedX > 180.0 )
1391  {
1392  value = wrappedX - 360.0;
1393  }
1394  else if ( wrappedX < -180.0 )
1395  {
1396  value = wrappedX + 360.0;
1397  }
1398  }
1399 
1400  if ( mGridAnnotationFormat == QgsComposerMapGrid::Decimal )
1401  {
1402  return QString::number( value, 'f', mGridAnnotationPrecision );
1403  }
1404  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DecimalWithSuffix )
1405  {
1406  QString hemisphere;
1407 
1408  double coordRounded = qRound( value * pow( 10.0, mGridAnnotationPrecision ) ) / pow( 10.0, mGridAnnotationPrecision );
1409  if ( coord == QgsComposerMapGrid::Longitude )
1410  {
1411  //don't use E/W suffixes if ambiguous (eg 180 degrees)
1412  if ( !geographic || ( coordRounded != 180.0 && coordRounded != 0.0 ) )
1413  {
1414  hemisphere = value < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
1415  }
1416  }
1417  else
1418  {
1419  //don't use N/S suffixes if ambiguous (eg 0 degrees)
1420  if ( !geographic || coordRounded != 0.0 )
1421  {
1422  hemisphere = value < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
1423  }
1424  }
1425  if ( geographic )
1426  {
1427  //insert degree symbol for geographic coordinates
1428  return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + QChar( 176 ) + hemisphere;
1429  }
1430  else
1431  {
1432  return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
1433  }
1434  }
1435 
1436  QgsPoint p;
1437  p.setX( coord == QgsComposerMapGrid::Longitude ? value : 0 );
1438  p.setY( coord == QgsComposerMapGrid::Longitude ? 0 : value );
1439 
1440  QString annotationString;
1441  if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinute )
1442  {
1443  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
1444  }
1445  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteNoSuffix )
1446  {
1447  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, false );
1448  }
1449  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinutePadded )
1450  {
1451  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, true, true );
1452  }
1453  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecond )
1454  {
1455  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
1456  }
1457  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecondNoSuffix )
1458  {
1459  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, false );
1460  }
1461  else if ( mGridAnnotationFormat == QgsComposerMapGrid::DegreeMinuteSecondPadded )
1462  {
1463  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, true, true );
1464  }
1465 
1466  QStringList split = annotationString.split( "," );
1467  if ( coord == QgsComposerMapGrid::Longitude )
1468  {
1469  return split.at( 0 );
1470  }
1471  else
1472  {
1473  if ( split.size() < 2 )
1474  {
1475  return "";
1476  }
1477  return split.at( 1 );
1478  }
1479 }
1480 
1481 int QgsComposerMapGrid::xGridLines( QList< QPair< double, QLineF > >& lines ) const
1482 {
1483  lines.clear();
1484  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1485  {
1486  return 1;
1487  }
1488 
1489 
1491  QRectF mapBoundingRect = mapPolygon.boundingRect();
1492  double gridIntervalY = mGridIntervalY;
1493  double gridOffsetY = mGridOffsetY;
1494  double annotationScale = 1.0;
1495  if ( mGridUnit != MapUnit )
1496  {
1497  mapBoundingRect = mComposerMap->rect();
1498  mapPolygon = QPolygonF( mComposerMap->rect() );
1499  if ( mGridUnit == CM )
1500  {
1501  annotationScale = 0.1;
1502  gridIntervalY *= 10; gridOffsetY *= 10;
1503  }
1504  }
1505 
1506  //consider to round up to the next step in case the left boundary is > 0
1507  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1508  double currentLevel = ( int )(( mapBoundingRect.top() - gridOffsetY ) / gridIntervalY + roundCorrection ) * gridIntervalY + gridOffsetY;
1509 
1510  int gridLineCount = 0;
1511  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
1512  {
1513  //no rotation. Do it 'the easy way'
1514 
1515  double yCanvasCoord;
1516  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1517  {
1518  yCanvasCoord = mComposerMap->rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1519  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( 0, yCanvasCoord, mComposerMap->rect().width(), yCanvasCoord ) ) );
1520  currentLevel += gridIntervalY;
1521  gridLineCount++;
1522  }
1523  return 0;
1524  }
1525 
1526  //the four border lines
1527  QVector<QLineF> borderLines;
1528  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1529  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1530  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1531  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1532 
1533  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1534 
1535  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1536  {
1537  intersectionList.clear();
1538  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1539 
1540  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1541  for ( ; it != borderLines.constEnd(); ++it )
1542  {
1543  QPointF intersectionPoint;
1544  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1545  {
1546  intersectionList.push_back( intersectionPoint );
1547  if ( intersectionList.size() >= 2 )
1548  {
1549  break; //we already have two intersections, skip further tests
1550  }
1551  }
1552  }
1553 
1554  if ( intersectionList.size() >= 2 )
1555  {
1556  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1557  gridLineCount++;
1558  }
1559  currentLevel += gridIntervalY;
1560  }
1561 
1562 
1563  return 0;
1564 }
1565 
1566 int QgsComposerMapGrid::yGridLines( QList< QPair< double, QLineF > >& lines ) const
1567 {
1568  lines.clear();
1569  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1570  {
1571  return 1;
1572  }
1573 
1575  QRectF mapBoundingRect = mapPolygon.boundingRect();
1576  double gridIntervalX = mGridIntervalX;
1577  double gridOffsetX = mGridOffsetX;
1578  double annotationScale = 1.0;
1579  if ( mGridUnit != MapUnit )
1580  {
1581  mapBoundingRect = mComposerMap->rect();
1582  mapPolygon = QPolygonF( mComposerMap->rect() );
1583  if ( mGridUnit == CM )
1584  {
1585  annotationScale = 0.1;
1586  gridIntervalX *= 10; gridOffsetX *= 10;
1587  }
1588  }
1589 
1590  //consider to round up to the next step in case the left boundary is > 0
1591  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1592  double currentLevel = ( int )(( mapBoundingRect.left() - gridOffsetX ) / gridIntervalX + roundCorrection ) * gridIntervalX + gridOffsetX;
1593 
1594  int gridLineCount = 0;
1595  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
1596  {
1597  //no rotation. Do it 'the easy way'
1598  double xCanvasCoord;
1599  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1600  {
1601  xCanvasCoord = mComposerMap->rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1602  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( xCanvasCoord, 0, xCanvasCoord, mComposerMap->rect().height() ) ) );
1603  currentLevel += gridIntervalX;
1604  gridLineCount++;
1605  }
1606  return 0;
1607  }
1608 
1609  //the four border lines
1610  QVector<QLineF> borderLines;
1611  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1612  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1613  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1614  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1615 
1616  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1617 
1618  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1619  {
1620  intersectionList.clear();
1621  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1622 
1623  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1624  for ( ; it != borderLines.constEnd(); ++it )
1625  {
1626  QPointF intersectionPoint;
1627  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1628  {
1629  intersectionList.push_back( intersectionPoint );
1630  if ( intersectionList.size() >= 2 )
1631  {
1632  break; //we already have two intersections, skip further tests
1633  }
1634  }
1635  }
1636 
1637  if ( intersectionList.size() >= 2 )
1638  {
1639  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1640  gridLineCount++;
1641  }
1642  currentLevel += gridIntervalX;
1643  }
1644 
1645  return 0;
1646 }
1647 
1648 int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1649 {
1650  lines.clear();
1651  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1652  {
1653  return 1;
1654  }
1655 
1656  double roundCorrection = bbox.yMaximum() > 0 ? 1.0 : 0.0;
1657  double currentLevel = ( int )(( bbox.yMaximum() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1658 
1659  double minX = bbox.xMinimum();
1660  double maxX = bbox.xMaximum();
1661  double step = ( maxX - minX ) / 20;
1662 
1663  bool crosses180 = false;
1664  bool crossed180 = false;
1665  if ( mCRS.geographicFlag() && ( minX > maxX ) )
1666  {
1667  //handle 180 degree longitude crossover
1668  crosses180 = true;
1669  step = ( maxX + 360.0 - minX ) / 20;
1670  }
1671 
1672  if ( step == 0 )
1673  return 1;
1674 
1675  int gridLineCount = 0;
1676  while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
1677  {
1678  QPolygonF gridLine;
1679  double currentX = minX;
1680  bool cont = true;
1681  while ( cont )
1682  {
1683  if (( !crosses180 || crossed180 ) && ( currentX > maxX ) )
1684  {
1685  cont = false;
1686  }
1687 
1688  try
1689  {
1690  QgsPoint mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
1691  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
1692  }
1693  catch ( QgsCsException & cse )
1694  {
1695  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
1696  }
1697 
1698  currentX += step;
1699  if ( crosses180 && currentX > 180.0 )
1700  {
1701  currentX -= 360.0;
1702  crossed180 = true;
1703  }
1704  }
1705  crossed180 = false;
1706 
1707  QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1708  QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1709  for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
1710  {
1711  if (( *lineIt ).size() > 0 )
1712  {
1713  lines.append( qMakePair( currentLevel, *lineIt ) );
1714  gridLineCount++;
1715  }
1716  }
1717  currentLevel -= mGridIntervalY;
1718  }
1719 
1720  return 0;
1721 }
1722 
1723 int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1724 {
1725  lines.clear();
1726  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1727  {
1728  return 1;
1729  }
1730 
1731  double roundCorrection = bbox.xMinimum() > 0 ? 1.0 : 0.0;
1732  double currentLevel = ( int )(( bbox.xMinimum() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1733 
1734  double minY = bbox.yMinimum();
1735  double maxY = bbox.yMaximum();
1736  double step = ( maxY - minY ) / 20;
1737 
1738  if ( step == 0 )
1739  return 1;
1740 
1741  bool crosses180 = false;
1742  bool crossed180 = false;
1743  if ( mCRS.geographicFlag() && ( bbox.xMinimum() > bbox.xMaximum() ) )
1744  {
1745  //handle 180 degree longitude crossover
1746  crosses180 = true;
1747  }
1748 
1749  int gridLineCount = 0;
1750  while (( currentLevel <= bbox.xMaximum() || ( crosses180 && !crossed180 ) ) && gridLineCount < MAX_GRID_LINES )
1751  {
1752  QPolygonF gridLine;
1753  double currentY = minY;
1754  bool cont = true;
1755  while ( cont )
1756  {
1757  if ( currentY > maxY )
1758  {
1759  cont = false;
1760  }
1761  try
1762  {
1763  //transform back to map crs
1764  QgsPoint mapPoint = t.transform( currentLevel, currentY );
1765  //transform back to composer coords
1766  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) );
1767  }
1768  catch ( QgsCsException & cse )
1769  {
1770  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
1771  }
1772 
1773  currentY += step;
1774  }
1775  //clip grid line to map polygon
1776  QList<QPolygonF> lineSegments = trimLinesToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1777  QList<QPolygonF>::const_iterator lineIt = lineSegments.constBegin();
1778  for ( ; lineIt != lineSegments.constEnd(); ++lineIt )
1779  {
1780  if (( *lineIt ).size() > 0 )
1781  {
1782  lines.append( qMakePair( currentLevel, *lineIt ) );
1783  gridLineCount++;
1784  }
1785  }
1786  currentLevel += mGridIntervalX;
1787  if ( crosses180 && currentLevel > 180.0 )
1788  {
1789  currentLevel -= 360.0;
1790  crossed180 = true;
1791  }
1792  }
1793 
1794  return 0;
1795 }
1796 
1797 void QgsComposerMapGrid::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
1798  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
1799 {
1800  QList< QgsMapAnnotation > borderPositions;
1801  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1802  for ( ; it != hLines.constEnd(); ++it )
1803  {
1804  QgsMapAnnotation p1;
1805  p1.coordinate = it->first;
1806  p1.itemPosition = it->second.p1();
1807  p1.coordinateType = QgsComposerMapGrid::Latitude;
1808  borderPositions << p1;
1809 
1810  QgsMapAnnotation p2;
1811  p2.coordinate = it->first;
1812  p2.itemPosition = it->second.p2();
1813  p2.coordinateType = QgsComposerMapGrid::Latitude;
1814  borderPositions << p2;
1815  }
1816  it = vLines.constBegin();
1817  for ( ; it != vLines.constEnd(); ++it )
1818  {
1819  QgsMapAnnotation p1;
1820  p1.coordinate = it->first;
1821  p1.itemPosition = it->second.p1();
1822  p1.coordinateType = QgsComposerMapGrid::Longitude;
1823  borderPositions << p1;
1824 
1825  QgsMapAnnotation p2;
1826  p2.coordinate = it->first;
1827  p2.itemPosition = it->second.p2();
1828  p2.coordinateType = QgsComposerMapGrid::Longitude;
1829  borderPositions << p2;
1830  }
1831 
1832  QList< QgsMapAnnotation >::const_iterator bIt = borderPositions.constBegin();
1833  for ( ; bIt != borderPositions.constEnd(); ++bIt )
1834  {
1835  QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( bIt->itemPosition, bIt->coordinateType );
1836  if ( frameBorder == QgsComposerMapGrid::Left && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Left ) )
1837  {
1838  leftFrameEntries.insert( bIt->itemPosition.y(), bIt->coordinate );
1839  }
1840  else if ( frameBorder == QgsComposerMapGrid::Right && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Right ) )
1841  {
1842  rightFrameEntries.insert( bIt->itemPosition.y(), bIt->coordinate );
1843  }
1844  else if ( frameBorder == QgsComposerMapGrid::Top && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Top ) )
1845  {
1846  topFrameEntries.insert( bIt->itemPosition.x(), bIt->coordinate );
1847  }
1848  else if ( frameBorder == QgsComposerMapGrid::Bottom && shouldShowDivisionForSide( bIt->coordinateType, QgsComposerMapGrid::Bottom ) )
1849  {
1850  bottomFrameEntries.insert( bIt->itemPosition.x(), bIt->coordinate );
1851  }
1852  }
1853 }
1854 
1855 bool QgsComposerMapGrid::shouldShowDivisionForSide( const QgsComposerMapGrid::AnnotationCoordinate& coordinate, const QgsComposerMapGrid::BorderSide& side ) const
1856 {
1857  switch ( side )
1858  {
1860  return shouldShowDivisionForDisplayMode( coordinate, mLeftFrameDivisions );
1862  return shouldShowDivisionForDisplayMode( coordinate, mRightFrameDivisions );
1864  return shouldShowDivisionForDisplayMode( coordinate, mTopFrameDivisions );
1866  default: //prevent warnings
1867  return shouldShowDivisionForDisplayMode( coordinate, mBottomFrameDivisions );
1868  }
1869 }
1870 
1871 bool QgsComposerMapGrid::shouldShowDivisionForDisplayMode( const QgsComposerMapGrid::AnnotationCoordinate& coordinate, const QgsComposerMapGrid::DisplayMode& mode ) const
1872 {
1873  return mode == QgsComposerMapGrid::ShowAll
1874  || ( mode == QgsComposerMapGrid::LatitudeOnly && coordinate == QgsComposerMapGrid::Latitude )
1875  || ( mode == QgsComposerMapGrid::LongitudeOnly && coordinate == QgsComposerMapGrid::Longitude );
1876 }
1877 
1879 {
1880  return a.first < b.first;
1881 }
1882 
1883 QgsComposerMapGrid::BorderSide QgsComposerMapGrid::borderForLineCoord( const QPointF& p, const AnnotationCoordinate coordinateType ) const
1884 {
1885  if ( !mComposerMap )
1886  {
1887  return QgsComposerMapGrid::Left;
1888  }
1889 
1890  double tolerance = qMax( mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0.0, 1.0 );
1891 
1892  //check for corner coordinates
1893  if (( p.y() <= tolerance && p.x() <= tolerance ) // top left
1894  || ( p.y() <= tolerance && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //top right
1895  || ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() <= tolerance ) //bottom left
1896  || ( p.y() >= ( mComposerMap->rect().height() - tolerance ) && p.x() >= ( mComposerMap->rect().width() - tolerance ) ) //bottom right
1897  )
1898  {
1899  //coordinate is in corner - fall back to preferred side for coordinate type
1900  if ( coordinateType == QgsComposerMapGrid::Latitude )
1901  {
1902  if ( p.x() <= tolerance )
1903  {
1904  return QgsComposerMapGrid::Left;
1905  }
1906  else
1907  {
1909  }
1910  }
1911  else
1912  {
1913  if ( p.y() <= tolerance )
1914  {
1915  return QgsComposerMapGrid::Top;
1916  }
1917  else
1918  {
1920  }
1921  }
1922  }
1923 
1924  //otherwise, guess side based on closest map side to point
1926  distanceToSide << qMakePair( p.x(), QgsComposerMapGrid::Left );
1927  distanceToSide << qMakePair( mComposerMap->rect().width() - p.x(), QgsComposerMapGrid::Right );
1928  distanceToSide << qMakePair( p.y(), QgsComposerMapGrid::Top );
1929  distanceToSide << qMakePair( mComposerMap->rect().height() - p.y(), QgsComposerMapGrid::Bottom );
1930 
1931  qSort( distanceToSide.begin(), distanceToSide.end(), sortByDistance );
1932  return distanceToSide.at( 0 ).second;
1933 }
1934 
1936 {
1937  delete mGridLineSymbol;
1938  mGridLineSymbol = symbol;
1939 }
1940 
1942 {
1943  delete mGridMarkerSymbol;
1944  mGridMarkerSymbol = symbol;
1945 }
1946 
1948 {
1949  switch ( border )
1950  {
1952  mLeftGridAnnotationDisplay = display;
1953  break;
1955  mRightGridAnnotationDisplay = display;
1956  break;
1958  mTopGridAnnotationDisplay = display;
1959  break;
1961  mBottomGridAnnotationDisplay = display;
1962  break;
1963  default:
1964  return;
1965  }
1966 
1967  if ( mComposerMap )
1968  {
1970  mComposerMap->update();
1971  }
1972 }
1973 
1975 {
1976  switch ( border )
1977  {
1979  return mLeftGridAnnotationDisplay;
1980  break;
1982  return mRightGridAnnotationDisplay;
1983  break;
1985  return mTopGridAnnotationDisplay;
1986  break;
1988  default:
1989  return mBottomGridAnnotationDisplay;
1990  break;
1991  }
1992 }
1993 
1995 {
1996  if ( !mComposerMap )
1997  {
1998  return 0;
1999  }
2000 
2001  if ( !mEnabled || ( mGridFrameStyle == QgsComposerMapGrid::NoFrame && ( !mShowGridAnnotation ||
2002  (( mLeftGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mLeftGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) &&
2003  ( mRightGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mRightGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) &&
2004  ( mTopGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mTopGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) &&
2005  ( mBottomGridAnnotationPosition != QgsComposerMapGrid::OutsideMapFrame || mBottomGridAnnotationDisplay == QgsComposerMapGrid::HideAll ) ) ) ) )
2006  {
2007  return 0;
2008  }
2009 
2011  QStringList coordStrings;
2012  if ( mCRS.isValid() && mCRS != ms.destinationCrs() )
2013  {
2014  QList< QPair< double, QPolygonF > > xGridLines;
2015  QList< QPair< double, QPolygonF > > yGridLines;
2016  QgsRectangle crsRect;
2017  QgsCoordinateTransform inverseTransform;
2018  if ( crsGridParams( crsRect, inverseTransform ) != 0 )
2019  {
2020  return 0;
2021  }
2022 
2023  int xGridReturn = xGridLinesCRSTransform( crsRect, inverseTransform, xGridLines );
2024  int yGridReturn = yGridLinesCRSTransform( crsRect, inverseTransform, yGridLines );
2025  if ( xGridReturn != 0 || yGridReturn != 0 )
2026  {
2027  return 0;
2028  }
2029 
2030  QList< QPair< double, QPolygonF > >::const_iterator it = xGridLines.constBegin();
2031  for ( ; it != xGridLines.constEnd(); ++it )
2032  {
2033  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
2034  }
2035  it = yGridLines.constBegin();
2036  for ( ; it != yGridLines.constEnd(); ++it )
2037  {
2038  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
2039  }
2040  }
2041  else
2042  {
2045  int xGridReturn = xGridLines( xLines );
2046  int yGridReturn = yGridLines( yLines );
2047  if ( xGridReturn != 0 && yGridReturn != 0 )
2048  {
2049  return 0;
2050  }
2051 
2052  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
2053  for ( ; it != xLines.constEnd(); ++it )
2054  {
2055  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
2056  }
2057 
2058  it = yLines.constBegin();
2059  for ( ; it != yLines.constEnd(); ++it )
2060  {
2061  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
2062  }
2063  }
2064 
2065  double maxExtension = 0;
2066  double currentExtension = 0;
2067 
2068  QStringList::const_iterator coordIt = coordStrings.constBegin();
2069  for ( ; coordIt != coordStrings.constEnd(); ++coordIt )
2070  {
2071  currentExtension = qMax( QgsComposerUtils::textWidthMM( mGridAnnotationFont, *coordIt ), QgsComposerUtils::fontAscentMM( mGridAnnotationFont ) );
2072  maxExtension = qMax( maxExtension, currentExtension );
2073  }
2074 
2075  //grid frame
2076  double gridFrameDist = ( mGridFrameStyle == QgsComposerMapGrid::NoFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
2077  return maxExtension + mAnnotationFrameDistance + gridFrameDist;
2078 }
2079 
2081 {
2082  if ( unit == mGridUnit )
2083  {
2084  return;
2085  }
2086  mGridUnit = unit;
2087  mTransformDirty = true;
2088 }
2089 
2090 void QgsComposerMapGrid::setIntervalX( const double interval )
2091 {
2092  if ( interval == mGridIntervalX )
2093  {
2094  return;
2095  }
2096  mGridIntervalX = interval;
2097  mTransformDirty = true;
2098 }
2099 
2100 void QgsComposerMapGrid::setIntervalY( const double interval )
2101 {
2102  if ( interval == mGridIntervalY )
2103  {
2104  return;
2105  }
2106  mGridIntervalY = interval;
2107  mTransformDirty = true;
2108 }
2109 
2110 void QgsComposerMapGrid::setOffsetX( const double offset )
2111 {
2112  if ( offset == mGridOffsetX )
2113  {
2114  return;
2115  }
2116  mGridOffsetX = offset;
2117  mTransformDirty = true;
2118 }
2119 
2120 void QgsComposerMapGrid::setOffsetY( const double offset )
2121 {
2122  if ( offset == mGridOffsetY )
2123  {
2124  return;
2125  }
2126  mGridOffsetY = offset;
2127  mTransformDirty = true;
2128 }
2129 
2131 {
2132  if ( style == mGridStyle )
2133  {
2134  return;
2135  }
2136  mGridStyle = style;
2137  mTransformDirty = true;
2138 }
2139 
2141 {
2142  switch ( border )
2143  {
2145  mLeftGridAnnotationDirection = direction;
2146  break;
2148  mRightGridAnnotationDirection = direction;
2149  break;
2151  mTopGridAnnotationDirection = direction;
2152  break;
2154  mBottomGridAnnotationDirection = direction;
2155  break;
2156  default:
2157  return;
2158  break;
2159  }
2160 
2161  if ( mComposerMap )
2162  {
2164  mComposerMap->update();
2165  }
2166 }
2167 
2168 void QgsComposerMapGrid::setFrameSideFlags( FrameSideFlags flags )
2169 {
2170  mGridFrameSides = flags;
2171 }
2172 
2174 {
2175  if ( on )
2176  mGridFrameSides |= flag;
2177  else
2178  mGridFrameSides &= ~flag;
2179 }
2180 
2181 QgsComposerMapGrid::FrameSideFlags QgsComposerMapGrid::frameSideFlags() const
2182 {
2183  return mGridFrameSides;
2184 }
2185 
2187 {
2188  return mGridFrameSides.testFlag( flag );
2189 }
2190 
2192 {
2193  mLeftGridAnnotationDirection = direction;
2194  mRightGridAnnotationDirection = direction;
2195  mTopGridAnnotationDirection = direction;
2196  mBottomGridAnnotationDirection = direction;
2197 }
2198 
2200 {
2201  switch ( border )
2202  {
2204  mLeftGridAnnotationPosition = position;
2205  break;
2207  mRightGridAnnotationPosition = position;
2208  break;
2210  mTopGridAnnotationPosition = position;
2211  break;
2213  mBottomGridAnnotationPosition = position;
2214  break;
2215  default:
2216  return;
2217  }
2218 
2219  if ( mComposerMap )
2220  {
2222  mComposerMap->update();
2223  }
2224 }
2225 
2227 {
2228  switch ( border )
2229  {
2231  return mLeftGridAnnotationPosition;
2232  break;
2234  return mRightGridAnnotationPosition;
2235  break;
2237  return mTopGridAnnotationPosition;
2238  break;
2240  default:
2241  return mBottomGridAnnotationPosition;
2242  break;
2243  }
2244 }
2245 
2247 {
2248  if ( !mComposerMap )
2249  {
2250  return mLeftGridAnnotationDirection;
2251  }
2252 
2253  switch ( border )
2254  {
2256  return mLeftGridAnnotationDirection;
2257  break;
2259  return mRightGridAnnotationDirection;
2260  break;
2262  return mTopGridAnnotationDirection;
2263  break;
2265  default:
2266  return mBottomGridAnnotationDirection;
2267  break;
2268  }
2269 }
2270 
2272 {
2273  switch ( border )
2274  {
2276  mLeftFrameDivisions = divisions;
2277  break;
2279  mRightFrameDivisions = divisions;
2280  break;
2282  mTopFrameDivisions = divisions;
2283  break;
2285  mBottomFrameDivisions = divisions;
2286  break;
2287  default:
2288  return;
2289  }
2290 
2291  if ( mComposerMap )
2292  {
2293  mComposerMap->update();
2294  }
2295 }
2296 
2298 {
2299  switch ( border )
2300  {
2302  return mLeftFrameDivisions;
2303  break;
2305  return mRightFrameDivisions;
2306  break;
2308  return mTopFrameDivisions;
2309  break;
2311  default:
2312  return mBottomFrameDivisions;
2313  break;
2314  }
2315 }
2316 
2317 int QgsComposerMapGrid::crsGridParams( QgsRectangle& crsRect, QgsCoordinateTransform& inverseTransform ) const
2318 {
2319  if ( !mComposerMap )
2320  {
2321  return 1;
2322  }
2323 
2324  try
2325  {
2328  QRectF mbr = mapPolygon.boundingRect();
2329  QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
2330 
2331 
2332  if ( mCRS.geographicFlag() )
2333  {
2334  //handle crossing the 180 degree longitude line
2335  QgsPoint lowerLeft( mapBoundingRect.xMinimum(), mapBoundingRect.yMinimum() );
2336  QgsPoint upperRight( mapBoundingRect.xMaximum(), mapBoundingRect.yMaximum() );
2337 
2338  lowerLeft = tr.transform( lowerLeft.x(), lowerLeft.y() );
2339  upperRight = tr.transform( upperRight.x(), upperRight.y() );
2340 
2341  if ( lowerLeft.x() > upperRight.x() )
2342  {
2343  //we've crossed the line
2344  crsRect = tr.transformBoundingBox( mapBoundingRect, QgsCoordinateTransform::ForwardTransform, true );
2345  }
2346  else
2347  {
2348  //didn't cross the line
2349  crsRect = tr.transformBoundingBox( mapBoundingRect );
2350  }
2351  }
2352  else
2353  {
2354  crsRect = tr.transformBoundingBox( mapBoundingRect );
2355  }
2356 
2357  inverseTransform.setSourceCrs( mCRS );
2358  inverseTransform.setDestCRS( mComposerMap->composition()->mapSettings().destinationCrs() );
2359  }
2360  catch ( QgsCsException & cse )
2361  {
2362  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
2363  return 1;
2364  }
2365  return 0;
2366 }
2367 
2368 QList<QPolygonF> QgsComposerMapGrid::trimLinesToMap( const QPolygonF& line, const QgsRectangle& rect )
2369 {
2370  QgsGeometry* lineGeom = QgsGeometry::fromQPolygonF( line );
2371  QgsGeometry* rectGeom = QgsGeometry::fromRect( rect );
2372 
2373  QgsGeometry* intersected = lineGeom->intersection( rectGeom );
2374  QList<QgsGeometry*> intersectedParts = intersected->asGeometryCollection();
2375 
2376  QList<QPolygonF> trimmedLines;
2377  QList<QgsGeometry*>::const_iterator geomIt = intersectedParts.constBegin();
2378  for ( ; geomIt != intersectedParts.constEnd(); ++geomIt )
2379  {
2380  trimmedLines << ( *geomIt )->asQPolygonF();
2381  }
2382 
2383  qDeleteAll( intersectedParts );
2384  intersectedParts.clear();
2385  delete intersected;
2386  delete lineGeom;
2387  delete rectGeom;
2388  return trimmedLines;
2389 }
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)
virtual QgsExpressionContext * createExpressionContext() const
Creates an expression context relating to the objects's current state.
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
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
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