Skip to content
Permalink
Browse files

[FEATURE] Add option to map unit scaling for limiting size in mm

Previously only the option to limit the scale range of the scaling
was available. Now you can also choose to limit the corresponding
rendered size in mm.
  • Loading branch information
nyalldawson committed Sep 17, 2015
1 parent b693020 commit 586d59a43267c4d2af9783202aa6d3cd5694fd15
@@ -25,6 +25,15 @@ class QgsMapUnitScale
/** The maximum scale, or 0.0 if unset */
double maxScale;

/** Whether the minimum size in mm should be respected */
bool minSizeMMEnabled;
/** The minimum size in millimeters, or 0.0 if unset */
double minSizeMM;
/** Whether the maximum size in mm should be respected */
bool maxSizeMMEnabled;
/** The maximum size in millimeters, or 0.0 if unset */
double maxSizeMM;

/** Computes a map units per pixel scaling factor, respecting the minimum and maximum scales
* set for the object.
* @param c render context
@@ -311,8 +311,27 @@ class QgsSymbolLayerV2Utils
*/
static QColor parseColorWithAlpha( const QString colorStr, bool &containsAlpha, bool strictEval = false );

/** Returns the line width scale factor depending on the unit and the paint device*/
/** Returns the line width scale factor depending on the unit and the paint device.
* Consider using convertToPainterUnits() instead, as convertToPainterUnits() respects the size limits specified by the scale
* parameter.
* @param c render context
* @param u units to convert from
* @param scale map unit scale, specifying limits for the map units to convert from
* @see convertToPainterUnits()
*/
static double lineWidthScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale = QgsMapUnitScale() );

/** Converts a size from the specied units to painter units. The conversion respects the limits
* specified by the optional scale parameter.
* @param c render context
* @param size size to convert
* @param unit units for specified size
* @param scale map unit scale
* @note added in QGIS 2.12
* @see lineWidthScaleFactor
*/
static double convertToPainterUnits( const QgsRenderContext&c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale& scale = QgsMapUnitScale() );

/** Returns scale factor painter units -> pixel dimensions*/
static double pixelSizeScaleFactor( const QgsRenderContext& c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale& scale = QgsMapUnitScale() );
/** Returns scale factor painter units -> map units*/
@@ -321,7 +321,7 @@ QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, Ite
if ( QgsMarkerSymbolV2* markerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( s ) )
{
// allow marker symbol to occupy bigger area if necessary
size = markerSymbol->size() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, s->outputUnit(), s->mapUnitScale() ) / context.scaleFactor();
size = QgsSymbolLayerV2Utils::convertToPainterUnits( context, markerSymbol->size(), s->outputUnit(), s->mapUnitScale() ) / context.scaleFactor();
height = size;
width = size;
if ( width < settings.symbolSize().width() )
@@ -38,13 +38,29 @@ class CORE_EXPORT QgsMapUnitScale
* @param minScale minimum allowed scale, or 0.0 if no minimum scale set
* @param maxScale maximum allowed scale, or 0.0 if no maximum scale set
*/
QgsMapUnitScale( double minScale = 0.0, double maxScale = 0.0 ) : minScale( minScale ), maxScale( maxScale ) {}
QgsMapUnitScale( double minScale = 0.0, double maxScale = 0.0 )
: minScale( minScale )
, maxScale( maxScale )
, minSizeMMEnabled( false )
, minSizeMM( 0.0 )
, maxSizeMMEnabled( false )
, maxSizeMM( 0.0 )
{}

/** The minimum scale, or 0.0 if unset */
double minScale;
/** The maximum scale, or 0.0 if unset */
double maxScale;

/** Whether the minimum size in mm should be respected */
bool minSizeMMEnabled;
/** The minimum size in millimeters, or 0.0 if unset */
double minSizeMM;
/** Whether the maximum size in mm should be respected */
bool maxSizeMMEnabled;
/** The maximum size in millimeters, or 0.0 if unset */
double maxSizeMM;

