QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsmaprenderer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaprender.cpp - class for rendering map layer set
3  ----------------------
4  begin : January 2006
5  copyright : (C) 2006 by Martin Dobias
6  email : wonder.sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <cmath>
17 #include <cfloat>
18 
19 #include "qgscoordinatetransform.h"
20 #include "qgscrscache.h"
21 #include "qgslogger.h"
22 #include "qgsmessagelog.h"
23 #include "qgsmaprenderer.h"
24 #include "qgsscalecalculator.h"
25 #include "qgsmaptopixel.h"
26 #include "qgsmaplayer.h"
27 #include "qgsmaplayerregistry.h"
28 #include "qgsdistancearea.h"
29 #include "qgsproject.h"
30 #include "qgsvectorlayer.h"
31 
32 
33 #include <QDomDocument>
34 #include <QDomNode>
35 #include <QMutexLocker>
36 #include <QPainter>
37 #include <QListIterator>
38 #include <QSettings>
39 #include <QTime>
40 #include <QCoreApplication>
41 
43 {
44  mScale = 1.0;
47 
48  mDrawing = false;
49  mOverview = false;
50 
51  // set default map units - we use WGS 84 thus use degrees
53 
54  mSize = QSize( 0, 0 );
55 
56  mProjectionsEnabled = false;
58 
60 
61  mLabelingEngine = NULL;
62 }
63 
65 {
66  delete mScaleCalculator;
67  delete mDistArea;
68  delete mDestCRS;
69  delete mLabelingEngine;
70 }
71 
73 {
74  return mExtent;
75 }
76 
78 {
80 }
81 
83 {
84  //remember the previous extent
86 
87  // Don't allow zooms where the current extent is so small that it
88  // can't be accurately represented using a double (which is what
89  // currentExtent uses). Excluding 0 avoids a divide by zero and an
90  // infinite loop when rendering to a new canvas. Excluding extents
91  // greater than 1 avoids doing unnecessary calculations.
92 
93  // The scheme is to compare the width against the mean x coordinate
94  // (and height against mean y coordinate) and only allow zooms where
95  // the ratio indicates that there is more than about 12 significant
96  // figures (there are about 16 significant figures in a double).
97 
98  if ( extent.width() > 0 &&
99  extent.height() > 0 &&
100  extent.width() < 1 &&
101  extent.height() < 1 )
102  {
103  // Use abs() on the extent to avoid the case where the extent is
104  // symmetrical about 0.
105  double xMean = ( qAbs( extent.xMinimum() ) + qAbs( extent.xMaximum() ) ) * 0.5;
106  double yMean = ( qAbs( extent.yMinimum() ) + qAbs( extent.yMaximum() ) ) * 0.5;
107 
108  double xRange = extent.width() / xMean;
109  double yRange = extent.height() / yMean;
110 
111  static const double minProportion = 1e-12;
112  if ( xRange < minProportion || yRange < minProportion )
113  return false;
114  }
115 
116  mExtent = extent;
117  if ( !extent.isEmpty() )
119  return true;
120 }
121 
122 
123 
124 void QgsMapRenderer::setOutputSize( QSize size, int dpi )
125 {
126  mSize = QSizeF( size.width(), size.height() );
127  mScaleCalculator->setDpi( dpi );
129 }
130 
131 void QgsMapRenderer::setOutputSize( QSizeF size, double dpi )
132 {
133  mSize = size;
134  mScaleCalculator->setDpi( dpi );
136 }
137 
139 {
140  return mScaleCalculator->dpi();
141 }
142 
144 {
145  return mSize.toSize();
146 }
147 
149 {
150  return mSize;
151 }
152 
154 {
155  double myHeight = mSize.height();
156  double myWidth = mSize.width();
157 
158  QgsMapToPixel newCoordXForm;
159 
160  if ( !myWidth || !myHeight )
161  {
162  mScale = 1.0;
163  newCoordXForm.setParameters( 0, 0, 0, 0 );
164  return;
165  }
166 
167  // calculate the translation and scaling parameters
168  // mapUnitsPerPixel = map units per pixel
169  double mapUnitsPerPixelY = mExtent.height() / myHeight;
170  double mapUnitsPerPixelX = mExtent.width() / myWidth;
171  mMapUnitsPerPixel = mapUnitsPerPixelY > mapUnitsPerPixelX ? mapUnitsPerPixelY : mapUnitsPerPixelX;
172 
173  // calculate the actual extent of the mapCanvas
174  double dxmin, dxmax, dymin, dymax, whitespace;
175 
176  if ( mapUnitsPerPixelY > mapUnitsPerPixelX )
177  {
178  dymin = mExtent.yMinimum();
179  dymax = mExtent.yMaximum();
180  whitespace = (( myWidth * mMapUnitsPerPixel ) - mExtent.width() ) * 0.5;
181  dxmin = mExtent.xMinimum() - whitespace;
182  dxmax = mExtent.xMaximum() + whitespace;
183  }
184  else
185  {
186  dxmin = mExtent.xMinimum();
187  dxmax = mExtent.xMaximum();
188  whitespace = (( myHeight * mMapUnitsPerPixel ) - mExtent.height() ) * 0.5;
189  dymin = mExtent.yMinimum() - whitespace;
190  dymax = mExtent.yMaximum() + whitespace;
191  }
192 
193  QgsDebugMsg( QString( "Map units per pixel (x,y) : %1, %2" ).arg( qgsDoubleToString( mapUnitsPerPixelX ) ).arg( qgsDoubleToString( mapUnitsPerPixelY ) ) );
194  QgsDebugMsg( QString( "Pixmap dimensions (x,y) : %1, %2" ).arg( qgsDoubleToString( myWidth ) ).arg( qgsDoubleToString( myHeight ) ) );
195  QgsDebugMsg( QString( "Extent dimensions (x,y) : %1, %2" ).arg( qgsDoubleToString( mExtent.width() ) ).arg( qgsDoubleToString( mExtent.height() ) ) );
197 
198  // update extent
199  mExtent.setXMinimum( dxmin );
200  mExtent.setXMaximum( dxmax );
201  mExtent.setYMinimum( dymin );
202  mExtent.setYMaximum( dymax );
203 
204  QgsDebugMsg( QString( "Adjusted map units per pixel (x,y) : %1, %2" ).arg( qgsDoubleToString( mExtent.width() / myWidth ) ).arg( qgsDoubleToString( mExtent.height() / myHeight ) ) );
205 
206  QgsDebugMsg( QString( "Recalced pixmap dimensions (x,y) : %1, %2" ).arg( qgsDoubleToString( mExtent.width() / mMapUnitsPerPixel ) ).arg( qgsDoubleToString( mExtent.height() / mMapUnitsPerPixel ) ) );
207 
208  // update the scale
209  updateScale();
210 
211  QgsDebugMsg( QString( "Scale (assuming meters as map units) = 1:%1" ).arg( qgsDoubleToString( mScale ) ) );
212 
213  newCoordXForm.setParameters( mMapUnitsPerPixel, dxmin, dymin, myHeight );
214  mRenderContext.setMapToPixel( newCoordXForm );
216 }
217 
218 
219 void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale )
220 {
221  //Lock render method for concurrent threads (e.g. from globe)
222  QMutexLocker renderLock( &mRenderMutex );
223 
224  //flag to see if the render context has changed
225  //since the last time we rendered. If it hasnt changed we can
226  //take some shortcuts with rendering
227  bool mySameAsLastFlag = true;
228 
229  QgsDebugMsg( "========== Rendering ==========" );
230 
231  if ( mExtent.isEmpty() )
232  {
233  QgsDebugMsg( "empty extent... not rendering" );
234  return;
235  }
236 
237  if ( mSize.width() == 1 && mSize.height() == 1 )
238  {
239  QgsDebugMsg( "size 1x1... not rendering" );
240  return;
241  }
242 
243  QPaintDevice* thePaintDevice = painter->device();
244  if ( !thePaintDevice )
245  {
246  return;
247  }
248 
249  // wait
250  if ( mDrawing )
251  {
252  QgsDebugMsg( "already rendering" );
253  QCoreApplication::processEvents();
254  }
255 
256  if ( mDrawing )
257  {
258  QgsDebugMsg( "still rendering - skipping" );
259  return;
260  }
261 
262  mDrawing = true;
263 
264  const QgsCoordinateTransform *ct;
265 
266 #ifdef QGISDEBUG
267  QgsDebugMsg( "Starting to render layer stack." );
268  QTime renderTime;
269  renderTime.start();
270 #endif
271 
272  if ( mOverview )
274 
275  mRenderContext.setPainter( painter );
277  //this flag is only for stopping during the current rendering progress,
278  //so must be false at every new render operation
280 
281  // set selection color
283  int myRed = prj->readNumEntry( "Gui", "/SelectionColorRedPart", 255 );
284  int myGreen = prj->readNumEntry( "Gui", "/SelectionColorGreenPart", 255 );
285  int myBlue = prj->readNumEntry( "Gui", "/SelectionColorBluePart", 0 );
286  int myAlpha = prj->readNumEntry( "Gui", "/SelectionColorAlphaPart", 255 );
287  mRenderContext.setSelectionColor( QColor( myRed, myGreen, myBlue, myAlpha ) );
288 
289  //calculate scale factor
290  //use the specified dpi and not those from the paint device
291  //because sometimes QPainter units are in a local coord sys (e.g. in case of QGraphicsScene)
292  double sceneDpi = mScaleCalculator->dpi();
293  double scaleFactor = 1.0;
295  {
296  if ( forceWidthScale )
297  {
298  scaleFactor = *forceWidthScale;
299  }
300  else
301  {
302  scaleFactor = sceneDpi / 25.4;
303  }
304  }
305  double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi;
307  {
308  mRenderContext.setRasterScaleFactor( rasterScaleFactor );
309  mySameAsLastFlag = false;
310  }
311  if ( mRenderContext.scaleFactor() != scaleFactor )
312  {
313  mRenderContext.setScaleFactor( scaleFactor );
314  mySameAsLastFlag = false;
315  }
317  {
318  //add map scale to render context
320  mySameAsLastFlag = false;
321  }
322  if ( mLastExtent != mExtent )
323  {
325  mySameAsLastFlag = false;
326  }
327 
329  if ( mLabelingEngine )
330  mLabelingEngine->init( this );
331 
332  // know we know if this render is just a repeat of the last time, we
333  // can clear caches if it has changed
334  if ( !mySameAsLastFlag )
335  {
336  //clear the cache pixmap if we changed resolution / extent
337  QSettings mySettings;
338  if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
339  {
341  }
342  }
343 
344  // render all layers in the stack, starting at the base
345  QListIterator<QString> li( mLayerSet );
346  li.toBack();
347 
348  QgsRectangle r1, r2;
349 
350  while ( li.hasPrevious() )
351  {
353  {
354  break;
355  }
356 
357  // Store the painter in case we need to swap it out for the
358  // cache painter
359  QPainter * mypContextPainter = mRenderContext.painter();
360  // Flattened image for drawing when a blending mode is set
361  QImage * mypFlattenedImage = 0;
362 
363  QString layerId = li.previous();
364 
365  QgsDebugMsg( "Rendering at layer item " + layerId );
366 
367  // This call is supposed to cause the progress bar to
368  // advance. However, it seems that updating the progress bar is
369  // incompatible with having a QPainter active (the one that is
370  // passed into this function), as Qt produces a number of errors
371  // when try to do so. I'm (Gavin) not sure how to fix this, but
372  // added these comments and debug statement to help others...
373  QgsDebugMsg( "If there is a QPaintEngine error here, it is caused by an emit call" );
374 
375  //emit drawingProgress(myRenderCounter++, mLayerSet.size());
377 
378  if ( !ml )
379  {
380  QgsDebugMsg( "Layer not found in registry!" );
381  continue;
382  }
383 
384  QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 extent:%5 blendmode:%6" )
385  .arg( ml->name() )
386  .arg( ml->minimumScale() )
387  .arg( ml->maximumScale() )
388  .arg( ml->hasScaleBasedVisibility() )
389  .arg( ml->extent().toString() )
390  .arg( ml->blendMode() )
391  );
392 
394  {
395  // Set the QPainter composition mode so that this layer is rendered using
396  // the desired blending mode
397  mypContextPainter->setCompositionMode( ml->blendMode() );
398  }
399 
400  if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() <= mScale && mScale < ml->maximumScale() ) || mOverview )
401  {
402  connect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
403 
404  //
405  // Now do the call to the layer that actually does
406  // the rendering work!
407  //
408 
409  bool split = false;
410 
411  if ( hasCrsTransformEnabled() )
412  {
413  r1 = mExtent;
414  split = splitLayersExtent( ml, r1, r2 );
415  ct = transformation( ml );
417  QgsDebugMsg( " extent 1: " + r1.toString() );
418  QgsDebugMsg( " extent 2: " + r2.toString() );
419  if ( !r1.isFinite() || !r2.isFinite() ) //there was a problem transforming the extent. Skip the layer
420  {
421  continue;
422  }
423  }
424  else
425  {
426  ct = NULL;
427  }
428 
430 
431  //decide if we have to scale the raster
432  //this is necessary in case QGraphicsScene is used
433  bool scaleRaster = false;
434  QgsMapToPixel rasterMapToPixel;
435  QgsMapToPixel bk_mapToPixel;
436 
437  if ( ml->type() == QgsMapLayer::RasterLayer && qAbs( rasterScaleFactor - 1.0 ) > 0.000001 )
438  {
439  scaleRaster = true;
440  }
441 
442  // Force render of layers that are being edited
443  // or if there's a labeling engine that needs the layer to register features
444  if ( ml->type() == QgsMapLayer::VectorLayer )
445  {
446  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
447  if ( vl->isEditable() ||
449  {
450  ml->setCacheImage( 0 );
451  }
452  }
453 
454  QSettings mySettings;
455  bool useRenderCaching = false;
456  if ( ! split )//render caching does not yet cater for split extents
457  {
458  if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
459  {
460  useRenderCaching = true;
461  if ( !mySameAsLastFlag || ml->cacheImage() == 0 )
462  {
463  QgsDebugMsg( "Caching enabled but layer redraw forced by extent change or empty cache" );
464  QImage * mypImage = new QImage( mRenderContext.painter()->device()->width(),
465  mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 );
466  if ( mypImage->isNull() )
467  {
468  QgsDebugMsg( "insufficient memory for image " + QString::number( mRenderContext.painter()->device()->width() ) + "x" + QString::number( mRenderContext.painter()->device()->height() ) );
469  emit drawError( ml );
470  painter->end(); // drawError is not caught by anyone, so we end painting to notify caller
471  return;
472  }
473  mypImage->fill( 0 );
474  ml->setCacheImage( mypImage ); //no need to delete the old one, maplayer does it for you
475  QPainter * mypPainter = new QPainter( ml->cacheImage() );
476  // Changed to enable anti aliasing by default in QGIS 1.7
477  if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() )
478  {
479  mypPainter->setRenderHint( QPainter::Antialiasing );
480  }
481  mRenderContext.setPainter( mypPainter );
482  }
483  else if ( mySameAsLastFlag )
484  {
485  //draw from cached image
486  QgsDebugMsg( "Caching enabled --- drawing layer from cached image" );
487  mypContextPainter->drawImage( 0, 0, *( ml->cacheImage() ) );
488  disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
489  //short circuit as there is nothing else to do...
490  continue;
491  }
492  }
493  }
494 
495  // If we are drawing with an alternative blending mode then we need to render to a separate image
496  // before compositing this on the map. This effectively flattens the layer and prevents
497  // blending occuring between objects on the layer
498  // (this is not required for raster layers or when layer caching is enabled, since that has the same effect)
499  bool flattenedLayer = false;
501  {
502  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
503  if (( !useRenderCaching )
504  && (( vl->blendMode() != QPainter::CompositionMode_SourceOver )
505  || ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
506  || ( vl->layerTransparency() != 0 ) ) )
507  {
508  flattenedLayer = true;
509  mypFlattenedImage = new QImage( mRenderContext.painter()->device()->width(),
510  mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 );
511  if ( mypFlattenedImage->isNull() )
512  {
513  QgsDebugMsg( "insufficient memory for image " + QString::number( mRenderContext.painter()->device()->width() ) + "x" + QString::number( mRenderContext.painter()->device()->height() ) );
514  emit drawError( ml );
515  painter->end(); // drawError is not caught by anyone, so we end painting to notify caller
516  return;
517  }
518  mypFlattenedImage->fill( 0 );
519  QPainter * mypPainter = new QPainter( mypFlattenedImage );
520  if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() )
521  {
522  mypPainter->setRenderHint( QPainter::Antialiasing );
523  }
524  mypPainter->scale( rasterScaleFactor, rasterScaleFactor );
525  mRenderContext.setPainter( mypPainter );
526  }
527  }
528 
529  // Per feature blending mode
531  {
532  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
533  if ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
534  {
535  // set the painter to the feature blend mode, so that features drawn
536  // on this layer will interact and blend with each other
537  mRenderContext.painter()->setCompositionMode( vl->featureBlendMode() );
538  }
539  }
540 
541  if ( scaleRaster )
542  {
543  bk_mapToPixel = mRenderContext.mapToPixel();
544  rasterMapToPixel = mRenderContext.mapToPixel();
546  rasterMapToPixel.setYMaximum( mSize.height() * rasterScaleFactor );
547  mRenderContext.setMapToPixel( rasterMapToPixel );
548  mRenderContext.painter()->save();
549  mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
550  }
551 
552  if ( !ml->draw( mRenderContext ) )
553  {
554  emit drawError( ml );
555  }
556  else
557  {
558  QgsDebugMsg( "Layer rendered without issues" );
559  }
560 
561  if ( split )
562  {
564  if ( !ml->draw( mRenderContext ) )
565  {
566  emit drawError( ml );
567  }
568  }
569 
570  if ( scaleRaster )
571  {
572  mRenderContext.setMapToPixel( bk_mapToPixel );
573  mRenderContext.painter()->restore();
574  }
575 
576  //apply layer transparency for vector layers
578  {
579  QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
580  if ( vl->layerTransparency() != 0 )
581  {
582  // a layer transparency has been set, so update the alpha for the flattened layer
583  // by combining it with the layer transparency
584  QColor transparentFillColor = QColor( 0, 0, 0, 255 - ( 255 * vl->layerTransparency() / 100 ) );
585  // use destination in composition mode to merge source's alpha with destination
586  mRenderContext.painter()->setCompositionMode( QPainter::CompositionMode_DestinationIn );
587  mRenderContext.painter()->fillRect( 0, 0, mRenderContext.painter()->device()->width(),
588  mRenderContext.painter()->device()->height(), transparentFillColor );
589  }
590  }
591 
592  if ( useRenderCaching )
593  {
594  // composite the cached image into our view and then clean up from caching
595  // by reinstating the painter as it was swapped out for caching renders
596  delete mRenderContext.painter();
597  mRenderContext.setPainter( mypContextPainter );
598  //draw from cached image that we created further up
599  if ( ml->cacheImage() )
600  mypContextPainter->drawImage( 0, 0, *( ml->cacheImage() ) );
601  }
602  else if ( flattenedLayer )
603  {
604  // If we flattened this layer for alternate blend modes, composite it now
605  delete mRenderContext.painter();
606  mRenderContext.setPainter( mypContextPainter );
607  mypContextPainter->save();
608  mypContextPainter->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
609  mypContextPainter->drawImage( 0, 0, *( mypFlattenedImage ) );
610  mypContextPainter->restore();
611  delete mypFlattenedImage;
612  mypFlattenedImage = 0;
613  }
614 
615  disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
616  }
617  else // layer not visible due to scale
618  {
619  QgsDebugMsg( "Layer not rendered because it is not within the defined "
620  "visibility scale range" );
621  }
622 
623  } // while (li.hasPrevious())
624 
625  QgsDebugMsg( "Done rendering map layers" );
626 
627  // Reset the composition mode before rendering the labels
628  mRenderContext.painter()->setCompositionMode( QPainter::CompositionMode_SourceOver );
629 
630  if ( !mOverview )
631  {
632  // render all labels for vector layers in the stack, starting at the base
633  li.toBack();
634  while ( li.hasPrevious() )
635  {
637  {
638  break;
639  }
640 
641  QString layerId = li.previous();
642 
643  // TODO: emit drawingProgress((myRenderCounter++),zOrder.size());
645 
646  if ( ml && ( ml->type() != QgsMapLayer::RasterLayer ) )
647  {
648  // only make labels if the layer is visible
649  // after scale dep viewing settings are checked
650  if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() < mScale && mScale < ml->maximumScale() ) )
651  {
652  bool split = false;
653 
654  if ( hasCrsTransformEnabled() )
655  {
656  QgsRectangle r1 = mExtent;
657  split = splitLayersExtent( ml, r1, r2 );
658  ct = transformation( ml );
660  }
661  else
662  {
663  ct = NULL;
664  }
665 
667 
668  ml->drawLabels( mRenderContext );
669  if ( split )
670  {
672  ml->drawLabels( mRenderContext );
673  }
674  }
675  }
676  }
677  } // if (!mOverview)
678 
679  // make sure progress bar arrives at 100%!
680  emit drawingProgress( 1, 1 );
681 
682  if ( mLabelingEngine )
683  {
684  // set correct extent
687 
690  }
691 
692  QgsDebugMsg( "Rendering completed in (seconds): " + QString( "%1" ).arg( renderTime.elapsed() / 1000.0 ) );
693 
694  mDrawing = false;
695 }
696 
698 {
700 
701  // Since the map units have changed, force a recalculation of the scale.
702  updateScale();
703 
704  emit mapUnitsChanged();
705 }
706 
708 {
709  return mScaleCalculator->mapUnits();
710 }
711 
712 void QgsMapRenderer::onDrawingProgress( int current, int total )
713 {
714  Q_UNUSED( current );
715  Q_UNUSED( total );
716  // TODO: emit signal with progress
717 // QgsDebugMsg(QString("onDrawingProgress: %1 / %2").arg(current).arg(total));
718  emit updateMap();
719 }
720 
722 {
723  if ( mProjectionsEnabled != enabled )
724  {
725  mProjectionsEnabled = enabled;
726  QgsDebugMsg( "Adjusting DistArea projection on/off" );
727  mDistArea->setEllipsoidalMode( enabled );
730  emit hasCrsTransformEnabled( enabled ); // deprecated
731  emit hasCrsTransformEnabledChanged( enabled );
732  }
733 }
734 
736 {
737  return mProjectionsEnabled;
738 }
739 
740 void QgsMapRenderer::setDestinationCrs( const QgsCoordinateReferenceSystem& crs, bool refreshCoordinateTransformInfo )
741 {
742  QgsDebugMsg( "* Setting destCRS : = " + crs.toProj4() );
743  QgsDebugMsg( "* DestCRS.srsid() = " + QString::number( crs.srsid() ) );
744  if ( *mDestCRS != crs )
745  {
746  if ( refreshCoordinateTransformInfo )
747  {
749  }
750  QgsRectangle rect;
751  if ( !mExtent.isEmpty() )
752  {
753  QgsCoordinateTransform transform( *mDestCRS, crs );
754  rect = transform.transformBoundingBox( mExtent );
755  }
756 
757  QgsDebugMsg( "Setting DistArea CRS to " + QString::number( crs.srsid() ) );
758  mDistArea->setSourceCrs( crs.srsid() );
759  *mDestCRS = crs;
761 
762  if ( !rect.isEmpty() )
763  {
764  setExtent( rect );
765  }
766 
767  emit destinationSrsChanged();
768  }
769 }
770 
772 {
773  QgsDebugMsgLevel( "* Returning destCRS", 3 );
774  QgsDebugMsgLevel( "* DestCRS.srsid() = " + QString::number( mDestCRS->srsid() ), 3 );
775  QgsDebugMsgLevel( "* DestCRS.proj4() = " + mDestCRS->toProj4(), 3 );
776  return *mDestCRS;
777 }
778 
779 
781 {
782  bool split = false;
783 
784  if ( hasCrsTransformEnabled() )
785  {
786  try
787  {
788 #ifdef QGISDEBUG
789  // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
790 #endif
791  // Split the extent into two if the source CRS is
792  // geographic and the extent crosses the split in
793  // geographic coordinates (usually +/- 180 degrees,
794  // and is assumed to be so here), and draw each
795  // extent separately.
796  static const double splitCoord = 180.0;
797 
798  const QgsCoordinateTransform *transform = transformation( layer );
799  if ( layer->crs().geographicFlag() )
800  {
801  // Note: ll = lower left point
802  // and ur = upper right point
803 
804  QgsPoint ll( extent.xMinimum(), extent.yMinimum() );
805  QgsPoint ur( extent.xMaximum(), extent.yMaximum() );
806 
807  if ( transform )
808  {
809  ll = transform->transform( ll.x(), ll.y(),
811  ur = transform->transform( ur.x(), ur.y(),
813  extent = transform->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
814  }
815 
816  if ( ll.x() > ur.x() )
817  {
818  r2 = extent;
819  extent.setXMinimum( splitCoord );
820  r2.setXMaximum( splitCoord );
821  split = true;
822  }
823  }
824  else // can't cross 180
825  {
826  if ( transform )
827  {
828  extent = transform->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
829  }
830  }
831  }
832  catch ( QgsCsException &cse )
833  {
834  Q_UNUSED( cse );
835  QgsDebugMsg( "Transform error caught" );
836  extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
837  r2 = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
838  }
839  }
840  return split;
841 }
842 
844 {
845  //QgsDebugMsg( QString( "sourceCrs = " + tr( theLayer )->sourceCrs().authid() ) );
846  //QgsDebugMsg( QString( "destCRS = " + tr( theLayer )->destCRS().authid() ) );
847  //QgsDebugMsg( QString( "extent = " + extent.toString() ) );
848  if ( hasCrsTransformEnabled() )
849  {
850  try
851  {
852  const QgsCoordinateTransform *transform = transformation( theLayer );
853  if ( transform )
854  {
855  extent = transform->transformBoundingBox( extent );
856  }
857  }
858  catch ( QgsCsException &cse )
859  {
860  QgsMessageLog::logMessage( tr( "Transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
861  }
862  }
863 
864  QgsDebugMsg( QString( "proj extent = " + extent.toString() ) );
865 
866  return extent;
867 }
868 
870 {
871 #if QGISDEBUG
872  const QgsCoordinateTransform *transform = transformation( theLayer );
873  QgsDebugMsg( QString( "layer sourceCrs = " + ( transform ? transform->sourceCrs().authid() : "none" ) ) );
874  QgsDebugMsg( QString( "layer destCRS = " + ( transform ? transform->destCRS().authid() : "none" ) ) );
875  QgsDebugMsg( QString( "extent = " + extent.toString() ) );
876 #endif
877  if ( hasCrsTransformEnabled() )
878  {
879  try
880  {
881  const QgsCoordinateTransform *transform = transformation( theLayer );
882  if ( transform )
883  {
884  extent = transform->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
885  }
886  }
887  catch ( QgsCsException &cse )
888  {
889  QgsMessageLog::logMessage( tr( "Transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
890  }
891  }
892 
893  QgsDebugMsg( QString( "proj extent = " + extent.toString() ) );
894 
895  return extent;
896 }
897 
899 {
900  if ( hasCrsTransformEnabled() )
901  {
902  try
903  {
904  const QgsCoordinateTransform *transform = transformation( theLayer );
905  if ( transform )
906  {
907  point = transform->transform( point, QgsCoordinateTransform::ForwardTransform );
908  }
909  }
910  catch ( QgsCsException &cse )
911  {
912  QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
913  }
914  }
915  else
916  {
917  // leave point without transformation
918  }
919  return point;
920 }
921 
923 {
924  if ( hasCrsTransformEnabled() )
925  {
926  try
927  {
928  const QgsCoordinateTransform *transform = transformation( theLayer );
929  if ( transform )
930  {
931  rect = transform->transform( rect, QgsCoordinateTransform::ForwardTransform );
932  }
933  }
934  catch ( QgsCsException &cse )
935  {
936  QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
937  }
938  }
939  else
940  {
941  // leave point without transformation
942  }
943  return rect;
944 }
945 
947 {
948  if ( hasCrsTransformEnabled() )
949  {
950  try
951  {
952  const QgsCoordinateTransform *transform = transformation( theLayer );
953  if ( transform )
954  point = transform->transform( point, QgsCoordinateTransform::ReverseTransform );
955  }
956  catch ( QgsCsException &cse )
957  {
958  QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
959  }
960  }
961  else
962  {
963  // leave point without transformation
964  }
965  return point;
966 }
967 
969 {
970  if ( hasCrsTransformEnabled() )
971  {
972  try
973  {
974  const QgsCoordinateTransform *transform = transformation( theLayer );
975  if ( transform )
976  rect = transform->transform( rect, QgsCoordinateTransform::ReverseTransform );
977  }
978  catch ( QgsCsException &cse )
979  {
980  QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
981  }
982  }
983  return rect;
984 }
985 
986 
988 {
989  QgsDebugMsg( "called." );
991 
992  // reset the map canvas extent since the extent may now be smaller
993  // We can't use a constructor since QgsRectangle normalizes the rectangle upon construction
995 
996  // iterate through the map layers and test each layers extent
997  // against the current min and max values
998  QStringList::iterator it = mLayerSet.begin();
999  QgsDebugMsg( QString( "Layer count: %1" ).arg( mLayerSet.count() ) );
1000  while ( it != mLayerSet.end() )
1001  {
1002  QgsMapLayer * lyr = registry->mapLayer( *it );
1003  if ( lyr == NULL )
1004  {
1005  QgsDebugMsg( QString( "WARNING: layer '%1' not found in map layer registry!" ).arg( *it ) );
1006  }
1007  else
1008  {
1009  QgsDebugMsg( "Updating extent using " + lyr->name() );
1010  QgsDebugMsg( "Input extent: " + lyr->extent().toString() );
1011 
1012  if ( lyr->extent().isEmpty() )
1013  {
1014  ++it;
1015  continue;
1016  }
1017 
1018  // Layer extents are stored in the coordinate system (CS) of the
1019  // layer. The extent must be projected to the canvas CS
1021 
1022  QgsDebugMsg( "Output extent: " + extent.toString() );
1023  mFullExtent.unionRect( extent );
1024 
1025  }
1026  ++it;
1027  }
1028 
1029  if ( mFullExtent.width() == 0.0 || mFullExtent.height() == 0.0 )
1030  {
1031  // If all of the features are at the one point, buffer the
1032  // rectangle a bit. If they are all at zero, do something a bit
1033  // more crude.
1034 
1035  if ( mFullExtent.xMinimum() == 0.0 && mFullExtent.xMaximum() == 0.0 &&
1036  mFullExtent.yMinimum() == 0.0 && mFullExtent.yMaximum() == 0.0 )
1037  {
1038  mFullExtent.set( -1.0, -1.0, 1.0, 1.0 );
1039  }
1040  else
1041  {
1042  const double padFactor = 1e-8;
1043  double widthPad = mFullExtent.xMinimum() * padFactor;
1044  double heightPad = mFullExtent.yMinimum() * padFactor;
1045  double xmin = mFullExtent.xMinimum() - widthPad;
1046  double xmax = mFullExtent.xMaximum() + widthPad;
1047  double ymin = mFullExtent.yMinimum() - heightPad;
1048  double ymax = mFullExtent.yMaximum() + heightPad;
1049  mFullExtent.set( xmin, ymin, xmax, ymax );
1050  }
1051  }
1052 
1053  QgsDebugMsg( "Full extent: " + mFullExtent.toString() );
1054 }
1055 
1057 {
1058  updateFullExtent();
1059  return mFullExtent;
1060 }
1061 
1062 void QgsMapRenderer::setLayerSet( const QStringList& layers )
1063 {
1064  QgsDebugMsg( QString( "Entering: %1" ).arg( layers.join( ", " ) ) );
1065  mLayerSet = layers;
1066  updateFullExtent();
1067 }
1068 
1070 {
1071  return mLayerSet;
1072 }
1073 
1074 bool QgsMapRenderer::readXML( QDomNode & theNode )
1075 {
1076  QDomNode myNode = theNode.namedItem( "units" );
1077  QDomElement element = myNode.toElement();
1078 
1079  // set units
1080  QGis::UnitType units;
1081  if ( "meters" == element.text() )
1082  {
1083  units = QGis::Meters;
1084  }
1085  else if ( "feet" == element.text() )
1086  {
1087  units = QGis::Feet;
1088  }
1089  else if ( "nautical miles" == element.text() )
1090  {
1091  units = QGis::NauticalMiles;
1092  }
1093  else if ( "degrees" == element.text() )
1094  {
1095  units = QGis::Degrees;
1096  }
1097  else if ( "unknown" == element.text() )
1098  {
1099  units = QGis::UnknownUnit;
1100  }
1101  else
1102  {
1103  QgsDebugMsg( "Unknown map unit type " + element.text() );
1104  units = QGis::Degrees;
1105  }
1106  setMapUnits( units );
1107 
1108  // set projections flag
1109  QDomNode projNode = theNode.namedItem( "projections" );
1110  element = projNode.toElement();
1111  setProjectionsEnabled( element.text().toInt() );
1112 
1113  //load coordinate transform into
1115  QDomElement layerCoordTransformInfoElem = theNode.firstChildElement( "layer_coordinate_transform_info" );
1116  if ( !layerCoordTransformInfoElem.isNull() )
1117  {
1118  QDomNodeList layerCoordinateTransformList = layerCoordTransformInfoElem.elementsByTagName( "layer_coordinate_transform" );
1119  QDomElement layerCoordTransformElem;
1120  for ( int i = 0; i < layerCoordinateTransformList.size(); ++i )
1121  {
1122  layerCoordTransformElem = layerCoordinateTransformList.at( i ).toElement();
1123  QString layerId = layerCoordTransformElem.attribute( "layerid" );
1124  if ( layerId.isEmpty() )
1125  {
1126  continue;
1127  }
1128 
1130  lct.srcAuthId = layerCoordTransformElem.attribute( "srcAuthId" );
1131  lct.destAuthId = layerCoordTransformElem.attribute( "destAuthId" );
1132  lct.srcDatumTransform = layerCoordTransformElem.attribute( "srcDatumTransform", "-1" ).toInt();
1133  lct.destDatumTransform = layerCoordTransformElem.attribute( "destDatumTransform", "-1" ).toInt();
1134  mLayerCoordinateTransformInfo.insert( layerId, lct );
1135  }
1136  }
1137 
1138  // set destination CRS
1140  QDomNode srsNode = theNode.namedItem( "destinationsrs" );
1141  srs.readXML( srsNode );
1142  setDestinationCrs( srs, false );
1143 
1144  // set extent
1145  QgsRectangle aoi;
1146  QDomNode extentNode = theNode.namedItem( "extent" );
1147 
1148  QDomNode xminNode = extentNode.namedItem( "xmin" );
1149  QDomNode yminNode = extentNode.namedItem( "ymin" );
1150  QDomNode xmaxNode = extentNode.namedItem( "xmax" );
1151  QDomNode ymaxNode = extentNode.namedItem( "ymax" );
1152 
1153  QDomElement exElement = xminNode.toElement();
1154  double xmin = exElement.text().toDouble();
1155  aoi.setXMinimum( xmin );
1156 
1157  exElement = yminNode.toElement();
1158  double ymin = exElement.text().toDouble();
1159  aoi.setYMinimum( ymin );
1160 
1161  exElement = xmaxNode.toElement();
1162  double xmax = exElement.text().toDouble();
1163  aoi.setXMaximum( xmax );
1164 
1165  exElement = ymaxNode.toElement();
1166  double ymax = exElement.text().toDouble();
1167  aoi.setYMaximum( ymax );
1168 
1169  setExtent( aoi );
1170 
1171  return true;
1172 }
1173 
1174 bool QgsMapRenderer::writeXML( QDomNode & theNode, QDomDocument & theDoc )
1175 {
1176  // units
1177 
1178  QDomElement unitsNode = theDoc.createElement( "units" );
1179  theNode.appendChild( unitsNode );
1180 
1181  QString unitsString;
1182 
1183  switch ( mapUnits() )
1184  {
1185  case QGis::Meters:
1186  unitsString = "meters";
1187  break;
1188  case QGis::Feet:
1189  unitsString = "feet";
1190  break;
1191  case QGis::NauticalMiles:
1192  unitsString = "nautical miles";
1193  break;
1194  case QGis::Degrees:
1195  unitsString = "degrees";
1196  break;
1197  case QGis::UnknownUnit:
1198  default:
1199  unitsString = "unknown";
1200  break;
1201  }
1202  QDomText unitsText = theDoc.createTextNode( unitsString );
1203  unitsNode.appendChild( unitsText );
1204 
1205 
1206  // Write current view extents
1207  QDomElement extentNode = theDoc.createElement( "extent" );
1208  theNode.appendChild( extentNode );
1209 
1210  QDomElement xMin = theDoc.createElement( "xmin" );
1211  QDomElement yMin = theDoc.createElement( "ymin" );
1212  QDomElement xMax = theDoc.createElement( "xmax" );
1213  QDomElement yMax = theDoc.createElement( "ymax" );
1214 
1215  QgsRectangle r = extent();
1216  QDomText xMinText = theDoc.createTextNode( qgsDoubleToString( r.xMinimum() ) );
1217  QDomText yMinText = theDoc.createTextNode( qgsDoubleToString( r.yMinimum() ) );
1218  QDomText xMaxText = theDoc.createTextNode( qgsDoubleToString( r.xMaximum() ) );
1219  QDomText yMaxText = theDoc.createTextNode( qgsDoubleToString( r.yMaximum() ) );
1220 
1221  xMin.appendChild( xMinText );
1222  yMin.appendChild( yMinText );
1223  xMax.appendChild( xMaxText );
1224  yMax.appendChild( yMaxText );
1225 
1226  extentNode.appendChild( xMin );
1227  extentNode.appendChild( yMin );
1228  extentNode.appendChild( xMax );
1229  extentNode.appendChild( yMax );
1230 
1231  // projections enabled
1232  QDomElement projNode = theDoc.createElement( "projections" );
1233  theNode.appendChild( projNode );
1234 
1235  QDomText projText = theDoc.createTextNode( QString::number( hasCrsTransformEnabled() ) );
1236  projNode.appendChild( projText );
1237 
1238  // destination CRS
1239  QDomElement srsNode = theDoc.createElement( "destinationsrs" );
1240  theNode.appendChild( srsNode );
1241  destinationCrs().writeXML( srsNode, theDoc );
1242 
1243  // layer coordinate transform infos
1244  QDomElement layerCoordTransformInfo = theDoc.createElement( "layer_coordinate_transform_info" );
1245  QHash< QString, QgsLayerCoordinateTransform >::const_iterator coordIt = mLayerCoordinateTransformInfo.constBegin();
1246  for ( ; coordIt != mLayerCoordinateTransformInfo.constEnd(); ++coordIt )
1247  {
1248  QDomElement layerCoordTransformElem = theDoc.createElement( "layer_coordinate_transform" );
1249  layerCoordTransformElem.setAttribute( "layerid", coordIt.key() );
1250  layerCoordTransformElem.setAttribute( "srcAuthId", coordIt->srcAuthId );
1251  layerCoordTransformElem.setAttribute( "destAuthId", coordIt->destAuthId );
1252  layerCoordTransformElem.setAttribute( "srcDatumTransform", QString::number( coordIt->srcDatumTransform ) );
1253  layerCoordTransformElem.setAttribute( "destDatumTransform", QString::number( coordIt->destDatumTransform ) );
1254  layerCoordTransformInfo.appendChild( layerCoordTransformElem );
1255  }
1256  theNode.appendChild( layerCoordTransformInfo );
1257  return true;
1258 }
1259 
1261 {
1262  if ( mLabelingEngine )
1263  delete mLabelingEngine;
1264 
1265  mLabelingEngine = iface;
1266 }
1267 
1269 {
1270  if ( !layer || !mDestCRS )
1271  {
1272  return 0;
1273  }
1274 
1275  if ( layer->crs().authid() == mDestCRS->authid() )
1276  {
1277  return 0;
1278  }
1279 
1280  QHash< QString, QgsLayerCoordinateTransform >::const_iterator ctIt = mLayerCoordinateTransformInfo.find( layer->id() );
1281  if ( ctIt != mLayerCoordinateTransformInfo.constEnd()
1282  && ctIt->srcAuthId == layer->crs().authid()
1283  && ctIt->destAuthId == mDestCRS->authid() )
1284  {
1285  return QgsCoordinateTransformCache::instance()->transform( ctIt->srcAuthId, ctIt->destAuthId, ctIt->srcDatumTransform, ctIt->destDatumTransform );
1286  }
1287  else
1288  {
1289  emit datumTransformInfoRequested( layer, layer->crs().authid(), mDestCRS->authid() );
1290  }
1291 
1292  //still not present? get coordinate transformation with -1/-1 datum transform as default
1293  ctIt = mLayerCoordinateTransformInfo.find( layer->id() );
1294  if ( ctIt == mLayerCoordinateTransformInfo.constEnd()
1295  || ctIt->srcAuthId == layer->crs().authid()
1296  || ctIt->destAuthId == mDestCRS->authid()
1297  )
1298  {
1299  return QgsCoordinateTransformCache::instance()->transform( layer->crs().authid(), mDestCRS->authid(), -1, -1 );
1300  }
1301  return QgsCoordinateTransformCache::instance()->transform( ctIt->srcAuthId, ctIt->destAuthId, ctIt->srcDatumTransform, ctIt->destDatumTransform );
1302 }
1303 
1306 QPainter::CompositionMode QgsMapRenderer::getCompositionMode( const QgsMapRenderer::BlendMode &blendMode )
1307 {
1308  // Map QgsMapRenderer::BlendNormal to QPainter::CompositionMode
1309  switch ( blendMode )
1310  {
1312  return QPainter::CompositionMode_SourceOver;
1314  return QPainter::CompositionMode_Lighten;
1316  return QPainter::CompositionMode_Screen;
1318  return QPainter::CompositionMode_ColorDodge;
1320  return QPainter::CompositionMode_Plus;
1322  return QPainter::CompositionMode_Darken;
1324  return QPainter::CompositionMode_Multiply;
1326  return QPainter::CompositionMode_ColorBurn;
1328  return QPainter::CompositionMode_Overlay;
1330  return QPainter::CompositionMode_SoftLight;
1332  return QPainter::CompositionMode_HardLight;
1334  return QPainter::CompositionMode_Difference;
1336  return QPainter::CompositionMode_Exclusion;
1337  default:
1338  return QPainter::CompositionMode_SourceOver;
1339  }
1340 }
1341 
1342 QgsMapRenderer::BlendMode QgsMapRenderer::getBlendModeEnum( const QPainter::CompositionMode &blendMode )
1343 {
1344  // Map QPainter::CompositionMode to QgsMapRenderer::BlendNormal
1345  switch ( blendMode )
1346  {
1347  case QPainter::CompositionMode_SourceOver:
1349  case QPainter::CompositionMode_Lighten:
1351  case QPainter::CompositionMode_Screen:
1353  case QPainter::CompositionMode_ColorDodge:
1355  case QPainter::CompositionMode_Plus:
1357  case QPainter::CompositionMode_Darken:
1359  case QPainter::CompositionMode_Multiply:
1361  case QPainter::CompositionMode_ColorBurn:
1363  case QPainter::CompositionMode_Overlay:
1365  case QPainter::CompositionMode_SoftLight:
1367  case QPainter::CompositionMode_HardLight:
1369  case QPainter::CompositionMode_Difference:
1371  case QPainter::CompositionMode_Exclusion:
1373  default:
1375  }
1376 }
1377 
1378 void QgsMapRenderer::addLayerCoordinateTransform( const QString& layerId, const QString& srcAuthId, const QString& destAuthId, int srcDatumTransform, int destDatumTransform )
1379 {
1381  lt.srcAuthId = srcAuthId;
1382  lt.destAuthId = destAuthId;
1383  lt.srcDatumTransform = srcDatumTransform;
1384  lt.destDatumTransform = destDatumTransform;
1385  mLayerCoordinateTransformInfo.insert( layerId, lt );
1386 }
1387 
1389 {
1391 }
1392 
1393 bool QgsMapRenderer::mDrawing = false;
virtual void exit()=0
called when we're done with rendering
void setMapUnits(QGis::UnitType mapUnits)
Set the map units.
const QgsCoordinateReferenceSystem & sourceCrs() const
void unionRect(const QgsRectangle &rect)
updates rectangle to include passed argument
void setRenderingStopped(bool stopped)
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:45
void clearLayerCoordinateTransforms()
void render(QPainter *painter, double *forceWidthScale=0)
starts rendering @ param forceWidthScale Force a specific scale factor for line widths and marker siz...
void setLabelingEngine(QgsLabelingEngineInterface *iface)
Set labeling engine.
bool isEmpty() const
test if rectangle is empty
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:88
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
virtual void drawLabels(QgsRenderContext &rendererContext)
Draw labels.
void setYMaximum(double ymax)
Set maximum y value.
void drawError(QgsMapLayer *)
emitted when layer's draw() returned false
void setCacheImage(QImage *thepImage)
Set the QImage used for caching render operations.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:164
OutputUnits mOutputUnits
Output units.
bool isFinite() const
Returns true if the rectangle has finite boundaries.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:189
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
bool mProjectionsEnabled
detemines whether on the fly projection support is enabled
QgsRectangle mLastExtent
Last extent to we drew so we know if we can used layer render caching or not.
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
double rendererScale() const
QgsScaleCalculator * mScaleCalculator
scale calculator
QgsRectangle extent() const
returns current extent
QString qgsDoubleToString(const double &a)
Definition: qgis.h:297
void addLayerCoordinateTransform(const QString &layerId, const QString &srcAuthId, const QString &destAuthId, int srcDatumTransform=-1, int destDatumTransform=-1)
void setRendererScale(double scale)
float minimumScale() const
void drawingProgress(int current, int total)
~QgsMapRenderer()
destructor
void setDpi(double dpi)
Set the dpi to be used in scale calculations.
QGis::UnitType mapUnits() const
Returns current map units.
QImage * cacheImage()
Get the QImage used for caching render operations.
Definition: qgsmaplayer.h:365
void setProjectionsEnabled(bool enabled)
sets whether to use projections for this layer set
static bool mDrawing
indicates drawing in progress
bool splitLayersExtent(QgsMapLayer *layer, QgsRectangle &extent, QgsRectangle &r2)
Convenience function to project an extent into the layer source CRS, but also split it into two exten...
double scaleFactor() const
void setLayerSet(const QStringList &layers)
change current layer set
double outputDpi()
accessor for output dpi
QgsPoint mapToLayerCoordinates(QgsMapLayer *theLayer, QgsPoint point)
transform point coordinates from output CRS to layer's CRS
static QgsCoordinateTransformCache * instance()
Definition: qgscrscache.cpp:22
QgsRectangle outputExtentToLayerExtent(QgsMapLayer *theLayer, QgsRectangle extent)
transform bounding box from output CRS to layer's CRS
void setExtent(const QgsRectangle &extent)
int readNumEntry(const QString &scope, const QString &key, int def=0, bool *ok=0) const
const QgsCoordinateTransform * transformation(const QgsMapLayer *layer) const
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer...
QgsRectangle mExtent
current extent to be drawn
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
QgsMapRenderer()
constructor
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point)
transform point coordinates from layer's CRS to output CRS
void set(const QgsPoint &p1, const QgsPoint &p2)
Set the rectangle from two QgsPoints.
void setCoordinateTransform(const QgsCoordinateTransform *t)
Sets coordinate transformation.
QSize outputSize()
accessor for output size
virtual bool draw(QgsRenderContext &rendererContext)
This is the method that does the actual work of drawing the layer onto a paint device.
bool useAdvancedEffects() const
Returns true if advanced effects such as blend modes such be used.
const QString & name() const
Get the display name of the layer.
QMutex mRenderMutex
Locks rendering loop for concurrent draws.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
const QgsCoordinateTransform * transform(const QString &srcAuthId, const QString &destAuthId, int srcDatumTransform=-1, int destDatumTransform=-1)
Returns coordinate transformation.
Definition: qgscrscache.cpp:37
void setSelectionColor(const QColor &color)
Added in QGIS v2.0.
QPainter::CompositionMode blendMode() const
Read blend mode for layer.
QgsCoordinateReferenceSystem * mDestCRS
destination spatial reference system of the projection
void setScaleFactor(double factor)
QgsDistanceArea * mDistArea
tool for measuring
QPainter::CompositionMode featureBlendMode() const
Read blend mode for layer.
double calculate(const QgsRectangle &mapExtent, int canvasWidth)
Calculate the scale denominator.
bool hasScaleBasedVisibility() const
void adjustExtentToSize()
adjust extent to fit the pixmap size
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:194
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:179
void hasCrsTransformEnabledChanged(bool flag)
This signal is emitted when CRS transformation is enabled/disabled.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
bool renderingStopped() const
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
float maximumScale() const
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:169
void setDrawEditingInformation(bool b)
bool setExtent(const QgsRectangle &extent)
sets extent and checks whether suitable (returns false if not)
void setMapUnits(QGis::UnitType u)
const long GEOCRS_ID
Magic number for a geographic coord sys in QGIS srs.db tbl_srs.srs_id.
Definition: qgis.h:365
void destinationSrsChanged()
void setPainter(QPainter *p)
double rasterScaleFactor() const
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:94
Reads and writes project states.
Definition: qgsproject.h:65
bool mOverview
indicates whether it's map image for overview
QgsPoint transform(const QgsPoint p, TransformDirection direction=ForwardTransform) const
double mapUnitsPerPixel() const
Return current map units per pixel.
void setOutputSize(QSize size, int dpi)
void mapUnitsChanged()
A class to represent a point geometry.
Definition: qgspoint.h:63
void updateFullExtent()
updates extent of the layer set
This class tracks map layers that are currently loaded and provides a means to fetch a pointer to a m...
double rasterScaleFactor
Definition: qgssvgcache.cpp:80
double dpi()
Accessor for dpi used in scale calculations.
bool writeXML(QDomNode &theNode, QDomDocument &theDoc)
write settings
Calculates scale for a given combination of canvas size, map extent, and monitor dpi.
int layerTransparency() const
Read transparency for layer.
static QPainter::CompositionMode getCompositionMode(const QgsMapRenderer::BlendMode &blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode Added in 1.9.
General purpose distance and area calculator.
QgsRectangle fullExtent()
returns current extent of layer set
QString what() const
Definition: qgsexception.h:35
bool writeXML(QDomNode &theNode, QDomDocument &theDoc) const
QgsRectangle transformBoundingBox(const QgsRectangle theRect, TransformDirection direction=ForwardTransform) const
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QPainter * painter()
virtual void drawLabeling(QgsRenderContext &context)=0
called when the map is drawn and labels should be placed
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:174
void onDrawingProgress(int current, int total)
called by signal from layer current being drawn
void setLabelingEngine(QgsLabelingEngineInterface *iface)
Added in QGIS v1.4.
double mScale
Map scale denominator at its current zoom level.
QHash< QString, QgsLayerCoordinateTransform > mLayerCoordinateTransformInfo
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs, bool refreshCoordinateTransformInfo=true)
sets destination coordinate reference system
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
Class for storing a coordinate reference system (CRS)
void setMapToPixel(const QgsMapToPixel &mtp)
Class for doing transforms between two map coordinate systems.
UnitType
Map units that qgis supports.
Definition: qgis.h:229
const QgsMapToPixel & mapToPixel() const
void clearAllLayerCaches()
Clears all layer caches, resetting them to zero and freeing up any memory they may have been using...
const QgsCoordinateReferenceSystem & crs() const
Returns layer's spatial reference system.
void setParameters(double mapUnitsPerPixel, double xmin, double ymin, double ymax)
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
virtual bool willUseLayer(QgsVectorLayer *layer)=0
called to find out whether the layer is used for labeling
void updateScale()
Recalculate the map scale.
QStringList mLayerSet
stores array of layers to be rendered (identified by string)
static QgsMapRenderer::BlendMode getBlendModeEnum(const QPainter::CompositionMode &blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode Added in 1.9.
void setRasterScaleFactor(double factor)
virtual void init(QgsMapRenderer *mp)=0
called when we're going to start with rendering
void datumTransformInfoRequested(const QgsMapLayer *ml, const QString &srcAuthId, const QString &destAuthId) const
Notifies higher level components to show the datum transform dialog and add a QgsLayerCoordinateTrans...
Custom exception class for Coordinate Reference System related exceptions.
double mMapUnitsPerPixel
map units per pixel
Labeling engine interface.
QgsRenderContext mRenderContext
Encapsulates context of rendering.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:199
void setMapUnitsPerPixel(double mapUnitsPerPixel)
virtual bool isEditable() const
Returns true if the provider is in editing mode.
const QgsCoordinateReferenceSystem & destCRS() const
virtual QgsRectangle extent()
Return the extent of the layer.
QGis::UnitType mapUnits() const
Represents a vector layer which manages a vector based data sets.
double size
Definition: qgssvgcache.cpp:77
QgsLabelingEngineInterface * mLabelingEngine
Labeling engine (NULL by default)
QString toString(bool automaticPrecision=false) const
returns string representation of form xmin,ymin xmax,ymax
bool readXML(QDomNode &theNode)
read settings
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:184
QStringList & layerSet()
returns current layer set
QgsRectangle mFullExtent
full extent of the layer set
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:159
void setEllipsoidalMode(bool flag)
sets whether coordinates must be projected to ellipsoid before measuring
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *theLayer, QgsRectangle extent)
transform bounding box from layer's CRS to output CRS
QgsLabelingEngineInterface * labelingEngine() const
Added in QGIS v1.4.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:204
QString toProj4() const
Get the Proj Proj4 string representation of this srs.
#define tr(sourceText)