Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgssinglesymbolrenderer.cpp 3 : : --------------------- 4 : : begin : November 2009 5 : : copyright : (C) 2009 by Martin Dobias 6 : : email : wonder dot sk at gmail dot com 7 : : *************************************************************************** 8 : : * * 9 : : * This program is free software; you can redistribute it and/or modify * 10 : : * it under the terms of the GNU General Public License as published by * 11 : : * the Free Software Foundation; either version 2 of the License, or * 12 : : * (at your option) any later version. * 13 : : * * 14 : : ***************************************************************************/ 15 : : 16 : : #include "qgssinglesymbolrenderer.h" 17 : : 18 : : #include "qgssymbol.h" 19 : : #include "qgssymbollayerutils.h" 20 : : 21 : : #include "qgsdatadefinedsizelegend.h" 22 : : #include "qgslogger.h" 23 : : #include "qgsfeature.h" 24 : : #include "qgsvectorlayer.h" 25 : : #include "qgssymbollayer.h" 26 : : #include "qgsogcutils.h" 27 : : #include "qgspointdisplacementrenderer.h" 28 : : #include "qgsinvertedpolygonrenderer.h" 29 : : #include "qgspainteffect.h" 30 : : #include "qgspainteffectregistry.h" 31 : : #include "qgsproperty.h" 32 : : #include "qgsstyleentityvisitor.h" 33 : : 34 : : #include <QDomDocument> 35 : : #include <QDomElement> 36 : : 37 : 156 : QgsSingleSymbolRenderer::QgsSingleSymbolRenderer( QgsSymbol *symbol ) 38 : 156 : : QgsFeatureRenderer( QStringLiteral( "singleSymbol" ) ) 39 : 78 : , mSymbol( symbol ) 40 : 78 : { 41 : : Q_ASSERT( symbol ); 42 : 78 : } 43 : : 44 : 124 : QgsSingleSymbolRenderer::~QgsSingleSymbolRenderer() = default; 45 : : 46 : 0 : QgsSymbol *QgsSingleSymbolRenderer::symbolForFeature( const QgsFeature &, QgsRenderContext & ) const 47 : : { 48 : 0 : return mSymbol.get(); 49 : : } 50 : : 51 : 0 : QgsSymbol *QgsSingleSymbolRenderer::originalSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const 52 : : { 53 : 0 : Q_UNUSED( context ) 54 : 0 : Q_UNUSED( feature ) 55 : 0 : return mSymbol.get(); 56 : : } 57 : : 58 : 0 : void QgsSingleSymbolRenderer::startRender( QgsRenderContext &context, const QgsFields &fields ) 59 : : { 60 : 0 : QgsFeatureRenderer::startRender( context, fields ); 61 : : 62 : 0 : if ( !mSymbol ) 63 : 0 : return; 64 : : 65 : 0 : mSymbol->startRender( context, fields ); 66 : 0 : } 67 : : 68 : 0 : void QgsSingleSymbolRenderer::stopRender( QgsRenderContext &context ) 69 : : { 70 : 0 : QgsFeatureRenderer::stopRender( context ); 71 : : 72 : 0 : if ( !mSymbol ) 73 : 0 : return; 74 : : 75 : 0 : mSymbol->stopRender( context ); 76 : 0 : } 77 : : 78 : 0 : QSet<QString> QgsSingleSymbolRenderer::usedAttributes( const QgsRenderContext &context ) const 79 : : { 80 : 0 : QSet<QString> attributes; 81 : 0 : if ( mSymbol ) 82 : 0 : attributes.unite( mSymbol->usedAttributes( context ) ); 83 : 0 : return attributes; 84 : 0 : } 85 : : 86 : 0 : bool QgsSingleSymbolRenderer::accept( QgsStyleEntityVisitorInterface *visitor ) const 87 : : { 88 : 0 : if ( mSymbol ) 89 : : { 90 : 0 : QgsStyleSymbolEntity entity( mSymbol.get() ); 91 : 0 : return visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity ) ); 92 : 0 : } 93 : 0 : return true; 94 : 0 : } 95 : : 96 : 0 : QgsSymbol *QgsSingleSymbolRenderer::symbol() const 97 : : { 98 : 0 : return mSymbol.get(); 99 : : } 100 : : 101 : 0 : void QgsSingleSymbolRenderer::setSymbol( QgsSymbol *s ) 102 : : { 103 : : Q_ASSERT( s ); 104 : 0 : mSymbol.reset( s ); 105 : 0 : } 106 : : 107 : 0 : QString QgsSingleSymbolRenderer::dump() const 108 : : { 109 : 0 : return mSymbol ? QStringLiteral( "SINGLE: %1" ).arg( mSymbol->dump() ) : QString(); 110 : 0 : } 111 : : 112 : 0 : QgsSingleSymbolRenderer *QgsSingleSymbolRenderer::clone() const 113 : : { 114 : 0 : QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( mSymbol->clone() ); 115 : 0 : r->setUsingSymbolLevels( usingSymbolLevels() ); 116 : 0 : r->setDataDefinedSizeLegend( mDataDefinedSizeLegend ? new QgsDataDefinedSizeLegend( *mDataDefinedSizeLegend ) : nullptr ); 117 : 0 : copyRendererData( r ); 118 : 0 : return r; 119 : 0 : } 120 : : 121 : 0 : void QgsSingleSymbolRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const 122 : : { 123 : 0 : QVariantMap newProps = props; 124 : : 125 : 0 : QDomElement ruleElem = doc.createElement( QStringLiteral( "se:Rule" ) ); 126 : 0 : element.appendChild( ruleElem ); 127 : : 128 : 0 : QDomElement nameElem = doc.createElement( QStringLiteral( "se:Name" ) ); 129 : 0 : nameElem.appendChild( doc.createTextNode( QStringLiteral( "Single symbol" ) ) ); 130 : 0 : ruleElem.appendChild( nameElem ); 131 : : 132 : 0 : QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElem, newProps ); 133 : : 134 : 0 : if ( mSymbol ) mSymbol->toSld( doc, ruleElem, newProps ); 135 : 0 : } 136 : : 137 : 0 : QgsSymbolList QgsSingleSymbolRenderer::symbols( QgsRenderContext &context ) const 138 : : { 139 : 0 : Q_UNUSED( context ) 140 : 0 : QgsSymbolList lst; 141 : 0 : lst.append( mSymbol.get() ); 142 : 0 : return lst; 143 : 0 : } 144 : : 145 : : 146 : 0 : QgsFeatureRenderer *QgsSingleSymbolRenderer::create( QDomElement &element, const QgsReadWriteContext &context ) 147 : : { 148 : 0 : QDomElement symbolsElem = element.firstChildElement( QStringLiteral( "symbols" ) ); 149 : 0 : if ( symbolsElem.isNull() ) 150 : 0 : return nullptr; 151 : : 152 : 0 : QgsSymbolMap symbolMap = QgsSymbolLayerUtils::loadSymbols( symbolsElem, context ); 153 : : 154 : 0 : if ( !symbolMap.contains( QStringLiteral( "0" ) ) ) 155 : 0 : return nullptr; 156 : : 157 : 0 : QgsSingleSymbolRenderer *r = new QgsSingleSymbolRenderer( symbolMap.take( QStringLiteral( "0" ) ) ); 158 : : 159 : : // delete symbols if there are any more 160 : 0 : QgsSymbolLayerUtils::clearSymbolMap( symbolMap ); 161 : : 162 : 0 : QDomElement rotationElem = element.firstChildElement( QStringLiteral( "rotation" ) ); 163 : 0 : if ( !rotationElem.isNull() && !rotationElem.attribute( QStringLiteral( "field" ) ).isEmpty() ) 164 : : { 165 : 0 : convertSymbolRotation( r->mSymbol.get(), rotationElem.attribute( QStringLiteral( "field" ) ) ); 166 : 0 : } 167 : : 168 : 0 : QDomElement sizeScaleElem = element.firstChildElement( QStringLiteral( "sizescale" ) ); 169 : 0 : if ( !sizeScaleElem.isNull() && !sizeScaleElem.attribute( QStringLiteral( "field" ) ).isEmpty() ) 170 : : { 171 : 0 : convertSymbolSizeScale( r->mSymbol.get(), 172 : 0 : QgsSymbolLayerUtils::decodeScaleMethod( sizeScaleElem.attribute( QStringLiteral( "scalemethod" ) ) ), 173 : 0 : sizeScaleElem.attribute( QStringLiteral( "field" ) ) ); 174 : 0 : } 175 : : 176 : 0 : QDomElement ddsLegendSizeElem = element.firstChildElement( QStringLiteral( "data-defined-size-legend" ) ); 177 : 0 : if ( !ddsLegendSizeElem.isNull() ) 178 : : { 179 : 0 : r->mDataDefinedSizeLegend.reset( QgsDataDefinedSizeLegend::readXml( ddsLegendSizeElem, context ) ); 180 : 0 : } 181 : : 182 : : // TODO: symbol levels 183 : 0 : return r; 184 : 0 : } 185 : : 186 : 0 : QgsFeatureRenderer *QgsSingleSymbolRenderer::createFromSld( QDomElement &element, QgsWkbTypes::GeometryType geomType ) 187 : : { 188 : : // XXX this renderer can handle only one Rule! 189 : : 190 : : // get the first Rule element 191 : 0 : QDomElement ruleElem = element.firstChildElement( QStringLiteral( "Rule" ) ); 192 : 0 : if ( ruleElem.isNull() ) 193 : : { 194 : 0 : QgsDebugMsg( QStringLiteral( "no Rule elements found!" ) ); 195 : 0 : return nullptr; 196 : : } 197 : : 198 : 0 : QString label, description; 199 : 0 : QgsSymbolLayerList layers; 200 : : 201 : : // retrieve the Rule element child nodes 202 : 0 : QDomElement childElem = ruleElem.firstChildElement(); 203 : 0 : while ( !childElem.isNull() ) 204 : : { 205 : 0 : if ( childElem.localName() == QLatin1String( "Name" ) ) 206 : : { 207 : : // <se:Name> tag contains the rule identifier, 208 : : // so prefer title tag for the label property value 209 : 0 : if ( label.isEmpty() ) 210 : 0 : label = childElem.firstChild().nodeValue(); 211 : 0 : } 212 : 0 : else if ( childElem.localName() == QLatin1String( "Description" ) ) 213 : : { 214 : : // <se:Description> can contains a title and an abstract 215 : 0 : QDomElement titleElem = childElem.firstChildElement( QStringLiteral( "Title" ) ); 216 : 0 : if ( !titleElem.isNull() ) 217 : : { 218 : 0 : label = titleElem.firstChild().nodeValue(); 219 : 0 : } 220 : : 221 : 0 : QDomElement abstractElem = childElem.firstChildElement( QStringLiteral( "Abstract" ) ); 222 : 0 : if ( !abstractElem.isNull() ) 223 : : { 224 : 0 : description = abstractElem.firstChild().nodeValue(); 225 : 0 : } 226 : 0 : } 227 : 0 : else if ( childElem.localName() == QLatin1String( "Abstract" ) ) 228 : : { 229 : : // <sld:Abstract> (v1.0) 230 : 0 : description = childElem.firstChild().nodeValue(); 231 : 0 : } 232 : 0 : else if ( childElem.localName() == QLatin1String( "Title" ) ) 233 : : { 234 : : // <sld:Title> (v1.0) 235 : 0 : label = childElem.firstChild().nodeValue(); 236 : 0 : } 237 : 0 : else if ( childElem.localName().endsWith( QLatin1String( "Symbolizer" ) ) ) 238 : : { 239 : : // create symbol layers for this symbolizer 240 : 0 : QgsSymbolLayerUtils::createSymbolLayerListFromSld( childElem, geomType, layers ); 241 : 0 : } 242 : : 243 : 0 : childElem = childElem.nextSiblingElement(); 244 : : } 245 : : 246 : 0 : if ( layers.isEmpty() ) 247 : 0 : return nullptr; 248 : : 249 : : // now create the symbol 250 : 0 : std::unique_ptr< QgsSymbol > symbol; 251 : 0 : switch ( geomType ) 252 : : { 253 : : case QgsWkbTypes::LineGeometry: 254 : 0 : symbol = std::make_unique< QgsLineSymbol >( layers ); 255 : 0 : break; 256 : : 257 : : case QgsWkbTypes::PolygonGeometry: 258 : 0 : symbol = std::make_unique< QgsFillSymbol >( layers ); 259 : 0 : break; 260 : : 261 : : case QgsWkbTypes::PointGeometry: 262 : 0 : symbol = std::make_unique< QgsMarkerSymbol >( layers ); 263 : 0 : break; 264 : : 265 : : default: 266 : 0 : QgsDebugMsg( QStringLiteral( "invalid geometry type: found %1" ).arg( geomType ) ); 267 : 0 : return nullptr; 268 : : } 269 : : 270 : : // and finally return the new renderer 271 : 0 : return new QgsSingleSymbolRenderer( symbol.release() ); 272 : 0 : } 273 : : 274 : 0 : QDomElement QgsSingleSymbolRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context ) 275 : : { 276 : 0 : QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME ); 277 : 0 : rendererElem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "singleSymbol" ) ); 278 : 0 : rendererElem.setAttribute( QStringLiteral( "symbollevels" ), ( mUsingSymbolLevels ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) ); 279 : 0 : rendererElem.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) ); 280 : : 281 : 0 : QgsSymbolMap symbols; 282 : 0 : symbols[QStringLiteral( "0" )] = mSymbol.get(); 283 : 0 : QDomElement symbolsElem = QgsSymbolLayerUtils::saveSymbols( symbols, QStringLiteral( "symbols" ), doc, context ); 284 : 0 : rendererElem.appendChild( symbolsElem ); 285 : : 286 : 0 : QDomElement rotationElem = doc.createElement( QStringLiteral( "rotation" ) ); 287 : 0 : rendererElem.appendChild( rotationElem ); 288 : : 289 : 0 : QDomElement sizeScaleElem = doc.createElement( QStringLiteral( "sizescale" ) ); 290 : 0 : rendererElem.appendChild( sizeScaleElem ); 291 : : 292 : 0 : if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) ) 293 : 0 : mPaintEffect->saveProperties( doc, rendererElem ); 294 : : 295 : 0 : if ( !mOrderBy.isEmpty() ) 296 : : { 297 : 0 : QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) ); 298 : 0 : mOrderBy.save( orderBy ); 299 : 0 : rendererElem.appendChild( orderBy ); 300 : 0 : } 301 : 0 : rendererElem.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) ); 302 : : 303 : 0 : if ( mDataDefinedSizeLegend ) 304 : : { 305 : 0 : QDomElement ddsLegendElem = doc.createElement( QStringLiteral( "data-defined-size-legend" ) ); 306 : 0 : mDataDefinedSizeLegend->writeXml( ddsLegendElem, context ); 307 : 0 : rendererElem.appendChild( ddsLegendElem ); 308 : 0 : } 309 : : 310 : 0 : return rendererElem; 311 : 0 : } 312 : : 313 : 0 : QgsLegendSymbolList QgsSingleSymbolRenderer::legendSymbolItems() const 314 : : { 315 : 0 : if ( mDataDefinedSizeLegend && mSymbol->type() == QgsSymbol::Marker ) 316 : : { 317 : 0 : const QgsMarkerSymbol *symbol = static_cast<const QgsMarkerSymbol *>( mSymbol.get() ); 318 : 0 : QgsProperty sizeDD( symbol->dataDefinedSize() ); 319 : 0 : if ( sizeDD && sizeDD.isActive() ) 320 : : { 321 : 0 : QgsDataDefinedSizeLegend ddSizeLegend( *mDataDefinedSizeLegend ); 322 : 0 : ddSizeLegend.updateFromSymbolAndProperty( static_cast<const QgsMarkerSymbol *>( mSymbol.get() ), sizeDD ); 323 : 0 : return ddSizeLegend.legendSymbolList(); 324 : 0 : } 325 : 0 : } 326 : : 327 : 0 : QgsLegendSymbolList lst; 328 : 0 : lst << QgsLegendSymbolItem( mSymbol.get(), QString(), QStringLiteral( "0" ) ); 329 : 0 : return lst; 330 : 0 : } 331 : : 332 : 0 : QSet< QString > QgsSingleSymbolRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const 333 : : { 334 : 0 : Q_UNUSED( feature ) 335 : 0 : Q_UNUSED( context ) 336 : 0 : return QSet< QString >() << QStringLiteral( "0" ); 337 : 0 : } 338 : : 339 : 0 : void QgsSingleSymbolRenderer::setLegendSymbolItem( const QString &key, QgsSymbol *symbol ) 340 : : { 341 : 0 : Q_UNUSED( key ) 342 : 0 : setSymbol( symbol ); 343 : 0 : } 344 : : 345 : 0 : QgsSingleSymbolRenderer *QgsSingleSymbolRenderer::convertFromRenderer( const QgsFeatureRenderer *renderer ) 346 : : { 347 : 0 : QgsSingleSymbolRenderer *r = nullptr; 348 : 0 : if ( renderer->type() == QLatin1String( "singleSymbol" ) ) 349 : : { 350 : 0 : r = dynamic_cast<QgsSingleSymbolRenderer *>( renderer->clone() ); 351 : 0 : } 352 : 0 : else if ( renderer->type() == QLatin1String( "pointDisplacement" ) || renderer->type() == QLatin1String( "pointCluster" ) ) 353 : : { 354 : 0 : const QgsPointDistanceRenderer *pointDistanceRenderer = dynamic_cast<const QgsPointDistanceRenderer *>( renderer ); 355 : 0 : if ( pointDistanceRenderer ) 356 : 0 : r = convertFromRenderer( pointDistanceRenderer->embeddedRenderer() ); 357 : 0 : } 358 : 0 : else if ( renderer->type() == QLatin1String( "invertedPolygonRenderer" ) ) 359 : : { 360 : 0 : const QgsInvertedPolygonRenderer *invertedPolygonRenderer = dynamic_cast<const QgsInvertedPolygonRenderer *>( renderer ); 361 : 0 : if ( invertedPolygonRenderer ) 362 : 0 : r = convertFromRenderer( invertedPolygonRenderer->embeddedRenderer() ); 363 : 0 : } 364 : : 365 : 0 : if ( !r ) 366 : : { 367 : 0 : QgsRenderContext context; 368 : 0 : QgsSymbolList symbols = const_cast<QgsFeatureRenderer *>( renderer )->symbols( context ); 369 : 0 : if ( !symbols.isEmpty() ) 370 : : { 371 : 0 : r = new QgsSingleSymbolRenderer( symbols.at( 0 )->clone() ); 372 : 0 : } 373 : 0 : } 374 : : 375 : 0 : if ( r ) 376 : : { 377 : 0 : r->setOrderBy( renderer->orderBy() ); 378 : 0 : r->setOrderByEnabled( renderer->orderByEnabled() ); 379 : 0 : } 380 : : 381 : 0 : return r; 382 : 0 : } 383 : : 384 : 0 : void QgsSingleSymbolRenderer::setDataDefinedSizeLegend( QgsDataDefinedSizeLegend *settings ) 385 : : { 386 : 0 : mDataDefinedSizeLegend.reset( settings ); 387 : 0 : } 388 : : 389 : 0 : QgsDataDefinedSizeLegend *QgsSingleSymbolRenderer::dataDefinedSizeLegend() const 390 : : { 391 : 0 : return mDataDefinedSizeLegend.get(); 392 : : }