Navigation Menu

Skip to content

Commit

Permalink
Export map level scale based dependencies in most vector symbology
Browse files Browse the repository at this point in the history
  • Loading branch information
aaime committed Sep 1, 2016
1 parent d477d19 commit a25b025
Show file tree
Hide file tree
Showing 26 changed files with 2,909 additions and 67 deletions.
9 changes: 9 additions & 0 deletions doc/api_break.dox
Expand Up @@ -999,6 +999,15 @@ in code which previously passed a null pointer to QgsVectorFileWriter.</li>
<li>QgsWMSLegendNode has been renamed to QgsWmsLegendNode</li>
</ul>

\subsection qgis_api_break_3_0_QgsRenderer QgsRenderer

<ul>
<li>New virtual method <code>bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage, QgsStringMap props = QgsStringMap() )</code> accepts an
optional property map passing down layer level properties to the SLD encoders. If scale based visibility is enabled, it will contain the
<code>scaleMinDenom</code> and <code>scaleMaxDenom</code> properties.
</ul>



\section qgis_api_break_2_4 QGIS 2.4

Expand Down
3 changes: 1 addition & 2 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -709,7 +709,7 @@ class QgsVectorLayer : QgsMapLayer
*/
bool writeStyle( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;

bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;
bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage, QgsStringMap& props ) const;
bool readSld( const QDomNode& node, QString& errorMessage );

/**
Expand Down Expand Up @@ -1660,4 +1660,3 @@ class QgsVectorLayer : QgsMapLayer


};

31 changes: 31 additions & 0 deletions python/core/symbology-ng/qgssymbollayerutils.sip
Expand Up @@ -224,6 +224,7 @@ class QgsSymbolLayerUtils
static void createGeometryElement( QDomDocument &doc, QDomElement &element, const QString& geomFunc );
static bool geometryFromSldElement( QDomElement &element, QString &geomFunc );

static bool createExpressionElement( QDomDocument &doc, QDomElement &element, const QString& function );
static bool createFunctionElement( QDomDocument &doc, QDomElement &element, const QString& function );
static bool functionFromSldElement( QDomElement &element, QString &function );

Expand Down Expand Up @@ -444,4 +445,34 @@ class 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
*/
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
*/
static QPointF rescaleUom( const QPointF& point, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props ) /PyName=rescalePointUom/;

/** 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
*/
static QVector<qreal> rescaleUom( const QVector<qreal>& array, QgsUnitTypes::RenderUnit unit, const QgsStringMap& props ) /PyName=rescaleArrayUom/;

/**
* Checks if the properties contain scaleMinDenom and scaleMaxDenom, if available, they are added into the SE Rule element
* @note added in 3.0
*/
static void applyScaleDependency( QDomDocument& doc, QDomElement& ruleElem, QgsStringMap& props );

/**
* Merges the local scale limits, if any, with the ones already in the map, if any
* @note added in 3.0
*/
static void mergeScaleDependencies( int mScaleMinDenom, int mScaleMaxDenom, QgsStringMap& props );

};
8 changes: 7 additions & 1 deletion src/core/qgsmaplayer.cpp
Expand Up @@ -1448,7 +1448,13 @@ void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
return;
}

if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) )
QgsStringMap props;
if ( hasScaleBasedVisibility() )
{
props[ "scaleMinDenom" ] = QString::number( mMinScale );
props[ "scaleMaxDenom" ] = QString::number( mMaxScale );
}
if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg, props ) )
{
errorMsg = tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
return;
Expand Down
14 changes: 12 additions & 2 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -1991,8 +1991,12 @@ bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
return true;
}


bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
{
return writeSld( node, doc, errorMessage, QgsStringMap() );
}

bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage, QgsStringMap props ) const
{
Q_UNUSED( errorMessage );

Expand All @@ -2001,9 +2005,15 @@ bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& error
nameNode.appendChild( doc.createTextNode( name() ) );
node.appendChild( nameNode );

QgsStringMap localProps = QgsStringMap( props );
if ( hasScaleBasedVisibility() )
{
QgsSymbolLayerUtils::mergeScaleDependencies( minimumScale(), maximumScale(), localProps );
}

if ( hasGeometryType() )
{
node.appendChild( mRenderer->writeSld( doc, name() ) );
node.appendChild( mRenderer->writeSld( doc, name(), localProps ) );
}
return true;
}
Expand Down
11 changes: 11 additions & 0 deletions src/core/qgsvectorlayer.h
Expand Up @@ -803,6 +803,17 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
bool writeStyle( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const override;

bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;

/**
* Writes the symbology of the layer into the document provided in SLD 1.1 format
* @param node the node that will have the style element added to it.
* @param doc the document that will have the QDomNode added.
* @param errorMessage reference to string that will be updated with any error messages
* @param props a open ended set of properties that can drive/inform the SLD encoding
* @return true in case of success
*/
bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage, QgsStringMap props = QgsStringMap() ) const;

bool readSld( const QDomNode& node, QString& errorMessage ) override;

