00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "qgscomposermap.h"
00019
00020 #include "qgscoordinatetransform.h"
00021 #include "qgslogger.h"
00022 #include "qgsmaprenderer.h"
00023 #include "qgsmaplayer.h"
00024 #include "qgsmaplayerregistry.h"
00025 #include "qgsmaptopixel.h"
00026 #include "qgsproject.h"
00027 #include "qgsmaprenderer.h"
00028 #include "qgsrasterlayer.h"
00029 #include "qgsrendercontext.h"
00030 #include "qgsscalecalculator.h"
00031 #include "qgsvectorlayer.h"
00032
00033 #include "qgslabel.h"
00034 #include "qgslabelattributes.h"
00035
00036 #include <QGraphicsScene>
00037 #include <QGraphicsView>
00038 #include <QPainter>
00039 #include <QSettings>
00040 #include <iostream>
00041 #include <cmath>
00042
00043 QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height )
00044 : QgsComposerItem( x, y, width, height, composition ), mKeepLayerSet( false ), mGridEnabled( false ), mGridStyle( Solid ), \
00045 mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), \
00046 mGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), mGridAnnotationDirection( Horizontal ), mCrossLength( 3 ), mMapCanvas( 0 )
00047 {
00048 mComposition = composition;
00049 mId = mComposition->composerMapItems().size();
00050 mMapRenderer = mComposition->mapRenderer();
00051 mPreviewMode = QgsComposerMap::Rectangle;
00052 mCurrentRectangle = rect();
00053
00054
00055 mCacheUpdated = false;
00056 mDrawing = false;
00057
00058
00059 mXOffset = 0.0;
00060 mYOffset = 0.0;
00061
00062 connectUpdateSlot();
00063
00064
00065 if ( mMapRenderer )
00066 {
00067 mExtent = mMapRenderer->extent();
00068 }
00069 setSceneRect( QRectF( x, y, width, height ) );
00070 setToolTip( tr( "Map %1" ).arg( mId ) );
00071 mGridPen.setCapStyle( Qt::FlatCap );
00072 }
00073
00074 QgsComposerMap::QgsComposerMap( QgsComposition *composition )
00075 : QgsComposerItem( 0, 0, 10, 10, composition ), mKeepLayerSet( false ), mGridEnabled( false ), mGridStyle( Solid ), \
00076 mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationPrecision( 3 ), mShowGridAnnotation( false ), \
00077 mGridAnnotationPosition( OutsideMapFrame ), mAnnotationFrameDistance( 1.0 ), mGridAnnotationDirection( Horizontal ), mCrossLength( 3 ), mMapCanvas( 0 )
00078 {
00079
00080 mXOffset = 0.0;
00081 mYOffset = 0.0;
00082
00083 connectUpdateSlot();
00084
00085 mComposition = composition;
00086 mMapRenderer = mComposition->mapRenderer();
00087 mId = mComposition->composerMapItems().size();
00088 mPreviewMode = QgsComposerMap::Rectangle;
00089 mCurrentRectangle = rect();
00090
00091 setToolTip( tr( "Map %1" ).arg( mId ) );
00092 mGridPen.setCapStyle( Qt::FlatCap );
00093 }
00094
00095 QgsComposerMap::~QgsComposerMap()
00096 {
00097 }
00098
00099 void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const QSize& size, int dpi )
00100 {
00101 draw( painter, extent, QSizeF( size.width(), size.height() ), dpi );
00102 }
00103
00104
00105
00106 void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const QSizeF& size, double dpi )
00107 {
00108 if ( !painter )
00109 {
00110 return;
00111 }
00112
00113 if ( !mMapRenderer )
00114 {
00115 return;
00116 }
00117
00118 QgsMapRenderer theMapRenderer;
00119 theMapRenderer.setExtent( extent );
00120 theMapRenderer.setOutputSize( size, dpi );
00121 if ( mMapRenderer->labelingEngine() )
00122 theMapRenderer.setLabelingEngine( mMapRenderer->labelingEngine()->clone() );
00123
00124
00125 if ( mKeepLayerSet )
00126 {
00127 theMapRenderer.setLayerSet( mLayerSet );
00128 }
00129 else
00130 {
00131 theMapRenderer.setLayerSet( mMapRenderer->layerSet() );
00132 }
00133 theMapRenderer.setProjectionsEnabled( mMapRenderer->hasCrsTransformEnabled() );
00134 theMapRenderer.setDestinationSrs( mMapRenderer->destinationSrs() );
00135
00136
00137 QSettings settings;
00138 if ( settings.value( "/qgis/enable_anti_aliasing", false ).toBool() )
00139 {
00140 painter->setRenderHint( QPainter::Antialiasing );
00141 }
00142
00143 QgsRenderContext* theRendererContext = theMapRenderer.rendererContext();
00144 if ( theRendererContext )
00145 {
00146 theRendererContext->setDrawEditingInformation( false );
00147 theRendererContext->setRenderingStopped( false );
00148 }
00149
00150
00151 theRendererContext->setForceVectorOutput( true );
00152
00153
00154 double bk_scale = theMapRenderer.scale();
00155 theMapRenderer.setScale( scale() );
00156
00157
00158 QSettings s;
00159 bool bkLayerCaching = s.value( "/qgis/enable_render_caching", false ).toBool();
00160 s.setValue( "/qgis/enable_render_caching", false );
00161
00162 theMapRenderer.render( painter );
00163 s.setValue( "/qgis/enable_render_caching", bkLayerCaching );
00164
00165 theMapRenderer.setScale( bk_scale );
00166 }
00167
00168 void QgsComposerMap::cache( void )
00169 {
00170 if ( mPreviewMode == Rectangle )
00171 {
00172 return;
00173 }
00174
00175 if ( mDrawing )
00176 {
00177 return;
00178 }
00179
00180 mDrawing = true;
00181
00182
00183 QgsRectangle requestExtent;
00184 requestedExtent( requestExtent );
00185
00186 double horizontalVScaleFactor = horizontalViewScaleFactor();
00187 if ( horizontalVScaleFactor < 0 )
00188 {
00189 horizontalVScaleFactor = mLastValidViewScaleFactor;
00190 }
00191
00192 int w = requestExtent.width() * mapUnitsToMM() * horizontalVScaleFactor;
00193 int h = requestExtent.height() * mapUnitsToMM() * horizontalVScaleFactor;
00194
00195 if ( w > 5000 )
00196 {
00197 w = 5000;
00198 }
00199
00200 if ( h > 5000 )
00201 {
00202 h = 5000;
00203 }
00204
00205 mCacheImage = QImage( w, h, QImage::Format_ARGB32 );
00206 mCacheImage.fill( brush().color().rgb() );
00207 double mapUnitsPerPixel = mExtent.width() / w;
00208
00209
00210 QgsMapToPixel transform( mapUnitsPerPixel, h, requestExtent.yMinimum(), requestExtent.xMinimum() );
00211
00212 QPainter p( &mCacheImage );
00213
00214 draw( &p, requestExtent, QSizeF( w, h ), mCacheImage.logicalDpiX() );
00215 p.end();
00216 mCacheUpdated = true;
00217
00218 mDrawing = false;
00219 }
00220
00221 void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
00222 {
00223 if ( !mComposition || !painter )
00224 {
00225 return;
00226 }
00227
00228 QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
00229 painter->save();
00230 painter->setClipRect( thisPaintRect );
00231
00232 drawBackground( painter );
00233
00234 if ( mComposition->plotStyle() == QgsComposition::Preview && mPreviewMode == Rectangle )
00235 {
00236 QFont messageFont( "", 12 );
00237 painter->setFont( messageFont );
00238 painter->setPen( QColor( 0, 0, 0 ) );
00239 painter->drawText( thisPaintRect, tr( "Map will be printed here" ) );
00240 }
00241 else if ( mComposition->plotStyle() == QgsComposition::Preview )
00242 {
00243
00244
00245
00246
00247
00248 QgsRectangle requestRectangle;
00249 requestedExtent( requestRectangle );
00250 double horizontalVScaleFactor = horizontalViewScaleFactor();
00251 if ( horizontalVScaleFactor < 0 )
00252 {
00253 horizontalVScaleFactor = mLastValidViewScaleFactor;
00254 }
00255
00256 double imagePixelWidth = mExtent.width() / requestRectangle.width() * mCacheImage.width() ;
00257 double scale = rect().width() / imagePixelWidth;
00258 QgsPoint rotationPoint = QgsPoint(( mExtent.xMaximum() + mExtent.xMinimum() ) / 2.0, ( mExtent.yMaximum() + mExtent.yMinimum() ) / 2.0 );
00259
00260
00261 double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
00262 double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
00263
00264
00265 double xTopLeftShift = ( rotationPoint.x() - mExtent.xMinimum() ) * mapUnitsToMM();
00266 double yTopLeftShift = ( mExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
00267
00268 painter->save();
00269
00270 painter->translate( mXOffset, mYOffset );
00271 painter->translate( xTopLeftShift, yTopLeftShift );
00272 painter->rotate( mRotation );
00273 painter->translate( xShiftMM, -yShiftMM );
00274 painter->scale( scale, scale );
00275 painter->drawImage( 0, 0, mCacheImage );
00276
00277
00278 painter->restore();
00279
00280
00281 drawCanvasItems( painter, itemStyle );
00282 }
00283 else if ( mComposition->plotStyle() == QgsComposition::Print ||
00284 mComposition->plotStyle() == QgsComposition::Postscript )
00285 {
00286 if ( mDrawing )
00287 {
00288 return;
00289 }
00290
00291 mDrawing = true;
00292 QPaintDevice* thePaintDevice = painter->device();
00293 if ( !thePaintDevice )
00294 {
00295 return;
00296 }
00297
00298 QgsRectangle requestRectangle;
00299 requestedExtent( requestRectangle );
00300
00301 QSizeF theSize( requestRectangle.width() * mapUnitsToMM(), requestRectangle.height() * mapUnitsToMM() );
00302 QgsPoint rotationPoint = QgsPoint(( mExtent.xMaximum() + mExtent.xMinimum() ) / 2.0, ( mExtent.yMaximum() + mExtent.yMinimum() ) / 2.0 );
00303
00304
00305 double yShiftMM = ( requestRectangle.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
00306 double xShiftMM = ( requestRectangle.xMinimum() - rotationPoint.x() ) * mapUnitsToMM();
00307
00308
00309 double xTopLeftShift = ( rotationPoint.x() - mExtent.xMinimum() ) * mapUnitsToMM();
00310 double yTopLeftShift = ( mExtent.yMaximum() - rotationPoint.y() ) * mapUnitsToMM();
00311 painter->save();
00312 painter->translate( mXOffset, mYOffset );
00313 painter->translate( xTopLeftShift, yTopLeftShift );
00314 painter->rotate( mRotation );
00315 painter->translate( xShiftMM, -yShiftMM );
00316 draw( painter, requestRectangle, theSize, 25.4 );
00317
00318
00319 painter->restore();
00320
00321
00322 drawCanvasItems( painter, itemStyle );
00323
00324 mDrawing = false;
00325 }
00326
00327 painter->setClipRect( thisPaintRect , Qt::NoClip );
00328
00329 if ( mGridEnabled )
00330 {
00331 drawGrid( painter );
00332 }
00333 drawFrame( painter );
00334 if ( isSelected() )
00335 {
00336 drawSelectionBoxes( painter );
00337 }
00338
00339
00340 painter->restore();
00341 }
00342
00343 void QgsComposerMap::updateCachedImage( void )
00344 {
00345 syncLayerSet();
00346 mCacheUpdated = false;
00347 cache();
00348 QGraphicsRectItem::update();
00349 }
00350
00351 void QgsComposerMap::renderModeUpdateCachedImage()
00352 {
00353 if ( mPreviewMode == Render )
00354 {
00355 updateCachedImage();
00356 }
00357 }
00358
00359 void QgsComposerMap::setCacheUpdated( bool u )
00360 {
00361 mCacheUpdated = u;
00362 }
00363
00364 double QgsComposerMap::scale() const
00365 {
00366 QgsScaleCalculator calculator;
00367 calculator.setMapUnits( mMapRenderer->mapUnits() );
00368 calculator.setDpi( 25.4 );
00369 return calculator.calculate( mExtent, rect().width() );
00370 }
00371
00372 void QgsComposerMap::resize( double dx, double dy )
00373 {
00374
00375 QRectF currentRect = rect();
00376 QRectF newSceneRect = QRectF( transform().dx(), transform().dy(), currentRect.width() + dx, currentRect.height() + dy );
00377 setSceneRect( newSceneRect );
00378 }
00379
00380 void QgsComposerMap::moveContent( double dx, double dy )
00381 {
00382 if ( !mDrawing )
00383 {
00384 transformShift( dx, dy );
00385 mExtent.setXMinimum( mExtent.xMinimum() + dx );
00386 mExtent.setXMaximum( mExtent.xMaximum() + dx );
00387 mExtent.setYMinimum( mExtent.yMinimum() + dy );
00388 mExtent.setYMaximum( mExtent.yMaximum() + dy );
00389 cache();
00390 update();
00391 emit extentChanged();
00392 }
00393 }
00394
00395 void QgsComposerMap::zoomContent( int delta, double x, double y )
00396 {
00397 if ( mDrawing )
00398 {
00399 return;
00400 }
00401
00402 QSettings settings;
00403
00404
00405
00406 int zoomMode = settings.value( "/qgis/wheel_action", 0 ).toInt();
00407 if ( zoomMode == 3 )
00408 {
00409 return;
00410 }
00411
00412 double zoomFactor = settings.value( "/qgis/zoom_factor", 2.0 ).toDouble();
00413
00414
00415 double centerX = ( mExtent.xMaximum() + mExtent.xMinimum() ) / 2;
00416 double centerY = ( mExtent.yMaximum() + mExtent.yMinimum() ) / 2;
00417
00418 if ( zoomMode != 0 )
00419 {
00420
00421 double mapMouseX = mExtent.xMinimum() + ( x / rect().width() ) * ( mExtent.xMaximum() - mExtent.xMinimum() );
00422 double mapMouseY = mExtent.yMinimum() + ( 1 - ( y / rect().height() ) ) * ( mExtent.yMaximum() - mExtent.yMinimum() );
00423 if ( zoomMode == 1 )
00424 {
00425 centerX = mapMouseX;
00426 centerY = mapMouseY;
00427 }
00428 else if ( zoomMode == 2 )
00429 {
00430 centerX = mapMouseX + ( centerX - mapMouseX ) * ( 1.0 / zoomFactor );
00431 centerY = mapMouseY + ( centerY - mapMouseY ) * ( 1.0 / zoomFactor );
00432 }
00433 }
00434
00435 double newIntervalX, newIntervalY;
00436
00437 if ( delta > 0 )
00438 {
00439 newIntervalX = ( mExtent.xMaximum() - mExtent.xMinimum() ) / zoomFactor;
00440 newIntervalY = ( mExtent.yMaximum() - mExtent.yMinimum() ) / zoomFactor;
00441 }
00442 else if ( delta < 0 )
00443 {
00444 newIntervalX = ( mExtent.xMaximum() - mExtent.xMinimum() ) * zoomFactor;
00445 newIntervalY = ( mExtent.yMaximum() - mExtent.yMinimum() ) * zoomFactor;
00446 }
00447 else
00448 {
00449 return;
00450 }
00451
00452 mExtent.setXMaximum( centerX + newIntervalX / 2 );
00453 mExtent.setXMinimum( centerX - newIntervalX / 2 );
00454 mExtent.setYMaximum( centerY + newIntervalY / 2 );
00455 mExtent.setYMinimum( centerY - newIntervalY / 2 );
00456
00457 cache();
00458 update();
00459 emit extentChanged();
00460 }
00461
00462 void QgsComposerMap::setSceneRect( const QRectF& rectangle )
00463 {
00464 double w = rectangle.width();
00465 double h = rectangle.height();
00466
00467
00468 QgsComposerItem::setSceneRect( rectangle );
00469
00470
00471 double newHeight = mExtent.width() * h / w ;
00472 mExtent = QgsRectangle( mExtent.xMinimum(), mExtent.yMinimum(), mExtent.xMaximum(), mExtent.yMinimum() + newHeight );
00473 mCacheUpdated = false;
00474
00475 if ( mPreviewMode != Rectangle )
00476 {
00477 cache();
00478 }
00479 updateBoundingRect();
00480 update();
00481 emit extentChanged();
00482 }
00483
00484 void QgsComposerMap::setNewExtent( const QgsRectangle& extent )
00485 {
00486 if ( mExtent == extent )
00487 {
00488 return;
00489 }
00490 mExtent = extent;
00491
00492
00493 QRectF currentRect = rect();
00494
00495 double newHeight = currentRect.width() * extent.height() / extent.width();
00496
00497 setSceneRect( QRectF( transform().dx(), transform().dy(), currentRect.width(), newHeight ) );
00498 }
00499
00500 void QgsComposerMap::setNewScale( double scaleDenominator )
00501 {
00502 double currentScaleDenominator = scale();
00503
00504 if ( scaleDenominator == currentScaleDenominator )
00505 {
00506 return;
00507 }
00508
00509 double scaleRatio = scaleDenominator / currentScaleDenominator;
00510 mExtent.scale( scaleRatio );
00511 mCacheUpdated = false;
00512 cache();
00513 update();
00514 emit extentChanged();
00515 }
00516
00517 void QgsComposerMap::setOffset( double xOffset, double yOffset )
00518 {
00519 mXOffset = xOffset;
00520 mYOffset = yOffset;
00521 }
00522
00523 void QgsComposerMap::setMapRotation( double r )
00524 {
00525 setRotation( r );
00526 emit rotationChanged( r );
00527 }
00528
00529 bool QgsComposerMap::containsWMSLayer() const
00530 {
00531 if ( !mMapRenderer )
00532 {
00533 return false;
00534 }
00535
00536 QStringList layers = mMapRenderer->layerSet();
00537
00538 QStringList::const_iterator layer_it = layers.constBegin();
00539 QgsMapLayer* currentLayer = 0;
00540
00541 for ( ; layer_it != layers.constEnd(); ++layer_it )
00542 {
00543 currentLayer = QgsMapLayerRegistry::instance()->mapLayer( *layer_it );
00544 if ( currentLayer )
00545 {
00546 QgsRasterLayer* currentRasterLayer = qobject_cast<QgsRasterLayer *>( currentLayer );
00547 if ( currentRasterLayer )
00548 {
00549 const QgsRasterDataProvider* rasterProvider = 0;
00550 if (( rasterProvider = currentRasterLayer->dataProvider() ) )
00551 {
00552 if ( rasterProvider->name() == "wms" )
00553 {
00554 return true;
00555 }
00556 }
00557 }
00558 }
00559 }
00560 return false;
00561 }
00562
00563 void QgsComposerMap::connectUpdateSlot()
00564 {
00565
00566 QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance();
00567 if ( layerRegistry )
00568 {
00569 connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( updateCachedImage() ) );
00570 connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( updateCachedImage() ) );
00571 }
00572 }
00573
00574 bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const
00575 {
00576 if ( elem.isNull() )
00577 {
00578 return false;
00579 }
00580
00581 QDomElement composerMapElem = doc.createElement( "ComposerMap" );
00582 composerMapElem.setAttribute( "id", mId );
00583
00584
00585 if ( mPreviewMode == Cache )
00586 {
00587 composerMapElem.setAttribute( "previewMode", "Cache" );
00588 }
00589 else if ( mPreviewMode == Render )
00590 {
00591 composerMapElem.setAttribute( "previewMode", "Render" );
00592 }
00593 else
00594 {
00595 composerMapElem.setAttribute( "previewMode", "Rectangle" );
00596 }
00597
00598 if ( mKeepLayerSet )
00599 {
00600 composerMapElem.setAttribute( "keepLayerSet", "true" );
00601 }
00602 else
00603 {
00604 composerMapElem.setAttribute( "keepLayerSet", "false" );
00605 }
00606
00607
00608 QDomElement extentElem = doc.createElement( "Extent" );
00609 extentElem.setAttribute( "xmin", mExtent.xMinimum() );
00610 extentElem.setAttribute( "xmax", mExtent.xMaximum() );
00611 extentElem.setAttribute( "ymin", mExtent.yMinimum() );
00612 extentElem.setAttribute( "ymax", mExtent.yMaximum() );
00613 composerMapElem.appendChild( extentElem );
00614
00615
00616 QDomElement layerSetElem = doc.createElement( "LayerSet" );
00617 QStringList::const_iterator layerIt = mLayerSet.constBegin();
00618 for ( ; layerIt != mLayerSet.constEnd(); ++layerIt )
00619 {
00620 QDomElement layerElem = doc.createElement( "Layer" );
00621 QDomText layerIdText = doc.createTextNode( *layerIt );
00622 layerElem.appendChild( layerIdText );
00623 layerSetElem.appendChild( layerElem );
00624 }
00625 composerMapElem.appendChild( layerSetElem );
00626
00627
00628 QDomElement gridElem = doc.createElement( "Grid" );
00629 gridElem.setAttribute( "show", mGridEnabled );
00630 gridElem.setAttribute( "gridStyle", mGridStyle );
00631 gridElem.setAttribute( "intervalX", mGridIntervalX );
00632 gridElem.setAttribute( "intervalY", mGridIntervalY );
00633 gridElem.setAttribute( "offsetX", mGridOffsetX );
00634 gridElem.setAttribute( "offsetY", mGridOffsetY );
00635 gridElem.setAttribute( "penWidth", mGridPen.widthF() );
00636 gridElem.setAttribute( "penColorRed", mGridPen.color().red() );
00637 gridElem.setAttribute( "penColorGreen", mGridPen.color().green() );
00638 gridElem.setAttribute( "penColorBlue", mGridPen.color().blue() );
00639 gridElem.setAttribute( "crossLength", mCrossLength );
00640
00641
00642 QDomElement annotationElem = doc.createElement( "Annotation" );
00643 annotationElem.setAttribute( "show", mShowGridAnnotation );
00644 annotationElem.setAttribute( "position", mGridAnnotationPosition );
00645 annotationElem.setAttribute( "frameDistance", mAnnotationFrameDistance );
00646 annotationElem.setAttribute( "direction", mGridAnnotationDirection );
00647 annotationElem.setAttribute( "font", mGridAnnotationFont.toString() );
00648 annotationElem.setAttribute( "precision", mGridAnnotationPrecision );
00649
00650 gridElem.appendChild( annotationElem );
00651 composerMapElem.appendChild( gridElem );
00652
00653 elem.appendChild( composerMapElem );
00654 return _writeXML( composerMapElem, doc );
00655 }
00656
00657 bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& doc )
00658 {
00659 if ( itemElem.isNull() )
00660 {
00661 return false;
00662 }
00663
00664 QString idRead = itemElem.attribute( "id", "not found" );
00665 if ( idRead != "not found" )
00666 {
00667 mId = idRead.toInt();
00668 }
00669 mPreviewMode = Rectangle;
00670
00671
00672 QString previewMode = itemElem.attribute( "previewMode" );
00673 if ( previewMode == "Cache" )
00674 {
00675 mPreviewMode = Cache;
00676 }
00677 else if ( previewMode == "Render" )
00678 {
00679 mPreviewMode = Render;
00680 }
00681 else
00682 {
00683 mPreviewMode = Rectangle;
00684 }
00685
00686
00687 QDomNodeList extentNodeList = itemElem.elementsByTagName( "Extent" );
00688 if ( extentNodeList.size() > 0 )
00689 {
00690 QDomElement extentElem = extentNodeList.at( 0 ).toElement();
00691 double xmin, xmax, ymin, ymax;
00692 xmin = extentElem.attribute( "xmin" ).toDouble();
00693 xmax = extentElem.attribute( "xmax" ).toDouble();
00694 ymin = extentElem.attribute( "ymin" ).toDouble();
00695 ymax = extentElem.attribute( "ymax" ).toDouble();
00696
00697 mExtent = QgsRectangle( xmin, ymin, xmax, ymax );
00698 }
00699
00700
00701 QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" );
00702 if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 )
00703 {
00704 mKeepLayerSet = true;
00705 }
00706 else
00707 {
00708 mKeepLayerSet = false;
00709 }
00710
00711
00712 QDomNodeList layerSetNodeList = itemElem.elementsByTagName( "LayerSet" );
00713 QStringList layerSet;
00714 if ( layerSetNodeList.size() > 0 )
00715 {
00716 QDomElement layerSetElem = layerSetNodeList.at( 0 ).toElement();
00717 QDomNodeList layerIdNodeList = layerSetElem.elementsByTagName( "Layer" );
00718 for ( int i = 0; i < layerIdNodeList.size(); ++i )
00719 {
00720 layerSet << layerIdNodeList.at( i ).toElement().text();
00721 }
00722 }
00723 mLayerSet = layerSet;
00724
00725 mDrawing = false;
00726 mNumCachedLayers = 0;
00727 mCacheUpdated = false;
00728
00729
00730 QDomNodeList gridNodeList = itemElem.elementsByTagName( "Grid" );
00731 if ( gridNodeList.size() > 0 )
00732 {
00733 QDomElement gridElem = gridNodeList.at( 0 ).toElement();
00734 mGridEnabled = ( gridElem.attribute( "show", "0" ) != "0" );
00735 mGridStyle = QgsComposerMap::GridStyle( gridElem.attribute( "gridStyle", "0" ).toInt() );
00736 mGridIntervalX = gridElem.attribute( "intervalX", "0" ).toDouble();
00737 mGridIntervalY = gridElem.attribute( "intervalY", "0" ).toDouble();
00738 mGridOffsetX = gridElem.attribute( "offsetX", "0" ).toDouble();
00739 mGridOffsetY = gridElem.attribute( "offsetY", "0" ).toDouble();
00740 mGridPen.setWidthF( gridElem.attribute( "penWidth", "0" ).toDouble() );
00741 mGridPen.setColor( QColor( gridElem.attribute( "penColorRed", "0" ).toInt(), \
00742 gridElem.attribute( "penColorGreen", "0" ).toInt(), \
00743 gridElem.attribute( "penColorBlue", "0" ).toInt() ) );
00744 mCrossLength = gridElem.attribute( "crossLength", "3" ).toDouble();
00745
00746 QDomNodeList annotationNodeList = gridElem.elementsByTagName( "Annotation" );
00747 if ( annotationNodeList.size() > 0 )
00748 {
00749 QDomElement annotationElem = annotationNodeList.at( 0 ).toElement();
00750 mShowGridAnnotation = ( annotationElem.attribute( "show", "0" ) != "0" );
00751 mGridAnnotationPosition = QgsComposerMap::GridAnnotationPosition( annotationElem.attribute( "position", "0" ).toInt() );
00752 mAnnotationFrameDistance = annotationElem.attribute( "frameDistance", "0" ).toDouble();
00753 mGridAnnotationDirection = QgsComposerMap::GridAnnotationDirection( annotationElem.attribute( "direction", "0" ).toInt() );
00754 mGridAnnotationFont.fromString( annotationElem.attribute( "font", "" ) );
00755 mGridAnnotationPrecision = annotationElem.attribute( "precision", "3" ).toInt();
00756 }
00757 }
00758
00759
00760 QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
00761 if ( composerItemList.size() > 0 )
00762 {
00763 QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
00764 _readXML( composerItemElem, doc );
00765 }
00766
00767 updateBoundingRect();
00768 return true;
00769 }
00770
00771 void QgsComposerMap::storeCurrentLayerSet()
00772 {
00773 if ( mMapRenderer )
00774 {
00775 mLayerSet = mMapRenderer->layerSet();
00776 }
00777 }
00778
00779 void QgsComposerMap::syncLayerSet()
00780 {
00781 if ( mLayerSet.size() < 1 && !mMapRenderer )
00782 {
00783 return;
00784 }
00785
00786 QStringList currentLayerSet = mMapRenderer->layerSet();
00787 for ( int i = mLayerSet.size() - 1; i >= 0; --i )
00788 {
00789 if ( !currentLayerSet.contains( mLayerSet.at( i ) ) )
00790 {
00791 mLayerSet.removeAt( i );
00792 }
00793 }
00794 }
00795
00796 void QgsComposerMap::drawGrid( QPainter* p )
00797 {
00798 p->setPen( mGridPen );
00799
00800 QList< QPair< double, QLineF > > verticalLines;
00801 yGridLines( verticalLines );
00802 QList< QPair< double, QLineF > >::const_iterator vIt = verticalLines.constBegin();
00803 QList< QPair< double, QLineF > > horizontalLines;
00804 xGridLines( horizontalLines );
00805 QList< QPair< double, QLineF > >::const_iterator hIt = horizontalLines.constBegin();
00806
00807 QRectF thisPaintRect = QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() );
00808 p->setClipRect( thisPaintRect );
00809
00810
00811 if ( mGridStyle == QgsComposerMap::Solid )
00812 {
00813 for ( ; vIt != verticalLines.constEnd(); ++vIt )
00814 {
00815 p->drawLine( vIt->second );
00816 }
00817
00818 for ( ; hIt != horizontalLines.constEnd(); ++hIt )
00819 {
00820 p->drawLine( hIt->second );
00821 }
00822 }
00823 else
00824 {
00825 QPointF intersectionPoint, crossEnd1, crossEnd2;
00826 for ( ; vIt != verticalLines.constEnd(); ++vIt )
00827 {
00828
00829 crossEnd1 = pointOnLineWithDistance( vIt->second.p1(), vIt->second.p2(), mCrossLength );
00830 p->drawLine( vIt->second.p1(), crossEnd1 );
00831
00832
00833 hIt = horizontalLines.constBegin();
00834 for ( ; hIt != horizontalLines.constEnd(); ++hIt )
00835 {
00836 if ( hIt->second.intersect( vIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
00837 {
00838 crossEnd1 = pointOnLineWithDistance( intersectionPoint, vIt->second.p1(), mCrossLength );
00839 crossEnd2 = pointOnLineWithDistance( intersectionPoint, vIt->second.p2(), mCrossLength );
00840 p->drawLine( crossEnd1, crossEnd2 );
00841 }
00842 }
00843
00844 QPointF crossEnd2 = pointOnLineWithDistance( vIt->second.p2(), vIt->second.p1(), mCrossLength );
00845 p->drawLine( vIt->second.p2(), crossEnd2 );
00846 }
00847
00848 hIt = horizontalLines.constBegin();
00849 for ( ; hIt != horizontalLines.constEnd(); ++hIt )
00850 {
00851
00852 crossEnd1 = pointOnLineWithDistance( hIt->second.p1(), hIt->second.p2(), mCrossLength );
00853 p->drawLine( hIt->second.p1(), crossEnd1 );
00854
00855 vIt = verticalLines.constBegin();
00856 for ( ; vIt != verticalLines.constEnd(); ++vIt )
00857 {
00858 if ( vIt->second.intersect( hIt->second, &intersectionPoint ) == QLineF::BoundedIntersection )
00859 {
00860 crossEnd1 = pointOnLineWithDistance( intersectionPoint, hIt->second.p1(), mCrossLength );
00861 crossEnd2 = pointOnLineWithDistance( intersectionPoint, hIt->second.p2(), mCrossLength );
00862 p->drawLine( crossEnd1, crossEnd2 );
00863 }
00864 }
00865
00866 crossEnd1 = pointOnLineWithDistance( hIt->second.p2(), hIt->second.p1(), mCrossLength );
00867 p->drawLine( hIt->second.p2(), crossEnd1 );
00868 }
00869
00870
00871 }
00872
00873 p->setClipRect( thisPaintRect , Qt::NoClip );
00874
00875 if ( mShowGridAnnotation )
00876 {
00877 drawCoordinateAnnotations( p, horizontalLines, verticalLines );
00878 }
00879 }
00880
00881 void QgsComposerMap::drawCoordinateAnnotations( QPainter* p, const QList< QPair< double, QLineF > >& hLines, const QList< QPair< double, QLineF > >& vLines )
00882 {
00883 if ( !p )
00884 {
00885 return;
00886 }
00887
00888
00889 QString currentAnnotationString;
00890 QList< QPair< double, QLineF > >::const_iterator it = hLines.constBegin();
00891 for ( ; it != hLines.constEnd(); ++it )
00892 {
00893 currentAnnotationString = QString::number( it->first, 'f', mGridAnnotationPrecision );
00894 drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
00895 drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
00896 }
00897
00898 it = vLines.constBegin();
00899 for ( ; it != vLines.constEnd(); ++it )
00900 {
00901 currentAnnotationString = QString::number( it->first, 'f', mGridAnnotationPrecision );
00902 drawCoordinateAnnotation( p, it->second.p1(), currentAnnotationString );
00903 drawCoordinateAnnotation( p, it->second.p2(), currentAnnotationString );
00904 }
00905 }
00906
00907 void QgsComposerMap::drawCoordinateAnnotation( QPainter* p, const QPointF& pos, QString annotationString )
00908 {
00909 Border frameBorder = borderForLineCoord( pos );
00910 double textWidth = textWidthMillimeters( mGridAnnotationFont, annotationString );
00911 double textHeight = fontAscentMillimeters( mGridAnnotationFont );
00912 double xpos = pos.x();
00913 double ypos = pos.y();
00914 int rotation = 0;
00915
00916 if ( frameBorder == Left )
00917 {
00918
00919 if ( mGridAnnotationPosition == InsideMapFrame )
00920 {
00921 if ( mGridAnnotationDirection == Vertical || mGridAnnotationDirection == BoundaryDirection )
00922 {
00923 xpos += textHeight + mAnnotationFrameDistance;
00924 ypos += textWidth / 2.0;
00925 rotation = 270;
00926 }
00927 else
00928 {
00929 xpos += mAnnotationFrameDistance;
00930 ypos += textHeight / 2.0;
00931 }
00932 }
00933 else
00934 {
00935 if ( mGridAnnotationDirection == Vertical || mGridAnnotationDirection == BoundaryDirection )
00936 {
00937 xpos -= mAnnotationFrameDistance;
00938 ypos += textWidth / 2.0;
00939 rotation = 270;
00940 }
00941 else
00942 {
00943 xpos -= textWidth + mAnnotationFrameDistance;
00944 ypos += textHeight / 2.0;
00945 }
00946 }
00947
00948 }
00949 else if ( frameBorder == Right )
00950 {
00951 if ( mGridAnnotationPosition == InsideMapFrame )
00952 {
00953 if ( mGridAnnotationDirection == Vertical || mGridAnnotationDirection == BoundaryDirection )
00954 {
00955 xpos -= mAnnotationFrameDistance;
00956 ypos += textWidth / 2.0;
00957 rotation = 270;
00958 }
00959 else
00960 {
00961 xpos -= textWidth + mAnnotationFrameDistance;
00962 ypos += textHeight / 2.0;
00963 }
00964 }
00965 else
00966 {
00967 if ( mGridAnnotationDirection == Vertical || mGridAnnotationDirection == BoundaryDirection )
00968 {
00969 xpos += textHeight + mAnnotationFrameDistance;
00970 ypos += textWidth / 2.0;
00971 rotation = 270;
00972 }
00973 else
00974 {
00975 xpos += mAnnotationFrameDistance;
00976 ypos += textHeight / 2.0;
00977 }
00978 }
00979 }
00980 else if ( frameBorder == Bottom )
00981 {
00982 if ( mGridAnnotationPosition == InsideMapFrame )
00983 {
00984 if ( mGridAnnotationDirection == Horizontal || mGridAnnotationDirection == BoundaryDirection )
00985 {
00986 ypos -= mAnnotationFrameDistance;
00987 xpos -= textWidth / 2.0;
00988 }
00989 else
00990 {
00991 xpos += textHeight / 2.0;
00992 ypos -= mAnnotationFrameDistance;
00993 rotation = 270;
00994 }
00995 }
00996 else
00997 {
00998 if ( mGridAnnotationDirection == Horizontal || mGridAnnotationDirection == BoundaryDirection )
00999 {
01000 ypos += mAnnotationFrameDistance + textHeight;
01001 xpos -= textWidth / 2.0;
01002 }
01003 else
01004 {
01005 xpos += textHeight / 2.0;
01006 ypos += textWidth + mAnnotationFrameDistance;
01007 rotation = 270;
01008 }
01009 }
01010 }
01011 else
01012 {
01013 if ( mGridAnnotationPosition == InsideMapFrame )
01014 {
01015 if ( mGridAnnotationDirection == Horizontal || mGridAnnotationDirection == BoundaryDirection )
01016 {
01017 xpos -= textWidth / 2.0;
01018 ypos += textHeight + mAnnotationFrameDistance;
01019 }
01020 else
01021 {
01022 xpos += textHeight / 2.0;
01023 ypos += textWidth + mAnnotationFrameDistance;
01024 rotation = 270;
01025 }
01026 }
01027 else
01028 {
01029 if ( mGridAnnotationDirection == Horizontal || mGridAnnotationDirection == BoundaryDirection )
01030 {
01031 xpos -= textWidth / 2.0;
01032 ypos -= mAnnotationFrameDistance;
01033 }
01034 else
01035 {
01036 xpos += textHeight / 2.0;
01037 ypos -= mAnnotationFrameDistance;
01038 rotation = 270;
01039 }
01040 }
01041 }
01042
01043 drawAnnotation( p, QPointF( xpos, ypos ), rotation, annotationString );
01044 }
01045
01046 void QgsComposerMap::drawAnnotation( QPainter* p, const QPointF& pos, int rotation, const QString& annotationText )
01047 {
01048 p->save();
01049 p->translate( pos );
01050 p->rotate( rotation );
01051 p->setPen( QColor( 0, 0, 0 ) );
01052 drawText( p, 0, 0, annotationText, mGridAnnotationFont );
01053 p->restore();
01054 }
01055
01056 int QgsComposerMap::xGridLines( QList< QPair< double, QLineF > >& lines ) const
01057 {
01058 lines.clear();
01059 if ( mGridIntervalY <= 0.0 )
01060 {
01061 return 1;
01062 }
01063
01064
01065 QPolygonF mapPolygon = transformedMapPolygon();
01066 QRectF mapBoundingRect = mapPolygon.boundingRect();
01067
01068
01069 double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0;
01070 double currentLevel = ( int )(( mapBoundingRect.top() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY;
01071
01072 if ( mRotation <= 0.0 )
01073 {
01074
01075
01076 double yCanvasCoord;
01077
01078 while ( currentLevel <= mapBoundingRect.bottom() )
01079 {
01080 yCanvasCoord = rect().height() * ( 1 - ( currentLevel - mapBoundingRect.top() ) / mapBoundingRect.height() );
01081 lines.push_back( qMakePair( currentLevel, QLineF( 0, yCanvasCoord, rect().width(), yCanvasCoord ) ) );
01082 currentLevel += mGridIntervalY;
01083 }
01084 }
01085
01086
01087 QVector<QLineF> borderLines;
01088 borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
01089 borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
01090 borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
01091 borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
01092
01093 QList<QPointF> intersectionList;
01094
01095 while ( currentLevel <= mapBoundingRect.bottom() )
01096 {
01097 intersectionList.clear();
01098 QLineF gridLine( mapBoundingRect.left(), currentLevel, mapBoundingRect.right(), currentLevel );
01099
01100 QVector<QLineF>::const_iterator it = borderLines.constBegin();
01101 for ( ; it != borderLines.constEnd(); ++it )
01102 {
01103 QPointF intersectionPoint;
01104 if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
01105 {
01106 intersectionList.push_back( intersectionPoint );
01107 if ( intersectionList.size() >= 2 )
01108 {
01109 break;
01110 }
01111 }
01112 }
01113
01114 if ( intersectionList.size() >= 2 )
01115 {
01116 lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
01117 }
01118 currentLevel += mGridIntervalY;
01119 }
01120
01121
01122 return 0;
01123 }
01124
01125 int QgsComposerMap::yGridLines( QList< QPair< double, QLineF > >& lines ) const
01126 {
01127 lines.clear();
01128 if ( mGridIntervalX <= 0.0 )
01129 {
01130 return 1;
01131 }
01132
01133 QPolygonF mapPolygon = transformedMapPolygon();
01134 QRectF mapBoundingRect = mapPolygon.boundingRect();
01135
01136
01137 double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0;
01138 double currentLevel = ( int )(( mapBoundingRect.left() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX;
01139
01140 if ( mRotation <= 0.0 )
01141 {
01142
01143 double xCanvasCoord;
01144
01145 while ( currentLevel <= mapBoundingRect.right() )
01146 {
01147 xCanvasCoord = rect().width() * ( currentLevel - mapBoundingRect.left() ) / mapBoundingRect.width();
01148 lines.push_back( qMakePair( currentLevel, QLineF( xCanvasCoord, 0, xCanvasCoord, rect().height() ) ) );
01149 currentLevel += mGridIntervalX;
01150 }
01151 }
01152
01153
01154 QVector<QLineF> borderLines;
01155 borderLines << QLineF( mapPolygon.at( 0 ), mapPolygon.at( 1 ) );
01156 borderLines << QLineF( mapPolygon.at( 1 ), mapPolygon.at( 2 ) );
01157 borderLines << QLineF( mapPolygon.at( 2 ), mapPolygon.at( 3 ) );
01158 borderLines << QLineF( mapPolygon.at( 3 ), mapPolygon.at( 0 ) );
01159
01160 QList<QPointF> intersectionList;
01161
01162 while ( currentLevel <= mapBoundingRect.right() )
01163 {
01164 intersectionList.clear();
01165 QLineF gridLine( currentLevel, mapBoundingRect.bottom(), currentLevel, mapBoundingRect.top() );
01166
01167 QVector<QLineF>::const_iterator it = borderLines.constBegin();
01168 for ( ; it != borderLines.constEnd(); ++it )
01169 {
01170 QPointF intersectionPoint;
01171 if ( it->intersect( gridLine, &intersectionPoint ) == QLineF::BoundedIntersection )
01172 {
01173 intersectionList.push_back( intersectionPoint );
01174 if ( intersectionList.size() >= 2 )
01175 {
01176 break;
01177 }
01178 }
01179 }
01180
01181 if ( intersectionList.size() >= 2 )
01182 {
01183 lines.push_back( qMakePair( currentLevel, QLineF( mapToItemCoords( intersectionList.at( 0 ) ), mapToItemCoords( intersectionList.at( 1 ) ) ) ) );
01184 }
01185 currentLevel += mGridIntervalX;
01186 }
01187
01188 return 0;
01189 }
01190
01191 void QgsComposerMap::setGridPenWidth( double w )
01192 {
01193 mGridPen.setWidthF( w );
01194 }
01195
01196 void QgsComposerMap::setGridPenColor( const QColor& c )
01197 {
01198 mGridPen.setColor( c );
01199 }
01200
01201 QRectF QgsComposerMap::boundingRect() const
01202 {
01203 return mCurrentRectangle;
01204 }
01205
01206 void QgsComposerMap::updateBoundingRect()
01207 {
01208 QRectF rectangle = rect();
01209 double extension = maxExtension();
01210 rectangle.setLeft( rectangle.left() - extension );
01211 rectangle.setRight( rectangle.right() + extension );
01212 rectangle.setTop( rectangle.top() - extension );
01213 rectangle.setBottom( rectangle.bottom() + extension );
01214 if ( rectangle != mCurrentRectangle )
01215 {
01216 prepareGeometryChange();
01217 mCurrentRectangle = rectangle;
01218 }
01219 }
01220
01221 QgsRectangle QgsComposerMap::transformedExtent() const
01222 {
01223 double dx = mXOffset;
01224 double dy = mYOffset;
01225 transformShift( dx, dy );
01226 return QgsRectangle( mExtent.xMinimum() - dx, mExtent.yMinimum() - dy, mExtent.xMaximum() - dx, mExtent.yMaximum() - dy );
01227 }
01228
01229 QPolygonF QgsComposerMap::transformedMapPolygon() const
01230 {
01231 double dx = mXOffset;
01232 double dy = mYOffset;
01233
01234
01235
01236 transformShift( dx, dy );
01237
01238
01239
01240 QPolygonF poly;
01241 mapPolygon( poly );
01242 poly.translate( -dx, -dy );
01243 return poly;
01244 }
01245
01246 double QgsComposerMap::maxExtension() const
01247 {
01248 if ( !mGridEnabled || !mShowGridAnnotation || mGridAnnotationPosition != OutsideMapFrame )
01249 {
01250 return 0;
01251 }
01252
01253 QList< QPair< double, QLineF > > xLines;
01254 QList< QPair< double, QLineF > > yLines;
01255
01256 if ( xGridLines( xLines ) != 0 )
01257 {
01258 return 0;
01259 }
01260
01261 if ( yGridLines( yLines ) != 0 )
01262 {
01263 return 0;
01264 }
01265
01266 double maxExtension = 0;
01267 double currentExtension = 0;
01268 QString currentAnnotationString;
01269
01270 QList< QPair< double, QLineF > >::const_iterator it = xLines.constBegin();
01271 for ( ; it != xLines.constEnd(); ++it )
01272 {
01273 currentAnnotationString = QString::number( it->first, 'f', mGridAnnotationPrecision );
01274 currentExtension = std::max( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
01275 maxExtension = std::max( maxExtension, currentExtension );
01276 }
01277
01278 it = yLines.constBegin();
01279 for ( ; it != yLines.constEnd(); ++it )
01280 {
01281 currentAnnotationString = QString::number( it->first, 'f', mGridAnnotationPrecision );
01282 currentExtension = std::max( textWidthMillimeters( mGridAnnotationFont, currentAnnotationString ), fontAscentMillimeters( mGridAnnotationFont ) );
01283 maxExtension = std::max( maxExtension, currentExtension );
01284 }
01285
01286 return maxExtension + mAnnotationFrameDistance;
01287 }
01288
01289 void QgsComposerMap::mapPolygon( QPolygonF& poly ) const
01290 {
01291 poly.clear();
01292 if ( mRotation == 0 )
01293 {
01294 poly << QPointF( mExtent.xMinimum(), mExtent.yMaximum() );
01295 poly << QPointF( mExtent.xMaximum(), mExtent.yMaximum() );
01296 poly << QPointF( mExtent.xMaximum(), mExtent.yMinimum() );
01297 poly << QPointF( mExtent.xMinimum(), mExtent.yMinimum() );
01298 return;
01299 }
01300
01301
01302 QgsPoint rotationPoint(( mExtent.xMaximum() + mExtent.xMinimum() ) / 2.0, ( mExtent.yMaximum() + mExtent.yMinimum() ) / 2.0 );
01303 double dx, dy;
01304
01305
01306 dx = rotationPoint.x() - mExtent.xMinimum();
01307 dy = rotationPoint.y() - mExtent.yMaximum();
01308 rotate( mRotation, dx, dy );
01309 poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
01310
01311
01312 dx = rotationPoint.x() - mExtent.xMaximum();
01313 dy = rotationPoint.y() - mExtent.yMaximum();
01314 rotate( mRotation, dx, dy );
01315 poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
01316
01317
01318 dx = rotationPoint.x() - mExtent.xMaximum();
01319 dy = rotationPoint.y() - mExtent.yMinimum();
01320 rotate( mRotation, dx, dy );
01321 poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
01322
01323
01324 dx = rotationPoint.x() - mExtent.xMinimum();
01325 dy = rotationPoint.y() - mExtent.yMinimum();
01326 rotate( mRotation, dx, dy );
01327 poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy );
01328 }
01329
01330 void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const
01331 {
01332 if ( mRotation == 0 )
01333 {
01334 extent = mExtent;
01335 return;
01336 }
01337
01338 QPolygonF poly;
01339 mapPolygon( poly );
01340 QRectF bRect = poly.boundingRect();
01341 extent.setXMinimum( bRect.left() );
01342 extent.setXMaximum( bRect.right() );
01343 extent.setYMinimum( bRect.top() );
01344 extent.setYMaximum( bRect.bottom() );
01345 return;
01346 }
01347
01348 double QgsComposerMap::mapUnitsToMM() const
01349 {
01350 double extentWidth = mExtent.width();
01351 if ( extentWidth <= 0 )
01352 {
01353 return 1;
01354 }
01355 return rect().width() / extentWidth;
01356 }
01357
01358 void QgsComposerMap::transformShift( double& xShift, double& yShift ) const
01359 {
01360 double mmToMapUnits = 1.0 / mapUnitsToMM();
01361 double dxScaled = xShift * mmToMapUnits;
01362 double dyScaled = - yShift * mmToMapUnits;
01363
01364 rotate( mRotation, dxScaled, dyScaled );
01365
01366 xShift = dxScaled;
01367 yShift = dyScaled;
01368 }
01369
01370 QPointF QgsComposerMap::mapToItemCoords( const QPointF& mapCoords ) const
01371 {
01372 QPolygonF mapPoly = transformedMapPolygon();
01373 if ( mapPoly.size() < 1 )
01374 {
01375 return QPointF( 0, 0 );
01376 }
01377
01378 QgsRectangle tExtent = transformedExtent();
01379 QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 );
01380 double dx = mapCoords.x() - rotationPoint.x();
01381 double dy = mapCoords.y() - rotationPoint.y();
01382 rotate( -mRotation, dx, dy );
01383 QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy );
01384
01385 QgsRectangle unrotatedExtent = transformedExtent();
01386 double xItem = rect().width() * ( backRotatedCoords.x() - unrotatedExtent.xMinimum() ) / unrotatedExtent.width();
01387 double yItem = rect().height() * ( 1 - ( backRotatedCoords.y() - unrotatedExtent.yMinimum() ) / unrotatedExtent.height() );
01388 return QPointF( xItem, yItem );
01389 }
01390
01391 QgsComposerMap::Border QgsComposerMap::borderForLineCoord( const QPointF& p ) const
01392 {
01393 if ( p.x() <= pen().widthF() )
01394 {
01395 return Left;
01396 }
01397 else if ( p.x() >= ( rect().width() - pen().widthF() ) )
01398 {
01399 return Right;
01400 }
01401 else if ( p.y() <= pen().widthF() )
01402 {
01403 return Top;
01404 }
01405 else
01406 {
01407 return Bottom;
01408 }
01409 }
01410
01411 void QgsComposerMap::drawCanvasItems( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
01412 {
01413 if ( !mMapCanvas )
01414 {
01415 return;
01416 }
01417
01418 QList<QGraphicsItem*> itemList = mMapCanvas->items();
01419 if ( itemList.size() < 1 )
01420 {
01421 return;
01422 }
01423 QGraphicsItem* currentItem = 0;
01424
01425 #if QT_VERSION >= 0x40600 //Qt 4.6 provides the items in visibility order
01426 for ( int i = itemList.size() - 1; i >= 0; --i )
01427 {
01428 currentItem = itemList.at( i );
01429
01430 if ( !currentItem || currentItem->zValue() == -10 )
01431 {
01432 continue;
01433 }
01434 drawCanvasItem( currentItem, painter, itemStyle );
01435 }
01436 #else //Qt <4.6 provides the items in random order
01437 QMultiMap<int, QGraphicsItem*> topLevelItems;
01438 QMultiMap<QGraphicsItem*, QGraphicsItem*> childItems;
01439
01440 for ( int i = 0; i < itemList.size(); ++i )
01441 {
01442 currentItem = itemList.at( i );
01443
01444 if ( !currentItem || currentItem->zValue() == -10 )
01445 {
01446 continue;
01447 }
01448 if ( currentItem->parentItem() )
01449 {
01450 childItems.insert( currentItem->parentItem(), currentItem );
01451 }
01452 else
01453 {
01454 topLevelItems.insert( currentItem->zValue(), currentItem );
01455 }
01456 }
01457
01458 QMultiMap<int, QGraphicsItem*>::iterator topLevelIt = topLevelItems.begin();
01459 for ( ; topLevelIt != topLevelItems.end(); ++topLevelIt )
01460 {
01461 drawCanvasItem( topLevelIt.value(), painter, itemStyle );
01462
01463
01464 QMap<QGraphicsItem*, QGraphicsItem*>::iterator childIt = childItems.find( topLevelIt.value() );
01465 while ( childIt != childItems.end() && childIt.key() == topLevelIt.value() )
01466 {
01467 drawCanvasItem( childIt.value(), painter, itemStyle );
01468 ++childIt;
01469 }
01470 }
01471 #endif
01472 }
01473
01474 void QgsComposerMap::drawCanvasItem( QGraphicsItem* item, QPainter* painter, const QStyleOptionGraphicsItem* itemStyle )
01475 {
01476 if ( !item || !mMapCanvas || !mMapRenderer || !item->isVisible() )
01477 {
01478 return;
01479 }
01480
01481 painter->save();
01482
01483 QgsRectangle rendererExtent = mMapRenderer->extent();
01484 QgsRectangle composerMapExtent = mExtent;
01485
01486
01487 double scaleFactor = 1.0 / mMapCanvas->logicalDpiX() * 25.4;
01488
01489 double itemX, itemY;
01490 QGraphicsItem* parent = item->parentItem();
01491 if ( !parent )
01492 {
01493 QPointF mapPos = composerMapPosForItem( item );
01494 itemX = mapPos.x();
01495 itemY = mapPos.y();
01496 }
01497 else
01498 {
01499 QPointF itemScenePos = item->scenePos();
01500 QPointF parentScenePos = parent->scenePos();
01501
01502 QPointF mapPos = composerMapPosForItem( parent );
01503
01504 itemX = mapPos.x() + ( itemScenePos.x() - parentScenePos.x() ) * scaleFactor;
01505 itemY = mapPos.y() + ( itemScenePos.y() - parentScenePos.y() ) * scaleFactor;
01506 }
01507 painter->translate( itemX, itemY );
01508
01509
01510 painter->scale( scaleFactor, scaleFactor );
01511
01512
01513 item->setData( 0, "composer" );
01514 item->paint( painter, itemStyle, 0 );
01515 item->setData( 0, "" );
01516 painter->restore();
01517 }
01518
01519 QPointF QgsComposerMap::composerMapPosForItem( const QGraphicsItem* item ) const
01520 {
01521 if ( !item || !mMapCanvas || !mMapRenderer )
01522 {
01523 return QPointF( 0, 0 );
01524 }
01525
01526 if ( mExtent.height() <= 0 || mExtent.width() <= 0 || mMapCanvas->width() <= 0 || mMapCanvas->height() <= 0 )
01527 {
01528 return QPointF( 0, 0 );
01529 }
01530
01531 double mapX = item->scenePos().x() / mMapCanvas->width() * mMapRenderer->extent().width() + mMapRenderer->extent().xMinimum();
01532 double mapY = mMapRenderer->extent().yMaximum() - item->scenePos().y() / mMapCanvas->height() * mMapRenderer->extent().height();
01533
01534 double itemX = rect().width() * ( mapX - mExtent.xMinimum() ) / mExtent.width() + mXOffset;
01535 double itemY = rect().height() * ( mExtent.yMaximum() - mapY ) / mExtent.height() + mYOffset;
01536 return QPointF( itemX, itemY );
01537 }