📄 qgscomposermap.cpp
字号:
/*************************************************************************** qgscomposermap.cpp ------------------- begin : January 2005 copyright : (C) 2005 by Radim Blazek email : blazek@itc.it ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "qgscomposermap.h"#include "qgscoordinatetransform.h"#include "qgsmapcanvas.h"#include "qgsmaplayer.h"#include "qgsmaptopixel.h"#include "qgsproject.h"#include "qgsmaprender.h"#include "qgsvectorlayer.h"#include "qgslabel.h"#include "qgslabelattributes.h"#include <QGraphicsScene>#include <QGraphicsRectItem>#include <QPainter>#include <iostream>#include <cmath>// round isn't defined by default in msvc#ifdef _MSC_VER #define round(x) ((x) >= 0 ? floor((x)+0.5) : floor((x)-0.5))#endifQgsComposerMap::QgsComposerMap ( QgsComposition *composition, int id, int x, int y, int width, int height ) : QWidget(), QGraphicsRectItem(0,0,width,height,0){std::cout << "QgsComposerMap::QgsComposerMap()" << std::endl; setupUi(this); mComposition = composition; mId = id; mMapCanvas = mComposition->mapCanvas(); mName = QString(tr("Map %1").arg(mId)); init(); recalculate(); // Add to scene mComposition->canvas()->addItem(this); QGraphicsRectItem::setPos(x, y); QGraphicsRectItem::show(); writeSettings();}QgsComposerMap::QgsComposerMap ( QgsComposition *composition, int id ) : QGraphicsRectItem(0,0,10,10,0){ setupUi(this); mComposition = composition; mId = id; mMapCanvas = mComposition->mapCanvas(); mName = QString(tr("Map %1").arg(mId)); init(); readSettings(); recalculate(); // Add to scene mComposition->canvas()->addItem(this); QGraphicsRectItem::show();}void QgsComposerMap::init (){ mNumCachedLayers = 0; mSelected = false; mUserExtent = mMapCanvas->extent(); mDrawing = false; // Cache mCacheUpdated = false; // Calculate mCalculateComboBox->insertItem( tr("Extent (calculate scale)"), Scale ); mCalculateComboBox->insertItem( tr("Scale (calculate extent)"), Extent ); mCalculate = Scale; setPlotStyle ( QgsComposition::Preview ); // Preview style mPreviewMode = Cache; mPreviewModeComboBox->insertItem ( tr("Cache"), Cache ); mPreviewModeComboBox->insertItem ( tr("Render"), Render ); mPreviewModeComboBox->insertItem ( tr("Rectangle"), Rectangle ); mPreviewModeComboBox->setCurrentItem ( Cache ); mWidthScale = 1.0 / mComposition->scale(); mSymbolScale = 0.5; mFontScale = 1.0; mFrame = true; QGraphicsRectItem::setZValue(20); connect ( mMapCanvas, SIGNAL(layersChanged()), this, SLOT(mapCanvasChanged()) );}QgsComposerMap::~QgsComposerMap(){ std::cerr << "QgsComposerMap::~QgsComposerMap" << std::endl;}/* This function is called by paint() and cache() to render the map. It does not override any functionsfrom QGraphicsItem. */void QgsComposerMap::draw ( QPainter *painter, QgsRect &extent, QgsMapToPixel *transform){ mMapCanvas->freeze(true); // necessary ? int nlayers = mMapCanvas->layerCount(); QgsCoordinateTransform* ct; for ( int i = nlayers - 1; i >= 0; i-- ) { QgsMapLayer *layer = mMapCanvas->getZpos(i); //if ( !layer->visible() ) continue; if (mMapCanvas->projectionsEnabled()) { ct = new QgsCoordinateTransform(layer->srs(), mMapCanvas->mapRender()->destinationSrs()); } else { ct = NULL; } if ( layer->type() == QgsMapLayer::VECTOR ) { QgsVectorLayer *vector = dynamic_cast <QgsVectorLayer*> (layer); double widthScale = mWidthScale; double symbolScale = mSymbolScale;//TODO: attempt to scale cache lines and point symbols to be larger as we zoom in/* if(creating cache pixmap) { widthScale *= (cachePixmap.width / map.rect.width); symbolScale *= (cachePixmap.width / map.rect.width); }*/ QgsRect r1, r2; r1 = extent; // TODO: revisit later and make this QgsMapRender-aware [MD] // bool split = layer->projectExtent(r1, r2); bool split = false; vector->draw( painter, r1, transform, ct, FALSE, widthScale, symbolScale); if ( split ) { vector->draw( painter, r2, transform, ct, FALSE, widthScale, symbolScale); } } else { // raster if ( plotStyle() == QgsComposition::Print || plotStyle() == QgsComposition::Postscript ) { // we have to rescale the raster to get requested resolution // calculate relation between composition point size and requested resolution (in mm) double multip = (1. / mComposition->scale()) / (25.4 / mComposition->resolution()) ; double sc = mExtent.width() / (multip*QGraphicsRectItem::rect().width()); QgsMapToPixel trans ( sc, multip*QGraphicsRectItem::rect().height(), mExtent.yMin(), mExtent.xMin() ); painter->save(); painter->scale( 1./multip, 1./multip); layer->draw( painter, extent, &trans, ct, FALSE); painter->restore(); } else { layer->draw( painter, extent, transform, ct, FALSE); } } delete ct; } // Draw vector labels for ( int i = nlayers - 1; i >= 0; i-- ) { QgsMapLayer *layer = mMapCanvas->getZpos(i); if (mMapCanvas->projectionsEnabled()) { ct = new QgsCoordinateTransform(layer->srs(), mMapCanvas->mapRender()->destinationSrs()); } else { ct = NULL; }// if ( !layer->visible() ) continue; //this doesn't work with the newer map layer code if ( layer->type() == QgsMapLayer::VECTOR ) { QgsVectorLayer *vector = dynamic_cast <QgsVectorLayer*> (layer); if ( vector->labelOn() ) { double fontScale = 25.4 * mFontScale * mComposition->scale() / 72; if ( plotStyle() == QgsComposition::Postscript ) { //fontScale = QgsComposition::psFontScaleFactor() * 72.0 / mComposition->resolution(); // TODO // This is not completely correct because fonts written to postscript // should use size metrics.ascent() * 72.0 / mComposition->resolution(); // We could add a factor for metrics.ascent()/size but it is variable // Add a parrameter in drawLables() ? QFont tempFont; tempFont.setFamily(vector->label()->layerAttributes()->family()); double size = vector->label()->layerAttributes()->size(); size = 25.4 * size / 72; tempFont.setPointSizeF(size); QFontMetricsF tempMetrics(tempFont); fontScale = tempMetrics.ascent() * 72.0 / mComposition->resolution(); //std::cout << "fontScale: " << fontScale << std::endl; fontScale *= mFontScale; //divide out the font size, since it will be multiplied back in when drawing the labels fontScale /= vector->label()->layerAttributes()->size(); } vector->drawLabels ( painter, extent, transform, ct, fontScale ); } delete ct; } } mMapCanvas->freeze(false);}void QgsComposerMap::setUserExtent ( QgsRect const & rect ){ mUserExtent = rect; recalculate(); QGraphicsRectItem::update(); QGraphicsRectItem::scene()->update();}void QgsComposerMap::cache ( void ){ std::cout << "QgsComposerMap::cache()" << std::endl; // Create preview on some reasonable size. It was slow with cca 1500x1500 points on 2x1.5GHz // Note: The resolution should also respect the line widths, it means that // 1 pixel in cache should have ia similar size as 1 pixel in canvas // but it can result in big cache -> limit int w = (int)(QGraphicsRectItem::rect().width() * mComposition->viewScale()); w = w < 1000 ? w : 1000; //limit the cache pixmap to 1000 pixels wide int h = (int) ( mExtent.height() * w / mExtent.width() ); // It can happen that extent is not initialised well -> check if ( h < 1 || h > 10000 ) h = w; std::cout << "extent = " << mExtent.width() << " x " << mExtent.height() << std::endl; std::cout << "cache = " << w << " x " << h << std::endl; mCacheExtent = QgsRect ( mExtent ); double scale = mExtent.width() / w; mCacheExtent.setXmax ( mCacheExtent.xMin() + w * scale ); mCacheExtent.setYmax ( mCacheExtent.yMin() + h * scale ); mCachePixmap.resize( w, h ); // WARNING: ymax in QgsMapToPixel is device height!!! QgsMapToPixel transform(scale, h, mCacheExtent.yMin(), mCacheExtent.xMin() );//somthing about this transform isn't really what we want.../*Ideally, the cache pixmap wouldn't behave the same as the map canvas.* zooming in should make the lines become thicker, and symbols larger, rather than just* redrawing them to be n pixels wide.* We also want to make sure that changing the composition's resolution has the desired effect * on both the cache, screen render, and print.*/ std::cout << "transform = " << transform.showParameters().toLocal8Bit().data() << std::endl; mCachePixmap.fill(QColor(255,255,255)); QPainter p(&mCachePixmap); draw( &p, mCacheExtent, &transform); p.end(); mNumCachedLayers = mMapCanvas->layerCount(); mCacheUpdated = true;}void QgsComposerMap::paint ( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget){ if ( mDrawing ) return; mDrawing = true; std::cout << "QgsComposerMapt::paint mPlotStyle = " << plotStyle() << " mPreviewMode = " << mPreviewMode << std::endl; if ( plotStyle() == QgsComposition::Preview && mPreviewMode == Cache ) { // Draw from cache std::cout << "use cache" << std::endl; if ( !mCacheUpdated || mMapCanvas->layerCount() != mNumCachedLayers ) { cache(); } // Scale so that the cache fills the map rectangle double scale = 1.0 * QGraphicsRectItem::rect().width() / mCachePixmap.width(); std::cout << "scale = " << scale << std::endl; painter->save(); painter->translate(0, 0); //do we need this? painter->scale(scale,scale); // Note: drawing only a visible part of the pixmap doesn't make it much faster painter->drawPixmap(0,0, mCachePixmap); painter->restore(); } else if ( (plotStyle() == QgsComposition::Preview && mPreviewMode == Render) || plotStyle() == QgsComposition::Print || plotStyle() == QgsComposition::Postscript ) { std::cout << "render" << std::endl; double scale = mExtent.width() / QGraphicsRectItem::rect().width(); QgsMapToPixel transform(scale, QGraphicsRectItem::rect().height(), mExtent.yMin(), mExtent.xMin() ); painter->save(); painter->translate(0, 0); //do we need this? // TODO: Qt4 appears to force QPainter::CoordDevice - need to check if this is actually valid. painter->setClipRect (QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() )); draw( painter, mExtent, &transform); painter->restore(); } // Draw frame around if ( mFrame ) { QPen pen(QColor(0,0,0)); pen.setWidthF(0.6*mComposition->scale()); painter->setPen( pen ); painter->setBrush( Qt::NoBrush ); painter->setRenderHint(QPainter::Antialiasing, true); //turn on antialiasing for drawing the box painter->save(); painter->translate(0, 0);//do we need this? painter->drawRect (QRectF( 0, 0, QGraphicsRectItem::rect().width(), QGraphicsRectItem::rect().height() )); painter->restore(); } // Show selected / Highlight if ( mSelected && plotStyle() == QgsComposition::Preview ) { painter->setPen( mComposition->selectionPen() ); painter->setBrush( mComposition->selectionBrush() );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -