QGIS API Documentation  master-6227475
src/core/qgsmaprenderer.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002     qgsmaprender.cpp  -  class for rendering map layer set
00003     ----------------------
00004     begin                : January 2006
00005     copyright            : (C) 2006 by Martin Dobias
00006     email                : wonder.sk at gmail dot com
00007  ***************************************************************************
00008  *                                                                         *
00009  *   This program is free software; you can redistribute it and/or modify  *
00010  *   it under the terms of the GNU General Public License as published by  *
00011  *   the Free Software Foundation; either version 2 of the License, or     *
00012  *   (at your option) any later version.                                   *
00013  *                                                                         *
00014  ***************************************************************************/
00015 
00016 #include <cmath>
00017 #include <cfloat>
00018 
00019 #include "qgscoordinatetransform.h"
00020 #include "qgscrscache.h"
00021 #include "qgslogger.h"
00022 #include "qgsmessagelog.h"
00023 #include "qgsmaprenderer.h"
00024 #include "qgsscalecalculator.h"
00025 #include "qgsmaptopixel.h"
00026 #include "qgsmaplayer.h"
00027 #include "qgsmaplayerregistry.h"
00028 #include "qgsdistancearea.h"
00029 #include "qgscentralpointpositionmanager.h"
00030 #include "qgsoverlayobjectpositionmanager.h"
00031 #include "qgspalobjectpositionmanager.h"
00032 #include "qgsproject.h"
00033 #include "qgsvectorlayer.h"
00034 #include "qgsvectoroverlay.h"
00035 
00036 
00037 #include <QDomDocument>
00038 #include <QDomNode>
00039 #include <QMutexLocker>
00040 #include <QPainter>
00041 #include <QListIterator>
00042 #include <QSettings>
00043 #include <QTime>
00044 #include <QCoreApplication>
00045 
00046 QgsMapRenderer::QgsMapRenderer()
00047 {
00048   mScale = 1.0;
00049   mScaleCalculator = new QgsScaleCalculator;
00050   mDistArea = new QgsDistanceArea;
00051 
00052   mDrawing = false;
00053   mOverview = false;
00054 
00055   // set default map units - we use WGS 84 thus use degrees
00056   setMapUnits( QGis::Degrees );
00057 
00058   mSize = QSize( 0, 0 );
00059 
00060   mProjectionsEnabled = false;
00061   mDestCRS = new QgsCoordinateReferenceSystem( GEOCRS_ID, QgsCoordinateReferenceSystem::InternalCrsId ); //WGS 84
00062 
00063   mOutputUnits = QgsMapRenderer::Millimeters;
00064 
00065   mLabelingEngine = NULL;
00066 }
00067 
00068 QgsMapRenderer::~QgsMapRenderer()
00069 {
00070   delete mScaleCalculator;
00071   delete mDistArea;
00072   delete mDestCRS;
00073   delete mLabelingEngine;
00074 }
00075 
00076 QgsRectangle QgsMapRenderer::extent() const
00077 {
00078   return mExtent;
00079 }
00080 
00081 void QgsMapRenderer::updateScale()
00082 {
00083   mScale = mScaleCalculator->calculate( mExtent, mSize.width() );
00084 }
00085 
00086 bool QgsMapRenderer::setExtent( const QgsRectangle& extent )
00087 {
00088   //remember the previous extent
00089   mLastExtent = mExtent;
00090 
00091   // Don't allow zooms where the current extent is so small that it
00092   // can't be accurately represented using a double (which is what
00093   // currentExtent uses). Excluding 0 avoids a divide by zero and an
00094   // infinite loop when rendering to a new canvas. Excluding extents
00095   // greater than 1 avoids doing unnecessary calculations.
00096 
00097   // The scheme is to compare the width against the mean x coordinate
00098   // (and height against mean y coordinate) and only allow zooms where
00099   // the ratio indicates that there is more than about 12 significant
00100   // figures (there are about 16 significant figures in a double).
00101 
00102   if ( extent.width()  > 0 &&
00103        extent.height() > 0 &&
00104        extent.width()  < 1 &&
00105        extent.height() < 1 )
00106   {
00107     // Use abs() on the extent to avoid the case where the extent is
00108     // symmetrical about 0.
00109     double xMean = ( qAbs( extent.xMinimum() ) + qAbs( extent.xMaximum() ) ) * 0.5;
00110     double yMean = ( qAbs( extent.yMinimum() ) + qAbs( extent.yMaximum() ) ) * 0.5;
00111 
00112     double xRange = extent.width() / xMean;
00113     double yRange = extent.height() / yMean;
00114 
00115     static const double minProportion = 1e-12;
00116     if ( xRange < minProportion || yRange < minProportion )
00117       return false;
00118   }
00119 
00120   mExtent = extent;
00121   if ( !extent.isEmpty() )
00122     adjustExtentToSize();
00123   return true;
00124 }
00125 
00126 
00127 
00128 void QgsMapRenderer::setOutputSize( QSize size, int dpi )
00129 {
00130   mSize = QSizeF( size.width(), size.height() );
00131   mScaleCalculator->setDpi( dpi );
00132   adjustExtentToSize();
00133 }
00134 
00135 void QgsMapRenderer::setOutputSize( QSizeF size, double dpi )
00136 {
00137   mSize = size;
00138   mScaleCalculator->setDpi( dpi );
00139   adjustExtentToSize();
00140 }
00141 
00142 double QgsMapRenderer::outputDpi()
00143 {
00144   return mScaleCalculator->dpi();
00145 }
00146 
00147 QSize QgsMapRenderer::outputSize()
00148 {
00149   return mSize.toSize();
00150 }
00151 
00152 QSizeF QgsMapRenderer::outputSizeF()
00153 {
00154   return mSize;
00155 }
00156 
00157 void QgsMapRenderer::adjustExtentToSize()
00158 {
00159   double myHeight = mSize.height();
00160   double myWidth = mSize.width();
00161 
00162   QgsMapToPixel newCoordXForm;
00163 
00164   if ( !myWidth || !myHeight )
00165   {
00166     mScale = 1.0;
00167     newCoordXForm.setParameters( 0, 0, 0, 0 );
00168     return;
00169   }
00170 
00171   // calculate the translation and scaling parameters
00172   // mapUnitsPerPixel = map units per pixel
00173   double mapUnitsPerPixelY = mExtent.height() / myHeight;
00174   double mapUnitsPerPixelX = mExtent.width() / myWidth;
00175   mMapUnitsPerPixel = mapUnitsPerPixelY > mapUnitsPerPixelX ? mapUnitsPerPixelY : mapUnitsPerPixelX;
00176 
00177   // calculate the actual extent of the mapCanvas
00178   double dxmin, dxmax, dymin, dymax, whitespace;
00179 
00180   if ( mapUnitsPerPixelY > mapUnitsPerPixelX )
00181   {
00182     dymin = mExtent.yMinimum();
00183     dymax = mExtent.yMaximum();
00184     whitespace = (( myWidth * mMapUnitsPerPixel ) - mExtent.width() ) * 0.5;
00185     dxmin = mExtent.xMinimum() - whitespace;
00186     dxmax = mExtent.xMaximum() + whitespace;
00187   }
00188   else
00189   {
00190     dxmin = mExtent.xMinimum();
00191     dxmax = mExtent.xMaximum();
00192     whitespace = (( myHeight * mMapUnitsPerPixel ) - mExtent.height() ) * 0.5;
00193     dymin = mExtent.yMinimum() - whitespace;
00194     dymax = mExtent.yMaximum() + whitespace;
00195   }
00196 
00197   QgsDebugMsg( QString( "Map units per pixel (x,y) : %1, %2" ).arg( mapUnitsPerPixelX, 0, 'f', 8 ).arg( mapUnitsPerPixelY, 0, 'f', 8 ) );
00198   QgsDebugMsg( QString( "Pixmap dimensions (x,y) : %1, %2" ).arg( myWidth, 0, 'f', 8 ).arg( myHeight, 0, 'f', 8 ) );
00199   QgsDebugMsg( QString( "Extent dimensions (x,y) : %1, %2" ).arg( mExtent.width(), 0, 'f', 8 ).arg( mExtent.height(), 0, 'f', 8 ) );
00200   QgsDebugMsg( mExtent.toString() );
00201 
00202   // update extent
00203   mExtent.setXMinimum( dxmin );
00204   mExtent.setXMaximum( dxmax );
00205   mExtent.setYMinimum( dymin );
00206   mExtent.setYMaximum( dymax );
00207 
00208   QgsDebugMsg( QString( "Adjusted map units per pixel (x,y) : %1, %2" ).arg( mExtent.width() / myWidth, 0, 'f', 8 ).arg( mExtent.height() / myHeight, 0, 'f', 8 ) );
00209 
00210   QgsDebugMsg( QString( "Recalced pixmap dimensions (x,y) : %1, %2" ).arg( mExtent.width() / mMapUnitsPerPixel, 0, 'f', 8 ).arg( mExtent.height() / mMapUnitsPerPixel, 0, 'f', 8 ) );
00211 
00212   // update the scale
00213   updateScale();
00214 
00215   QgsDebugMsg( QString( "Scale (assuming meters as map units) = 1:%1" ).arg( mScale, 0, 'f', 8 ) );
00216 
00217   newCoordXForm.setParameters( mMapUnitsPerPixel, dxmin, dymin, myHeight );
00218   mRenderContext.setMapToPixel( newCoordXForm );
00219   mRenderContext.setExtent( mExtent );
00220 }
00221 
00222 
00223 void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale )
00224 {
00225   //Lock render method for concurrent threads (e.g. from globe)
00226   QMutexLocker renderLock( &mRenderMutex );
00227 
00228   //flag to see if the render context has changed
00229   //since the last time we rendered. If it hasnt changed we can
00230   //take some shortcuts with rendering
00231   bool mySameAsLastFlag = true;
00232 
00233   QgsDebugMsg( "========== Rendering ==========" );
00234 
00235   if ( mExtent.isEmpty() )
00236   {
00237     QgsDebugMsg( "empty extent... not rendering" );
00238     return;
00239   }
00240 
00241   if ( mSize.width() == 1 && mSize.height() == 1 )
00242   {
00243     QgsDebugMsg( "size 1x1... not rendering" );
00244     return;
00245   }
00246 
00247   QPaintDevice* thePaintDevice = painter->device();
00248   if ( !thePaintDevice )
00249   {
00250     return;
00251   }
00252 
00253   // wait
00254   if ( mDrawing )
00255   {
00256     QgsDebugMsg( "already rendering" );
00257     QCoreApplication::processEvents();
00258   }
00259 
00260   if ( mDrawing )
00261   {
00262     QgsDebugMsg( "still rendering - skipping" );
00263     return;
00264   }
00265 
00266   mDrawing = true;
00267 
00268   const QgsCoordinateTransform* ct;
00269 
00270 #ifdef QGISDEBUG
00271   QgsDebugMsg( "Starting to render layer stack." );
00272   QTime renderTime;
00273   renderTime.start();
00274 #endif
00275 
00276   if ( mOverview )
00277     mRenderContext.setDrawEditingInformation( !mOverview );
00278 
00279   mRenderContext.setPainter( painter );
00280   mRenderContext.setCoordinateTransform( 0 );
00281   //this flag is only for stopping during the current rendering progress,
00282   //so must be false at every new render operation
00283   mRenderContext.setRenderingStopped( false );
00284 
00285   // set selection color
00286   QgsProject* prj = QgsProject::instance();
00287   int myRed = prj->readNumEntry( "Gui", "/SelectionColorRedPart", 255 );
00288   int myGreen = prj->readNumEntry( "Gui", "/SelectionColorGreenPart", 255 );
00289   int myBlue = prj->readNumEntry( "Gui", "/SelectionColorBluePart", 0 );
00290   int myAlpha = prj->readNumEntry( "Gui", "/SelectionColorAlphaPart", 255 );
00291   mRenderContext.setSelectionColor( QColor( myRed, myGreen, myBlue, myAlpha ) );
00292 
00293   //calculate scale factor
00294   //use the specified dpi and not those from the paint device
00295   //because sometimes QPainter units are in a local coord sys (e.g. in case of QGraphicsScene)
00296   double sceneDpi = mScaleCalculator->dpi();
00297   double scaleFactor = 1.0;
00298   if ( mOutputUnits == QgsMapRenderer::Millimeters )
00299   {
00300     if ( forceWidthScale )
00301     {
00302       scaleFactor = *forceWidthScale;
00303     }
00304     else
00305     {
00306       scaleFactor = sceneDpi / 25.4;
00307     }
00308   }
00309   double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi;
00310   if ( mRenderContext.rasterScaleFactor() != rasterScaleFactor )
00311   {
00312     mRenderContext.setRasterScaleFactor( rasterScaleFactor );
00313     mySameAsLastFlag = false;
00314   }
00315   if ( mRenderContext.scaleFactor() != scaleFactor )
00316   {
00317     mRenderContext.setScaleFactor( scaleFactor );
00318     mySameAsLastFlag = false;
00319   }
00320   if ( mRenderContext.rendererScale() != mScale )
00321   {
00322     //add map scale to render context
00323     mRenderContext.setRendererScale( mScale );
00324     mySameAsLastFlag = false;
00325   }
00326   if ( mLastExtent != mExtent )
00327   {
00328     mLastExtent = mExtent;
00329     mySameAsLastFlag = false;
00330   }
00331 
00332   mRenderContext.setLabelingEngine( mLabelingEngine );
00333   if ( mLabelingEngine )
00334     mLabelingEngine->init( this );
00335 
00336   // know we know if this render is just a repeat of the last time, we
00337   // can clear caches if it has changed
00338   if ( !mySameAsLastFlag )
00339   {
00340     //clear the cache pixmap if we changed resolution / extent
00341     QSettings mySettings;
00342     if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
00343     {
00344       QgsMapLayerRegistry::instance()->clearAllLayerCaches();
00345     }
00346   }
00347 
00348   QgsOverlayObjectPositionManager* overlayManager = overlayManagerFromSettings();
00349   QList<QgsVectorOverlay*> allOverlayList; //list of all overlays, used to draw them after layers have been rendered
00350 
00351   // render all layers in the stack, starting at the base
00352   QListIterator<QString> li( mLayerSet );
00353   li.toBack();
00354 
00355   QgsRectangle r1, r2;
00356 
00357   while ( li.hasPrevious() )
00358   {
00359     if ( mRenderContext.renderingStopped() )
00360     {
00361       break;
00362     }
00363 
00364     // Store the painter in case we need to swap it out for the
00365     // cache painter
00366     QPainter * mypContextPainter = mRenderContext.painter();
00367     // Flattened image for drawing when a blending mode is set
00368     QImage * mypFlattenedImage = 0;
00369 
00370     QString layerId = li.previous();
00371 
00372     QgsDebugMsg( "Rendering at layer item " + layerId );
00373 
00374     // This call is supposed to cause the progress bar to
00375     // advance. However, it seems that updating the progress bar is
00376     // incompatible with having a QPainter active (the one that is
00377     // passed into this function), as Qt produces a number of errors
00378     // when try to do so. I'm (Gavin) not sure how to fix this, but
00379     // added these comments and debug statement to help others...
00380     QgsDebugMsg( "If there is a QPaintEngine error here, it is caused by an emit call" );
00381 
00382     //emit drawingProgress(myRenderCounter++, mLayerSet.size());
00383     QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
00384 
00385     if ( !ml )
00386     {
00387       QgsDebugMsg( "Layer not found in registry!" );
00388       continue;
00389     }
00390 
00391     QgsDebugMsg( QString( "layer %1:  minscale:%2  maxscale:%3  scaledepvis:%4  extent:%5  blendmode:%6" )
00392                  .arg( ml->name() )
00393                  .arg( ml->minimumScale() )
00394                  .arg( ml->maximumScale() )
00395                  .arg( ml->hasScaleBasedVisibility() )
00396                  .arg( ml->extent().toString() )
00397                  .arg( ml->blendMode() )
00398                );
00399 
00400     if ( mRenderContext.useAdvancedEffects() )
00401     {
00402       // Set the QPainter composition mode so that this layer is rendered using
00403       // the desired blending mode
00404       mypContextPainter->setCompositionMode( ml->blendMode() );
00405     }
00406 
00407     if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() <= mScale && mScale < ml->maximumScale() ) || mOverview )
00408     {
00409       connect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
00410 
00411       //
00412       // Now do the call to the layer that actually does
00413       // the rendering work!
00414       //
00415 
00416       bool split = false;
00417 
00418       if ( hasCrsTransformEnabled() )
00419       {
00420         r1 = mExtent;
00421         split = splitLayersExtent( ml, r1, r2 );
00422         ct = QgsCoordinateTransformCache::instance()->transform( ml->crs().authid(), mDestCRS->authid() );
00423         mRenderContext.setExtent( r1 );
00424         QgsDebugMsg( "  extent 1: " + r1.toString() );
00425         QgsDebugMsg( "  extent 2: " + r2.toString() );
00426         if ( !r1.isFinite() || !r2.isFinite() ) //there was a problem transforming the extent. Skip the layer
00427         {
00428           continue;
00429         }
00430       }
00431       else
00432       {
00433         ct = NULL;
00434       }
00435 
00436       mRenderContext.setCoordinateTransform( ct );
00437 
00438       //decide if we have to scale the raster
00439       //this is necessary in case QGraphicsScene is used
00440       bool scaleRaster = false;
00441       QgsMapToPixel rasterMapToPixel;
00442       QgsMapToPixel bk_mapToPixel;
00443 
00444       if ( ml->type() == QgsMapLayer::RasterLayer && qAbs( rasterScaleFactor - 1.0 ) > 0.000001 )
00445       {
00446         scaleRaster = true;
00447       }
00448 
00449 
00450       //create overlay objects for features within the view extent
00451       if ( ml->type() == QgsMapLayer::VectorLayer && overlayManager )
00452       {
00453         QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
00454         if ( vl )
00455         {
00456           QList<QgsVectorOverlay*> thisLayerOverlayList;
00457           vl->vectorOverlays( thisLayerOverlayList );
00458 
00459           QList<QgsVectorOverlay*>::iterator overlayIt = thisLayerOverlayList.begin();
00460           for ( ; overlayIt != thisLayerOverlayList.end(); ++overlayIt )
00461           {
00462             if (( *overlayIt )->displayFlag() )
00463             {
00464               ( *overlayIt )->createOverlayObjects( mRenderContext );
00465               allOverlayList.push_back( *overlayIt );
00466             }
00467           }
00468 
00469           overlayManager->addLayer( vl, thisLayerOverlayList );
00470         }
00471       }
00472 
00473       // Force render of layers that are being edited
00474       // or if there's a labeling engine that needs the layer to register features
00475       if ( ml->type() == QgsMapLayer::VectorLayer )
00476       {
00477         QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
00478         if ( vl->isEditable() ||
00479              ( mRenderContext.labelingEngine() && mRenderContext.labelingEngine()->willUseLayer( vl ) ) )
00480         {
00481           ml->setCacheImage( 0 );
00482         }
00483       }
00484 
00485       QSettings mySettings;
00486       if ( ! split )//render caching does not yet cater for split extents
00487       {
00488         if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
00489         {
00490           if ( !mySameAsLastFlag || ml->cacheImage() == 0 )
00491           {
00492             QgsDebugMsg( "Caching enabled but layer redraw forced by extent change or empty cache" );
00493             QImage * mypImage = new QImage( mRenderContext.painter()->device()->width(),
00494                                             mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 );
00495             mypImage->fill( 0 );
00496             ml->setCacheImage( mypImage ); //no need to delete the old one, maplayer does it for you
00497             QPainter * mypPainter = new QPainter( ml->cacheImage() );
00498             // Changed to enable anti aliasing by default in QGIS 1.7
00499             if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() )
00500             {
00501               mypPainter->setRenderHint( QPainter::Antialiasing );
00502             }
00503             mRenderContext.setPainter( mypPainter );
00504           }
00505           else if ( mySameAsLastFlag )
00506           {
00507             //draw from cached image
00508             QgsDebugMsg( "Caching enabled --- drawing layer from cached image" );
00509             mypContextPainter->drawImage( 0, 0, *( ml->cacheImage() ) );
00510             disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
00511             //short circuit as there is nothing else to do...
00512             continue;
00513           }
00514         }
00515       }
00516 
00517       // If we are drawing with an alternative blending mode then we need to render to a separate image
00518       // before compositing this on the map. This effectively flattens the layer and prevents
00519       // blending occuring between objects on the layer
00520       // (this is not required for raster layers or when layer caching is enabled, since that has the same effect)
00521       bool flattenedLayer = false;
00522       if (( mRenderContext.useAdvancedEffects() ) && ( ml->type() == QgsMapLayer::VectorLayer ) )
00523       {
00524         QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
00525         if (( vl->blendMode() != QPainter::CompositionMode_SourceOver && ( split || !mySettings.value( "/qgis/enable_render_caching", false ).toBool() ) )
00526             || ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
00527             || ( vl->layerTransparency() != 0 ) )
00528 
00529         {
00530           flattenedLayer = true;
00531           mypFlattenedImage = new QImage( mRenderContext.painter()->device()->width(),
00532                                           mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 );
00533           mypFlattenedImage->fill( 0 );
00534           QPainter * mypPainter = new QPainter( mypFlattenedImage );
00535           if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() )
00536           {
00537             mypPainter->setRenderHint( QPainter::Antialiasing );
00538           }
00539           mypPainter->scale( rasterScaleFactor,  rasterScaleFactor );
00540           mRenderContext.setPainter( mypPainter );
00541 
00542           // set the painter to the feature blend mode
00543           mypPainter->setCompositionMode( vl->featureBlendMode() );
00544         }
00545       }
00546 
00547       if ( scaleRaster )
00548       {
00549         bk_mapToPixel = mRenderContext.mapToPixel();
00550         rasterMapToPixel = mRenderContext.mapToPixel();
00551         rasterMapToPixel.setMapUnitsPerPixel( mRenderContext.mapToPixel().mapUnitsPerPixel() / rasterScaleFactor );
00552         rasterMapToPixel.setYMaximum( mSize.height() * rasterScaleFactor );
00553         mRenderContext.setMapToPixel( rasterMapToPixel );
00554         mRenderContext.painter()->save();
00555         mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
00556       }
00557 
00558       if ( !ml->draw( mRenderContext ) )
00559       {
00560         emit drawError( ml );
00561       }
00562       else
00563       {
00564         QgsDebugMsg( "Layer rendered without issues" );
00565       }
00566 
00567       if ( split )
00568       {
00569         mRenderContext.setExtent( r2 );
00570         if ( !ml->draw( mRenderContext ) )
00571         {
00572           emit drawError( ml );
00573         }
00574       }
00575 
00576       if ( scaleRaster )
00577       {
00578         mRenderContext.setMapToPixel( bk_mapToPixel );
00579         mRenderContext.painter()->restore();
00580       }
00581 
00582       if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
00583       {
00584         if ( !split )
00585         {
00586           // composite the cached image into our view and then clean up from caching
00587           // by reinstating the painter as it was swapped out for caching renders
00588           delete mRenderContext.painter();
00589           mRenderContext.setPainter( mypContextPainter );
00590           //draw from cached image that we created further up
00591           if ( ml->cacheImage() )
00592             mypContextPainter->drawImage( 0, 0, *( ml->cacheImage() ) );
00593         }
00594       }
00595 
00596       // If we flattened this layer for alternate blend modes, composite it now
00597       if ( flattenedLayer )
00598       {
00599         QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
00600         if ( vl->layerTransparency() != 0 )
00601         {
00602           // a layer transparency has been set, so update the alpha for the flattened layer
00603           // by combining it with the layer transparency
00604           QColor transparentFillColor = QColor( 0, 0, 0, 255 - ( 255 * vl->layerTransparency() / 100 ) );
00605           // use destination in composition mode to merge source's alpha with destination
00606           mRenderContext.painter()->setCompositionMode( QPainter::CompositionMode_DestinationIn );
00607           mRenderContext.painter()->fillRect( mypFlattenedImage->rect(), transparentFillColor );
00608         }
00609 
00610         delete mRenderContext.painter();
00611         mRenderContext.setPainter( mypContextPainter );
00612         mypContextPainter->save();
00613         mypContextPainter->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
00614         mypContextPainter->drawImage( 0, 0, *( mypFlattenedImage ) );
00615         mypContextPainter->restore();
00616         delete mypFlattenedImage;
00617         mypFlattenedImage = 0;
00618       }
00619 
00620       disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
00621     }
00622     else // layer not visible due to scale
00623     {
00624       QgsDebugMsg( "Layer not rendered because it is not within the defined "
00625                    "visibility scale range" );
00626     }
00627 
00628   } // while (li.hasPrevious())
00629 
00630   QgsDebugMsg( "Done rendering map layers" );
00631 
00632   // Reset the composition mode before rendering the labels
00633   mRenderContext.painter()->setCompositionMode( QPainter::CompositionMode_SourceOver );
00634 
00635   if ( !mOverview )
00636   {
00637     // render all labels for vector layers in the stack, starting at the base
00638     li.toBack();
00639     while ( li.hasPrevious() )
00640     {
00641       if ( mRenderContext.renderingStopped() )
00642       {
00643         break;
00644       }
00645 
00646       QString layerId = li.previous();
00647 
00648       // TODO: emit drawingProgress((myRenderCounter++),zOrder.size());
00649       QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
00650 
00651       if ( ml && ( ml->type() != QgsMapLayer::RasterLayer ) )
00652       {
00653         // only make labels if the layer is visible
00654         // after scale dep viewing settings are checked
00655         if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() < mScale && mScale < ml->maximumScale() ) )
00656         {
00657           bool split = false;
00658 
00659           if ( hasCrsTransformEnabled() )
00660           {
00661             QgsRectangle r1 = mExtent;
00662             split = splitLayersExtent( ml, r1, r2 );
00663             ct = new QgsCoordinateTransform( ml->crs(), *mDestCRS );
00664             mRenderContext.setExtent( r1 );
00665           }
00666           else
00667           {
00668             ct = NULL;
00669           }
00670 
00671           mRenderContext.setCoordinateTransform( ct );
00672 
00673           ml->drawLabels( mRenderContext );
00674           if ( split )
00675           {
00676             mRenderContext.setExtent( r2 );
00677             ml->drawLabels( mRenderContext );
00678           }
00679         }
00680       }
00681     }
00682   } // if (!mOverview)
00683 
00684   //find overlay positions and draw the vector overlays
00685   if ( overlayManager && allOverlayList.size() > 0 )
00686   {
00687     overlayManager->findObjectPositions( mRenderContext, mScaleCalculator->mapUnits() );
00688     //draw all the overlays
00689     QList<QgsVectorOverlay*>::iterator allOverlayIt = allOverlayList.begin();
00690     for ( ; allOverlayIt != allOverlayList.end(); ++allOverlayIt )
00691     {
00692       ( *allOverlayIt )->drawOverlayObjects( mRenderContext );
00693     }
00694     overlayManager->removeLayers();
00695   }
00696 
00697   delete overlayManager;
00698   // make sure progress bar arrives at 100%!
00699   emit drawingProgress( 1, 1 );
00700 
00701   if ( mLabelingEngine )
00702   {
00703     // set correct extent
00704     mRenderContext.setExtent( mExtent );
00705     mRenderContext.setCoordinateTransform( NULL );
00706 
00707     mLabelingEngine->drawLabeling( mRenderContext );
00708     mLabelingEngine->exit();
00709   }
00710 
00711   QgsDebugMsg( "Rendering completed in (seconds): " + QString( "%1" ).arg( renderTime.elapsed() / 1000.0 ) );
00712 
00713   mDrawing = false;
00714 }
00715 
00716 void QgsMapRenderer::setMapUnits( QGis::UnitType u )
00717 {
00718   mScaleCalculator->setMapUnits( u );
00719 
00720   // Since the map units have changed, force a recalculation of the scale.
00721   updateScale();
00722 
00723   emit mapUnitsChanged();
00724 }
00725 
00726 QGis::UnitType QgsMapRenderer::mapUnits() const
00727 {
00728   return mScaleCalculator->mapUnits();
00729 }
00730 
00731 void QgsMapRenderer::onDrawingProgress( int current, int total )
00732 {
00733   Q_UNUSED( current );
00734   Q_UNUSED( total );
00735   // TODO: emit signal with progress
00736 // QgsDebugMsg(QString("onDrawingProgress: %1 / %2").arg(current).arg(total));
00737   emit updateMap();
00738 }
00739 
00740 void QgsMapRenderer::setProjectionsEnabled( bool enabled )
00741 {
00742   if ( mProjectionsEnabled != enabled )
00743   {
00744     mProjectionsEnabled = enabled;
00745     QgsDebugMsg( "Adjusting DistArea projection on/off" );
00746     mDistArea->setEllipsoidalMode( enabled );
00747     updateFullExtent();
00748     mLastExtent.setMinimal();
00749     emit hasCrsTransformEnabled( enabled );
00750   }
00751 }
00752 
00753 bool QgsMapRenderer::hasCrsTransformEnabled() const
00754 {
00755   return mProjectionsEnabled;
00756 }
00757 
00758 void QgsMapRenderer::setDestinationCrs( const QgsCoordinateReferenceSystem& crs )
00759 {
00760   QgsDebugMsg( "* Setting destCRS : = " + crs.toProj4() );
00761   QgsDebugMsg( "* DestCRS.srsid() = " + QString::number( crs.srsid() ) );
00762   if ( *mDestCRS != crs )
00763   {
00764     QgsRectangle rect;
00765     if ( !mExtent.isEmpty() )
00766     {
00767       QgsCoordinateTransform transform( *mDestCRS, crs );
00768       rect = transform.transformBoundingBox( mExtent );
00769     }
00770 
00771     QgsDebugMsg( "Setting DistArea CRS to " + QString::number( crs.srsid() ) );
00772     mDistArea->setSourceCrs( crs.srsid() );
00773     *mDestCRS = crs;
00774     updateFullExtent();
00775 
00776     if ( !rect.isEmpty() )
00777     {
00778       setExtent( rect );
00779     }
00780 
00781     emit destinationSrsChanged();
00782   }
00783 }
00784 
00785 const QgsCoordinateReferenceSystem& QgsMapRenderer::destinationCrs() const
00786 {
00787   QgsDebugMsgLevel( "* Returning destCRS", 3 );
00788   QgsDebugMsgLevel( "* DestCRS.srsid() = " + QString::number( mDestCRS->srsid() ), 3 );
00789   QgsDebugMsgLevel( "* DestCRS.proj4() = " + mDestCRS->toProj4(), 3 );
00790   return *mDestCRS;
00791 }
00792 
00793 
00794 bool QgsMapRenderer::splitLayersExtent( QgsMapLayer* layer, QgsRectangle& extent, QgsRectangle& r2 )
00795 {
00796   bool split = false;
00797 
00798   if ( hasCrsTransformEnabled() )
00799   {
00800     try
00801     {
00802 #ifdef QGISDEBUG
00803       // QgsLogger::debug<QgsRectangle>("Getting extent of canvas in layers CS. Canvas is ", extent, __FILE__, __FUNCTION__, __LINE__);
00804 #endif
00805       // Split the extent into two if the source CRS is
00806       // geographic and the extent crosses the split in
00807       // geographic coordinates (usually +/- 180 degrees,
00808       // and is assumed to be so here), and draw each
00809       // extent separately.
00810       static const double splitCoord = 180.0;
00811 
00812       if ( layer->crs().geographicFlag() )
00813       {
00814         // Note: ll = lower left point
00815         //   and ur = upper right point
00816         QgsPoint ll = tr( layer )->transform( extent.xMinimum(), extent.yMinimum(),
00817                                               QgsCoordinateTransform::ReverseTransform );
00818 
00819         QgsPoint ur = tr( layer )->transform( extent.xMaximum(), extent.yMaximum(),
00820                                               QgsCoordinateTransform::ReverseTransform );
00821 
00822         extent = tr( layer )->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
00823 
00824         if ( ll.x() > ur.x() )
00825         {
00826           r2 = extent;
00827           extent.setXMinimum( splitCoord );
00828           r2.setXMaximum( splitCoord );
00829           split = true;
00830         }
00831       }
00832       else // can't cross 180
00833       {
00834         extent = tr( layer )->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
00835       }
00836     }
00837     catch ( QgsCsException &cse )
00838     {
00839       Q_UNUSED( cse );
00840       QgsDebugMsg( "Transform error caught" );
00841       extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
00842       r2     = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
00843     }
00844   }
00845   return split;
00846 }
00847 
00848 QgsRectangle QgsMapRenderer::layerExtentToOutputExtent( QgsMapLayer* theLayer, QgsRectangle extent )
00849 {
00850   QgsDebugMsg( QString( "sourceCrs = " + tr( theLayer )->sourceCrs().authid() ) );
00851   QgsDebugMsg( QString( "destCRS = " + tr( theLayer )->destCRS().authid() ) );
00852   QgsDebugMsg( QString( "extent = " + extent.toString() ) );
00853   if ( hasCrsTransformEnabled() )
00854   {
00855     try
00856     {
00857       extent = tr( theLayer )->transformBoundingBox( extent );
00858     }
00859     catch ( QgsCsException &cse )
00860     {
00861       QgsMessageLog::logMessage( tr( "Transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
00862     }
00863   }
00864 
00865   QgsDebugMsg( QString( "proj extent = " + extent.toString() ) );
00866 
00867   return extent;
00868 }
00869 
00870 QgsRectangle QgsMapRenderer::outputExtentToLayerExtent( QgsMapLayer* theLayer, QgsRectangle extent )
00871 {
00872   QgsDebugMsg( QString( "layer sourceCrs = " + tr( theLayer )->sourceCrs().authid() ) );
00873   QgsDebugMsg( QString( "layer destCRS = " + tr( theLayer )->destCRS().authid() ) );
00874   QgsDebugMsg( QString( "extent = " + extent.toString() ) );
00875   if ( hasCrsTransformEnabled() )
00876   {
00877     try
00878     {
00879       extent = tr( theLayer )->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
00880     }
00881     catch ( QgsCsException &cse )
00882     {
00883       QgsMessageLog::logMessage( tr( "Transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
00884     }
00885   }
00886 
00887   QgsDebugMsg( QString( "proj extent = " + extent.toString() ) );
00888 
00889   return extent;
00890 }
00891 
00892 QgsPoint QgsMapRenderer::layerToMapCoordinates( QgsMapLayer* theLayer, QgsPoint point )
00893 {
00894   if ( hasCrsTransformEnabled() )
00895   {
00896     try
00897     {
00898       point = tr( theLayer )->transform( point, QgsCoordinateTransform::ForwardTransform );
00899     }
00900     catch ( QgsCsException &cse )
00901     {
00902       QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00903     }
00904   }
00905   else
00906   {
00907     // leave point without transformation
00908   }
00909   return point;
00910 }
00911 
00912 QgsRectangle QgsMapRenderer::layerToMapCoordinates( QgsMapLayer* theLayer, QgsRectangle rect )
00913 {
00914   if ( hasCrsTransformEnabled() )
00915   {
00916     try
00917     {
00918       rect = tr( theLayer )->transform( rect, QgsCoordinateTransform::ForwardTransform );
00919     }
00920     catch ( QgsCsException &cse )
00921     {
00922       QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00923     }
00924   }
00925   else
00926   {
00927     // leave point without transformation
00928   }
00929   return rect;
00930 }
00931 
00932 QgsPoint QgsMapRenderer::mapToLayerCoordinates( QgsMapLayer* theLayer, QgsPoint point )
00933 {
00934   if ( hasCrsTransformEnabled() )
00935   {
00936     try
00937     {
00938       point = tr( theLayer )->transform( point, QgsCoordinateTransform::ReverseTransform );
00939     }
00940     catch ( QgsCsException &cse )
00941     {
00942       QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00943     }
00944   }
00945   else
00946   {
00947     // leave point without transformation
00948   }
00949   return point;
00950 }
00951 
00952 QgsRectangle QgsMapRenderer::mapToLayerCoordinates( QgsMapLayer* theLayer, QgsRectangle rect )
00953 {
00954   if ( hasCrsTransformEnabled() )
00955   {
00956     try
00957     {
00958       rect = tr( theLayer )->transform( rect, QgsCoordinateTransform::ReverseTransform );
00959     }
00960     catch ( QgsCsException &cse )
00961     {
00962       QgsMessageLog::logMessage( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00963     }
00964   }
00965   return rect;
00966 }
00967 
00968 
00969 void QgsMapRenderer::updateFullExtent()
00970 {
00971   QgsDebugMsg( "called." );
00972   QgsMapLayerRegistry* registry = QgsMapLayerRegistry::instance();
00973 
00974   // reset the map canvas extent since the extent may now be smaller
00975   // We can't use a constructor since QgsRectangle normalizes the rectangle upon construction
00976   mFullExtent.setMinimal();
00977 
00978   // iterate through the map layers and test each layers extent
00979   // against the current min and max values
00980   QStringList::iterator it = mLayerSet.begin();
00981   QgsDebugMsg( QString( "Layer count: %1" ).arg( mLayerSet.count() ) );
00982   while ( it != mLayerSet.end() )
00983   {
00984     QgsMapLayer * lyr = registry->mapLayer( *it );
00985     if ( lyr == NULL )
00986     {
00987       QgsDebugMsg( QString( "WARNING: layer '%1' not found in map layer registry!" ).arg( *it ) );
00988     }
00989     else
00990     {
00991       QgsDebugMsg( "Updating extent using " + lyr->name() );
00992       QgsDebugMsg( "Input extent: " + lyr->extent().toString() );
00993 
00994       // Layer extents are stored in the coordinate system (CS) of the
00995       // layer. The extent must be projected to the canvas CS
00996       QgsRectangle extent = layerExtentToOutputExtent( lyr, lyr->extent() );
00997 
00998       QgsDebugMsg( "Output extent: " + extent.toString() );
00999       mFullExtent.unionRect( extent );
01000 
01001     }
01002     it++;
01003   }
01004 
01005   if ( mFullExtent.width() == 0.0 || mFullExtent.height() == 0.0 )
01006   {
01007     // If all of the features are at the one point, buffer the
01008     // rectangle a bit. If they are all at zero, do something a bit
01009     // more crude.
01010 
01011     if ( mFullExtent.xMinimum() == 0.0 && mFullExtent.xMaximum() == 0.0 &&
01012          mFullExtent.yMinimum() == 0.0 && mFullExtent.yMaximum() == 0.0 )
01013     {
01014       mFullExtent.set( -1.0, -1.0, 1.0, 1.0 );
01015     }
01016     else
01017     {
01018       const double padFactor = 1e-8;
01019       double widthPad = mFullExtent.xMinimum() * padFactor;
01020       double heightPad = mFullExtent.yMinimum() * padFactor;
01021       double xmin = mFullExtent.xMinimum() - widthPad;
01022       double xmax = mFullExtent.xMaximum() + widthPad;
01023       double ymin = mFullExtent.yMinimum() - heightPad;
01024       double ymax = mFullExtent.yMaximum() + heightPad;
01025       mFullExtent.set( xmin, ymin, xmax, ymax );
01026     }
01027   }
01028 
01029   QgsDebugMsg( "Full extent: " + mFullExtent.toString() );
01030 }
01031 
01032 QgsRectangle QgsMapRenderer::fullExtent()
01033 {
01034   updateFullExtent();
01035   return mFullExtent;
01036 }
01037 
01038 void QgsMapRenderer::setLayerSet( const QStringList& layers )
01039 {
01040   QgsDebugMsg( QString( "Entering: %1" ).arg( layers.join( ", " ) ) );
01041   mLayerSet = layers;
01042   updateFullExtent();
01043 }
01044 
01045 QStringList& QgsMapRenderer::layerSet()
01046 {
01047   return mLayerSet;
01048 }
01049 
01050 QgsOverlayObjectPositionManager* QgsMapRenderer::overlayManagerFromSettings()
01051 {
01052   QSettings settings;
01053   QString overlayAlgorithmQString = settings.value( "qgis/overlayPlacementAlgorithm", "Central point" ).toString();
01054 
01055   QgsOverlayObjectPositionManager* result = 0;
01056 
01057   if ( overlayAlgorithmQString != "Central point" )
01058   {
01059     QgsPALObjectPositionManager* palManager = new QgsPALObjectPositionManager();
01060     if ( overlayAlgorithmQString == "Chain" )
01061     {
01062       palManager->setPlacementAlgorithm( "Chain" );
01063     }
01064     else if ( overlayAlgorithmQString == "Popmusic tabu chain" )
01065     {
01066       palManager->setPlacementAlgorithm( "Popmusic tabu chain" );
01067     }
01068     else if ( overlayAlgorithmQString == "Popmusic tabu" )
01069     {
01070       palManager->setPlacementAlgorithm( "Popmusic tabu" );
01071     }
01072     else if ( overlayAlgorithmQString == "Popmusic chain" )
01073     {
01074       palManager->setPlacementAlgorithm( "Popmusic chain" );
01075     }
01076     result = palManager;
01077   }
01078   else
01079   {
01080     result = new QgsCentralPointPositionManager();
01081   }
01082 
01083   return result;
01084 }
01085 
01086 bool QgsMapRenderer::readXML( QDomNode & theNode )
01087 {
01088   QDomNode myNode = theNode.namedItem( "units" );
01089   QDomElement element = myNode.toElement();
01090 
01091   // set units
01092   QGis::UnitType units;
01093   if ( "meters" == element.text() )
01094   {
01095     units = QGis::Meters;
01096   }
01097   else if ( "feet" == element.text() )
01098   {
01099     units = QGis::Feet;
01100   }
01101   else if ( "degrees" == element.text() )
01102   {
01103     units = QGis::Degrees;
01104   }
01105   else if ( "unknown" == element.text() )
01106   {
01107     units = QGis::UnknownUnit;
01108   }
01109   else
01110   {
01111     QgsDebugMsg( "Unknown map unit type " + element.text() );
01112     units = QGis::Degrees;
01113   }
01114   setMapUnits( units );
01115 
01116   // set projections flag
01117   QDomNode projNode = theNode.namedItem( "projections" );
01118   element = projNode.toElement();
01119   setProjectionsEnabled( element.text().toInt() );
01120 
01121   // set destination CRS
01122   QgsCoordinateReferenceSystem srs;
01123   QDomNode srsNode = theNode.namedItem( "destinationsrs" );
01124   srs.readXML( srsNode );
01125   setDestinationCrs( srs );
01126 
01127   // set extent
01128   QgsRectangle aoi;
01129   QDomNode extentNode = theNode.namedItem( "extent" );
01130 
01131   QDomNode xminNode = extentNode.namedItem( "xmin" );
01132   QDomNode yminNode = extentNode.namedItem( "ymin" );
01133   QDomNode xmaxNode = extentNode.namedItem( "xmax" );
01134   QDomNode ymaxNode = extentNode.namedItem( "ymax" );
01135 
01136   QDomElement exElement = xminNode.toElement();
01137   double xmin = exElement.text().toDouble();
01138   aoi.setXMinimum( xmin );
01139 
01140   exElement = yminNode.toElement();
01141   double ymin = exElement.text().toDouble();
01142   aoi.setYMinimum( ymin );
01143 
01144   exElement = xmaxNode.toElement();
01145   double xmax = exElement.text().toDouble();
01146   aoi.setXMaximum( xmax );
01147 
01148   exElement = ymaxNode.toElement();
01149   double ymax = exElement.text().toDouble();
01150   aoi.setYMaximum( ymax );
01151 
01152   setExtent( aoi );
01153   return true;
01154 }
01155 
01156 bool QgsMapRenderer::writeXML( QDomNode & theNode, QDomDocument & theDoc )
01157 {
01158   // units
01159 
01160   QDomElement unitsNode = theDoc.createElement( "units" );
01161   theNode.appendChild( unitsNode );
01162 
01163   QString unitsString;
01164 
01165   switch ( mapUnits() )
01166   {
01167     case QGis::Meters:
01168       unitsString = "meters";
01169       break;
01170     case QGis::Feet:
01171       unitsString = "feet";
01172       break;
01173     case QGis::Degrees:
01174       unitsString = "degrees";
01175       break;
01176     case QGis::UnknownUnit:
01177     default:
01178       unitsString = "unknown";
01179       break;
01180   }
01181   QDomText unitsText = theDoc.createTextNode( unitsString );
01182   unitsNode.appendChild( unitsText );
01183 
01184 
01185   // Write current view extents
01186   QDomElement extentNode = theDoc.createElement( "extent" );
01187   theNode.appendChild( extentNode );
01188 
01189   QDomElement xMin = theDoc.createElement( "xmin" );
01190   QDomElement yMin = theDoc.createElement( "ymin" );
01191   QDomElement xMax = theDoc.createElement( "xmax" );
01192   QDomElement yMax = theDoc.createElement( "ymax" );
01193 
01194   QgsRectangle r = extent();
01195   QDomText xMinText = theDoc.createTextNode( QString::number( r.xMinimum(), 'f' ) );
01196   QDomText yMinText = theDoc.createTextNode( QString::number( r.yMinimum(), 'f' ) );
01197   QDomText xMaxText = theDoc.createTextNode( QString::number( r.xMaximum(), 'f' ) );
01198   QDomText yMaxText = theDoc.createTextNode( QString::number( r.yMaximum(), 'f' ) );
01199 
01200   xMin.appendChild( xMinText );
01201   yMin.appendChild( yMinText );
01202   xMax.appendChild( xMaxText );
01203   yMax.appendChild( yMaxText );
01204 
01205   extentNode.appendChild( xMin );
01206   extentNode.appendChild( yMin );
01207   extentNode.appendChild( xMax );
01208   extentNode.appendChild( yMax );
01209 
01210   // projections enabled
01211   QDomElement projNode = theDoc.createElement( "projections" );
01212   theNode.appendChild( projNode );
01213 
01214   QDomText projText = theDoc.createTextNode( QString::number( hasCrsTransformEnabled() ) );
01215   projNode.appendChild( projText );
01216 
01217   // destination CRS
01218   QDomElement srsNode = theDoc.createElement( "destinationsrs" );
01219   theNode.appendChild( srsNode );
01220   destinationCrs().writeXML( srsNode, theDoc );
01221 
01222   return true;
01223 }
01224 
01225 void QgsMapRenderer::setLabelingEngine( QgsLabelingEngineInterface* iface )
01226 {
01227   if ( mLabelingEngine )
01228     delete mLabelingEngine;
01229 
01230   mLabelingEngine = iface;
01231 }
01232 
01233 const QgsCoordinateTransform* QgsMapRenderer::tr( QgsMapLayer *layer )
01234 {
01235   if ( !layer || !mDestCRS )
01236   {
01237     return 0;
01238   }
01239   return QgsCoordinateTransformCache::instance()->transform( layer->crs().authid(), mDestCRS->authid() );
01240 }
01241 
01244 QPainter::CompositionMode QgsMapRenderer::getCompositionMode( const QgsMapRenderer::BlendMode blendMode )
01245 {
01246   // Map QgsMapRenderer::BlendNormal to QPainter::CompositionMode
01247   switch ( blendMode )
01248   {
01249     case QgsMapRenderer::BlendNormal:
01250       return QPainter::CompositionMode_SourceOver;
01251     case QgsMapRenderer::BlendLighten:
01252       return QPainter::CompositionMode_Lighten;
01253     case QgsMapRenderer::BlendScreen:
01254       return QPainter::CompositionMode_Screen;
01255     case QgsMapRenderer::BlendDodge:
01256       return QPainter::CompositionMode_ColorDodge;
01257     case QgsMapRenderer::BlendAddition:
01258       return QPainter::CompositionMode_Plus;
01259     case QgsMapRenderer::BlendDarken:
01260       return QPainter::CompositionMode_Darken;
01261     case QgsMapRenderer::BlendMultiply:
01262       return QPainter::CompositionMode_Multiply;
01263     case QgsMapRenderer::BlendBurn:
01264       return QPainter::CompositionMode_ColorBurn;
01265     case QgsMapRenderer::BlendOverlay:
01266       return QPainter::CompositionMode_Overlay;
01267     case QgsMapRenderer::BlendSoftLight:
01268       return QPainter::CompositionMode_SoftLight;
01269     case QgsMapRenderer::BlendHardLight:
01270       return QPainter::CompositionMode_HardLight;
01271     case QgsMapRenderer::BlendDifference:
01272       return QPainter::CompositionMode_Difference;
01273     case QgsMapRenderer::BlendSubtract:
01274       return QPainter::CompositionMode_Exclusion;
01275     default:
01276       return QPainter::CompositionMode_SourceOver;
01277   }
01278 }
01279 
01280 QgsMapRenderer::BlendMode QgsMapRenderer::getBlendModeEnum( const QPainter::CompositionMode blendMode )
01281 {
01282   // Map QPainter::CompositionMode to QgsMapRenderer::BlendNormal
01283   switch ( blendMode )
01284   {
01285     case QPainter::CompositionMode_SourceOver:
01286       return QgsMapRenderer::BlendNormal;
01287     case QPainter::CompositionMode_Lighten:
01288       return QgsMapRenderer::BlendLighten;
01289     case QPainter::CompositionMode_Screen:
01290       return QgsMapRenderer::BlendScreen;
01291     case QPainter::CompositionMode_ColorDodge:
01292       return QgsMapRenderer::BlendDodge;
01293     case QPainter::CompositionMode_Plus:
01294       return QgsMapRenderer::BlendAddition;
01295     case QPainter::CompositionMode_Darken:
01296       return QgsMapRenderer::BlendDarken;
01297     case QPainter::CompositionMode_Multiply:
01298       return QgsMapRenderer::BlendMultiply;
01299     case QPainter::CompositionMode_ColorBurn:
01300       return QgsMapRenderer::BlendBurn;
01301     case QPainter::CompositionMode_Overlay:
01302       return QgsMapRenderer::BlendOverlay;
01303     case QPainter::CompositionMode_SoftLight:
01304       return QgsMapRenderer::BlendSoftLight;
01305     case QPainter::CompositionMode_HardLight:
01306       return QgsMapRenderer::BlendHardLight;
01307     case QPainter::CompositionMode_Difference:
01308       return QgsMapRenderer::BlendDifference;
01309     case QPainter::CompositionMode_Exclusion:
01310       return QgsMapRenderer::BlendSubtract;
01311     default:
01312       return QgsMapRenderer::BlendNormal;
01313   }
01314 }
01315 
01316 bool QgsMapRenderer::mDrawing = false;
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines