LCOV - code coverage report
Current view: top level - core/symbology - qgspointdistancerenderer.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 276 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :          qgspointdistancerenderer.cpp
       3                 :            :          ----------------------------
       4                 :            :   begin                : January 26, 2010
       5                 :            :   copyright            : (C) 2010 by Marco Hugentobler
       6                 :            :   email                : marco at hugis dot net
       7                 :            :  ***************************************************************************/
       8                 :            : 
       9                 :            : /***************************************************************************
      10                 :            :  *                                                                         *
      11                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      12                 :            :  *   it under the terms of the GNU General Public License as published by  *
      13                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      14                 :            :  *   (at your option) any later version.                                   *
      15                 :            :  *                                                                         *
      16                 :            :  ***************************************************************************/
      17                 :            : 
      18                 :            : #include "qgspointdistancerenderer.h"
      19                 :            : #include "qgsgeometry.h"
      20                 :            : #include "qgssymbollayerutils.h"
      21                 :            : #include "qgsspatialindex.h"
      22                 :            : #include "qgsmultipoint.h"
      23                 :            : #include "qgslogger.h"
      24                 :            : #include "qgsstyleentityvisitor.h"
      25                 :            : #include "qgsexpressioncontextutils.h"
      26                 :            : 
      27                 :            : #include <QDomElement>
      28                 :            : #include <QPainter>
      29                 :            : 
      30                 :            : #include <cmath>
      31                 :            : 
      32                 :          0 : QgsPointDistanceRenderer::QgsPointDistanceRenderer( const QString &rendererName, const QString &labelAttributeName )
      33                 :          0 :   : QgsFeatureRenderer( rendererName )
      34                 :          0 :   , mLabelAttributeName( labelAttributeName )
      35                 :          0 :   , mLabelIndex( -1 )
      36                 :          0 :   , mTolerance( 3 )
      37                 :          0 :   , mToleranceUnit( QgsUnitTypes::RenderMillimeters )
      38                 :          0 :   , mDrawLabels( true )
      39                 :            : 
      40                 :          0 : {
      41                 :          0 :   mRenderer.reset( QgsFeatureRenderer::defaultRenderer( QgsWkbTypes::PointGeometry ) );
      42                 :          0 : }
      43                 :            : 
      44                 :          0 : void QgsPointDistanceRenderer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
      45                 :            : {
      46                 :          0 :   mRenderer->toSld( doc, element, props );
      47                 :          0 : }
      48                 :            : 
      49                 :            : 
      50                 :          0 : bool QgsPointDistanceRenderer::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker )
      51                 :            : {
      52                 :            :   Q_UNUSED( drawVertexMarker )
      53                 :          0 :   Q_UNUSED( context )
      54                 :            :   Q_UNUSED( layer )
      55                 :            : 
      56                 :            :   /*
      57                 :            :    * IMPORTANT: This algorithm is ported to Python in the processing "Points Displacement" algorithm.
      58                 :            :    * Please port any changes/improvements to that algorithm too!
      59                 :            :    */
      60                 :            : 
      61                 :            :   //check if there is already a point at that position
      62                 :          0 :   if ( !feature.hasGeometry() )
      63                 :          0 :     return false;
      64                 :            : 
      65                 :          0 :   QgsMarkerSymbol *symbol = firstSymbolForFeature( feature, context );
      66                 :            : 
      67                 :            :   //if the feature has no symbol (e.g., no matching rule in a rule-based renderer), skip it
      68                 :          0 :   if ( !symbol )
      69                 :          0 :     return false;
      70                 :            : 
      71                 :            :   //point position in screen coords
      72                 :          0 :   QgsGeometry geom = feature.geometry();
      73                 :          0 :   QgsWkbTypes::Type geomType = geom.wkbType();
      74                 :          0 :   if ( QgsWkbTypes::flatType( geomType ) != QgsWkbTypes::Point )
      75                 :            :   {
      76                 :            :     //can only render point type
      77                 :          0 :     return false;
      78                 :            :   }
      79                 :            : 
      80                 :          0 :   QString label;
      81                 :          0 :   if ( mDrawLabels )
      82                 :            :   {
      83                 :          0 :     label = getLabel( feature );
      84                 :          0 :   }
      85                 :            : 
      86                 :          0 :   QgsCoordinateTransform xform = context.coordinateTransform();
      87                 :          0 :   QgsFeature transformedFeature = feature;
      88                 :          0 :   if ( xform.isValid() )
      89                 :            :   {
      90                 :          0 :     geom.transform( xform );
      91                 :          0 :     transformedFeature.setGeometry( geom );
      92                 :          0 :   }
      93                 :            : 
      94                 :          0 :   double searchDistance = context.convertToMapUnits( mTolerance, mToleranceUnit, mToleranceMapUnitScale );
      95                 :          0 :   QgsPointXY point = transformedFeature.geometry().asPoint();
      96                 :          0 :   QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( point, searchDistance ) );
      97                 :          0 :   if ( intersectList.empty() )
      98                 :            :   {
      99                 :          0 :     mSpatialIndex->addFeature( transformedFeature );
     100                 :            :     // create new group
     101                 :          0 :     ClusteredGroup newGroup;
     102                 :          0 :     newGroup << GroupedFeature( transformedFeature, symbol->clone(), selected, label );
     103                 :          0 :     mClusteredGroups.push_back( newGroup );
     104                 :            :     // add to group index
     105                 :          0 :     mGroupIndex.insert( transformedFeature.id(), mClusteredGroups.count() - 1 );
     106                 :          0 :     mGroupLocations.insert( transformedFeature.id(), point );
     107                 :          0 :   }
     108                 :            :   else
     109                 :            :   {
     110                 :            :     // find group with closest location to this point (may be more than one within search tolerance)
     111                 :          0 :     QgsFeatureId minDistFeatureId = intersectList.at( 0 );
     112                 :          0 :     double minDist = mGroupLocations.value( minDistFeatureId ).distance( point );
     113                 :          0 :     for ( int i = 1; i < intersectList.count(); ++i )
     114                 :            :     {
     115                 :          0 :       QgsFeatureId candidateId = intersectList.at( i );
     116                 :          0 :       double newDist = mGroupLocations.value( candidateId ).distance( point );
     117                 :          0 :       if ( newDist < minDist )
     118                 :            :       {
     119                 :          0 :         minDist = newDist;
     120                 :          0 :         minDistFeatureId = candidateId;
     121                 :          0 :       }
     122                 :          0 :     }
     123                 :            : 
     124                 :          0 :     int groupIdx = mGroupIndex[ minDistFeatureId ];
     125                 :          0 :     ClusteredGroup &group = mClusteredGroups[groupIdx];
     126                 :            : 
     127                 :            :     // calculate new centroid of group
     128                 :          0 :     QgsPointXY oldCenter = mGroupLocations.value( minDistFeatureId );
     129                 :          0 :     mGroupLocations[ minDistFeatureId ] = QgsPointXY( ( oldCenter.x() * group.size() + point.x() ) / ( group.size() + 1.0 ),
     130                 :          0 :                                           ( oldCenter.y() * group.size() + point.y() ) / ( group.size() + 1.0 ) );
     131                 :            : 
     132                 :            :     // add to a group
     133                 :          0 :     group << GroupedFeature( transformedFeature, symbol->clone(), selected, label );
     134                 :            :     // add to group index
     135                 :          0 :     mGroupIndex.insert( transformedFeature.id(), groupIdx );
     136                 :            :   }
     137                 :            : 
     138                 :          0 :   return true;
     139                 :          0 : }
     140                 :            : 
     141                 :          0 : void QgsPointDistanceRenderer::drawGroup( const ClusteredGroup &group, QgsRenderContext &context )
     142                 :            : {
     143                 :            :   //calculate centroid of all points, this will be center of group
     144                 :          0 :   QgsMultiPoint *groupMultiPoint = new QgsMultiPoint();
     145                 :          0 :   const auto constGroup = group;
     146                 :          0 :   for ( const GroupedFeature &f : constGroup )
     147                 :            :   {
     148                 :          0 :     groupMultiPoint->addGeometry( f.feature.geometry().constGet()->clone() );
     149                 :            :   }
     150                 :          0 :   QgsGeometry groupGeom( groupMultiPoint );
     151                 :          0 :   QgsGeometry centroid = groupGeom.centroid();
     152                 :          0 :   QPointF pt = centroid.asQPointF();
     153                 :          0 :   context.mapToPixel().transformInPlace( pt.rx(), pt.ry() );
     154                 :            : 
     155                 :          0 :   QgsExpressionContextScopePopper scopePopper( context.expressionContext(), createGroupScope( group ) );
     156                 :          0 :   drawGroup( pt, context, group );
     157                 :          0 : }
     158                 :            : 
     159                 :          0 : void QgsPointDistanceRenderer::setEmbeddedRenderer( QgsFeatureRenderer *r )
     160                 :            : {
     161                 :          0 :   mRenderer.reset( r );
     162                 :          0 : }
     163                 :            : 
     164                 :          0 : const QgsFeatureRenderer *QgsPointDistanceRenderer::embeddedRenderer() const
     165                 :            : {
     166                 :          0 :   return mRenderer.get();
     167                 :            : }
     168                 :            : 
     169                 :          0 : void QgsPointDistanceRenderer::setLegendSymbolItem( const QString &key, QgsSymbol *symbol )
     170                 :            : {
     171                 :          0 :   if ( !mRenderer )
     172                 :          0 :     return;
     173                 :            : 
     174                 :          0 :   mRenderer->setLegendSymbolItem( key, symbol );
     175                 :          0 : }
     176                 :            : 
     177                 :          0 : bool QgsPointDistanceRenderer::legendSymbolItemsCheckable() const
     178                 :            : {
     179                 :          0 :   if ( !mRenderer )
     180                 :          0 :     return false;
     181                 :            : 
     182                 :          0 :   return mRenderer->legendSymbolItemsCheckable();
     183                 :          0 : }
     184                 :            : 
     185                 :          0 : bool QgsPointDistanceRenderer::legendSymbolItemChecked( const QString &key )
     186                 :            : {
     187                 :          0 :   if ( !mRenderer )
     188                 :          0 :     return false;
     189                 :            : 
     190                 :          0 :   return mRenderer->legendSymbolItemChecked( key );
     191                 :          0 : }
     192                 :            : 
     193                 :          0 : void QgsPointDistanceRenderer::checkLegendSymbolItem( const QString &key, bool state )
     194                 :            : {
     195                 :          0 :   if ( !mRenderer )
     196                 :          0 :     return;
     197                 :            : 
     198                 :          0 :   mRenderer->checkLegendSymbolItem( key, state );
     199                 :          0 : }
     200                 :            : 
     201                 :          0 : QString QgsPointDistanceRenderer::filter( const QgsFields &fields )
     202                 :            : {
     203                 :          0 :   if ( !mRenderer )
     204                 :          0 :     return QgsFeatureRenderer::filter( fields );
     205                 :            :   else
     206                 :          0 :     return mRenderer->filter( fields );
     207                 :          0 : }
     208                 :            : 
     209                 :          0 : bool QgsPointDistanceRenderer::accept( QgsStyleEntityVisitorInterface *visitor ) const
     210                 :            : {
     211                 :          0 :   if ( mRenderer )
     212                 :          0 :     if ( !mRenderer->accept( visitor ) )
     213                 :          0 :       return false;
     214                 :            : 
     215                 :          0 :   return true;
     216                 :          0 : }
     217                 :            : 
     218                 :          0 : QSet<QString> QgsPointDistanceRenderer::usedAttributes( const QgsRenderContext &context ) const
     219                 :            : {
     220                 :          0 :   QSet<QString> attributeList;
     221                 :          0 :   if ( !mLabelAttributeName.isEmpty() )
     222                 :            :   {
     223                 :          0 :     attributeList.insert( mLabelAttributeName );
     224                 :          0 :   }
     225                 :          0 :   if ( mRenderer )
     226                 :            :   {
     227                 :          0 :     attributeList += mRenderer->usedAttributes( context );
     228                 :          0 :   }
     229                 :          0 :   return attributeList;
     230                 :          0 : }
     231                 :            : 
     232                 :          0 : bool QgsPointDistanceRenderer::filterNeedsGeometry() const
     233                 :            : {
     234                 :          0 :   return mRenderer ? mRenderer->filterNeedsGeometry() : false;
     235                 :            : }
     236                 :            : 
     237                 :          0 : QgsFeatureRenderer::Capabilities QgsPointDistanceRenderer::capabilities()
     238                 :            : {
     239                 :          0 :   if ( !mRenderer )
     240                 :            :   {
     241                 :          0 :     return Capabilities();
     242                 :            :   }
     243                 :          0 :   return mRenderer->capabilities();
     244                 :          0 : }
     245                 :            : 
     246                 :          0 : QgsSymbolList QgsPointDistanceRenderer::symbols( QgsRenderContext &context ) const
     247                 :            : {
     248                 :          0 :   if ( !mRenderer )
     249                 :            :   {
     250                 :          0 :     return QgsSymbolList();
     251                 :            :   }
     252                 :          0 :   return mRenderer->symbols( context );
     253                 :          0 : }
     254                 :            : 
     255                 :          0 : QgsSymbol *QgsPointDistanceRenderer::symbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
     256                 :          0 : {
     257                 :          0 :   if ( !mRenderer )
     258                 :            :   {
     259                 :          0 :     return nullptr;
     260                 :            :   }
     261                 :          0 :   return mRenderer->symbolForFeature( feature, context );
     262                 :          0 : }
     263                 :            : 
     264                 :          0 : QgsSymbol *QgsPointDistanceRenderer::originalSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
     265                 :            : {
     266                 :          0 :   if ( !mRenderer )
     267                 :          0 :     return nullptr;
     268                 :          0 :   return mRenderer->originalSymbolForFeature( feature, context );
     269                 :          0 : }
     270                 :            : 
     271                 :          0 : QgsSymbolList QgsPointDistanceRenderer::symbolsForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
     272                 :            : {
     273                 :          0 :   if ( !mRenderer )
     274                 :            :   {
     275                 :          0 :     return QgsSymbolList();
     276                 :            :   }
     277                 :          0 :   return mRenderer->symbolsForFeature( feature, context );
     278                 :          0 : }
     279                 :            : 
     280                 :          0 : QgsSymbolList QgsPointDistanceRenderer::originalSymbolsForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
     281                 :            : {
     282                 :          0 :   if ( !mRenderer )
     283                 :          0 :     return QgsSymbolList();
     284                 :          0 :   return mRenderer->originalSymbolsForFeature( feature, context );
     285                 :          0 : }
     286                 :            : 
     287                 :          0 : QSet< QString > QgsPointDistanceRenderer::legendKeysForFeature( const QgsFeature &feature, QgsRenderContext &context ) const
     288                 :            : {
     289                 :          0 :   if ( !mRenderer )
     290                 :          0 :     return QSet< QString >() << QString();
     291                 :          0 :   return mRenderer->legendKeysForFeature( feature, context );
     292                 :          0 : }
     293                 :            : 
     294                 :          0 : bool QgsPointDistanceRenderer::willRenderFeature( const QgsFeature &feature, QgsRenderContext &context ) const
     295                 :            : {
     296                 :          0 :   if ( !mRenderer )
     297                 :            :   {
     298                 :          0 :     return false;
     299                 :            :   }
     300                 :          0 :   return mRenderer->willRenderFeature( feature, context );
     301                 :          0 : }
     302                 :            : 
     303                 :            : 
     304                 :          0 : void QgsPointDistanceRenderer::startRender( QgsRenderContext &context, const QgsFields &fields )
     305                 :            : {
     306                 :          0 :   QgsFeatureRenderer::startRender( context, fields );
     307                 :            : 
     308                 :          0 :   mRenderer->startRender( context, fields );
     309                 :            : 
     310                 :          0 :   mClusteredGroups.clear();
     311                 :          0 :   mGroupIndex.clear();
     312                 :          0 :   mGroupLocations.clear();
     313                 :          0 :   mSpatialIndex = new QgsSpatialIndex;
     314                 :            : 
     315                 :          0 :   if ( mLabelAttributeName.isEmpty() )
     316                 :            :   {
     317                 :          0 :     mLabelIndex = -1;
     318                 :          0 :   }
     319                 :            :   else
     320                 :            :   {
     321                 :          0 :     mLabelIndex = fields.lookupField( mLabelAttributeName );
     322                 :            :   }
     323                 :            : 
     324                 :          0 :   if ( mMinLabelScale <= 0 || context.rendererScale() < mMinLabelScale )
     325                 :            :   {
     326                 :          0 :     mDrawLabels = true;
     327                 :          0 :   }
     328                 :            :   else
     329                 :            :   {
     330                 :          0 :     mDrawLabels = false;
     331                 :            :   }
     332                 :          0 : }
     333                 :            : 
     334                 :          0 : void QgsPointDistanceRenderer::stopRender( QgsRenderContext &context )
     335                 :            : {
     336                 :          0 :   QgsFeatureRenderer::stopRender( context );
     337                 :            : 
     338                 :            :   //printInfoDisplacementGroups(); //just for debugging
     339                 :            : 
     340                 :          0 :   if ( !context.renderingStopped() )
     341                 :            :   {
     342                 :          0 :     const auto constMClusteredGroups = mClusteredGroups;
     343                 :          0 :     for ( const ClusteredGroup &group : constMClusteredGroups )
     344                 :            :     {
     345                 :          0 :       drawGroup( group, context );
     346                 :            :     }
     347                 :          0 :   }
     348                 :            : 
     349                 :          0 :   mClusteredGroups.clear();
     350                 :          0 :   mGroupIndex.clear();
     351                 :          0 :   mGroupLocations.clear();
     352                 :          0 :   delete mSpatialIndex;
     353                 :          0 :   mSpatialIndex = nullptr;
     354                 :            : 
     355                 :          0 :   mRenderer->stopRender( context );
     356                 :          0 : }
     357                 :            : 
     358                 :          0 : QgsLegendSymbolList QgsPointDistanceRenderer::legendSymbolItems() const
     359                 :            : {
     360                 :          0 :   if ( mRenderer )
     361                 :            :   {
     362                 :          0 :     return mRenderer->legendSymbolItems();
     363                 :            :   }
     364                 :          0 :   return QgsLegendSymbolList();
     365                 :          0 : }
     366                 :            : 
     367                 :          0 : QgsRectangle QgsPointDistanceRenderer::searchRect( const QgsPointXY &p, double distance ) const
     368                 :            : {
     369                 :          0 :   return QgsRectangle( p.x() - distance, p.y() - distance, p.x() + distance, p.y() + distance );
     370                 :            : }
     371                 :            : 
     372                 :          0 : void QgsPointDistanceRenderer::printGroupInfo() const
     373                 :            : {
     374                 :            : #ifdef QGISDEBUG
     375                 :            :   int nGroups = mClusteredGroups.size();
     376                 :            :   QgsDebugMsgLevel( "number of displacement groups:" + QString::number( nGroups ), 3 );
     377                 :            :   for ( int i = 0; i < nGroups; ++i )
     378                 :            :   {
     379                 :            :     QgsDebugMsgLevel( "***************displacement group " + QString::number( i ), 3 );
     380                 :            :     const auto constAt = mClusteredGroups.at( i );
     381                 :            :     for ( const GroupedFeature &feature : constAt )
     382                 :            :     {
     383                 :            :       QgsDebugMsgLevel( FID_TO_STRING( feature.feature.id() ), 3 );
     384                 :            :     }
     385                 :            :   }
     386                 :            : #endif
     387                 :          0 : }
     388                 :            : 
     389                 :          0 : QString QgsPointDistanceRenderer::getLabel( const QgsFeature &feature ) const
     390                 :            : {
     391                 :          0 :   QString attribute;
     392                 :          0 :   QgsAttributes attrs = feature.attributes();
     393                 :          0 :   if ( mLabelIndex >= 0 && mLabelIndex < attrs.count() )
     394                 :            :   {
     395                 :          0 :     attribute = attrs.at( mLabelIndex ).toString();
     396                 :          0 :   }
     397                 :          0 :   return attribute;
     398                 :          0 : }
     399                 :            : 
     400                 :          0 : void QgsPointDistanceRenderer::drawLabels( QPointF centerPoint, QgsSymbolRenderContext &context, const QList<QPointF> &labelShifts, const ClusteredGroup &group )
     401                 :            : {
     402                 :          0 :   QPainter *p = context.renderContext().painter();
     403                 :          0 :   if ( !p )
     404                 :            :   {
     405                 :          0 :     return;
     406                 :            :   }
     407                 :            : 
     408                 :          0 :   QPen labelPen( mLabelColor );
     409                 :          0 :   p->setPen( labelPen );
     410                 :            : 
     411                 :            :   //scale font (for printing)
     412                 :          0 :   QFont pixelSizeFont = mLabelFont;
     413                 :            : 
     414                 :          0 :   const double fontSizeInPixels = context.renderContext().convertToPainterUnits( mLabelFont.pointSizeF(), QgsUnitTypes::RenderPoints );
     415                 :          0 :   pixelSizeFont.setPixelSize( static_cast< int >( std::round( fontSizeInPixels ) ) );
     416                 :          0 :   QFont scaledFont = pixelSizeFont;
     417                 :          0 :   scaledFont.setPixelSize( pixelSizeFont.pixelSize() );
     418                 :          0 :   p->setFont( scaledFont );
     419                 :            : 
     420                 :          0 :   QFontMetricsF fontMetrics( pixelSizeFont );
     421                 :          0 :   QPointF currentLabelShift; //considers the signs to determine the label position
     422                 :            : 
     423                 :          0 :   QList<QPointF>::const_iterator labelPosIt = labelShifts.constBegin();
     424                 :          0 :   ClusteredGroup::const_iterator groupIt = group.constBegin();
     425                 :            : 
     426                 :          0 :   for ( ; labelPosIt != labelShifts.constEnd() && groupIt != group.constEnd(); ++labelPosIt, ++groupIt )
     427                 :            :   {
     428                 :          0 :     currentLabelShift = *labelPosIt;
     429                 :          0 :     if ( currentLabelShift.x() < 0 )
     430                 :            :     {
     431                 :          0 :       currentLabelShift.setX( currentLabelShift.x() - fontMetrics.horizontalAdvance( groupIt->label ) );
     432                 :          0 :     }
     433                 :          0 :     if ( currentLabelShift.y() > 0 )
     434                 :            :     {
     435                 :          0 :       currentLabelShift.setY( currentLabelShift.y() + fontMetrics.ascent() );
     436                 :          0 :     }
     437                 :            : 
     438                 :          0 :     QPointF drawingPoint( centerPoint + currentLabelShift );
     439                 :          0 :     QgsScopedQPainterState painterState( p );
     440                 :          0 :     p->translate( drawingPoint.x(), drawingPoint.y() );
     441                 :          0 :     p->drawText( QPointF( 0, 0 ), groupIt->label );
     442                 :          0 :   }
     443                 :          0 : }
     444                 :            : 
     445                 :          0 : QgsExpressionContextScope *QgsPointDistanceRenderer::createGroupScope( const ClusteredGroup &group ) const
     446                 :            : {
     447                 :          0 :   QgsExpressionContextScope *clusterScope = new QgsExpressionContextScope();
     448                 :          0 :   if ( group.size() > 1 )
     449                 :            :   {
     450                 :            :     //scan through symbols to check color, e.g., if all clustered symbols are same color
     451                 :          0 :     QColor groupColor;
     452                 :          0 :     ClusteredGroup::const_iterator groupIt = group.constBegin();
     453                 :          0 :     for ( ; groupIt != group.constEnd(); ++groupIt )
     454                 :            :     {
     455                 :          0 :       if ( !groupIt->symbol() )
     456                 :          0 :         continue;
     457                 :            : 
     458                 :          0 :       if ( !groupColor.isValid() )
     459                 :            :       {
     460                 :          0 :         groupColor = groupIt->symbol()->color();
     461                 :          0 :       }
     462                 :            :       else
     463                 :            :       {
     464                 :          0 :         if ( groupColor != groupIt->symbol()->color() )
     465                 :            :         {
     466                 :          0 :           groupColor = QColor();
     467                 :          0 :           break;
     468                 :            :         }
     469                 :            :       }
     470                 :          0 :     }
     471                 :            : 
     472                 :          0 :     if ( groupColor.isValid() )
     473                 :            :     {
     474                 :          0 :       clusterScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, QgsSymbolLayerUtils::encodeColor( groupColor ), true ) );
     475                 :          0 :     }
     476                 :            :     else
     477                 :            :     {
     478                 :            :       //mixed colors
     479                 :          0 :       clusterScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, QVariant(), true ) );
     480                 :            :     }
     481                 :            : 
     482                 :          0 :     clusterScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, group.size(), true ) );
     483                 :          0 :   }
     484                 :          0 :   if ( !group.empty() )
     485                 :            :   {
     486                 :            :     // data defined properties may require a feature in the expression context, so just use first feature in group
     487                 :          0 :     clusterScope->setFeature( group.at( 0 ).feature );
     488                 :          0 :   }
     489                 :          0 :   return clusterScope;
     490                 :          0 : }
     491                 :            : 
     492                 :          0 : QgsMarkerSymbol *QgsPointDistanceRenderer::firstSymbolForFeature( const QgsFeature &feature, QgsRenderContext &context )
     493                 :            : {
     494                 :          0 :   if ( !mRenderer )
     495                 :            :   {
     496                 :          0 :     return nullptr;
     497                 :            :   }
     498                 :            : 
     499                 :          0 :   QgsSymbolList symbolList = mRenderer->symbolsForFeature( feature, context );
     500                 :          0 :   if ( symbolList.isEmpty() )
     501                 :            :   {
     502                 :          0 :     return nullptr;
     503                 :            :   }
     504                 :            : 
     505                 :          0 :   return dynamic_cast< QgsMarkerSymbol * >( symbolList.at( 0 ) );
     506                 :          0 : }

Generated by: LCOV version 1.14