QGIS API Documentation  2.4.0-Chugiak
 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 : [email protected]
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"
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 ), mAtlasScalingMode( Auto ), 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  setBackgroundColor( 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 ), mAtlasScalingMode( Auto ), 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  if ( size.width() == 0 || size.height() == 0 )
175  {
176  //don't attempt to draw if size is invalid
177  return;
178  }
179 
180  const QgsMapSettings& ms = mComposition->mapSettings();
181 
182  QgsMapSettings jobMapSettings;
183  jobMapSettings.setExtent( extent );
184  jobMapSettings.setOutputSize( size.toSize() );
185  jobMapSettings.setOutputDpi( dpi );
186  jobMapSettings.setMapUnits( ms.mapUnits() );
187  jobMapSettings.setBackgroundColor( Qt::transparent );
188  jobMapSettings.setOutputImageFormat( ms.outputImageFormat() );
189 
190  //set layers to render
191  QStringList theLayerSet = layersToRender();
192  if ( -1 != mCurrentExportLayer )
193  {
194  //exporting with separate layers (eg, to svg layers), so we only want to render a single map layer
195  const int layerIdx = mCurrentExportLayer - ( hasBackground() ? 1 : 0 );
196  theLayerSet =
197  ( layerIdx >= 0 && layerIdx < theLayerSet.length() )
198  ? QStringList( theLayerSet[ theLayerSet.length() - layerIdx - 1 ] )
199  : QStringList(); //exporting decorations such as map frame/grid/overview, so no map layers required
200  }
201  jobMapSettings.setLayers( theLayerSet );
202  jobMapSettings.setDestinationCrs( ms.destinationCrs() );
203  jobMapSettings.setCrsTransformEnabled( ms.hasCrsTransformEnabled() );
204  jobMapSettings.setFlags( ms.flags() );
205  jobMapSettings.setFlag( QgsMapSettings::DrawSelection, false );
206 
209  {
210  //if outputing composer, disable optimisations like layer simplification
211  jobMapSettings.setFlag( QgsMapSettings::UseRenderingOptimization, false );
212  }
213 
214  //update $map variable. Use QgsComposerItem's id since that is user-definable
216 
217  // composer-specific overrides of flags
218  jobMapSettings.setFlag( QgsMapSettings::ForceVectorOutput ); // force vector output (no caching of marker images etc.)
219  jobMapSettings.setFlag( QgsMapSettings::DrawEditingInfo, false );
220  jobMapSettings.setFlag( QgsMapSettings::UseAdvancedEffects, mComposition->useAdvancedEffects() ); // respect the composition's useAdvancedEffects flag
221 
222  // render
223  QgsMapRendererCustomPainterJob job( jobMapSettings, painter );
224  // Render the map in this thread. This is done because of problems
225  // with printing to printer on Windows (printing to PDF is fine though).
226  // Raster images were not displayed - see #10599
227  job.renderSynchronously();
228 }
229 
231 {
232  if ( mPreviewMode == Rectangle )
233  {
234  return;
235  }
236 
237  if ( mDrawing )
238  {
239  return;
240  }
241 
242  mDrawing = true;
243 
244  //in case of rotation, we need to request a larger rectangle and create a larger cache image
245  QgsRectangle requestExtent;
246  requestedExtent( requestExtent );
247 
248  double horizontalVScaleFactor = horizontalViewScaleFactor();
249  if ( horizontalVScaleFactor < 0 )
250  {
251  //make sure scale factor is positive
252  horizontalVScaleFactor = mLastValidViewScaleFactor > 0 ? mLastValidViewScaleFactor : 1;
253  }
254 
255  double widthMM = requestExtent.width() * mapUnitsToMM();
256  double heightMM = requestExtent.height() * mapUnitsToMM();
257 
258  int w = widthMM * horizontalVScaleFactor;
259  int h = heightMM * horizontalVScaleFactor;
260 
261  if ( w > 5000 ) //limit size of image for better performance
262  {
263  w = 5000;
264  }
265 
266  if ( h > 5000 )
267  {
268  h = 5000;
269  }
270 
271  mCacheImage = QImage( w, h, QImage::Format_ARGB32 );
272 
273  // set DPI of the image
274  mCacheImage.setDotsPerMeterX( 1000 * w / widthMM );
275  mCacheImage.setDotsPerMeterY( 1000 * h / heightMM );
276 
277  if ( hasBackground() )
278  {
279  //Initially fill image with specified background color. This ensures that layers with blend modes will
280  //preview correctly
281  mCacheImage.fill( backgroundColor().rgba() );
282  }
283  else
284  {
285  //no background, but start with empty fill to avoid artifacts
286  mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
287  }
288 
289  QPainter p( &mCacheImage );
290 
291  draw( &p, requestExtent, QSizeF( w, h ), mCacheImage.logicalDpiX() );
292  p.end();
293  mCacheUpdated = true;
294 
295  mDrawing = false;
296 }
297 
298 void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
299 {
300  Q_UNUSED( pWidget );
301 
302  if ( !mComposition || !painter )
303  {
304  return;
305  }
306 
307  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
308  painter->save();
309  painter->setClipRect( thisPaintRect );
310 
312  {
313  // Fill with background color
314  drawBackground( painter );
315  QFont messageFont( "", 12 );
316  painter->setFont( messageFont );
317  painter->setPen( QColor( 0, 0, 0, 125 ) );
318  painter->drawText( thisPaintRect, tr( "Map will be printed here" ) );
319  }
321  {
322  //draw cached pixmap. This function does not call cache() any more because
323  //Qt 4.4.0 and 4.4.1 have problems with recursive paintings
324  //QgsComposerMap::cache() and QgsComposerMap::update() need to be called by
325  //client functions
326 
327  //Background color is already included in cached image, so no need to draw
328 
329  QgsRectangle requestRectangle;
330  requestedExtent( requestRectangle );
331 
332  QgsRectangle cExtent = *currentMapExtent();
333 
334  double imagePixelWidth = cExtent.width() / requestRectangle.width() * mCacheImage.width() ; //how many pixels of the image are for the map extent?
335  double scale = rect().width() / imagePixelWidth;
336  QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );
337 
338  //shift such that rotation point is at 0/0 point in the coordinate system
339  double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
340  double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
341 
342  //shift such that top left point of the extent at point 0/0 in item coordinate system
343  double xTopLeftShift = ( rotationPoint.x() - cExtent.xMinimum() ) * mapUnitsToMM();
344  double yTopLeftShift = ( cExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
345 
346  painter->save();
347 
348  painter->translate( mXOffset, mYOffset );
349  painter->translate( xTopLeftShift, yTopLeftShift );
350  painter->rotate( mMapRotation );
351  painter->translate( xShiftMM, -yShiftMM );
352  painter->scale( scale, scale );
353  painter->drawImage( 0, 0, mCacheImage );
354 
355  //restore rotation
356  painter->restore();
357 
358  //draw canvas items
359  drawCanvasItems( painter, itemStyle );
360  }
361  else if ( mComposition->plotStyle() == QgsComposition::Print ||
363  {
364  if ( mDrawing )
365  {
366  return;
367  }
368 
369  mDrawing = true;
370  QPaintDevice* thePaintDevice = painter->device();
371  if ( !thePaintDevice )
372  {
373  return;
374  }
375 
376  // Fill with background color
377  if ( shouldDrawPart( Background ) )
378  {
379  drawBackground( painter );
380  }
381 
382  QgsRectangle requestRectangle;
383  requestedExtent( requestRectangle );
384 
385  QgsRectangle cExtent = *currentMapExtent();
386 
387  QSizeF theSize( requestRectangle.width() * mapUnitsToMM(), requestRectangle.height() * mapUnitsToMM() );
388 
389  QgsPoint rotationPoint = QgsPoint(( cExtent.xMaximum() + cExtent.xMinimum() ) / 2.0, ( cExtent.yMaximum() + cExtent.yMinimum() ) / 2.0 );
390 
391  //shift such that rotation point is at 0/0 point in the coordinate system
392  double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
393  double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
394 
395  //shift such that top left point of the extent at point 0/0 in item coordinate system
396  double xTopLeftShift = ( rotationPoint.x() - cExtent.xMinimum() ) * mapUnitsToMM();
397  double yTopLeftShift = ( cExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
398  painter->save();
399  painter->translate( mXOffset, mYOffset );
400  painter->translate( xTopLeftShift, yTopLeftShift );
401  painter->rotate( mMapRotation );
402  painter->translate( xShiftMM, -yShiftMM );
403 
404  double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
405  theSize *= dotsPerMM; // output size will be in dots (pixels)
406  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
407  draw( painter, requestRectangle, theSize, thePaintDevice->logicalDpiX() );
408 
409  //restore rotation
410  painter->restore();
411 
412  //draw canvas items
413  drawCanvasItems( painter, itemStyle );
414 
415  mDrawing = false;
416  }
417 
418  painter->setClipRect( thisPaintRect , Qt::NoClip );
419 
420  if ( mGridEnabled && shouldDrawPart( Grid ) )
421  {
422  drawGrid( painter );
423  }
425  {
426  drawOverviewMapExtent( painter );
427  }
428  if ( shouldDrawPart( Frame ) )
429  {
430  drawFrame( painter );
431  }
432  if ( isSelected() && shouldDrawPart( SelectionBoxes ) )
433  {
434  drawSelectionBoxes( painter );
435  }
436 
437  painter->restore();
438 }
439 
441 {
442  return
443  ( hasBackground() ? 1 : 0 )
444  + layersToRender().length()
445  + ( mGridEnabled ? 1 : 0 )
446  + ( mOverviewFrameMapId != -1 ? 1 : 0 )
447  + ( hasFrame() ? 1 : 0 )
448  + ( isSelected() ? 1 : 0 )
449  ;
450 }
451 
453 {
454  if ( -1 == mCurrentExportLayer )
455  {
456  //all parts of the composer map are visible
457  return true;
458  }
459 
460  int idx = numberExportLayers();
461  if ( isSelected() )
462  {
463  --idx;
464  if ( SelectionBoxes == part )
465  {
466  return mCurrentExportLayer == idx;
467  }
468  }
469 
470  if ( hasFrame() )
471  {
472  --idx;
473  if ( Frame == part )
474  {
475  return mCurrentExportLayer == idx;
476  }
477  }
478  if ( mOverviewFrameMapId )
479  {
480  --idx;
481  if ( OverviewMapExtent == part )
482  {
483  return mCurrentExportLayer == idx;
484  }
485  }
486  if ( mGridEnabled )
487  {
488  --idx;
489  if ( Grid == part )
490  {
491  return mCurrentExportLayer == idx;
492  }
493  }
494  if ( hasBackground() )
495  {
496  if ( Background == part )
497  {
498  return mCurrentExportLayer == 0;
499  }
500  }
501 
502  return true; // for Layer
503 }
504 
505 
507 {
508  syncLayerSet(); //layer list may have changed
509  mCacheUpdated = false;
510  cache();
511  QGraphicsRectItem::update();
512 }
513 
515 {
516  if ( mPreviewMode == Render )
517  {
519  }
520 }
521 
523 {
524  mCacheUpdated = u;
525 }
526 
528 {
530  return mComposition->mapRenderer();
532 }
533 
535 {
536  //use stored layer set or read current set from main canvas
537  QStringList renderLayerSet;
538  if ( mKeepLayerSet )
539  {
540  renderLayerSet = mLayerSet;
541  }
542  else
543  {
544  renderLayerSet = mComposition->mapSettings().layers();
545  }
546 
547  //remove atlas coverage layer if required
548  //TODO - move setting for hiding coverage layer to map item properties
550  {
552  {
553  //hiding coverage layer
554  int removeAt = renderLayerSet.indexOf( mComposition->atlasComposition().coverageLayer()->id() );
555  if ( removeAt != -1 )
556  {
557  renderLayerSet.removeAt( removeAt );
558  }
559  }
560  }
561 
562  return renderLayerSet;
563 }
564 
565 double QgsComposerMap::scale() const
566 {
567  QgsScaleCalculator calculator;
568  calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
569  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
570  return calculator.calculate( *currentMapExtent(), rect().width() );
571 }
572 
573 void QgsComposerMap::resize( double dx, double dy )
574 {
575  //setRect
576  QRectF currentRect = rect();
577  QRectF newSceneRect = QRectF( pos().x(), pos().y(), currentRect.width() + dx, currentRect.height() + dy );
578  setSceneRect( newSceneRect );
579  updateItem();
580 }
581 
582 void QgsComposerMap::moveContent( double dx, double dy )
583 {
584  if ( !mDrawing )
585  {
586  transformShift( dx, dy );
587  currentMapExtent()->setXMinimum( currentMapExtent()->xMinimum() + dx );
588  currentMapExtent()->setXMaximum( currentMapExtent()->xMaximum() + dx );
589  currentMapExtent()->setYMinimum( currentMapExtent()->yMinimum() + dy );
590  currentMapExtent()->setYMaximum( currentMapExtent()->yMaximum() + dy );
591  cache();
592  update();
593  emit itemChanged();
594  emit extentChanged();
595  }
596 }
597 
598 void QgsComposerMap::zoomContent( int delta, double x, double y )
599 {
600  if ( mDrawing )
601  {
602  return;
603  }
604 
605  QSettings settings;
606 
607  //read zoom mode
608  //0: zoom, 1: zoom and recenter, 2: zoom to cursor, 3: nothing
609  int zoomMode = settings.value( "/qgis/wheel_action", 2 ).toInt();
610  if ( zoomMode == 3 ) //do nothing
611  {
612  return;
613  }
614 
615  double zoomFactor = settings.value( "/qgis/zoom_factor", 2.0 ).toDouble();
616 
617  //find out new center point
618  double centerX = ( currentMapExtent()->xMaximum() + currentMapExtent()->xMinimum() ) / 2;
619  double centerY = ( currentMapExtent()->yMaximum() + currentMapExtent()->yMinimum() ) / 2;
620 
621  if ( zoomMode != 0 )
622  {
623  //find out map coordinates of mouse position
624  double mapMouseX = currentMapExtent()->xMinimum() + ( x / rect().width() ) * ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() );
625  double mapMouseY = currentMapExtent()->yMinimum() + ( 1 - ( y / rect().height() ) ) * ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() );
626  if ( zoomMode == 1 ) //zoom and recenter
627  {
628  centerX = mapMouseX;
629  centerY = mapMouseY;
630  }
631  else if ( zoomMode == 2 ) //zoom to cursor
632  {
633  centerX = mapMouseX + ( centerX - mapMouseX ) * ( 1.0 / zoomFactor );
634  centerY = mapMouseY + ( centerY - mapMouseY ) * ( 1.0 / zoomFactor );
635  }
636  }
637 
638  double newIntervalX, newIntervalY;
639 
640  if ( delta > 0 )
641  {
642  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) / zoomFactor;
643  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) / zoomFactor;
644  }
645  else if ( delta < 0 )
646  {
647  newIntervalX = ( currentMapExtent()->xMaximum() - currentMapExtent()->xMinimum() ) * zoomFactor;
648  newIntervalY = ( currentMapExtent()->yMaximum() - currentMapExtent()->yMinimum() ) * zoomFactor;
649  }
650  else //no need to zoom
651  {
652  return;
653  }
654 
655  currentMapExtent()->setXMaximum( centerX + newIntervalX / 2 );
656  currentMapExtent()->setXMinimum( centerX - newIntervalX / 2 );
657  currentMapExtent()->setYMaximum( centerY + newIntervalY / 2 );
658  currentMapExtent()->setYMinimum( centerY - newIntervalY / 2 );
659 
661  {
662  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanant
663  //and also apply to the map's original extent (see #9602)
664  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
665  QgsScaleCalculator calculator;
666  calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
667  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
668  double scaleRatio = scale() / calculator.calculate( mExtent, rect().width() );
669  mExtent.scale( scaleRatio );
670  }
671 
672  cache();
673  update();
674  emit itemChanged();
675  emit extentChanged();
676 }
677 
678 void QgsComposerMap::setSceneRect( const QRectF& rectangle )
679 {
680  double w = rectangle.width();
681  double h = rectangle.height();
682  //prepareGeometryChange();
683 
684  QgsComposerItem::setSceneRect( rectangle );
685 
686  //QGraphicsRectItem::update();
687  double newHeight = mExtent.width() * h / w ;
689  mCacheUpdated = false;
690 
692  update();
693  emit itemChanged();
694  emit extentChanged();
695 }
696 
698 {
699  if ( mExtent == extent )
700  {
701  return;
702  }
703  mExtent = extent;
704 
705  //adjust height
706  QRectF currentRect = rect();
707 
708  double newHeight = currentRect.width() * extent.height() / extent.width();
709 
710  setSceneRect( QRectF( pos().x(), pos().y(), currentRect.width(), newHeight ) );
711  updateItem();
712 }
713 
715 {
716  if ( mAtlasFeatureExtent == extent )
717  {
718  emit preparedForAtlas();
719  return;
720  }
721 
722  //don't adjust size of item, instead adjust size of bounds to fit
723  QgsRectangle newExtent = extent;
724 
725  //Make sure the width/height ratio is the same as the map item size
726  double currentWidthHeightRatio = rect().width() / rect().height();
727  double newWidthHeightRatio = newExtent.width() / newExtent.height();
728 
729  if ( currentWidthHeightRatio < newWidthHeightRatio )
730  {
731  //enlarge height of new extent, ensuring the map center stays the same
732  double newHeight = newExtent.width() / currentWidthHeightRatio;
733  double deltaHeight = newHeight - newExtent.height();
734  newExtent.setYMinimum( extent.yMinimum() - deltaHeight / 2 );
735  newExtent.setYMaximum( extent.yMaximum() + deltaHeight / 2 );
736  }
737  else if ( currentWidthHeightRatio >= newWidthHeightRatio )
738  {
739  //enlarge width of new extent, ensuring the map center stays the same
740  double newWidth = currentWidthHeightRatio * newExtent.height();
741  double deltaWidth = newWidth - newExtent.width();
742  newExtent.setXMinimum( extent.xMinimum() - deltaWidth / 2 );
743  newExtent.setXMaximum( extent.xMaximum() + deltaWidth / 2 );
744  }
745 
746  mAtlasFeatureExtent = newExtent;
747  mCacheUpdated = false;
748  emit preparedForAtlas();
749  updateItem();
750  emit itemChanged();
751  emit extentChanged();
752 }
753 
755 {
756  //atlas preview has been toggled, so update item and extents
757  mCacheUpdated = false;
758  updateItem();
759  emit itemChanged();
760  emit extentChanged();
761 }
762 
764 {
765  //non-const version
767  {
768  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
769  //return the current temporary atlas feature extent
770  return &mAtlasFeatureExtent;
771  }
772  else
773  {
774  //otherwise return permenant user set extent
775  return &mExtent;
776  }
777 }
778 
780 {
781  //const version
783  {
784  //if atlas is enabled, and we are either exporting the composition or previewing the atlas, then
785  //return the current temporary atlas feature extent
786  return &mAtlasFeatureExtent;
787  }
788  else
789  {
790  //otherwise return permenant user set extent
791  return &mExtent;
792  }
793 }
794 
795 void QgsComposerMap::setNewScale( double scaleDenominator )
796 {
797  double currentScaleDenominator = scale();
798 
799  if ( scaleDenominator == currentScaleDenominator || scaleDenominator == 0 )
800  {
801  return;
802  }
803 
804  double scaleRatio = scaleDenominator / currentScaleDenominator;
805  currentMapExtent()->scale( scaleRatio );
806 
808  {
809  //if map is atlas controlled and set to fixed scaling mode, then scale changes should be treated as permanant
810  //and also apply to the map's original extent (see #9602)
811  //we can't use the scaleRatio calculated earlier, as the scale can vary depending on extent for geographic coordinate systems
812  QgsScaleCalculator calculator;
813  calculator.setMapUnits( mComposition->mapSettings().mapUnits() );
814  calculator.setDpi( 25.4 ); //QGraphicsView units are mm
815  scaleRatio = scaleDenominator / calculator.calculate( mExtent, rect().width() );
816  mExtent.scale( scaleRatio );
817  }
818 
819  mCacheUpdated = false;
820  cache();
821  update();
822  emit itemChanged();
823  emit extentChanged();
824 }
825 
827 {
828  mPreviewMode = m;
829  emit itemChanged();
830 }
831 
832 void QgsComposerMap::setOffset( double xOffset, double yOffset )
833 {
834  mXOffset = xOffset;
835  mYOffset = yOffset;
836 }
837 
839 {
840  //kept for api compatibility with QGIS 2.0
841  setMapRotation( r );
842 }
843 
845 {
846  mMapRotation = r;
847  emit mapRotationChanged( r );
848  emit itemChanged();
849  update();
850 }
851 
853 {
854  if ( !mUpdatesEnabled )
855  {
856  return;
857  }
858 
860  {
861  cache();
862  }
864 }
865 
867 {
868  QStringList layers = mComposition->mapSettings().layers();
869 
870  QStringList::const_iterator layer_it = layers.constBegin();
871  QgsMapLayer* currentLayer = 0;
872 
873  for ( ; layer_it != layers.constEnd(); ++layer_it )
874  {
875  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
876  if ( currentLayer )
877  {
878  QgsRasterLayer* currentRasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
879  if ( currentRasterLayer )
880  {
881  const QgsRasterDataProvider* rasterProvider = 0;
882  if (( rasterProvider = currentRasterLayer->dataProvider() ) )
883  {
884  if ( rasterProvider->name() == "wms" )
885  {
886  return true;
887  }
888  }
889  }
890  }
891  }
892  return false;
893 }
894 
896 {
897  // check if map contains advanced effects like blend modes, or flattened layers for transparency
898 
899  QStringList layers = mComposition->mapSettings().layers();
900 
901  QStringList::const_iterator layer_it = layers.constBegin();
902  QgsMapLayer* currentLayer = 0;
903 
904  for ( ; layer_it != layers.constEnd(); ++layer_it )
905  {
906  currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
907  if ( currentLayer )
908  {
909  if ( currentLayer->blendMode() != QPainter::CompositionMode_SourceOver )
910  {
911  return true;
912  }
913  // if vector layer, check labels and feature blend mode
914  QgsVectorLayer* currentVectorLayer = qobject_cast<QgsVectorLayer *>( currentLayer );
915  if ( currentVectorLayer )
916  {
917  if ( currentVectorLayer->layerTransparency() != 0 )
918  {
919  return true;
920  }
921  if ( currentVectorLayer->featureBlendMode() != QPainter::CompositionMode_SourceOver )
922  {
923  return true;
924  }
925  // check label blend modes
926  if ( QgsPalLabeling::staticWillUseLayer( currentVectorLayer ) )
927  {
928  // Check all label blending properties
929  QgsPalLayerSettings layerSettings = QgsPalLayerSettings::fromLayer( currentVectorLayer );
930  if (( layerSettings.blendMode != QPainter::CompositionMode_SourceOver ) ||
931  ( layerSettings.bufferSize != 0 && layerSettings.bufferBlendMode != QPainter::CompositionMode_SourceOver ) ||
932  ( layerSettings.shadowDraw && layerSettings.shadowBlendMode != QPainter::CompositionMode_SourceOver ) ||
933  ( layerSettings.shapeDraw && layerSettings.shapeBlendMode != QPainter::CompositionMode_SourceOver ) )
934  {
935  return true;
936  }
937  }
938  }
939  }
940  }
941 
942  return false;
943 }
944 
946 {
947  //connect signal from layer registry to update in case of new or deleted layers
949  if ( layerRegistry )
950  {
951  connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( updateCachedImage() ) );
952  connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( updateCachedImage() ) );
953  }
954 }
955 
956 bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
957 {
958  if ( elem.isNull() )
959  {
960  return false;
961  }
962 
963  QDomElement composerMapElem = doc.createElement( "ComposerMap" );
964  composerMapElem.setAttribute( "id", mId );
965 
966  //previewMode
967  if ( mPreviewMode == Cache )
968  {
969  composerMapElem.setAttribute( "previewMode", "Cache" );
970  }
971  else if ( mPreviewMode == Render )
972  {
973  composerMapElem.setAttribute( "previewMode", "Render" );
974  }
975  else //rectangle
976  {
977  composerMapElem.setAttribute( "previewMode", "Rectangle" );
978  }
979 
980  if ( mKeepLayerSet )
981  {
982  composerMapElem.setAttribute( "keepLayerSet", "true" );
983  }
984  else
985  {
986  composerMapElem.setAttribute( "keepLayerSet", "false" );
987  }
988 
989  if ( mDrawCanvasItems )
990  {
991  composerMapElem.setAttribute( "drawCanvasItems", "true" );
992  }
993  else
994  {
995  composerMapElem.setAttribute( "drawCanvasItems", "false" );
996  }
997 
998  //overview map frame
999  QDomElement overviewFrameElem = doc.createElement( "overviewFrame" );
1000  overviewFrameElem.setAttribute( "overviewFrameMap", mOverviewFrameMapId );
1001  overviewFrameElem.setAttribute( "overviewBlendMode", QgsMapRenderer::getBlendModeEnum( mOverviewBlendMode ) );
1002  if ( mOverviewInverted )
1003  {
1004  overviewFrameElem.setAttribute( "overviewInverted", "true" );
1005  }
1006  else
1007  {
1008  overviewFrameElem.setAttribute( "overviewInverted", "false" );
1009  }
1010 
1011  overviewFrameElem.setAttribute( "overviewCentered", mOverviewCentered ? "true" : "false" );
1012 
1013  QDomElement overviewFrameStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mOverviewFrameMapSymbol, doc );
1014  overviewFrameElem.appendChild( overviewFrameStyleElem );
1015  composerMapElem.appendChild( overviewFrameElem );
1016 
1017 
1018  //extent
1019  QDomElement extentElem = doc.createElement( "Extent" );
1020  extentElem.setAttribute( "xmin", qgsDoubleToString( mExtent.xMinimum() ) );
1021  extentElem.setAttribute( "xmax", qgsDoubleToString( mExtent.xMaximum() ) );
1022  extentElem.setAttribute( "ymin", qgsDoubleToString( mExtent.yMinimum() ) );
1023  extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) );
1024  composerMapElem.appendChild( extentElem );
1025 
1026  //map rotation
1027  composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) );
1028 
1029  //layer set
1030  QDomElement layerSetElem = doc.createElement( "LayerSet" );
1031  QStringList::const_iterator layerIt = mLayerSet.constBegin();
1032  for ( ; layerIt != mLayerSet.constEnd(); ++layerIt )
1033  {
1034  QDomElement layerElem = doc.createElement( "Layer" );
1035  QDomText layerIdText = doc.createTextNode( *layerIt );
1036  layerElem.appendChild( layerIdText );
1037  layerSetElem.appendChild( layerElem );
1038  }
1039  composerMapElem.appendChild( layerSetElem );
1040 
1041  //overview map frame
1042  composerMapElem.setAttribute( "overviewFrameMap", mOverviewFrameMapId );
1043 
1044  //grid
1045  QDomElement gridElem = doc.createElement( "Grid" );
1046  gridElem.setAttribute( "show", mGridEnabled );
1047  gridElem.setAttribute( "gridStyle", mGridStyle );
1048  gridElem.setAttribute( "intervalX", qgsDoubleToString( mGridIntervalX ) );
1049  gridElem.setAttribute( "intervalY", qgsDoubleToString( mGridIntervalY ) );
1050  gridElem.setAttribute( "offsetX", qgsDoubleToString( mGridOffsetX ) );
1051  gridElem.setAttribute( "offsetY", qgsDoubleToString( mGridOffsetY ) );
1052  gridElem.setAttribute( "crossLength", qgsDoubleToString( mCrossLength ) );
1053  gridElem.setAttribute( "gridFrameStyle", mGridFrameStyle );
1054  gridElem.setAttribute( "gridFrameWidth", qgsDoubleToString( mGridFrameWidth ) );
1055  gridElem.setAttribute( "gridFramePenThickness", qgsDoubleToString( mGridFramePenThickness ) );
1056  //grid frame pen color
1057  QDomElement framePenColorElem = doc.createElement( "framePenColor" );
1058  framePenColorElem.setAttribute( "red", mGridFramePenColor.red() );
1059  framePenColorElem.setAttribute( "green", mGridFramePenColor.green() );
1060  framePenColorElem.setAttribute( "blue", mGridFramePenColor.blue() );
1061  framePenColorElem.setAttribute( "alpha", mGridFramePenColor.alpha() );
1062  gridElem.appendChild( framePenColorElem );
1063  //grid frame fill colors
1064  QDomElement frameFillColor1Elem = doc.createElement( "frameFillColor1" );
1065  frameFillColor1Elem.setAttribute( "red", mGridFrameFillColor1.red() );
1066  frameFillColor1Elem.setAttribute( "green", mGridFrameFillColor1.green() );
1067  frameFillColor1Elem.setAttribute( "blue", mGridFrameFillColor1.blue() );
1068  frameFillColor1Elem.setAttribute( "alpha", mGridFrameFillColor1.alpha() );
1069  gridElem.appendChild( frameFillColor1Elem );
1070  QDomElement frameFillColor2Elem = doc.createElement( "frameFillColor2" );
1071  frameFillColor2Elem.setAttribute( "red", mGridFrameFillColor2.red() );
1072  frameFillColor2Elem.setAttribute( "green", mGridFrameFillColor2.green() );
1073  frameFillColor2Elem.setAttribute( "blue", mGridFrameFillColor2.blue() );
1074  frameFillColor2Elem.setAttribute( "alpha", mGridFrameFillColor2.alpha() );
1075  gridElem.appendChild( frameFillColor2Elem );
1076 
1077  gridElem.setAttribute( "gridBlendMode", QgsMapRenderer::getBlendModeEnum( mGridBlendMode ) );
1078  QDomElement gridLineStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mGridLineSymbol, doc );
1079  gridElem.appendChild( gridLineStyleElem );
1080 
1081  //grid annotation
1082  QDomElement annotationElem = doc.createElement( "Annotation" );
1083  annotationElem.setAttribute( "format", mGridAnnotationFormat );
1084  annotationElem.setAttribute( "show", mShowGridAnnotation );
1085  annotationElem.setAttribute( "leftPosition", mLeftGridAnnotationPosition );
1086  annotationElem.setAttribute( "rightPosition", mRightGridAnnotationPosition );
1087  annotationElem.setAttribute( "topPosition", mTopGridAnnotationPosition );
1088  annotationElem.setAttribute( "bottomPosition", mBottomGridAnnotationPosition );
1089  annotationElem.setAttribute( "leftDirection", mLeftGridAnnotationDirection );
1090  annotationElem.setAttribute( "rightDirection", mRightGridAnnotationDirection );
1091  annotationElem.setAttribute( "topDirection", mTopGridAnnotationDirection );
1092  annotationElem.setAttribute( "bottomDirection", mBottomGridAnnotationDirection );
1093  annotationElem.setAttribute( "frameDistance", QString::number( mAnnotationFrameDistance ) );
1094  annotationElem.setAttribute( "font", mGridAnnotationFont.toString() );
1095  annotationElem.setAttribute( "precision", mGridAnnotationPrecision );
1096  //annotation font color
1097  QDomElement annotationFontColorElem = doc.createElement( "fontColor" );
1098  annotationFontColorElem.setAttribute( "red", mGridAnnotationFontColor.red() );
1099  annotationFontColorElem.setAttribute( "green", mGridAnnotationFontColor.green() );
1100  annotationFontColorElem.setAttribute( "blue", mGridAnnotationFontColor.blue() );
1101  annotationFontColorElem.setAttribute( "alpha", mGridAnnotationFontColor.alpha() );
1102  annotationElem.appendChild( annotationFontColorElem );
1103 
1104  gridElem.appendChild( annotationElem );
1105  composerMapElem.appendChild( gridElem );
1106 
1107  //atlas
1108  QDomElement atlasElem = doc.createElement( "AtlasMap" );
1109  atlasElem.setAttribute( "atlasDriven", mAtlasDriven );
1110  atlasElem.setAttribute( "scalingMode", mAtlasScalingMode );
1111  atlasElem.setAttribute( "margin", qgsDoubleToString( mAtlasMargin ) );
1112  composerMapElem.appendChild( atlasElem );
1113 
1114  elem.appendChild( composerMapElem );
1115  return _writeXML( composerMapElem, doc );
1116 }
1117 
1118 bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& doc )
1119 {
1120  if ( itemElem.isNull() )
1121  {
1122  return false;
1123  }
1124 
1125  QString idRead = itemElem.attribute( "id", "not found" );
1126  if ( idRead != "not found" )
1127  {
1128  mId = idRead.toInt();
1129  }
1131 
1132  //previewMode
1133  QString previewMode = itemElem.attribute( "previewMode" );
1134  if ( previewMode == "Cache" )
1135  {
1136  mPreviewMode = Cache;
1137  }
1138  else if ( previewMode == "Render" )
1139  {
1140  mPreviewMode = Render;
1141  }
1142  else
1143  {
1145  }
1146 
1147  QDomElement overviewFrameElem = itemElem.firstChildElement( "overviewFrame" );
1148  if ( !overviewFrameElem.isNull() )
1149  {
1150  setOverviewFrameMap( overviewFrameElem.attribute( "overviewFrameMap", "-1" ).toInt() );
1151  setOverviewBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) overviewFrameElem.attribute( "overviewBlendMode", "0" ).toUInt() ) );
1152 
1153  QString overviewInvertedFlag = overviewFrameElem.attribute( "overviewInverted" );
1154  if ( overviewInvertedFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1155  {
1156  setOverviewInverted( true );
1157  }
1158  else
1159  {
1160  setOverviewInverted( false );
1161  }
1162 
1163  if ( overviewFrameElem.attribute( "overviewCentered" ).compare( "true", Qt::CaseInsensitive ) == 0 )
1164  {
1165  mOverviewCentered = true;
1166  }
1167  else
1168  {
1169  mOverviewCentered = false;
1170  }
1171 
1172  QDomElement overviewFrameSymbolElem = overviewFrameElem.firstChildElement( "symbol" );
1173  if ( !overviewFrameSymbolElem.isNull() )
1174  {
1175  delete mOverviewFrameMapSymbol;
1176  mOverviewFrameMapSymbol = dynamic_cast<QgsFillSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( overviewFrameSymbolElem ) );
1177  }
1178  }
1179 
1180  //extent
1181  QDomNodeList extentNodeList = itemElem.elementsByTagName( "Extent" );
1182  if ( extentNodeList.size() > 0 )
1183  {
1184  QDomElement extentElem = extentNodeList.at( 0 ).toElement();
1185  double xmin, xmax, ymin, ymax;
1186  xmin = extentElem.attribute( "xmin" ).toDouble();
1187  xmax = extentElem.attribute( "xmax" ).toDouble();
1188  ymin = extentElem.attribute( "ymin" ).toDouble();
1189  ymax = extentElem.attribute( "ymax" ).toDouble();
1190  setNewExtent( QgsRectangle( xmin, ymin, xmax, ymax ) );
1191  }
1192 
1193  //map rotation
1194  if ( itemElem.attribute( "mapRotation", "0" ).toDouble() != 0 )
1195  {
1196  mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble();
1197  }
1198 
1199  //mKeepLayerSet flag
1200  QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
1201  if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1202  {
1203  mKeepLayerSet = true;
1204  }
1205  else
1206  {
1207  mKeepLayerSet = false;
1208  }
1209 
1210  QString drawCanvasItemsFlag = itemElem.attribute( "drawCanvasItems", "true" );
1211  if ( drawCanvasItemsFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
1212  {
1213  mDrawCanvasItems = true;
1214  }
1215  else
1216  {
1217  mDrawCanvasItems = false;
1218  }
1219 
1220  //mLayerSet
1221  QDomNodeList layerSetNodeList = itemElem.elementsByTagName( "LayerSet" );
1222  QStringList layerSet;
1223  if ( layerSetNodeList.size() > 0 )
1224  {
1225  QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
1226  QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( "Layer" );
1227  for ( int i = 0; i < layerIdNodeList.size(); ++i )
1228  {
1229  layerSet << layerIdNodeList.at( i ).toElement().text();
1230  }
1231  }
1232  mLayerSet = layerSet;
1233 
1234  mDrawing = false;
1235  mNumCachedLayers = 0;
1236  mCacheUpdated = false;
1237 
1238  //grid
1239  QDomNodeList gridNodeList = itemElem.elementsByTagName( "Grid" );
1240  if ( gridNodeList.size() > 0 )
1241  {
1242  QDomElement gridElem = gridNodeList.at( 0 ).toElement();
1243  mGridEnabled = ( gridElem.attribute( "show", "0" ) != "0" );
1244  mGridStyle = QgsComposerMap::GridStyle( gridElem.attribute( "gridStyle", "0" ).toInt() );
1245  mGridIntervalX = gridElem.attribute( "intervalX", "0" ).toDouble();
1246  mGridIntervalY = gridElem.attribute( "intervalY", "0" ).toDouble();
1247  mGridOffsetX = gridElem.attribute( "offsetX", "0" ).toDouble();
1248  mGridOffsetY = gridElem.attribute( "offsetY", "0" ).toDouble();
1249  mCrossLength = gridElem.attribute( "crossLength", "3" ).toDouble();
1250  mGridFrameStyle = ( QgsComposerMap::GridFrameStyle )gridElem.attribute( "gridFrameStyle", "0" ).toInt();
1251  mGridFrameWidth = gridElem.attribute( "gridFrameWidth", "2.0" ).toDouble();
1252  mGridFramePenThickness = gridElem.attribute( "gridFramePenThickness", "0.5" ).toDouble();
1253 
1254  //grid frame pen color
1255  QDomNodeList gridFramePenColorList = gridElem.elementsByTagName( "framePenColor" );
1256  if ( gridFramePenColorList.size() > 0 )
1257  {
1258  QDomElement penColorElem = gridFramePenColorList.at( 0 ).toElement();
1259  int red = penColorElem.attribute( "red", "0" ).toInt();
1260  int green = penColorElem.attribute( "green", "0" ).toInt();
1261  int blue = penColorElem.attribute( "blue", "0" ).toInt();
1262  int alpha = penColorElem.attribute( "alpha", "255" ).toInt();
1263  mGridFramePenColor = QColor( red, green, blue, alpha );
1264  }
1265  else
1266  {
1267  mGridFramePenColor = QColor( 0, 0, 0 );
1268  }
1269  //grid frame fill color 1
1270  QDomNodeList gridFrameFillColor1List = gridElem.elementsByTagName( "frameFillColor1" );
1271  if ( gridFrameFillColor1List.size() > 0 )
1272  {
1273  QDomElement fillColorElem = gridFrameFillColor1List.at( 0 ).toElement();
1274  int red = fillColorElem.attribute( "red", "0" ).toInt();
1275  int green = fillColorElem.attribute( "green", "0" ).toInt();
1276  int blue = fillColorElem.attribute( "blue", "0" ).toInt();
1277  int alpha = fillColorElem.attribute( "alpha", "255" ).toInt();
1278  mGridFrameFillColor1 = QColor( red, green, blue, alpha );
1279  }
1280  else
1281  {
1282  mGridFrameFillColor1 = Qt::white;
1283  }
1284  //grid frame fill color 2
1285  QDomNodeList gridFrameFillColor2List = gridElem.elementsByTagName( "frameFillColor2" );
1286  if ( gridFrameFillColor2List.size() > 0 )
1287  {
1288  QDomElement fillColorElem = gridFrameFillColor2List.at( 0 ).toElement();
1289  int red = fillColorElem.attribute( "red", "0" ).toInt();
1290  int green = fillColorElem.attribute( "green", "0" ).toInt();
1291  int blue = fillColorElem.attribute( "blue", "0" ).toInt();
1292  int alpha = fillColorElem.attribute( "alpha", "255" ).toInt();
1293  mGridFrameFillColor2 = QColor( red, green, blue, alpha );
1294  }
1295  else
1296  {
1297  mGridFrameFillColor2 = Qt::black;
1298  }
1299 
1300  setGridBlendMode( QgsMapRenderer::getCompositionMode(( QgsMapRenderer::BlendMode ) gridElem.attribute( "gridBlendMode", "0" ).toUInt() ) );
1301 
1302  QDomElement gridSymbolElem = gridElem.firstChildElement( "symbol" );
1303  delete mGridLineSymbol;
1304  if ( gridSymbolElem.isNull( ) )
1305  {
1306  //old project file, read penWidth /penColorRed, penColorGreen, penColorBlue
1308  mGridLineSymbol->setWidth( gridElem.attribute( "penWidth", "0" ).toDouble() );
1309  mGridLineSymbol->setColor( QColor( gridElem.attribute( "penColorRed", "0" ).toInt(),
1310  gridElem.attribute( "penColorGreen", "0" ).toInt(),
1311  gridElem.attribute( "penColorBlue", "0" ).toInt() ) );
1312  }
1313  else
1314  {
1315  mGridLineSymbol = dynamic_cast<QgsLineSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( gridSymbolElem ) );
1316  }
1317 
1318  QDomNodeList annotationNodeList = gridElem.elementsByTagName( "Annotation" );
1319  if ( annotationNodeList.size() > 0 )
1320  {
1321  QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
1322  mShowGridAnnotation = ( annotationElem.attribute( "show", "0" ) != "0" );
1323  mGridAnnotationFormat = QgsComposerMap::GridAnnotationFormat( annotationElem.attribute( "format", "0" ).toInt() );
1324  mLeftGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "leftPosition", "0" ).toInt() );
1325  mRightGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "rightPosition", "0" ).toInt() );
1326  mTopGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "topPosition", "0" ).toInt() );
1327  mBottomGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "bottomPosition", "0" ).toInt() );
1328  mLeftGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "leftDirection", "0" ).toInt() );
1329  mRightGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "rightDirection", "0" ).toInt() );
1330  mTopGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "topDirection", "0" ).toInt() );
1331  mBottomGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "bottomDirection", "0" ).toInt() );
1332  mAnnotationFrameDistance = annotationElem.attribute( "frameDistance", "0" ).toDouble();
1333  mGridAnnotationFont.fromString( annotationElem.attribute( "font", "" ) );
1334 
1335  //annotation font color
1336  QDomNodeList annotationFontColorList = annotationElem.elementsByTagName( "fontColor" );
1337  if ( annotationFontColorList.size() > 0 )
1338  {
1339  QDomElement fontColorElem = annotationFontColorList.at( 0 ).toElement();
1340  int red = fontColorElem.attribute( "red", "0" ).toInt();
1341  int green = fontColorElem.attribute( "green", "0" ).toInt();
1342  int blue = fontColorElem.attribute( "blue", "0" ).toInt();
1343  int alpha = fontColorElem.attribute( "alpha", "255" ).toInt();
1344  mGridAnnotationFontColor = QColor( red, green, blue, alpha );
1345  }
1346  else
1347  {
1348  mGridAnnotationFontColor = QColor( 0, 0, 0 );
1349  }
1350 
1351  mGridAnnotationPrecision = annotationElem.attribute( "precision", "3" ).toInt();
1352  }
1353  }
1354 
1355  //atlas
1356  QDomNodeList atlasNodeList = itemElem.elementsByTagName( "AtlasMap" );
1357  if ( atlasNodeList.size() > 0 )
1358  {
1359  QDomElement atlasElem = atlasNodeList.at( 0 ).toElement();
1360  mAtlasDriven = ( atlasElem.attribute( "atlasDriven", "0" ) != "0" );
1361  if ( atlasElem.hasAttribute( "fixedScale" ) ) // deprecated XML
1362  {
1363  mAtlasScalingMode = ( atlasElem.attribute( "fixedScale", "0" ) != "0" ) ? Fixed : Auto;
1364  }
1365  else if ( atlasElem.hasAttribute( "scalingMode" ) )
1366  {
1367  mAtlasScalingMode = static_cast<AtlasScalingMode>( atlasElem.attribute( "scalingMode" ).toInt() );
1368  }
1369  mAtlasMargin = atlasElem.attribute( "margin", "0.1" ).toDouble();
1370  }
1371 
1372  //restore general composer item properties
1373  QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
1374  if ( composerItemList.size() > 0 )
1375  {
1376  QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
1377 
1378  if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 )
1379  {
1380  //in versions prior to 2.1 map rotation was stored in the rotation attribute
1381  mMapRotation = composerItemElem.attribute( "rotation", "0" ).toDouble();
1382  }
1383 
1384  _readXML( composerItemElem, doc );
1385  }
1386 
1388  emit itemChanged();
1389  return true;
1390 }
1391 
1393 {
1395 }
1396 
1398 {
1399  if ( mLayerSet.size() < 1 )
1400  {
1401  return;
1402  }
1403 
1404  //if layer set is fixed, do a lookup in the layer registry to also find the non-visible layers
1405  QStringList currentLayerSet;
1406  if ( mKeepLayerSet )
1407  {
1408  currentLayerSet = QgsMapLayerRegistry::instance()->mapLayers().uniqueKeys();
1409  }
1410  else //only consider layers visible in the map
1411  {
1412  currentLayerSet = mComposition->mapSettings().layers();
1413  }
1414 
1415  for ( int i = mLayerSet.size() - 1; i >= 0; --i )
1416  {
1417  if ( !currentLayerSet.contains( mLayerSet.at( i ) ) )
1418  {
1419  mLayerSet.removeAt( i );
1420  }
1421  }
1422 }
1423 
1424 void QgsComposerMap::drawGrid( QPainter* p )
1425 {
1426  QList< QPair< double, QLineF > > verticalLines;
1427  yGridLines( verticalLines );
1428  QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
1429  QList< QPair< double, QLineF > > horizontalLines;
1430  xGridLines( horizontalLines );
1431  QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
1432 
1433  QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
1434  p->setClipRect( thisPaintRect );
1435 
1436  QPaintDevice* thePaintDevice = p->device();
1437  if ( !thePaintDevice )
1438  {
1439  return;
1440  }
1441 
1442  // set the blend mode for drawing grid lines
1443  p->save();
1444  p->setCompositionMode( mGridBlendMode );
1445  p->setRenderHint( QPainter::Antialiasing );
1446 
1447  //setup painter scaling to dots so that raster symbology is drawn to scale
1448  double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
1449  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
1450 
1451  //setup render context
1453  //context units should be in dots
1454  ms.setOutputSize( QSizeF( rect().width() * dotsPerMM, rect().height() * dotsPerMM ).toSize() );
1455  ms.setExtent( *currentMapExtent() );
1456  ms.setOutputDpi( p->device()->logicalDpiX() );
1458  context.setForceVectorOutput( true );
1459  context.setPainter( p );
1460 
1461  //simpler approach: draw vertical lines first, then horizontal ones
1463  {
1464  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
1465  QLineF line;
1466  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1467  {
1468  line = QLineF( vIt->second.p1() * dotsPerMM, vIt->second.p2() * dotsPerMM ) ;
1469  drawGridLine( line, context );
1470  }
1471 
1472  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1473  {
1474  line = QLineF( hIt->second.p1() * dotsPerMM, hIt->second.p2() * dotsPerMM ) ;
1475  drawGridLine( line, context );
1476  }
1477  }
1478  else //cross
1479  {
1480  QPointF intersectionPoint, crossEnd1, crossEnd2;
1481  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1482  {
1483  //start mark
1484  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
1485  drawGridLine( QLineF( vIt->second.p1() * dotsPerMM, crossEnd1 * dotsPerMM ), context );
1486 
1487  //test for intersection with every horizontal line
1488  hIt = horizontalLines.constBegin();
1489  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1490  {
1491  if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
1492  {
1493  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength );
1494  crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength );
1495  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
1496  }
1497  }
1498  //end mark
1499  QPointF crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
1500  drawGridLine( QLineF( vIt->second.p2() * dotsPerMM, crossEnd2 * dotsPerMM ), context );
1501  }
1502 
1503  hIt = horizontalLines.constBegin();
1504  for ( ; hIt != horizontalLines.constEnd(); ++hIt )
1505  {
1506  //start mark
1507  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
1508  drawGridLine( QLineF( hIt->second.p1() * dotsPerMM, crossEnd1 * dotsPerMM ), context );
1509 
1510  vIt = verticalLines.constBegin();
1511  for ( ; vIt != verticalLines.constEnd(); ++vIt )
1512  {
1513  if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
1514  {
1515  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength );
1516  crossEnd2 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength );
1517  drawGridLine( QLineF( crossEnd1 * dotsPerMM, crossEnd2 * dotsPerMM ), context );
1518  }
1519  }
1520  //end mark
1521  crossEnd1 = QgsSymbolLayerV2Utils::pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
1522  drawGridLine( QLineF( hIt->second.p2() * dotsPerMM, crossEnd1 * dotsPerMM ), context );
1523  }
1524  }
1525  // reset composition mode
1526  p->restore();
1527 
1528  p->setClipRect( thisPaintRect , Qt::NoClip );
1529 
1531  {
1532  drawGridFrame( p, horizontalLines, verticalLines );
1533  }
1534 
1535  if ( mShowGridAnnotation )
1536  {
1537  drawCoordinateAnnotations( p, horizontalLines, verticalLines );
1538  }
1539 
1540 }
1541 
1542 void QgsComposerMap::drawGridFrame( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
1543 {
1544  //Sort the coordinate positions for each side
1545  QMap< double, double > leftGridFrame;
1546  QMap< double, double > rightGridFrame;
1547  QMap< double, double > topGridFrame;
1548  QMap< double, double > bottomGridFrame;
1549 
1550  sortGridLinesOnBorders( hLines, vLines, leftGridFrame, rightGridFrame, topGridFrame, bottomGridFrame );
1551 
1552  drawGridFrameBorder( p, leftGridFrame, QgsComposerMap::Left );
1553  drawGridFrameBorder( p, rightGridFrame, QgsComposerMap::Right );
1554  drawGridFrameBorder( p, topGridFrame, QgsComposerMap::Top );
1555  drawGridFrameBorder( p, bottomGridFrame, QgsComposerMap::Bottom );
1556 }
1557 
1558 void QgsComposerMap::drawGridLine( const QLineF& line, QgsRenderContext& context )
1559 {
1560  if ( !mGridLineSymbol )
1561  {
1562  return;
1563  }
1564  if ( mPreviewMode == Rectangle )
1565  {
1566  return;
1567  }
1568 
1569  QPolygonF poly;
1570  poly << line.p1() << line.p2();
1571  mGridLineSymbol->startRender( context );
1572  mGridLineSymbol->renderPolyline( poly, 0, context );
1573  mGridLineSymbol->stopRender( context );
1574 }
1575 
1576 void QgsComposerMap::drawGridFrameBorder( QPainter* p, const QMap< double, double >& borderPos, Border border )
1577 {
1578  double currentCoord = - mGridFrameWidth;
1579  bool color1 = true;
1580  double x = 0;
1581  double y = 0;
1582  double width = 0;
1583  double height = 0;
1584 
1585  QMap< double, double > pos = borderPos;
1586  pos.insert( 0, 0 );
1587  if ( border == Left || border == Right )
1588  {
1589  pos.insert( rect().height(), rect().height() );
1590  pos.insert( rect().height() + mGridFrameWidth, rect().height() + mGridFrameWidth );
1591  }
1592  else //top or bottom
1593  {
1594  pos.insert( rect().width(), rect().width() );
1595  pos.insert( rect().width() + mGridFrameWidth, rect().width() + mGridFrameWidth );
1596  }
1597 
1598  //set pen to current frame pen
1599  QPen framePen = QPen( mGridFramePenColor );
1600  framePen.setWidthF( mGridFramePenThickness );
1601  framePen.setJoinStyle( Qt::MiterJoin );
1602  p->setPen( framePen );
1603 
1604  QMap< double, double >::const_iterator posIt = pos.constBegin();
1605  for ( ; posIt != pos.constEnd(); ++posIt )
1606  {
1607  p->setBrush( QBrush( color1 ? mGridFrameFillColor1 : mGridFrameFillColor2 ) );
1608  if ( border == Left || border == Right )
1609  {
1610  height = posIt.key() - currentCoord;
1611  width = mGridFrameWidth;
1612  x = ( border == Left ) ? -mGridFrameWidth : rect().width();
1613  y = currentCoord;
1614  }
1615  else //top or bottom
1616  {
1617  height = mGridFrameWidth;
1618  width = posIt.key() - currentCoord;
1619  x = currentCoord;
1620  y = ( border == Top ) ? -mGridFrameWidth : rect().height();
1621  }
1622  p->drawRect( QRectF( x, y, width, height ) );
1623  currentCoord = posIt.key();
1624  color1 = !color1;
1625  }
1626 }
1627 
1628 void QgsComposerMap::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
1629 {
1630  if ( !p )
1631  {
1632  return;
1633  }
1634 
1635 
1636  QString currentAnnotationString;
1637  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
1638  for ( ; it != hLines.constEnd(); ++it )
1639  {
1640  currentAnnotationString = gridAnnotationString( it->first, Latitude );
1641  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
1642  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
1643  }
1644 
1645  it = vLines.constBegin();
1646  for ( ; it != vLines.constEnd(); ++it )
1647  {
1648  currentAnnotationString = gridAnnotationString( it->first, Longitude );
1649  drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
1650  drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
1651  }
1652 }
1653 
1654 void QgsComposerMap::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString )
1655 {
1656  Border frameBorder = borderForLineCoord( pos );
1657  double textWidth = textWidthMillimeters( mGridAnnotationFont, annotationString );
1658  //relevant for annotations is the height of digits
1659  double textHeight = fontHeightCharacterMM( mGridAnnotationFont, QChar( '0' ) );
1660  double xpos = pos.x();
1661  double ypos = pos.y();
1662  int rotation = 0;
1663 
1664  double gridFrameDistance = ( mGridFrameStyle == NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
1665 
1666  if ( frameBorder == Left )
1667  {
1668 
1670  {
1672  {
1673  xpos += textHeight + mAnnotationFrameDistance;
1674  ypos += textWidth / 2.0;
1675  rotation = 270;
1676  }
1677  else
1678  {
1679  xpos += mAnnotationFrameDistance;
1680  ypos += textHeight / 2.0;
1681  }
1682  }
1683  else if ( mLeftGridAnnotationPosition == OutsideMapFrame ) //Outside map frame
1684  {
1686  {
1687  xpos -= ( mAnnotationFrameDistance + gridFrameDistance );
1688  ypos += textWidth / 2.0;
1689  rotation = 270;
1690  }
1691  else
1692  {
1693  xpos -= ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1694  ypos += textHeight / 2.0;
1695  }
1696  }
1697  else
1698  {
1699  return;
1700  }
1701 
1702  }
1703  else if ( frameBorder == Right )
1704  {
1706  {
1708  {
1709  xpos -= mAnnotationFrameDistance;
1710  ypos += textWidth / 2.0;
1711  rotation = 270;
1712  }
1713  else
1714  {
1715  xpos -= textWidth + mAnnotationFrameDistance;
1716  ypos += textHeight / 2.0;
1717  }
1718  }
1719  else if ( mRightGridAnnotationPosition == OutsideMapFrame )//OutsideMapFrame
1720  {
1722  {
1723  xpos += ( textHeight + mAnnotationFrameDistance + gridFrameDistance );
1724  ypos += textWidth / 2.0;
1725  rotation = 270;
1726  }
1727  else //Horizontal
1728  {
1729  xpos += ( mAnnotationFrameDistance + gridFrameDistance );
1730  ypos += textHeight / 2.0;
1731  }
1732  }
1733  else
1734  {
1735  return;
1736  }
1737  }
1738  else if ( frameBorder == Bottom )
1739  {
1741  {
1743  {
1744  ypos -= mAnnotationFrameDistance;
1745  xpos -= textWidth / 2.0;
1746  }
1747  else //Vertical
1748  {
1749  xpos += textHeight / 2.0;
1750  ypos -= mAnnotationFrameDistance;
1751  rotation = 270;
1752  }
1753  }
1754  else if ( mBottomGridAnnotationPosition == OutsideMapFrame ) //OutsideMapFrame
1755  {
1757  {
1758  ypos += ( mAnnotationFrameDistance + textHeight + gridFrameDistance );
1759  xpos -= textWidth / 2.0;
1760  }
1761  else //Vertical
1762  {
1763  xpos += textHeight / 2.0;
1764  ypos += ( textWidth + mAnnotationFrameDistance + gridFrameDistance );
1765  rotation = 270;
1766  }
1767  }
1768  else
1769  {
1770  return;
1771  }
1772  }
1773  else //Top
1774  {
1776  {
1778  {
1779  xpos -= textWidth / 2.0;
1780  ypos += textHeight + mAnnotationFrameDistance;
1781  }
1782  else //Vertical
1783  {
1784  xpos += textHeight / 2.0;
1785  ypos += textWidth + mAnnotationFrameDistance;
1786  rotation = 270;
1787  }
1788  }
1789  else if ( mTopGridAnnotationPosition == OutsideMapFrame ) //OutsideMapFrame
1790  {
1792  {
1793  xpos -= textWidth / 2.0;
1794  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1795  }
1796  else //Vertical
1797  {
1798  xpos += textHeight / 2.0;
1799  ypos -= ( mAnnotationFrameDistance + gridFrameDistance );
1800  rotation = 270;
1801  }
1802  }
1803  else
1804  {
1805  return;
1806  }
1807  }
1808 
1809  drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
1810 }
1811 
1812 void QgsComposerMap::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText )
1813 {
1814  p->save();
1815  p->translate( pos );
1816  p->rotate( rotation );
1817  p->setPen( QPen( QColor( mGridAnnotationFontColor ) ) );
1818  drawText( p, 0, 0, annotationText, mGridAnnotationFont );
1819  p->restore();
1820 }
1821 
1823 {
1824  if ( mGridAnnotationFormat == Decimal )
1825  {
1826  return QString::number( value, 'f', mGridAnnotationPrecision );
1827  }
1828 
1829  QgsPoint p;
1830  p.setX( coord == Longitude ? value : 0 );
1831  p.setY( coord == Longitude ? 0 : value );
1832 
1833  QString annotationString;
1835  {
1836  annotationString = p.toDegreesMinutes( mGridAnnotationPrecision );
1837  }
1838  else //DegreeMinuteSecond
1839  {
1840  annotationString = p.toDegreesMinutesSeconds( mGridAnnotationPrecision );
1841  }
1842 
1843  QStringList split = annotationString.split( "," );
1844  if ( coord == Longitude )
1845  {
1846  return split.at( 0 );
1847  }
1848  else
1849  {
1850  if ( split.size() < 2 )
1851  {
1852  return "";
1853  }
1854  return split.at( 1 );
1855  }
1856 }
1857 
1858 int QgsComposerMap::xGridLines( QList< QPair< double, QLineF > >& lines ) const
1859 {
1860  lines.clear();
1861  if ( mGridIntervalY <= 0.0 )
1862  {
1863  return 1;
1864  }
1865 
1866 
1867  QPolygonF mapPolygon = transformedMapPolygon();
1868  QRectF mapBoundingRect = mapPolygon.boundingRect();
1869 
1870  //consider to round up to the next step in case the left boundary is > 0
1871  double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
1872  double currentLevel = ( int )(( mapBoundingRect.top() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
1873 
1874  if ( qgsDoubleNear( mMapRotation, 0.0 ) )
1875  {
1876  //no rotation. Do it 'the easy way'
1877 
1878  double yCanvasCoord;
1879 
1880  while ( currentLevel <= mapBoundingRect.bottom() )
1881  {
1882  yCanvasCoord = rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
1883  lines.push_back( qMakePair( currentLevel, QLineF( 0, yCanvasCoord, rect().width(), yCanvasCoord ) ) );
1884  currentLevel += mGridIntervalY;
1885  }
1886  }
1887 
1888  //the four border lines
1889  QVector<QLineF> borderLines;
1890  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1891  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1892  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1893  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1894 
1895  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1896 
1897  while ( currentLevel <= mapBoundingRect.bottom() )
1898  {
1899  intersectionList.clear();
1900  QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
1901 
1902  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1903  for ( ; it != borderLines.constEnd(); ++it )
1904  {
1905  QPointF intersectionPoint;
1906  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1907  {
1908  intersectionList.push_back( intersectionPoint );
1909  if ( intersectionList.size() >= 2 )
1910  {
1911  break; //we already have two intersections, skip further tests
1912  }
1913  }
1914  }
1915 
1916  if ( intersectionList.size() >= 2 )
1917  {
1918  lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1919  }
1920  currentLevel += mGridIntervalY;
1921  }
1922 
1923 
1924  return 0;
1925 }
1926 
1927 int QgsComposerMap::yGridLines( QList< QPair< double, QLineF > >& lines ) const
1928 {
1929  lines.clear();
1930  if ( mGridIntervalX <= 0.0 )
1931  {
1932  return 1;
1933  }
1934 
1935  QPolygonF mapPolygon = transformedMapPolygon();
1936  QRectF mapBoundingRect = mapPolygon.boundingRect();
1937 
1938  //consider to round up to the next step in case the left boundary is > 0
1939  double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
1940  double currentLevel = ( int )(( mapBoundingRect.left() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
1941 
1942  if ( qgsDoubleNear( mMapRotation, 0.0 ) )
1943  {
1944  //no rotation. Do it 'the easy way'
1945  double xCanvasCoord;
1946 
1947  while ( currentLevel <= mapBoundingRect.right() )
1948  {
1949  xCanvasCoord = rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
1950  lines.push_back( qMakePair( currentLevel, QLineF( xCanvasCoord, 0, xCanvasCoord, rect().height() ) ) );
1951  currentLevel += mGridIntervalX;
1952  }
1953  }
1954 
1955  //the four border lines
1956  QVector<QLineF> borderLines;
1957  borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
1958  borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
1959  borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
1960  borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
1961 
1962  QList<QPointF> intersectionList; //intersects between border lines and grid lines
1963 
1964  while ( currentLevel <= mapBoundingRect.right() )
1965  {
1966  intersectionList.clear();
1967  QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
1968 
1969  QVector<QLineF>::const_iterator it = borderLines.constBegin();
1970  for ( ; it != borderLines.constEnd(); ++it )
1971  {
1972  QPointF intersectionPoint;
1973  if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
1974  {
1975  intersectionList.push_back( intersectionPoint );
1976  if ( intersectionList.size() >= 2 )
1977  {
1978  break; //we already have two intersections, skip further tests
1979  }
1980  }
1981  }
1982 
1983  if ( intersectionList.size() >= 2 )
1984  {
1985  lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
1986  }
1987  currentLevel += mGridIntervalX;
1988  }
1989 
1990  return 0;
1991 }
1992 
1994 {
1995  if ( mGridLineSymbol )
1996  {
1997  mGridLineSymbol->setWidth( w );
1998  }
1999 }
2000 
2001 void QgsComposerMap::setGridPenColor( const QColor& c )
2002 {
2003  if ( mGridLineSymbol )
2004  {
2005  mGridLineSymbol->setColor( c );
2006  }
2007 }
2008 
2009 void QgsComposerMap::setGridPen( const QPen& p )
2010 {
2011  setGridPenWidth( p.widthF() );
2012  setGridPenColor( p.color() );
2013 }
2014 
2016 {
2017  QPen p;
2018  if ( mGridLineSymbol )
2019  {
2020  p.setWidthF( mGridLineSymbol->width() );
2021  p.setColor( mGridLineSymbol->color() );
2022  p.setCapStyle( Qt::FlatCap );
2023  }
2024  return p;
2025 }
2026 
2027 void QgsComposerMap::setGridBlendMode( QPainter::CompositionMode blendMode )
2028 {
2030  update();
2031 }
2032 
2034 {
2035  return mCurrentRectangle;
2036 }
2037 
2039 {
2040  QRectF rectangle = rect();
2041  double extension = maxExtension();
2042  rectangle.setLeft( rectangle.left() - extension );
2043  rectangle.setRight( rectangle.right() + extension );
2044  rectangle.setTop( rectangle.top() - extension );
2045  rectangle.setBottom( rectangle.bottom() + extension );
2046  if ( rectangle != mCurrentRectangle )
2047  {
2048  prepareGeometryChange();
2049  mCurrentRectangle = rectangle;
2050  }
2051 }
2052 
2054 {
2055  QgsComposerItem::setFrameOutlineWidth( outlineWidth );
2057 }
2058 
2060 {
2061  double dx = mXOffset;
2062  double dy = mYOffset;
2063  transformShift( dx, dy );
2064  return QgsRectangle( currentMapExtent()->xMinimum() - dx, currentMapExtent()->yMinimum() - dy, currentMapExtent()->xMaximum() - dx, currentMapExtent()->yMaximum() - dy );
2065 }
2066 
2068 {
2069  double dx = mXOffset;
2070  double dy = mYOffset;
2071  //qWarning("offset");
2072  //qWarning(QString::number(dx).toLocal8Bit().data());
2073  //qWarning(QString::number(dy).toLocal8Bit().data());
2074  transformShift( dx, dy );
2075  //qWarning("transformed:");
2076  //qWarning(QString::number(dx).toLocal8Bit().data());
2077  //qWarning(QString::number(dy).toLocal8Bit().data());
2078  QPolygonF poly = visibleExtentPolygon();
2079  poly.translate( -dx, -dy );
2080  return poly;
2081 }
2082 
2084 {
2085  double frameExtension = mFrame ? pen().widthF() / 2.0 : 0.0;
2088  {
2089  return frameExtension;
2090  }
2091 
2092  QList< QPair< double, QLineF > > xLines;
2093  QList< QPair< double, QLineF > > yLines;
2094 
2095  int xGridReturn = xGridLines( xLines );
2096  int yGridReturn = yGridLines( yLines );
2097 
2098  if ( xGridReturn != 0 && yGridReturn != 0 )
2099  {
2100  return frameExtension;
2101  }
2102 
2103  double maxExtension = 0;
2104  double currentExtension = 0;
2105  QString currentAnnotationString;
2106 
2107  QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
2108  for ( ; it != xLines.constEnd(); ++it )
2109  {
2110  currentAnnotationString = gridAnnotationString( it->first, Latitude );
2111  currentExtension = qMax( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
2112  maxExtension = qMax( maxExtension, currentExtension );
2113  }
2114 
2115  it = yLines.constBegin();
2116  for ( ; it != yLines.constEnd(); ++it )
2117  {
2118  currentAnnotationString = gridAnnotationString( it->first, Longitude );
2119  currentExtension = qMax( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
2120  maxExtension = qMax( maxExtension, currentExtension );
2121  }
2122 
2123  //grid frame
2124  double gridFrameDist = ( mGridFrameStyle == NoGridFrame ) ? 0 : mGridFrameWidth + ( mGridFramePenThickness / 2.0 );
2125  return qMax( frameExtension, maxExtension + mAnnotationFrameDistance + gridFrameDist );
2126 }
2127 
2128 void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const
2129 {
2130  poly.clear();
2131  if ( mMapRotation == 0 )
2132  {
2133  poly << QPointF( extent.xMinimum(), extent.yMaximum() );
2134  poly << QPointF( extent.xMaximum(), extent.yMaximum() );
2135  poly << QPointF( extent.xMaximum(), extent.yMinimum() );
2136  poly << QPointF( extent.xMinimum(), extent.yMinimum() );
2137  return;
2138  }
2139 
2140  //there is rotation
2141  QgsPoint rotationPoint(( extent.xMaximum() + extent.xMinimum() ) / 2.0, ( extent.yMaximum() + extent.yMinimum() ) / 2.0 );
2142  double dx, dy; //x-, y- shift from rotation point to corner point
2143 
2144  //top left point
2145  dx = rotationPoint.x() - extent.xMinimum();
2146  dy = rotationPoint.y() - extent.yMaximum();
2147  rotate( mMapRotation, dx, dy );
2148  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2149 
2150  //top right point
2151  dx = rotationPoint.x() - extent.xMaximum();
2152  dy = rotationPoint.y() - extent.yMaximum();
2153  rotate( mMapRotation, dx, dy );
2154  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2155 
2156  //bottom right point
2157  dx = rotationPoint.x() - extent.xMaximum();
2158  dy = rotationPoint.y() - extent.yMinimum();
2159  rotate( mMapRotation, dx, dy );
2160  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2161 
2162  //bottom left point
2163  dx = rotationPoint.x() - extent.xMinimum();
2164  dy = rotationPoint.y() - extent.yMinimum();
2165  rotate( mMapRotation, dx, dy );
2166  poly << QPointF( rotationPoint.x() - dx, rotationPoint.y() - dy );
2167 }
2168 
2170 {
2171  QPolygonF poly;
2172  mapPolygon( *currentMapExtent(), poly );
2173  return poly;
2174 }
2175 
2177 {
2178  QgsRectangle newExtent = *currentMapExtent();
2179  if ( mMapRotation == 0 )
2180  {
2181  extent = newExtent;
2182  }
2183  else
2184  {
2185  QPolygonF poly;
2186  mapPolygon( newExtent, poly );
2187  QRectF bRect = poly.boundingRect();
2188  extent.setXMinimum( bRect.left() );
2189  extent.setXMaximum( bRect.right() );
2190  extent.setYMinimum( bRect.top() );
2191  extent.setYMaximum( bRect.bottom() );
2192  }
2193 }
2194 
2196 {
2197  double extentWidth = currentMapExtent()->width();
2198  if ( extentWidth <= 0 )
2199  {
2200  return 1;
2201  }
2202  return rect().width() / extentWidth;
2203 }
2204 
2206 {
2207  if ( mOverviewFrameMapId != -1 )
2208  {
2209  const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
2210  if ( map )
2211  {
2212  QObject::disconnect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
2213  }
2214  }
2215  mOverviewFrameMapId = mapId;
2216  if ( mOverviewFrameMapId != -1 )
2217  {
2218  const QgsComposerMap* map = mComposition->getComposerMapById( mapId );
2219  if ( map )
2220  {
2221  QObject::connect( map, SIGNAL( extentChanged() ), this, SLOT( overviewExtentChanged() ) );
2222  }
2223  }
2224  update();
2225 }
2226 
2228 {
2229  //if using overview centering, update the map's extent
2230  if ( mOverviewCentered && mOverviewFrameMapId != -1 )
2231  {
2233 
2234  const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
2235  QgsRectangle otherExtent = *overviewFrameMap->currentMapExtent();
2236 
2237  QgsPoint center = otherExtent.center();
2238  QgsRectangle movedExtent( center.x() - currentMapExtent()->width() / 2,
2239  center.y() - currentMapExtent()->height() / 2,
2240  center.x() - currentMapExtent()->width() / 2 + currentMapExtent()->width(),
2241  center.y() - currentMapExtent()->height() / 2 + currentMapExtent()->height() );
2242  *currentMapExtent() = movedExtent;
2243 
2244  emit itemChanged();
2245  emit extentChanged();
2246  }
2247 
2248  //redraw so that overview gets updated
2249  cache();
2250  update();
2251 }
2252 
2253 
2255 {
2256  delete mOverviewFrameMapSymbol;
2257  mOverviewFrameMapSymbol = symbol;
2258 }
2259 
2260 void QgsComposerMap::setOverviewBlendMode( QPainter::CompositionMode blendMode )
2261 {
2263  update();
2264 }
2265 
2267 {
2268  mOverviewInverted = inverted;
2269  update();
2270 }
2271 
2273 {
2274  mOverviewCentered = centered;
2276 }
2277 
2279 {
2280  delete mGridLineSymbol;
2281  mGridLineSymbol = symbol;
2282 }
2283 
2284 void QgsComposerMap::transformShift( double& xShift, double& yShift ) const
2285 {
2286  double mmToMapUnits = 1.0 / mapUnitsToMM();
2287  double dxScaled = xShift * mmToMapUnits;
2288  double dyScaled = - yShift * mmToMapUnits;
2289 
2290  rotate( mMapRotation, dxScaled, dyScaled );
2291 
2292  xShift = dxScaled;
2293  yShift = dyScaled;
2294 }
2295 
2296 QPointF QgsComposerMap::mapToItemCoords( const QPointF& mapCoords ) const
2297 {
2298  QPolygonF mapPoly = transformedMapPolygon();
2299  if ( mapPoly.size() < 1 )
2300  {
2301  return QPointF( 0, 0 );
2302  }
2303 
2304  QgsRectangle tExtent = transformedExtent();
2305  QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
2306  double dx = mapCoords.x() - rotationPoint.x();
2307  double dy = mapCoords.y() - rotationPoint.y();
2308  rotate( -mMapRotation, dx, dy );
2309  QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
2310 
2311  QgsRectangle unrotatedExtent = transformedExtent();
2312  double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
2313  double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
2314  return QPointF( xItem, yItem );
2315 }
2316 
2318 {
2319  if ( p.x() <= pen().widthF() )
2320  {
2321  return Left;
2322  }
2323  else if ( p.x() >= ( rect().width() - pen().widthF() ) )
2324  {
2325  return Right;
2326  }
2327  else if ( p.y() <= pen().widthF() )
2328  {
2329  return Top;
2330  }
2331  else
2332  {
2333  return Bottom;
2334  }
2335 }
2336 
2337 void QgsComposerMap::drawCanvasItems( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
2338 {
2339  if ( !mMapCanvas || !mDrawCanvasItems )
2340  {
2341  return;
2342  }
2343 
2344  QList<QGraphicsItem*> itemList = mMapCanvas->items();
2345  if ( itemList.size() < 1 )
2346  {
2347  return;
2348  }
2349  QGraphicsItem* currentItem = 0;
2350 
2351  for ( int i = itemList.size() - 1; i >= 0; --i )
2352  {
2353  currentItem = itemList.at( i );
2354  //don't draw mapcanvasmap (has z value -10)
2355  if ( !currentItem || currentItem->data( 0 ).toString() != "AnnotationItem" )
2356  {
2357  continue;
2358  }
2359  drawCanvasItem( currentItem, painter, itemStyle );
2360  }
2361 }
2362 
2363 void QgsComposerMap::drawCanvasItem( QGraphicsItem* item, QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
2364 {
2365  if ( !item || !mMapCanvas || !item->isVisible() )
2366  {
2367  return;
2368  }
2369 
2370  painter->save();
2371 
2372  //determine scale factor according to graphics view dpi
2373  double scaleFactor = 1.0 / mMapCanvas->logicalDpiX() * 25.4;
2374 
2375  double itemX, itemY;
2376  QGraphicsItem* parent = item->parentItem();
2377  if ( !parent )
2378  {
2379  QPointF mapPos = composerMapPosForItem( item );
2380  itemX = mapPos.x();
2381  itemY = mapPos.y();
2382  }
2383  else //place item relative to the parent item
2384  {
2385  QPointF itemScenePos = item->scenePos();
2386  QPointF parentScenePos = parent->scenePos();
2387 
2388  QPointF mapPos = composerMapPosForItem( parent );
2389 
2390  itemX = mapPos.x() + ( itemScenePos.x() - parentScenePos.x() ) * scaleFactor;
2391  itemY = mapPos.y() + ( itemScenePos.y() - parentScenePos.y() ) * scaleFactor;
2392  }
2393  painter->translate( itemX, itemY );
2394 
2395 
2396  painter->scale( scaleFactor, scaleFactor );
2397 
2398  //a little trick to let the item know that the paint request comes from the composer
2399  item->setData( 1, "composer" );
2400  item->paint( painter, itemStyle, 0 );
2401  item->setData( 1, "" );
2402  painter->restore();
2403 }
2404 
2405 QPointF QgsComposerMap::composerMapPosForItem( const QGraphicsItem* item ) const
2406 {
2407  if ( !item || !mMapCanvas )
2408  {
2409  return QPointF( 0, 0 );
2410  }
2411 
2412  if ( currentMapExtent()->height() <= 0 || currentMapExtent()->width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
2413  {
2414  return QPointF( 0, 0 );
2415  }
2416 
2417  QRectF graphicsSceneRect = mMapCanvas->sceneRect();
2418  QPointF itemScenePos = item->scenePos();
2419  QgsRectangle mapRendererExtent = mComposition->mapSettings().visibleExtent();
2420 
2421  double mapX = itemScenePos.x() / graphicsSceneRect.width() * mapRendererExtent.width() + mapRendererExtent.xMinimum();
2422  double mapY = mapRendererExtent.yMaximum() - itemScenePos.y() / graphicsSceneRect.height() * mapRendererExtent.height();
2423  return mapToItemCoords( QPointF( mapX, mapY ) );
2424 }
2425 
2427 {
2428  switch ( border )
2429  {
2430  case QgsComposerMap::Left:
2432  break;
2433  case QgsComposerMap::Right:
2435  break;
2436  case QgsComposerMap::Top:
2438  break;
2441  break;
2442  default:
2443  return;
2444  }
2446  update();
2447 }
2448 
2450 {
2451  switch ( border )
2452  {
2453  case QgsComposerMap::Left:
2455  break;
2456  case QgsComposerMap::Right:
2458  break;
2459  case QgsComposerMap::Top:
2461  break;
2463  default:
2465  break;
2466  }
2467 }
2468 
2470 {
2471  switch ( border )
2472  {
2473  case QgsComposerMap::Left:
2475  break;
2476  case QgsComposerMap::Right:
2478  break;
2479  case QgsComposerMap::Top:
2481  break;
2484  break;
2485  default:
2486  return;
2487  break;
2488  }
2490  update();
2491 }
2492 
2494 {
2495  switch ( border )
2496  {
2497  case QgsComposerMap::Left:
2499  break;
2500  case QgsComposerMap::Right:
2502  break;
2503  case QgsComposerMap::Top:
2505  break;
2507  default:
2509  break;
2510  }
2511 }
2512 
2513 void QgsComposerMap::sortGridLinesOnBorders( const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines, QMap< double, double >& leftFrameEntries,
2514  QMap< double, double >& rightFrameEntries, QMap< double, double >& topFrameEntries, QMap< double, double >& bottomFrameEntries ) const
2515 {
2516  QList< QPair< double, QPointF > > borderPositions;
2517  QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
2518  for ( ; it != hLines.constEnd(); ++it )
2519  {
2520  borderPositions << qMakePair( it->first, it->second.p1() );
2521  borderPositions << qMakePair( it->first, it->second.p2() );
2522  }
2523  it = vLines.constBegin();
2524  for ( ; it != vLines.constEnd(); ++it )
2525  {
2526  borderPositions << qMakePair( it->first, it->second.p1() );
2527  borderPositions << qMakePair( it->first, it->second.p2() );
2528  }
2529 
2530  QList< QPair< double, QPointF > >::const_iterator bIt = borderPositions.constBegin();
2531  for ( ; bIt != borderPositions.constEnd(); ++bIt )
2532  {
2533  Border frameBorder = borderForLineCoord( bIt->second );
2534  if ( frameBorder == QgsComposerMap::Left )
2535  {
2536  leftFrameEntries.insert( bIt->second.y(), bIt->first );
2537  }
2538  else if ( frameBorder == QgsComposerMap::Right )
2539  {
2540  rightFrameEntries.insert( bIt->second.y(), bIt->first );
2541  }
2542  else if ( frameBorder == QgsComposerMap::Top )
2543  {
2544  topFrameEntries.insert( bIt->second.x(), bIt->first );
2545  }
2546  else //Bottom
2547  {
2548  bottomFrameEntries.insert( bIt->second.x(), bIt->first );
2549  }
2550  }
2551 }
2552 
2554 {
2555  if ( mOverviewFrameMapId == -1 || !mComposition )
2556  {
2557  return;
2558  }
2559 
2561  {
2562  //if map item is set to rectangle preview mode and we are not exporting the composition
2563  //then don't draw an overview rectangle
2564  return;
2565  }
2566 
2567  const QgsComposerMap* overviewFrameMap = mComposition->getComposerMapById( mOverviewFrameMapId );
2568  if ( !overviewFrameMap )
2569  {
2570  return;
2571  }
2572 
2573  //get polygon for other overview frame map's extent (use visibleExtentPolygon as it accounts for map rotation)
2574  QPolygonF otherExtent = overviewFrameMap->visibleExtentPolygon();
2575 
2576  //get current map's extent as a QPolygonF
2577  QPolygonF thisExtent = visibleExtentPolygon();
2578  //intersect the two
2579  QPolygonF intersectExtent = thisExtent.intersected( otherExtent );
2580 
2581  //setup painter scaling to dots so that raster symbology is drawn to scale
2582  double dotsPerMM = p->device()->logicalDpiX() / 25.4;
2583 
2584  //setup render context
2586  //context units should be in dots
2587  ms.setOutputSize( QSizeF( rect().width() * dotsPerMM, rect().height() * dotsPerMM ).toSize() );
2588  ms.setExtent( *currentMapExtent() );
2589  ms.setOutputDpi( p->device()->logicalDpiX() );
2591  context.setForceVectorOutput( true );
2592  context.setPainter( p );
2593 
2594  p->save();
2595  p->setCompositionMode( mOverviewBlendMode );
2596  p->translate( mXOffset, mYOffset );
2597  p->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
2598  p->setRenderHint( QPainter::Antialiasing );
2599 
2601 
2602  //construct a polygon corresponding to the intersecting map extent
2603  //need to scale line to dots, rather then mm, since the painter has been scaled to dots
2604  QTransform mapTransform;
2605  QPolygonF thisRectPoly = QPolygonF( QRectF( 0, 0, dotsPerMM * rect().width(), dotsPerMM * rect().height() ) );
2606 
2607  //workaround QT Bug #21329
2608  thisRectPoly.pop_back();
2609  //create transform from map coordinates to painter coordinates
2610  QTransform::quadToQuad( thisExtent, thisRectPoly, mapTransform );
2611  QPolygonF intersectPolygon;
2612  intersectPolygon = mapTransform.map( intersectExtent );
2613 
2614  QList<QPolygonF> rings; //empty list
2615  if ( !mOverviewInverted )
2616  {
2617  //Render the intersecting map extent
2618  mOverviewFrameMapSymbol->renderPolygon( intersectPolygon, &rings, 0, context );;
2619  }
2620  else
2621  {
2622  //We are inverting the overview frame (ie, shading outside the intersecting extent)
2623  //Construct a polygon corresponding to the overview map extent
2624  QPolygonF outerPolygon;
2625  outerPolygon << QPointF( 0, 0 ) << QPointF( rect().width() * dotsPerMM, 0 ) << QPointF( rect().width() * dotsPerMM, rect().height() * dotsPerMM ) << QPointF( 0, rect().height() * dotsPerMM ) << QPointF( 0, 0 );
2626 
2627  //Intersecting extent is an inner ring for the shaded area
2628  rings.append( intersectPolygon );
2629  mOverviewFrameMapSymbol->renderPolygon( outerPolygon, &rings, 0, context );
2630  }
2631 
2632  mOverviewFrameMapSymbol->stopRender( context );
2633  p->restore();
2634 }
2635 
2637 {
2638  delete mOverviewFrameMapSymbol;
2639  QgsStringMap properties;
2640  properties.insert( "color", "255,0,0,255" );
2641  properties.insert( "style", "solid" );
2642  properties.insert( "style_border", "no" );
2645 }
2646 
2648 {
2649  delete mGridLineSymbol;
2650  QgsStringMap properties;
2651  properties.insert( "color", "0,0,0,255" );
2652  properties.insert( "width", "0.3" );
2653  properties.insert( "capstyle", "flat" );
2655 }
2656 
2658 {
2659  QString format = QgsProject::instance()->readEntry( "PositionPrecision", "/DegreeFormat", "D" );
2660 
2661  bool degreeUnits = ( mComposition->mapSettings().mapUnits() == QGis::Degrees );
2662 
2663  if ( format == "DM" && degreeUnits )
2664  {
2666  }
2667  else if ( format == "DMS" && degreeUnits )
2668  {
2670  }
2671  else
2672  {
2674  }
2675 }
2676 
2678 {
2679  if ( !mComposition )
2680  {
2681  return;
2682  }
2683 
2684  const QgsComposerMap* existingMap = mComposition->getComposerMapById( mId );
2685  if ( !existingMap )
2686  {
2687  return; //keep mId as it is still available
2688  }
2689 
2690  int maxId = -1;
2691  QList<const QgsComposerMap*> mapList = mComposition->composerMapItems();
2692  QList<const QgsComposerMap*>::const_iterator mapIt = mapList.constBegin();
2693  for ( ; mapIt != mapList.constEnd(); ++mapIt )
2694  {
2695  if (( *mapIt )->id() > maxId )
2696  {
2697  maxId = ( *mapIt )->id();
2698  }
2699  }
2700  mId = maxId + 1;
2701 }
2702 
2703 bool QgsComposerMap::imageSizeConsideringRotation( double& width, double& height ) const
2704 {
2705  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2707 }
2708 
2709 bool QgsComposerMap::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
2710 {
2711  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2713 }
2714 
2715 void QgsComposerMap::sizeChangedByRotation( double& width, double& height )
2716 {
2717  //kept for api compatibility with QGIS 2.0 - use mMapRotation
2718  return QgsComposerItem::sizeChangedByRotation( width, height, mMapRotation );
2719 }
2720 
2722 {
2723  return mAtlasScalingMode == Fixed;
2724 }
2725 
2727 {
2728  // implicit : if set to false => auto scaling
2729  mAtlasScalingMode = fixed ? Fixed : Auto;
2730 }
2731 
QString toDegreesMinutesSeconds(int thePrecision) const
Return a string representation as degrees minutes seconds.
Definition: qgspoint.cpp:137
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 setForceVectorOutput(bool force)
Added in QGIS v1.5.
void preparedForAtlas()
Is emitted when the map has been prepared for atlas rendering, just before actual rendering...
AtlasScalingMode
Scaling modes used for the serial rendering (atlas)
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:169
double mapUnitsToMM() const
Returns the conversion factor map units -> mm.
bool hideCoverage() const
Returns true if the atlas is set to hide the coverage layer.
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:194
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)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
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
void mapPolygon(const QgsRectangle &extent, QPolygonF &poly) const
mapPolygon variant using a given extent
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.
Q_DECL_DEPRECATED 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
Return the actual extent derived from requested extent that takes takes output image size into accoun...
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.
AtlasScalingMode mAtlasScalingMode
Current atlas scaling mode.
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
Return combination of flags used for rendering.
Q_DECL_DEPRECATED 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 setLayers(const QStringList &layers)
Set list of layer IDs for map rendering.
Enable layer transparency and blending effects.
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
Vector graphics should not be cached and drawn as raster images.
QColor mGridFrameFillColor1
QColor mGridFramePenColor
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
int mGridAnnotationPrecision
Digits after the dot.
The QgsMapSettings class contains configuration for rendering of the map.
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.
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:199
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:184
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
bool mFrame
True if item fram needs to be painted.
bool writeXML(QDomElement &elem, QDomDocument &doc) const
stores state in Dom node
Whether vector selections should be shown in the rendered map.
void setMapUnits(QGis::UnitType u)
Set units of map's geographical coordinates - used for scale calculation.
bool drawCanvasItems() const
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:174
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
Q_DECL_DEPRECATED bool atlasFixedScale() const
Returns true if the map uses a fixed scale when in atlas mode.
QGis::UnitType mapUnits() const
Get units of map's geographical coordinates - used for scale calculation.
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
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 setOutputImageFormat(QImage::Format format)
sets format of internal QImage
void drawCanvasItem(QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *itemStyle)
Q_DECL_DEPRECATED 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
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation...
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.
Enable drawing of vertex markers for layers in editing mode.
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
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.
double mAtlasMargin
Margin size for atlas driven extents (percentage of feature size) - when in auto scaling mode...
void setBackgroundColor(const QColor &color)
Set the background color of the map.
void drawGridLine(const QLineF &line, QgsRenderContext &context)
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 setBackgroundColor(const QColor &backgroundColor)
Sets the background color for this item.
void setOverviewInverted(bool inverted)
Sets the overview's inversion mode.
Q_DECL_DEPRECATED double rotation() const
Returns the rotation used for drawing the map within the composer item.
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)
Set the size of the resulting map image.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:179
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
virtual void drawBackground(QPainter *p)
Draw background.
bool mUpdatesEnabled
Whether updates to the map are enabled.
bool hasFrame() const
Whether this item has a frame or not.
QImage::Format outputImageFormat() const
format of internal QImage, default QImage::Format_ARGB32_Premultiplied
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
void setExtent(const QgsRectangle &rect)
Set coordinates of the rectangle which should be rendered.
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
Q_DECL_DEPRECATED void setAtlasFixedScale(bool fixed)
Set to true if the map should use a fixed scale when in atlas mode.
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
Get list of layer IDs for map rendering The layers are stored in the reverse order of how they are re...
QgsAtlasComposition & atlasComposition()
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
Enable vector simplification and other rendering optimizations.
QPainter::CompositionMode shadowBlendMode
static QgsSymbolV2 * loadSymbol(QDomElement &element)
QgsRasterDataProvider * dataProvider()
Returns the data provider.
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
Returns the coverage layer used for the atlas features.
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:204
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)
Set combination of flags that will be used for rendering.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:189
PreviewMode mPreviewMode
Preview style.
Q_DECL_DEPRECATED 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:214
void renderSynchronously()
Render the map synchronously in this thread.
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:127
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:164
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:209
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)