/**
Expand Down
6 changes: 4 additions & 2 deletions src/core/symbology-ng/qgscategorizedsymbolrenderer.cpp
Expand Up @@ -141,6 +141,9 @@ void QgsRendererCategory::toSld( QDomDocument &doc, QDomElement &element, QgsStr
mValue.toString().replace( '\'', "''" ) );
QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, filterFunc );

// add the mix/max scale denoms if we got any from the callers
QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, props );

mSymbol->toSld( doc, ruleElem, props );
}

Expand Down Expand Up @@ -517,9 +520,8 @@ QgsCategorizedSymbolRenderer* QgsCategorizedSymbolRenderer::clone() const
return r;
}

void QgsCategorizedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element ) const
void QgsCategorizedSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
QgsStringMap props;
props[ "attribute" ] = mAttrName;
if ( mRotation.data() )
props[ "angle" ] = mRotation->expression();
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgscategorizedsymbolrenderer.h
Expand Up @@ -99,7 +99,7 @@ class CORE_EXPORT QgsCategorizedSymbolRenderer : public QgsFeatureRenderer

virtual QgsCategorizedSymbolRenderer* clone() const override;

virtual void toSld( QDomDocument& doc, QDomElement &element ) const override;
virtual void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props = QgsStringMap() ) const override;

//! returns bitwise OR-ed capabilities of the renderer
virtual Capabilities capabilities() override { return SymbolLevels | RotationField | Filter; }
Expand Down
3 changes: 1 addition & 2 deletions src/core/symbology-ng/qgsgraduatedsymbolrenderer.cpp
Expand Up @@ -560,9 +560,8 @@ QgsGraduatedSymbolRenderer* QgsGraduatedSymbolRenderer::clone() const
return r;
}

void QgsGraduatedSymbolRenderer::toSld( QDomDocument& doc, QDomElement &element ) const
void QgsGraduatedSymbolRenderer::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const
{
QgsStringMap props;
props[ "attribute" ] = mAttrName;
props[ "method" ] = graduatedMethodStr( mGraduatedMethod );
if ( mRotation.data() )
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgsgraduatedsymbolrenderer.h
Expand Up @@ -152,7 +152,7 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer : public QgsFeatureRenderer

virtual QgsGraduatedSymbolRenderer* clone() const override;

virtual void toSld( QDomDocument& doc, QDomElement &element ) const override;
virtual void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props = QgsStringMap() ) const override;

//! returns bitwise OR-ed capabilities of the renderer
virtual Capabilities capabilities() override { return SymbolLevels | RotationField | Filter; }
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgslinesymbollayer.cpp
Expand Up @@ -1450,7 +1450,7 @@ void QgsMarkerLineSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, c
if ( !gap.isEmpty() )
{
QDomElement gapElem = doc.createElement( "se:Gap" );
QgsSymbolLayerUtils::createFunctionElement( doc, gapElem, gap );
QgsSymbolLayerUtils::createExpressionElement( doc, gapElem, gap );
graphicStrokeElem.appendChild( gapElem );
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/symbology-ng/qgspointdisplacementrenderer.cpp
Expand Up @@ -87,9 +87,9 @@ QgsPointDisplacementRenderer* QgsPointDisplacementRenderer::clone() const
return r;
}

void QgsPointDisplacementRenderer::toSld( QDomDocument& doc, QDomElement &element ) const
void QgsPointDisplacementRenderer::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const
{
mRenderer->toSld( doc, element );
mRenderer->toSld( doc, element, props );
}


Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgspointdisplacementrenderer.h
Expand Up @@ -46,7 +46,7 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsFeatureRenderer

QgsPointDisplacementRenderer* clone() const override;

virtual void toSld( QDomDocument& doc, QDomElement &element ) const override;
virtual void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props = QgsStringMap() ) const override;

/** Reimplemented from QgsFeatureRenderer*/
bool renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false ) override;
Expand Down
7 changes: 4 additions & 3 deletions src/core/symbology-ng/qgsrenderer.cpp
Expand Up @@ -340,10 +340,11 @@ QgsFeatureRenderer* QgsFeatureRenderer::loadSld( const QDomNode &node, QgsWkbTyp

QDomElement QgsFeatureRenderer::writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const
{
return writeSld( doc, layer.name() );
QgsStringMap props;
return writeSld( doc, layer.name(), props );
}

QDomElement QgsFeatureRenderer::writeSld( QDomDocument& doc, const QString& styleName ) const
QDomElement QgsFeatureRenderer::writeSld( QDomDocument& doc, const QString& styleName, QgsStringMap props ) const
{
QDomElement userStyleElem = doc.createElement( "UserStyle" );

Expand All @@ -352,7 +353,7 @@ QDomElement QgsFeatureRenderer::writeSld( QDomDocument& doc, const QString& styl
userStyleElem.appendChild( nameElem );

QDomElement featureTypeStyleElem = doc.createElement( "se:FeatureTypeStyle" );
toSld( doc, featureTypeStyleElem );
toSld( doc, featureTypeStyleElem, props );
userStyleElem.appendChild( featureTypeStyleElem );

return userStyleElem;
Expand Down
9 changes: 6 additions & 3 deletions src/core/symbology-ng/qgsrenderer.h
Expand Up @@ -263,7 +263,7 @@ class CORE_EXPORT QgsFeatureRenderer
Q_DECL_DEPRECATED virtual QDomElement writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const;
//! create the SLD UserStyle element following the SLD v1.1 specs with the given name
//! @note added in 2.8
virtual QDomElement writeSld( QDomDocument& doc, const QString& styleName ) const;
virtual QDomElement writeSld( QDomDocument& doc, const QString& styleName, QgsStringMap props = QgsStringMap() ) const;

/** Create a new renderer according to the information contained in
* the UserStyle element of a SLD style document
Expand All @@ -278,8 +278,11 @@ class CORE_EXPORT QgsFeatureRenderer
static QgsFeatureRenderer* loadSld( const QDomNode &node, QgsWkbTypes::GeometryType geomType, QString &errorMessage );

//! used from subclasses to create SLD Rule elements following SLD v1.1 specs
virtual void toSld( QDomDocument& doc, QDomElement &element ) const
{ element.appendChild( doc.createComment( QString( "FeatureRendererV2 %1 not implemented yet" ).arg( type() ) ) ); }
virtual void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props = QgsStringMap() ) const
{
element.appendChild( doc.createComment( QString( "FeatureRendererV2 %1 not implemented yet" ).arg( type() ) ) );
( void ) props; // warning avoidance
}

//! return a list of symbology items for the legend
virtual QgsLegendSymbologyList legendSymbologyItems( QSize iconSize );
Expand Down
38 changes: 4 additions & 34 deletions src/core/symbology-ng/qgsrulebasedrenderer.cpp
Expand Up @@ -348,25 +348,7 @@ void QgsRuleBasedRenderer::Rule::toSld( QDomDocument& doc, QDomElement &element,
props[ "filter" ] += mFilterExp;
}

if ( mScaleMinDenom != 0 )
{
bool ok;
int parentScaleMinDenom = props.value( "scaleMinDenom", "0" ).toInt( &ok );
if ( !ok || parentScaleMinDenom <= 0 )
props[ "scaleMinDenom" ] = QString::number( mScaleMinDenom );
else
props[ "scaleMinDenom" ] = QString::number( qMax( parentScaleMinDenom, mScaleMinDenom ) );
}

if ( mScaleMaxDenom != 0 )
{
bool ok;
int parentScaleMaxDenom = props.value( "scaleMaxDenom", "0" ).toInt( &ok );
if ( !ok || parentScaleMaxDenom <= 0 )
props[ "scaleMaxDenom" ] = QString::number( mScaleMaxDenom );
else
props[ "scaleMaxDenom" ] = QString::number( qMin( parentScaleMaxDenom, mScaleMaxDenom ) );
}
QgsSymbolLayerUtils::mergeScaleDependencies( mScaleMinDenom, mScaleMaxDenom, props );

if ( mSymbol )
{
Expand Down Expand Up @@ -402,19 +384,7 @@ void QgsRuleBasedRenderer::Rule::toSld( QDomDocument& doc, QDomElement &element,
QgsSymbolLayerUtils::createFunctionElement( doc, ruleElem, props.value( "filter", "" ) );
}

if ( !props.value( "scaleMinDenom", "" ).isEmpty() )
{
QDomElement scaleMinDenomElem = doc.createElement( "se:MinScaleDenominator" );
scaleMinDenomElem.appendChild( doc.createTextNode( props.value( "scaleMinDenom", "" ) ) );
ruleElem.appendChild( scaleMinDenomElem );
}

if ( !props.value( "scaleMaxDenom", "" ).isEmpty() )
{
QDomElement scaleMaxDenomElem = doc.createElement( "se:MaxScaleDenominator" );
scaleMaxDenomElem.appendChild( doc.createTextNode( props.value( "scaleMaxDenom", "" ) ) );
ruleElem.appendChild( scaleMaxDenomElem );
}
QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, props );

mSymbol->toSld( doc, ruleElem, props );
}
Expand Down Expand Up @@ -977,9 +947,9 @@ QgsRuleBasedRenderer* QgsRuleBasedRenderer::clone() const
return r;
}

void QgsRuleBasedRenderer::toSld( QDomDocument& doc, QDomElement &element ) const
void QgsRuleBasedRenderer::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const
{
mRootRule->toSld( doc, element, QgsStringMap() );
mRootRule->toSld( doc, element, props );
}

// TODO: ideally this function should be removed in favor of legendSymbol(ogy)Items
Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgsrulebasedrenderer.h
Expand Up @@ -441,7 +441,7 @@ class CORE_EXPORT QgsRuleBasedRenderer : public QgsFeatureRenderer

virtual QgsRuleBasedRenderer* clone() const override;

virtual void toSld( QDomDocument& doc, QDomElement &element ) const override;
virtual void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props = QgsStringMap() ) const override;

static QgsFeatureRenderer* createFromSld( QDomElement& element, QgsWkbTypes::GeometryType geomType );

Expand Down
5 changes: 3 additions & 2 deletions src/core/symbology-ng/qgssinglesymbolrenderer.cpp
Expand Up @@ -205,9 +205,8 @@ QgsSingleSymbolRenderer* QgsSingleSymbolRenderer::clone() const
return r;
}

void QgsSingleSymbolRenderer::toSld( QDomDocument& doc, QDomElement &element ) const
void QgsSingleSymbolRenderer::toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const
{
QgsStringMap props;
if ( mRotation.data() )
props[ "angle" ] = mRotation->expression();
if ( mSizeScale.data() )
Expand All @@ -220,6 +219,8 @@ void QgsSingleSymbolRenderer::toSld( QDomDocument& doc, QDomElement &element ) c
nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
ruleElem.appendChild( nameElem );

QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, props );

if ( mSymbol.data() ) mSymbol->toSld( doc, ruleElem, props );
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/symbology-ng/qgssinglesymbolrenderer.h
Expand Up @@ -61,7 +61,7 @@ class CORE_EXPORT QgsSingleSymbolRenderer : public QgsFeatureRenderer

virtual QgsSingleSymbolRenderer* clone() const override;

virtual void toSld( QDomDocument& doc, QDomElement &element ) const override;
virtual void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props = QgsStringMap() ) const override;
static QgsFeatureRenderer* createFromSld( QDomElement& element, QgsWkbTypes::GeometryType geomType );

//! returns bitwise OR-ed capabilities of the renderer
Expand Down

0 comments on commit a25b025

Please sign in to comment.