LCOV - code coverage report
Current view: top level - core/symbology - qgssinglesymbolrenderer.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 6 224 2.7 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           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                 :            : }

Generated by: LCOV version 1.14