Fix #11006 (wrong size of symbols in print composer legend if map units are used)

This commit is contained in:
Martin Dobias 2014-08-25 21:17:38 +07:00
parent d3e24c75b1
commit d994e0a1b3
8 changed files with 47 additions and 35 deletions

View File

@ -71,6 +71,12 @@ class QgsLegendSettings
bool useAdvancedEffects() const; bool useAdvancedEffects() const;
void setUseAdvancedEffects( bool use ); void setUseAdvancedEffects( bool use );
double mapScale() const;
void setMapScale( double scale );
int dpi() const;
void setDpi( int dpi );
// utility functions // utility functions
/** Splits a string using the wrap char taking into account handling empty /** Splits a string using the wrap char taking into account handling empty

View File

@ -80,7 +80,10 @@ class QgsSymbolV2
void setColor( const QColor& color ); void setColor( const QColor& color );
QColor color() const; QColor color() const;
void drawPreviewIcon( QPainter* painter, QSize size ); //! Draw icon of the symbol that occupyies area given by size using the painter.
//! Optionally custom context may be given in order to get rendering of symbols that use map units right.
//! @note customContext parameter added in 2.6
void drawPreviewIcon( QPainter* painter, QSize size, QgsRenderContext* customContext = 0 );
QImage bigSymbolPreviewImage(); QImage bigSymbolPreviewImage();

View File

@ -65,7 +65,11 @@ void QgsComposerLegend::paint( QPainter* painter, const QStyleOptionGraphicsItem
if ( mComposition ) if ( mComposition )
{
mSettings.setUseAdvancedEffects( mComposition->useAdvancedEffects() ); mSettings.setUseAdvancedEffects( mComposition->useAdvancedEffects() );
mSettings.setMapScale( mComposition->mapSettings().scale() );
mSettings.setDpi( painter->device()->logicalDpiX() );
}
if ( mComposerMap ) if ( mComposerMap )
mSettings.setMmPerMapUnit( mComposerMap->mapUnitsToMM() ); mSettings.setMmPerMapUnit( mComposerMap->mapUnitsToMM() );

View File

@ -207,9 +207,13 @@ QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, Ite
return QSizeF(); return QSizeF();
} }
//consider relation to composer map for symbol sizes in mm // setup temporary render context
bool sizeInMapUnits = s->outputUnit() == QgsSymbolV2::MapUnit; QgsRenderContext context;
QgsMarkerSymbolV2* markerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( s ); context.setScaleFactor( settings.dpi() / 25.4 );
context.setRendererScale( settings.mapScale() );
context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) ); // hope it's ok to leave out other params
context.setForceVectorOutput( true );
context.setPainter( ctx ? ctx->painter : 0 );
//Consider symbol size for point markers //Consider symbol size for point markers
double height = settings.symbolSize().height(); double height = settings.symbolSize().height();
@ -219,17 +223,12 @@ QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, Ite
double widthOffset = 0; double widthOffset = 0;
double heightOffset = 0; double heightOffset = 0;
if ( markerSymbol ) if ( QgsMarkerSymbolV2* markerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( s ) )
{ {
size = markerSymbol->size(); // allow marker symbol to occupy bigger area if necessary
size = markerSymbol->size() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, s->outputUnit(), s->mapUnitScale() ) / context.scaleFactor();
height = size; height = size;
width = size; width = size;
if ( sizeInMapUnits )
{
height *= settings.mmPerMapUnit();
width *= settings.mmPerMapUnit();
markerSymbol->setSize( width );
}
if ( width < settings.symbolSize().width() ) if ( width < settings.symbolSize().width() )
{ {
widthOffset = ( settings.symbolSize().width() - width ) / 2.0; widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
@ -247,18 +246,7 @@ QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, Ite
QPainter* p = ctx->painter; QPainter* p = ctx->painter;
//setup painter scaling to dots so that raster symbology is drawn to scale //setup painter scaling to dots so that raster symbology is drawn to scale
double dotsPerMM = 1.0; double dotsPerMM = context.scaleFactor();
QPaintDevice* paintDevice = p->device();
if ( !paintDevice )
{
return QSizeF();
}
dotsPerMM = paintDevice->logicalDpiX() / 25.4;
if ( markerSymbol && sizeInMapUnits )
{
s->setOutputUnit( QgsSymbolV2::MM );
}
int opacity = 255; int opacity = 255;
if ( QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( parent()->layer() ) ) if ( QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( parent()->layer() ) )
@ -275,7 +263,7 @@ QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, Ite
tempImage.fill( Qt::transparent ); tempImage.fill( Qt::transparent );
imagePainter.translate( dotsPerMM * ( currentXPosition + widthOffset ), imagePainter.translate( dotsPerMM * ( currentXPosition + widthOffset ),
dotsPerMM * ( currentYCoord + heightOffset ) ); dotsPerMM * ( currentYCoord + heightOffset ) );
s->drawPreviewIcon( &imagePainter, QSize( width * dotsPerMM, height * dotsPerMM ) ); s->drawPreviewIcon( &imagePainter, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
//reduce opacity of image //reduce opacity of image
imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn ); imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) ); imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
@ -287,15 +275,9 @@ QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, Ite
{ {
p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset ); p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM ); p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ) ); s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
} }
p->restore(); p->restore();
if ( markerSymbol && sizeInMapUnits )
{
s->setOutputUnit( QgsSymbolV2::MapUnit );
markerSymbol->setSize( size );
}
} }
return QSizeF( qMax( width + 2 * widthOffset, settings.symbolSize().width() ), return QSizeF( qMax( width + 2 * widthOffset, settings.symbolSize().width() ),

View File

@ -32,6 +32,8 @@ QgsLegendSettings::QgsLegendSettings()
, mEqualColumnWidth( false ) , mEqualColumnWidth( false )
, mMmPerMapUnit( 1 ) , mMmPerMapUnit( 1 )
, mUseAdvancedEffects( true ) , mUseAdvancedEffects( true )
, mMapScale( 1 )
, mDpi( 96 ) // based on QImage's default DPI
{ {
rstyle( QgsComposerLegendStyle::Title ).setMargin( QgsComposerLegendStyle::Bottom, 2 ); rstyle( QgsComposerLegendStyle::Title ).setMargin( QgsComposerLegendStyle::Bottom, 2 );
rstyle( QgsComposerLegendStyle::Group ).setMargin( QgsComposerLegendStyle::Top, 2 ); rstyle( QgsComposerLegendStyle::Group ).setMargin( QgsComposerLegendStyle::Top, 2 );

View File

@ -94,6 +94,12 @@ class CORE_EXPORT QgsLegendSettings
bool useAdvancedEffects() const { return mUseAdvancedEffects; } bool useAdvancedEffects() const { return mUseAdvancedEffects; }
void setUseAdvancedEffects( bool use ) { mUseAdvancedEffects = use; } void setUseAdvancedEffects( bool use ) { mUseAdvancedEffects = use; }
double mapScale() const { return mMapScale; }
void setMapScale( double scale ) { mMapScale = scale; }
int dpi() const { return mDpi; }
void setDpi( int dpi ) { mDpi = dpi; }
// utility functions // utility functions
/** Splits a string using the wrap char taking into account handling empty /** Splits a string using the wrap char taking into account handling empty
@ -175,6 +181,12 @@ class CORE_EXPORT QgsLegendSettings
/** Whether to use advanced effects like transparency for symbols - may require their rasterization */ /** Whether to use advanced effects like transparency for symbols - may require their rasterization */
bool mUseAdvancedEffects; bool mUseAdvancedEffects;
/** Denominator of map's scale */
double mMapScale;
/** DPI to be used when rendering legend */
int mDpi;
}; };

