Skip to content

Commit

Permalink
Emit valid SLD when on screen mm are used
Browse files Browse the repository at this point in the history
SLD does not have a notion of on screen mm, rescale them to pixels to get an equivalent, more valid and more widely usable, output
  • Loading branch information
aaime authored and rldhont committed Sep 20, 2016
1 parent 5c4fd97 commit 2f268d4
Show file tree
Hide file tree
Showing 8 changed files with 505 additions and 33 deletions.
1 change: 0 additions & 1 deletion src/core/qgsmaplayer.cpp
Expand Up @@ -1462,7 +1462,6 @@ void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg )
// Create the root element
QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" );
root.setAttribute( "version", "1.1.0" );
root.setAttribute( "units", "mm" ); // default qgsmaprenderer is Millimeters
root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" );
root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
root.setAttribute( "xmlns:se", "http://www.opengis.net/se" );
Expand Down
19 changes: 13 additions & 6 deletions src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
Expand Up @@ -409,12 +409,9 @@ void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &el
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, mOutlineWidth, mSymbolWidth );

// store w/h factor in a <VendorOption>
double widthHeightFactor = mSymbolWidth / mSymbolHeight;
QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
graphicElem.appendChild( factorElem );
double outlineWidth = QgsSymbolLayerV2Utils::rescaleUom( mOutlineWidth, mOutlineWidthUnit, props );
double symbolWidth = QgsSymbolLayerV2Utils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, outlineWidth, symbolWidth );

// <Rotation>
QgsDataDefined* ddRotation = getDataDefinedProperty( QgsSymbolLayerV2::EXPR_ROTATION );
Expand Down Expand Up @@ -452,6 +449,16 @@ void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &el
}
}
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QPointF offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );

// store w/h factor in a <VendorOption>
double widthHeightFactor = mSymbolWidth / mSymbolHeight;
QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
graphicElem.appendChild( factorElem );
}

QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::createFromSld( QDomElement &element )
Expand Down
27 changes: 21 additions & 6 deletions src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Expand Up @@ -352,11 +352,13 @@ void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element,
// <Stroke>
QDomElement strokeElem = doc.createElement( "se:Stroke" );
symbolizerElem.appendChild( strokeElem );
QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, mBorderColor, mBorderWidth, &mPenJoinStyle );
double borderWidth = QgsSymbolLayerV2Utils::rescaleUom( mBorderWidth, mBorderWidthUnit, props );
QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, borderWidth, borderWidth, &mPenJoinStyle );
}

// <se:Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, mOffset );
QPointF offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, offset );
}

QString QgsSimpleFillSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
Expand Down Expand Up @@ -1778,6 +1780,7 @@ void QgsSVGFillSymbolLayer::setOutputUnit( QgsSymbolV2::OutputUnit unit )
mPatternWidthUnit = unit;
mSvgOutlineWidthUnit = unit;
mOutlineWidthUnit = unit;
mOutline->setOutputUnit( unit );
}

QgsSymbolV2::OutputUnit QgsSVGFillSymbolLayer::outputUnit() const
Expand Down Expand Up @@ -2088,7 +2091,8 @@ void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, cons

if ( !mSvgFilePath.isEmpty() )
{
QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mColor, mPatternWidth );
double partternWidth = QgsSymbolLayerV2Utils::rescaleUom( mPatternWidth, mPatternWidthUnit, props );
QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mColor, partternWidth );
}
else
{
Expand All @@ -2099,7 +2103,8 @@ void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, cons

if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
{
QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
double svgOutlineWidth = QgsSymbolLayerV2Utils::rescaleUom( mSvgOutlineWidth, mSvgOutlineWidthUnit, props );
QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, svgOutlineWidth );
}

// <Rotation>
Expand Down Expand Up @@ -2887,7 +2892,9 @@ void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &eleme
//line properties must be inside the graphic definition
QColor lineColor = mFillLineSymbol ? mFillLineSymbol->color() : QColor();
double lineWidth = mFillLineSymbol ? mFillLineSymbol->width() : 0.0;
QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, mDistance );
lineWidth = QgsSymbolLayerV2Utils::rescaleUom( lineWidth, mLineWidthUnit, props );
double distance = QgsSymbolLayerV2Utils::rescaleUom( mDistance, mDistanceUnit, props );
QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, distance );

