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