|
QGIS API Documentation
master-6227475
|
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;