QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules 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  mName( name ),
37  mUuid( QUuid::createUuid().toString() ),
38  mGridEnabled( true ),
39  mGridStyle( QgsComposerMap::Solid ),
40  mGridIntervalX( 0.0 ),
41  mGridIntervalY( 0.0 ),
42  mGridOffsetX( 0.0 ),
43  mGridOffsetY( 0.0 ),
44  mGridAnnotationFontColor( Qt::black ),
45  mGridAnnotationPrecision( 3 ),
46  mShowGridAnnotation( false ),
47  mLeftGridAnnotationPosition( QgsComposerMap::OutsideMapFrame ),
48  mRightGridAnnotationPosition( QgsComposerMap::OutsideMapFrame ),
49  mTopGridAnnotationPosition( QgsComposerMap::OutsideMapFrame ),
50  mBottomGridAnnotationPosition( QgsComposerMap::OutsideMapFrame ),
51  mAnnotationFrameDistance( 1.0 ),
52  mLeftGridAnnotationDirection( QgsComposerMap::Horizontal ),
53  mRightGridAnnotationDirection( QgsComposerMap::Horizontal ),
54  mTopGridAnnotationDirection( QgsComposerMap::Horizontal ),
55  mBottomGridAnnotationDirection( QgsComposerMap::Horizontal ),
56  mGridAnnotationFormat( QgsComposerMap::Decimal ),
57  mGridFrameStyle( QgsComposerMap::NoGridFrame ),
58  mGridFrameWidth( 2.0 ),
59  mGridFramePenThickness( 0.5 ),
60  mGridFramePenColor( QColor( 0, 0, 0 ) ),
61  mGridFrameFillColor1( Qt::white ),
62  mGridFrameFillColor2( Qt::black ),
63  mCrossLength( 3 ),
64  mGridLineSymbol( 0 ),
65  mGridMarkerSymbol( 0 ),
66  mGridUnit( MapUnit ),
67  mBlendMode( QPainter::CompositionMode_SourceOver )
68 {
69  //get default composer font from settings
70  QSettings settings;
71  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
72  if ( !defaultFontString.isEmpty() )
73  {
74  mGridAnnotationFont.setFamily( defaultFontString );
75  }
76 
79 }
80 
82 {
83 }
84 
86 {
87  delete mGridLineSymbol;
88  delete mGridMarkerSymbol;
89 }
90 
92 {
93  delete mGridLineSymbol;
94  QgsStringMap properties;
95  properties.insert( "color", "0,0,0,255" );
96  properties.insert( "width", "0.3" );
97  properties.insert( "capstyle", "flat" );
99 }
100 
102 {
103  delete mGridMarkerSymbol;
104  QgsStringMap properties;
105  properties.insert( "name", "circle" );
106  properties.insert( "size", "2.0" );
107  properties.insert( "color", "0,0,0,255" );
109 }
110 
112 {
113  mComposerMap = map;
114 }
115 
117 {
118  if ( mGridLineSymbol )
119  {
121  }
122 }
123 
124 void QgsComposerMapGrid::setGridPenColor( const QColor& c )
125 {
126  if ( mGridLineSymbol )
127  {
129  }
130 }
131 
132 void QgsComposerMapGrid::setGridPen( const QPen& p )
133 {
134  setGridPenWidth( p.widthF() );
135  setGridPenColor( p.color() );
136 }
137 
139 {
140  QPen p;
141  if ( mGridLineSymbol )
142  {
143  p.setWidthF( mGridLineSymbol->width() );
144  p.setColor( mGridLineSymbol->color() );
145  p.setCapStyle( Qt::FlatCap );
146  }
147  return p;
148 }
149 
150 bool QgsComposerMapGrid::writeXML( QDomElement& elem, QDomDocument& doc ) const
151 {
152  if ( elem.isNull() )
153  {
154  return false;
155  }
156 
157  QDomElement mapGridElem = doc.createElement( "ComposerMapGrid" );
158  mapGridElem.setAttribute( "name", mName );
159  mapGridElem.setAttribute( "uuid", mUuid );
160  mapGridElem.setAttribute( "show", mGridEnabled );
161  mapGridElem.setAttribute( "gridStyle", mGridStyle );
162  mapGridElem.setAttribute( "intervalX", qgsDoubleToString( mGridIntervalX ) );
163  mapGridElem.setAttribute( "intervalY", qgsDoubleToString( mGridIntervalY ) );
164  mapGridElem.setAttribute( "offsetX", qgsDoubleToString( mGridOffsetX ) );
165  mapGridElem.setAttribute( "offsetY", qgsDoubleToString( mGridOffsetY ) );
166  mapGridElem.setAttribute( "crossLength", qgsDoubleToString( mCrossLength ) );
167 
168  QDomElement lineStyleElem = doc.createElement( "lineStyle" );
169  QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc );
170  lineStyleElem.appendChild( gridLineStyleElem );
171  mapGridElem.appendChild( lineStyleElem );
172 
173  QDomElement markerStyleElem = doc.createElement( "markerStyle" );
174  QDomElement gridMarkerStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridMarkerSymbol, doc );
175  markerStyleElem.appendChild( gridMarkerStyleElem );
176  mapGridElem.appendChild( markerStyleElem );
177 
178  mapGridElem.setAttribute( "gridFrameStyle", mGridFrameStyle );
179  mapGridElem.setAttribute( "gridFrameWidth", qgsDoubleToString( mGridFrameWidth ) );
180  mapGridElem.setAttribute( "gridFramePenThickness", qgsDoubleToString( mGridFramePenThickness ) );
181  mapGridElem.setAttribute( "gridFramePenColor", QgsSymbolLayerV2Utils::encodeColor( mGridFramePenColor ) );
182  mapGridElem.setAttribute( "frameFillColor1", QgsSymbolLayerV2Utils::encodeColor( mGridFrameFillColor1 ) );
183  mapGridElem.setAttribute( "frameFillColor2", QgsSymbolLayerV2Utils::encodeColor( mGridFrameFillColor2 ) );
184  if ( mCRS.isValid() )
185  {
186  mCRS.writeXML( mapGridElem, doc );
187  }
188 
189  mapGridElem.setAttribute( "annotationFormat", mGridAnnotationFormat );
190  mapGridElem.setAttribute( "showAnnotation", mShowGridAnnotation );
191  mapGridElem.setAttribute( "leftAnnotationPosition", mLeftGridAnnotationPosition );
192  mapGridElem.setAttribute( "rightAnnotationPosition", mRightGridAnnotationPosition );
193  mapGridElem.setAttribute( "topAnnotationPosition", mTopGridAnnotationPosition );
194  mapGridElem.setAttribute( "bottomAnnotationPosition", mBottomGridAnnotationPosition );
195  mapGridElem.setAttribute( "leftAnnotationDirection", mLeftGridAnnotationDirection );
196  mapGridElem.setAttribute( "rightAnnotationDirection", mRightGridAnnotationDirection );
197  mapGridElem.setAttribute( "topAnnotationDirection", mTopGridAnnotationDirection );
198  mapGridElem.setAttribute( "bottomAnnotationDirection", mBottomGridAnnotationDirection );
199  mapGridElem.setAttribute( "frameAnnotationDistance", QString::number( mAnnotationFrameDistance ) );
200  mapGridElem.setAttribute( "annotationFont", mGridAnnotationFont.toString() );
201  mapGridElem.setAttribute( "annotationFontColor", QgsSymbolLayerV2Utils::encodeColor( mGridAnnotationFontColor ) );
202  mapGridElem.setAttribute( "annotationPrecision", mGridAnnotationPrecision );
203  mapGridElem.setAttribute( "unit", mGridUnit );
204  mapGridElem.setAttribute( "blendMode", mBlendMode );
205 
206  elem.appendChild( mapGridElem );
207  return true;
208 }
209 
210 bool QgsComposerMapGrid::readXML( const QDomElement& itemElem, const QDomDocument& doc )
211 {
212  Q_UNUSED( doc );
213  if ( itemElem.isNull() )
214  {
215  return false;
216  }
217 
218  mName = itemElem.attribute( "name" );
219  mUuid = itemElem.attribute( "uuid" );
220 
221  //grid
222  mGridEnabled = ( itemElem.attribute( "show", "0" ) != "0" );
223  mGridStyle = QgsComposerMap::GridStyle( itemElem.attribute( "gridStyle", "0" ).toInt() );
224  mGridIntervalX = itemElem.attribute( "intervalX", "0" ).toDouble();
225  mGridIntervalY = itemElem.attribute( "intervalY", "0" ).toDouble();
226  mGridOffsetX = itemElem.attribute( "offsetX", "0" ).toDouble();
227  mGridOffsetY = itemElem.attribute( "offsetY", "0" ).toDouble();
228  mCrossLength = itemElem.attribute( "crossLength", "3" ).toDouble();
229  mGridFrameStyle = ( QgsComposerMap::GridFrameStyle )itemElem.attribute( "gridFrameStyle", "0" ).toInt();
230  mGridFrameWidth = itemElem.attribute( "gridFrameWidth", "2.0" ).toDouble();
231  mGridFramePenThickness = itemElem.attribute( "gridFramePenThickness", "0.5" ).toDouble();
232  mGridFramePenColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "gridFramePenColor", "0,0,0" ) );
233  mGridFrameFillColor1 = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "frameFillColor1", "255,255,255,255" ) );
234  mGridFrameFillColor2 = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "frameFillColor2", "0,0,0,255" ) );
235 
236  QDomElement lineStyleElem = itemElem.firstChildElement( "lineStyle" );
237  if ( !lineStyleElem.isNull() )
238  {
239  QDomElement symbolElem = lineStyleElem.firstChildElement( "symbol" );
240  if ( !symbolElem.isNull( ) )
241  {
242  delete mGridLineSymbol;
243  mGridLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( symbolElem ) );
244  }
245  }
246  else
247  {
248  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
250  mGridLineSymbol->setWidth( itemElem.attribute( "penWidth", "0" ).toDouble() );
251  mGridLineSymbol->setColor( QColor( itemElem.attribute( "penColorRed", "0" ).toInt(),
252  itemElem.attribute( "penColorGreen", "0" ).toInt(),
253  itemElem.attribute( "penColorBlue", "0" ).toInt() ) );
254  }
255 
256  QDomElement markerStyleElem = itemElem.firstChildElement( "markerStyle" );
257  if ( !markerStyleElem.isNull() )
258  {
259  QDomElement symbolElem = markerStyleElem.firstChildElement( "symbol" );
260  if ( !symbolElem.isNull( ) )
261  {
262  delete mGridMarkerSymbol;
264  }
265  }
266 
267 
268  QDomElement crsElem = itemElem.firstChildElement( "spatialrefsys" );
269  if ( !crsElem.isNull() )
270  {
271  mCRS.readXML( const_cast<QDomElement&>( itemElem ) ); //better would be to change argument in QgsCoordinateReferenceSystem::readXML to const
272  }
273  else
274  {
276  }
277  mBlendMode = ( QPainter::CompositionMode )( itemElem.attribute( "blendMode", "0" ).toUInt() );
278 
279  //annotation
280  mShowGridAnnotation = ( itemElem.attribute( "showAnnotation", "0" ) != "0" );
281  mGridAnnotationFormat = QgsComposerMap::GridAnnotationFormat( itemElem.attribute( "annotationFormat", "0" ).toInt() );
282  mLeftGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( itemElem.attribute( "leftAnnotationPosition", "0" ).toInt() );
283  mRightGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( itemElem.attribute( "rightAnnotationPosition", "0" ).toInt() );
284  mTopGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( itemElem.attribute( "topAnnotationPosition", "0" ).toInt() );
285  mBottomGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( itemElem.attribute( "bottomAnnotationPosition", "0" ).toInt() );
286  mLeftGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( itemElem.attribute( "leftAnnotationDirection", "0" ).toInt() );
287  mRightGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( itemElem.attribute( "rightAnnotationDirection", "0" ).toInt() );
288  mTopGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( itemElem.attribute( "topAnnotationDirection", "0" ).toInt() );
289  mBottomGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( itemElem.attribute( "bottomAnnotationDirection", "0" ).toInt() );
290  mAnnotationFrameDistance = itemElem.attribute( "frameAnnotationDistance", "0" ).toDouble();
291  mGridAnnotationFont.fromString( itemElem.attribute( "annotationFont", "" ) );
292  mGridAnnotationFontColor = QgsSymbolLayerV2Utils::decodeColor( itemElem.attribute( "annotationFontColor", "0,0,0,255" ) );
293  mGridAnnotationPrecision = itemElem.attribute( "annotationPrecision", "3" ).toInt();
294  int gridUnitInt = itemElem.attribute( "unit", QString::number( MapUnit ) ).toInt();
295  mGridUnit = ( gridUnitInt <= ( int )CM ) ? ( GridUnit )gridUnitInt : MapUnit;
296  return true;
297 }
298 
299 QPolygonF QgsComposerMapGrid::scalePolygon( const QPolygonF &polygon, const double scale ) const
300 {
301  QTransform t = QTransform::fromScale( scale, scale );
302  return t.map( polygon );
303 }
304 
305 void QgsComposerMapGrid::drawGridCRSTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
306  QList< QPair< double, QLineF > > &verticalLines ) const
307 {
308  if ( !mComposerMap || !mGridEnabled )
309  {
310  return;
311  }
312 
313  QgsRectangle crsBoundingRect;
314  QgsCoordinateTransform inverseTr;
315  if ( crsGridParams( crsBoundingRect, inverseTr ) != 0 )
316  {
317  return;
318  }
319 
320  //x grid lines
321  QList< QPair< double, QPolygonF > > xGridLines;
322  xGridLinesCRSTransform( crsBoundingRect, inverseTr, xGridLines );
323  QList< QPair< double, QPolygonF > >::const_iterator xGridIt = xGridLines.constBegin();
324  for ( ; xGridIt != xGridLines.constEnd(); ++xGridIt )
325  {
326  drawGridLine( scalePolygon( xGridIt->second, dotsPerMM ), context );
327  }
328 
329  //y grid lines
330  QList< QPair< double, QPolygonF > > yGridLines;
331  yGridLinesCRSTransform( crsBoundingRect, inverseTr, yGridLines );
332  QList< QPair< double, QPolygonF > >::const_iterator yGridIt = yGridLines.constBegin();
333  for ( ; yGridIt != yGridLines.constEnd(); ++yGridIt )
334  {
335  drawGridLine( scalePolygon( yGridIt->second, dotsPerMM ), context );
336  }
337 
338  //convert QPolygonF to QLineF to draw grid frames and annotations
339  QList< QPair< double, QPolygonF > >::const_iterator yGridLineIt = yGridLines.constBegin();
340  for ( ; yGridLineIt != yGridLines.constEnd(); ++yGridLineIt )
341  {
342  horizontalLines.push_back( qMakePair( yGridLineIt->first, QLineF( yGridLineIt->second.first(), yGridLineIt->second.last() ) ) );
343  }
344  QList< QPair< double, QPolygonF > >::const_iterator xGridLineIt = xGridLines.constBegin();
345  for ( ; xGridLineIt != xGridLines.constEnd(); ++xGridLineIt )
346  {
347  verticalLines.push_back( qMakePair( xGridLineIt->first, QLineF( xGridLineIt->second.first(), xGridLineIt->second.last() ) ) );
348  }
349 
350 }
351 
352 void QgsComposerMapGrid::drawGrid( QPainter* p ) const
353 {
354  if ( !mComposerMap || !mGridEnabled )
355  {
356  return;
357  }
358  QPaintDevice* thePaintDevice = p->device();
359  if ( !thePaintDevice )
360  {
361  return;
362  }
363 
364  p->save();
365  p->setCompositionMode( mBlendMode );
366  p->setRenderHint( QPainter::Antialiasing );
367 
368  QRectF thisPaintRect = QRectF( 0, 0, mComposerMap->rect().width(), mComposerMap->rect().height() );
369  p->setClipRect( thisPaintRect );
370 
371  //setup painter scaling to dots so that raster symbology is drawn to scale
372  double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
373  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); //scale painter from mm to dots
374 
375  //setup render context
377  //context units should be in dots
378  ms.setOutputSize( QSizeF( mComposerMap->rect().width() * dotsPerMM, mComposerMap->rect().height() * dotsPerMM ).toSize() );
380  ms.setOutputDpi( p->device()->logicalDpiX() );
382  context.setForceVectorOutput( true );
383  context.setPainter( p );
384 
385  QList< QPair< double, QLineF > > verticalLines;
386  QList< QPair< double, QLineF > > horizontalLines;
387 
388  //is grid in a different crs than map?
389  if ( mGridUnit == MapUnit && mCRS.isValid() && mCRS != ms.destinationCrs() )
390  {
391  drawGridCRSTransform( context, dotsPerMM, horizontalLines, verticalLines );
392  }
393  else
394  {
395  drawGridNoTransform( context, dotsPerMM, horizontalLines, verticalLines );
396  }
397 
398  p->restore();
399  p->setClipping( false );
400 
402  {
403  drawGridFrame( p, horizontalLines, verticalLines );
404  }
405 
406  if ( mShowGridAnnotation )
407  {
408  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
409  }
410 }
411 
412 void QgsComposerMapGrid::drawGridNoTransform( QgsRenderContext &context, double dotsPerMM, QList< QPair< double, QLineF > > &horizontalLines,
413  QList< QPair< double, QLineF > > &verticalLines ) const
414 {
415  //get line positions
416  yGridLines( verticalLines );
417  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
418  xGridLines( horizontalLines );
419  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
420 
421  //simple approach: draw vertical lines first, then horizontal ones
423  {
424  //we need to scale line coordinates to dots, rather than mm, since the painter has already been scaled to dots
425  //this is done by multiplying each line coordinate by dotsPerMM
426  QLineF line;
427  for ( ; vIt != verticalLines.constEnd(); ++vIt )
428  {
429  line = QLineF( vIt->second.p1() * dotsPerMM, vIt->second.p2() * dotsPerMM );
430  drawGridLine( line, context );
431  }
432 
433  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
434  {
435  line = QLineF( hIt->second.p1() * dotsPerMM, hIt->second.p2() * dotsPerMM );
436  drawGridLine( line, context );
437  }
438  }
439  else //cross or markers
440  {
441  QPointF intersectionPoint, crossEnd1, crossEnd2;
442  for ( ; vIt != verticalLines.constEnd(); ++vIt )
443  {
444  //start mark
446  {
447  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
448  drawGridLine( QLineF( vIt->second.p1() * dotsPerMM, crossEnd1 * dotsPerMM ), context );
449  }
450 
451  //test for intersection with every horizontal line
452  hIt = horizontalLines.constBegin();
453  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
454  {
455  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
456  {
458  {
459  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
460  crossEnd1 = (( intersectionPoint - vIt->second.p1() ).manhattanLength() > 0.01 ) ?
461  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength ) : intersectionPoint;
462  crossEnd2 = (( intersectionPoint - vIt->second.p2() ).manhattanLength() > 0.01 ) ?
463  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength ) : intersectionPoint;
464  //draw line using coordinates scaled to dots
465  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
466  }
467  else if ( mGridStyle == QgsComposerMap::Markers )
468  {
469  drawGridMarker( intersectionPoint * dotsPerMM , context );
470  }
471  }
472  }
473  //end mark
475  {
476  QPointF crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
477  drawGridLine( QLineF( vIt->second.p2() * dotsPerMM, crossEnd2 * dotsPerMM ), context );
478  }
479  }
481  {
482  //markers mode, so we have no need to process horizontal lines (we've already
483  //drawn markers on the intersections between horizontal and vertical lines)
484  return;
485  }
486 
487  hIt = horizontalLines.constBegin();
488  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
489  {
490  //start mark
491  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
492  drawGridLine( QLineF( hIt->second.p1() * dotsPerMM, crossEnd1 * dotsPerMM ), context );
493 
494  vIt = verticalLines.constBegin();
495  for ( ; vIt != verticalLines.constEnd(); ++vIt )
496  {
497  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
498  {
499  //apply a threshold to avoid calculate point if the two points are very close together (can lead to artifacts)
500  crossEnd1 = (( intersectionPoint - hIt->second.p1() ).manhattanLength() > 0.01 ) ?
501  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength ) : intersectionPoint;
502  crossEnd2 = (( intersectionPoint - hIt->second.p2() ).manhattanLength() > 0.01 ) ?
503  QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength ) : intersectionPoint;
504  //draw line using coordinates scaled to dots
505  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
506  }
507  }
508  //end mark
509  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
510  drawGridLine( QLineF( hIt->second.p2() * dotsPerMM, crossEnd1 * dotsPerMM ), context );
511  }
512  }
513 }
514 
515 void QgsComposerMapGrid::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
516 {
517  p->save();
518  p->setRenderHint( QPainter::Antialiasing );
519 
520  //Sort the coordinate positions for each side
521  QMap< double, double > leftGridFrame;
522  QMap< double, double > rightGridFrame;
523  QMap< double, double > topGridFrame;
524  QMap< double, double > bottomGridFrame;
525 
526  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
527 
528  drawGridFrameBorder( p, leftGridFrame, QgsComposerMap::Left );
529  drawGridFrameBorder( p, rightGridFrame, QgsComposerMap::Right );
530  drawGridFrameBorder( p, topGridFrame, QgsComposerMap::Top );
531  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMap::Bottom );
532 
533  p->restore();
534 }
535 
536 void QgsComposerMapGrid::drawGridLine( const QLineF& line, QgsRenderContext& context ) const
537 {
538  QPolygonF poly;
539  poly << line.p1() << line.p2();
540  drawGridLine( poly, context );
541 }
542 
543 void QgsComposerMapGrid::drawGridLine( const QPolygonF& line, QgsRenderContext& context ) const
544 {
546  {
547  return;
548  }
549 
550  mGridLineSymbol->startRender( context );
551  mGridLineSymbol->renderPolyline( line, 0, context );
552  mGridLineSymbol->stopRender( context );
553 }
554 
555 void QgsComposerMapGrid::drawGridMarker( const QPointF& point, QgsRenderContext& context ) const
556 {
558  {
559  return;
560  }
561 
562  mGridMarkerSymbol->startRender( context );
563  mGridMarkerSymbol->renderPoint( point, 0, context );
564  mGridMarkerSymbol->stopRender( context );
565 }
566 
567 void QgsComposerMapGrid::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, QgsComposerMap::Border border ) const
568 {
569  if ( !mComposerMap )
570  {
571  return;
572  }
573 
574  double currentCoord = - mGridFrameWidth;
575  bool color1 = true;
576  double x = 0;
577  double y = 0;
578  double width = 0;
579  double height = 0;
580 
581  QMap< double, double > pos = borderPos;
582  pos.insert( 0, 0 );
583  if ( border == QgsComposerMap::Left || border == QgsComposerMap::Right )
584  {
585  pos.insert( mComposerMap->rect().height(), mComposerMap->rect().height() );
586  pos.insert( mComposerMap->rect().height() + mGridFrameWidth, mComposerMap->rect().height() + mGridFrameWidth );
587  }
588  else //top or bottom
589  {
590  pos.insert( mComposerMap->rect().width(), mComposerMap->rect().width() );
591  pos.insert( mComposerMap->rect().width() + mGridFrameWidth, mComposerMap->rect().width() + mGridFrameWidth );
592  }
593 
594  //set pen to current frame pen
595  QPen framePen = QPen( mGridFramePenColor );
596  framePen.setWidthF( mGridFramePenThickness );
597  framePen.setJoinStyle( Qt::MiterJoin );
598  p->setPen( framePen );
599 
600  QMap< double, double >::const_iterator posIt = pos.constBegin();
601  for ( ; posIt != pos.constEnd(); ++posIt )
602  {
603  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
604  if ( border == QgsComposerMap::Left || border == QgsComposerMap::Right )
605  {
606  height = posIt.key() - currentCoord;
607  width = mGridFrameWidth;
608  x = ( border == QgsComposerMap::Left ) ? -mGridFrameWidth : mComposerMap->rect().width();
609  y = currentCoord;
610  }
611  else //top or bottom
612  {
613  height = mGridFrameWidth;
614  width = posIt.key() - currentCoord;
615  x = currentCoord;
616  y = ( border == QgsComposerMap::Top ) ? -mGridFrameWidth : mComposerMap->rect().height();
617  }
618  p->drawRect( QRectF( x, y, width, height ) );
619  currentCoord = posIt.key();
620  color1 = !color1;
621  }
622 }
623 
624 void QgsComposerMapGrid::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines ) const
625 {
626  if ( !p )
627  {
628  return;
629  }
630 
631 
632  QString currentAnnotationString;
633  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
634  for ( ; it != hLines.constEnd(); ++it )
635  {
636  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMap::Longitude );
637  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
638  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
639  }
640 
641  it = vLines.constBegin();
642  for ( ; it != vLines.constEnd(); ++it )
643  {
644  currentAnnotationString = gridAnnotationString( it->first, QgsComposerMap::Latitude );
645  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
646  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
647  }
648 }
649 
650 void QgsComposerMapGrid::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString ) const
651 {
652  if ( !mComposerMap )
653  {
654  return;
655  }
656  QgsComposerMap::Border frameBorder = borderForLineCoord( pos );
657  double textWidth = QgsComposerUtils::textWidthMM( mGridAnnotationFont, annotationString );
658  //relevant for annotations is the height of digits
659  double textHeight = QgsComposerUtils::fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
660  double xpos = pos.x();
661  double ypos = pos.y();
662  int rotation = 0;
663 
664  double gridFrameDistance = ( mGridFrameStyle == QgsComposerMap::NoGridFrame ) ? 0 : mGridFrameWidth;
665 
666  if ( frameBorder == QgsComposerMap::Left )
667  {
668 
670  {
672  {
673  xpos += textHeight + mAnnotationFrameDistance;
674  ypos += textWidth / 2.0;
675  rotation = 270;
676  }
677  else
678  {
679  xpos += mAnnotationFrameDistance;
680  ypos += textHeight / 2.0;
681  }
682  }
683  else if ( mLeftGridAnnotationPosition == QgsComposerMap::OutsideMapFrame ) //Outside map frame
684  {
686  {
687  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
688  ypos += textWidth / 2.0;
689  rotation = 270;
690  }
691  else
692  {
693  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
694  ypos += textHeight / 2.0;
695  }
696  }
697  else
698  {
699  return;
700  }
701 
702  }
703  else if ( frameBorder == QgsComposerMap::Right )
704  {
706  {
708  {
709  xpos -= mAnnotationFrameDistance;
710  ypos += textWidth / 2.0;
711  rotation = 270;
712  }
713  else
714  {
715  xpos -= textWidth + mAnnotationFrameDistance;
716  ypos += textHeight / 2.0;
717  }
718  }
719  else if ( mRightGridAnnotationPosition == QgsComposerMap::OutsideMapFrame )//OutsideMapFrame
720  {
722  {
723  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
724  ypos += textWidth / 2.0;
725  rotation = 270;
726  }
727  else //Horizontal
728  {
729  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
730  ypos += textHeight / 2.0;
731  }
732  }
733  else
734  {
735  return;
736  }
737  }
738  else if ( frameBorder == QgsComposerMap::Bottom )
739  {
741  {
743  {
744  ypos -= mAnnotationFrameDistance;
745  xpos -= textWidth / 2.0;
746  }
747  else //Vertical
748  {
749  xpos += textHeight / 2.0;
750  ypos -= mAnnotationFrameDistance;
751  rotation = 270;
752  }
753  }
754  else if ( mBottomGridAnnotationPosition == QgsComposerMap::OutsideMapFrame ) //OutsideMapFrame
755  {
757  {
758  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
759  xpos -= textWidth / 2.0;
760  }
761  else //Vertical
762  {
763  xpos += textHeight / 2.0;
764  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
765  rotation = 270;
766  }
767  }
768  else
769  {
770  return;
771  }
772  }
773  else //Top
774  {
776  {
778  {
779  xpos -= textWidth / 2.0;
780  ypos += textHeight + mAnnotationFrameDistance;
781  }
782  else //Vertical
783  {
784  xpos += textHeight / 2.0;
785  ypos += textWidth + mAnnotationFrameDistance;
786  rotation = 270;
787  }
788  }
789  else if ( mTopGridAnnotationPosition == QgsComposerMap::OutsideMapFrame ) //OutsideMapFrame
790  {
792  {
793  xpos -= textWidth / 2.0;
794  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
795  }
796  else //Vertical
797  {
798  xpos += textHeight / 2.0;
799  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
800  rotation = 270;
801  }
802  }
803  else
804  {
805  return;
806  }
807  }
808 
809  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
810 }
811 
812 void QgsComposerMapGrid::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText ) const
813 {
814  if ( !mComposerMap )
815  {
816  return;
817  }
818 
819  p->save();
820  p->translate( pos );
821  p->rotate( rotation );
822  QgsComposerUtils::drawText( p, QPointF( 0, 0 ), annotationText, mGridAnnotationFont, mGridAnnotationFontColor );
823  p->restore();
824 }
825 
827 {
829  {
830  return QString::number( value, 'f', mGridAnnotationPrecision );
831  }
832 
833  QgsPoint p;
834  p.setX( coord == QgsComposerMap::Longitude ? value : 0 );
835  p.setY( coord == QgsComposerMap::Longitude ? 0 : value );
836 
837  QString annotationString;
839  {
840  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
841  }
842  else //DegreeMinuteSecond
843  {
844  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
845  }
846 
847  QStringList split = annotationString.split( "," );
848  if ( coord == QgsComposerMap::Longitude )
849  {
850  return split.at( 0 );
851  }
852  else
853  {
854  if ( split.size() < 2 )
855  {
856  return "";
857  }
858  return split.at( 1 );
859  }
860 }
861 
862 int QgsComposerMapGrid::xGridLines( QList< QPair< double, QLineF > >& lines ) const
863 {
864  lines.clear();
865  if ( !mComposerMap || mGridIntervalY <= 0.0 )
866  {
867  return 1;
868  }
869 
870 
871  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
872  QRectF mapBoundingRect = mapPolygon.boundingRect();
873  double gridIntervalY = mGridIntervalY;
874  double gridOffsetY = mGridOffsetY;
875  double annotationScale = 1.0;
876  if ( mGridUnit != MapUnit )
877  {
878  mapBoundingRect = mComposerMap->rect();
879  mapPolygon = QPolygonF( mComposerMap->rect() );
880  if ( mGridUnit == CM )
881  {
882  annotationScale = 0.1;
883  gridIntervalY *= 10; gridOffsetY *= 10;
884  }
885  }
886 
887  //consider to round up to the next step in case the left boundary is > 0
888  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
889  double currentLevel = ( int )(( mapBoundingRect.top() - gridOffsetY ) / gridIntervalY + roundCorrection ) * gridIntervalY + gridOffsetY;
890 
891  int gridLineCount = 0;
892  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
893  {
894  //no rotation. Do it 'the easy way'
895 
896  double yCanvasCoord;
897  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
898  {
899  yCanvasCoord = mComposerMap->rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
900  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( 0, yCanvasCoord, mComposerMap->rect().width(), yCanvasCoord ) ) );
901  currentLevel += gridIntervalY;
902  gridLineCount++;
903  }
904  return 0;
905  }
906 
907  //the four border lines
908  QVector<QLineF> borderLines;
909  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
910  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
911  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
912  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
913 
914  QList<QPointF> intersectionList; //intersects between border lines and grid lines
915 
916  while ( currentLevel <= mapBoundingRect.bottom() && gridLineCount < MAX_GRID_LINES )
917  {
918  intersectionList.clear();
919  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
920 
921  QVector<QLineF>::const_iterator it = borderLines.constBegin();
922  for ( ; it != borderLines.constEnd(); ++it )
923  {
924  QPointF intersectionPoint;
925  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
926  {
927  intersectionList.push_back( intersectionPoint );
928  if ( intersectionList.size() >= 2 )
929  {
930  break; //we already have two intersections, skip further tests
931  }
932  }
933  }
934 
935  if ( intersectionList.size() >= 2 )
936  {
937  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
938  gridLineCount++;
939  }
940  currentLevel += gridIntervalY;
941  }
942 
943 
944  return 0;
945 }
946 
947 int QgsComposerMapGrid::yGridLines( QList< QPair< double, QLineF > >& lines ) const
948 {
949  lines.clear();
950  if ( !mComposerMap || mGridIntervalX <= 0.0 )
951  {
952  return 1;
953  }
954 
955  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
956  QRectF mapBoundingRect = mapPolygon.boundingRect();
957  double gridIntervalX = mGridIntervalX;
958  double gridOffsetX = mGridOffsetX;
959  double annotationScale = 1.0;
960  if ( mGridUnit != MapUnit )
961  {
962  mapBoundingRect = mComposerMap->rect();
963  mapPolygon = QPolygonF( mComposerMap->rect() );
964  if ( mGridUnit == CM )
965  {
966  annotationScale = 0.1;
967  gridIntervalX *= 10; gridOffsetX *= 10;
968  }
969  }
970 
971  //consider to round up to the next step in case the left boundary is > 0
972  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
973  double currentLevel = ( int )(( mapBoundingRect.left() - gridOffsetX ) / gridIntervalX + roundCorrection ) * gridIntervalX + gridOffsetX;
974 
975  int gridLineCount = 0;
976  if ( qgsDoubleNear( mComposerMap->mapRotation(), 0.0 ) || mGridUnit != MapUnit )
977  {
978  //no rotation. Do it 'the easy way'
979  double xCanvasCoord;
980  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
981  {
982  xCanvasCoord = mComposerMap->rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
983  lines.push_back( qMakePair( currentLevel * annotationScale, QLineF( xCanvasCoord, 0, xCanvasCoord, mComposerMap->rect().height() ) ) );
984  currentLevel += gridIntervalX;
985  gridLineCount++;
986  }
987  return 0;
988  }
989 
990  //the four border lines
991  QVector<QLineF> borderLines;
992  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
993  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
994  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
995  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
996 
997  QList<QPointF> intersectionList; //intersects between border lines and grid lines
998 
999  while ( currentLevel <= mapBoundingRect.right() && gridLineCount < MAX_GRID_LINES )
1000  {
1001  intersectionList.clear();
1002  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1003 
1004  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1005  for ( ; it != borderLines.constEnd(); ++it )
1006  {
1007  QPointF intersectionPoint;
1008  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1009  {
1010  intersectionList.push_back( intersectionPoint );
1011  if ( intersectionList.size() >= 2 )
1012  {
1013  break; //we already have two intersections, skip further tests
1014  }
1015  }
1016  }
1017 
1018  if ( intersectionList.size() >= 2 )
1019  {
1020  lines.push_back( qMakePair( currentLevel, QLineF( mComposerMap->mapToItemCoords( intersectionList.at( 0 ) ), mComposerMap->mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1021  gridLineCount++;
1022  }
1023  currentLevel += gridIntervalX;
1024  }
1025 
1026  return 0;
1027 }
1028 
1029 int QgsComposerMapGrid::xGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1030 {
1031  lines.clear();
1032  if ( !mComposerMap || mGridIntervalY <= 0.0 )
1033  {
1034  return 1;
1035  }
1036 
1037  double roundCorrection = bbox.yMaximum() > 0 ? 1.0 : 0.0;
1038  double currentLevel = ( int )(( bbox.yMaximum() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1039 
1040  double minX = bbox.xMinimum();
1041  double maxX = bbox.xMaximum();
1042  double step = ( maxX - minX ) / 20;
1043 
1044  int gridLineCount = 0;
1045  while ( currentLevel >= bbox.yMinimum() && gridLineCount < MAX_GRID_LINES )
1046  {
1047  QPolygonF gridLine;
1048  double currentX = minX;
1049  bool cont = true;
1050  while ( cont )
1051  {
1052  if ( currentX > maxX )
1053  {
1054  cont = false;
1055  }
1056 
1057  QgsPoint mapPoint = t.transform( currentX, currentLevel ); //transform back to map crs
1058  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) ); //transform back to composer coords
1059  currentX += step;
1060  }
1061 
1062  gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1063  if ( gridLine.size() > 0 )
1064  {
1065  lines.append( qMakePair( currentLevel, gridLine ) );
1066  gridLineCount++;
1067  }
1068  currentLevel -= mGridIntervalY;
1069  }
1070 
1071  return 0;
1072 }
1073 
1074 int QgsComposerMapGrid::yGridLinesCRSTransform( const QgsRectangle& bbox, const QgsCoordinateTransform& t, QList< QPair< double, QPolygonF > >& lines ) const
1075 {
1076  lines.clear();
1077  if ( !mComposerMap || mGridIntervalX <= 0.0 )
1078  {
1079  return 1;
1080  }
1081 
1082  double roundCorrection = bbox.xMinimum() > 0 ? 1.0 : 0.0;
1083  double currentLevel = ( int )(( bbox.xMinimum() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1084 
1085  double minY = bbox.yMinimum();
1086  double maxY = bbox.yMaximum();
1087  double step = ( maxY - minY ) / 20;
1088 
1089  int gridLineCount = 0;
1090  while ( currentLevel <= bbox.xMaximum() && gridLineCount < MAX_GRID_LINES )
1091  {
1092  QPolygonF gridLine;
1093  double currentY = minY;
1094  bool cont = true;
1095  while ( cont )
1096  {
1097  if ( currentY > maxY )
1098  {
1099  cont = false;
1100  }
1101  //transform back to map crs
1102  QgsPoint mapPoint = t.transform( currentLevel, currentY );
1103  //transform back to composer coords
1104  gridLine.append( mComposerMap->mapToItemCoords( QPointF( mapPoint.x(), mapPoint.y() ) ) );
1105  currentY += step;
1106  }
1107  //clip grid line to map polygon
1108  gridLine = trimLineToMap( gridLine, QgsRectangle( mComposerMap->rect() ) );
1109  if ( gridLine.size() > 0 )
1110  {
1111  lines.append( qMakePair( currentLevel, gridLine ) );
1112  gridLineCount++;
1113  }
1114  currentLevel += mGridIntervalX;
1115  }
1116 
1117  return 0;
1118 }
1119 
1120 void QgsComposerMapGrid::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
1121  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
1122 {
1123  QList< QPair< double, QPointF > > borderPositions;
1124  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1125  for ( ; it != hLines.constEnd(); ++it )
1126  {
1127  borderPositions << qMakePair( it->first, it->second.p1() );
1128  borderPositions << qMakePair( it->first, it->second.p2() );
1129  }
1130  it = vLines.constBegin();
1131  for ( ; it != vLines.constEnd(); ++it )
1132  {
1133  borderPositions << qMakePair( it->first, it->second.p1() );
1134  borderPositions << qMakePair( it->first, it->second.p2() );
1135  }
1136 
1137  QList< QPair< double, QPointF > >::const_iterator bIt = borderPositions.constBegin();
1138  for ( ; bIt != borderPositions.constEnd(); ++bIt )
1139  {
1140  QgsComposerMap::Border frameBorder = borderForLineCoord( bIt->second );
1141  if ( frameBorder == QgsComposerMap::Left )
1142  {
1143  leftFrameEntries.insert( bIt->second.y(), bIt->first );
1144  }
1145  else if ( frameBorder == QgsComposerMap::Right )
1146  {
1147  rightFrameEntries.insert( bIt->second.y(), bIt->first );
1148  }
1149  else if ( frameBorder == QgsComposerMap::Top )
1150  {
1151  topFrameEntries.insert( bIt->second.x(), bIt->first );
1152  }
1153  else //Bottom
1154  {
1155  bottomFrameEntries.insert( bIt->second.x(), bIt->first );
1156  }
1157  }
1158 }
1159 
1161 {
1162  if ( !mComposerMap )
1163  {
1164  return QgsComposerMap::Left;
1165  }
1166 
1167  double framePenWidth = mComposerMap->hasFrame() ? mComposerMap->pen().widthF() : 0;
1168  if ( p.y() <= framePenWidth )
1169  {
1170  return QgsComposerMap::Top;
1171  }
1172  else if ( p.x() <= framePenWidth )
1173  {
1174  return QgsComposerMap::Left;
1175  }
1176  else if ( p.x() >= ( mComposerMap->rect().width() - framePenWidth ) )
1177  {
1178  return QgsComposerMap::Right;
1179  }
1180  else
1181  {
1182  return QgsComposerMap::Bottom;
1183  }
1184 }
1185 
1187 {
1188  delete mGridLineSymbol;
1189  mGridLineSymbol = symbol;
1190 }
1191 
1193 {
1194  delete mGridMarkerSymbol;
1195  mGridMarkerSymbol = symbol;
1196 }
1197 
1199 {
1200  if ( !mComposerMap )
1201  {
1202  return 0;
1203  }
1204 
1207  {
1208  return 0;
1209  }
1210 
1212  QStringList coordStrings;
1213  if ( mCRS.isValid() && mCRS != ms.destinationCrs() )
1214  {
1215  QList< QPair< double, QPolygonF > > xGridLines;
1216  QList< QPair< double, QPolygonF > > yGridLines;
1217  QgsRectangle crsRect;
1218  QgsCoordinateTransform inverseTransform;
1219  if ( crsGridParams( crsRect, inverseTransform ) != 0 )
1220  {
1221  return 0;
1222  }
1223 
1224  int xGridReturn = xGridLinesCRSTransform( crsRect, inverseTransform, xGridLines );
1225  int yGridReturn = yGridLinesCRSTransform( crsRect, inverseTransform, yGridLines );
1226  if ( xGridReturn != 0 || yGridReturn != 0 )
1227  {
1228  return 0;
1229  }
1230 
1231  QList< QPair< double, QPolygonF > >::const_iterator it = xGridLines.constBegin();
1232  for ( ; it != xGridLines.constEnd(); ++it )
1233  {
1234  coordStrings.append( gridAnnotationString( it->first, QgsComposerMap::Latitude ) );
1235  }
1236  it = yGridLines.constBegin();
1237  for ( ; it != yGridLines.constEnd(); ++it )
1238  {
1239  coordStrings.append( gridAnnotationString( it->first, QgsComposerMap::Longitude ) );
1240  }
1241  }
1242  else
1243  {
1244  QList< QPair< double, QLineF > > xLines;
1245  QList< QPair< double, QLineF > > yLines;
1246  int xGridReturn = xGridLines( xLines );
1247  int yGridReturn = yGridLines( yLines );
1248  if ( xGridReturn != 0 && yGridReturn != 0 )
1249  {
1250  return 0;
1251  }
1252 
1253  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
1254  for ( ; it != xLines.constEnd(); ++it )
1255  {
1256  coordStrings.append( gridAnnotationString( it->first, QgsComposerMap::Latitude ) );
1257  }
1258 
1259  it = yLines.constBegin();
1260  for ( ; it != yLines.constEnd(); ++it )
1261  {
1262  coordStrings.append( gridAnnotationString( it->first, QgsComposerMap::Longitude ) );
1263  }
1264  }
1265 
1266  double maxExtension = 0;
1267  double currentExtension = 0;
1268 
1269  QStringList::const_iterator coordIt = coordStrings.constBegin();
1270  for ( ; coordIt != coordStrings.constEnd(); ++coordIt )
1271  {
1273  maxExtension = qMax( maxExtension, currentExtension );
1274  }
1275 
1276  //grid frame
1277  double gridFrameDist = ( mGridFrameStyle == QgsComposerMap::NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
1278  return maxExtension + mAnnotationFrameDistance + gridFrameDist;
1279 }
1280 
1282 {
1283  switch ( border )
1284  {
1285  case QgsComposerMap::Left:
1287  break;
1288  case QgsComposerMap::Right:
1290  break;
1291  case QgsComposerMap::Top:
1293  break;
1296  break;
1297  default:
1298  return;
1299  break;
1300  }
1301 
1302  if ( mComposerMap )
1303  {
1305  mComposerMap->update();
1306  }
1307 }
1308 
1310 {
1312 }
1313 
1315 {
1320 }
1321 
1323 {
1324  switch ( border )
1325  {
1326  case QgsComposerMap::Left:
1328  break;
1329  case QgsComposerMap::Right:
1331  break;
1332  case QgsComposerMap::Top:
1334  break;
1337  break;
1338  default:
1339  return;
1340  }
1341 
1342  if ( mComposerMap )
1343  {
1345  mComposerMap->update();
1346  }
1347 }
1348 
1350 {
1351  switch ( border )
1352  {
1353  case QgsComposerMap::Left:
1355  break;
1356  case QgsComposerMap::Right:
1358  break;
1359  case QgsComposerMap::Top:
1361  break;
1363  default:
1365  break;
1366  }
1367 }
1368 
1370 {
1371  if ( !mComposerMap )
1372  {
1374  }
1375 
1376  switch ( border )
1377  {
1378  case QgsComposerMap::Left:
1380  break;
1381  case QgsComposerMap::Right:
1383  break;
1384  case QgsComposerMap::Top:
1386  break;
1388  default:
1390  break;
1391  }
1392 }
1393 
1395 {
1396  if ( !mComposerMap )
1397  {
1398  return 1;
1399  }
1400 
1402  QPolygonF mapPolygon = mComposerMap->transformedMapPolygon();
1403  QRectF mbr = mapPolygon.boundingRect();
1404  QgsRectangle mapBoundingRect( mbr.left(), mbr.bottom(), mbr.right(), mbr.top() );
1405  crsRect = tr.transformBoundingBox( mapBoundingRect );
1406  inverseTransform.setSourceCrs( mCRS );
1407  inverseTransform.setDestCRS( mComposerMap->composition()->mapSettings().destinationCrs() );
1408  return 0;
1409 }
1410 
1411 QPolygonF QgsComposerMapGrid::trimLineToMap( const QPolygonF& line, const QgsRectangle& rect )
1412 {
1413  QgsPolyline polyLine;
1414  QPolygonF::const_iterator lineIt = line.constBegin();
1415  for ( ; lineIt != line.constEnd(); ++lineIt )
1416  {
1417  polyLine.append( QgsPoint( lineIt->x(), lineIt->y() ) );
1418  }
1419 
1420  QgsGeometry* geom = QgsGeometry::fromPolyline( polyLine );
1421 
1422  QPolygonF clippedLine;
1423  QgsClipper::clippedLineWKB( geom->asWkb(), rect, clippedLine );
1424  delete geom;
1425  return clippedLine;
1426 }
1427 
1428 
int crsGridParams(QgsRectangle &crsRect, QgsCoordinateTransform &inverseTransform) const
Get parameters for drawing grid in CRS different to map CRS.
QString toDegreesMinutesSeconds(int thePrecision) const
Return a string representation as degrees minutes seconds.
Definition: qgspoint.cpp:137
void setForceVectorOutput(bool force)
Added in QGIS v1.5.
void setGridPenWidth(double w)
Sets with of grid pen.
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 setGridAnnotationDirection(QgsComposerMap::GridAnnotationDirection d, QgsComposerMap::Border border)
QPolygonF scalePolygon(const QPolygonF &polygon, const double scale) const
double gridIntervalX() const
double mGridOffsetX
Grid line offset in x-direction.
QgsComposerMap::GridAnnotationPosition mLeftGridAnnotationPosition
Annotation position for left map side (inside / outside / not shown)
QgsComposerMap::GridAnnotationDirection gridAnnotationDirection() const
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)
QgsComposerMap::Border borderForLineCoord(const QPointF &p) const
Returns the item border of a point (in item coordinates)
QString toDegreesMinutes(int thePrecision) const
Return a string representation as degrees minutes.
Definition: qgspoint.cpp:162
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
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
Border
Enum for different frame borders.
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 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 state from Dom document
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
double x() const
Definition: qgspoint.h:110
QgsComposerMap * mComposerMap
void setWidth(double width)
QgsComposerMap::GridAnnotationDirection mBottomGridAnnotationDirection
Annotation direction on bottom side ( horizontal or vertical )
void setGridMarkerSymbol(QgsMarkerSymbolV2 *symbol)
static QString encodeColor(QColor color)
The QgsMapSettings class contains configuration for rendering of the map.
QPainter::CompositionMode mBlendMode
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void setGridAnnotationPosition(QgsComposerMap::GridAnnotationPosition p, QgsComposerMap::Border border)
void setColor(const QColor &color)
int xGridLines(QList< QPair< double, QLineF > > &lines) const
Returns the grid lines with associated coordinate value.
QgsComposerMap::GridStyle mGridStyle
Solid or crosses.
QgsComposerMap::GridAnnotationDirection mRightGridAnnotationDirection
Annotation direction on right side ( horizontal or vertical )
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
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)
QgsComposerMap::GridAnnotationPosition mRightGridAnnotationPosition
Annotation position for right map side (inside / outside / not shown)
QgsComposerMap::GridAnnotationPosition gridAnnotationPosition(QgsComposerMap::Border border) const
static QgsLineSymbolV2 * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
double gridIntervalY() const
const QgsComposition * composition() const
Returns the composition the item is attached to.
QgsComposerMap::GridAnnotationPosition mTopGridAnnotationPosition
Annotation position for top map side (inside / outside / not shown)
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
void setPainter(QPainter *p)
QgsComposerMap::GridFrameStyle mGridFrameStyle
QgsPoint transform(const QgsPoint p, TransformDirection direction=ForwardTransform) const
void renderPoint(const QPointF &point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
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.
A class to represent a point geometry.
Definition: qgspoint.h:63
QPainter::CompositionMode mBlendMode
Blend mode for overview.
Object representing map window.
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
QgsComposerMap::GridAnnotationDirection mTopGridAnnotationDirection
Annotation direction on top side ( horizontal or vertical )
void setX(double x)
Definition: qgspoint.h:87
QString qgsDoubleToString(const double &a, const int &precision=17)
Definition: qgis.h:316
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.
void setGridPenColor(const QColor &c)
Sets the color of the grid pen.
QgsComposerMap::GridAnnotationPosition mBottomGridAnnotationPosition
Annotation position for bottom map side (inside / outside / not shown)
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)
QgsComposerMap::GridAnnotationDirection mLeftGridAnnotationDirection
Annotation direction on left side ( horizontal or vertical )
bool mGridEnabled
True if coordinate grid has to be displayed.
void drawGridFrameBorder(QPainter *p, const QMap< double, double > &borderPos, QgsComposerMap::Border border) const
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
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.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
void setGridLineSymbol(QgsLineSymbolV2 *symbol)
QgsComposerMap::GridAnnotationFormat mGridAnnotationFormat
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.
double gridOffsetX() const
Class for doing transforms between two map coordinate systems.
double mGridOffsetY
Grid line offset in y-direction.
static QgsGeometry * fromPolyline(const QgsPolyline &polyline)
construct geometry from a polyline
double y() const
Definition: qgspoint.h:118
QString gridAnnotationString(double value, QgsComposerMap::AnnotationCoordinate coord) const
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
static QgsSymbolV2 * loadSymbol(QDomElement &element)
QgsMarkerSymbolV2 * mGridMarkerSymbol
QPointF mapToItemCoords(const QPointF &mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset) ...
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
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)
QFont mGridAnnotationFont
Font for grid line annotation.
void setGridPen(const QPen &p)
Sets the pen to draw composer grid.
double gridOffsetY() const
int yGridLinesCRSTransform(const QgsRectangle &bbox, const QgsCoordinateTransform &t, QList< QPair< double, QPolygonF > > &lines) const
void drawGrid(QPainter *painter) const
Reimplementation of QCanvasItem::paint.
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
QgsCoordinateReferenceSystem mCRS
static QPolygonF trimLineToMap(const QPolygonF &line, const QgsRectangle &rect)
QColor color() const
double mAnnotationFrameDistance
Distance between map frame and annotation.
#define tr(sourceText)
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom element