QGIS API Documentation  2.5.0-Master
 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"
28 
29 #include <QPainter>
30 #include <QPen>
31 
32 #define MAX_GRID_LINES 1000 //maximum number of horizontal or vertical grid lines to draw
33 
35  : mComposerMap( map )
36 {
37 
38 }
39 
41 {
42  removeGrids();
43 }
44 
46 {
47  mGrids.append( grid );
48 }
49 
50 void QgsComposerMapGridStack::removeGrid( const QString& gridId )
51 {
52  for ( int i = mGrids.size() - 1; i >= 0; --i )
53  {
54  if ( mGrids.at( i )->id() == gridId )
55  {
56  delete mGrids.takeAt( i );
57  return;
58  }
59  }
60 }
61 
62 void QgsComposerMapGridStack::moveGridUp( const QString& gridId )
63 {
64  QgsComposerMapGrid* targetGrid = grid( gridId );
65  if ( !targetGrid )
66  {
67  return;
68  }
69 
70  int index = mGrids.indexOf( targetGrid );
71  if ( index >= mGrids.size() - 1 )
72  {
73  return;
74  }
75  mGrids.swap( index, index + 1 );
76 }
77 
78 void QgsComposerMapGridStack::moveGridDown( const QString& gridId )
79 {
80  QgsComposerMapGrid* targetGrid = grid( gridId );
81  if ( !targetGrid )
82  {
83  return;
84  }
85 
86  int index = mGrids.indexOf( targetGrid );
87  if ( index < 1 )
88  {
89  return;
90  }
91  mGrids.swap( index, index - 1 );
92 }
93 
94 
95 const QgsComposerMapGrid* QgsComposerMapGridStack::constGrid( const QString& gridId ) const
96 {
97  QList< QgsComposerMapGrid* >::const_iterator it = mGrids.constBegin();
98  for ( ; it != mGrids.constEnd(); ++it )
99  {
100  if (( *it )->id() == gridId )
101  {
102  return ( *it );
103  }
104  }
105 
106  return 0;
107 }
108 
109 QgsComposerMapGrid* QgsComposerMapGridStack::grid( const QString& gridId ) const
110 {
111  QList< QgsComposerMapGrid* >::const_iterator it = mGrids.begin();
112  for ( ; it != mGrids.end(); ++it )
113  {
114  if (( *it )->id() == gridId )
115  {
116  return ( *it );
117  }
118  }
119 
120  return 0;
121 }
122 
124 {
125  if ( index < mGrids.length() )
126  {
127  return mGrids.at( index );
128  }
129 
130  return 0;
131 }
132 
133 
134 QList<QgsComposerMapGrid *> QgsComposerMapGridStack::asList() const
135 {
136  QList< QgsComposerMapGrid* > list;
137  QList< QgsComposerMapGrid* >::const_iterator it = mGrids.begin();
138  for ( ; it != mGrids.end(); ++it )
139  {
140  list.append( *it );
141  }
142  return list;
143 }
144 
146 {
147  return *mGrids[idx];
148 }
149 
150 bool QgsComposerMapGridStack::writeXML( QDomElement &elem, QDomDocument &doc ) const
151 {
152  //write grid stack
153  QList< QgsComposerMapGrid* >::const_iterator gridIt = mGrids.constBegin();
154  for ( ; gridIt != mGrids.constEnd(); ++gridIt )
155  {
156  ( *gridIt )->writeXML( elem, doc );
157  }
158 
159  return true;
160 }
161 
162 bool QgsComposerMapGridStack::readXML( const QDomElement &elem, const QDomDocument &doc )
163 {
164  removeGrids();
165 
166  //read grid stack
167  QDomNodeList mapGridNodeList = elem.elementsByTagName( "ComposerMapGrid" );
168  for ( int i = 0; i < mapGridNodeList.size(); ++i )
169  {
170  QDomElement mapGridElem = mapGridNodeList.at( i ).toElement();
171  QgsComposerMapGrid* mapGrid = new QgsComposerMapGrid( mapGridElem.attribute( "name" ), mComposerMap );
172  mapGrid->readXML( mapGridElem, doc );
173  mGrids.append( mapGrid );
174  }
175 
176  return true;
177 }
178 
179 void QgsComposerMapGridStack::drawGrids( QPainter *painter )
180 {
181  if ( !painter )
182  {
183  return;
184  }
185 
186  QList< QgsComposerMapGrid* >::const_iterator gridIt = mGrids.constBegin();
187  for ( ; gridIt != mGrids.constEnd(); ++gridIt )
188  {
189  ( *gridIt )->drawGrid( painter );
190  }
191 }
192 
194 {
195  double maxGridExtension = 0;
196 
197  QList< QgsComposerMapGrid* >::const_iterator it = mGrids.constBegin();
198  for ( ; it != mGrids.constEnd(); ++it )
199  {
200  maxGridExtension = qMax( maxGridExtension, ( *it )->maxExtension() );
201  }
202 
203  return maxGridExtension;
204 }
205 
207 {
208  QList< QgsComposerMapGrid* >::const_iterator it = mGrids.constBegin();
209  for ( ; it != mGrids.constEnd(); ++it )
210  {
211  if (( *it )->enabled() && ( *it )->blendMode() != QPainter::CompositionMode_SourceOver )
212  {
213  return true;
214  }
215  }
216  return false;
217 }
218 
220 {
221  qDeleteAll( mGrids );
222  mGrids.clear();
223 }
224 
225 
226 //
227 // QgsComposerMapGrid
228 //
229 
230 
232  mComposerMap( map ),
233  mName( name ),
234  mUuid( QUuid::createUuid().toString() ),
235  mGridEnabled( true ),
236  mGridStyle( QgsComposerMapGrid::Solid ),
237  mGridIntervalX( 0.0 ),
238  mGridIntervalY( 0.0 ),
239  mGridOffsetX( 0.0 ),
240  mGridOffsetY( 0.0 ),
241  mGridAnnotationFontColor( Qt::black ),
242  mGridAnnotationPrecision( 3 ),
243  mShowGridAnnotation( false ),
244  mLeftGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame ),
245  mRightGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame ),
246  mTopGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame ),
247  mBottomGridAnnotationPosition( QgsComposerMapGrid::OutsideMapFrame ),
248  mAnnotationFrameDistance( 1.0 ),
249  mLeftGridAnnotationDirection( QgsComposerMapGrid::Horizontal ),
250  mRightGridAnnotationDirection( QgsComposerMapGrid::Horizontal ),
251  mTopGridAnnotationDirection( QgsComposerMapGrid::Horizontal ),
252  mBottomGridAnnotationDirection( QgsComposerMapGrid::Horizontal ),
253  mGridAnnotationFormat( QgsComposerMapGrid::Decimal ),
254  mGridFrameStyle( QgsComposerMapGrid::NoFrame ),
255  mGridFrameSides( QgsComposerMapGrid::FrameLeft | QgsComposerMapGrid::FrameRight |
256  QgsComposerMapGrid::FrameTop | QgsComposerMapGrid::FrameBottom ),
257  mGridFrameWidth( 2.0 ),
258  mGridFramePenThickness( 0.3 ),
259  mGridFramePenColor( QColor( 0, 0, 0 ) ),
260  mGridFrameFillColor1( Qt::white ),
261  mGridFrameFillColor2( Qt::black ),
262  mCrossLength( 3 ),
263  mGridLineSymbol( 0 ),
264  mGridMarkerSymbol( 0 ),
265  mGridUnit( MapUnit ),
266  mBlendMode( QPainter::CompositionMode_SourceOver )
267 {
268  //get default composer font from settings
269  QSettings settings;
270  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
271  if ( !defaultFontString.isEmpty() )
272  {
273  mGridAnnotationFont.setFamily( defaultFontString );
274  }
275 
278 }
279 
281 {
282 }
283 
285 {
286  delete mGridLineSymbol;
287  delete mGridMarkerSymbol;
288 }
289 
291 {
292  delete mGridLineSymbol;
293  QgsStringMap properties;
294  properties.insert( "color", "0,0,0,255" );
295  properties.insert( "width", "0.3" );
296  properties.insert( "capstyle", "flat" );
298 }
299 
301 {
302  delete mGridMarkerSymbol;
303  QgsStringMap properties;
304  properties.insert( "name", "circle" );
305  properties.insert( "size", "2.0" );
306  properties.insert( "color", "0,0,0,255" );
308 }
309 
311 {
312  mComposerMap = map;
313 }
314 
315 void QgsComposerMapGrid::setGridLineWidth( const double width )
316 {
317  if ( mGridLineSymbol )
318  {
319  mGridLineSymbol->setWidth( width );
320  }
321 }
322 
324 {
325  if ( mGridLineSymbol )
326  {
328  }
329 }
330 
331 bool QgsComposerMapGrid::writeXML( QDomElement& elem, QDomDocument& doc ) const
332 {
333  if ( elem.isNull() )
334  {
335  return false;
336  }
337 
338  QDomElement mapGridElem = doc.createElement( "ComposerMapGrid" );
339  mapGridElem.setAttribute( "name", mName );
340  mapGridElem.setAttribute( "uuid", mUuid );
341  mapGridElem.setAttribute( "show", mGridEnabled );
342  mapGridElem.setAttribute( "gridStyle", mGridStyle );
343  mapGridElem.setAttribute( "intervalX", qgsDoubleToString( mGridIntervalX ) );
344  mapGridElem.setAttribute( "intervalY", qgsDoubleToString( mGridIntervalY ) );
345  mapGridElem.setAttribute( "offsetX", qgsDoubleToString( mGridOffsetX ) );
346  mapGridElem.setAttribute( "offsetY", qgsDoubleToString( mGridOffsetY ) );
347  mapGridElem.setAttribute( "crossLength", qgsDoubleToString( mCrossLength ) );
348 
349  QDomElement lineStyleElem = doc.createElement( "lineStyle" );
350  QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc );
351  lineStyleElem.appendChild( gridLineStyleElem );
352  mapGridElem.appendChild( lineStyleElem );
353 
354  QDomElement markerStyleElem = doc.createElement( "markerStyle" );
355  QDomElement gridMarkerStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridMarkerSymbol, doc );
356  markerStyleElem.appendChild( gridMarkerStyleElem );
357  mapGridElem.appendChild( markerStyleElem );
358 
359  mapGridElem.setAttribute( "gridFrameStyle", mGridFrameStyle );
360  mapGridElem.setAttribute( "gridFrameSideFlags", mGridFrameSides );
361  mapGridElem.setAttribute( "gridFrameWidth", qgsDoubleToString( mGridFrameWidth ) );
362  mapGridElem.setAttribute( "gridFramePenThickness", qgsDoubleToString( mGridFramePenThickness ) );
363  mapGridElem.setAttribute( "gridFramePenColor", QgsSymbolLayerV2Utils::encodeColor( mGridFramePenColor ) );
364  mapGridElem.setAttribute( "frameFillColor1", QgsSymbolLayerV2Utils::encodeColor( mGridFrameFillColor1 ) );
365  mapGridElem.setAttribute( "frameFillColor2", QgsSymbolLayerV2Utils::encodeColor( mGridFrameFillColor2 ) );
366  if ( mCRS.isValid() )
367  {
368  mCRS.writeXML( mapGridElem, doc );
369  }
370 
371  mapGridElem.setAttribute( "annotationFormat", mGridAnnotationFormat );
372  mapGridElem.setAttribute( "showAnnotation", mShowGridAnnotation );
373  mapGridElem.setAttribute( "leftAnnotationPosition", mLeftGridAnnotationPosition );
374  mapGridElem.setAttribute( "rightAnnotationPosition", mRightGridAnnotationPosition );
375  mapGridElem.setAttribute( "topAnnotationPosition", mTopGridAnnotationPosition );
376  mapGridElem.setAttribute( "bottomAnnotationPosition", mBottomGridAnnotationPosition );
377  mapGridElem.setAttribute( "leftAnnotationDirection", mLeftGridAnnotationDirection );
378  mapGridElem.setAttribute( "rightAnnotationDirection", mRightGridAnnotationDirection );
379  mapGridElem.setAttribute( "topAnnotationDirection", mTopGridAnnotationDirection );
380  mapGridElem.setAttribute( "bottomAnnotationDirection", mBottomGridAnnotationDirection );
381  mapGridElem.setAttribute( "frameAnnotationDistance", QString::number( mAnnotationFrameDistance ) );
382  mapGridElem.setAttribute( "annotationFont", mGridAnnotationFont.toString() );
383  mapGridElem.setAttribute( "annotationFontColor", QgsSymbolLayerV2Utils::encodeColor( mGridAnnotationFontColor ) );
384  mapGridElem.setAttribute( "annotationPrecision", mGridAnnotationPrecision );
385  mapGridElem.setAttribute( "unit", mGridUnit );
386  mapGridElem.setAttribute( "blendMode", mBlendMode );
387 
388  elem.appendChild( mapGridElem );
389  return true;
390 }
391 
392 bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocument& doc )
393 {
394  Q_UNUSED( doc );
395  if ( itemElem.isNull() )
396  {
397  return false;
398  }
399 
400  mName = itemElem.attribute( "name" );
401  mUuid = itemElem.attribute( "uuid" );
402 
403  //grid
404  mGridEnabled = ( itemElem.attribute( "show", "0" ) != "0" );
405  mGridStyle = QgsComposerMapGrid::GridStyle( itemElem.attribute( "gridStyle", "0" ).toInt() );
406  mGridIntervalX = itemElem.attribute( "intervalX", "0" ).toDouble();
407  mGridIntervalY = itemElem.attribute( "intervalY", "0" ).toDouble();
408  mGridOffsetX = itemElem.attribute( "offsetX", "0" ).toDouble();
409  mGridOffsetY = itemElem.attribute( "offsetY", "0" ).toDouble();
410  mCrossLength = itemElem.attribute( "crossLength", "3" ).toDouble();
411  mGridFrameStyle = ( QgsComposerMapGrid::FrameStyle )itemElem.attribute( "gridFrameStyle", "0" ).toInt();
412  mGridFrameSides = ( QgsComposerMapGrid::FrameSideFlags )itemElem.attribute( "gridFrameSideFlags", "15" ).toInt();
413  mGridFrameWidth = itemElem.attribute( "gridFrameWidth", "2.0" ).toDouble();
414  mGridFramePenThickness = itemElem.attribute( "gridFramePenThickness", "0.3" ).toDouble();
415  mGridFramePenColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "gridFramePenColor", "0,0,0" ) );
416  mGridFrameFillColor1 = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "frameFillColor1", "255,255,255,255" ) );
417  mGridFrameFillColor2 = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "frameFillColor2", "0,0,0,255" ) );
418 
419  QDomElement lineStyleElem = itemElem.firstChildElement( "lineStyle" );
420  if ( !lineStyleElem.isNull() )
421  {
422  QDomElement symbolElem = lineStyleElem.firstChildElement( "symbol" );
423  if ( !symbolElem.isNull( ) )
424  {
425  delete mGridLineSymbol;
426  mGridLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( symbolElem ) );
427  }
428  }
429  else
430  {
431  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
433  mGridLineSymbol->setWidth( itemElem.attribute( "penWidth", "0" ).toDouble() );
434  mGridLineSymbol->setColor( QColor( itemElem.attribute( "penColorRed", "0" ).toInt(),
435  itemElem.attribute( "penColorGreen", "0" ).toInt(),
436  itemElem.attribute( "penColorBlue", "0" ).toInt() ) );
437  }
438 
439  QDomElement markerStyleElem = itemElem.firstChildElement( "markerStyle" );
440  if ( !markerStyleElem.isNull() )
441  {
442  QDomElement symbolElem = markerStyleElem.firstChildElement( "symbol" );
443  if ( !symbolElem.isNull( ) )
444  {
445  delete mGridMarkerSymbol;
447  }
448  }
449 
450 
451  QDomElement crsElem = itemElem.firstChildElement( "spatialrefsys" );
452  if ( !crsElem.isNull() )
453  {
454  mCRS.readXML( const_cast<QDomElement&>( itemElem ) ); //better would be to change argument in QgsCoordinateReferenceSystem::readXML to const
455  }
456  else
457  {
459  }
460  mBlendMode = ( QPainter::CompositionMode )( itemElem.attribute( "blendMode", "0" ).toUInt() );
461 
462  //annotation
463  mShowGridAnnotation = ( itemElem.attribute( "showAnnotation", "0" ) != "0" );
464  mGridAnnotationFormat = QgsComposerMapGrid::AnnotationFormat( itemElem.attribute( "annotationFormat", "0" ).toInt() );
465  mLeftGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "leftAnnotationPosition", "0" ).toInt() );
466  mRightGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "rightAnnotationPosition", "0" ).toInt() );
467  mTopGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "topAnnotationPosition", "0" ).toInt() );
468  mBottomGridAnnotationPosition = QgsComposerMapGrid::AnnotationPosition( itemElem.attribute( "bottomAnnotationPosition", "0" ).toInt() );
469  mLeftGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "leftAnnotationDirection", "0" ).toInt() );
470  mRightGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "rightAnnotationDirection", "0" ).toInt() );
471  mTopGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "topAnnotationDirection", "0" ).toInt() );
472  mBottomGridAnnotationDirection = QgsComposerMapGrid::AnnotationDirection( itemElem.attribute( "bottomAnnotationDirection", "0" ).toInt() );
473  mAnnotationFrameDistance = itemElem.attribute( "frameAnnotationDistance", "0" ).toDouble();
474  mGridAnnotationFont.fromString( itemElem.attribute( "annotationFont", "" ) );
475  mGridAnnotationFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "annotationFontColor", "0,0,0,255" ) );
476  mGridAnnotationPrecision = itemElem.attribute( "annotationPrecision", "3" ).toInt();
477  int gridUnitInt = itemElem.attribute( "unit", QString::number( MapUnit ) ).toInt();
478  mGridUnit = ( gridUnitInt <= ( int )CM ) ? ( GridUnit )gridUnitInt : MapUnit;
479  return true;
480 }
481 
482 QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const double scale ) const
483 {
484  QTransform t = QTransform::fromScale( scale, scale );
485  return t.map( polygon );
486 }
487 
488 void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
489  QList< QPair< double, QLineF > > &verticalLines ) const
490 {
491  if ( !mComposerMap || !mGridEnabled )
492  {
493  return;
494  }
495 
496  QgsRectangle crsBoundingRect;
497  QgsCoordinateTransform inverseTr;
498  if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
499  {
500  return;
501  }
502 
503  //x grid lines
504  QList< QPair< double, QPolygonF > > xGridLines;
505  xGridLinesCRSTransform( crsBoundingRect, inverseTr, xGridLines );
506  QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin();
508  {
509  for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt )
510  {
511  drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
512  }
513  }
514 
515  //y grid lines
516  QList< QPair< double, QPolygonF > > yGridLines;
517  yGridLinesCRSTransform( crsBoundingRect, inverseTr, yGridLines );
518  QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin();
520  {
521  for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt )
522  {
523  drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
524  }
525  }
526 
527  //convert QPolygonF to QLineF to draw grid frames and annotations
528  QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = yGridLines.constBegin();
529  for ( ; yGridLineIt != yGridLines.constEnd(); ++yGridLineIt )
530  {
531  horizontalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
532  }
533  QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = xGridLines.constBegin();
534  for ( ; xGridLineIt != xGridLines.constEnd(); ++xGridLineIt )
535  {
536  verticalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
537  }
538 
539 }
540 
541 void QgsComposerMapGrid::drawGrid( QPainter* p ) const
542 {
543  if ( !mComposerMap || !mGridEnabled )
544  {
545  return;
546  }
547  QPaintDevice* thePaintDevice = p->device();
548  if ( !thePaintDevice )
549  {
550  return;
551  }
552 
553  p->save();
554  p->setCompositionMode( mBlendMode );
555  p->setRenderHint( QPainter::Antialiasing );
556 
557  QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
558  p->setClipRect( thisPaintRect );
559 
560  //setup painter scaling to dots so that raster symbology is drawn to scale
561  double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
562  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
563 
564  //setup render context
566  //context units should be in dots
567  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
569  ms.setOutputDpi( p->device()->logicalDpiX() );
571  context.setForceVectorOutput( true );
572  context.setPainter( p );
573 
574  QList< QPair< double, QLineF > > verticalLines;
575  QList< QPair< double, QLineF > > horizontalLines;
576 
577  //is grid in a different crs than map?
578  if ( mGridUnit == MapUnit && mCRS.isValid() && mCRS != ms.destinationCrs() )
579  {
580  drawGridCRSTransform( context, dotsPerMM, horizontalLines, verticalLines );
581  }
582  else
583  {
584  drawGridNoTransform( context, dotsPerMM, horizontalLines, verticalLines );
585  }
586 
587  p->restore();
588  p->setClipping( false );
589 
591  {
592  drawGridFrame( p, horizontalLines, verticalLines );
593  }
594 
595  if ( mShowGridAnnotation )
596  {
597  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
598  }
599 }
600 
601 void QgsComposerMapGrid::drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
602  QList< QPair< double, QLineF > > &verticalLines ) const
603 {
604  //get line positions
605  yGridLines( verticalLines );
606  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
607  xGridLines( horizontalLines );
608  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
609 
610  //simple approach: draw vertical lines first, then horizontal ones
612  {
613  //we need to scale line coordinates to dots, rather than mm, since the painter has already been scaled to dots
614  //this is done by multiplying each line coordinate by dotsPerMM
615  QLineF line;
616  for ( ; vIt != verticalLines.constEnd(); ++vIt )
617  {
618  line = QLineF( vIt->second.p1() * dotsPerMM, vIt->second.p2() * dotsPerMM );
619  drawGridLine( line, context );
620  }
621 
622  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
623  {
624  line = QLineF( hIt->second.p1() * dotsPerMM, hIt->second.p2() * dotsPerMM );
625  drawGridLine( line, context );
626  }
627  }
628  else if ( mGridStyle != QgsComposerMapGrid::FrameAnnotationsOnly ) //cross or markers
629  {
630  QPointF intersectionPoint, crossEnd1, crossEnd2;
631  for ( ; vIt != verticalLines.constEnd(); ++vIt )
632  {
633  //test for intersection with every horizontal line
634  hIt = horizontalLines.constBegin();
635  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
636  {
637  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
638  {
640  {
641  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
642  crossEnd1 = (( intersectionPoint - vIt->second.p1() ).manhattanLength() > 0.01 ) ?
643  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength ) : intersectionPoint;
644  crossEnd2 = (( intersectionPoint - vIt->second.p2() ).manhattanLength() > 0.01 ) ?
645  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength ) : intersectionPoint;
646  //draw line using coordinates scaled to dots
647  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
648  }
650  {
651  drawGridMarker( intersectionPoint * dotsPerMM , context );
652  }
653  }
654  }
655  }
657  {
658  //markers mode, so we have no need to process horizontal lines (we've already
659  //drawn markers on the intersections between horizontal and vertical lines)
660  return;
661  }
662 
663  hIt = horizontalLines.constBegin();
664  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
665  {
666  vIt = verticalLines.constBegin();
667  for ( ; vIt != verticalLines.constEnd(); ++vIt )
668  {
669  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
670  {
671  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
672  crossEnd1 = (( intersectionPoint - hIt->second.p1() ).manhattanLength() > 0.01 ) ?
673  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength ) : intersectionPoint;
674  crossEnd2 = (( intersectionPoint - hIt->second.p2() ).manhattanLength() > 0.01 ) ?
675  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength ) : intersectionPoint;
676  //draw line using coordinates scaled to dots
677  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
678  }
679  }
680  }
681  }
682 }
683 
684 void QgsComposerMapGrid::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
685 {
686  p->save();
687  p->setRenderHint( QPainter::Antialiasing );
688 
689  //Sort the coordinate positions for each side
690  QMap< double, double > leftGridFrame;
691  QMap< double, double > rightGridFrame;
692  QMap< double, double > topGridFrame;
693  QMap< double, double > bottomGridFrame;
694 
695  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
696 
698  {
699  drawGridFrameBorder( p, leftGridFrame, QgsComposerMapGrid::Left );
700  }
702  {
703  drawGridFrameBorder( p, rightGridFrame, QgsComposerMapGrid::Right );
704  }
706  {
707  drawGridFrameBorder( p, topGridFrame, QgsComposerMapGrid::Top );
708  }
710  {
711  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMapGrid::Bottom );
712  }
713  p->restore();
714 }
715 
716 void QgsComposerMapGrid::drawGridLine( const QLineF& line, QgsRenderContext& context ) const
717 {
718  QPolygonF poly;
719  poly << line.p1() << line.p2();
720  drawGridLine( poly, context );
721 }
722 
723 void QgsComposerMapGrid::drawGridLine( const QPolygonF& line, QgsRenderContext& context ) const
724 {
726  {
727  return;
728  }
729 
730  mGridLineSymbol->startRender( context );
731  mGridLineSymbol->renderPolyline( line, 0, context );
732  mGridLineSymbol->stopRender( context );
733 }
734 
735 void QgsComposerMapGrid::drawGridMarker( const QPointF& point, QgsRenderContext& context ) const
736 {
738  {
739  return;
740  }
741 
742  mGridMarkerSymbol->startRender( context );
743  mGridMarkerSymbol->renderPoint( point, 0, context );
744  mGridMarkerSymbol->stopRender( context );
745 }
746 
747 void QgsComposerMapGrid::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
748 {
749  if ( !mComposerMap )
750  {
751  return;
752  }
753 
754  switch ( mGridFrameStyle )
755  {
757  drawGridFrameZebraBorder( p, borderPos, border );
758  break;
762  drawGridFrameTicks( p, borderPos, border );
763  break;
764 
766  drawGridFrameLineBorder( p, border );
767  break;
768 
770  break;
771  }
772 
773 }
774 
775 void QgsComposerMapGrid::drawGridFrameZebraBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
776 {
777  if ( !mComposerMap )
778  {
779  return;
780  }
781 
782  QMap< double, double > pos = borderPos;
783 
784  double currentCoord = 0;
786  {
787  currentCoord = - mGridFrameWidth;
788  pos.insert( 0, 0 );
789  }
791  {
792  currentCoord = - mGridFrameWidth;
793  pos.insert( 0, 0 );
794  }
795  bool color1 = true;
796  double x = 0;
797  double y = 0;
798  double width = 0;
799  double height = 0;
800 
801  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
802  {
803  pos.insert( mComposerMap->rect().height(), mComposerMap->rect().height() );
805  {
806  pos.insert( mComposerMap->rect().height() + mGridFrameWidth, mComposerMap->rect().height() + mGridFrameWidth );
807  }
808  }
809  else if ( border == QgsComposerMapGrid::Top || border == QgsComposerMapGrid::Bottom )
810  {
811  pos.insert( mComposerMap->rect().width(), mComposerMap->rect().width() );
813  {
814  pos.insert( mComposerMap->rect().width() + mGridFrameWidth, mComposerMap->rect().width() + mGridFrameWidth );
815  }
816  }
817 
818  //set pen to current frame pen
819  QPen framePen = QPen( mGridFramePenColor );
820  framePen.setWidthF( mGridFramePenThickness );
821  framePen.setJoinStyle( Qt::MiterJoin );
822  p->setPen( framePen );
823 
824  QMap< double, double >::const_iterator posIt = pos.constBegin();
825  for ( ; posIt != pos.constEnd(); ++posIt )
826  {
827  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
828  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
829  {
830  height = posIt.key() - currentCoord;
831  width = mGridFrameWidth;
832  x = ( border == QgsComposerMapGrid::Left ) ? -mGridFrameWidth : mComposerMap->rect().width();
833  y = currentCoord;
834  }
835  else //top or bottom
836  {
837  height = mGridFrameWidth;
838  width = posIt.key() - currentCoord;
839  x = currentCoord;
840  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
841  }
842  p->drawRect( QRectF( x, y, width, height ) );
843  currentCoord = posIt.key();
844  color1 = !color1;
845  }
846 }
847 
848 void QgsComposerMapGrid::drawGridFrameTicks( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMapGrid::BorderSide border ) const
849 {
850  if ( !mComposerMap )
851  {
852  return;
853  }
854 
855  double x = 0;
856  double y = 0;
857  double width = 0;
858  double height = 0;
859 
860  //set pen to current frame pen
861  QPen framePen = QPen( mGridFramePenColor );
862  framePen.setWidthF( mGridFramePenThickness );
863  framePen.setCapStyle( Qt::FlatCap );
864  p->setBrush( Qt::NoBrush );
865  p->setPen( framePen );
866 
867  QMap< double, double >::const_iterator posIt = borderPos.constBegin();
868  for ( ; posIt != borderPos.constEnd(); ++posIt )
869  {
870  if ( border == QgsComposerMapGrid::Left || border == QgsComposerMapGrid::Right )
871  {
872  y = posIt.key();
873  height = 0;
875  {
876  width = mGridFrameWidth;
877  x = ( border == QgsComposerMapGrid::Left ) ? 0 : mComposerMap->rect().width() - mGridFrameWidth;
878  }
880  {
881  width = mGridFrameWidth;
882  x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width();
883  }
885  {
886  width = mGridFrameWidth * 2;
887  x = ( border == QgsComposerMapGrid::Left ) ? - mGridFrameWidth : mComposerMap->rect().width() - mGridFrameWidth;
888  }
889  }
890  else //top or bottom
891  {
892  x = posIt.key();
893  width = 0;
895  {
896  height = mGridFrameWidth;
897  y = ( border == QgsComposerMapGrid::Top ) ? 0 : mComposerMap->rect().height() - mGridFrameWidth;
898  }
900  {
901  height = mGridFrameWidth;
902  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
903  }
905  {
906  height = mGridFrameWidth * 2;
907  y = ( border == QgsComposerMapGrid::Top ) ? -mGridFrameWidth : mComposerMap->rect().height() - mGridFrameWidth;
908  }
909  }
910  p->drawLine( QLineF( x, y, x + width, y + height ) );
911  }
912 }
913 
915 {
916  if ( !mComposerMap )
917  {
918  return;
919  }
920 
921  //set pen to current frame pen
922  QPen framePen = QPen( mGridFramePenColor );
923  framePen.setWidthF( mGridFramePenThickness );
924  framePen.setCapStyle( Qt::SquareCap );
925  p->setBrush( Qt::NoBrush );
926  p->setPen( framePen );
927 
928  switch ( border )
929  {
931  p->drawLine( QLineF( 0, 0, 0, mComposerMap->rect().height() ) );
932  break;
934  p->drawLine( QLineF( mComposerMap->rect().width(), 0, mComposerMap->rect().width(), mComposerMap->rect().height() ) );
935  break;
937  p->drawLine( QLineF( 0, 0, mComposerMap->rect().width(), 0 ) );
938  break;
940  p->drawLine( QLineF( 0, mComposerMap->rect().height(), mComposerMap->rect().width(), mComposerMap->rect().height() ) );
941  break;
942  }
943 }
944 
945 void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
946 {
947  if ( !p )
948  {
949  return;
950  }
951 
952  QString currentAnnotationString;
953  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
954  for ( ; it != hLines.constEnd(); ++it )
955  {
956  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Latitude );
957  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
958  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
959  }
960 
961  it = vLines.constBegin();
962  for ( ; it != vLines.constEnd(); ++it )
963  {
964  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMapGrid::Longitude );
965  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
966  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
967  }
968 }
969 
970 void QgsComposerMapGrid::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString ) const
971 {
972  if ( !mComposerMap )
973  {
974  return;
975  }
977  double textWidth = QgsComposerUtils::textWidthMM( mGridAnnotationFont, annotationString );
978  //relevant for annotations is the height of digits
979  double textHeight = QgsComposerUtils::fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
980  double xpos = pos.x();
981  double ypos = pos.y();
982  int rotation = 0;
983 
984  double gridFrameDistance = 0;
986  {
987  gridFrameDistance = mGridFrameWidth;
988  }
990  {
991  gridFrameDistance += ( mGridFramePenThickness / 2.0 );
992  }
993 
994  if ( frameBorder == QgsComposerMapGrid::Left )
995  {
997  {
998  gridFrameDistance = 0;
999  }
1000 
1002  {
1004  {
1005  gridFrameDistance = 0;
1006  }
1008  {
1009  xpos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
1010  ypos += textWidth / 2.0;
1011  rotation = 270;
1012  }
1013  else
1014  {
1015  xpos += mAnnotationFrameDistance + gridFrameDistance;
1016  ypos += textHeight / 2.0;
1017  }
1018  }
1019  else if ( mLeftGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //Outside map frame
1020  {
1022  {
1023  gridFrameDistance = 0;
1024  }
1026  {
1027  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
1028  ypos += textWidth / 2.0;
1029  rotation = 270;
1030  }
1031  else
1032  {
1033  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1034  ypos += textHeight / 2.0;
1035  }
1036  }
1037  else
1038  {
1039  return;
1040  }
1041 
1042  }
1043  else if ( frameBorder == QgsComposerMapGrid::Right )
1044  {
1046  {
1047  gridFrameDistance = 0;
1048  }
1049 
1051  {
1053  {
1054  gridFrameDistance = 0;
1055  }
1057  {
1058  xpos -= mAnnotationFrameDistance + gridFrameDistance;
1059  ypos += textWidth / 2.0;
1060  rotation = 270;
1061  }
1062  else
1063  {
1064  xpos -= textWidth + mAnnotationFrameDistance + gridFrameDistance;
1065  ypos += textHeight / 2.0;
1066  }
1067  }
1069  {
1071  {
1072  gridFrameDistance = 0;
1073  }
1075  {
1076  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
1077  ypos += textWidth / 2.0;
1078  rotation = 270;
1079  }
1080  else //Horizontal
1081  {
1082  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1083  ypos += textHeight / 2.0;
1084  }
1085  }
1086  else
1087  {
1088  return;
1089  }
1090  }
1091  else if ( frameBorder == QgsComposerMapGrid::Bottom )
1092  {
1094  {
1095  gridFrameDistance = 0;
1096  }
1097 
1099  {
1101  {
1102  gridFrameDistance = 0;
1103  }
1105  {
1106  ypos -= mAnnotationFrameDistance + gridFrameDistance;
1107  xpos -= textWidth / 2.0;
1108  }
1109  else //Vertical
1110  {
1111  xpos += textHeight / 2.0;
1112  ypos -= mAnnotationFrameDistance + gridFrameDistance;
1113  rotation = 270;
1114  }
1115  }
1117  {
1119  {
1120  gridFrameDistance = 0;
1121  }
1123  {
1124  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
1125  xpos -= textWidth / 2.0;
1126  }
1127  else //Vertical
1128  {
1129  xpos += textHeight / 2.0;
1130  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1131  rotation = 270;
1132  }
1133  }
1134  else
1135  {
1136  return;
1137  }
1138  }
1139  else //Top
1140  {
1142  {
1143  gridFrameDistance = 0;
1144  }
1145 
1147  {
1149  {
1150  gridFrameDistance = 0;
1151  }
1153  {
1154  xpos -= textWidth / 2.0;
1155  ypos += textHeight + mAnnotationFrameDistance + gridFrameDistance;
1156  }
1157  else //Vertical
1158  {
1159  xpos += textHeight / 2.0;
1160  ypos += textWidth + mAnnotationFrameDistance + gridFrameDistance;
1161  rotation = 270;
1162  }
1163  }
1164  else if ( mTopGridAnnotationPosition == QgsComposerMapGrid::OutsideMapFrame ) //OutsideMapFrame
1165  {
1167  {
1168  gridFrameDistance = 0;
1169  }
1171  {
1172  xpos -= textWidth / 2.0;
1173  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1174  }
1175  else //Vertical
1176  {
1177  xpos += textHeight / 2.0;
1178  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1179  rotation = 270;
1180  }
1181  }
1182  else
1183  {
1184  return;
1185  }
1186  }
1187 
1188  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
1189 }
1190 
1191 void QgsComposerMapGrid::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText ) const
1192 {
1193  if ( !mComposerMap )
1194  {
1195  return;
1196  }
1197 
1198  p->save();
1199  p->translate( pos );
1200  p->rotate( rotation );
1201  QgsComposerUtils::drawText( p, QPointF( 0, 0 ), annotationText, mGridAnnotationFont, mGridAnnotationFontColor );
1202  p->restore();
1203 }
1204 
1206 {
1208  {
1209  return QString::number( value, 'f', mGridAnnotationPrecision );
1210  }
1212  {
1213  QString hemisphere;
1214  if ( coord == QgsComposerMapGrid::Longitude )
1215  {
1216  hemisphere = value < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
1217  }
1218  else
1219  {
1220  hemisphere = value < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
1221  }
1222  return QString::number( qAbs( value ), 'f', mGridAnnotationPrecision ) + hemisphere;
1223  }
1224 
1225  QgsPoint p;
1226  p.setX( coord == QgsComposerMapGrid::Longitude ? value : 0 );
1227  p.setY( coord == QgsComposerMapGrid::Longitude ? 0 : value );
1228 
1229  QString annotationString;
1231  {
1232  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
1233  }
1235  {
1236  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, false );
1237  }
1239  {
1240  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision, true, true );
1241  }
1243  {
1244  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
1245  }
1247  {
1248  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, false );
1249  }
1251  {
1252  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision, true, true );
1253  }
1254 
1255  QStringList split = annotationString.split( "," );
1256  if ( coord == QgsComposerMapGrid::Longitude )
1257  {
1258  return split.at( 0 );
1259  }
1260  else
1261  {
1262  if ( split.size() < 2 )
1263  {
1264  return "";
1265  }
1266  return split.at( 1 );
1267  }
1268 }
1269 
1270 int QgsComposerMapGrid::xGridLines( QList< QPair< double, QLineF > >& lines ) const
1271 {
1272  lines.clear();
1273  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1274  {
1275  return 1;
1276  }
1277 
1278 
1279  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
1280  QRectF mapBoundingRect = mapPolygon.boundingRect();
1281  double gridIntervalY = mGridIntervalY;
1282  double gridOffsetY = mGridOffsetY;
1283  double annotationScale = 1.0;
1284  if ( mGridUnit != MapUnit )
1285  {
1286  mapBoundingRect = mComposerMap->rect();
1287  mapPolygon = QPolygonF( mComposerMap->rect() );
1288  if ( mGridUnit == CM )
1289  {
1290  annotationScale = 0.1;
1291  gridIntervalY *= 10; gridOffsetY *= 10;
1292  }
1293  }
1294 
1295  //consider to round up to the next step in case the left boundary is > 0
1296  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1297  double currentLevel = ( int )(( mapBoundingRect.top() - gridOffsetY ) / gridIntervalY + roundCorrection ) * gridIntervalY + gridOffsetY;
1298 
1299  int gridLineCount = 0;
1300  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
1301  {
1302  //no rotation. Do it 'the easy way'
1303 
1304  double yCanvasCoord;
1305  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1306  {
1307  yCanvasCoord = mComposerMap->rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1308  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( 0, yCanvasCoord, mComposerMap->rect().width(), yCanvasCoord ) ) );
1309  currentLevel += gridIntervalY;
1310  gridLineCount++;
1311  }
1312  return 0;
1313  }
1314 
1315  //the four border lines
1316  QVector<QLineF> borderLines;
1317  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1318  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1319  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1320  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1321 
1322  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1323 
1324  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
1325  {
1326  intersectionList.clear();
1327  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1328 
1329  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1330  for ( ; it != borderLines.constEnd(); ++it )
1331  {
1332  QPointF intersectionPoint;
1333  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1334  {
1335  intersectionList.push_back( intersectionPoint );
1336  if ( intersectionList.size() >= 2 )
1337  {
1338  break; //we already have two intersections, skip further tests
1339  }
1340  }
1341  }
1342 
1343  if ( intersectionList.size() >= 2 )
1344  {
1345  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1346  gridLineCount++;
1347  }
1348  currentLevel += gridIntervalY;
1349  }
1350 
1351 
1352  return 0;
1353 }
1354 
1355 int QgsComposerMapGrid::yGridLines( QList< QPair< double, QLineF > >& lines ) const
1356 {
1357  lines.clear();
1358  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1359  {
1360  return 1;
1361  }
1362 
1363  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
1364  QRectF mapBoundingRect = mapPolygon.boundingRect();
1365  double gridIntervalX = mGridIntervalX;
1366  double gridOffsetX = mGridOffsetX;
1367  double annotationScale = 1.0;
1368  if ( mGridUnit != MapUnit )
1369  {
1370  mapBoundingRect = mComposerMap->rect();
1371  mapPolygon = QPolygonF( mComposerMap->rect() );
1372  if ( mGridUnit == CM )
1373  {
1374  annotationScale = 0.1;
1375  gridIntervalX *= 10; gridOffsetX *= 10;
1376  }
1377  }
1378 
1379  //consider to round up to the next step in case the left boundary is > 0
1380  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1381  double currentLevel = ( int )(( mapBoundingRect.left() - gridOffsetX ) / gridIntervalX + roundCorrection ) * gridIntervalX + gridOffsetX;
1382 
1383  int gridLineCount = 0;
1384  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
1385  {
1386  //no rotation. Do it 'the easy way'
1387  double xCanvasCoord;
1388  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1389  {
1390  xCanvasCoord = mComposerMap->rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1391  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( xCanvasCoord, 0, xCanvasCoord, mComposerMap->rect().height() ) ) );
1392  currentLevel += gridIntervalX;
1393  gridLineCount++;
1394  }
1395  return 0;
1396  }
1397 
1398  //the four border lines
1399  QVector<QLineF> borderLines;
1400  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1401  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1402  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1403  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1404 
1405  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1406 
1407  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1408  {
1409  intersectionList.clear();
1410  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1411 
1412  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1413  for ( ; it != borderLines.constEnd(); ++it )
1414  {
1415  QPointF intersectionPoint;
1416  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1417  {
1418  intersectionList.push_back( intersectionPoint );
1419  if ( intersectionList.size() >= 2 )
1420  {
1421  break; //we already have two intersections, skip further tests
1422  }
1423  }
1424  }
1425 
1426  if ( intersectionList.size() >= 2 )
1427  {
1428  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1429  gridLineCount++;
1430  }
1431  currentLevel += gridIntervalX;
1432  }
1433 
1434  return 0;
1435 }
1436 
1437 int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1438 {
1439  lines.clear();
1440  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1441  {
1442  return 1;
1443  }
1444 
1445  double roundCorrection = bbox.yMaximum() > 0 ? 1.0 : 0.0;
1446  double currentLevel = ( int )(( bbox.yMaximum() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1447 
1448  double minX = bbox.xMinimum();
1449  double maxX = bbox.xMaximum();
1450  double step = ( maxX - minX ) / 20;
1451 
1452  int gridLineCount = 0;
1453  while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
1454  {
1455  QPolygonF gridLine;
1456  double currentX = minX;
1457  bool cont = true;
1458  while ( cont )
1459  {
1460  if ( currentX > maxX )
1461  {
1462  cont = false;
1463  }
1464 
1465  QgsPoint mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
1466  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
1467  currentX += step;
1468  }
1469 
1470  gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1471  if ( gridLine.size() > 0 )
1472  {
1473  lines.append( qMakePair( currentLevel, gridLine ) );
1474  gridLineCount++;
1475  }
1476  currentLevel -= mGridIntervalY;
1477  }
1478 
1479  return 0;
1480 }
1481 
1482 int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1483 {
1484  lines.clear();
1485  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1486  {
1487  return 1;
1488  }
1489 
1490  double roundCorrection = bbox.xMinimum() > 0 ? 1.0 : 0.0;
1491  double currentLevel = ( int )(( bbox.xMinimum() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1492 
1493  double minY = bbox.yMinimum();
1494  double maxY = bbox.yMaximum();
1495  double step = ( maxY - minY ) / 20;
1496 
1497  int gridLineCount = 0;
1498  while ( currentLevel <= bbox.xMaximum() && gridLineCount < MAX_GRID_LINES )
1499  {
1500  QPolygonF gridLine;
1501  double currentY = minY;
1502  bool cont = true;
1503  while ( cont )
1504  {
1505  if ( currentY > maxY )
1506  {
1507  cont = false;
1508  }
1509  //transform back to map crs
1510  QgsPoint mapPoint = t.transform( currentLevel, currentY );
1511  //transform back to composer coords
1512  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) );
1513  currentY += step;
1514  }
1515  //clip grid line to map polygon
1516  gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1517  if ( gridLine.size() > 0 )
1518  {
1519  lines.append( qMakePair( currentLevel, gridLine ) );
1520  gridLineCount++;
1521  }
1522  currentLevel += mGridIntervalX;
1523  }
1524 
1525  return 0;
1526 }
1527 
1528 void QgsComposerMapGrid::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
1529  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
1530 {
1531  QList< QPair< double, QPointF > > borderPositions;
1532  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1533  for ( ; it != hLines.constEnd(); ++it )
1534  {
1535  borderPositions << qMakePair( it->first, it->second.p1() );
1536  borderPositions << qMakePair( it->first, it->second.p2() );
1537  }
1538  it = vLines.constBegin();
1539  for ( ; it != vLines.constEnd(); ++it )
1540  {
1541  borderPositions << qMakePair( it->first, it->second.p1() );
1542  borderPositions << qMakePair( it->first, it->second.p2() );
1543  }
1544 
1545  QList< QPair< double, QPointF > >::const_iterator bIt = borderPositions.constBegin();
1546  for ( ; bIt != borderPositions.constEnd(); ++bIt )
1547  {
1548  QgsComposerMapGrid::BorderSide frameBorder = borderForLineCoord( bIt->second );
1549  if ( frameBorder == QgsComposerMapGrid::Left )
1550  {
1551  leftFrameEntries.insert( bIt->second.y(), bIt->first );
1552  }
1553  else if ( frameBorder == QgsComposerMapGrid::Right )
1554  {
1555  rightFrameEntries.insert( bIt->second.y(), bIt->first );
1556  }
1557  else if ( frameBorder == QgsComposerMapGrid::Top )
1558  {
1559  topFrameEntries.insert( bIt->second.x(), bIt->first );
1560  }
1561  else //Bottom
1562  {
1563  bottomFrameEntries.insert( bIt->second.x(), bIt->first );
1564  }
1565  }
1566 }
1567 
1569 {
1570  if ( !mComposerMap )
1571  {
1572  return QgsComposerMapGrid::Left;
1573  }
1574 
1575  double framePenWidth = mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0;
1576  if ( p.y() <= framePenWidth )
1577  {
1578  return QgsComposerMapGrid::Top;
1579  }
1580  else if ( p.x() <= framePenWidth )
1581  {
1582  return QgsComposerMapGrid::Left;
1583  }
1584  else if ( p.x() >= ( mComposerMap->rect().width() - framePenWidth ) )
1585  {
1587  }
1588  else
1589  {
1591  }
1592 }
1593 
1595 {
1596  delete mGridLineSymbol;
1597  mGridLineSymbol = symbol;
1598 }
1599 
1601 {
1602  delete mGridMarkerSymbol;
1603  mGridMarkerSymbol = symbol;
1604 }
1605 
1607 {
1608  if ( !mComposerMap )
1609  {
1610  return 0;
1611  }
1612 
1615  {
1616  return 0;
1617  }
1618 
1620  QStringList coordStrings;
1621  if ( mCRS.isValid() && mCRS != ms.destinationCrs() )
1622  {
1623  QList< QPair< double, QPolygonF > > xGridLines;
1624  QList< QPair< double, QPolygonF > > yGridLines;
1625  QgsRectangle crsRect;
1626  QgsCoordinateTransform inverseTransform;
1627  if ( crsGridParams( crsRect, inverseTransform ) != 0 )
1628  {
1629  return 0;
1630  }
1631 
1632  int xGridReturn = xGridLinesCRSTransform( crsRect, inverseTransform, xGridLines );
1633  int yGridReturn = yGridLinesCRSTransform( crsRect, inverseTransform, yGridLines );
1634  if ( xGridReturn != 0 || yGridReturn != 0 )
1635  {
1636  return 0;
1637  }
1638 
1639  QList< QPair< double, QPolygonF > >::const_iterator it = xGridLines.constBegin();
1640  for ( ; it != xGridLines.constEnd(); ++it )
1641  {
1642  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
1643  }
1644  it = yGridLines.constBegin();
1645  for ( ; it != yGridLines.constEnd(); ++it )
1646  {
1647  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
1648  }
1649  }
1650  else
1651  {
1652  QList< QPair< double, QLineF > > xLines;
1653  QList< QPair< double, QLineF > > yLines;
1654  int xGridReturn = xGridLines( xLines );
1655  int yGridReturn = yGridLines( yLines );
1656  if ( xGridReturn != 0 && yGridReturn != 0 )
1657  {
1658  return 0;
1659  }
1660 
1661  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
1662  for ( ; it != xLines.constEnd(); ++it )
1663  {
1664  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Latitude ) );
1665  }
1666 
1667  it = yLines.constBegin();
1668  for ( ; it != yLines.constEnd(); ++it )
1669  {
1670  coordStrings.append( gridAnnotationString( it->first, QgsComposerMapGrid::Longitude ) );
1671  }
1672  }
1673 
1674  double maxExtension = 0;
1675  double currentExtension = 0;
1676 
1677  QStringList::const_iterator coordIt = coordStrings.constBegin();
1678  for ( ; coordIt != coordStrings.constEnd(); ++coordIt )
1679  {
1681  maxExtension = qMax( maxExtension, currentExtension );
1682  }
1683 
1684  //grid frame
1685  double gridFrameDist = ( mGridFrameStyle == QgsComposerMapGrid::NoFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
1686  return maxExtension + mAnnotationFrameDistance + gridFrameDist;
1687 }
1688 
1690 {
1691  switch ( border )
1692  {
1694  mLeftGridAnnotationDirection = direction;
1695  break;
1697  mRightGridAnnotationDirection = direction;
1698  break;
1700  mTopGridAnnotationDirection = direction;
1701  break;
1703  mBottomGridAnnotationDirection = direction;
1704  break;
1705  default:
1706  return;
1707  break;
1708  }
1709 
1710  if ( mComposerMap )
1711  {
1713  mComposerMap->update();
1714  }
1715 }
1716 
1717 void QgsComposerMapGrid::setFrameSideFlags( FrameSideFlags flags )
1718 {
1719  mGridFrameSides = flags;
1720 }
1721 
1723 {
1724  if ( on )
1725  mGridFrameSides |= flag;
1726  else
1727  mGridFrameSides &= ~flag;
1728 }
1729 
1730 QgsComposerMapGrid::FrameSideFlags QgsComposerMapGrid::frameSideFlags() const
1731 {
1732  return mGridFrameSides;
1733 }
1734 
1736 {
1737  return mGridFrameSides.testFlag( flag );
1738 }
1739 
1741 {
1742  mLeftGridAnnotationDirection = direction;
1743  mRightGridAnnotationDirection = direction;
1744  mTopGridAnnotationDirection = direction;
1745  mBottomGridAnnotationDirection = direction;
1746 }
1747 
1749 {
1750  switch ( border )
1751  {
1753  mLeftGridAnnotationPosition = position;
1754  break;
1756  mRightGridAnnotationPosition = position;
1757  break;
1759  mTopGridAnnotationPosition = position;
1760  break;
1762  mBottomGridAnnotationPosition = position;
1763  break;
1764  default:
1765  return;
1766  }
1767 
1768  if ( mComposerMap )
1769  {
1771  mComposerMap->update();
1772  }
1773 }
1774 
1776 {
1777  switch ( border )
1778  {
1781  break;
1784  break;
1787  break;
1789  default:
1791  break;
1792  }
1793 }
1794 
1796 {
1797  if ( !mComposerMap )
1798  {
1800  }
1801 
1802  switch ( border )
1803  {
1806  break;
1809  break;
1812  break;
1814  default:
1816  break;
1817  }
1818 }
1819 
1821 {
1822  if ( !mComposerMap )
1823  {
1824  return 1;
1825  }
1826 
1828  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
1829  QRectF mbr = mapPolygon.boundingRect();
1830  QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
1831  crsRect = tr.transformBoundingBox( mapBoundingRect );
1832  inverseTransform.setSourceCrs( mCRS );
1833  inverseTransform.setDestCRS( mComposerMap->composition()->mapSettings().destinationCrs() );
1834  return 0;
1835 }
1836 
1837 QPolygonF QgsComposerMapGrid::trimLineToMap( const QPolygonF& line, const QgsRectangle& rect )
1838 {
1839  QgsPolyline polyLine;
1840  QPolygonF::const_iterator lineIt = line.constBegin();
1841  for ( ; lineIt != line.constEnd(); ++lineIt )
1842  {
1843  polyLine.append( QgsPoint( lineIt->x(), lineIt->y() ) );
1844  }
1845 
1846  QgsGeometry* geom = QgsGeometry::fromPolyline( polyLine );
1847 
1848  QPolygonF clippedLine;
1849  QgsClipper::clippedLineWKB( geom->asWkb(), rect, clippedLine );
1850  delete geom;
1851  return clippedLine;
1852 }
1853 
1854 
int crsGridParams(QgsRectangle &crsRect, QgsCoordinateTransform &inverseTransform) const
Get parameters for drawing grid in CRS different to map CRS.
void drawGridFrameZebraBorder(QPainter *p, const QMap< double, double > &borderPos, BorderSide border) const
void setForceVectorOutput(bool force)
Added in QGIS v1.5.
void addGrid(QgsComposerMapGrid *grid)
Adds a new map grid to the stack and takes ownership of the grid.
AnnotationPosition mRightGridAnnotationPosition
Annotation position for right map side (inside / outside / not shown)
void drawGridFrameTicks(QPainter *p, const QMap< double, double > &borderPos, BorderSide border) const
static unsigned index
void drawGridFrame(QPainter *p, const QList< QPair< double, QLineF > > &hLines, const QList< QPair< double, QLineF > > &vLines) const
Draws the map grid.
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 drawGridFrameBorder(QPainter *p, const QMap< double, double > &borderPos, BorderSide border) const
void setAnnotationDirection(const AnnotationDirection direction, const BorderSide border)
Sets the direction for drawing frame annotations.
AnnotationPosition mBottomGridAnnotationPosition
Annotation position for bottom map side (inside / outside / not shown)
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.
QPolygonF scalePolygon(const QPolygonF &polygon, const double scale) const
double mGridOffsetX
Grid line offset in x-direction.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:194
void setOutputDpi(int dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
void setSourceCrs(const QgsCoordinateReferenceSystem &theCRS)
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
FrameStyle
Style for grid frame.
QVector< QgsPoint > QgsPolyline
polyline is represented as a vector of points
Definition: qgsgeometry.h:38
static const unsigned char * clippedLineWKB(const unsigned char *wkb, const QgsRectangle &clipExtent, QPolygonF &line)
Reads a polyline from WKB and clips it to clipExtent.
Definition: qgsclipper.cpp:39
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 ...
double mGridIntervalY
Grid line interval in y-direction (map units)
QgsLineSymbolV2 * mGridLineSymbol
static QColor decodeColor(QString str)
static double fontAscentMM(const QFont &font)
Calculate font ascent in millimeters, including workarounds for QT font rendering issues...
bool containsAdvancedEffects() const
Returns whether any grids within the stack contain advanced effects, such as blending modes...
bool mShowGridAnnotation
True if coordinate values should be drawn.
QPolygonF transformedMapPolygon() const
Returns extent that considers rotation and shift with mOffsetX / mOffsetY.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets grid state from a DOM document.
AnnotationDirection
Direction of grid annotations.
void removeGrid(const QString &gridId)
Removes a grid from the stack and deletes the corresponding QgsComposerMapGrid.
void setGridLineColor(const QColor &color)
Sets color of grid lines.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
AnnotationFormat
Format for displaying grid annotations.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
double x() const
Definition: qgspoint.h:110
AnnotationPosition annotationPosition(const BorderSide border) const
Gets the position for the grid annotations on a specified side of the map frame.
QgsComposerMap * mComposerMap
void setWidth(double width)
QList< QgsComposerMapGrid * > mGrids
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.
QPainter::CompositionMode mBlendMode
bool testFrameSideFlag(const FrameSideFlag flag) const
Tests whether the grid frame should be drawn on a specified side of the map item. ...
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void setColor(const QColor &color)
int xGridLines(QList< QPair< double, QLineF > > &lines) const
Returns the grid lines with associated coordinate value.
QColor mGridAnnotationFontColor
Font color for grid coordinates.
void updateBoundingRect()
Updates the bounding rect of this item.
#define MAX_GRID_LINES
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:199
const QgsComposerMapGrid * constGrid(const QString &gridId) const
Returns a const reference to a grid within the stack.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:184
static double fontHeightCharacterMM(const QFont &font, const QChar &character)
Calculate font height in millimeters of a single character, including workarounds for QT font renderi...
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. ...
FrameSideFlags mGridFrameSides
const QgsComposition * composition() const
Returns the composition the item is attached to.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores the state of the grid stack in a DOM node.
FrameSideFlags frameSideFlags() const
Returns the flags which control which sides of the map item the grid frame is drawn on...
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
AnnotationPosition
Position for grid annotations.
void setPainter(QPainter *p)
QgsPoint transform(const QgsPoint p, TransformDirection direction=ForwardTransform) const
FrameSideFlag
Flags for controlling which side of the map a frame is drawn on.
An individual grid which is drawn above the map content in a QgsComposerMap.
QgsComposerMapGrid & operator[](int idx)
Returns a reference to a grid within the stack.
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.
void drawGridLine(const QLineF &line, QgsRenderContext &context) const
double mapRotation(QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the composer item.
bool readXML(const QDomElement &elem, const QDomDocument &doc)
Sets the grid stack's state from a DOM document.
A class to represent a point geometry.
Definition: qgspoint.h:63
AnnotationDirection mLeftGridAnnotationDirection
Annotation direction on left side ( horizontal or vertical )
QPainter::CompositionMode mBlendMode
Blend mode for overview.
QgsComposerMapGridStack(QgsComposerMap *map)
Constructor for QgsComposerMapGridStack.
Object representing map window.
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.
void setX(double x)
Definition: qgspoint.h:87
BorderSide
Border sides for annotations.
QString qgsDoubleToString(const double &a, const int &precision=17)
Definition: qgis.h:316
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:95
void drawAnnotation(QPainter *p, const QPointF &pos, int rotation, const QString &annotationText) const
Draws a single annotation.
AnnotationDirection mRightGridAnnotationDirection
Annotation direction on right side ( horizontal or vertical )
static double textWidthMM(const QFont &font, const QString &text)
Calculate font width in millimeters for a string, including workarounds for QT font rendering issues...
void setDestCRS(const QgsCoordinateReferenceSystem &theCRS)
double mGridIntervalX
Grid line interval in x-direction (map units)
bool mGridEnabled
True if coordinate grid has to be displayed.
void drawGridNoTransform(QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines, QList< QPair< double, QLineF > > &verticalLines) const
void drawCoordinateAnnotation(QPainter *p, const QPointF &pos, QString annotationString) 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...
int yGridLines(QList< QPair< double, QLineF > > &lines) const
Returns the grid lines for the y-coordinates.
void drawGridMarker(const QPointF &point, QgsRenderContext &context) const
void stopRender(QgsRenderContext &context)
int mGridAnnotationPrecision
Digits after the dot.
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:239
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
QString gridAnnotationString(double value, AnnotationCoordinate coord) const
BorderSide borderForLineCoord(const QPointF &p) const
Returns the item border of a point (in item coordinates)
bool hasFrame() const
Whether this item has a frame or not.
Class for storing a coordinate reference system (CRS)
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
void setMarkerSymbol(QgsMarkerSymbolV2 *symbol)
Sets the marker symbol used for drawing grid points.
Class for doing transforms between two map coordinate systems.
void drawGrids(QPainter *painter)
Draws the grids from the stack on a specified painter.
double mGridOffsetY
Grid line offset in y-direction.
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
construct geometry from a polyline
void moveGridUp(const QString &gridId)
Moves a grid up the stack, causing it to be rendered above other grids.
double y() const
Definition: qgspoint.h:118
void sortGridLinesOnBorders(const QList< QPair< double, QLineF > > &hLines, const QList< QPair< double, QLineF > > &vLines, QMap< double, double > &leftFrameEntries, QMap< double, double > &rightFrameEntries, QMap< double, double > &topFrameEntries, QMap< double, double > &bottomFrameEntries) const
AnnotationPosition mTopGridAnnotationPosition
Annotation position for top map side (inside / outside / not shown)
QString toDegreesMinutesSeconds(int thePrecision, const bool useSuffix=true, const bool padded=false) const
Return a string representation as degrees minutes seconds.
Definition: qgspoint.cpp:137
static QgsSymbolV2 * loadSymbol(QDomElement &element)
AnnotationPosition mLeftGridAnnotationPosition
Annotation position for left map side (inside / outside / not shown)
QgsMarkerSymbolV2 * mGridMarkerSymbol
GridStyle mGridStyle
Solid or crosses.
double maxGridExtension() const
Calculates the maximum distance grids within the stack extend beyond the QgsComposerMap's item rect...
void removeGrids()
Clears the grid stack and deletes all QgsComposerMapGrids contained by the stack. ...
void moveGridDown(const QString &gridId)
Moves a grid up the stack, causing it to be rendered above other grids.
QPointF mapToItemCoords(const QPointF &mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset) ...
QgsComposerMap * mComposerMap
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...
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:189
AnnotationDirection mBottomGridAnnotationDirection
Annotation direction on bottom side ( horizontal or vertical )
void drawCoordinateAnnotations(QPainter *p, const QList< QPair< double, QLineF > > &hLines, const QList< QPair< double, QLineF > > &vLines) const
Draw coordinates for mGridAnnotationType Coordinate.
void setComposerMap(QgsComposerMap *map)
Sets composer map for the grid.
QFont mGridAnnotationFont
Font for grid line annotation.
GridUnit
Unit for grid values.
AnnotationCoordinate
Annotation coordinate type.
int yGridLinesCRSTransform(const QgsRectangle &bbox, const QgsCoordinateTransform &t, QList< QPair< double, QPolygonF > > &lines) const
void drawGrid(QPainter *painter) const
Draws a grid.
void drawGridCRSTransform(QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines, QList< QPair< double, QLineF > > &verticalLines) const
Draws grid if CRS is different to map CRS.
int xGridLinesCRSTransform(const QgsRectangle &bbox, const QgsCoordinateTransform &t, QList< QPair< double, QPolygonF > > &lines) const
void drawGridFrameLineBorder(QPainter *p, BorderSide border) const
QgsCoordinateReferenceSystem mCRS
static QPolygonF trimLineToMap(const QPolygonF &line, const QgsRectangle &rect)
AnnotationFormat mGridAnnotationFormat
AnnotationDirection mTopGridAnnotationDirection
Annotation direction on top side ( horizontal or vertical )
double mAnnotationFrameDistance
Distance between map frame and annotation.
#define tr(sourceText)
bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores grid state in DOM element.