// <Rotation>
QString angleFunc;
Expand All @@ -2905,6 +2912,7 @@ void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &eleme

// <se:Displacement>
QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
lineOffset = QgsSymbolLayerV2Utils::rescaleUom( lineOffset, mOffsetUnit, props );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
}

Expand Down Expand Up @@ -3064,6 +3072,11 @@ void QgsPointPatternFillSymbolLayer::setOutputUnit( QgsSymbolV2::OutputUnit unit
mDistanceYUnit = unit;
mDisplacementXUnit = unit;
mDisplacementYUnit = unit;
if ( mMarkerSymbol )
{
mMarkerSymbol->setOutputUnit( unit );
}

}

QgsSymbolV2::OutputUnit QgsPointPatternFillSymbolLayer::outputUnit() const
Expand Down Expand Up @@ -3306,7 +3319,9 @@ void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &elem
fillElem.appendChild( graphicFillElem );

// store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
QString dist = QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
double dx = QgsSymbolLayerV2Utils::rescaleUom( mDistanceX, mDistanceXUnit, props );
double dy = QgsSymbolLayerV2Utils::rescaleUom( mDistanceY, mDistanceYUnit, props );
QString dist = QgsSymbolLayerV2Utils::encodePoint( QPointF( dx, dy ) );
QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
symbolizerElem.appendChild( distanceElem );

Expand Down
16 changes: 11 additions & 5 deletions src/core/symbology-ng/qgslinesymbollayerv2.cpp
Expand Up @@ -410,14 +410,17 @@ void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element,
symbolizerElem.appendChild( strokeElem );

Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
&mPenJoinStyle, &mPenCapStyle, &mCustomDashVector );
double width = QgsSymbolLayerV2Utils::rescaleUom( mWidth, mWidthUnit, props );
QVector<qreal> customDashVector = QgsSymbolLayerV2Utils::rescaleUom( mCustomDashVector, mCustomDashPatternUnit, props );
QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, width,
&mPenJoinStyle, &mPenCapStyle, &customDashVector );

// <se:PerpendicularOffset>
if ( !qgsDoubleNear( mOffset, 0.0 ) )
{
QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( mOffset ) ) );
double offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
symbolizerElem.appendChild( perpOffsetElem );
}
}
Expand Down Expand Up @@ -1413,7 +1416,8 @@ void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element,
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
break;
default:
gap = qgsDoubleToString( mInterval );
double interval = QgsSymbolLayerV2Utils::rescaleUom( mInterval, mIntervalUnit, props );
gap = qgsDoubleToString( interval );
break;
}

Expand Down Expand Up @@ -1453,7 +1457,8 @@ void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element,
if ( !qgsDoubleNear( mOffset, 0.0 ) )
{
QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( mOffset ) ) );
double offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
symbolizerElem.appendChild( perpOffsetElem );
}
}
Expand Down Expand Up @@ -1554,6 +1559,7 @@ double QgsMarkerLineSymbolLayerV2::width() const
void QgsMarkerLineSymbolLayerV2::setOutputUnit( QgsSymbolV2::OutputUnit unit )
{
QgsLineSymbolLayerV2::setOutputUnit( unit );
mMarker->setOutputUnit( unit );
mIntervalUnit = unit;
mOffsetUnit = unit;
mOffsetAlongLineUnit = unit;
Expand Down
18 changes: 13 additions & 5 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Expand Up @@ -1123,7 +1123,9 @@ void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElemen
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mBorderColor, mOutlineStyle, mOutlineWidth, mSize );
double outlineWidth = QgsSymbolLayerV2Utils::rescaleUom( mOutlineWidth, mOutlineWidthUnit, props );
double size = QgsSymbolLayerV2Utils::rescaleUom( mSize, mSizeUnit, props );
QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mBorderColor, mOutlineStyle, outlineWidth, size );

// <Rotation>
QString angleFunc;
Expand All @@ -1140,7 +1142,8 @@ void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElemen
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
QPointF offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
}

QString QgsSimpleMarkerSymbolLayerV2::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
Expand Down Expand Up @@ -2225,7 +2228,8 @@ void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
double size = QgsSymbolLayerV2Utils::rescaleUom( mSize, mSizeUnit, props );
QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, size );

// <Rotation>
QString angleFunc;
Expand All @@ -2243,7 +2247,8 @@ void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
QPointF offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
}

QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element )
Expand Down Expand Up @@ -2848,6 +2853,8 @@ void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement
QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
int markIndex = mChr.unicode();
QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
double size = QgsSymbolLayerV2Utils::rescaleUom( mSize, mSizeUnit, props );
QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, size );

// <Rotation>
QString angleFunc;
Expand All @@ -2864,7 +2871,8 @@ void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
QPointF offset = QgsSymbolLayerV2Utils::rescaleUom( mOffset, mOffsetUnit, props );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, offset );
}

QRectF QgsFontMarkerSymbolLayerV2::bounds( QPointF point, QgsSymbolV2RenderContext& context )
Expand Down
79 changes: 78 additions & 1 deletion src/core/symbology-ng/qgssymbollayerv2utils.cpp
Expand Up @@ -455,7 +455,7 @@ QString QgsSymbolLayerV2Utils::encodeSldUom( QgsSymbolV2::OutputUnit unit, doubl
// pixel is the SLD default uom. The "standardized rendering pixel
// size" is defined to be 0.28mm × 0.28mm (millimeters).
if ( scaleFactor )
*scaleFactor = 0.28; // from millimeters to pixels
*scaleFactor = 1 / 0.28; // from millimeters to pixels

// http://www.opengeospatial.org/sld/units/pixel
return QString();
Expand Down Expand Up @@ -4081,3 +4081,80 @@ QList<double> QgsSymbolLayerV2Utils::prettyBreaks( double minimum, double maximu

return breaks;
}

double QgsSymbolLayerV2Utils::rescaleUom( double size, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props )
{
double scale = 1;
bool roundToUnit = false;
if ( unit == QgsUnitTypes::RenderUnknownUnit )
{
if ( props.contains( "uomScale" ) )
{
bool ok;
scale = props.value( "uomScale" ).toDouble( &ok );
if ( !ok )
{
return size;
}
}
}
else
{
if ( props.value( "uom" ) == "http://www.opengeospatial.org/se/units/metre" )
{
switch ( unit )
{
case QgsUnitTypes::RenderMillimeters:
scale = 0.001;
break;
case QgsUnitTypes::RenderPixels:
scale = 0.00028;
roundToUnit = true;
break;
default:
scale = 1;
}
}
else
{
// target is pixels
switch ( unit )
{
case QgsUnitTypes::RenderMillimeters:
scale = 1 / 0.28;
roundToUnit = true;
break;
// we don't have a good case for map units, as pixel values won't change based on zoom
default:
scale = 1;
}
}

}
double rescaled = size * scale;
// round to unit if the result is pixels to avoid a weird looking SLD (people often think
// of pixels as integers, even if SLD allows for float values in there
if ( roundToUnit )
{
rescaled = qRound( rescaled );
}
return rescaled;
}

QPointF QgsSymbolLayerV2Utils::rescaleUom( const QPointF& point, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props )
{
double x = rescaleUom( point.x(), unit, props );
double y = rescaleUom( point.y(), unit, props );
return QPointF( x, y );
}

QVector<qreal> QgsSymbolLayerV2Utils::rescaleUom( const QVector<qreal>& array, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props )
{
QVector<qreal> result;
QVector<qreal>::const_iterator it = array.constBegin();
for ( ; it != array.constEnd(); ++it )
{
result.append( rescaleUom( *it, unit, props ) );
}
return result;
}
22 changes: 22 additions & 0 deletions src/core/symbology-ng/qgssymbollayerv2utils.h
Expand Up @@ -479,6 +479,28 @@ class CORE_EXPORT QgsSymbolLayerV2Utils
*/
static QList<double> prettyBreaks( double minimum, double maximum, int classes );

/** Rescales the given size based on the uomScale found in the props, if any is found, otherwise
* returns the value un-modified
* @note added in 3.0
* @note not available in Python bindings
*/
static double rescaleUom( double size, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props );

/** Rescales the given point based on the uomScale found in the props, if any is found, otherwise
* returns a copy of the original point
* @note added in 3.0
* @note not available in Python bindings
*/
static QPointF rescaleUom( const QPointF& point, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props );

/** Rescales the given array based on the uomScale found in the props, if any is found, otherwise
* returns a copy of the original point
* @note added in 3.0
* @note not available in Python bindings
*/
static QVector<qreal> rescaleUom( const QVector<qreal>& array, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props );


};

class QPolygonF;
Expand Down

0 comments on commit 2f268d4

Please sign in to comment.