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

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :          qgspointdisplacementrenderer.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 "qgspointdisplacementrenderer.h"
      19                 :            : #include "qgssymbollayerutils.h"
      20                 :            : #include "qgsfontutils.h"
      21                 :            : #include "qgspainteffectregistry.h"
      22                 :            : #include "qgspainteffect.h"
      23                 :            : #include "qgspointclusterrenderer.h"
      24                 :            : #include "qgsstyleentityvisitor.h"
      25                 :            : #include "qgsrenderedfeaturehandlerinterface.h"
      26                 :            : 
      27                 :            : #include <QPainter>
      28                 :            : #include <cmath>
      29                 :            : 
      30                 :          0 : QgsPointDisplacementRenderer::QgsPointDisplacementRenderer( const QString &labelAttributeName )
      31                 :          0 :   : QgsPointDistanceRenderer( QStringLiteral( "pointDisplacement" ), labelAttributeName )
      32                 :          0 :   , mCircleColor( QColor( 125, 125, 125 ) )
      33                 :          0 : {
      34                 :          0 :   mCenterSymbol.reset( new QgsMarkerSymbol() );
      35                 :          0 : }
      36                 :            : 
      37                 :          0 : QgsPointDisplacementRenderer *QgsPointDisplacementRenderer::clone() const
      38                 :            : {
      39                 :          0 :   QgsPointDisplacementRenderer *r = new QgsPointDisplacementRenderer( mLabelAttributeName );
      40                 :          0 :   if ( mRenderer )
      41                 :          0 :     r->setEmbeddedRenderer( mRenderer->clone() );
      42                 :          0 :   r->setCircleWidth( mCircleWidth );
      43                 :          0 :   r->setCircleColor( mCircleColor );
      44                 :          0 :   r->setLabelFont( mLabelFont );
      45                 :          0 :   r->setLabelColor( mLabelColor );
      46                 :          0 :   r->setPlacement( mPlacement );
      47                 :          0 :   r->setCircleRadiusAddition( mCircleRadiusAddition );
      48                 :          0 :   r->setLabelDistanceFactor( mLabelDistanceFactor );
      49                 :          0 :   r->setMinimumLabelScale( mMinLabelScale );
      50                 :          0 :   r->setTolerance( mTolerance );
      51                 :          0 :   r->setToleranceUnit( mToleranceUnit );
      52                 :          0 :   r->setToleranceMapUnitScale( mToleranceMapUnitScale );
      53                 :          0 :   if ( mCenterSymbol )
      54                 :            :   {
      55                 :          0 :     r->setCenterSymbol( mCenterSymbol->clone() );
      56                 :          0 :   }
      57                 :          0 :   copyRendererData( r );
      58                 :          0 :   return r;
      59                 :          0 : }
      60                 :            : 
      61                 :          0 : void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderContext &context, const ClusteredGroup &group )
      62                 :            : {
      63                 :            : 
      64                 :            :   //calculate max diagonal size from all symbols in group
      65                 :          0 :   double diagonal = 0;
      66                 :          0 :   QVector<double> diagonals( group.size() );
      67                 :            :   double currentDiagonal;
      68                 :            : 
      69                 :          0 :   int groupPosition = 0;
      70                 :          0 :   for ( const GroupedFeature &feature : group )
      71                 :            :   {
      72                 :          0 :     if ( QgsMarkerSymbol *symbol = feature.symbol() )
      73                 :            :     {
      74                 :          0 :       currentDiagonal = M_SQRT2 * symbol->size( context );
      75                 :          0 :       diagonals[groupPosition] = currentDiagonal;
      76                 :          0 :       diagonal = std::max( diagonal, currentDiagonal );
      77                 :            : 
      78                 :          0 :     }
      79                 :            :     else
      80                 :            :     {
      81                 :          0 :       diagonals[groupPosition] = 0.0;
      82                 :            :     }
      83                 :          0 :     groupPosition++;
      84                 :            :   }
      85                 :            : 
      86                 :          0 :   QgsSymbolRenderContext symbolContext( context, QgsUnitTypes::RenderMillimeters, 1.0, false );
      87                 :            : 
      88                 :          0 :   QList<QPointF> symbolPositions;
      89                 :          0 :   QList<QPointF> labelPositions;
      90                 :          0 :   double circleRadius = -1.0;
      91                 :          0 :   double gridRadius = -1.0;
      92                 :          0 :   int gridSize = -1;
      93                 :            : 
      94                 :          0 :   calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );
      95                 :            : 
      96                 :            :   //only draw circle/grid if there's a pen present - otherwise skip drawing transparent grids
      97                 :          0 :   if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
      98                 :            :   {
      99                 :            :     //draw circle
     100                 :          0 :     if ( circleRadius > 0 )
     101                 :          0 :       drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
     102                 :            :     //draw grid
     103                 :            :     else
     104                 :          0 :       drawGrid( gridSize, symbolContext, symbolPositions, group.size() );
     105                 :          0 :   }
     106                 :            : 
     107                 :          0 :   if ( group.size() > 1 )
     108                 :            :   {
     109                 :            :     //draw mid point
     110                 :          0 :     QgsFeature firstFeature = group.at( 0 ).feature;
     111                 :          0 :     if ( mCenterSymbol )
     112                 :            :     {
     113                 :          0 :       mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1, false );
     114                 :          0 :     }
     115                 :            :     else
     116                 :            :     {
     117                 :          0 :       const double rectSize = symbolContext.renderContext().convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
     118                 :          0 :       context.painter()->drawRect( QRectF( centerPoint.x() - rectSize, centerPoint.y() - rectSize, rectSize * 2, rectSize * 2 ) );
     119                 :            :     }
     120                 :          0 :   }
     121                 :            : 
     122                 :            :   //draw symbols on the circle
     123                 :          0 :   drawSymbols( group, context, symbolPositions );
     124                 :            :   //and also the labels
     125                 :          0 :   if ( mLabelIndex >= 0 )
     126                 :            :   {
     127                 :          0 :     drawLabels( centerPoint, symbolContext, labelPositions, group );
     128                 :          0 :   }
     129                 :          0 : }
     130                 :            : 
     131                 :            : 
     132                 :          0 : void QgsPointDisplacementRenderer::startRender( QgsRenderContext &context, const QgsFields &fields )
     133                 :            : {
     134                 :          0 :   if ( mCenterSymbol )
     135                 :            :   {
     136                 :          0 :     mCenterSymbol->startRender( context, fields );
     137                 :          0 :   }
     138                 :            : 
     139                 :          0 :   QgsPointDistanceRenderer::startRender( context, fields );
     140                 :          0 : }
     141                 :            : 
     142                 :          0 : void QgsPointDisplacementRenderer::stopRender( QgsRenderContext &context )
     143                 :            : {
     144                 :          0 :   QgsPointDistanceRenderer::stopRender( context );
     145                 :          0 :   if ( mCenterSymbol )
     146                 :            :   {
     147                 :          0 :     mCenterSymbol->stopRender( context );
     148                 :          0 :   }
     149                 :          0 : }
     150                 :            : 
     151                 :          0 : QgsFeatureRenderer *QgsPointDisplacementRenderer::create( QDomElement &symbologyElem, const QgsReadWriteContext &context )
     152                 :            : {
     153                 :          0 :   QgsPointDisplacementRenderer *r = new QgsPointDisplacementRenderer();
     154                 :          0 :   r->setLabelAttributeName( symbologyElem.attribute( QStringLiteral( "labelAttributeName" ) ) );
     155                 :          0 :   QFont labelFont;
     156                 :          0 :   if ( !QgsFontUtils::setFromXmlChildNode( labelFont, symbologyElem, QStringLiteral( "labelFontProperties" ) ) )
     157                 :            :   {
     158                 :          0 :     labelFont.fromString( symbologyElem.attribute( QStringLiteral( "labelFont" ), QString() ) );
     159                 :          0 :   }
     160                 :          0 :   r->setLabelFont( labelFont );
     161                 :          0 :   r->setPlacement( static_cast< Placement >( symbologyElem.attribute( QStringLiteral( "placement" ), QStringLiteral( "0" ) ).toInt() ) );
     162                 :          0 :   r->setCircleWidth( symbologyElem.attribute( QStringLiteral( "circleWidth" ), QStringLiteral( "0.4" ) ).toDouble() );
     163                 :          0 :   r->setCircleColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "circleColor" ), QString() ) ) );
     164                 :          0 :   r->setLabelColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "labelColor" ), QString() ) ) );
     165                 :          0 :   r->setCircleRadiusAddition( symbologyElem.attribute( QStringLiteral( "circleRadiusAddition" ), QStringLiteral( "0.0" ) ).toDouble() );
     166                 :          0 :   r->setLabelDistanceFactor( symbologyElem.attribute( QStringLiteral( "labelDistanceFactor" ), QStringLiteral( "0.5" ) ).toDouble() );
     167                 :          0 :   r->setMinimumLabelScale( symbologyElem.attribute( QStringLiteral( "maxLabelScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble() );
     168                 :          0 :   r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
     169                 :          0 :   r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
     170                 :          0 :   r->setToleranceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( symbologyElem.attribute( QStringLiteral( "toleranceUnitScale" ) ) ) );
     171                 :            : 
     172                 :          0 :   //look for an embedded renderer <renderer-v2>
     173                 :          0 :   QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral( "renderer-v2" ) );
     174                 :          0 :   if ( !embeddedRendererElem.isNull() )
     175                 :            :   {
     176                 :          0 :     r->setEmbeddedRenderer( QgsFeatureRenderer::load( embeddedRendererElem, context ) );
     177                 :          0 :   }
     178                 :            : 
     179                 :            :   //center symbol
     180                 :          0 :   QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral( "symbol" ) );
     181                 :          0 :   if ( !centerSymbolElem.isNull() )
     182                 :            :   {
     183                 :          0 :     r->setCenterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
     184                 :          0 :   }
     185                 :          0 :   return r;
     186                 :          0 : }
     187                 :            : 
     188                 :          0 : QgsMarkerSymbol *QgsPointDisplacementRenderer::centerSymbol()
     189                 :            : {
     190                 :          0 :   return mCenterSymbol.get();
     191                 :            : }
     192                 :            : 
     193                 :          0 : QDomElement QgsPointDisplacementRenderer::save( QDomDocument &doc, const QgsReadWriteContext &context )
     194                 :            : {
     195                 :          0 :   QDomElement rendererElement = doc.createElement( RENDERER_TAG_NAME );
     196                 :          0 :   rendererElement.setAttribute( QStringLiteral( "forceraster" ), ( mForceRaster ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
     197                 :          0 :   rendererElement.setAttribute( QStringLiteral( "type" ), QStringLiteral( "pointDisplacement" ) );
     198                 :          0 :   rendererElement.setAttribute( QStringLiteral( "labelAttributeName" ), mLabelAttributeName );
     199                 :          0 :   rendererElement.appendChild( QgsFontUtils::toXmlElement( mLabelFont, doc, QStringLiteral( "labelFontProperties" ) ) );
     200                 :          0 :   rendererElement.setAttribute( QStringLiteral( "circleWidth" ), QString::number( mCircleWidth ) );
     201                 :          0 :   rendererElement.setAttribute( QStringLiteral( "circleColor" ), QgsSymbolLayerUtils::encodeColor( mCircleColor ) );
     202                 :          0 :   rendererElement.setAttribute( QStringLiteral( "labelColor" ), QgsSymbolLayerUtils::encodeColor( mLabelColor ) );
     203                 :          0 :   rendererElement.setAttribute( QStringLiteral( "circleRadiusAddition" ), QString::number( mCircleRadiusAddition ) );
     204                 :          0 :   rendererElement.setAttribute( QStringLiteral( "labelDistanceFactor" ), QString::number( mLabelDistanceFactor ) );
     205                 :          0 :   rendererElement.setAttribute( QStringLiteral( "placement" ), static_cast< int >( mPlacement ) );
     206                 :          0 :   rendererElement.setAttribute( QStringLiteral( "maxLabelScaleDenominator" ), QString::number( mMinLabelScale ) );
     207                 :          0 :   rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
     208                 :          0 :   rendererElement.setAttribute( QStringLiteral( "toleranceUnit" ), QgsUnitTypes::encodeUnit( mToleranceUnit ) );
     209                 :          0 :   rendererElement.setAttribute( QStringLiteral( "toleranceUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mToleranceMapUnitScale ) );
     210                 :            : 
     211                 :          0 :   if ( mRenderer )
     212                 :            :   {
     213                 :          0 :     QDomElement embeddedRendererElem = mRenderer->save( doc, context );
     214                 :          0 :     rendererElement.appendChild( embeddedRendererElem );
     215                 :          0 :   }
     216                 :          0 :   if ( mCenterSymbol )
     217                 :            :   {
     218                 :          0 :     QDomElement centerSymbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "centerSymbol" ), mCenterSymbol.get(), doc, context );
     219                 :          0 :     rendererElement.appendChild( centerSymbolElem );
     220                 :          0 :   }
     221                 :            : 
     222                 :          0 :   if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
     223                 :          0 :     mPaintEffect->saveProperties( doc, rendererElement );
     224                 :            : 
     225                 :          0 :   if ( !mOrderBy.isEmpty() )
     226                 :            :   {
     227                 :          0 :     QDomElement orderBy = doc.createElement( QStringLiteral( "orderby" ) );
     228                 :          0 :     mOrderBy.save( orderBy );
     229                 :          0 :     rendererElement.appendChild( orderBy );
     230                 :          0 :   }
     231                 :          0 :   rendererElement.setAttribute( QStringLiteral( "enableorderby" ), ( mOrderByEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ) );
     232                 :            : 
     233                 :          0 :   return rendererElement;
     234                 :          0 : }
     235                 :            : 
     236                 :          0 : QSet<QString> QgsPointDisplacementRenderer::usedAttributes( const QgsRenderContext &context ) const
     237                 :            : {
     238                 :          0 :   QSet<QString> attr = QgsPointDistanceRenderer::usedAttributes( context );
     239                 :          0 :   if ( mCenterSymbol )
     240                 :          0 :     attr.unite( mCenterSymbol->usedAttributes( context ) );
     241                 :          0 :   return attr;
     242                 :          0 : }
     243                 :            : 
     244                 :          0 : bool QgsPointDisplacementRenderer::accept( QgsStyleEntityVisitorInterface *visitor ) const
     245                 :            : {
     246                 :          0 :   if ( !QgsPointDistanceRenderer::accept( visitor ) )
     247                 :          0 :     return false;
     248                 :            : 
     249                 :          0 :   if ( mCenterSymbol )
     250                 :            :   {
     251                 :          0 :     QgsStyleSymbolEntity entity( mCenterSymbol.get() );
     252                 :          0 :     if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, QStringLiteral( "center" ), QObject::tr( "Center Symbol" ) ) ) )
     253                 :          0 :       return false;
     254                 :          0 :   }
     255                 :            : 
     256                 :          0 :   return true;
     257                 :          0 : }
     258                 :            : 
     259                 :          0 : void QgsPointDisplacementRenderer::setCenterSymbol( QgsMarkerSymbol *symbol )
     260                 :            : {
     261                 :          0 :   mCenterSymbol.reset( symbol );
     262                 :          0 : }
     263                 :            : 
     264                 :          0 : void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
     265                 :            :     double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
     266                 :            :     int &gridSize, QVector<double> &diagonals ) const
     267                 :            : {
     268                 :          0 :   symbolPositions.clear();
     269                 :          0 :   labelShifts.clear();
     270                 :            : 
     271                 :          0 :   if ( nPosition < 1 )
     272                 :            :   {
     273                 :          0 :     return;
     274                 :            :   }
     275                 :          0 :   else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
     276                 :            :   {
     277                 :          0 :     const double side = std::sqrt( std::pow( symbolDiagonal, 2 ) / 2.0 );
     278                 :          0 :     symbolPositions.append( centerPoint );
     279                 :          0 :     labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
     280                 :          0 :     return;
     281                 :            :   }
     282                 :            : 
     283                 :          0 :   double circleAdditionPainterUnits = symbolContext.renderContext().convertToPainterUnits( mCircleRadiusAddition, QgsUnitTypes::RenderMillimeters );
     284                 :            : 
     285                 :          0 :   switch ( mPlacement )
     286                 :            :   {
     287                 :            :     case Ring:
     288                 :            :     {
     289                 :          0 :       const double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
     290                 :          0 :       const double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
     291                 :            : 
     292                 :          0 :       const double angleStep = 2 * M_PI / nPosition;
     293                 :          0 :       double currentAngle = 0.0;
     294                 :          0 :       for ( int featureIndex = 0; featureIndex < nPosition; currentAngle += angleStep, featureIndex++ )
     295                 :            :       {
     296                 :          0 :         const double sinusCurrentAngle = std::sin( currentAngle );
     297                 :          0 :         const double cosinusCurrentAngle = std::cos( currentAngle );
     298                 :          0 :         const QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
     299                 :            : 
     300                 :          0 :         const QPointF labelShift( ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
     301                 :          0 :         symbolPositions.append( centerPoint + positionShift );
     302                 :          0 :         labelShifts.append( labelShift );
     303                 :          0 :       }
     304                 :          0 :       circleRadius = radius;
     305                 :          0 :       break;
     306                 :            :     }
     307                 :            :     case ConcentricRings:
     308                 :            :     {
     309                 :          0 :       double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
     310                 :            : 
     311                 :          0 :       int pointsRemaining = nPosition;
     312                 :          0 :       int ringNumber = 1;
     313                 :          0 :       double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
     314                 :          0 :       int featureIndex = 0;
     315                 :          0 :       while ( pointsRemaining > 0 )
     316                 :            :       {
     317                 :          0 :         double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
     318                 :          0 :         int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
     319                 :          0 :         int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining );
     320                 :            : 
     321                 :          0 :         double angleStep = 2 * M_PI / actualPointsCurrentRing;
     322                 :          0 :         double currentAngle = 0.0;
     323                 :          0 :         for ( int i = 0; i < actualPointsCurrentRing; ++i )
     324                 :            :         {
     325                 :          0 :           double sinusCurrentAngle = std::sin( currentAngle );
     326                 :          0 :           double cosinusCurrentAngle = std::cos( currentAngle );
     327                 :          0 :           QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
     328                 :          0 :           QPointF labelShift( ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
     329                 :          0 :           symbolPositions.append( centerPoint + positionShift );
     330                 :          0 :           labelShifts.append( labelShift );
     331                 :          0 :           currentAngle += angleStep;
     332                 :          0 :           featureIndex++;
     333                 :          0 :         }
     334                 :            : 
     335                 :          0 :         pointsRemaining -= actualPointsCurrentRing;
     336                 :          0 :         ringNumber++;
     337                 :          0 :         circleRadius = radiusCurrentRing;
     338                 :            :       }
     339                 :          0 :       break;
     340                 :            :     }
     341                 :            :     case Grid:
     342                 :            :     {
     343                 :          0 :       double centerDiagonal = mCenterSymbol->size( symbolContext.renderContext() ) * M_SQRT2;
     344                 :          0 :       int pointsRemaining = nPosition;
     345                 :          0 :       gridSize = std::ceil( std::sqrt( pointsRemaining ) );
     346                 :          0 :       if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
     347                 :          0 :         gridSize -= 1;
     348                 :          0 :       double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
     349                 :          0 :       double userPointRadius =  originalPointRadius + circleAdditionPainterUnits;
     350                 :            : 
     351                 :          0 :       int yIndex = 0;
     352                 :          0 :       while ( pointsRemaining > 0 )
     353                 :            :       {
     354                 :          0 :         for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
     355                 :            :         {
     356                 :          0 :           QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
     357                 :          0 :           symbolPositions.append( centerPoint + positionShift );
     358                 :          0 :           pointsRemaining--;
     359                 :          0 :         }
     360                 :          0 :         yIndex++;
     361                 :            :       }
     362                 :            : 
     363                 :          0 :       centralizeGrid( symbolPositions, userPointRadius, gridSize );
     364                 :            : 
     365                 :            :       int xFactor;
     366                 :            :       int yFactor;
     367                 :          0 :       double side = 0;
     368                 :          0 :       for ( int symbolIndex = 0; symbolIndex < symbolPositions.size(); ++symbolIndex )
     369                 :            :       {
     370                 :          0 :         if ( symbolPositions.at( symbolIndex ).x() < centerPoint.x() )
     371                 :            :         {
     372                 :          0 :           xFactor = -1;
     373                 :          0 :         }
     374                 :            :         else
     375                 :            :         {
     376                 :          0 :           xFactor = 1;
     377                 :            :         }
     378                 :            : 
     379                 :          0 :         if ( symbolPositions.at( symbolIndex ).y() < centerPoint.y() )
     380                 :            :         {
     381                 :          0 :           yFactor = 1;
     382                 :          0 :         }
     383                 :            :         else
     384                 :            :         {
     385                 :          0 :           yFactor = -1;
     386                 :            :         }
     387                 :            : 
     388                 :          0 :         side = std::sqrt( std::pow( diagonals.at( symbolIndex ), 2 ) / 2.0 );
     389                 :          0 :         QPointF labelShift( ( side * mLabelDistanceFactor * xFactor ), ( -side * mLabelDistanceFactor * yFactor ) );
     390                 :          0 :         labelShifts.append( symbolPositions.at( symbolIndex ) - centerPoint + labelShift );
     391                 :          0 :       }
     392                 :            : 
     393                 :          0 :       gridRadius = userPointRadius;
     394                 :          0 :       break;
     395                 :            :     }
     396                 :            :   }
     397                 :          0 : }
     398                 :            : 
     399                 :          0 : void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions, double radius, int size ) const
     400                 :            : {
     401                 :          0 :   double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
     402                 :          0 :   QPointF centralShift( shiftAmount, shiftAmount );
     403                 :          0 :   for ( int i = 0; i < pointSymbolPositions.size(); ++i )
     404                 :            :   {
     405                 :          0 :     pointSymbolPositions[i] += centralShift;
     406                 :          0 :   }
     407                 :          0 : }
     408                 :            : 
     409                 :          0 : void QgsPointDisplacementRenderer::drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
     410                 :            :     QList<QPointF> pointSymbolPositions, int nSymbols )
     411                 :            : {
     412                 :          0 :   QPainter *p = context.renderContext().painter();
     413                 :          0 :   if ( nSymbols < 2 || !p ) //draw grid only if multiple features
     414                 :            :   {
     415                 :          0 :     return;
     416                 :            :   }
     417                 :            : 
     418                 :          0 :   QPen gridPen( mCircleColor );
     419                 :          0 :   gridPen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, QgsUnitTypes::RenderMillimeters ) );
     420                 :          0 :   p->setPen( gridPen );
     421                 :            : 
     422                 :          0 :   for ( int i = 0; i < pointSymbolPositions.size(); ++i )
     423                 :            :   {
     424                 :          0 :     if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
     425                 :            :     {
     426                 :          0 :       QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
     427                 :          0 :       p->drawLine( gridLineRow );
     428                 :          0 :     }
     429                 :            : 
     430                 :          0 :     if ( i + gridSizeUnits < pointSymbolPositions.size() )
     431                 :            :     {
     432                 :          0 :       QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
     433                 :          0 :       p->drawLine( gridLineColumn );
     434                 :          0 :     }
     435                 :          0 :   }
     436                 :          0 : }
     437                 :            : 
     438                 :          0 : void QgsPointDisplacementRenderer::drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols )
     439                 :            : {
     440                 :          0 :   QPainter *p = context.renderContext().painter();
     441                 :          0 :   if ( nSymbols < 2 || !p ) //draw circle only if multiple features
     442                 :            :   {
     443                 :          0 :     return;
     444                 :            :   }
     445                 :            : 
     446                 :            :   //draw Circle
     447                 :          0 :   QPen circlePen( mCircleColor );
     448                 :          0 :   circlePen.setWidthF( context.renderContext().convertToPainterUnits( mCircleWidth, QgsUnitTypes::RenderMillimeters ) );
     449                 :          0 :   p->setPen( circlePen );
     450                 :          0 :   p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
     451                 :          0 : }
     452                 :            : 
     453                 :          0 : void QgsPointDisplacementRenderer::drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions )
     454                 :            : {
     455                 :          0 :   QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
     456                 :          0 :   ClusteredGroup::const_iterator groupIt = group.constBegin();
     457                 :          0 :   for ( ; symbolPosIt != symbolPositions.constEnd() && groupIt != group.constEnd();
     458                 :          0 :         ++symbolPosIt, ++groupIt )
     459                 :            :   {
     460                 :          0 :     context.expressionContext().setFeature( groupIt->feature );
     461                 :          0 :     groupIt->symbol()->startRender( context );
     462                 :          0 :     groupIt->symbol()->renderPoint( *symbolPosIt, &( groupIt->feature ), context, -1, groupIt->isSelected );
     463                 :          0 :     if ( context.hasRenderedFeatureHandlers() )
     464                 :            :     {
     465                 :          0 :       const QgsGeometry bounds( QgsGeometry::fromRect( QgsRectangle( groupIt->symbol()->bounds( *symbolPosIt, context, groupIt->feature ) ) ) );
     466                 :          0 :       const QList< QgsRenderedFeatureHandlerInterface * > handlers = context.renderedFeatureHandlers();
     467                 :          0 :       QgsRenderedFeatureHandlerInterface::RenderedFeatureContext featureContext( context );
     468                 :          0 :       for ( QgsRenderedFeatureHandlerInterface *handler : handlers )
     469                 :          0 :         handler->handleRenderedFeature( groupIt->feature, bounds, featureContext );
     470                 :          0 :     }
     471                 :          0 :     groupIt->symbol()->stopRender( context );
     472                 :          0 :   }
     473                 :          0 : }
     474                 :            : 
     475                 :          0 : QgsPointDisplacementRenderer *QgsPointDisplacementRenderer::convertFromRenderer( const QgsFeatureRenderer *renderer )
     476                 :            : {
     477                 :          0 :   if ( renderer->type() == QLatin1String( "pointDisplacement" ) )
     478                 :            :   {
     479                 :          0 :     return dynamic_cast<QgsPointDisplacementRenderer *>( renderer->clone() );
     480                 :            :   }
     481                 :          0 :   else if ( renderer->type() == QLatin1String( "singleSymbol" ) ||
     482                 :          0 :             renderer->type() == QLatin1String( "categorizedSymbol" ) ||
     483                 :          0 :             renderer->type() == QLatin1String( "graduatedSymbol" ) ||
     484                 :          0 :             renderer->type() == QLatin1String( "RuleRenderer" ) )
     485                 :            :   {
     486                 :          0 :     QgsPointDisplacementRenderer *pointRenderer = new QgsPointDisplacementRenderer();
     487                 :          0 :     pointRenderer->setEmbeddedRenderer( renderer->clone() );
     488                 :          0 :     return pointRenderer;
     489                 :            :   }
     490                 :          0 :   else if ( renderer->type() == QLatin1String( "pointCluster" ) )
     491                 :            :   {
     492                 :          0 :     QgsPointDisplacementRenderer *pointRenderer = new QgsPointDisplacementRenderer();
     493                 :          0 :     const QgsPointClusterRenderer *clusterRenderer = static_cast< const QgsPointClusterRenderer * >( renderer );
     494                 :          0 :     if ( clusterRenderer->embeddedRenderer() )
     495                 :          0 :       pointRenderer->setEmbeddedRenderer( clusterRenderer->embeddedRenderer()->clone() );
     496                 :          0 :     pointRenderer->setTolerance( clusterRenderer->tolerance() );
     497                 :          0 :     pointRenderer->setToleranceUnit( clusterRenderer->toleranceUnit() );
     498                 :          0 :     pointRenderer->setToleranceMapUnitScale( clusterRenderer->toleranceMapUnitScale() );
     499                 :          0 :     if ( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol() )
     500                 :          0 :       pointRenderer->setCenterSymbol( const_cast< QgsPointClusterRenderer * >( clusterRenderer )->clusterSymbol()->clone() );
     501                 :          0 :     return pointRenderer;
     502                 :            :   }
     503                 :            :   else
     504                 :            :   {
     505                 :          0 :     return nullptr;
     506                 :            :   }
     507                 :          0 : }

Generated by: LCOV version 1.14