View File

@ -283,9 +283,9 @@ QColor QgsSymbolV2::color() const
return QColor( 0, 0, 0 ); return QColor( 0, 0, 0 );
} }
void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size ) void QgsSymbolV2::drawPreviewIcon( QPainter* painter, QSize size, QgsRenderContext* customContext )
{ {
QgsRenderContext context = QgsSymbolLayerV2Utils::createRenderContext( painter ); QgsRenderContext context = customContext ? *customContext : QgsSymbolLayerV2Utils::createRenderContext( painter );
context.setForceVectorOutput( true ); context.setForceVectorOutput( true );
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, 0, mapUnitScale() ); QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, 0, 0, mapUnitScale() );

View File

@ -105,7 +105,10 @@ class CORE_EXPORT QgsSymbolV2
void setColor( const QColor& color ); void setColor( const QColor& color );
QColor color() const; QColor color() const;
void drawPreviewIcon( QPainter* painter, QSize size ); //! Draw icon of the symbol that occupyies area given by size using the painter.
//! Optionally custom context may be given in order to get rendering of symbols that use map units right.
//! @note customContext parameter added in 2.6
void drawPreviewIcon( QPainter* painter, QSize size, QgsRenderContext* customContext = 0 );
QImage bigSymbolPreviewImage(); QImage bigSymbolPreviewImage();