mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Emit valid SLD when on screen mm are used
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
This commit is contained in:
parent
ee87b0dbc9
commit
a0adcc22e7
@ -1429,7 +1429,6 @@ void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
|
||||
// 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" );
|
||||
|
@ -409,12 +409,9 @@ void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &elem
|
||||
QDomElement graphicElem = doc.createElement( "se:Graphic" );
|
||||
element.appendChild( graphicElem );
|
||||
|
||||
QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, mOutlineWidth, mSymbolWidth );
|
||||
|
||||
// store w/h factor in a <VendorOption>
|
||||
double widthHeightFactor = mSymbolWidth / mSymbolHeight;
|
||||
QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
|
||||
graphicElem.appendChild( factorElem );
|
||||
double outlineWidth = QgsSymbolLayerUtils::rescaleUom( mOutlineWidth, mOutlineWidthUnit, props );
|
||||
double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
|
||||
QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mColor, mOutlineColor, mOutlineStyle, outlineWidth, symbolWidth );
|
||||
|
||||
// <Rotation>
|
||||
QgsDataDefined* ddRotation = getDataDefinedProperty( QgsSymbolLayer::EXPR_ROTATION );
|
||||
@ -452,6 +449,15 @@ void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &elem
|
||||
}
|
||||
}
|
||||
QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
|
||||
|
||||
// <Displacement>
|
||||
QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
|
||||
|
||||
// store w/h factor in a <VendorOption>
|
||||
double widthHeightFactor = mSymbolWidth / mSymbolHeight;
|
||||
QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
|
||||
graphicElem.appendChild( factorElem );
|
||||
}
|
||||
|
||||
QgsSymbolLayer* QgsEllipseSymbolLayer::createFromSld( QDomElement &element )
|
||||
|
@ -352,11 +352,13 @@ void QgsSimpleFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, c
|
||||
// <Stroke>
|
||||
QDomElement strokeElem = doc.createElement( "se:Stroke" );
|
||||
symbolizerElem.appendChild( strokeElem );
|
||||
QgsSymbolLayerUtils::lineToSld( doc, strokeElem, mBorderStyle, mBorderColor, mBorderWidth, &mPenJoinStyle );
|
||||
double borderWidth = QgsSymbolLayerUtils::rescaleUom( mBorderWidth, mBorderWidthUnit, props );
|
||||
QgsSymbolLayerUtils::lineToSld( doc, strokeElem, mBorderStyle, borderWidth, borderWidth, &mPenJoinStyle );
|
||||
}
|
||||
|
||||
// <se:Displacement>
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, symbolizerElem, mOffset );
|
||||
QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, symbolizerElem, offset );
|
||||
}
|
||||
|
||||
QString QgsSimpleFillSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
|
||||
@ -1778,6 +1780,7 @@ void QgsSVGFillSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
|
||||
mPatternWidthUnit = unit;
|
||||
mSvgOutlineWidthUnit = unit;
|
||||
mOutlineWidthUnit = unit;
|
||||
mOutline->setOutputUnit( unit );
|
||||
}
|
||||
|
||||
QgsUnitTypes::RenderUnit QgsSVGFillSymbolLayer::outputUnit() const
|
||||
@ -2088,7 +2091,8 @@ void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, cons
|
||||
|
||||
if ( !mSvgFilePath.isEmpty() )
|
||||
{
|
||||
QgsSymbolLayerUtils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mColor, mPatternWidth );
|
||||
double partternWidth = QgsSymbolLayerUtils::rescaleUom( mPatternWidth, mPatternWidthUnit, props );
|
||||
QgsSymbolLayerUtils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mColor, partternWidth );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2099,7 +2103,8 @@ void QgsSVGFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, cons
|
||||
|
||||
if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
|
||||
{
|
||||
QgsSymbolLayerUtils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
|
||||
double svgOutlineWidth = QgsSymbolLayerUtils::rescaleUom( mSvgOutlineWidth, mSvgOutlineWidthUnit, props );
|
||||
QgsSymbolLayerUtils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, svgOutlineWidth );
|
||||
}
|
||||
|
||||
// <Rotation>
|
||||
@ -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;
|
||||
QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, mDistance );
|
||||
lineWidth = QgsSymbolLayerUtils::rescaleUom( lineWidth, mLineWidthUnit, props );
|
||||
double distance = QgsSymbolLayerUtils::rescaleUom( mDistance, mDistanceUnit, props );
|
||||
QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), lineColor, Qt::SolidLine, lineWidth, distance );
|
||||
|
||||
// <Rotation>
|
||||
QString angleFunc;
|
||||
@ -2905,6 +2912,7 @@ void QgsLinePatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &eleme
|
||||
|
||||
// <se:Displacement>
|
||||
QPointF lineOffset( sin( mLineAngle ) * mOffset, cos( mLineAngle ) * mOffset );
|
||||
lineOffset = QgsSymbolLayerUtils::rescaleUom( lineOffset, mOffsetUnit, props );
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, lineOffset );
|
||||
}
|
||||
|
||||
@ -3064,6 +3072,11 @@ void QgsPointPatternFillSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit uni
|
||||
mDistanceYUnit = unit;
|
||||
mDisplacementXUnit = unit;
|
||||
mDisplacementYUnit = unit;
|
||||
if ( mMarkerSymbol )
|
||||
{
|
||||
mMarkerSymbol->setOutputUnit( unit );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QgsUnitTypes::RenderUnit QgsPointPatternFillSymbolLayer::outputUnit() const
|
||||
@ -3306,7 +3319,9 @@ void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &elem
|
||||
fillElem.appendChild( graphicFillElem );
|
||||
|
||||
// store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
|
||||
QString dist = QgsSymbolLayerUtils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
|
||||
double dx = QgsSymbolLayerUtils::rescaleUom( mDistanceX, mDistanceXUnit, props );
|
||||
double dy = QgsSymbolLayerUtils::rescaleUom( mDistanceY, mDistanceYUnit, props );
|
||||
QString dist = QgsSymbolLayerUtils::encodePoint( QPointF( dx, dy ) );
|
||||
QDomElement distanceElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, "distance", dist );
|
||||
symbolizerElem.appendChild( distanceElem );
|
||||
|
||||
|
@ -410,14 +410,17 @@ void QgsSimpleLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, c
|
||||
symbolizerElem.appendChild( strokeElem );
|
||||
|
||||
Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
|
||||
QgsSymbolLayerUtils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
|
||||
&mPenJoinStyle, &mPenCapStyle, &mCustomDashVector );
|
||||
double width = QgsSymbolLayerUtils::rescaleUom( mWidth, mWidthUnit, props );
|
||||
QVector<qreal> customDashVector = QgsSymbolLayerUtils::rescaleUom( mCustomDashVector, mCustomDashPatternUnit, props );
|
||||
QgsSymbolLayerUtils::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 = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
|
||||
symbolizerElem.appendChild( perpOffsetElem );
|
||||
}
|
||||
}
|
||||
@ -1413,7 +1416,8 @@ void QgsMarkerLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, c
|
||||
symbolizerElem.appendChild( QgsSymbolLayerUtils::createVendorOptionElement( doc, "placement", "points" ) );
|
||||
break;
|
||||
default:
|
||||
gap = qgsDoubleToString( mInterval );
|
||||
double interval = QgsSymbolLayerUtils::rescaleUom( mInterval, mIntervalUnit, props );
|
||||
gap = qgsDoubleToString( interval );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1453,7 +1457,8 @@ void QgsMarkerLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, c
|
||||
if ( !qgsDoubleNear( mOffset, 0.0 ) )
|
||||
{
|
||||
QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
|
||||
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( mOffset ) ) );
|
||||
double offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
perpOffsetElem.appendChild( doc.createTextNode( qgsDoubleToString( offset ) ) );
|
||||
symbolizerElem.appendChild( perpOffsetElem );
|
||||
}
|
||||
}
|
||||
@ -1554,6 +1559,7 @@ double QgsMarkerLineSymbolLayer::width() const
|
||||
void QgsMarkerLineSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
|
||||
{
|
||||
QgsLineSymbolLayer::setOutputUnit( unit );
|
||||
mMarker->setOutputUnit( unit );
|
||||
mIntervalUnit = unit;
|
||||
mOffsetUnit = unit;
|
||||
mOffsetAlongLineUnit = unit;
|
||||
|
@ -1122,7 +1122,9 @@ void QgsSimpleMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement
|
||||
QDomElement graphicElem = doc.createElement( "se:Graphic" );
|
||||
element.appendChild( graphicElem );
|
||||
|
||||
QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mBorderColor, mOutlineStyle, mOutlineWidth, mSize );
|
||||
double outlineWidth = QgsSymbolLayerUtils::rescaleUom( mOutlineWidth, mOutlineWidthUnit, props );
|
||||
double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
|
||||
QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mBorderColor, mOutlineStyle, outlineWidth, size );
|
||||
|
||||
// <Rotation>
|
||||
QString angleFunc;
|
||||
@ -1139,7 +1141,8 @@ void QgsSimpleMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement
|
||||
QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
|
||||
|
||||
// <Displacement>
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, mOffset );
|
||||
QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
|
||||
}
|
||||
|
||||
QString QgsSimpleMarkerSymbolLayer::ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const
|
||||
@ -2223,7 +2226,8 @@ void QgsSvgMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &el
|
||||
QDomElement graphicElem = doc.createElement( "se:Graphic" );
|
||||
element.appendChild( graphicElem );
|
||||
|
||||
QgsSymbolLayerUtils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, mSize );
|
||||
double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
|
||||
QgsSymbolLayerUtils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mColor, size );
|
||||
|
||||
// <Rotation>
|
||||
QString angleFunc;
|
||||
@ -2241,7 +2245,8 @@ void QgsSvgMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &el
|
||||
QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
|
||||
|
||||
// <Displacement>
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, mOffset );
|
||||
QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
|
||||
}
|
||||
|
||||
QgsSymbolLayer* QgsSvgMarkerSymbolLayer::createFromSld( QDomElement &element )
|
||||
@ -2844,7 +2849,8 @@ void QgsFontMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &e
|
||||
|
||||
QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
|
||||
int markIndex = mChr.unicode();
|
||||
QgsSymbolLayerUtils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );
|
||||
double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
|
||||
QgsSymbolLayerUtils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, size );
|
||||
|
||||
// <Rotation>
|
||||
QString angleFunc;
|
||||
@ -2861,7 +2867,8 @@ void QgsFontMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &e
|
||||
QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
|
||||
|
||||
// <Displacement>
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, mOffset );
|
||||
QPointF offset = QgsSymbolLayerUtils::rescaleUom( mOffset, mOffsetUnit, props );
|
||||
QgsSymbolLayerUtils::createDisplacementElement( doc, graphicElem, offset );
|
||||
}
|
||||
|
||||
QRectF QgsFontMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext& context )
|
||||
|
@ -421,7 +421,7 @@ QString QgsSymbolLayerUtils::encodeSldUom( QgsUnitTypes::RenderUnit unit, double
|
||||
// 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();
|
||||
@ -3923,3 +3923,80 @@ QList<double> QgsSymbolLayerUtils::prettyBreaks( double minimum, double maximum,
|
||||
|
||||
return breaks;
|
||||
}
|
||||
|
||||
double QgsSymbolLayerUtils::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 QgsSymbolLayerUtils::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> QgsSymbolLayerUtils::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;
|
||||
}
|
||||
|
@ -500,6 +500,28 @@ class CORE_EXPORT QgsSymbolLayerUtils
|
||||
*/
|
||||
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;
|
||||
|
@ -28,10 +28,15 @@ import qgis # NOQA
|
||||
import os
|
||||
|
||||
from qgis.PyQt.QtCore import pyqtWrapperType, Qt, QDir, QFile, QIODevice, QPointF
|
||||
from qgis.PyQt.QtXml import (QDomDocument, QDomElement)
|
||||
from qgis.PyQt.QtXml import (
|
||||
QDomDocument, QDomElement, QDomNode, QDomNamedNodeMap)
|
||||
from qgis.PyQt.QtGui import QColor
|
||||
|
||||
from qgis.core import QgsSimpleMarkerSymbolLayer
|
||||
from qgis.core import (
|
||||
QgsSimpleMarkerSymbolLayer, QgsUnitTypes, QgsSvgMarkerSymbolLayer,
|
||||
QgsFontMarkerSymbolLayer, QgsEllipseSymbolLayer, QgsSimpleLineSymbolLayer,
|
||||
QgsMarkerLineSymbolLayer, QgsMarkerSymbol, QgsSimpleFillSymbolLayer, QgsSVGFillSymbolLayer,
|
||||
QgsLinePatternFillSymbolLayer, QgsPointPatternFillSymbolLayer)
|
||||
from qgis.testing import start_app, unittest
|
||||
from utilities import unitTestDataPath
|
||||
|
||||
@ -46,22 +51,355 @@ class TestQgsSymbolLayerCreateSld(unittest.TestCase):
|
||||
This class tests the creation of SLD from QGis layers
|
||||
"""
|
||||
|
||||
def testSimpleMarkerSymbolLayer(self):
|
||||
def testSimpleMarkerRotation(self):
|
||||
symbol = QgsSimpleMarkerSymbolLayer(
|
||||
'star', QColor(255, 0, 0), QColor(0, 255, 0), 10)
|
||||
symbol.setAngle(50)
|
||||
dom = QDomDocument()
|
||||
root = dom.createElement("FakeRoot")
|
||||
dom.appendChild(root)
|
||||
symbol.toSld(dom, root, {})
|
||||
# print "This is the dom: " + dom.toString()
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print( "Simple marker rotation: " + root.ownerDocument().toString())
|
||||
|
||||
self.assertStaticRotation(root, '50')
|
||||
|
||||
def assertStaticRotation(self, root, expectedValue):
|
||||
# Check the rotation element is a literal, not a
|
||||
rotation = root.elementsByTagName('se:Rotation').item(0)
|
||||
literal = rotation.firstChild()
|
||||
self.assertEquals("ogc:Literal", literal.nodeName())
|
||||
self.assertEquals('50', literal.firstChild().nodeValue())
|
||||
self.assertEquals(expectedValue, literal.firstChild().nodeValue())
|
||||
|
||||
def assertStaticDisplacement(self, root, expectedDispX, expectedDispY):
|
||||
displacement = root.elementsByTagName('se:Displacement').item(0)
|
||||
self.assertIsNotNone(displacement)
|
||||
dx = displacement.firstChild()
|
||||
self.assertIsNotNone(dx)
|
||||
self.assertEquals("se:DisplacementX", dx.nodeName())
|
||||
self.assertSldNumber(expectedDispX, dx.firstChild().nodeValue())
|
||||
dy = displacement.lastChild()
|
||||
self.assertIsNotNone(dy)
|
||||
self.assertEquals("se:DisplacementY", dy.nodeName())
|
||||
self.assertSldNumber(expectedDispY, dy.firstChild().nodeValue())
|
||||
|
||||
def assertSldNumber(self, expected, stringValue):
|
||||
value = float(stringValue)
|
||||
self.assertFloatEquals(expected, value, 0.01)
|
||||
|
||||
def assertFloatEquals(self, expected, actual, tol):
|
||||
self.assertLess(abs(expected - actual), tol)
|
||||
|
||||
def testSimpleMarkerUnitDefault(self):
|
||||
symbol = QgsSimpleMarkerSymbolLayer(
|
||||
'star', QColor(255, 0, 0), QColor(0, 255, 0), 10)
|
||||
symbol.setOutlineWidth(3)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print("Simple marker unit mm: " + root.ownerDocument().toString())
|
||||
|
||||
# Check the size has been rescaled to pixels
|
||||
self.assertStaticSize(root, '36')
|
||||
|
||||
# Check the same happened to the outline width
|
||||
self.assertStrokeWidth(root, 2, 11)
|
||||
self.assertStaticDisplacement(root, 18, 36)
|
||||
|
||||
def assertStrokeWidth(self, root, svgParameterIdx, expectedWidth):
|
||||
strokeWidth = root.elementsByTagName(
|
||||
'se:SvgParameter').item(svgParameterIdx)
|
||||
svgParameterName = strokeWidth.attributes().namedItem('name')
|
||||
self.assertEquals("stroke-width", svgParameterName.nodeValue())
|
||||
self.assertSldNumber(
|
||||
expectedWidth, strokeWidth.firstChild().nodeValue())
|
||||
|
||||
def testSimpleMarkerUnitPixels(self):
|
||||
symbol = QgsSimpleMarkerSymbolLayer(
|
||||
'star', QColor(255, 0, 0), QColor(0, 255, 0), 10)
|
||||
symbol.setOutlineWidth(3)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print("Marker unit mm: " + root.ownerDocument().toString())
|
||||
|
||||
# Check the size has not been rescaled
|
||||
self.assertStaticSize(root, '10')
|
||||
|
||||
# Check the same happened to the outline width
|
||||
self.assertStrokeWidth(root, 2, 3)
|
||||
self.assertStaticDisplacement(root, 5, 10)
|
||||
|
||||
def testSvgMarkerUnitDefault(self):
|
||||
symbol = QgsSvgMarkerSymbolLayer('symbols/star.svg', 10, 90)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print("Svg marker mm: " + dom.toString())
|
||||
|
||||
# Check the size has been rescaled
|
||||
self.assertStaticSize(root, '36')
|
||||
|
||||
# Check rotation for good measure
|
||||
self.assertStaticRotation(root, '90')
|
||||
self.assertStaticDisplacement(root, 18, 36)
|
||||
|
||||
def testSvgMarkerUnitPixels(self):
|
||||
symbol = QgsSvgMarkerSymbolLayer('symbols/star.svg', 10, 0)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print("Svg marker unit px: " + dom.toString())
|
||||
|
||||
# Check the size has not been rescaled
|
||||
self.assertStaticSize(root, '10')
|
||||
self.assertStaticDisplacement(root, 5, 10)
|
||||
|
||||
def testFontMarkerUnitDefault(self):
|
||||
symbol = QgsFontMarkerSymbolLayer('sans', ',', 10, QColor('black'), 45)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print "Font marker unit mm: " + dom.toString()
|
||||
|
||||
# Check the size has been rescaled
|
||||
self.assertStaticSize(root, '36')
|
||||
self.assertStaticRotation(root, '45')
|
||||
self.assertStaticDisplacement(root, 18, 36)
|
||||
|
||||
def testFontMarkerUnitPixel(self):
|
||||
symbol = QgsFontMarkerSymbolLayer('sans', ',', 10, QColor('black'), 45)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Font marker unit mm: " + dom.toString())
|
||||
|
||||
# Check the size has been rescaled
|
||||
self.assertStaticSize(root, '10')
|
||||
self.assertStaticRotation(root, '45')
|
||||
self.assertStaticDisplacement(root, 5, 10)
|
||||
|
||||
def createEllipseSymbolLayer(self):
|
||||
# No way to build it programmatically...
|
||||
mTestName = 'QgsEllipseSymbolLayer'
|
||||
mFilePath = QDir.toNativeSeparators(
|
||||
'%s/symbol_layer/%s.sld' % (unitTestDataPath(), mTestName))
|
||||
|
||||
mDoc = QDomDocument(mTestName)
|
||||
mFile = QFile(mFilePath)
|
||||
mFile.open(QIODevice.ReadOnly)
|
||||
mDoc.setContent(mFile, True)
|
||||
mFile.close()
|
||||
mSymbolLayer = QgsEllipseSymbolLayer.createFromSld(
|
||||
mDoc.elementsByTagName('PointSymbolizer').item(0).toElement())
|
||||
return mSymbolLayer
|
||||
|
||||
def testEllipseMarkerUnitDefault(self):
|
||||
symbol = self.createEllipseSymbolLayer()
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderMillimeters)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Ellipse marker unit mm: " + dom.toString())
|
||||
|
||||
# Check the size has been rescaled
|
||||
self.assertStaticSize(root, '25')
|
||||
# Check also the stroke width
|
||||
self.assertStrokeWidth(root, 2, 4)
|
||||
self.assertStaticDisplacement(root, 18, 36)
|
||||
|
||||
def testEllipseMarkerUnitPixel(self):
|
||||
symbol = self.createEllipseSymbolLayer()
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Ellipse marker unit mm: " + dom.toString())
|
||||
|
||||
# Check the size has been rescaled
|
||||
self.assertStaticSize(root, '7')
|
||||
# Check also the stroke width
|
||||
self.assertStrokeWidth(root, 2, 1)
|
||||
self.assertStaticDisplacement(root, 5, 10)
|
||||
|
||||
def testSimpleLineUnitDefault(self):
|
||||
symbol = QgsSimpleLineSymbolLayer(QColor("black"), 1)
|
||||
symbol.setCustomDashVector([10, 10])
|
||||
symbol.setUseCustomDashPattern(True)
|
||||
symbol.setOffset(5)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
|
||||
# print ("Simple line px: \n" + dom.toString())
|
||||
|
||||
self.assertStrokeWidth(root, 1, 4)
|
||||
self.assertDashPattern(root, 4, '36 36')
|
||||
self.assertStaticPerpendicularOffset(root, '18')
|
||||
|
||||
def testSimpleLineUnitPixel(self):
|
||||
symbol = QgsSimpleLineSymbolLayer(QColor("black"), 1)
|
||||
symbol.setCustomDashVector([10, 10])
|
||||
symbol.setUseCustomDashPattern(True)
|
||||
symbol.setOffset(5)
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
|
||||
# print ("Simple line px: \n" + dom.toString())
|
||||
|
||||
self.assertStrokeWidth(root, 1, 1)
|
||||
self.assertDashPattern(root, 4, '10 10')
|
||||
self.assertStaticPerpendicularOffset(root, '5')
|
||||
|
||||
def testMarkLineUnitDefault(self):
|
||||
symbol = QgsMarkerLineSymbolLayer()
|
||||
symbol.setSubSymbol(
|
||||
QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '3'}))
|
||||
symbol.setInterval(5)
|
||||
symbol.setOffset(5)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
|
||||
# print ("Mark line mm: \n" + dom.toString())
|
||||
|
||||
# size of the mark
|
||||
self.assertStaticSize(root, '11')
|
||||
# gap and offset
|
||||
self.assertStaticGap(root, '18')
|
||||
self.assertStaticPerpendicularOffset(root, '18')
|
||||
|
||||
def testMarkLineUnitPixels(self):
|
||||
symbol = QgsMarkerLineSymbolLayer()
|
||||
symbol.setSubSymbol(
|
||||
QgsMarkerSymbol.createSimple({'color': '#ffffff', 'size': '3'}))
|
||||
symbol.setInterval(5)
|
||||
symbol.setOffset(5)
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
|
||||
# print ("Mark line px: \n" + dom.toString())
|
||||
|
||||
# size of the mark
|
||||
self.assertStaticSize(root, '3')
|
||||
# gap and offset
|
||||
self.assertStaticGap(root, '5')
|
||||
self.assertStaticPerpendicularOffset(root, '5')
|
||||
|
||||
def testSimpleFillDefault(self):
|
||||
symbol = QgsSimpleFillSymbolLayer(
|
||||
QColor('red'), Qt.SolidPattern, QColor('green'), Qt.SolidLine, 5)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
|
||||
# print ("Simple fill mm: \n" + dom.toString())
|
||||
|
||||
self.assertStrokeWidth(root, 2, 18)
|
||||
self.assertStaticDisplacement(root, 18, 36)
|
||||
|
||||
def testSimpleFillPixels(self):
|
||||
symbol = QgsSimpleFillSymbolLayer(
|
||||
QColor('red'), Qt.SolidPattern, QColor('green'), Qt.SolidLine, 5)
|
||||
symbol.setOffset(QPointF(5, 10))
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ( "Simple fill px: \n" + dom.toString())
|
||||
|
||||
self.assertStrokeWidth(root, 2, 5)
|
||||
self.assertStaticDisplacement(root, 5, 10)
|
||||
|
||||
def testSvgFillDefault(self):
|
||||
symbol = QgsSVGFillSymbolLayer('test/star.svg', 10, 45)
|
||||
symbol.setSvgOutlineWidth(3)
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Svg fill mm: \n" + dom.toString())
|
||||
|
||||
self.assertStaticRotation(root, '45')
|
||||
self.assertStaticSize(root, '36')
|
||||
# width of the svg outline
|
||||
self.assertStrokeWidth(root, 1, 11)
|
||||
# width of the polygon outline
|
||||
self.assertStrokeWidth(root, 3, 1)
|
||||
|
||||
def testSvgFillPixel(self):
|
||||
symbol = QgsSVGFillSymbolLayer('test/star.svg', 10, 45)
|
||||
symbol.setSvgOutlineWidth(3)
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Svg fill px: \n" + dom.toString())
|
||||
|
||||
self.assertStaticRotation(root, '45')
|
||||
self.assertStaticSize(root, '10')
|
||||
# width of the svg outline
|
||||
self.assertStrokeWidth(root, 1, 3)
|
||||
# width of the polygon outline
|
||||
self.assertStrokeWidth(root, 3, 0.26)
|
||||
|
||||
def testLineFillDefault(self):
|
||||
symbol = QgsLinePatternFillSymbolLayer()
|
||||
symbol.setLineAngle(45)
|
||||
symbol.setLineWidth(1)
|
||||
symbol.setOffset(5)
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Line fill mm: \n" + dom.toString())
|
||||
|
||||
self.assertStaticRotation(root, '45')
|
||||
self.assertStrokeWidth(root, 1, 4)
|
||||
self.assertStaticSize(root, '18')
|
||||
self.assertStaticDisplacement(root, 15, 9)
|
||||
|
||||
def testLineFillPixels(self):
|
||||
symbol = QgsLinePatternFillSymbolLayer()
|
||||
symbol.setLineAngle(45)
|
||||
symbol.setLineWidth(1)
|
||||
symbol.setOffset(5)
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Line fill px: \n" + dom.toString())
|
||||
|
||||
self.assertStaticRotation(root, '45')
|
||||
self.assertStrokeWidth(root, 1, 1)
|
||||
self.assertStaticSize(root, '5')
|
||||
self.assertStaticDisplacement(root, 4.25, 2.63)
|
||||
|
||||
def testPointFillDefault(self):
|
||||
symbol = QgsPointPatternFillSymbolLayer()
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Point fill mm: \n" + dom.toString())
|
||||
|
||||
self.assertStaticSize(root, '7')
|
||||
|
||||
def testPointFillpixels(self):
|
||||
symbol = QgsPointPatternFillSymbolLayer()
|
||||
symbol.setOutputUnit(QgsUnitTypes.RenderPixels)
|
||||
dom, root = self.symbolToSld(symbol)
|
||||
# print ("Point fill px: \n" + dom.toString())
|
||||
|
||||
self.assertStaticSize(root, '2')
|
||||
|
||||
def assertDashPattern(self, root, svgParameterIdx, expectedPattern):
|
||||
strokeWidth = root.elementsByTagName(
|
||||
'se:SvgParameter').item(svgParameterIdx)
|
||||
svgParameterName = strokeWidth.attributes().namedItem('name')
|
||||
self.assertEquals("stroke-dasharray", svgParameterName.nodeValue())
|
||||
self.assertEquals(
|
||||
expectedPattern, strokeWidth.firstChild().nodeValue())
|
||||
|
||||
def assertStaticGap(self, root, expectedValue):
|
||||
# Check the rotation element is a literal, not a
|
||||
rotation = root.elementsByTagName('se:Gap').item(0)
|
||||
literal = rotation.firstChild()
|
||||
self.assertEquals("ogc:Literal", literal.nodeName())
|
||||
self.assertEquals(expectedValue, literal.firstChild().nodeValue())
|
||||
|
||||
def assertStaticSize(self, root, expectedValue):
|
||||
size = root.elementsByTagName('se:Size').item(0)
|
||||
self.assertEquals(expectedValue, size.firstChild().nodeValue())
|
||||
|
||||
def assertStaticPerpendicularOffset(self, root, expectedValue):
|
||||
offset = root.elementsByTagName('se:PerpendicularOffset').item(0)
|
||||
self.assertEquals(expectedValue, offset.firstChild().nodeValue())
|
||||
|
||||
def symbolToSld(self, symbolLayer):
|
||||
dom = QDomDocument()
|
||||
root = dom.createElement("FakeRoot")
|
||||
dom.appendChild(root)
|
||||
symbolLayer.toSld(dom, root, {})
|
||||
return dom, root
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user