Skip to content
Permalink
Browse files

Simplified map rendering configuration.

- scene and painter DPI are always the same
- raster scale factor is always 1
- scale factor always means pixels per milimeter
- no need to force of custom-computed scale
- no "output units" - map settings always use pixels as units

The logic used previously was getting too complex:
- scene DPI vs painter DPI
- enforcing custom scale in composer
- unclear logic behind scale factor and raster scale factor settings

This is resolved by doing composer-specific tweaks inside composer:
- set map cache image's DPI (to get correct scale)
- scale printer's painter to switch from mm to pixels (dots)
  • Loading branch information
wonder-sk committed Nov 13, 2013
1 parent 630272d commit 735fab1a1e969f4d83e3563a1c57458b9e2840ed
@@ -147,6 +147,8 @@ QgsComposerMap::~QgsComposerMap()
from QGraphicsItem. */
void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const QSizeF& size, double dpi, double* forceWidthScale )
{
Q_UNUSED( forceWidthScale );

if ( !painter )
{
return;
@@ -156,7 +158,7 @@ void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const

QgsMapSettings jobMapSettings;
jobMapSettings.setExtent( extent );
jobMapSettings.setOutputSize( size.toSize() ); // TODO: sizeF
jobMapSettings.setOutputSize( size.toSize() );
jobMapSettings.setOutputDpi( dpi );
/* TODO: if ( mMapRenderer->labelingEngine() )
theMapRenderer.setLabelingEngine( mMapRenderer->labelingEngine()->clone() );*/
@@ -174,20 +176,6 @@ void QgsComposerMap::draw( QPainter *painter, const QgsRectangle& extent, const
// make the renderer respect the composition's useAdvancedEffects flag
jobMapSettings.setUseAdvancedEffects( mComposition->useAdvancedEffects() );

// force composer map scale for scale dependent visibility
// TODO: custom scale jobMapSettings.setScale( scale() );

Q_UNUSED(forceWidthScale);
/*
if ( forceWidthScale ) //force wysiwyg line widths / marker sizes
{
theMapRenderer.render( painter, forceWidthScale );
}
else
{
theMapRenderer.render( painter );
}*/

// render
QgsMapRendererCustomPainterJob job( jobMapSettings, painter );
job.start();
@@ -219,8 +207,11 @@ void QgsComposerMap::cache( void )
horizontalVScaleFactor = mLastValidViewScaleFactor;
}

int w = requestExtent.width() * mapUnitsToMM() * horizontalVScaleFactor;
int h = requestExtent.height() * mapUnitsToMM() * horizontalVScaleFactor;
double widthMM = requestExtent.width() * mapUnitsToMM();
double heightMM = requestExtent.height() * mapUnitsToMM();

int w = widthMM * horizontalVScaleFactor;
int h = heightMM * horizontalVScaleFactor;

if ( w > 5000 ) //limit size of image for better performance
{
@@ -232,10 +223,12 @@ void QgsComposerMap::cache( void )
h = 5000;
}

double forcedWidthScaleFactor = w / requestExtent.width() / mapUnitsToMM();

mCacheImage = QImage( w, h, QImage::Format_ARGB32 );

// set DPI of the image
mCacheImage.setDotsPerMeterX( 1000 * w / widthMM );
mCacheImage.setDotsPerMeterX( 1000 * h / heightMM );

if ( hasBackground() )
{
//Initially fill image with specified background color. This ensures that layers with blend modes will
@@ -248,14 +241,9 @@ void QgsComposerMap::cache( void )
mCacheImage.fill( QColor( 255, 255, 255, 0 ).rgba() );
}

double mapUnitsPerPixel = mExtent.width() / w;

// WARNING: ymax in QgsMapToPixel is device height!!!
QgsMapToPixel transform( mapUnitsPerPixel, h, requestExtent.yMinimum(), requestExtent.xMinimum() );

QPainter p( &mCacheImage );

draw( &p, requestExtent, QSizeF( w, h ), mCacheImage.logicalDpiX(), &forcedWidthScaleFactor );
draw( &p, requestExtent, QSizeF( w, h ), mCacheImage.logicalDpiX() );
p.end();
mCacheUpdated = true;

@@ -372,7 +360,11 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i
painter->translate( xTopLeftShift, yTopLeftShift );
painter->rotate( mRotation );
painter->translate( xShiftMM, -yShiftMM );
draw( painter, requestRectangle, theSize, 25.4 ); //scene coordinates seem to be in mm

double dotsPerMM = thePaintDevice->logicalDpiX() / 25.4;
theSize *= dotsPerMM; // output size will be in dots (pixels)
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
draw( painter, requestRectangle, theSize, thePaintDevice->logicalDpiX() );

//restore rotation
painter->restore();
@@ -181,7 +181,6 @@ void QgsMapRendererCustomPainterJob::staticRender(QgsMapRendererCustomPainterJob
self->startRender();
}


void QgsMapRendererCustomPainterJob::startRender()
{
qDebug("QPAINTER startRender");
@@ -193,47 +192,28 @@ void QgsMapRendererCustomPainterJob::startRender()

QPaintDevice* thePaintDevice = mPainter->device();

Q_ASSERT_X( thePaintDevice->logicalDpiX() == mSettings.outputDpi(), "Job::startRender()", "pre-set DPI not equal to painter's DPI" );

#ifdef QGISDEBUG
QgsDebugMsg( "Starting to render layer stack." );
QTime renderTime;
renderTime.start();
#endif

mRenderContext.setMapToPixel( mSettings.mapToPixel() ); // QgsMapToPixel( mSettings.mapUnitsPerPixel(), mSettings.outputSize().height(), mSettings.visibleExtent().yMinimum(), mSettings.visibleExtent().xMinimum() ) );
mRenderContext.setMapToPixel( mSettings.mapToPixel() );
mRenderContext.setExtent( mSettings.visibleExtent() );

mRenderContext.setDrawEditingInformation( false );
mRenderContext.setPainter( mPainter );
mRenderContext.setCoordinateTransform( 0 );
mRenderContext.setSelectionColor( mSettings.selectionColor() );
mRenderContext.setRasterScaleFactor( 1.0 );
mRenderContext.setScaleFactor( mSettings.outputDpi() / 25.4 ); // = pixels per mm
mRenderContext.setRendererScale( mSettings.scale() );

//this flag is only for stopping during the current rendering progress,
//so must be false at every new render operation
mRenderContext.setRenderingStopped( false );

// set selection color
mRenderContext.setSelectionColor( mSettings.selectionColor() );

//calculate scale factor
//use the specified dpi and not those from the paint device
//because sometimes QPainter units are in a local coord sys (e.g. in case of QGraphicsScene)
double* forceWidthScale = 0; // TODO: may point to a value (composer)
double sceneDpi = mSettings.outputDpi();
double scaleFactor = 1.0;
if ( mSettings.outputUnits() == QgsMapSettings::Millimeters )
{
if ( forceWidthScale )
{
scaleFactor = *forceWidthScale;
}
else
{
scaleFactor = sceneDpi / 25.4;
}
}
double rasterScaleFactor = ( thePaintDevice->logicalDpiX() + thePaintDevice->logicalDpiY() ) / 2.0 / sceneDpi;
mRenderContext.setRasterScaleFactor( rasterScaleFactor );
mRenderContext.setScaleFactor( scaleFactor );
mRenderContext.setRendererScale( mSettings.scale() );

mRenderContext.setLabelingEngine( mLabelingEngine );
if ( mLabelingEngine )
mLabelingEngine->init( mSettings );
@@ -315,17 +295,6 @@ void QgsMapRendererCustomPainterJob::startRender()

mRenderContext.setCoordinateTransform( ct );

//decide if we have to scale the raster
//this is necessary in case QGraphicsScene is used
bool scaleRaster = false;
QgsMapToPixel rasterMapToPixel;
QgsMapToPixel bk_mapToPixel;

if ( ml->type() == QgsMapLayer::RasterLayer && qAbs( rasterScaleFactor - 1.0 ) > 0.000001 )
{
scaleRaster = true;
}

/*QSettings mySettings;
bool useRenderCaching = false;
if ( ! split )//render caching does not yet cater for split extents
@@ -412,17 +381,6 @@ void QgsMapRendererCustomPainterJob::startRender()
}
}*/

if ( scaleRaster )
{
bk_mapToPixel = mRenderContext.mapToPixel();
rasterMapToPixel = mRenderContext.mapToPixel();
rasterMapToPixel.setMapUnitsPerPixel( mRenderContext.mapToPixel().mapUnitsPerPixel() / rasterScaleFactor );
rasterMapToPixel.setYMaximum( mSettings.outputSize().height() * rasterScaleFactor );
mRenderContext.setMapToPixel( rasterMapToPixel );
mRenderContext.painter()->save();
mRenderContext.painter()->scale( 1.0 / rasterScaleFactor, 1.0 / rasterScaleFactor );
}

if ( !ml->draw( mRenderContext ) )
{
// TODO emit drawError( ml );
@@ -441,12 +399,6 @@ void QgsMapRendererCustomPainterJob::startRender()
}
}

if ( scaleRaster )
{
mRenderContext.setMapToPixel( bk_mapToPixel );
mRenderContext.painter()->restore();
}

//apply layer transparency for vector layers
/*if (( mRenderContext.useAdvancedEffects() ) && ( ml->type() == QgsMapLayer::VectorLayer ) )
{
@@ -36,7 +36,6 @@ QgsMapSettings::QgsMapSettings()
, mBackgroundColor( Qt::white )
, mSelectionColor( Qt::yellow )
, mAntiAliasing( true )
, mOutputUnits( QgsMapSettings::Millimeters )
{
updateDerived();

@@ -162,12 +161,12 @@ void QgsMapSettings::setOutputSize(const QSize& size)
updateDerived();
}

double QgsMapSettings::outputDpi() const
int QgsMapSettings::outputDpi() const
{
return mDpi;
}

void QgsMapSettings::setOutputDpi(double dpi)
void QgsMapSettings::setOutputDpi(int dpi)
{
mDpi = dpi;

@@ -23,22 +23,14 @@ class QgsMapSettings
public:
QgsMapSettings();

/**Output units for pen width and point marker width/height*/
enum OutputUnits // TODO[MD]: sync with QgsMapRenderer
{
Millimeters,
Pixels
//MAP_UNITS probably supported in future versions
};

QgsRectangle extent() const;
void setExtent(const QgsRectangle& rect);

QSize outputSize() const;
void setOutputSize(const QSize& size);

double outputDpi() const;
void setOutputDpi(double dpi);
int outputDpi() const;
void setOutputDpi(int dpi);

QStringList layers() const;
void setLayers(const QStringList& layers);
@@ -56,10 +48,6 @@ class QgsMapSettings
QGis::UnitType mapUnits() const;
void setMapUnits( QGis::UnitType u );

// TODO: maybe used just for something local... and not necessary here!
void setOutputUnits( OutputUnits u ) { mOutputUnits = u; }
OutputUnits outputUnits() const { return mOutputUnits; }

void setBackgroundColor( const QColor& color ) { mBackgroundColor = color; }
QColor backgroundColor() const { return mBackgroundColor; }

@@ -133,7 +121,7 @@ class QgsMapSettings

protected:

double mDpi;
int mDpi;

QSize mSize;

@@ -148,9 +136,6 @@ class QgsMapSettings
QColor mSelectionColor;
bool mAntiAliasing;

//! Output units
OutputUnits mOutputUnits;

// derived properties
bool mValid; //!< whether the actual settings are valid (set in updateDerived())
QgsRectangle mVisibleExtent; //!< extent with some additional white space that matches the output aspect ratio
@@ -116,27 +116,8 @@ bool QgsMapCanvasItem::setRenderContextVariables( QPainter* p, QgsRenderContext&

context.setPainter( p );
context.setRendererScale( mMapCanvas->scale() );

int dpi = ms.outputDpi();
int painterDpi = p->device()->logicalDpiX();
double scaleFactor = 1.0;
double rasterScaleFactor = 1.0;

//little trick to find out if painting origines from composer or main map canvas
if ( data( 1 ).toString() == "composer" )
{
rasterScaleFactor = painterDpi / 25.4;
scaleFactor = dpi / 25.4;
}
else
{
if ( ms.outputUnits() == QgsMapSettings::Millimeters )
{
scaleFactor = dpi / 25.4;
}
}
context.setScaleFactor( scaleFactor );
context.setRasterScaleFactor( rasterScaleFactor );
context.setScaleFactor( ms.outputDpi() / 25.4 );
context.setRasterScaleFactor( 1.0 );
return true;
}

0 comments on commit 735fab1

Please sign in to comment.
You can’t perform that action at this time.