QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposermap.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposermap.cpp
3  -------------------
4  begin : January 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : blazek@itc.it
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 "qgscomposermap.h"
19 #include "qgscomposition.h"
20 #include "qgscoordinatetransform.h"
21 #include "qgslogger.h"
22 #include "qgsmaprenderer.h"
23 #include "qgsmaprendererjob.h"
24 #include "qgsmaplayerregistry.h"
25 #include "qgsmaptopixel.h"
26 #include "qgsproject.h"
27 #include "qgsrasterlayer.h"
28 #include "qgsrendercontext.h"
29 #include "qgsscalecalculator.h"
30 #include "qgsvectorlayer.h"
31 #include "qgspallabeling.h"
32 #include "qgsexpression.h"
33 
34 #include "qgslabel.h"
35 #include "qgslabelattributes.h"
36 #include "qgssymbollayerv2utils.h" //for pointOnLineWithDistance
37 
38 #include <QGraphicsScene>
39 #include <QGraphicsView>
40 #include <QPainter>
41 #include <QSettings>
42 #include <cmath>
43 
44 QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
45  : QgsComposerItem( x, y, width, height, composition ), mMapRotation( 0 ), mKeepLayerSet( false )
46  , mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false )
47  , mUpdatesEnabled( true ), mGridEnabled( false ), mGridStyle( Solid )
48  , mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) )
49  , mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), mGridBlendMode( QPainter::CompositionMode_SourceOver )
50  , mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame )
51  , mTopGridAnnotationPosition( OutsideMapFrame ), mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 )
52  , mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal )
53  , mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 )
54  , mGridFramePenThickness( 0.5 ), mGridFramePenColor( QColor( 0, 0, 0 ) ), mGridFrameFillColor1( Qt::white ), mGridFrameFillColor2( Qt::black )
55  , mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ), mAtlasDriven( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 )
56 {
59  mGridLineSymbol = 0;
62 
63  mId = 0;
64  assignFreeId();
65 
67  mCurrentRectangle = rect();
68 
69  // Cache
70  mCacheUpdated = false;
71  mDrawing = false;
72 
73  //Offset
74  mXOffset = 0.0;
75  mYOffset = 0.0;
76 
77  //get default composer font from settings
78  QSettings settings;
79  QString defaultFontString = settings.value( "/Composer/defaultFont" ).toString();
80  if ( !defaultFontString.isEmpty() )
81  {
82  mGridAnnotationFont.setFamily( defaultFontString );
83  }
84 
85  //get the color for map canvas background and set map background color accordingly
86  int bgRedInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorRedPart", 255 );
87  int bgGreenInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorGreenPart", 255 );
88  int bgBlueInt = QgsProject::instance()->readNumEntry( "Gui", "/CanvasColorBluePart", 255 );
89  mBackgroundColor = QColor( bgRedInt, bgGreenInt, bgBlueInt );
90 
92 
93  //calculate mExtent based on width/height ratio and map canvas extent
95 
96  setSceneRect( QRectF( x, y, width, height ) );
97  setToolTip( tr( "Map %1" ).arg( mId ) );
98 
100 }
101 
103  : QgsComposerItem( 0, 0, 10, 10, composition ), mMapRotation( 0 ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 )
104  , mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false )
105  , mUpdatesEnabled( true ), mGridEnabled( false ), mGridStyle( Solid )
106  , mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) )
107  , mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), mGridBlendMode( QPainter::CompositionMode_SourceOver )
108  , mLeftGridAnnotationPosition( OutsideMapFrame ), mRightGridAnnotationPosition( OutsideMapFrame )
109  , mTopGridAnnotationPosition( OutsideMapFrame ), mBottomGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 )
110  , mLeftGridAnnotationDirection( Horizontal ), mRightGridAnnotationDirection( Horizontal ), mTopGridAnnotationDirection( Horizontal )
111  , mBottomGridAnnotationDirection( Horizontal ), mGridFrameStyle( NoGridFrame ), mGridFrameWidth( 2.0 ), mGridFramePenThickness( 0.5 )
112  , mGridFramePenColor( QColor( 0, 0, 0 ) ), mGridFrameFillColor1( Qt::white ), mGridFrameFillColor2( Qt::black )
113  , mCrossLength( 3 ), mMapCanvas( 0 ), mDrawCanvasItems( true ), mAtlasDriven( false ), mAtlasFixedScale( false ), mAtlasMargin( 0.10 )
114 {
116  mGridLineSymbol = 0;
118 
119  //Offset
120  mXOffset = 0.0;
121  mYOffset = 0.0;
122 
124 
126  mId = mComposition->composerMapItems().size();
128  mCurrentRectangle = rect();
129 
130  setToolTip( tr( "Map %1" ).arg( mId ) );
131 
133 }
134 
135 void QgsComposerMap::adjustExtentToItemShape( double itemWidth, double itemHeight, QgsRectangle& extent ) const
136 {
137  double itemWidthHeightRatio = itemWidth / itemHeight;
138  double newWidthHeightRatio = extent.width() / extent.height();
139 
140  if ( itemWidthHeightRatio <= newWidthHeightRatio )
141  {
142  //enlarge height of new extent, ensuring the map center stays the same
143  double newHeight = extent.width() / itemWidthHeightRatio;
144  double deltaHeight = newHeight - extent.height();
145  extent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
146  extent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
147  }
148  else
149  {
150  //enlarge width of new extent, ensuring the map center stays the same
151  double newWidth = itemWidthHeightRatio * extent.height();
152  double deltaWidth = newWidth - extent.width();
153  extent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
154  extent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
155  }
156 }
157 
159 {
161  delete mGridLineSymbol;
162 }
163 
164 /* This function is called by paint() and cache() to render the map. It does not override any functions
165 from QGraphicsItem. */
166 void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const QSizeF& size, double dpi, double* forceWidthScale )
167 {
168  Q_UNUSED( forceWidthScale );
169 
170  if ( !painter )
171  {
172  return;
173  }
174 
175  const QgsMapSettings& ms = mComposition->mapSettings();
176 
177  QgsMapSettings jobMapSettings;
178  jobMapSettings.setExtent( extent );
179  jobMapSettings.setOutputSize( size.toSize() );
180  jobMapSettings.setOutputDpi( dpi );
181  jobMapSettings.setMapUnits( ms.mapUnits() );
182  jobMapSettings.setBackgroundColor( Qt::transparent );
183 
184  //set layers to render
185  QStringList theLayerSet = layersToRender();
186  if ( -1 != mCurrentExportLayer )
187  {
188  //exporting with seperate layers (eg, to svg layers), so we only want to render a single map layer
189  const int layerIdx = mCurrentExportLayer - ( hasBackground() ? 1 : 0 );
190  theLayerSet =
191  ( layerIdx >= 0 && layerIdx < theLayerSet.length() )
192  ? QStringList( theLayerSet[ theLayerSet.length() - layerIdx - 1 ] )
193  : QStringList(); //exporting decorations such as map frame/grid/overview, so no map layers required
194  }
195  jobMapSettings.setLayers( theLayerSet );
196  jobMapSettings.setDestinationCrs( ms.destinationCrs() );
197  jobMapSettings.setCrsTransformEnabled( ms.hasCrsTransformEnabled() );
198  jobMapSettings.setFlags( ms.flags() );
199  /* TODO[MD] fix after merge
200  if ( mComposition->plotStyle() == QgsComposition::Print ||
201  mComposition->plotStyle() == QgsComposition::Postscript )
202  {
203  //if outputing composer, disable optimisations like layer simplification
204  theRendererContext->setUseRenderingOptimization( false );
205  }*/
206 
207  //update $map variable. Use QgsComposerItem's id since that is user-definable
209 
210  // composer-specific overrides of flags
211  jobMapSettings.setFlag( QgsMapSettings::ForceVectorOutput ); // force vector output (no caching of marker images etc.)
212  jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
213  jobMapSettings.setFlag( QgsMapSettings::UseAdvancedEffects, mComposition->useAdvancedEffects() ); // respect the composition's useAdvancedEffects flag
214 
215  // render
216  QgsMapRendererCustomPainterJob job( jobMapSettings, painter );
217  job.start();
218  job.waitForFinished();
219 }
220 
222 {
223  if ( mPreviewMode == Rectangle )
224  {
225  return;
226  }
227 
228  if ( mDrawing )
229  {
230  return;
231  }
232 
233  mDrawing = true;
234 
235  //in case of rotation, we need to request a larger rectangle and create a larger cache image
236  QgsRectangle requestExtent;
237  requestedExtent( requestExtent );
238 
239  double horizontalVScaleFactor = horizontalViewScaleFactor();
240  if ( horizontalVScaleFactor < 0 )
241  {
242  //make sure scale factor is positive
243  horizontalVScaleFactor = mLastValidViewScaleFactor > 0 ? mLastValidViewScaleFactor : 1;
244  }
245 
246  double widthMM = requestExtent.width() * mapUnitsToMM();
247  double heightMM = requestExtent.height() * mapUnitsToMM();
248 
249  int w = widthMM * horizontalVScaleFactor;
250  int h = heightMM * horizontalVScaleFactor;
251 
252  if ( w > 5000 ) //limit size of image for better performance
253  {
254  w = 5000;
255  }
256 
257  if ( h > 5000 )
258  {
259  h = 5000;
260  }
261 
262  mCacheImage = QImage( w, h, QImage::Format_ARGB32 );
263 
264  // set DPI of the image
265  mCacheImage.setDotsPerMeterX( 1000 * w / widthMM );
266  mCacheImage.setDotsPerMeterY( 1000 * h / heightMM );
267 
268  if ( hasBackground() )
269  {
270  //Initially fill image with specified background color. This ensures that layers with blend modes will
271  //preview correctly
272  mCacheImage.fill( backgroundColor().rgba() );
273  }
274  else
275  {
276  //no background, but start with empty fill to avoid artifacts
277  mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
278  }
279 
280  QPainter p( &mCacheImage );
281 
282  draw( &p, requestExtent, QSizeF( w, h ), mCacheImage.logicalDpiX() );
283  p.end();
284  mCacheUpdated = true;
285 
286  mDrawing = false;
287 }
288 
289 void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
290 {
291  Q_UNUSED( pWidget );
292 
293  if ( !mComposition || !painter )
294  {
295  return;
296  }
297 
298  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
299  painter->save();
300  painter->setClipRect( thisPaintRect );
301 
303  {
304  // Fill with background color
305  drawBackground( painter );
306  QFont messageFont( "", 12 );
307  painter->setFont( messageFont );
308  painter->setPen( QColor( 0, 0, 0, 125 ) );
309  painter->drawText( thisPaintRect, tr( "Map will be printed here" ) );
310  }
312  {
313  //draw cached pixmap. This function does not call cache() any more because
314  //Qt 4.4.0 and 4.4.1 have problems with recursive paintings
315  //QgsComposerMap::cache() and QgsComposerMap::update() need to be called by
316  //client functions
317 
318  //Background color is already included in cached image, so no need to draw
319 
320  QgsRectangle requestRectangle;
321  requestedExtent( requestRectangle );
322 
323  QgsRectangle cExtent = *currentMapExtent();
324 
325  double imagePixelWidth = cExtent.width() / requestRectangle.width() * mCacheImage.width() ; //how many pixels of the image are for the map extent?
326  double scale = rect().width() / imagePixelWidth;
327  QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );
328 
329  //shift such that rotation point is at 0/0 point in the coordinate system
330  double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
331  double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
332 
333  //shift such that top left point of the extent at point 0/0 in item coordinate system
334  double xTopLeftShift = ( rotationPoint.x() - cExtent.xMinimum() ) * mapUnitsToMM();
335  double yTopLeftShift = ( cExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
336 
337  painter->save();
338 
339  painter->translate( mXOffset, mYOffset );
340  painter->translate( xTopLeftShift, yTopLeftShift );
341  painter->rotate( mMapRotation );
342  painter->translate( xShiftMM, -yShiftMM );
343  painter->scale( scale, scale );
344  painter->drawImage( 0, 0, mCacheImage );
345 
346  //restore rotation
347  painter->restore();
348 
349  //draw canvas items
350  drawCanvasItems( painter, itemStyle );
351  }
352  else if ( mComposition->plotStyle() == QgsComposition::Print ||
354  {
355  if ( mDrawing )
356  {
357  return;
358  }
359 
360  mDrawing = true;
361  QPaintDevice* thePaintDevice = painter->device();
362  if ( !thePaintDevice )
363  {
364  return;
365  }
366 
367  // Fill with background color
368  if ( shouldDrawPart( Background ) )
369  {
370  drawBackground( painter );
371  }
372 
373  QgsRectangle requestRectangle;
374  requestedExtent( requestRectangle );
375 
376  QgsRectangle cExtent = *currentMapExtent();
377 
378  QSizeF theSize( requestRectangle.width() * mapUnitsToMM(), requestRectangle.height() * mapUnitsToMM() );
379 
380  QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );
381 
382  //shift such that rotation point is at 0/0 point in the coordinate system
383  double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
384  double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
385 
386  //shift such that top left point of the extent at point 0/0 in item coordinate system
387  double xTopLeftShift = ( rotationPoint.x() - cExtent.xMinimum() ) * mapUnitsToMM();
388  double yTopLeftShift = ( cExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
389  painter->save();
390  painter->translate( mXOffset, mYOffset );
391  painter->translate( xTopLeftShift, yTopLeftShift );
392  painter->rotate( mMapRotation );
393  painter->translate( xShiftMM, -yShiftMM );
394 
395  double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
396  theSize *= dotsPerMM; // output size will be in dots (pixels)
397  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
398  draw( painter, requestRectangle, theSize, thePaintDevice->logicalDpiX() );
399 
400  //restore rotation
401  painter->restore();
402 
403  //draw canvas items
404  drawCanvasItems( painter, itemStyle );
405 
406  mDrawing = false;
407  }
408 
409  painter->setClipRect( thisPaintRect , Qt::NoClip );
410 
411  if ( mGridEnabled && shouldDrawPart( Grid ) )
412  {
413  drawGrid( painter );
414  }
416  {
417  drawOverviewMapExtent( painter );
418  }
419  if ( shouldDrawPart( Frame ) )
420  {
421  drawFrame( painter );
422  }
423  if ( isSelected() && shouldDrawPart( SelectionBoxes ) )
424  {
425  drawSelectionBoxes( painter );
426  }
427 
428  painter->restore();
429 }
430 
432 {
433  return
434  ( hasBackground() ? 1 : 0 )
435  + layersToRender().length()
436  + ( mGridEnabled ? 1 : 0 )
437  + ( mOverviewFrameMapId != -1 ? 1 : 0 )
438  + ( hasFrame() ? 1 : 0 )
439  + ( isSelected() ? 1 : 0 )
440  ;
441 }
442 
444 {
445  if ( -1 == mCurrentExportLayer )
446  {
447  //all parts of the composer map are visible
448  return true;
449  }
450 
451  int idx = numberExportLayers();
452  if ( isSelected() )
453  {
454  --idx;
455  if ( SelectionBoxes == part )
456  {
457  return mCurrentExportLayer == idx;
458  }
459  }
460 
461  if ( hasFrame() )
462  {
463  --idx;
464  if ( Frame == part )
465  {
466  return mCurrentExportLayer == idx;
467  }
468  }
469  if ( mOverviewFrameMapId )
470  {
471  --idx;
472  if ( OverviewMapExtent == part )
473  {
474  return mCurrentExportLayer == idx;
475  }
476  }
477  if ( mGridEnabled )
478  {
479  --idx;
480  if ( Grid == part )
481  {
482  return mCurrentExportLayer == idx;
483  }
484  }
485  if ( hasBackground() )
486  {
487  if ( Background == part )
488  {
489  return mCurrentExportLayer == 0;
490  }
491  }
492 
493  return true; // for Layer
494 }
495 
496 
498 {
499  syncLayerSet(); //layer list may have changed
500  mCacheUpdated = false;
501  cache();
502  QGraphicsRectItem::update();
503 }
504 
506 {
507  if ( mPreviewMode == Render )
508  {
510  }
511 }
512 
514 {
515  mCacheUpdated = u;
516 }
517 
519 {
521  return mComposition->mapRenderer();
523 }
524 
526 {
527  //use stored layer set or read current set from main canvas
528  QStringList renderLayerSet;
529  if ( mKeepLayerSet )
530  {
531  renderLayerSet = mLayerSet;
532  }
533  else
534  {
535  renderLayerSet = mComposition->mapSettings().layers();
536  }
537 
538  //remove atlas coverage layer if required
539  //TODO - move setting for hiding coverage layer to map item properties
541  {
543  {
544  //hiding coverage layer
545  int removeAt = renderLayerSet.indexOf( mComposition->atlasComposition().coverageLayer()->id() );
546  if ( removeAt != -1 )
547  {
548  renderLayerSet.removeAt( removeAt );
549  }
550  }
551  }
552 
553  return renderLayerSet;
554 }
555 
556 double QgsComposerMap::scale() const
557 {
558  QgsScaleCalculator calculator;
559  calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
560  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
561  return calculator.calculate( *currentMapExtent(), rect().width() );
562 }
563 
564 void QgsComposerMap::resize( double dx, double dy )
565 {
566  //setRect
567  QRectF currentRect = rect();
568  QRectF newSceneRect = QRectF( pos().x(), pos().y(), currentRect.width() + dx, currentRect.height() + dy );
569  setSceneRect( newSceneRect );
570  updateItem();
571 }
572 
573 void QgsComposerMap::moveContent( double dx, double dy )
574 {
575  if ( !mDrawing )
576  {
577  transformShift( dx, dy );
578  currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
579  currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
580  currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
581  currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
582  cache();
583  update();
584  emit itemChanged();
585  emit extentChanged();
586  }
587 }
588 
589 void QgsComposerMap::zoomContent( int delta, double x, double y )
590 {
591  if ( mDrawing )
592  {
593  return;
594  }
595 
596  QSettings settings;
597 
598  //read zoom mode
599  //0: zoom, 1: zoom and recenter, 2: zoom to cursor, 3: nothing
600  int zoomMode = settings.value( "/qgis/wheel_action", 2 ).toInt();
601  if ( zoomMode == 3 ) //do nothing
602  {
603  return;
604  }
605 
606  double zoomFactor = settings.value( "/qgis/zoom_factor", 2.0 ).toDouble();
607 
608  //find out new center point
609  double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
610  double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;
611 
612  if ( zoomMode != 0 )
613  {
614  //find out map coordinates of mouse position
615  double mapMouseX = currentMapExtent()->xMinimum() + ( x / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
616  double mapMouseY = currentMapExtent()->yMinimum() + ( 1 - ( y / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
617  if ( zoomMode == 1 ) //zoom and recenter
618  {
619  centerX = mapMouseX;
620  centerY = mapMouseY;
621  }
622  else if ( zoomMode == 2 ) //zoom to cursor
623  {
624  centerX = mapMouseX + ( centerX - mapMouseX ) * ( 1.0 / zoomFactor );
625  centerY = mapMouseY + ( centerY - mapMouseY ) * ( 1.0 / zoomFactor );
626  }
627  }
628 
629  double newIntervalX, newIntervalY;
630 
631  if ( delta > 0 )
632  {
633  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / zoomFactor;
634  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / zoomFactor;
635  }
636  else if ( delta < 0 )
637  {
638  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) * zoomFactor;
639  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) * zoomFactor;
640  }
641  else //no need to zoom
642  {
643  return;
644  }
645 
646  currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
647  currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
648  currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
649  currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );
650 
651  cache();
652  update();
653  emit itemChanged();
654  emit extentChanged();
655 }
656 
657 void QgsComposerMap::setSceneRect( const QRectF& rectangle )
658 {
659  double w = rectangle.width();
660  double h = rectangle.height();
661  //prepareGeometryChange();
662 
663  QgsComposerItem::setSceneRect( rectangle );
664 
665  //QGraphicsRectItem::update();
666  double newHeight = mExtent.width() * h / w ;
668  mCacheUpdated = false;
669 
671  update();
672  emit itemChanged();
673  emit extentChanged();
674 }
675 
677 {
678  if ( mExtent == extent )
679  {
680  return;
681  }
682  mExtent = extent;
683 
684  //adjust height
685  QRectF currentRect = rect();
686 
687  double newHeight = currentRect.width() * extent.height() / extent.width();
688 
689  setSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
690  updateItem();
691 }
692 
694 {
695  if ( mAtlasFeatureExtent == extent )
696  {
697  return;
698  }
699 
700  //don't adjust size of item, instead adjust size of bounds to fit
701  QgsRectangle newExtent = extent;
702 
703  //Make sure the width/height ratio is the same as the map item size
704  double currentWidthHeightRatio = rect().width() / rect().height();
705  double newWidthHeightRatio = newExtent.width() / newExtent.height();
706 
707  if ( currentWidthHeightRatio < newWidthHeightRatio )
708  {
709  //enlarge height of new extent, ensuring the map center stays the same
710  double newHeight = newExtent.width() / currentWidthHeightRatio;
711  double deltaHeight = newHeight - newExtent.height();
712  newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
713  newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
714  }
715  else if ( currentWidthHeightRatio >= newWidthHeightRatio )
716  {
717  //enlarge width of new extent, ensuring the map center stays the same
718  double newWidth = currentWidthHeightRatio * newExtent.height();
719  double deltaWidth = newWidth - newExtent.width();
720  newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
721  newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
722  }
723 
724  mAtlasFeatureExtent = newExtent;
725  mCacheUpdated = false;
726  emit preparedForAtlas();
727  updateItem();
728  emit itemChanged();
729  emit extentChanged();
730 }
731 
733 {
734  //atlas preview has been toggled, so update item and extents
735  mCacheUpdated = false;
736  updateItem();
737  emit itemChanged();
738  emit extentChanged();
739 }
740 
742 {
743  //non-const version
745  {
746  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
747  //return the current temporary atlas feature extent
748  return &mAtlasFeatureExtent;
749  }
750  else
751  {
752  //otherwise return permenant user set extent
753  return &mExtent;
754  }
755 }
756 
758 {
759  //const version
761  {
762  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
763  //return the current temporary atlas feature extent
764  return &mAtlasFeatureExtent;
765  }
766  else
767  {
768  //otherwise return permenant user set extent
769  return &mExtent;
770  }
771 }
772 
773 void QgsComposerMap::setNewScale( double scaleDenominator )
774 {
775  double currentScaleDenominator = scale();
776 
777  if ( scaleDenominator == currentScaleDenominator )
778  {
779  return;
780  }
781 
782  double scaleRatio = scaleDenominator / currentScaleDenominator;
783  currentMapExtent()->scale( scaleRatio );
784  mCacheUpdated = false;
785  cache();
786  update();
787  emit itemChanged();
788  emit extentChanged();
789 }
790 
792 {
793  mPreviewMode = m;
794  emit itemChanged();
795 }
796 
797 void QgsComposerMap::setOffset( double xOffset, double yOffset )
798 {
799  mXOffset = xOffset;
800  mYOffset = yOffset;
801 }
802 
804 {
805  //kept for api compatibility with QGIS 2.0
806  setMapRotation( r );
807 }
808 
810 {
811  mMapRotation = r;
812  emit mapRotationChanged( r );
813  emit itemChanged();
814  update();
815 }
816 
818 {
819  if ( !mUpdatesEnabled )
820  {
821  return;
822  }
823 
825  {
826  cache();
827  }
829 }
830 
832 {
833  QStringList layers = mComposition->mapSettings().layers();
834 
835  QStringList::const_iterator layer_it = layers.constBegin();
836  QgsMapLayer* currentLayer = 0;
837 
838  for ( ; layer_it != layers.constEnd(); ++layer_it )
839  {
840  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
841  if ( currentLayer )
842  {
843  QgsRasterLayer* currentRasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
844  if ( currentRasterLayer )
845  {
846  const QgsRasterDataProvider* rasterProvider = 0;
847  if (( rasterProvider = currentRasterLayer->dataProvider() ) )
848  {
849  if ( rasterProvider->name() == "wms" )
850  {
851  return true;
852  }
853  }
854  }
855  }
856  }
857  return false;
858 }
859 
861 {
862  // check if map contains advanced effects like blend modes, or flattened layers for transparency
863 
864  QStringList layers = mComposition->mapSettings().layers();
865 
866  QStringList::const_iterator layer_it = layers.constBegin();
867  QgsMapLayer* currentLayer = 0;
868 
869  for ( ; layer_it != layers.constEnd(); ++layer_it )
870  {
871  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
872  if ( currentLayer )
873  {
874  if ( currentLayer->blendMode() != QPainter::CompositionMode_SourceOver )
875  {
876  return true;
877  }
878  // if vector layer, check labels and feature blend mode
879  QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
880  if ( currentVectorLayer )
881  {
882  if ( currentVectorLayer->layerTransparency() != 0 )
883  {
884  return true;
885  }
886  if ( currentVectorLayer->featureBlendMode() != QPainter::CompositionMode_SourceOver )
887  {
888  return true;
889  }
890  // check label blend modes
891  if ( QgsPalLabeling::staticWillUseLayer( currentVectorLayer ) )
892  {
893  // Check all label blending properties
894  QgsPalLayerSettings layerSettings = QgsPalLayerSettings::fromLayer( currentVectorLayer );
895  if (( layerSettings.blendMode != QPainter::CompositionMode_SourceOver ) ||
896  ( layerSettings.bufferSize != 0 && layerSettings.bufferBlendMode != QPainter::CompositionMode_SourceOver ) ||
897  ( layerSettings.shadowDraw && layerSettings.shadowBlendMode != QPainter::CompositionMode_SourceOver ) ||
898  ( layerSettings.shapeDraw && layerSettings.shapeBlendMode != QPainter::CompositionMode_SourceOver ) )
899  {
900  return true;
901  }
902  }
903  }
904  }
905  }
906 
907  return false;
908 }
909 
911 {
912  //connect signal from layer registry to update in case of new or deleted layers
914  if ( layerRegistry )
915  {
916  connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( updateCachedImage() ) );
917  connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( updateCachedImage() ) );
918  }
919 }
920 
921 bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
922 {
923  if ( elem.isNull() )
924  {
925  return false;
926  }
927 
928  QDomElement composerMapElem = doc.createElement( "ComposerMap" );
929  composerMapElem.setAttribute( "id", mId );
930 
931  //previewMode
932  if ( mPreviewMode == Cache )
933  {
934  composerMapElem.setAttribute( "previewMode", "Cache" );
935  }
936  else if ( mPreviewMode == Render )
937  {
938  composerMapElem.setAttribute( "previewMode", "Render" );
939  }
940  else //rectangle
941  {
942  composerMapElem.setAttribute( "previewMode", "Rectangle" );
943  }
944 
945  if ( mKeepLayerSet )
946  {
947  composerMapElem.setAttribute( "keepLayerSet", "true" );
948  }
949  else
950  {
951  composerMapElem.setAttribute( "keepLayerSet", "false" );
952  }
953 
954  if ( mDrawCanvasItems )
955  {
956  composerMapElem.setAttribute( "drawCanvasItems", "true" );
957  }
958  else
959  {
960  composerMapElem.setAttribute( "drawCanvasItems", "false" );
961  }
962 
963  //overview map frame
964  QDomElement overviewFrameElem = doc.createElement( "overviewFrame" );
965  overviewFrameElem.setAttribute( "overviewFrameMap", mOverviewFrameMapId );
966  overviewFrameElem.setAttribute( "overviewBlendMode", QgsMapRenderer::getBlendModeEnum( mOverviewBlendMode ) );
967  if ( mOverviewInverted )
968  {
969  overviewFrameElem.setAttribute( "overviewInverted", "true" );
970  }
971  else
972  {
973  overviewFrameElem.setAttribute( "overviewInverted", "false" );
974  }
975 
976  overviewFrameElem.setAttribute( "overviewCentered", mOverviewCentered ? "true" : "false" );
977 
978  QDomElement overviewFrameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mOverviewFrameMapSymbol, doc );
979  overviewFrameElem.appendChild( overviewFrameStyleElem );
980  composerMapElem.appendChild( overviewFrameElem );
981 
982 
983  //extent
984  QDomElement extentElem = doc.createElement( "Extent" );
985  extentElem.setAttribute( "xmin", qgsDoubleToString( mExtent.xMinimum() ) );
986  extentElem.setAttribute( "xmax", qgsDoubleToString( mExtent.xMaximum() ) );
987  extentElem.setAttribute( "ymin", qgsDoubleToString( mExtent.yMinimum() ) );
988  extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) );
989  composerMapElem.appendChild( extentElem );
990 
991  //map rotation
992  composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) );
993 
994  //layer set
995  QDomElement layerSetElem = doc.createElement( "LayerSet" );
996  QStringList::const_iterator layerIt = mLayerSet.constBegin();
997  for ( ; layerIt != mLayerSet.constEnd(); ++layerIt )
998  {
999  QDomElement layerElem = doc.createElement( "Layer" );
1000  QDomText layerIdText = doc.createTextNode( *layerIt );
1001  layerElem.appendChild( layerIdText );
1002  layerSetElem.appendChild( layerElem );
1003  }
1004  composerMapElem.appendChild( layerSetElem );
1005 
1006  //overview map frame
1007  composerMapElem.setAttribute( "overviewFrameMap", mOverviewFrameMapId );
1008 
1009  //grid
1010  QDomElement gridElem = doc.createElement( "Grid" );
1011  gridElem.setAttribute( "show", mGridEnabled );
1012  gridElem.setAttribute( "gridStyle", mGridStyle );
1013  gridElem.setAttribute( "intervalX", qgsDoubleToString( mGridIntervalX ) );
1014  gridElem.setAttribute( "intervalY", qgsDoubleToString( mGridIntervalY ) );
1015  gridElem.setAttribute( "offsetX", qgsDoubleToString( mGridOffsetX ) );
1016  gridElem.setAttribute( "offsetY", qgsDoubleToString( mGridOffsetY ) );
1017  gridElem.setAttribute( "crossLength", qgsDoubleToString( mCrossLength ) );
1018  gridElem.setAttribute( "gridFrameStyle", mGridFrameStyle );
1019  gridElem.setAttribute( "gridFrameWidth", qgsDoubleToString( mGridFrameWidth ) );
1020  gridElem.setAttribute( "gridFramePenThickness", qgsDoubleToString( mGridFramePenThickness ) );
1021  //grid frame pen color
1022  QDomElement framePenColorElem = doc.createElement( "framePenColor" );
1023  framePenColorElem.setAttribute( "red", mGridFramePenColor.red() );
1024  framePenColorElem.setAttribute( "green", mGridFramePenColor.green() );
1025  framePenColorElem.setAttribute( "blue", mGridFramePenColor.blue() );
1026  framePenColorElem.setAttribute( "alpha", mGridFramePenColor.alpha() );
1027  gridElem.appendChild( framePenColorElem );
1028  //grid frame fill colors
1029  QDomElement frameFillColor1Elem = doc.createElement( "frameFillColor1" );
1030  frameFillColor1Elem.setAttribute( "red", mGridFrameFillColor1.red() );
1031  frameFillColor1Elem.setAttribute( "green", mGridFrameFillColor1.green() );
1032  frameFillColor1Elem.setAttribute( "blue", mGridFrameFillColor1.blue() );
1033  frameFillColor1Elem.setAttribute( "alpha", mGridFrameFillColor1.alpha() );
1034  gridElem.appendChild( frameFillColor1Elem );
1035  QDomElement frameFillColor2Elem = doc.createElement( "frameFillColor2" );
1036  frameFillColor2Elem.setAttribute( "red", mGridFrameFillColor2.red() );
1037  frameFillColor2Elem.setAttribute( "green", mGridFrameFillColor2.green() );
1038  frameFillColor2Elem.setAttribute( "blue", mGridFrameFillColor2.blue() );
1039  frameFillColor2Elem.setAttribute( "alpha", mGridFrameFillColor2.alpha() );
1040  gridElem.appendChild( frameFillColor2Elem );
1041 
1042  gridElem.setAttribute( "gridBlendMode", QgsMapRenderer::getBlendModeEnum( mGridBlendMode ) );
1043  QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc );
1044  gridElem.appendChild( gridLineStyleElem );
1045 
1046  //grid annotation
1047  QDomElement annotationElem = doc.createElement( "Annotation" );
1048  annotationElem.setAttribute( "format", mGridAnnotationFormat );
1049  annotationElem.setAttribute( "show", mShowGridAnnotation );
1050  annotationElem.setAttribute( "leftPosition", mLeftGridAnnotationPosition );
1051  annotationElem.setAttribute( "rightPosition", mRightGridAnnotationPosition );
1052  annotationElem.setAttribute( "topPosition", mTopGridAnnotationPosition );
1053  annotationElem.setAttribute( "bottomPosition", mBottomGridAnnotationPosition );
1054  annotationElem.setAttribute( "leftDirection", mLeftGridAnnotationDirection );
1055  annotationElem.setAttribute( "rightDirection", mRightGridAnnotationDirection );
1056  annotationElem.setAttribute( "topDirection", mTopGridAnnotationDirection );
1057  annotationElem.setAttribute( "bottomDirection", mBottomGridAnnotationDirection );
1058  annotationElem.setAttribute( "frameDistance", QString::number( mAnnotationFrameDistance ) );
1059  annotationElem.setAttribute( "font", mGridAnnotationFont.toString() );
1060  annotationElem.setAttribute( "precision", mGridAnnotationPrecision );
1061  //annotation font color
1062  QDomElement annotationFontColorElem = doc.createElement( "fontColor" );
1063  annotationFontColorElem.setAttribute( "red", mGridAnnotationFontColor.red() );
1064  annotationFontColorElem.setAttribute( "green", mGridAnnotationFontColor.green() );
1065  annotationFontColorElem.setAttribute( "blue", mGridAnnotationFontColor.blue() );
1066  annotationFontColorElem.setAttribute( "alpha", mGridAnnotationFontColor.alpha() );
1067  annotationElem.appendChild( annotationFontColorElem );
1068 
1069  gridElem.appendChild( annotationElem );
1070  composerMapElem.appendChild( gridElem );
1071 
1072  //atlas
1073  QDomElement atlasElem = doc.createElement( "AtlasMap" );
1074  atlasElem.setAttribute( "atlasDriven", mAtlasDriven );
1075  atlasElem.setAttribute( "fixedScale", mAtlasFixedScale );
1076  atlasElem.setAttribute( "margin", qgsDoubleToString( mAtlasMargin ) );
1077  composerMapElem.appendChild( atlasElem );
1078 
1079  elem.appendChild( composerMapElem );
1080  return _writeXML( composerMapElem, doc );
1081 }
1082 
1083 bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& doc )
1084 {
1085  if ( itemElem.isNull() )
1086  {
1087  return false;
1088  }
1089 
1090  QString idRead = itemElem.attribute( "id", "not found" );
1091  if ( idRead != "not found" )
1092  {
1093  mId = idRead.toInt();
1094  }
1096 
1097  //previewMode
1098  QString previewMode = itemElem.attribute( "previewMode" );
1099  if ( previewMode == "Cache" )
1100  {
1101  mPreviewMode = Cache;
1102  }
1103  else if ( previewMode == "Render" )
1104  {
1105  mPreviewMode = Render;
1106  }
1107  else
1108  {
1110  }
1111 
1112  QDomElement overviewFrameElem = itemElem.firstChildElement( "overviewFrame" );
1113  if ( !overviewFrameElem.isNull() )
1114  {
1115  setOverviewFrameMap( overviewFrameElem.attribute( "overviewFrameMap", "-1" ).toInt() );
1116  setOverviewBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) overviewFrameElem.attribute( "overviewBlendMode", "0" ).toUInt() ) );
1117 
1118  QString overviewInvertedFlag = overviewFrameElem.attribute( "overviewInverted" );
1119  if ( overviewInvertedFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1120  {
1121  setOverviewInverted( true );
1122  }
1123  else
1124  {
1125  setOverviewInverted( false );
1126  }
1127 
1128  if ( overviewFrameElem.attribute( "overviewCentered" ).compare( "true", Qt::CaseInsensitive ) == 0 )
1129  {
1130  mOverviewCentered = true;
1131  }
1132  else
1133  {
1134  mOverviewCentered = false;
1135  }
1136 
1137  QDomElement overviewFrameSymbolElem = overviewFrameElem.firstChildElement( "symbol" );
1138  if ( !overviewFrameSymbolElem.isNull() )
1139  {
1140  delete mOverviewFrameMapSymbol;
1141  mOverviewFrameMapSymbol = dynamic_cast<QgsFillSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( overviewFrameSymbolElem ) );
1142  }
1143  }
1144 
1145  //extent
1146  QDomNodeList extentNodeList = itemElem.elementsByTagName( "Extent" );
1147  if ( extentNodeList.size() > 0 )
1148  {
1149  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
1150  double xmin, xmax, ymin, ymax;
1151  xmin = extentElem.attribute( "xmin" ).toDouble();
1152  xmax = extentElem.attribute( "xmax" ).toDouble();
1153  ymin = extentElem.attribute( "ymin" ).toDouble();
1154  ymax = extentElem.attribute( "ymax" ).toDouble();
1155  setNewExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
1156  }
1157 
1158  //map rotation
1159  if ( itemElem.attribute( "mapRotation", "0" ).toDouble() != 0 )
1160  {
1161  mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble();
1162  }
1163 
1164  //mKeepLayerSet flag
1165  QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
1166  if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1167  {
1168  mKeepLayerSet = true;
1169  }
1170  else
1171  {
1172  mKeepLayerSet = false;
1173  }
1174 
1175  QString drawCanvasItemsFlag = itemElem.attribute( "drawCanvasItems" );
1176  if ( drawCanvasItemsFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1177  {
1178  mDrawCanvasItems = true;
1179  }
1180  else
1181  {
1182  mDrawCanvasItems = false;
1183  }
1184 
1185  //mLayerSet
1186  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( "LayerSet" );
1187  QStringList layerSet;
1188  if ( layerSetNodeList.size() > 0 )
1189  {
1190  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
1191  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( "Layer" );
1192  for ( int i = 0; i < layerIdNodeList.size(); ++i )
1193  {
1194  layerSet << layerIdNodeList.at( i ).toElement().text();
1195  }
1196  }
1197  mLayerSet = layerSet;
1198 
1199  mDrawing = false;
1200  mNumCachedLayers = 0;
1201  mCacheUpdated = false;
1202 
1203  //grid
1204  QDomNodeList gridNodeList = itemElem.elementsByTagName( "Grid" );
1205  if ( gridNodeList.size() > 0 )
1206  {
1207  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
1208  mGridEnabled = ( gridElem.attribute( "show", "0" ) != "0" );
1209  mGridStyle = QgsComposerMap::GridStyle( gridElem.attribute( "gridStyle", "0" ).toInt() );
1210  mGridIntervalX = gridElem.attribute( "intervalX", "0" ).toDouble();
1211  mGridIntervalY = gridElem.attribute( "intervalY", "0" ).toDouble();
1212  mGridOffsetX = gridElem.attribute( "offsetX", "0" ).toDouble();
1213  mGridOffsetY = gridElem.attribute( "offsetY", "0" ).toDouble();
1214  mCrossLength = gridElem.attribute( "crossLength", "3" ).toDouble();
1215  mGridFrameStyle = ( QgsComposerMap::GridFrameStyle )gridElem.attribute( "gridFrameStyle", "0" ).toInt();
1216  mGridFrameWidth = gridElem.attribute( "gridFrameWidth", "2.0" ).toDouble();
1217  mGridFramePenThickness = gridElem.attribute( "gridFramePenThickness", "0.5" ).toDouble();
1218 
1219  //grid frame pen color
1220  QDomNodeList gridFramePenColorList = gridElem.elementsByTagName( "framePenColor" );
1221  if ( gridFramePenColorList.size() > 0 )
1222  {
1223  QDomElement penColorElem = gridFramePenColorList.at( 0 ).toElement();
1224  int red = penColorElem.attribute( "red", "0" ).toInt();
1225  int green = penColorElem.attribute( "green", "0" ).toInt();
1226  int blue = penColorElem.attribute( "blue", "0" ).toInt();
1227  int alpha = penColorElem.attribute( "alpha", "255" ).toInt();
1228  mGridFramePenColor = QColor( red, green, blue, alpha );
1229  }
1230  else
1231  {
1232  mGridFramePenColor = QColor( 0, 0, 0 );
1233  }
1234  //grid frame fill color 1
1235  QDomNodeList gridFrameFillColor1List = gridElem.elementsByTagName( "frameFillColor1" );
1236  if ( gridFrameFillColor1List.size() > 0 )
1237  {
1238  QDomElement fillColorElem = gridFrameFillColor1List.at( 0 ).toElement();
1239  int red = fillColorElem.attribute( "red", "0" ).toInt();
1240  int green = fillColorElem.attribute( "green", "0" ).toInt();
1241  int blue = fillColorElem.attribute( "blue", "0" ).toInt();
1242  int alpha = fillColorElem.attribute( "alpha", "255" ).toInt();
1243  mGridFrameFillColor1 = QColor( red, green, blue, alpha );
1244  }
1245  else
1246  {
1247  mGridFrameFillColor1 = Qt::white;
1248  }
1249  //grid frame fill color 2
1250  QDomNodeList gridFrameFillColor2List = gridElem.elementsByTagName( "frameFillColor2" );
1251  if ( gridFrameFillColor2List.size() > 0 )
1252  {
1253  QDomElement fillColorElem = gridFrameFillColor2List.at( 0 ).toElement();
1254  int red = fillColorElem.attribute( "red", "0" ).toInt();
1255  int green = fillColorElem.attribute( "green", "0" ).toInt();
1256  int blue = fillColorElem.attribute( "blue", "0" ).toInt();
1257  int alpha = fillColorElem.attribute( "alpha", "255" ).toInt();
1258  mGridFrameFillColor2 = QColor( red, green, blue, alpha );
1259  }
1260  else
1261  {
1262  mGridFrameFillColor2 = Qt::black;
1263  }
1264 
1265  setGridBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) gridElem.attribute( "gridBlendMode", "0" ).toUInt() ) );
1266 
1267  QDomElement gridSymbolElem = gridElem.firstChildElement( "symbol" );
1268  delete mGridLineSymbol;
1269  if ( gridSymbolElem.isNull( ) )
1270  {
1271  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
1273  mGridLineSymbol->setWidth( gridElem.attribute( "penWidth", "0" ).toDouble() );
1274  mGridLineSymbol->setColor( QColor( gridElem.attribute( "penColorRed", "0" ).toInt(),
1275  gridElem.attribute( "penColorGreen", "0" ).toInt(),
1276  gridElem.attribute( "penColorBlue", "0" ).toInt() ) );
1277  }
1278  else
1279  {
1280  mGridLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( gridSymbolElem ) );
1281  }
1282 
1283  QDomNodeList annotationNodeList = gridElem.elementsByTagName( "Annotation" );
1284  if ( annotationNodeList.size() > 0 )
1285  {
1286  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
1287  mShowGridAnnotation = ( annotationElem.attribute( "show", "0" ) != "0" );
1288  mGridAnnotationFormat = QgsComposerMap::GridAnnotationFormat( annotationElem.attribute( "format", "0" ).toInt() );
1289  mLeftGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "leftPosition", "0" ).toInt() );
1290  mRightGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "rightPosition", "0" ).toInt() );
1291  mTopGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "topPosition", "0" ).toInt() );
1292  mBottomGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "bottomPosition", "0" ).toInt() );
1293  mLeftGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "leftDirection", "0" ).toInt() );
1294  mRightGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "rightDirection", "0" ).toInt() );
1295  mTopGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "topDirection", "0" ).toInt() );
1296  mBottomGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "bottomDirection", "0" ).toInt() );
1297  mAnnotationFrameDistance = annotationElem.attribute( "frameDistance", "0" ).toDouble();
1298  mGridAnnotationFont.fromString( annotationElem.attribute( "font", "" ) );
1299 
1300  //annotation font color
1301  QDomNodeList annotationFontColorList = annotationElem.elementsByTagName( "fontColor" );
1302  if ( annotationFontColorList.size() > 0 )
1303  {
1304  QDomElement fontColorElem = annotationFontColorList.at( 0 ).toElement();
1305  int red = fontColorElem.attribute( "red", "0" ).toInt();
1306  int green = fontColorElem.attribute( "green", "0" ).toInt();
1307  int blue = fontColorElem.attribute( "blue", "0" ).toInt();
1308  int alpha = fontColorElem.attribute( "alpha", "255" ).toInt();
1309  mGridAnnotationFontColor = QColor( red, green, blue, alpha );
1310  }
1311  else
1312  {
1313  mGridAnnotationFontColor = QColor( 0, 0, 0 );
1314  }
1315 
1316  mGridAnnotationPrecision = annotationElem.attribute( "precision", "3" ).toInt();
1317  }
1318  }
1319 
1320  //atlas
1321  QDomNodeList atlasNodeList = itemElem.elementsByTagName( "AtlasMap" );
1322  if ( atlasNodeList.size() > 0 )
1323  {
1324  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
1325  mAtlasDriven = ( atlasElem.attribute( "atlasDriven", "0" ) != "0" );
1326  mAtlasFixedScale = ( atlasElem.attribute( "fixedScale", "0" ) != "0" );
1327  mAtlasMargin = atlasElem.attribute( "margin", "0.1" ).toDouble();
1328  }
1329 
1330  //restore general composer item properties
1331  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
1332  if ( composerItemList.size() > 0 )
1333  {
1334  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
1335 
1336  if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
1337  {
1338  //in versions prior to 2.1 map rotation was stored in the rotation attribute
1339  mMapRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
1340  }
1341 
1342  _readXML( composerItemElem, doc );
1343  }
1344 
1346  emit itemChanged();
1347  return true;
1348 }
1349 
1351 {
1353 }
1354 
1356 {
1357  if ( mLayerSet.size() < 1 )
1358  {
1359  return;
1360  }
1361 
1362  //if layer set is fixed, do a lookup in the layer registry to also find the non-visible layers
1363  QStringList currentLayerSet;
1364  if ( mKeepLayerSet )
1365  {
1366  currentLayerSet = QgsMapLayerRegistry::instance()->mapLayers().uniqueKeys();
1367  }
1368  else //only consider layers visible in the map
1369  {
1370  currentLayerSet = mComposition->mapSettings().layers();
1371  }
1372 
1373  for ( int i = mLayerSet.size() - 1; i >= 0; --i )
1374  {
1375  if ( !currentLayerSet.contains( mLayerSet.at( i ) ) )
1376  {
1377  mLayerSet.removeAt( i );
1378  }
1379  }
1380 }
1381 
1382 void QgsComposerMap::drawGrid( QPainter* p )
1383 {
1384  QList< QPair< double, QLineF > > verticalLines;
1385  yGridLines( verticalLines );
1386  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
1387  QList< QPair< double, QLineF > > horizontalLines;
1388  xGridLines( horizontalLines );
1389  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
1390 
1391  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
1392  p->setClipRect( thisPaintRect );
1393 
1394  // set the blend mode for drawing grid lines
1395  p->save();
1396  p->setCompositionMode( mGridBlendMode );
1397 
1398  //simpler approach: draw vertical lines first, then horizontal ones
1400  {
1401  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1402  {
1403  drawGridLine( vIt->second, p );
1404  }
1405 
1406  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1407  {
1408  drawGridLine( hIt->second, p );
1409  }
1410  }
1411  else //cross
1412  {
1413  QPointF intersectionPoint, crossEnd1, crossEnd2;
1414  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1415  {
1416  //start mark
1417  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
1418  drawGridLine( QLineF( vIt->second.p1(), crossEnd1 ), p );
1419 
1420  //test for intersection with every horizontal line
1421  hIt = horizontalLines.constBegin();
1422  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1423  {
1424  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
1425  {
1426  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength );
1427  crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength );
1428  drawGridLine( QLineF( crossEnd1, crossEnd2 ), p );
1429  }
1430  }
1431  //end mark
1432  QPointF crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
1433  drawGridLine( QLineF( vIt->second.p2(), crossEnd2 ), p );
1434  }
1435 
1436  hIt = horizontalLines.constBegin();
1437  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1438  {
1439  //start mark
1440  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
1441  drawGridLine( QLineF( hIt->second.p1(), crossEnd1 ), p );
1442 
1443  vIt = verticalLines.constBegin();
1444  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1445  {
1446  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
1447  {
1448  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength );
1449  crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength );
1450  drawGridLine( QLineF( crossEnd1, crossEnd2 ), p );
1451  }
1452  }
1453  //end mark
1454  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
1455  drawGridLine( QLineF( hIt->second.p2(), crossEnd1 ), p );
1456  }
1457  }
1458  // reset composition mode
1459  p->restore();
1460 
1461  p->setClipRect( thisPaintRect , Qt::NoClip );
1462 
1464  {
1465  drawGridFrame( p, horizontalLines, verticalLines );
1466  }
1467 
1468  if ( mShowGridAnnotation )
1469  {
1470  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
1471  }
1472 
1473 }
1474 
1475 void QgsComposerMap::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
1476 {
1477  //Sort the coordinate positions for each side
1478  QMap< double, double > leftGridFrame;
1479  QMap< double, double > rightGridFrame;
1480  QMap< double, double > topGridFrame;
1481  QMap< double, double > bottomGridFrame;
1482 
1483  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
1484 
1485  drawGridFrameBorder( p, leftGridFrame, QgsComposerMap::Left );
1486  drawGridFrameBorder( p, rightGridFrame, QgsComposerMap::Right );
1487  drawGridFrameBorder( p, topGridFrame, QgsComposerMap::Top );
1488  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMap::Bottom );
1489 }
1490 
1491 void QgsComposerMap::drawGridLine( const QLineF& line, QPainter* p )
1492 {
1493  if ( !mGridLineSymbol || !p )
1494  {
1495  return;
1496  }
1497 
1498  //setup render context
1499  QgsRenderContext context;
1500  context.setPainter( p );
1501  if ( mPreviewMode == Rectangle )
1502  {
1503  return;
1504  }
1505  else
1506  {
1507  context.setScaleFactor( 1.0 );
1508  context.setRasterScaleFactor( mComposition->printResolution() / 25.4 );
1509  }
1510 
1511  QPolygonF poly;
1512  poly << line.p1() << line.p2();
1513  mGridLineSymbol->startRender( context );
1514  mGridLineSymbol->renderPolyline( poly, 0, context );
1515  mGridLineSymbol->stopRender( context );
1516 }
1517 
1518 void QgsComposerMap::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, Border border )
1519 {
1520  double currentCoord = - mGridFrameWidth;
1521  bool color1 = true;
1522  double x = 0;
1523  double y = 0;
1524  double width = 0;
1525  double height = 0;
1526 
1527  QMap< double, double > pos = borderPos;
1528  pos.insert( 0, 0 );
1529  if ( border == Left || border == Right )
1530  {
1531  pos.insert( rect().height(), rect().height() );
1532  pos.insert( rect().height() + mGridFrameWidth, rect().height() + mGridFrameWidth );
1533  }
1534  else //top or bottom
1535  {
1536  pos.insert( rect().width(), rect().width() );
1537  pos.insert( rect().width() + mGridFrameWidth, rect().width() + mGridFrameWidth );
1538  }
1539 
1540  //set pen to current frame pen
1541  QPen framePen = QPen( mGridFramePenColor );
1542  framePen.setWidthF( mGridFramePenThickness );
1543  framePen.setJoinStyle( Qt::MiterJoin );
1544  p->setPen( framePen );
1545 
1546  QMap< double, double >::const_iterator posIt = pos.constBegin();
1547  for ( ; posIt != pos.constEnd(); ++posIt )
1548  {
1549  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
1550  if ( border == Left || border == Right )
1551  {
1552  height = posIt.key() - currentCoord;
1553  width = mGridFrameWidth;
1554  x = ( border == Left ) ? -mGridFrameWidth : rect().width();
1555  y = currentCoord;
1556  }
1557  else //top or bottom
1558  {
1559  height = mGridFrameWidth;
1560  width = posIt.key() - currentCoord;
1561  x = currentCoord;
1562  y = ( border == Top ) ? -mGridFrameWidth : rect().height();
1563  }
1564  p->drawRect( QRectF( x, y, width, height ) );
1565  currentCoord = posIt.key();
1566  color1 = !color1;
1567  }
1568 }
1569 
1570 void QgsComposerMap::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
1571 {
1572  if ( !p )
1573  {
1574  return;
1575  }
1576 
1577 
1578  QString currentAnnotationString;
1579  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1580  for ( ; it != hLines.constEnd(); ++it )
1581  {
1582  currentAnnotationString = gridAnnotationString( it->first, Latitude );
1583  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
1584  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
1585  }
1586 
1587  it = vLines.constBegin();
1588  for ( ; it != vLines.constEnd(); ++it )
1589  {
1590  currentAnnotationString = gridAnnotationString( it->first, Longitude );
1591  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
1592  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
1593  }
1594 }
1595 
1596 void QgsComposerMap::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString )
1597 {
1598  Border frameBorder = borderForLineCoord( pos );
1599  double textWidth = textWidthMillimeters( mGridAnnotationFont, annotationString );
1600  //relevant for annotations is the height of digits
1601  double textHeight = fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
1602  double xpos = pos.x();
1603  double ypos = pos.y();
1604  int rotation = 0;
1605 
1606  double gridFrameDistance = ( mGridFrameStyle == NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
1607 
1608  if ( frameBorder == Left )
1609  {
1610 
1612  {
1614  {
1615  xpos += textHeight + mAnnotationFrameDistance;
1616  ypos += textWidth / 2.0;
1617  rotation = 270;
1618  }
1619  else
1620  {
1621  xpos += mAnnotationFrameDistance;
1622  ypos += textHeight / 2.0;
1623  }
1624  }
1625  else if ( mLeftGridAnnotationPosition == OutsideMapFrame ) //Outside map frame
1626  {
1628  {
1629  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
1630  ypos += textWidth / 2.0;
1631  rotation = 270;
1632  }
1633  else
1634  {
1635  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1636  ypos += textHeight / 2.0;
1637  }
1638  }
1639  else
1640  {
1641  return;
1642  }
1643 
1644  }
1645  else if ( frameBorder == Right )
1646  {
1648  {
1650  {
1651  xpos -= mAnnotationFrameDistance;
1652  ypos += textWidth / 2.0;
1653  rotation = 270;
1654  }
1655  else
1656  {
1657  xpos -= textWidth + mAnnotationFrameDistance;
1658  ypos += textHeight / 2.0;
1659  }
1660  }
1661  else if ( mRightGridAnnotationPosition == OutsideMapFrame )//OutsideMapFrame
1662  {
1664  {
1665  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
1666  ypos += textWidth / 2.0;
1667  rotation = 270;
1668  }
1669  else //Horizontal
1670  {
1671  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1672  ypos += textHeight / 2.0;
1673  }
1674  }
1675  else
1676  {
1677  return;
1678  }
1679  }
1680  else if ( frameBorder == Bottom )
1681  {
1683  {
1685  {
1686  ypos -= mAnnotationFrameDistance;
1687  xpos -= textWidth / 2.0;
1688  }
1689  else //Vertical
1690  {
1691  xpos += textHeight / 2.0;
1692  ypos -= mAnnotationFrameDistance;
1693  rotation = 270;
1694  }
1695  }
1696  else if ( mBottomGridAnnotationPosition == OutsideMapFrame ) //OutsideMapFrame
1697  {
1699  {
1700  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
1701  xpos -= textWidth / 2.0;
1702  }
1703  else //Vertical
1704  {
1705  xpos += textHeight / 2.0;
1706  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1707  rotation = 270;
1708  }
1709  }
1710  else
1711  {
1712  return;
1713  }
1714  }
1715  else //Top
1716  {
1718  {
1720  {
1721  xpos -= textWidth / 2.0;
1722  ypos += textHeight + mAnnotationFrameDistance;
1723  }
1724  else //Vertical
1725  {
1726  xpos += textHeight / 2.0;
1727  ypos += textWidth + mAnnotationFrameDistance;
1728  rotation = 270;
1729  }
1730  }
1731  else if ( mTopGridAnnotationPosition == OutsideMapFrame ) //OutsideMapFrame
1732  {
1734  {
1735  xpos -= textWidth / 2.0;
1736  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1737  }
1738  else //Vertical
1739  {
1740  xpos += textHeight / 2.0;
1741  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1742  rotation = 270;
1743  }
1744  }
1745  else
1746  {
1747  return;
1748  }
1749  }
1750 
1751  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
1752 }
1753 
1754 void QgsComposerMap::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText )
1755 {
1756  p->save();
1757  p->translate( pos );
1758  p->rotate( rotation );
1759  p->setPen( QPen( QColor( mGridAnnotationFontColor ) ) );
1760  drawText( p, 0, 0, annotationText, mGridAnnotationFont );
1761  p->restore();
1762 }
1763 
1765 {
1766  if ( mGridAnnotationFormat == Decimal )
1767  {
1768  return QString::number( value, 'f', mGridAnnotationPrecision );
1769  }
1770 
1771  QgsPoint p;
1772  p.setX( coord == Longitude ? value : 0 );
1773  p.setY( coord == Longitude ? 0 : value );
1774 
1775  QString annotationString;
1777  {
1778  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
1779  }
1780  else //DegreeMinuteSecond
1781  {
1782  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
1783  }
1784 
1785  QStringList split = annotationString.split( "," );
1786  if ( coord == Longitude )
1787  {
1788  return split.at( 0 );
1789  }
1790  else
1791  {
1792  if ( split.size() < 2 )
1793  {
1794  return "";
1795  }
1796  return split.at( 1 );
1797  }
1798 }
1799 
1800 int QgsComposerMap::xGridLines( QList< QPair< double, QLineF > >& lines ) const
1801 {
1802  lines.clear();
1803  if ( mGridIntervalY <= 0.0 )
1804  {
1805  return 1;
1806  }
1807 
1808 
1809  QPolygonF mapPolygon = transformedMapPolygon();
1810  QRectF mapBoundingRect = mapPolygon.boundingRect();
1811 
1812  //consider to round up to the next step in case the left boundary is > 0
1813  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1814  double currentLevel = ( int )(( mapBoundingRect.top() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1815 
1816  if ( qgsDoubleNear( mMapRotation, 0.0 ) )
1817  {
1818  //no rotation. Do it 'the easy way'
1819 
1820  double yCanvasCoord;
1821 
1822  while ( currentLevel <= mapBoundingRect.bottom() )
1823  {
1824  yCanvasCoord = rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1825  lines.push_back( qMakePair( currentLevel, QLineF( 0, yCanvasCoord, rect().width(), yCanvasCoord ) ) );
1826  currentLevel += mGridIntervalY;
1827  }
1828  }
1829 
1830  //the four border lines
1831  QVector<QLineF> borderLines;
1832  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1833  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1834  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1835  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1836 
1837  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1838 
1839  while ( currentLevel <= mapBoundingRect.bottom() )
1840  {
1841  intersectionList.clear();
1842  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1843 
1844  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1845  for ( ; it != borderLines.constEnd(); ++it )
1846  {
1847  QPointF intersectionPoint;
1848  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1849  {
1850  intersectionList.push_back( intersectionPoint );
1851  if ( intersectionList.size() >= 2 )
1852  {
1853  break; //we already have two intersections, skip further tests
1854  }
1855  }
1856  }
1857 
1858  if ( intersectionList.size() >= 2 )
1859  {
1860  lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1861  }
1862  currentLevel += mGridIntervalY;
1863  }
1864 
1865 
1866  return 0;
1867 }
1868 
1869 int QgsComposerMap::yGridLines( QList< QPair< double, QLineF > >& lines ) const
1870 {
1871  lines.clear();
1872  if ( mGridIntervalX <= 0.0 )
1873  {
1874  return 1;
1875  }
1876 
1877  QPolygonF mapPolygon = transformedMapPolygon();
1878  QRectF mapBoundingRect = mapPolygon.boundingRect();
1879 
1880  //consider to round up to the next step in case the left boundary is > 0
1881  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1882  double currentLevel = ( int )(( mapBoundingRect.left() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1883 
1884  if ( qgsDoubleNear( mMapRotation, 0.0 ) )
1885  {
1886  //no rotation. Do it 'the easy way'
1887  double xCanvasCoord;
1888 
1889  while ( currentLevel <= mapBoundingRect.right() )
1890  {
1891  xCanvasCoord = rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1892  lines.push_back( qMakePair( currentLevel, QLineF( xCanvasCoord, 0, xCanvasCoord, rect().height() ) ) );
1893  currentLevel += mGridIntervalX;
1894  }
1895  }
1896 
1897  //the four border lines
1898  QVector<QLineF> borderLines;
1899  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1900  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1901  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1902  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1903 
1904  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1905 
1906  while ( currentLevel <= mapBoundingRect.right() )
1907  {
1908  intersectionList.clear();
1909  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1910 
1911  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1912  for ( ; it != borderLines.constEnd(); ++it )
1913  {
1914  QPointF intersectionPoint;
1915  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1916  {
1917  intersectionList.push_back( intersectionPoint );
1918  if ( intersectionList.size() >= 2 )
1919  {
1920  break; //we already have two intersections, skip further tests
1921  }
1922  }
1923  }
1924 
1925  if ( intersectionList.size() >= 2 )
1926  {
1927  lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1928  }
1929  currentLevel += mGridIntervalX;
1930  }
1931 
1932  return 0;
1933 }
1934 
1936 {
1937  if ( mGridLineSymbol )
1938  {
1939  mGridLineSymbol->setWidth( w );
1940  }
1941 }
1942 
1943 void QgsComposerMap::setGridPenColor( const QColor& c )
1944 {
1945  if ( mGridLineSymbol )
1946  {
1947  mGridLineSymbol->setColor( c );
1948  }
1949 }
1950 
1951 void QgsComposerMap::setGridPen( const QPen& p )
1952 {
1953  setGridPenWidth( p.widthF() );
1954  setGridPenColor( p.color() );
1955 }
1956 
1958 {
1959  QPen p;
1960  if ( mGridLineSymbol )
1961  {
1962  p.setWidthF( mGridLineSymbol->width() );
1963  p.setColor( mGridLineSymbol->color() );
1964  p.setCapStyle( Qt::FlatCap );
1965  }
1966  return p;
1967 }
1968 
1969 void QgsComposerMap::setGridBlendMode( QPainter::CompositionMode blendMode )
1970 {
1972  update();
1973 }
1974 
1976 {
1977  return mCurrentRectangle;
1978 }
1979 
1981 {
1982  QRectF rectangle = rect();
1983  double extension = maxExtension();
1984  rectangle.setLeft( rectangle.left() - extension );
1985  rectangle.setRight( rectangle.right() + extension );
1986  rectangle.setTop( rectangle.top() - extension );
1987  rectangle.setBottom( rectangle.bottom() + extension );
1988  if ( rectangle != mCurrentRectangle )
1989  {
1990  prepareGeometryChange();
1991  mCurrentRectangle = rectangle;
1992  }
1993 }
1994 
1996 {
1997  QgsComposerItem::setFrameOutlineWidth( outlineWidth );
1999 }
2000 
2002 {
2003  double dx = mXOffset;
2004  double dy = mYOffset;
2005  transformShift( dx, dy );
2006  return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
2007 }
2008 
2010 {
2011  double dx = mXOffset;
2012  double dy = mYOffset;
2013  //qWarning("offset");
2014  //qWarning(QString::number(dx).toLocal8Bit().data());
2015  //qWarning(QString::number(dy).toLocal8Bit().data());
2016  transformShift( dx, dy );
2017  //qWarning("transformed:");
2018  //qWarning(QString::number(dx).toLocal8Bit().data());
2019  //qWarning(QString::number(dy).toLocal8Bit().data());
2020  QPolygonF poly;
2021  mapPolygon( poly );
2022  poly.translate( -dx, -dy );
2023  return poly;
2024 }
2025 
2027 {
2028  double frameExtension = mFrame ? pen().widthF() / 2.0 : 0.0;
2031  {
2032  return frameExtension;
2033  }
2034 
2035  QList< QPair< double, QLineF > > xLines;
2036  QList< QPair< double, QLineF > > yLines;
2037 
2038  int xGridReturn = xGridLines( xLines );
2039  int yGridReturn = yGridLines( yLines );
2040 
2041  if ( xGridReturn != 0 && yGridReturn != 0 )
2042  {
2043  return frameExtension;
2044  }
2045 
2046  double maxExtension = 0;
2047  double currentExtension = 0;
2048  QString currentAnnotationString;
2049 
2050  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
2051  for ( ; it != xLines.constEnd(); ++it )
2052  {
2053  currentAnnotationString = gridAnnotationString( it->first, Latitude );
2054  currentExtension = qMax( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
2055  maxExtension = qMax( maxExtension, currentExtension );
2056  }
2057 
2058  it = yLines.constBegin();
2059  for ( ; it != yLines.constEnd(); ++it )
2060  {
2061  currentAnnotationString = gridAnnotationString( it->first, Longitude );
2062  currentExtension = qMax( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
2063  maxExtension = qMax( maxExtension, currentExtension );
2064  }
2065 
2066  //grid frame
2067  double gridFrameDist = ( mGridFrameStyle == NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
2068  return qMax( frameExtension, maxExtension + mAnnotationFrameDistance + gridFrameDist );
2069 }
2070 
2071 void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const
2072 {
2073  poly.clear();
2074  if ( mMapRotation == 0 )
2075  {
2076  poly << QPointF( extent.xMinimum(), extent.yMaximum() );
2077  poly << QPointF( extent.xMaximum(), extent.yMaximum() );
2078  poly << QPointF( extent.xMaximum(), extent.yMinimum() );
2079  poly << QPointF( extent.xMinimum(), extent.yMinimum() );
2080  return;
2081  }
2082 
2083  //there is rotation
2084  QgsPoint rotationPoint(( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
2085  double dx, dy; //x-, y- shift from rotation point to corner point
2086 
2087  //top left point
2088  dx = rotationPoint.x() - extent.xMinimum();
2089  dy = rotationPoint.y() - extent.yMaximum();
2090  rotate( mMapRotation, dx, dy );
2091  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2092 
2093  //top right point
2094  dx = rotationPoint.x() - extent.xMaximum();
2095  dy = rotationPoint.y() - extent.yMaximum();
2096  rotate( mMapRotation, dx, dy );
2097  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2098 
2099  //bottom right point
2100  dx = rotationPoint.x() - extent.xMaximum();
2101  dy = rotationPoint.y() - extent.yMinimum();
2102  rotate( mMapRotation, dx, dy );
2103  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2104 
2105  //bottom left point
2106  dx = rotationPoint.x() - extent.xMinimum();
2107  dy = rotationPoint.y() - extent.yMinimum();
2108  rotate( mMapRotation, dx, dy );
2109  poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
2110 }
2111 
2112 void QgsComposerMap::mapPolygon( QPolygonF& poly ) const
2113 {
2114  return mapPolygon( *currentMapExtent(), poly );
2115 }
2116 
2118 {
2119  QgsRectangle newExtent = *currentMapExtent();
2120  if ( mMapRotation == 0 )
2121  {
2122  extent = newExtent;
2123  }
2124  else
2125  {
2126  QPolygonF poly;
2127  mapPolygon( newExtent, poly );
2128  QRectF bRect = poly.boundingRect();
2129  extent.setXMinimum( bRect.left() );
2130  extent.setXMaximum( bRect.right() );
2131  extent.setYMinimum( bRect.top() );
2132  extent.setYMaximum( bRect.bottom() );
2133  }
2134 }
2135 
2137 {
2138  double extentWidth = currentMapExtent()->width();
2139  if ( extentWidth <= 0 )
2140  {
2141  return 1;
2142  }
2143  return rect().width() / extentWidth;
2144 }
2145 
2147 {
2148  if ( mOverviewFrameMapId != -1 )
2149  {
2150  const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
2151  if ( map )
2152  {
2153  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
2154  }
2155  }
2156  mOverviewFrameMapId = mapId;
2157  if ( mOverviewFrameMapId != -1 )
2158  {
2159  const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
2160  if ( map )
2161  {
2162  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
2163  }
2164  }
2165  update();
2166 }
2167 
2169 {
2170  //if using overview centering, update the map's extent
2171  if ( mOverviewCentered && mOverviewFrameMapId != -1 )
2172  {
2174 
2175  const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
2176  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
2177 
2178  QgsPoint center = otherExtent.center();
2179  QgsRectangle movedExtent( center.x() - currentMapExtent()->width() / 2,
2180  center.y() - currentMapExtent()->height() / 2,
2181  center.x() - currentMapExtent()->width() / 2 + currentMapExtent()->width(),
2182  center.y() - currentMapExtent()->height() / 2 + currentMapExtent()->height() );
2183  *currentMapExtent() = movedExtent;
2184 
2185  emit itemChanged();
2186  emit extentChanged();
2187  }
2188 
2189  //redraw so that overview gets updated
2190  cache();
2191  update();
2192 }
2193 
2194 
2196 {
2197  delete mOverviewFrameMapSymbol;
2198  mOverviewFrameMapSymbol = symbol;
2199 }
2200 
2201 void QgsComposerMap::setOverviewBlendMode( QPainter::CompositionMode blendMode )
2202 {
2204  update();
2205 }
2206 
2208 {
2209  mOverviewInverted = inverted;
2210  update();
2211 }
2212 
2214 {
2215  mOverviewCentered = centered;
2217 }
2218 
2220 {
2221  delete mGridLineSymbol;
2222  mGridLineSymbol = symbol;
2223 }
2224 
2225 void QgsComposerMap::transformShift( double& xShift, double& yShift ) const
2226 {
2227  double mmToMapUnits = 1.0 / mapUnitsToMM();
2228  double dxScaled = xShift * mmToMapUnits;
2229  double dyScaled = - yShift * mmToMapUnits;
2230 
2231  rotate( mMapRotation, dxScaled, dyScaled );
2232 
2233  xShift = dxScaled;
2234  yShift = dyScaled;
2235 }
2236 
2237 QPointF QgsComposerMap::mapToItemCoords( const QPointF& mapCoords ) const
2238 {
2239  QPolygonF mapPoly = transformedMapPolygon();
2240  if ( mapPoly.size() < 1 )
2241  {
2242  return QPointF( 0, 0 );
2243  }
2244 
2245  QgsRectangle tExtent = transformedExtent();
2246  QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
2247  double dx = mapCoords.x() - rotationPoint.x();
2248  double dy = mapCoords.y() - rotationPoint.y();
2249  rotate( -mMapRotation, dx, dy );
2250  QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
2251 
2252  QgsRectangle unrotatedExtent = transformedExtent();
2253  double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
2254  double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
2255  return QPointF( xItem, yItem );
2256 }
2257 
2259 {
2260  if ( p.x() <= pen().widthF() )
2261  {
2262  return Left;
2263  }
2264  else if ( p.x() >= ( rect().width() - pen().widthF() ) )
2265  {
2266  return Right;
2267  }
2268  else if ( p.y() <= pen().widthF() )
2269  {
2270  return Top;
2271  }
2272  else
2273  {
2274  return Bottom;
2275  }
2276 }
2277 
2278 void QgsComposerMap::drawCanvasItems( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
2279 {
2280  if ( !mMapCanvas || !mDrawCanvasItems )
2281  {
2282  return;
2283  }
2284 
2285  QList<QGraphicsItem*> itemList = mMapCanvas->items();
2286  if ( itemList.size() < 1 )
2287  {
2288  return;
2289  }
2290  QGraphicsItem* currentItem = 0;
2291 
2292  for ( int i = itemList.size() - 1; i >= 0; --i )
2293  {
2294  currentItem = itemList.at( i );
2295  //don't draw mapcanvasmap (has z value -10)
2296  if ( !currentItem || currentItem->data( 0 ).toString() != "AnnotationItem" )
2297  {
2298  continue;
2299  }
2300  drawCanvasItem( currentItem, painter, itemStyle );
2301  }
2302 }
2303 
2304 void QgsComposerMap::drawCanvasItem( QGraphicsItem* item, QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
2305 {
2306  if ( !item || !mMapCanvas || !item->isVisible() )
2307  {
2308  return;
2309  }
2310 
2311  painter->save();
2312 
2313  //determine scale factor according to graphics view dpi
2314  double scaleFactor = 1.0 / mMapCanvas->logicalDpiX() * 25.4;
2315 
2316  double itemX, itemY;
2317  QGraphicsItem* parent = item->parentItem();
2318  if ( !parent )
2319  {
2320  QPointF mapPos = composerMapPosForItem( item );
2321  itemX = mapPos.x();
2322  itemY = mapPos.y();
2323  }
2324  else //place item relative to the parent item
2325  {
2326  QPointF itemScenePos = item->scenePos();
2327  QPointF parentScenePos = parent->scenePos();
2328 
2329  QPointF mapPos = composerMapPosForItem( parent );
2330 
2331  itemX = mapPos.x() + ( itemScenePos.x() - parentScenePos.x() ) * scaleFactor;
2332  itemY = mapPos.y() + ( itemScenePos.y() - parentScenePos.y() ) * scaleFactor;
2333  }
2334  painter->translate( itemX, itemY );
2335 
2336 
2337  painter->scale( scaleFactor, scaleFactor );
2338 
2339  //a little trick to let the item know that the paint request comes from the composer
2340  item->setData( 1, "composer" );
2341  item->paint( painter, itemStyle, 0 );
2342  item->setData( 1, "" );
2343  painter->restore();
2344 }
2345 
2346 QPointF QgsComposerMap::composerMapPosForItem( const QGraphicsItem* item ) const
2347 {
2348  if ( !item || !mMapCanvas )
2349  {
2350  return QPointF( 0, 0 );
2351  }
2352 
2353  if ( currentMapExtent()->height() <= 0 || currentMapExtent()->width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
2354  {
2355  return QPointF( 0, 0 );
2356  }
2357 
2358  QRectF graphicsSceneRect = mMapCanvas->sceneRect();
2359  QPointF itemScenePos = item->scenePos();
2360  QgsRectangle mapRendererExtent = mComposition->mapSettings().visibleExtent();
2361 
2362  double mapX = itemScenePos.x() / graphicsSceneRect.width() * mapRendererExtent.width() + mapRendererExtent.xMinimum();
2363  double mapY = mapRendererExtent.yMaximum() - itemScenePos.y() / graphicsSceneRect.height() * mapRendererExtent.height();
2364  return mapToItemCoords( QPointF( mapX, mapY ) );
2365 }
2366 
2368 {
2369  switch ( border )
2370  {
2371  case QgsComposerMap::Left:
2373  break;
2374  case QgsComposerMap::Right:
2376  break;
2377  case QgsComposerMap::Top:
2379  break;
2382  break;
2383  default:
2384  return;
2385  }
2387  update();
2388 }
2389 
2391 {
2392  switch ( border )
2393  {
2394  case QgsComposerMap::Left:
2396  break;
2397  case QgsComposerMap::Right:
2399  break;
2400  case QgsComposerMap::Top:
2402  break;
2404  default:
2406  break;
2407  }
2408 }
2409 
2411 {
2412  switch ( border )
2413  {
2414  case QgsComposerMap::Left:
2416  break;
2417  case QgsComposerMap::Right:
2419  break;
2420  case QgsComposerMap::Top:
2422  break;
2425  break;
2426  default:
2427  return;
2428  break;
2429  }
2431  update();
2432 }
2433 
2435 {
2436  switch ( border )
2437  {
2438  case QgsComposerMap::Left:
2440  break;
2441  case QgsComposerMap::Right:
2443  break;
2444  case QgsComposerMap::Top:
2446  break;
2448  default:
2450  break;
2451  }
2452 }
2453 
2454 void QgsComposerMap::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
2455  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
2456 {
2457  QList< QPair< double, QPointF > > borderPositions;
2458  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
2459  for ( ; it != hLines.constEnd(); ++it )
2460  {
2461  borderPositions << qMakePair( it->first, it->second.p1() );
2462  borderPositions << qMakePair( it->first, it->second.p2() );
2463  }
2464  it = vLines.constBegin();
2465  for ( ; it != vLines.constEnd(); ++it )
2466  {
2467  borderPositions << qMakePair( it->first, it->second.p1() );
2468  borderPositions << qMakePair( it->first, it->second.p2() );
2469  }
2470 
2471  QList< QPair< double, QPointF > >::const_iterator bIt = borderPositions.constBegin();
2472  for ( ; bIt != borderPositions.constEnd(); ++bIt )
2473  {
2474  Border frameBorder = borderForLineCoord( bIt->second );
2475  if ( frameBorder == QgsComposerMap::Left )
2476  {
2477  leftFrameEntries.insert( bIt->second.y(), bIt->first );
2478  }
2479  else if ( frameBorder == QgsComposerMap::Right )
2480  {
2481  rightFrameEntries.insert( bIt->second.y(), bIt->first );
2482  }
2483  else if ( frameBorder == QgsComposerMap::Top )
2484  {
2485  topFrameEntries.insert( bIt->second.x(), bIt->first );
2486  }
2487  else //Bottom
2488  {
2489  bottomFrameEntries.insert( bIt->second.x(), bIt->first );
2490  }
2491  }
2492 }
2493 
2495 {
2496  if ( mOverviewFrameMapId == -1 || !mComposition )
2497  {
2498  return;
2499  }
2500 
2502  {
2503  //if map item is set to rectangle preview mode and we are not exporting the composition
2504  //then don't draw an overview rectangle
2505  return;
2506  }
2507 
2508  const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
2509  if ( !overviewFrameMap )
2510  {
2511  return;
2512  }
2513 
2514  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
2515  QgsRectangle thisExtent = *currentMapExtent();
2516  QgsRectangle intersectRect = thisExtent.intersect( &otherExtent );
2517 
2518  QgsRenderContext context;
2519  context.setPainter( p );
2520  context.setScaleFactor( 1.0 );
2521  context.setRasterScaleFactor( mComposition->printResolution() / 25.4 );
2522 
2523  p->save();
2524  p->setCompositionMode( mOverviewBlendMode );
2525  p->translate( mXOffset, mYOffset );
2527 
2528  //construct a polygon corresponding to the intersecting map extent
2529  QPolygonF intersectPolygon;
2530  double x = ( intersectRect.xMinimum() - thisExtent.xMinimum() ) / thisExtent.width() * rect().width();
2531  double y = ( thisExtent.yMaximum() - intersectRect.yMaximum() ) / thisExtent.height() * rect().height();
2532  double width = intersectRect.width() / thisExtent.width() * rect().width();
2533  double height = intersectRect.height() / thisExtent.height() * rect().height();
2534  intersectPolygon << QPointF( x, y ) << QPointF( x + width, y ) << QPointF( x + width, y + height ) << QPointF( x, y + height ) << QPointF( x, y );
2535 
2536  QList<QPolygonF> rings; //empty list
2537  if ( !mOverviewInverted )
2538  {
2539  //Render the intersecting map extent
2540  mOverviewFrameMapSymbol->renderPolygon( intersectPolygon, &rings, 0, context );;
2541  }
2542  else
2543  {
2544  //We are inverting the overview frame (ie, shading outside the intersecting extent)
2545  //Construct a polygon corresponding to the overview map extent
2546  QPolygonF outerPolygon;
2547  outerPolygon << QPointF( 0, 0 ) << QPointF( rect().width(), 0 ) << QPointF( rect().width(), rect().height() ) << QPointF( 0, rect().height() ) << QPointF( 0, 0 );
2548 
2549  //Intersecting extent is an inner ring for the shaded area
2550  rings.append( intersectPolygon );
2551  mOverviewFrameMapSymbol->renderPolygon( outerPolygon, &rings, 0, context );
2552  }
2553 
2554  mOverviewFrameMapSymbol->stopRender( context );
2555  p->restore();
2556 }
2557 
2559 {
2560  delete mOverviewFrameMapSymbol;
2561  QgsStringMap properties;
2562  properties.insert( "color", "255,0,0,255" );
2563  properties.insert( "style", "solid" );
2564  properties.insert( "style_border", "no" );
2567 }
2568 
2570 {
2571  delete mGridLineSymbol;
2572  QgsStringMap properties;
2573  properties.insert( "color", "0,0,0,255" );
2574  properties.insert( "width", "0.3" );
2575  properties.insert( "capstyle", "flat" );
2577 }
2578 
2580 {
2581  QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "D" );
2582 
2583  bool degreeUnits = ( mComposition->mapSettings().mapUnits() == QGis::Degrees );
2584 
2585  if ( format == "DM" && degreeUnits )
2586  {
2588  }
2589  else if ( format == "DMS" && degreeUnits )
2590  {
2592  }
2593  else
2594  {
2596  }
2597 }
2598 
2600 {
2601  if ( !mComposition )
2602  {
2603  return;
2604  }
2605 
2606  const QgsComposerMap* existingMap = mComposition->getComposerMapById( mId );
2607  if ( !existingMap )
2608  {
2609  return; //keep mId as it is still available
2610  }
2611 
2612  int maxId = -1;
2613  QList<const QgsComposerMap*> mapList = mComposition->composerMapItems();
2614  QList<const QgsComposerMap*>::const_iterator mapIt = mapList.constBegin();
2615  for ( ; mapIt != mapList.constEnd(); ++mapIt )
2616  {
2617  if (( *mapIt )->id() > maxId )
2618  {
2619  maxId = ( *mapIt )->id();
2620  }
2621  }
2622  mId = maxId + 1;
2623 }
2624 
2625 bool QgsComposerMap::imageSizeConsideringRotation( double& width, double& height ) const
2626 {
2627  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2629 }
2630 
2631 bool QgsComposerMap::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
2632 {
2633  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2635 }
2636 
2637 void QgsComposerMap::sizeChangedByRotation( double& width, double& height )
2638 {
2639  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2640  return QgsComposerItem::sizeChangedByRotation( width, height, mMapRotation );
2641 }
2642 
QString toDegreesMinutesSeconds(int thePrecision) const
Return a string representation as degrees minutes seconds.
Definition: qgspoint.cpp:137
bool mAtlasFixedScale
True if map uses a fixed scale when controlled by an atlas.
int mOverviewFrameMapId
Id of map which displays its extent rectangle into this composer map (overview map functionality)...
double mGridFrameWidth
double mXOffset
Offset in x direction for showing map cache image.
void setMapUnits(QGis::UnitType mapUnits)
Set the map units.
void preparedForAtlas()
Is emitted when the map has been prepared for atlas rendering, just before actual rendering...
QgsComposition::AtlasMode atlasMode() const
Returns the current atlas mode of the composition.
bool mGridEnabled
True if coordinate grid has to be displayed.
void draw(QPainter *painter, const QgsRectangle &extent, const QSizeF &size, double dpi, double *forceWidthScale=0)
Draw to paint device.
bool imageSizeConsideringRotation(double &width, double &height, double rotation) const
Calculates width and hight of the picture (in mm) such that it fits into the item frame with the give...
double outlineWidth
Definition: qgssvgcache.cpp:78
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:47
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
bool mDrawing
set to true if in state of drawing.
job implementation that renders everything sequentially using a custom painter.
double mGridIntervalY
Grid line interval in y-direction (map units)
double mMapRotation
Map rotation.
GridAnnotationDirection gridAnnotationDirection(QgsComposerMap::Border border) const
void overviewExtentChanged()
double fontHeightCharacterMM(const QFont &font, const QChar &c) const
Returns the font height of a character in millimeters.
void setOverviewCentered(bool centered)
Set the overview's centering mode.
bool containsWMSLayer() const
True if composer map renders a WMS layer.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:164
double mapUnitsToMM() const
Returns the conversion factor map units -> mm.
bool hideCoverage() const
void assignFreeId()
Sets mId to a number not yet used in the composition.
void setNewAtlasFeatureExtent(const QgsRectangle &extent)
Sets new Extent for the current atlas preview and changes width, height (and implicitely also scale)...
void setOffset(double xOffset, double yOffset)
Sets offset values to shift image (useful for live updates when moving item content) ...
Q_DECL_DEPRECATED QgsMapRenderer * mapRenderer()
Returns pointer to map renderer of qgis map canvas.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:189
QStringList mLayerSet
Stored layer list (used if layer live-link mKeepLayerSet is disabled)
QFont mGridAnnotationFont
Font for grid line annotation.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
void setOutputDpi(int dpi)
void requestedExtent(QgsRectangle &extent) const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
bool mDrawCanvasItems
True if annotation items, rubber band, etc.
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.
QPainter::CompositionMode bufferBlendMode
QStringList layerSet() const
Getter for stored layer set that is used if mKeepLayerSet is true.
double maxExtension() const
QString qgsDoubleToString(const double &a)
Definition: qgis.h:316
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
void cache()
Create cache image.
bool imageSizeConsideringRotation(double &width, double &height) const
Calculates width and hight of the picture (in mm) such that it fits into the item frame with the give...
QList< const QgsComposerMap * > composerMapItems() const
Returns pointers to all composer maps in the scene.
A item that forms part of a map composition.
void connectUpdateSlot()
Establishes signal/slot connection for update in case of layer change.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:439
Border
Enum for different frame borders.
QgsRectangle visibleExtent() const
void updateItem()
Updates item, with the possibility to do custom update for subclasses.
QPointF composerMapPosForItem(const QGraphicsItem *item) const
QPainter::CompositionMode mOverviewBlendMode
Blend mode for overview.
void setDpi(double dpi)
Set the dpi to be used in scale calculations.
QGraphicsView * mMapCanvas
double mLastValidViewScaleFactor
Backup to restore item appearance if no view scale factor is available.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
void mapRotationChanged(double newRotation)
Is emitted on rotation change to notify north arrow pictures.
static QgsPalLayerSettings fromLayer(QgsVectorLayer *layer)
virtual void drawFrame(QPainter *p)
Draw black frame around item.
void updateCachedImage()
Called if map canvas has changed.
Flags flags() const
bool cornerPointOnRotatedAndScaledRect(double &x, double &y, double width, double height) const
Calculates corner point after rotation and scaling.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
void createDefaultGridLineSymbol()
QPolygonF transformedMapPolygon() const
Returns extent that considers rotation and shift with mOffsetX / mOffsetY.
QColor backgroundColor() const
Gets the background color for this item.
A non GUI class for rendering a map layer set onto a QPainter.
void mapPolygon(QPolygonF &poly) const
Returns the polygon of the map extent.
void setLayers(const QStringList &layers)
void initGridAnnotationFormatFromProject()
bool mShowGridAnnotation
True if coordinate values should be drawn.
void setSceneRect(const QRectF &rectangle)
Sets new scene rectangle bounds and recalculates hight and extent.
bool containsAdvancedEffects() const
True if composer map contains layers with blend modes or flattened layers for vectors.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=0) const
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
QRectF boundingRect() const
In case of annotations, the bounding rectangle can be larger than the map item rectangle.
bool mOverviewCentered
Centering mode for overview.
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer...
double x() const
Definition: qgspoint.h:110
void zoomContent(int delta, double x, double y)
Zoom content of map.
void setGridPenColor(const QColor &c)
Sets the color of the grid pen.
virtual QString name() const =0
return a provider name
void setWidth(double width)
GridFrameStyle mGridFrameStyle
QColor mGridFrameFillColor1
QColor mGridFramePenColor
void setFlag(Flag flag, bool on=true)
int mGridAnnotationPrecision
Digits after the dot.
void itemChanged()
Used e.g.
void setNewScale(double scaleDenominator)
Sets new scale and changes only mExtent.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads parameter that are not subclass specific in document.
static bool staticWillUseLayer(QgsVectorLayer *layer)
called to find out whether the layer is used for labeling
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
Q_DECL_DEPRECATED const QgsMapRenderer * mapRenderer() const
QgsRectangle mExtent
QgsLineSymbolV2 * mGridLineSymbol
void storeCurrentLayerSet()
Stores the current layer set of the qgis mapcanvas in mLayerSet.
GridAnnotationDirection mLeftGridAnnotationDirection
Annotation direction on left side ( horizontal or vertical )
void setColor(const QColor &color)
double mAnnotationFrameDistance
Distance between map frame and annotation.
bool shouldDrawPart(PartType part) const
Test if a part of the copmosermap needs to be drawn, considering mCurrentExportLayer.
double scale() const
Scale.
GridAnnotationDirection mRightGridAnnotationDirection
Annotation direction on right side ( horizontal or vertical )
void drawCoordinateAnnotations(QPainter *p, const QList< QPair< double, QLineF > > &hLines, const QList< QPair< double, QLineF > > &vLines)
Draw coordinates for mGridAnnotationType Coordinate.
QPainter::CompositionMode blendMode() const
Read blend mode for layer.
double horizontalViewScaleFactor() const
Returns the zoom factor of the graphics view.
QRectF mCurrentRectangle
Current bounding rectangle.
void setScaleFactor(double factor)
double mCrossLength
The length of the cross sides for mGridStyle Cross.
double mGridFramePenThickness
QPainter::CompositionMode featureBlendMode() const
Read blend mode for layer.
double calculate(const QgsRectangle &mapExtent, int canvasWidth)
Calculate the scale denominator.
void updateBoundingRect()
Updates the bounding rect of this item.
double mGridOffsetY
Grid line offset in y-direction.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:194
void toggleAtlasPreview()
Called when atlas preview is toggled, to force map item to update its extent and redraw.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:179
virtual void updateItem()
Updates item, with the possibility to do custom update for subclasses.
void drawOverviewMapExtent(QPainter *p)
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
virtual void drawSelectionBoxes(QPainter *p)
Draw selection boxes around item.
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...
static QgsLineSymbolV2 * createSimple(const QgsStringMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties. ...
void rotate(double angle, double &x, double &y) const
Rotates a point / vector.
QPainter::CompositionMode blendMode
QString gridAnnotationString(double value, AnnotationCoordinate coord) const
int printResolution() const
bool mFrame
True if item fram needs to be painted.
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom node
void setMapUnits(QGis::UnitType u)
bool drawCanvasItems() const
virtual void waitForFinished()
Block until the job has finished.
void setCacheUpdated(bool u=false)
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:169
double rotation() const
Returns the rotation used for drawing the map within the composer item.
int yGridLines(QList< QPair< double, QLineF > > &lines) const
Returns the grid lines for the y-coordinates.
double mYOffset
Offset in y direction for showing map cache image.
void renderPolyline(const QPolygonF &points, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
virtual void setFrameOutlineWidth(double outlineWidth)
Sets frame outline width.
QColor mGridFrameFillColor2
void drawAnnotation(QPainter *p, const QPointF &pos, int rotation, const QString &annotationText)
Draws a single annotation.
void setNewExtent(const QgsRectangle &extent)
Sets new Extent and changes width, height (and implicitely also scale)
void setGridPen(const QPen &p)
Sets the pen to draw composer grid.
void setPainter(QPainter *p)
void moveContent(double dx, double dy)
Move content of map.
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:92
QGis::UnitType mapUnits() const
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
virtual void start()
Start the rendering job and immediately return.
void drawGridFrame(QPainter *p, const QList< QPair< double, QLineF > > &hLines, const QList< QPair< double, QLineF > > &vLines)
double mGridIntervalX
Grid line interval in x-direction (map units)
GridAnnotationPosition mTopGridAnnotationPosition
Annotation position for top map side (inside / outside / not shown)
QPainter::CompositionMode shapeBlendMode
void drawCanvasItem(QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *itemStyle)
void sizeChangedByRotation(double &width, double &height)
Calculates width / height of the bounding box of a rotated rectangle.
void setOverviewFrameMapSymbol(QgsFillSymbolV2 *symbol)
bool mAtlasDriven
True if map is being controlled by an atlas.
PreviewMode
Preview style.
GridAnnotationPosition gridAnnotationPosition(QgsComposerMap::Border border) const
GridAnnotationPosition mLeftGridAnnotationPosition
Annotation position for left map side (inside / outside / not shown)
QgsComposition * mComposition
A class to represent a point geometry.
Definition: qgspoint.h:63
GridAnnotationFormat mGridAnnotationFormat
Graphics scene for map printing.
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
This class tracks map layers that are currently loaded and provides a means to fetch a pointer to a m...
Object representing map window.
GridStyle mGridStyle
Solid or crosses.
QPen gridPen() const
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
QgsFillSymbolV2 * mOverviewFrameMapSymbol
Drawing style for overview farme.
GridAnnotationPosition mRightGridAnnotationPosition
Annotation position for right map side (inside / outside / not shown)
void setX(double x)
Definition: qgspoint.h:87
GridAnnotationDirection mTopGridAnnotationDirection
Annotation direction on top side ( horizontal or vertical )
void renderModeUpdateCachedImage()
Call updateCachedImage if item is in render mode.
PreviewMode previewMode() const
void drawGridLine(const QLineF &line, QPainter *p)
virtual ~QgsComposerMap()
void setY(double y)
Definition: qgspoint.h:95
void setGridAnnotationDirection(GridAnnotationDirection d, QgsComposerMap::Border border)
Calculates scale for a given combination of canvas size, map extent, and monitor dpi.
int layerTransparency() const
Read transparency for layer.
int xGridLines(QList< QPair< double, QLineF > > &lines) const
Returns the grid lines with associated coordinate value.
static QPainter::CompositionMode getCompositionMode(const QgsMapRenderer::BlendMode &blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode Added in 1.9.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:440
bool useAdvancedEffects() const
Returns true if a composition should use advanced effects such as blend modes.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget)
Reimplementation of QCanvasItem::paint - draw on canvas.
QColor mBackgroundColor
Background color.
double mAtlasMargin
Margin size for atlas driven extents (percentage of feature size)
void setBackgroundColor(const QColor &color)
Contains information about the context of a rendering operation.
bool mKeepLayerSet
Flag if layers to be displayed should be read from qgis canvas (true) or from stored list in mLayerSe...
bool cornerPointOnRotatedAndScaledRect(double &x, double &y, double width, double height, double rotation) const
Calculates corner point after rotation and scaling.
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=0) const
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
virtual void setFrameOutlineWidth(double outlineWidth)
Sets frame outline width.
void stopRender(QgsRenderContext &context)
double mGridOffsetX
Grid line offset in x-direction.
void setOverviewInverted(bool inverted)
Sets the overview's inversion mode.
bool _writeXML(QDomElement &itemElem, QDomDocument &doc) const
Writes parameter that are not subclass specific in document.
int mCurrentExportLayer
The layer that needs to be exported.
QgsRectangle extent() const
GridAnnotationDirection mBottomGridAnnotationDirection
Annotation direction on bottom side ( horizontal or vertical )
QPainter::CompositionMode blendMode() const
Returns the item's composition blending mode.
int mId
Unique identifier.
void setOutputSize(const QSize &size)
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:174
virtual void drawBackground(QPainter *p)
Draw background.
QgsRectangle intersect(const QgsRectangle *rect) const
return the intersection with the given rectangle
bool mUpdatesEnabled
Whether updates to the map are enabled.
bool hasFrame() const
Whether this item has a frame or not.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
void setExtent(const QgsRectangle &rect)
void setMapRotation(double r)
Sets rotation for the map - this does not affect the composer item shape, only the way the map is dra...
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
void setGridAnnotationPosition(GridAnnotationPosition p, QgsComposerMap::Border border)
void drawCoordinateAnnotation(QPainter *p, const QPointF &pos, QString annotationString)
void transformShift(double &xShift, double &yShift) const
Scales a composer map shift (in MM) and rotates it by mRotation.
const QgsComposition * composition() const
void adjustExtentToItemShape(double itemWidth, double itemHeight, QgsRectangle &extent) const
Adjusts an extent rectangle to match the provided item width and height, so that extent center of ext...
void drawGridFrameBorder(QPainter *p, const QMap< double, double > &borderPos, Border border)
bool hasBackground() const
Whether this item has a Background or not.
const QMap< QString, QgsMapLayer * > & mapLayers()
Retrieve the mapLayers collection (mainly intended for use by projection)
QgsComposerMap(QgsComposition *composition, int x, int y, int width, int height)
Constructor.
QgsRectangle mAtlasFeatureExtent
void resize(double dx, double dy)
resizes an item in x- and y direction (canvas coordinates)
double y() const
Definition: qgspoint.h:118
QStringList layers() const
QgsAtlasComposition & atlasComposition()
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
QPainter::CompositionMode shadowBlendMode
static QgsSymbolV2 * loadSymbol(QDomElement &element)
QgsRasterDataProvider * dataProvider()
Returns the data provider.
void setRasterScaleFactor(double factor)
static QgsMapRenderer::BlendMode getBlendModeEnum(const QPainter::CompositionMode &blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode Added in 1.9.
void setOverviewBlendMode(QPainter::CompositionMode blendMode)
Sets the overview's blending mode.
QgsVectorLayer * coverageLayer() const
GridAnnotationPosition mBottomGridAnnotationPosition
Annotation position for bottom map side (inside / outside / not shown)
void setGridLineSymbol(QgsLineSymbolV2 *symbol)
void extentChanged()
void setGridPenWidth(double w)
Sets with of grid pen.
void createDefaultOverviewFrameSymbol()
static void setSpecialColumn(const QString &name, QVariant value)
Assign a special column.
void drawGrid(QPainter *p)
Draws the map grid.
QColor mGridAnnotationFontColor
Font color for grid line annotation.
QPointF mapToItemCoords(const QPointF &mapCoords) const
Transforms map coordinates to item coordinates (considering rotation and move offset) ...
void setPreviewMode(PreviewMode m)
QgsComposition::PlotStyle plotStyle() const
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:199
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...
Represents a vector layer which manages a vector based data sets.
double size
Definition: qgssvgcache.cpp:77
const QgsComposerMap * getComposerMapById(int id) const
Returns the composer map with specified id.
void setFlags(Flags flags)
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:184
PreviewMode mPreviewMode
Preview style.
void setRotation(double r)
Sets rotation for the map - this does not affect the composer item shape, only the way the map is dra...
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:209
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:123
QPainter::CompositionMode mGridBlendMode
Blend mode for grid.
QStringList layersToRender() const
Returns a list of the layers to render for this map item.
int numberExportLayers() const
Get the number of layers that this item requires for exporting as layers.
void setGridBlendMode(QPainter::CompositionMode blendMode)
Sets the grid's blending mode.
void syncLayerSet()
Removes layer ids from mLayerSet that are no longer present in the qgis main map. ...
double fontAscentMillimeters(const QFont &font) const
Returns the font ascent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCAL...
void setOverviewFrameMap(int mapId)
Sets overview frame map.
int mNumCachedLayers
Number of layers when cache was created.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:159
QgsRectangle transformedExtent() const
Returns extent that considers mOffsetX / mOffsetY (during content move)
void sizeChangedByRotation(double &width, double &height, double rotation)
Calculates width / height of the bounding box of a rotated rectangle.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:204
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set
Base class for raster data providers.
QColor color() const
#define tr(sourceText)
void scale(double scaleFactor, const QgsPoint *c=0)
Scale the rectangle around its center point.
Border borderForLineCoord(const QPointF &p) const
Returns the item border of a point (in item coordinates)
QString id() const
Get item's id (which is not necessarly unique)