/** Computes a map units per pixel scaling factor, respecting the minimum and maximum scales
* set for the object.
* @param c render context
@@ -67,12 +83,16 @@ class CORE_EXPORT QgsMapUnitScale

bool operator==( const QgsMapUnitScale& other ) const
{
return minScale == other.minScale && maxScale == other.maxScale;
return minScale == other.minScale && maxScale == other.maxScale
&& minSizeMMEnabled == other.minSizeMMEnabled
&& minSizeMM == other.minSizeMM
&& maxSizeMMEnabled == other.maxSizeMMEnabled
&& maxSizeMM == other.maxSizeMM;
}

bool operator!=( const QgsMapUnitScale& other ) const
{
return minScale != other.minScale || maxScale != other.maxScale;
return !operator==( other );
}
};

@@ -208,7 +208,7 @@ void QgsEllipseSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Rend
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) )
{
double width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH, context, mOutlineWidth ).toDouble();
width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit, mOutlineWidthMapUnitScale );
width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mOutlineWidthUnit, mOutlineWidthMapUnitScale );
mPen.setWidthF( width );
}
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE ) )
@@ -295,7 +295,7 @@ void QgsEllipseSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context )
}
mPen.setColor( mOutlineColor );
mPen.setStyle( mOutlineStyle );
mPen.setWidthF( mOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );
mBrush.setColor( mFillColor );
prepareExpressions( context );
}
@@ -476,7 +476,7 @@ void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV
{
*scaledWidth = width;
}
width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( ct, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
width = QgsSymbolLayerV2Utils::convertToPainterUnits( ct, width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );

double height = 0;
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_HEIGHT ) ) //1. priority: data defined setting on symbol layer level
@@ -495,7 +495,7 @@ void QgsEllipseSymbolLayerV2::preparePath( const QString& symbolName, QgsSymbolV
{
*scaledHeight = height;
}
height *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( ct, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
height = QgsSymbolLayerV2Utils::convertToPainterUnits( ct, height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );

if ( symbolName == "circle" )
{
@@ -103,7 +103,7 @@ void QgsSimpleFillSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderCon
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH_BORDER ) )
{
double width = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH_BORDER, context, mBorderWidth ).toDouble();
width *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mBorderWidthUnit, mBorderWidthMapUnitScale );
width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), width, mBorderWidthUnit, mBorderWidthMapUnitScale );
pen.setWidthF( width );
selPen.setWidthF( width );
}
@@ -247,7 +247,7 @@ void QgsSimpleFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context
mPen = QPen( borderColor );
mSelPen = QPen( selPenColor );
mPen.setStyle( mBorderStyle );
mPen.setWidthF( mBorderWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mBorderWidthUnit, mBorderWidthMapUnitScale ) );
mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mBorderWidth, mBorderWidthUnit, mBorderWidthMapUnitScale ) );
mPen.setJoinStyle( mPenJoinStyle );
prepareExpressions( context );
}
@@ -273,8 +273,8 @@ void QgsSimpleFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList<Q
QPointF offset;
if ( !mOffset.isNull() )
{
offset.setX( mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setX( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset );
}

@@ -831,8 +831,8 @@ void QgsGradientFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList
QPointF offset;
if ( !mOffset.isNull() )
{
offset.setX( mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setX( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset );
}

@@ -1118,8 +1118,8 @@ void QgsShapeburstFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QLi
QPointF offset;
if ( !mOffset.isNull() )
{
offset.setX( mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setX( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset );
}
_renderPolygon( p, points, rings, context );
@@ -1238,8 +1238,8 @@ void QgsShapeburstFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QLi
QPointF offset;
if ( !mOffset.isNull() )
{
offset.setX( mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setX( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset );
}

@@ -1888,7 +1888,7 @@ void QgsSVGFillSymbolLayer::applyPattern( QBrush& brush, const QString& svgFileP
else
{
bool fitsInCache = true;
double outlineWidth = svgOutlineWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), svgOutlineWidthUnit, svgOutlineWidthMapUnitScale );
double outlineWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), svgOutlineWidth, svgOutlineWidthUnit, svgOutlineWidthMapUnitScale );
const QImage& patternImage = QgsSvgCache::instance()->svgAsImage( svgFilePath, size, svgFillColor, svgOutlineColor, outlineWidth,
context.renderContext().scaleFactor(), context.renderContext().rasterScaleFactor(), fitsInCache );
if ( !fitsInCache )
@@ -3561,8 +3561,8 @@ void QgsRasterFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPo
QPointF offset;
if ( !mOffset.isNull() )
{
offset.setX( mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setX( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.x(), mOffsetUnit, mOffsetMapUnitScale ) );
offset.setY( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOffset.y(), mOffsetUnit, mOffsetMapUnitScale ) );
p->translate( offset );
}
if ( mCoordinateMode == Feature )
@@ -190,7 +190,7 @@ void QgsSimpleLineSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context
QColor penColor = mColor;
penColor.setAlphaF( mColor.alphaF() * context.alpha() );
mPen.setColor( penColor );
double scaledWidth = mWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit, mWidthMapUnitScale );
double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mWidth, mWidthUnit, mWidthMapUnitScale );
mPen.setWidthF( scaledWidth );
if ( mUseCustomDashPattern && scaledWidth != 0 )
{
@@ -211,7 +211,7 @@ void QgsSimpleLineSymbolLayerV2::startRender( QgsSymbolV2RenderContext& context
for ( ; it != mCustomDashVector.constEnd(); ++it )
{
//the dash is specified in terms of pen widths, therefore the division
scaledVector << ( *it ) * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
scaledVector << QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), ( *it ), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv;
}
mPen.setDashPattern( scaledVector );
}
@@ -321,7 +321,7 @@ void QgsSimpleLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSym
}
else
{
double scaledOffset = offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale );
double scaledOffset = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), offset, mOffsetUnit, mOffsetMapUnitScale );
QList<QPolygonF> mline = ::offsetLine( points, scaledOffset, context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );
for ( int part = 0; part < mline.count(); ++part )
p->drawPolyline( mline[ part ] );
@@ -457,7 +457,7 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::createFromSld( QDomElement &elemen

void QgsSimpleLineSymbolLayerV2::applySizeScale( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen )
{
double scaledWidth = mWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit, mWidthMapUnitScale );
double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mWidth, mWidthUnit, mWidthMapUnitScale );
pen.setWidthF( scaledWidth );
selPen.setWidthF( scaledWidth );
}
@@ -471,8 +471,9 @@ void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderCon
bool hasStrokeWidthExpression = false;
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH ) )
{
double scaledWidth = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mWidth ).toDouble()
* QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit, mWidthMapUnitScale );
double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(),
evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_WIDTH, context, mWidth ).toDouble(),
mWidthUnit, mWidthMapUnitScale );
pen.setWidthF( scaledWidth );
selPen.setWidthF( scaledWidth );
hasStrokeWidthExpression = true;
@@ -496,7 +497,7 @@ void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderCon
//dash dot vector
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_CUSTOMDASH ) )
{
double scaledWidth = mWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit, mWidthMapUnitScale );
double scaledWidth = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mWidth, mWidthUnit, mWidthMapUnitScale );
double dashWidthDiv = mPen.widthF();

if ( hasStrokeWidthExpression )
@@ -521,7 +522,7 @@ void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderCon
QStringList::const_iterator dashIt = dashList.constBegin();
for ( ; dashIt != dashList.constEnd(); ++dashIt )
{
dashVector.push_back( dashIt->toDouble() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
dashVector.push_back( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), dashIt->toDouble(), mCustomDashPatternUnit, mCustomDashPatternMapUnitScale ) / dashWidthDiv );
}
pen.setDashPattern( dashVector );
}
@@ -586,7 +587,7 @@ double QgsSimpleLineSymbolLayerV2::dxfWidth( const QgsDxfExport& e, const QgsSym
}
else if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
{
width = mWidth * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mWidthUnit, mWidthMapUnitScale );
width = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mWidth, mWidthUnit, mWidthMapUnitScale );
}

return width * e.mapUnitScaleFactor( e.symbologyScaleDenominator(), widthUnit(), e.mapUnits() );
@@ -854,7 +855,7 @@ void QgsMarkerLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSym
else
{
context.renderContext().setGeometry( 0 ); //always use segmented geometry with offset
QList<QPolygonF> mline = ::offsetLine( points, offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit, mOffsetMapUnitScale ), context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );
QList<QPolygonF> mline = ::offsetLine( points, QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), offset, mOffsetUnit, mOffsetMapUnitScale ), context.feature() ? context.feature()->constGeometry()->type() : QGis::Line );

for ( int part = 0; part < mline.count(); ++part )
{
@@ -920,8 +921,8 @@ void QgsMarkerLineSymbolLayerV2::renderPolylineInterval( const QPolygonF& points
offsetAlongLine = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_OFFSET_ALONG_LINE, context, mOffsetAlongLine ).toDouble();
}

double painterUnitInterval = interval * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
lengthLeft = painterUnitInterval - offsetAlongLine * QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mIntervalUnit, mIntervalMapUnitScale );
double painterUnitInterval = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, interval, mIntervalUnit, mIntervalMapUnitScale );
lengthLeft = painterUnitInterval - QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mIntervalUnit, mIntervalMapUnitScale );

for ( int i = 1; i < points.count(); ++i )
{
@@ -996,7 +997,7 @@ void QgsMarkerLineSymbolLayerV2::renderPolylineVertex( const QPolygonF& points,
if ( offsetAlongLine != 0 )
{
//scale offset along line
offsetAlongLine *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( rc, mOffsetAlongLineUnit, mOffsetAlongLineMapUnitScale );
offsetAlongLine = QgsSymbolLayerV2Utils::convertToPainterUnits( rc, offsetAlongLine, mOffsetAlongLineUnit, mOffsetAlongLineMapUnitScale );
}

if ( offsetAlongLine == 0 && context.renderContext().geometry()

0 comments on commit 586d59a

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