00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <cmath>
00017 #include <cfloat>
00018
00019 #include "qgscoordinatetransform.h"
00020 #include "qgslogger.h"
00021 #include "qgsmessagelog.h"
00022 #include "qgsmaprenderer.h"
00023 #include "qgsscalecalculator.h"
00024 #include "qgsmaptopixel.h"
00025 #include "qgsmaplayer.h"
00026 #include "qgsmaplayerregistry.h"
00027 #include "qgsdistancearea.h"
00028 #include "qgscentralpointpositionmanager.h"
00029 #include "qgsoverlayobjectpositionmanager.h"
00030 #include "qgspalobjectpositionmanager.h"
00031 #include "qgsvectorlayer.h"
00032 #include "qgsvectoroverlay.h"
00033
00034
00035 #include <QDomDocument>
00036 #include <QDomNode>
00037 #include <QMutexLocker>
00038 #include <QPainter>
00039 #include <QListIterator>
00040 #include <QSettings>
00041 #include <QTime>
00042 #include <QCoreApplication>
00043
00044 QgsMapRenderer::QgsMapRenderer()
00045 {
00046 mScaleCalculator = new QgsScaleCalculator;
00047 mDistArea = new QgsDistanceArea;
00048 mCachedTrForLayer = 0;
00049 mCachedTr = 0;
00050
00051 mDrawing = false;
00052 mOverview = false;
00053
00054
00055 setMapUnits( QGis::Degrees );
00056
00057 mSize = QSize( 0, 0 );
00058
00059 mProjectionsEnabled = false;
00060 mDestCRS = new QgsCoordinateReferenceSystem( GEOCRS_ID, QgsCoordinateReferenceSystem::InternalCrsId );
00061
00062 mOutputUnits = QgsMapRenderer::Millimeters;
00063
00064 mLabelingEngine = NULL;
00065 }
00066
00067 QgsMapRenderer::~QgsMapRenderer()
00068 {
00069 delete mScaleCalculator;
00070 delete mDistArea;
00071 delete mDestCRS;
00072 delete mLabelingEngine;
00073 delete mCachedTr;
00074 }
00075
00076
00077 QgsRectangle QgsMapRenderer::extent() const
00078 {
00079 return mExtent;
00080 }
00081
00082 void QgsMapRenderer::updateScale()
00083 {
00084 mScale = mScaleCalculator->calculate( mExtent, mSize.width() );
00085 }
00086
00087 bool QgsMapRenderer::setExtent( const QgsRectangle& extent )
00088 {
00089
00090 mLastExtent = mExtent;
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 if ( extent.width() > 0 &&
00104 extent.height() > 0 &&
00105 extent.width() < 1 &&
00106 extent.height() < 1 )
00107 {
00108
00109
00110 double xMean = ( qAbs( extent.xMinimum() ) + qAbs( extent.xMaximum() ) ) * 0.5;
00111 double yMean = ( qAbs( extent.yMinimum() ) + qAbs( extent.yMaximum() ) ) * 0.5;
00112
00113 double xRange = extent.width() / xMean;
00114 double yRange = extent.height() / yMean;
00115
00116 static const double minProportion = 1e-12;
00117 if ( xRange < minProportion || yRange < minProportion )
00118 return false;
00119 }
00120
00121 mExtent = extent;
00122 if ( !extent.isEmpty() )
00123 adjustExtentToSize();
00124 return true;
00125 }
00126
00127
00128
00129 void QgsMapRenderer::setOutputSize( QSize size, int dpi )
00130 {
00131 mSize = QSizeF( size.width(), size.height() );
00132 mScaleCalculator->setDpi( dpi );
00133 adjustExtentToSize();
00134 }
00135
00136 void QgsMapRenderer::setOutputSize( QSizeF size, double dpi )
00137 {
00138 mSize = size;
00139 mScaleCalculator->setDpi( dpi );
00140 adjustExtentToSize();
00141 }
00142
00143 double QgsMapRenderer::outputDpi()
00144 {
00145 return mScaleCalculator->dpi();
00146 }
00147
00148 QSize QgsMapRenderer::outputSize()
00149 {
00150 return mSize.toSize();
00151 }
00152
00153 QSizeF QgsMapRenderer::outputSizeF()
00154 {
00155 return mSize;
00156 }
00157
00158 void QgsMapRenderer::adjustExtentToSize()
00159 {
00160 double myHeight = mSize.height();
00161 double myWidth = mSize.width();
00162
00163 QgsMapToPixel newCoordXForm;
00164
00165 if ( !myWidth || !myHeight )
00166 {
00167 mScale = 1;
00168 newCoordXForm.setParameters( 0, 0, 0, 0 );
00169 return;
00170 }
00171
00172
00173
00174 double mapUnitsPerPixelY = mExtent.height() / myHeight;
00175 double mapUnitsPerPixelX = mExtent.width() / myWidth;
00176 mMapUnitsPerPixel = mapUnitsPerPixelY > mapUnitsPerPixelX ? mapUnitsPerPixelY : mapUnitsPerPixelX;
00177
00178
00179 double dxmin, dxmax, dymin, dymax, whitespace;
00180
00181 if ( mapUnitsPerPixelY > mapUnitsPerPixelX )
00182 {
00183 dymin = mExtent.yMinimum();
00184 dymax = mExtent.yMaximum();
00185 whitespace = (( myWidth * mMapUnitsPerPixel ) - mExtent.width() ) * 0.5;
00186 dxmin = mExtent.xMinimum() - whitespace;
00187 dxmax = mExtent.xMaximum() + whitespace;
00188 }
00189 else
00190 {
00191 dxmin = mExtent.xMinimum();
00192 dxmax = mExtent.xMaximum();
00193 whitespace = (( myHeight * mMapUnitsPerPixel ) - mExtent.height() ) * 0.5;
00194 dymin = mExtent.yMinimum() - whitespace;
00195 dymax = mExtent.yMaximum() + whitespace;
00196 }
00197
00198 QgsDebugMsg( QString( "Map units per pixel (x,y) : %1, %2" ).arg( mapUnitsPerPixelX, 0, 'f', 8 ).arg( mapUnitsPerPixelY, 0, 'f', 8 ) );
00199 QgsDebugMsg( QString( "Pixmap dimensions (x,y) : %1, %2" ).arg( myWidth, 0, 'f', 8 ).arg( myHeight, 0, 'f', 8 ) );
00200 QgsDebugMsg( QString( "Extent dimensions (x,y) : %1, %2" ).arg( mExtent.width(), 0, 'f', 8 ).arg( mExtent.height(), 0, 'f', 8 ) );
00201 QgsDebugMsg( mExtent.toString() );
00202
00203
00204 mExtent.setXMinimum( dxmin );
00205 mExtent.setXMaximum( dxmax );
00206 mExtent.setYMinimum( dymin );
00207 mExtent.setYMaximum( dymax );
00208
00209
00210 updateScale();
00211
00212 QgsDebugMsg( QString( "Scale (assuming meters as map units) = 1:%1" ).arg( mScale, 0, 'f', 8 ) );
00213
00214 newCoordXForm.setParameters( mMapUnitsPerPixel, dxmin, dymin, myHeight );
00215 mRenderContext.setMapToPixel( newCoordXForm );
00216 mRenderContext.setExtent( mExtent );
00217 }
00218
00219
00220 void QgsMapRenderer::render( QPainter* painter, double* forceWidthScale )
00221 {
00222
00223 QMutexLocker renderLock( &mRenderMutex );
00224
00225
00226
00227
00228 bool mySameAsLastFlag = true;
00229
00230 QgsDebugMsg( "========== Rendering ==========" );
00231
00232 if ( mExtent.isEmpty() )
00233 {
00234 QgsDebugMsg( "empty extent... not rendering" );
00235 return;
00236 }
00237
00238 if ( mSize.width() == 1 && mSize.height() == 1 )
00239 {
00240 QgsDebugMsg( "size 1x1... not rendering" );
00241 return;
00242 }
00243
00244 QPaintDevice* thePaintDevice = painter->device();
00245 if ( !thePaintDevice )
00246 {
00247 return;
00248 }
00249
00250
00251 if ( mDrawing )
00252 {
00253 QgsDebugMsg( "already rendering" );
00254 QCoreApplication::processEvents();
00255 }
00256
00257 if ( mDrawing )
00258 {
00259 QgsDebugMsg( "still rendering - skipping" );
00260 return;
00261 }
00262
00263 mDrawing = true;
00264
00265 QgsCoordinateTransform* ct;
00266
00267 #ifdef QGISDEBUG
00268 QgsDebugMsg( "Starting to render layer stack." );
00269 QTime renderTime;
00270 renderTime.start();
00271 #endif
00272
00273 if ( mOverview )
00274 mRenderContext.setDrawEditingInformation( !mOverview );
00275
00276 mRenderContext.setPainter( painter );
00277 mRenderContext.setCoordinateTransform( 0 );
00278
00279
00280 mRenderContext.setRenderingStopped( false );
00281
00282
00283
00284
00285 double sceneDpi = mScaleCalculator->dpi();
00286 double scaleFactor = 1.0;
00287 if ( mOutputUnits == QgsMapRenderer::Millimeters )
00288 {
00289 if ( forceWidthScale )
00290 {
00291 scaleFactor = *forceWidthScale;
00292 }
00293 else
00294 {
00295 scaleFactor = sceneDpi / 25.4;
00296 }
00297 }
00298 double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi;
00299 if ( mRenderContext.rasterScaleFactor() != rasterScaleFactor )
00300 {
00301 mRenderContext.setRasterScaleFactor( rasterScaleFactor );
00302 mySameAsLastFlag = false;
00303 }
00304 if ( mRenderContext.scaleFactor() != scaleFactor )
00305 {
00306 mRenderContext.setScaleFactor( scaleFactor );
00307 mySameAsLastFlag = false;
00308 }
00309 if ( mRenderContext.rendererScale() != mScale )
00310 {
00311
00312 mRenderContext.setRendererScale( mScale );
00313 mySameAsLastFlag = false;
00314 }
00315 if ( mLastExtent != mExtent )
00316 {
00317 mLastExtent = mExtent;
00318 mySameAsLastFlag = false;
00319 }
00320
00321 mRenderContext.setLabelingEngine( mLabelingEngine );
00322 if ( mLabelingEngine )
00323 mLabelingEngine->init( this );
00324
00325
00326
00327 if ( !mySameAsLastFlag )
00328 {
00329
00330 QSettings mySettings;
00331 if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
00332 {
00333 QgsMapLayerRegistry::instance()->clearAllLayerCaches();
00334 }
00335 }
00336
00337 QgsOverlayObjectPositionManager* overlayManager = overlayManagerFromSettings();
00338 QList<QgsVectorOverlay*> allOverlayList;
00339
00340
00341 QListIterator<QString> li( mLayerSet );
00342 li.toBack();
00343
00344 QgsRectangle r1, r2;
00345
00346 while ( li.hasPrevious() )
00347 {
00348 if ( mRenderContext.renderingStopped() )
00349 {
00350 break;
00351 }
00352
00353
00354
00355 QPainter * mypContextPainter = mRenderContext.painter();
00356
00357 QString layerId = li.previous();
00358
00359 QgsDebugMsg( "Rendering at layer item " + layerId );
00360
00361
00362
00363
00364
00365
00366
00367 QgsDebugMsg( "If there is a QPaintEngine error here, it is caused by an emit call" );
00368
00369
00370 QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
00371
00372 if ( !ml )
00373 {
00374 QgsDebugMsg( "Layer not found in registry!" );
00375 continue;
00376 }
00377
00378 QgsDebugMsg( QString( "layer %1: minscale:%2 maxscale:%3 scaledepvis:%4 extent:%5" )
00379 .arg( ml->name() )
00380 .arg( ml->minimumScale() )
00381 .arg( ml->maximumScale() )
00382 .arg( ml->hasScaleBasedVisibility() )
00383 .arg( ml->extent().toString() )
00384 );
00385
00386 if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() < mScale && mScale < ml->maximumScale() ) || mOverview )
00387 {
00388 connect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
00389
00390
00391
00392
00393
00394
00395 bool split = false;
00396
00397 if ( hasCrsTransformEnabled() )
00398 {
00399 r1 = mExtent;
00400 split = splitLayersExtent( ml, r1, r2 );
00401 ct = new QgsCoordinateTransform( ml->crs(), *mDestCRS );
00402 mRenderContext.setExtent( r1 );
00403 QgsDebugMsg( " extent 1: " + r1.toString() );
00404 QgsDebugMsg( " extent 2: " + r2.toString() );
00405 if ( !r1.isFinite() || !r2.isFinite() )
00406 {
00407 continue;
00408 }
00409 }
00410 else
00411 {
00412 ct = NULL;
00413 }
00414
00415 mRenderContext.setCoordinateTransform( ct );
00416
00417
00418
00419 bool scaleRaster = false;
00420 QgsMapToPixel rasterMapToPixel;
00421 QgsMapToPixel bk_mapToPixel;
00422
00423 if ( ml->type() == QgsMapLayer::RasterLayer && qAbs( rasterScaleFactor - 1.0 ) > 0.000001 )
00424 {
00425 scaleRaster = true;
00426 }
00427
00428
00429
00430 if ( ml->type() == QgsMapLayer::VectorLayer && overlayManager )
00431 {
00432 QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
00433 if ( vl )
00434 {
00435 QList<QgsVectorOverlay*> thisLayerOverlayList;
00436 vl->vectorOverlays( thisLayerOverlayList );
00437
00438 QList<QgsVectorOverlay*>::iterator overlayIt = thisLayerOverlayList.begin();
00439 for ( ; overlayIt != thisLayerOverlayList.end(); ++overlayIt )
00440 {
00441 if (( *overlayIt )->displayFlag() )
00442 {
00443 ( *overlayIt )->createOverlayObjects( mRenderContext );
00444 allOverlayList.push_back( *overlayIt );
00445 }
00446 }
00447
00448 overlayManager->addLayer( vl, thisLayerOverlayList );
00449 }
00450 }
00451
00452
00453
00454 if ( ml->type() == QgsMapLayer::VectorLayer )
00455 {
00456 QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
00457 if ( vl->isEditable() ||
00458 ( mRenderContext.labelingEngine() && mRenderContext.labelingEngine()->willUseLayer( vl ) ) )
00459 {
00460 ml->setCacheImage( 0 );
00461 }
00462 }
00463
00464 QSettings mySettings;
00465 if ( ! split )
00466 {
00467 if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
00468 {
00469 if ( !mySameAsLastFlag || ml->cacheImage() == 0 )
00470 {
00471 QgsDebugMsg( "Caching enabled but layer redraw forced by extent change or empty cache" );
00472 QImage * mypImage = new QImage( mRenderContext.painter()->device()->width(),
00473 mRenderContext.painter()->device()->height(), QImage::Format_ARGB32 );
00474 mypImage->fill( 0 );
00475 ml->setCacheImage( mypImage );
00476 QPainter * mypPainter = new QPainter( ml->cacheImage() );
00477
00478 if ( mySettings.value( "/qgis/enable_anti_aliasing", true ).toBool() )
00479 {
00480 mypPainter->setRenderHint( QPainter::Antialiasing );
00481 }
00482 mRenderContext.setPainter( mypPainter );
00483 }
00484 else if ( mySameAsLastFlag )
00485 {
00486
00487 QgsDebugMsg( "Caching enabled --- drawing layer from cached image" );
00488 mypContextPainter->drawImage( 0, 0, *( ml->cacheImage() ) );
00489 disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
00490
00491 continue;
00492 }
00493 }
00494 }
00495
00496 if ( scaleRaster )
00497 {
00498 bk_mapToPixel = mRenderContext.mapToPixel();
00499 rasterMapToPixel = mRenderContext.mapToPixel();
00500 rasterMapToPixel.setMapUnitsPerPixel( mRenderContext.mapToPixel().mapUnitsPerPixel() / rasterScaleFactor );
00501 rasterMapToPixel.setYMaximum( mSize.height() * rasterScaleFactor );
00502 mRenderContext.setMapToPixel( rasterMapToPixel );
00503 mRenderContext.painter()->save();
00504 mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
00505 }
00506
00507
00508 if ( !ml->draw( mRenderContext ) )
00509 {
00510 emit drawError( ml );
00511 }
00512 else
00513 {
00514 QgsDebugMsg( "Layer rendered without issues" );
00515 }
00516
00517 if ( split )
00518 {
00519 mRenderContext.setExtent( r2 );
00520 if ( !ml->draw( mRenderContext ) )
00521 {
00522 emit drawError( ml );
00523 }
00524 }
00525
00526 if ( scaleRaster )
00527 {
00528 mRenderContext.setMapToPixel( bk_mapToPixel );
00529 mRenderContext.painter()->restore();
00530 }
00531
00532 if ( mySettings.value( "/qgis/enable_render_caching", false ).toBool() )
00533 {
00534 if ( !split )
00535 {
00536
00537
00538 delete mRenderContext.painter();
00539 mRenderContext.setPainter( mypContextPainter );
00540
00541 mypContextPainter->drawImage( 0, 0, *( ml->cacheImage() ) );
00542 }
00543 }
00544 disconnect( ml, SIGNAL( drawingProgress( int, int ) ), this, SLOT( onDrawingProgress( int, int ) ) );
00545 }
00546 else
00547 {
00548 QgsDebugMsg( "Layer not rendered because it is not within the defined "
00549 "visibility scale range" );
00550 }
00551
00552 }
00553
00554 QgsDebugMsg( "Done rendering map layers" );
00555
00556 if ( !mOverview )
00557 {
00558
00559 li.toBack();
00560 while ( li.hasPrevious() )
00561 {
00562 if ( mRenderContext.renderingStopped() )
00563 {
00564 break;
00565 }
00566
00567 QString layerId = li.previous();
00568
00569
00570 QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
00571
00572 if ( ml && ( ml->type() != QgsMapLayer::RasterLayer ) )
00573 {
00574
00575
00576 if ( !ml->hasScaleBasedVisibility() || ( ml->minimumScale() < mScale && mScale < ml->maximumScale() ) )
00577 {
00578 bool split = false;
00579
00580 if ( hasCrsTransformEnabled() )
00581 {
00582 QgsRectangle r1 = mExtent;
00583 split = splitLayersExtent( ml, r1, r2 );
00584 ct = new QgsCoordinateTransform( ml->crs(), *mDestCRS );
00585 mRenderContext.setExtent( r1 );
00586 }
00587 else
00588 {
00589 ct = NULL;
00590 }
00591
00592 mRenderContext.setCoordinateTransform( ct );
00593
00594 ml->drawLabels( mRenderContext );
00595 if ( split )
00596 {
00597 mRenderContext.setExtent( r2 );
00598 ml->drawLabels( mRenderContext );
00599 }
00600 }
00601 }
00602 }
00603 }
00604
00605
00606 if ( overlayManager && allOverlayList.size() > 0 )
00607 {
00608 overlayManager->findObjectPositions( mRenderContext, mScaleCalculator->mapUnits() );
00609
00610 QList<QgsVectorOverlay*>::iterator allOverlayIt = allOverlayList.begin();
00611 for ( ; allOverlayIt != allOverlayList.end(); ++allOverlayIt )
00612 {
00613 ( *allOverlayIt )->drawOverlayObjects( mRenderContext );
00614 }
00615 overlayManager->removeLayers();
00616 }
00617
00618 delete overlayManager;
00619
00620 emit drawingProgress( 1, 1 );
00621
00622 if ( mLabelingEngine )
00623 {
00624
00625 mRenderContext.setExtent( mExtent );
00626 mRenderContext.setCoordinateTransform( NULL );
00627
00628 mLabelingEngine->drawLabeling( mRenderContext );
00629 mLabelingEngine->exit();
00630 }
00631
00632 QgsDebugMsg( "Rendering completed in (seconds): " + QString( "%1" ).arg( renderTime.elapsed() / 1000.0 ) );
00633
00634 mDrawing = false;
00635 }
00636
00637 void QgsMapRenderer::setMapUnits( QGis::UnitType u )
00638 {
00639 mScaleCalculator->setMapUnits( u );
00640
00641
00642 updateScale();
00643
00644 emit mapUnitsChanged();
00645 }
00646
00647 QGis::UnitType QgsMapRenderer::mapUnits() const
00648 {
00649 return mScaleCalculator->mapUnits();
00650 }
00651
00652 void QgsMapRenderer::onDrawingProgress( int current, int total )
00653 {
00654 Q_UNUSED( current );
00655 Q_UNUSED( total );
00656
00657
00658 emit updateMap();
00659 }
00660
00661 void QgsMapRenderer::setProjectionsEnabled( bool enabled )
00662 {
00663 if ( mProjectionsEnabled != enabled )
00664 {
00665 mProjectionsEnabled = enabled;
00666 QgsDebugMsg( "Adjusting DistArea projection on/off" );
00667 mDistArea->setProjectionsEnabled( enabled );
00668 updateFullExtent();
00669 mLastExtent.setMinimal();
00670 emit hasCrsTransformEnabled( enabled );
00671 }
00672 }
00673
00674 bool QgsMapRenderer::hasCrsTransformEnabled()
00675 {
00676 return mProjectionsEnabled;
00677 }
00678
00679 void QgsMapRenderer::setDestinationCrs( const QgsCoordinateReferenceSystem& crs )
00680 {
00681 QgsDebugMsg( "* Setting destCRS : = " + crs.toProj4() );
00682 QgsDebugMsg( "* DestCRS.srsid() = " + QString::number( crs.srsid() ) );
00683 if ( *mDestCRS != crs )
00684 {
00685 QgsRectangle rect;
00686 if ( !mExtent.isEmpty() )
00687 {
00688 QgsCoordinateTransform transform( *mDestCRS, crs );
00689 rect = transform.transformBoundingBox( mExtent );
00690 }
00691
00692 invalidateCachedLayerCrs();
00693 QgsDebugMsg( "Setting DistArea CRS to " + QString::number( crs.srsid() ) );
00694 mDistArea->setSourceCrs( crs.srsid() );
00695 *mDestCRS = crs;
00696 updateFullExtent();
00697
00698 if ( !rect.isEmpty() )
00699 {
00700 setExtent( rect );
00701 }
00702
00703 emit destinationSrsChanged();
00704 }
00705 }
00706
00707 const QgsCoordinateReferenceSystem& QgsMapRenderer::destinationCrs()
00708 {
00709 QgsDebugMsgLevel( "* Returning destCRS", 3 );
00710 QgsDebugMsgLevel( "* DestCRS.srsid() = " + QString::number( mDestCRS->srsid() ), 3 );
00711 QgsDebugMsgLevel( "* DestCRS.proj4() = " + mDestCRS->toProj4(), 3 );
00712 return *mDestCRS;
00713 }
00714
00715
00716 bool QgsMapRenderer::splitLayersExtent( QgsMapLayer* layer, QgsRectangle& extent, QgsRectangle& r2 )
00717 {
00718 bool split = false;
00719
00720 if ( hasCrsTransformEnabled() )
00721 {
00722 try
00723 {
00724 #ifdef QGISDEBUG
00725
00726 #endif
00727
00728
00729
00730
00731
00732 static const double splitCoord = 180.0;
00733
00734 if ( mCachedTr->sourceCrs().geographicFlag() )
00735 {
00736
00737
00738 QgsPoint ll = tr( layer )->transform( extent.xMinimum(), extent.yMinimum(),
00739 QgsCoordinateTransform::ReverseTransform );
00740
00741 QgsPoint ur = tr( layer )->transform( extent.xMaximum(), extent.yMaximum(),
00742 QgsCoordinateTransform::ReverseTransform );
00743
00744 extent = tr( layer )->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
00745
00746 if ( ll.x() > ur.x() )
00747 {
00748 r2 = extent;
00749 extent.setXMinimum( splitCoord );
00750 r2.setXMaximum( splitCoord );
00751 split = true;
00752 }
00753 }
00754 else
00755 {
00756 extent = tr( layer )->transformBoundingBox( extent, QgsCoordinateTransform::ReverseTransform );
00757 }
00758 }
00759 catch ( QgsCsException &cse )
00760 {
00761 Q_UNUSED( cse );
00762 QgsDebugMsg( "Transform error caught" );
00763 extent = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
00764 r2 = QgsRectangle( -DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX );
00765 }
00766 }
00767 return split;
00768 }
00769
00770
00771 QgsRectangle QgsMapRenderer::layerExtentToOutputExtent( QgsMapLayer* theLayer, QgsRectangle extent )
00772 {
00773 QgsDebugMsg( QString( "sourceCrs = " + tr( theLayer )->sourceCrs().authid() ) );
00774 QgsDebugMsg( QString( "destCRS = " + tr( theLayer )->destCRS().authid() ) );
00775 QgsDebugMsg( QString( "extent = " + extent.toString() ) );
00776 if ( hasCrsTransformEnabled() )
00777 {
00778 try
00779 {
00780 extent = tr( theLayer )->transformBoundingBox( extent );
00781 }
00782 catch ( QgsCsException &cse )
00783 {
00784 QgsMessageLog::logMessage( tr( "Transform error caught: %1" ).arg( cse.what() ), tr( "CRS" ) );
00785 }
00786 }
00787
00788 QgsDebugMsg( QString( "proj extent = " + extent.toString() ) );
00789
00790 return extent;
00791 }
00792
00793 QgsPoint QgsMapRenderer::layerToMapCoordinates( QgsMapLayer* theLayer, QgsPoint point )
00794 {
00795 if ( hasCrsTransformEnabled() )
00796 {
00797 try
00798 {
00799 point = tr( theLayer )->transform( point, QgsCoordinateTransform::ForwardTransform );
00800 }
00801 catch ( QgsCsException &cse )
00802 {
00803 Q_UNUSED( cse );
00804 QgsDebugMsg( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00805 }
00806 }
00807 else
00808 {
00809
00810 }
00811 return point;
00812 }
00813
00814 QgsPoint QgsMapRenderer::mapToLayerCoordinates( QgsMapLayer* theLayer, QgsPoint point )
00815 {
00816 if ( hasCrsTransformEnabled() )
00817 {
00818 try
00819 {
00820 point = tr( theLayer )->transform( point, QgsCoordinateTransform::ReverseTransform );
00821 }
00822 catch ( QgsCsException &cse )
00823 {
00824 QgsDebugMsg( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00825 throw cse;
00826 }
00827 }
00828 else
00829 {
00830
00831 }
00832 return point;
00833 }
00834
00835 QgsRectangle QgsMapRenderer::mapToLayerCoordinates( QgsMapLayer* theLayer, QgsRectangle rect )
00836 {
00837 if ( hasCrsTransformEnabled() )
00838 {
00839 try
00840 {
00841 rect = tr( theLayer )->transform( rect, QgsCoordinateTransform::ReverseTransform );
00842 }
00843 catch ( QgsCsException &cse )
00844 {
00845 QgsDebugMsg( QString( "Transform error caught: %1" ).arg( cse.what() ) );
00846 throw cse;
00847 }
00848 }
00849 return rect;
00850 }
00851
00852
00853 void QgsMapRenderer::updateFullExtent()
00854 {
00855 QgsDebugMsg( "called." );
00856 QgsMapLayerRegistry* registry = QgsMapLayerRegistry::instance();
00857
00858
00859
00860 mFullExtent.setMinimal();
00861
00862
00863
00864 QStringList::iterator it = mLayerSet.begin();
00865 QgsDebugMsg( QString( "Layer count: %1" ).arg( mLayerSet.count() ) );
00866 while ( it != mLayerSet.end() )
00867 {
00868 QgsMapLayer * lyr = registry->mapLayer( *it );
00869 if ( lyr == NULL )
00870 {
00871 QgsDebugMsg( QString( "WARNING: layer '%1' not found in map layer registry!" ).arg( *it ) );
00872 }
00873 else
00874 {
00875 QgsDebugMsg( "Updating extent using " + lyr->name() );
00876 QgsDebugMsg( "Input extent: " + lyr->extent().toString() );
00877
00878
00879
00880 QgsRectangle extent = layerExtentToOutputExtent( lyr, lyr->extent() );
00881
00882 QgsDebugMsg( "Output extent: " + extent.toString() );
00883 mFullExtent.unionRect( extent );
00884
00885 }
00886 it++;
00887 }
00888
00889 if ( mFullExtent.width() == 0.0 || mFullExtent.height() == 0.0 )
00890 {
00891
00892
00893
00894
00895 if ( mFullExtent.xMinimum() == 0.0 && mFullExtent.xMaximum() == 0.0 &&
00896 mFullExtent.yMinimum() == 0.0 && mFullExtent.yMaximum() == 0.0 )
00897 {
00898 mFullExtent.set( -1.0, -1.0, 1.0, 1.0 );
00899 }
00900 else
00901 {
00902 const double padFactor = 1e-8;
00903 double widthPad = mFullExtent.xMinimum() * padFactor;
00904 double heightPad = mFullExtent.yMinimum() * padFactor;
00905 double xmin = mFullExtent.xMinimum() - widthPad;
00906 double xmax = mFullExtent.xMaximum() + widthPad;
00907 double ymin = mFullExtent.yMinimum() - heightPad;
00908 double ymax = mFullExtent.yMaximum() + heightPad;
00909 mFullExtent.set( xmin, ymin, xmax, ymax );
00910 }
00911 }
00912
00913 QgsDebugMsg( "Full extent: " + mFullExtent.toString() );
00914 }
00915
00916 QgsRectangle QgsMapRenderer::fullExtent()
00917 {
00918 updateFullExtent();
00919 return mFullExtent;
00920 }
00921
00922 void QgsMapRenderer::setLayerSet( const QStringList& layers )
00923 {
00924 QgsDebugMsg( QString( "Entering: %1" ).arg( layers.join( ", " ) ) );
00925 mLayerSet = layers;
00926 updateFullExtent();
00927 }
00928
00929 QStringList& QgsMapRenderer::layerSet()
00930 {
00931 return mLayerSet;
00932 }
00933
00934 QgsOverlayObjectPositionManager* QgsMapRenderer::overlayManagerFromSettings()
00935 {
00936 QSettings settings;
00937 QString overlayAlgorithmQString = settings.value( "qgis/overlayPlacementAlgorithm", "Central point" ).toString();
00938
00939 QgsOverlayObjectPositionManager* result = 0;
00940
00941 if ( overlayAlgorithmQString != "Central point" )
00942 {
00943 QgsPALObjectPositionManager* palManager = new QgsPALObjectPositionManager();
00944 if ( overlayAlgorithmQString == "Chain" )
00945 {
00946 palManager->setPlacementAlgorithm( "Chain" );
00947 }
00948 else if ( overlayAlgorithmQString == "Popmusic tabu chain" )
00949 {
00950 palManager->setPlacementAlgorithm( "Popmusic tabu chain" );
00951 }
00952 else if ( overlayAlgorithmQString == "Popmusic tabu" )
00953 {
00954 palManager->setPlacementAlgorithm( "Popmusic tabu" );
00955 }
00956 else if ( overlayAlgorithmQString == "Popmusic chain" )
00957 {
00958 palManager->setPlacementAlgorithm( "Popmusic chain" );
00959 }
00960 result = palManager;
00961 }
00962 else
00963 {
00964 result = new QgsCentralPointPositionManager();
00965 }
00966
00967 return result;
00968 }
00969
00970 bool QgsMapRenderer::readXML( QDomNode & theNode )
00971 {
00972 QDomNode myNode = theNode.namedItem( "units" );
00973 QDomElement element = myNode.toElement();
00974
00975
00976 QGis::UnitType units;
00977 if ( "meters" == element.text() )
00978 {
00979 units = QGis::Meters;
00980 }
00981 else if ( "feet" == element.text() )
00982 {
00983 units = QGis::Feet;
00984 }
00985 else if ( "degrees" == element.text() )
00986 {
00987 units = QGis::Degrees;
00988 }
00989 else if ( "unknown" == element.text() )
00990 {
00991 units = QGis::UnknownUnit;
00992 }
00993 else
00994 {
00995 QgsDebugMsg( "Unknown map unit type " + element.text() );
00996 units = QGis::Degrees;
00997 }
00998 setMapUnits( units );
00999
01000
01001 QDomNode projNode = theNode.namedItem( "projections" );
01002 element = projNode.toElement();
01003 setProjectionsEnabled( element.text().toInt() );
01004
01005
01006 QgsCoordinateReferenceSystem srs;
01007 QDomNode srsNode = theNode.namedItem( "destinationsrs" );
01008 srs.readXML( srsNode );
01009 setDestinationCrs( srs );
01010
01011
01012 QgsRectangle aoi;
01013 QDomNode extentNode = theNode.namedItem( "extent" );
01014
01015 QDomNode xminNode = extentNode.namedItem( "xmin" );
01016 QDomNode yminNode = extentNode.namedItem( "ymin" );
01017 QDomNode xmaxNode = extentNode.namedItem( "xmax" );
01018 QDomNode ymaxNode = extentNode.namedItem( "ymax" );
01019
01020 QDomElement exElement = xminNode.toElement();
01021 double xmin = exElement.text().toDouble();
01022 aoi.setXMinimum( xmin );
01023
01024 exElement = yminNode.toElement();
01025 double ymin = exElement.text().toDouble();
01026 aoi.setYMinimum( ymin );
01027
01028 exElement = xmaxNode.toElement();
01029 double xmax = exElement.text().toDouble();
01030 aoi.setXMaximum( xmax );
01031
01032 exElement = ymaxNode.toElement();
01033 double ymax = exElement.text().toDouble();
01034 aoi.setYMaximum( ymax );
01035
01036 setExtent( aoi );
01037 return true;
01038 }
01039
01040 bool QgsMapRenderer::writeXML( QDomNode & theNode, QDomDocument & theDoc )
01041 {
01042
01043
01044 QDomElement unitsNode = theDoc.createElement( "units" );
01045 theNode.appendChild( unitsNode );
01046
01047 QString unitsString;
01048
01049 switch ( mapUnits() )
01050 {
01051 case QGis::Meters:
01052 unitsString = "meters";
01053 break;
01054 case QGis::Feet:
01055 unitsString = "feet";
01056 break;
01057 case QGis::Degrees:
01058 unitsString = "degrees";
01059 break;
01060 case QGis::UnknownUnit:
01061 default:
01062 unitsString = "unknown";
01063 break;
01064 }
01065 QDomText unitsText = theDoc.createTextNode( unitsString );
01066 unitsNode.appendChild( unitsText );
01067
01068
01069
01070 QDomElement extentNode = theDoc.createElement( "extent" );
01071 theNode.appendChild( extentNode );
01072
01073 QDomElement xMin = theDoc.createElement( "xmin" );
01074 QDomElement yMin = theDoc.createElement( "ymin" );
01075 QDomElement xMax = theDoc.createElement( "xmax" );
01076 QDomElement yMax = theDoc.createElement( "ymax" );
01077
01078 QgsRectangle r = extent();
01079 QDomText xMinText = theDoc.createTextNode( QString::number( r.xMinimum(), 'f' ) );
01080 QDomText yMinText = theDoc.createTextNode( QString::number( r.yMinimum(), 'f' ) );
01081 QDomText xMaxText = theDoc.createTextNode( QString::number( r.xMaximum(), 'f' ) );
01082 QDomText yMaxText = theDoc.createTextNode( QString::number( r.yMaximum(), 'f' ) );
01083
01084 xMin.appendChild( xMinText );
01085 yMin.appendChild( yMinText );
01086 xMax.appendChild( xMaxText );
01087 yMax.appendChild( yMaxText );
01088
01089 extentNode.appendChild( xMin );
01090 extentNode.appendChild( yMin );
01091 extentNode.appendChild( xMax );
01092 extentNode.appendChild( yMax );
01093
01094
01095 QDomElement projNode = theDoc.createElement( "projections" );
01096 theNode.appendChild( projNode );
01097
01098 QDomText projText = theDoc.createTextNode( QString::number( hasCrsTransformEnabled() ) );
01099 projNode.appendChild( projText );
01100
01101
01102 QDomElement srsNode = theDoc.createElement( "destinationsrs" );
01103 theNode.appendChild( srsNode );
01104 destinationCrs().writeXML( srsNode, theDoc );
01105
01106 return true;
01107 }
01108
01109 void QgsMapRenderer::setLabelingEngine( QgsLabelingEngineInterface* iface )
01110 {
01111 if ( mLabelingEngine )
01112 delete mLabelingEngine;
01113
01114 mLabelingEngine = iface;
01115 }
01116
01117 QgsCoordinateTransform *QgsMapRenderer::tr( QgsMapLayer *layer )
01118 {
01119 if ( mCachedTrForLayer != layer )
01120 {
01121 invalidateCachedLayerCrs();
01122
01123 delete mCachedTr;
01124 mCachedTr = new QgsCoordinateTransform( layer->crs(), *mDestCRS );
01125 mCachedTrForLayer = layer;
01126
01127 connect( layer, SIGNAL( layerCrsChanged() ), this, SLOT( invalidateCachedLayerCrs() ) );
01128 connect( layer, SIGNAL( destroyed() ), this, SLOT( cachedLayerDestroyed() ) );
01129 }
01130
01131 return mCachedTr;
01132 }
01133
01134 void QgsMapRenderer::cachedLayerDestroyed()
01135 {
01136 if ( mCachedTrForLayer == sender() )
01137 mCachedTrForLayer = 0;
01138 }
01139
01140 void QgsMapRenderer::invalidateCachedLayerCrs()
01141 {
01142 if ( mCachedTrForLayer )
01143 disconnect( mCachedTrForLayer, SIGNAL( layerCrsChanged() ), this, SLOT( invalidateCachedLayerCrs() ) );
01144
01145 mCachedTrForLayer = 0;
01146 }
01147
01148 bool QgsMapRenderer::mDrawing = false;