Porting Raymond Nijssen FOSS4G 2016 labeling work onto latest version of master, with basic support for testing. fixes #8925

This commit is contained in:
Andrea Aime 2016-11-20 15:41:51 +01:00
parent 1b9c5be10d
commit 59d8b18ed8
5 changed files with 424 additions and 10 deletions

View File

@ -2205,20 +2205,34 @@ bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &error
{
Q_UNUSED( errorMessage );
// store the Name element
QDomElement nameNode = doc.createElement( QStringLiteral( "se:Name" ) );
nameNode.appendChild( doc.createTextNode( name() ) );
node.appendChild( nameNode );
QgsStringMap localProps = QgsStringMap( props );
if ( hasScaleBasedVisibility() )
{
QgsSymbolLayerUtils::mergeScaleDependencies( maximumScale(), minimumScale(), localProps );
}
if ( isSpatial() )
{
node.appendChild( mRenderer->writeSld( doc, name(), localProps ) );
if ( isSpatial() ) {
// store the Name element
QDomElement nameNode = doc.createElement( "se:Name" );
nameNode.appendChild( doc.createTextNode( name() ) );
node.appendChild( nameNode );
QDomElement userStyleElem = doc.createElement( "UserStyle" );
node.appendChild( userStyleElem );
QDomElement nameElem = doc.createElement( "se:Name" );
nameElem.appendChild( doc.createTextNode( name() ) );
userStyleElem.appendChild( nameElem );
QDomElement featureTypeStyleElem = doc.createElement( "se:FeatureTypeStyle" );
userStyleElem.appendChild( featureTypeStyleElem );
mRenderer->toSld( doc, featureTypeStyleElem, localProps );
if ( mLabeling != nullptr )
{
mLabeling->toSld( featureTypeStyleElem, localProps );
}
}
return true;
}

View File

@ -17,6 +17,8 @@
#include "qgspallabeling.h"
#include "qgsrulebasedlabeling.h"
#include "qgsvectorlayer.h"
#include "qgssymbollayerutils.h"
#include "qgis.h"
QgsAbstractVectorLayerLabeling *QgsAbstractVectorLayerLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
@ -88,3 +90,50 @@ QgsVectorLayerSimpleLabeling *QgsVectorLayerSimpleLabeling::create( const QDomEl
return new QgsVectorLayerSimpleLabeling( QgsPalLayerSettings() );
}
void QgsVectorLayerSimpleLabeling::toSld( QDomNode &parent, const QgsStringMap &props ) const
{
if ( mSettings->drawLabels )
{
QDomDocument doc = parent.ownerDocument();
QDomElement ruleElement = doc.createElement( QStringLiteral( "se:Rule" ) );
parent.appendChild( ruleElement );
QDomElement textSymbolizerElement = doc.createElement( QStringLiteral( "se:TextSymbolizer" ) );
ruleElement.appendChild( textSymbolizerElement );
// label
QDomElement labelElement = doc.createElement( QStringLiteral( "se:Label" ) );
textSymbolizerElement.appendChild( labelElement );
if ( mSettings->isExpression )
{
labelElement.appendChild( doc.createComment( QStringLiteral( "SE Export for %1 not implemented yet" ).arg( mSettings->getLabelExpression()->dump() ) ) );
labelElement.appendChild( doc.createTextNode( "Placeholder" ) );
}
else
{
QDomElement propertyNameElement = doc.createElement( QStringLiteral( "ogc:PropertyName" ) );
propertyNameElement.appendChild( doc.createTextNode( mSettings->fieldName ) );
labelElement.appendChild( propertyNameElement );
}
// font
QDomElement fontElement = doc.createElement( QStringLiteral( "se:Font" ) );
textSymbolizerElement.appendChild( fontElement );
QgsTextFormat format = mSettings->format();
fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-family" ), format.font().family() ) );
double fontSize = QgsSymbolLayerUtils::rescaleUom( format.size(), format.sizeUnit(), props );
fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-size" ), QString::number( fontSize ) ) );
// fill
QDomElement fillElement = doc.createElement( QStringLiteral( "se:Fill" ) );
textSymbolizerElement.appendChild( fillElement );
fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill" ), format.color().name() ) );
}
}

View File

@ -19,9 +19,9 @@
#include <QString>
#include <QStringList>
#include <QDomNode>
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgis.h"
class QDomDocument;
class QDomElement;
@ -76,6 +76,17 @@ class CORE_EXPORT QgsAbstractVectorLayerLabeling
//! Try to create instance of an implementation based on the XML data
static QgsAbstractVectorLayerLabeling *create( const QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
/**
* Writes the SE 1.1 TextSymbolizer element based on the current layer labelling settings
*/
virtual void toSld( QDomNode& parent, const QgsStringMap& props ) const
{
Q_UNUSED( parent )
Q_UNUSED( props )
QDomDocument doc = parent.ownerDocument();
parent.appendChild( doc.createComment( QStringLiteral( "SE Export for %1 not implemented yet" ).arg( type() ) ) );
}
private:
Q_DISABLE_COPY( QgsAbstractVectorLayerLabeling )
@ -105,6 +116,7 @@ class CORE_EXPORT QgsVectorLayerSimpleLabeling : public QgsAbstractVectorLayerLa
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const override;
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const override;
bool requiresAdvancedEffects() const override;
virtual void toSld( QDomNode& parent, const QgsStringMap& props ) const override;
//! Create the instance from a DOM element with saved configuration
static QgsVectorLayerSimpleLabeling *create( const QDomElement &element, const QgsReadWriteContext &context );

View File

@ -546,6 +546,60 @@ class TestQgsSymbolLayerCreateSld(unittest.TestCase):
ltValue = lt.childNodes().item(1)
self.assertEquals(max, ltValue.toElement().text())
def testSimpleLabelling(self):
layer = QgsVectorLayer("Point", "addfeat", "memory")
self.loadStyleWithCustomProperties(layer, "simpleLabel")
dom, root = self.layerToSld(layer)
# print("Simple label text symbolizer" + dom.toString())
ts = self.getTextSymbolizer(root, 1, 0)
self.assertPropertyName(ts, 'se:Label', 'NAME')
font = self.assertElement(ts, 'se:Font', 0)
self.assertEquals('Liberation Mono', self.assertSvgParameter(font, 'font-family').text())
self.assertEquals('9', self.assertSvgParameter(font, 'font-size').text())
fill = self.assertElement(ts, 'se:Fill', 0)
self.assertEquals('#000000', self.assertSvgParameter(fill, "fill").text())
def loadStyleWithCustomProperties(self, layer, qmlFileName):
# load the style, only vector symbology
path = QDir.toNativeSeparators('%s/symbol_layer/%s.qml' % (unitTestDataPath(), qmlFileName))
# labelling is in custom properties, they need to be loaded separately
status = layer.loadNamedStyle(path)
doc = QDomDocument()
file = QFile(path)
file.open(QIODevice.ReadOnly)
doc.setContent(file, True)
file.close()
flag = layer.readCustomProperties(doc.documentElement())
def assertElement(self, container, elementName, index):
list = container.elementsByTagName(elementName)
self.assertTrue(list.size() > index, 'Expected to find at least ' + str(index + 1) + ' ' + elementName + ' in ' + container.nodeName() + ' but found ' + str(list.size()))
node = list.item(index)
self.assertTrue(node.isElement(), 'Found node but it''s not an element')
return node.toElement()
def getTextSymbolizer(self, root, ruleIndex, textSymbolizerIndex):
rule = self.assertElement(root, 'se:Rule', ruleIndex)
textSymbolizer = self.assertElement(rule, 'se:TextSymbolizer', textSymbolizerIndex)
return textSymbolizer
def assertPropertyName(self, root, containerProperty, expectedAttributeName):
container = root.elementsByTagName(containerProperty).item(0).toElement()
property = container.elementsByTagName("ogc:PropertyName").item(0).toElement()
self.assertEqual(expectedAttributeName, property.text())
def assertSvgParameter(self, container, expectedName):
list = container.elementsByTagName("se:SvgParameter")
for i in range(0, list.size()):
item = list.item(i)
if item.isElement and item.isElement() and item.toElement().attribute('name') == expectedName:
return item.toElement()
self.fail('Could not find a se:SvgParameter named ' + expectedName + ' in ' + container.nodeName())
def assertScaleDenominator(self, root, expectedMinScale, expectedMaxScale, index=0):
rule = root.elementsByTagName('se:Rule').item(index).toElement()

View File

@ -0,0 +1,285 @@
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
<qgis version="2.18.0" simplifyAlgorithm="0" minimumScale="0" maximumScale="1e+08" simplifyDrawingHints="0" minLabelScale="0" maxLabelScale="1e+08" simplifyDrawingTol="1" simplifyMaxScale="1" hasScaleBasedVisibilityFlag="0" simplifyLocal="1" scaleBasedLabelVisibilityFlag="0">
<edittypes>
<edittype widgetv2type="TextEdit" name="ID">
<widgetv2config IsMultiline="0" fieldEditable="1" constraint="" UseHtml="0" labelOnTop="0" constraintDescription="" notNull="0"/>
</edittype>
<edittype widgetv2type="TextEdit" name="AUTHORITY">
<widgetv2config IsMultiline="0" fieldEditable="1" constraint="" UseHtml="0" labelOnTop="0" constraintDescription="" notNull="0"/>
</edittype>
<edittype widgetv2type="TextEdit" name="NAME">
<widgetv2config IsMultiline="0" fieldEditable="1" constraint="" UseHtml="0" labelOnTop="0" constraintDescription="" notNull="0"/>
</edittype>
</edittypes>
<renderer-v2 forceraster="0" symbollevels="0" type="singleSymbol" enableorderby="0">
<symbols>
<symbol alpha="1" clip_to_extent="1" type="marker" name="0">
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="160,80,26,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="5"/>
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
</symbol>
</symbols>
<rotation/>
<sizescale scalemethod="diameter"/>
</renderer-v2>
<labeling type="simple"/>
<customproperties>
<property key="embeddedWidgets/count" value="0"/>
<property key="labeling" value="pal"/>
<property key="labeling/addDirectionSymbol" value="false"/>
<property key="labeling/angleOffset" value="0"/>
<property key="labeling/blendMode" value="0"/>
<property key="labeling/bufferBlendMode" value="0"/>
<property key="labeling/bufferColorA" value="255"/>
<property key="labeling/bufferColorB" value="255"/>
<property key="labeling/bufferColorG" value="255"/>
<property key="labeling/bufferColorR" value="255"/>
<property key="labeling/bufferDraw" value="true"/>
<property key="labeling/bufferJoinStyle" value="128"/>
<property key="labeling/bufferNoFill" value="false"/>
<property key="labeling/bufferSize" value="1"/>
<property key="labeling/bufferSizeInMapUnits" value="false"/>
<property key="labeling/bufferSizeMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/bufferTransp" value="0"/>
<property key="labeling/centroidInside" value="false"/>
<property key="labeling/centroidWhole" value="false"/>
<property key="labeling/decimals" value="3"/>
<property key="labeling/displayAll" value="false"/>
<property key="labeling/dist" value="0"/>
<property key="labeling/distInMapUnits" value="false"/>
<property key="labeling/distMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/drawLabels" value="true"/>
<property key="labeling/enabled" value="true"/>
<property key="labeling/fieldName" value="NAME"/>
<property key="labeling/fitInPolygonOnly" value="false"/>
<property key="labeling/fontCapitals" value="0"/>
<property key="labeling/fontFamily" value="Liberation Mono"/>
<property key="labeling/fontItalic" value="true"/>
<property key="labeling/fontLetterSpacing" value="0"/>
<property key="labeling/fontLimitPixelSize" value="false"/>
<property key="labeling/fontMaxPixelSize" value="10000"/>
<property key="labeling/fontMinPixelSize" value="3"/>
<property key="labeling/fontSize" value="9"/>
<property key="labeling/fontSizeInMapUnits" value="false"/>
<property key="labeling/fontSizeMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/fontStrikeout" value="false"/>
<property key="labeling/fontUnderline" value="false"/>
<property key="labeling/fontWeight" value="75"/>
<property key="labeling/fontWordSpacing" value="0"/>
<property key="labeling/formatNumbers" value="false"/>
<property key="labeling/isExpression" value="false"/>
<property key="labeling/labelOffsetInMapUnits" value="true"/>
<property key="labeling/labelOffsetMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/labelPerPart" value="false"/>
<property key="labeling/leftDirectionSymbol" value="&lt;"/>
<property key="labeling/limitNumLabels" value="false"/>
<property key="labeling/maxCurvedCharAngleIn" value="25"/>
<property key="labeling/maxCurvedCharAngleOut" value="-25"/>
<property key="labeling/maxNumLabels" value="2000"/>
<property key="labeling/mergeLines" value="false"/>
<property key="labeling/minFeatureSize" value="0"/>
<property key="labeling/multilineAlign" value="3"/>
<property key="labeling/multilineHeight" value="1"/>
<property key="labeling/namedStyle" value="Bold Italic"/>
<property key="labeling/obstacle" value="true"/>
<property key="labeling/obstacleFactor" value="1"/>
<property key="labeling/obstacleType" value="0"/>
<property key="labeling/offsetType" value="0"/>
<property key="labeling/placeDirectionSymbol" value="0"/>
<property key="labeling/placement" value="1"/>
<property key="labeling/placementFlags" value="10"/>
<property key="labeling/plussign" value="false"/>
<property key="labeling/predefinedPositionOrder" value="TR,TL,BR,BL,R,L,TSR,BSR"/>
<property key="labeling/preserveRotation" value="true"/>
<property key="labeling/previewBkgrdColor" value="#ffffff"/>
<property key="labeling/priority" value="5"/>
<property key="labeling/quadOffset" value="7"/>
<property key="labeling/repeatDistance" value="0"/>
<property key="labeling/repeatDistanceMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/repeatDistanceUnit" value="1"/>
<property key="labeling/reverseDirectionSymbol" value="false"/>
<property key="labeling/rightDirectionSymbol" value=">"/>
<property key="labeling/scaleMax" value="10000000"/>
<property key="labeling/scaleMin" value="1"/>
<property key="labeling/scaleVisibility" value="false"/>
<property key="labeling/shadowBlendMode" value="6"/>
<property key="labeling/shadowColorB" value="0"/>
<property key="labeling/shadowColorG" value="0"/>
<property key="labeling/shadowColorR" value="0"/>
<property key="labeling/shadowDraw" value="false"/>
<property key="labeling/shadowOffsetAngle" value="135"/>
<property key="labeling/shadowOffsetDist" value="1"/>
<property key="labeling/shadowOffsetGlobal" value="true"/>
<property key="labeling/shadowOffsetMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/shadowOffsetUnits" value="1"/>
<property key="labeling/shadowRadius" value="1.5"/>
<property key="labeling/shadowRadiusAlphaOnly" value="false"/>
<property key="labeling/shadowRadiusMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/shadowRadiusUnits" value="1"/>
<property key="labeling/shadowScale" value="100"/>
<property key="labeling/shadowTransparency" value="30"/>
<property key="labeling/shadowUnder" value="0"/>
<property key="labeling/shapeBlendMode" value="0"/>
<property key="labeling/shapeBorderColorA" value="255"/>
<property key="labeling/shapeBorderColorB" value="128"/>
<property key="labeling/shapeBorderColorG" value="128"/>
<property key="labeling/shapeBorderColorR" value="128"/>
<property key="labeling/shapeBorderWidth" value="0"/>
<property key="labeling/shapeBorderWidthMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/shapeBorderWidthUnits" value="1"/>
<property key="labeling/shapeDraw" value="false"/>
<property key="labeling/shapeFillColorA" value="255"/>
<property key="labeling/shapeFillColorB" value="255"/>
<property key="labeling/shapeFillColorG" value="255"/>
<property key="labeling/shapeFillColorR" value="255"/>
<property key="labeling/shapeJoinStyle" value="64"/>
<property key="labeling/shapeOffsetMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/shapeOffsetUnits" value="1"/>
<property key="labeling/shapeOffsetX" value="0"/>
<property key="labeling/shapeOffsetY" value="0"/>
<property key="labeling/shapeRadiiMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/shapeRadiiUnits" value="1"/>
<property key="labeling/shapeRadiiX" value="0"/>
<property key="labeling/shapeRadiiY" value="0"/>
<property key="labeling/shapeRotation" value="0"/>
<property key="labeling/shapeRotationType" value="0"/>
<property key="labeling/shapeSVGFile" value=""/>
<property key="labeling/shapeSizeMapUnitScale" value="0,0,0,0,0,0"/>
<property key="labeling/shapeSizeType" value="0"/>
<property key="labeling/shapeSizeUnits" value="1"/>
<property key="labeling/shapeSizeX" value="0"/>
<property key="labeling/shapeSizeY" value="0"/>
<property key="labeling/shapeTransparency" value="0"/>
<property key="labeling/shapeType" value="0"/>
<property key="labeling/substitutions" value="&lt;substitutions/>"/>
<property key="labeling/textColorA" value="255"/>
<property key="labeling/textColorB" value="0"/>
<property key="labeling/textColorG" value="0"/>
<property key="labeling/textColorR" value="0"/>
<property key="labeling/textTransp" value="0"/>
<property key="labeling/upsidedownLabels" value="0"/>
<property key="labeling/useSubstitutions" value="false"/>
<property key="labeling/wrapChar" value=""/>
<property key="labeling/xOffset" value="0"/>
<property key="labeling/yOffset" value="0"/>
<property key="labeling/zIndex" value="0"/>
<property key="variableNames" value="_fields_"/>
<property key="variableValues" value=""/>
</customproperties>
<blendMode>0</blendMode>
<featureBlendMode>0</featureBlendMode>
<layerTransparency>0</layerTransparency>
<displayfield>NAME</displayfield>
<label>0</label>
<labelattributes>
<label fieldname="" text="Etichetta"/>
<family fieldname="" name="Liberation Mono"/>
<size fieldname="" units="pt" value="12"/>
<bold fieldname="" on="0"/>
<italic fieldname="" on="0"/>
<underline fieldname="" on="0"/>
<strikeout fieldname="" on="0"/>
<color fieldname="" red="0" blue="0" green="0"/>
<x fieldname=""/>
<y fieldname=""/>
<offset x="0" y="0" units="pt" yfieldname="" xfieldname=""/>
<angle fieldname="" value="0" auto="0"/>
<alignment fieldname="" value="center"/>
<buffercolor fieldname="" red="255" blue="255" green="255"/>
<buffersize fieldname="" units="pt" value="1"/>
<bufferenabled fieldname="" on=""/>
<multilineenabled fieldname="" on=""/>
<selectedonly on=""/>
</labelattributes>
<SingleCategoryDiagramRenderer diagramType="Histogram" sizeLegend="0" attributeLegend="1">
<DiagramCategory penColor="#000000" labelPlacementMethod="XHeight" penWidth="0" diagramOrientation="Up" sizeScale="0,0,0,0,0,0" minimumSize="0" barWidth="5" penAlpha="255" maxScaleDenominator="1e+08" backgroundColor="#ffffff" transparency="0" width="15" scaleDependency="Area" backgroundAlpha="255" angleOffset="1440" scaleBasedVisibility="0" enabled="0" height="15" lineSizeScale="0,0,0,0,0,0" sizeType="MM" lineSizeType="MM" minScaleDenominator="inf">
<fontProperties description="Liberation Mono,9,-1,5,50,0,0,0,0,0" style=""/>
</DiagramCategory>
<symbol alpha="1" clip_to_extent="1" type="marker" name="sizeSymbol">
<layer pass="0" class="SimpleMarker" locked="0">
<prop k="angle" v="0"/>
<prop k="color" v="255,0,0,255"/>
<prop k="horizontal_anchor_point" v="1"/>
<prop k="joinstyle" v="bevel"/>
<prop k="name" v="circle"/>
<prop k="offset" v="0,0"/>
<prop k="offset_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="offset_unit" v="MM"/>
<prop k="outline_color" v="0,0,0,255"/>
<prop k="outline_style" v="solid"/>
<prop k="outline_width" v="0"/>
<prop k="outline_width_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="outline_width_unit" v="MM"/>
<prop k="scale_method" v="diameter"/>
<prop k="size" v="2"/>
<prop k="size_map_unit_scale" v="0,0,0,0,0,0"/>
<prop k="size_unit" v="MM"/>
<prop k="vertical_anchor_point" v="1"/>
</layer>
</symbol>
</SingleCategoryDiagramRenderer>
<DiagramLayerSettings yPosColumn="-1" showColumn="-1" linePlacementFlags="10" placement="0" dist="0" xPosColumn="-1" priority="0" obstacle="0" zIndex="0" showAll="1"/>
<annotationform></annotationform>
<aliases>
<alias field="ID" index="0" name=""/>
<alias field="AUTHORITY" index="1" name=""/>
<alias field="NAME" index="2" name=""/>
</aliases>
<excludeAttributesWMS/>
<excludeAttributesWFS/>
<attributeactions default="-1"/>
<attributetableconfig actionWidgetStyle="dropDown" sortExpression="" sortOrder="2359551">
<columns>
<column width="-1" hidden="0" type="field" name="ID"/>
<column width="-1" hidden="0" type="field" name="AUTHORITY"/>
<column width="-1" hidden="0" type="field" name="NAME"/>
<column width="-1" hidden="1" type="actions"/>
</columns>
</attributetableconfig>
<editform></editform>
<editforminit/>
<editforminitcodesource>0</editforminitcodesource>
<editforminitfilepath></editforminitfilepath>
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
"""
QGIS forms can have a Python function that is called when the form is
opened.
Use this function to add extra logic to your forms.
Enter the name of the function in the "Python Init function"
field.
An example follows:
"""
from qgis.PyQt.QtWidgets import QWidget
def my_form_open(dialog, layer, feature):
geom = feature.geometry()
control = dialog.findChild(QWidget, "MyLineEdit")
]]></editforminitcode>
<featformsuppress>0</featformsuppress>
<editorlayout>generatedlayout</editorlayout>
<widgets/>
<conditionalstyles>
<rowstyles/>
<fieldstyles/>
</conditionalstyles>
<layerGeometryType>0</layerGeometryType>
</qgis>