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