33 , mCircleColor( QColor( 125, 125, 125 ) )
62 void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint,
QgsRenderContext &context,
const ClusteredGroup &group )
const
67 QVector<double> diagonals( group.size() );
68 double currentDiagonal;
70 int groupPosition = 0;
71 for (
const GroupedFeature &feature : group )
75 currentDiagonal = M_SQRT2 * symbol->size( context );
76 diagonals[groupPosition] = currentDiagonal;
77 diagonal = std::max( diagonal, currentDiagonal );
82 diagonals[groupPosition] = 0.0;
89 QList<QPointF> symbolPositions;
90 QList<QPointF> labelPositions;
91 double circleRadius = -1.0;
92 double gridRadius = -1.0;
95 calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );
98 if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
101 if ( circleRadius > 0 )
102 drawCircle( circleRadius, symbolContext, centerPoint, group.size() );
105 drawGrid( gridSize, symbolContext, symbolPositions, group.size() );
108 if ( group.size() > 1 )
111 const QgsFeature firstFeature = group.at( 0 ).feature;
114 mCenterSymbol->renderPoint( centerPoint, &firstFeature, context, -1,
false );
119 context.
painter()->drawRect( QRectF( centerPoint.x() - rectSize, centerPoint.y() - rectSize, rectSize * 2, rectSize * 2 ) );
124 drawSymbols( group, context, symbolPositions );
128 drawLabels( centerPoint, symbolContext, labelPositions, group );
137 mCenterSymbol->startRender( context, fields );
148 mCenterSymbol->stopRender( context );
159 labelFont.fromString( symbologyElem.attribute( QStringLiteral(
"labelFont" ), QString() ) );
162 r->
setPlacement(
static_cast< Placement >( symbologyElem.attribute( QStringLiteral(
"placement" ), QStringLiteral(
"0" ) ).toInt() ) );
163 r->
setCircleWidth( symbologyElem.attribute( QStringLiteral(
"circleWidth" ), QStringLiteral(
"0.4" ) ).toDouble() );
166 r->
setCircleRadiusAddition( symbologyElem.attribute( QStringLiteral(
"circleRadiusAddition" ), QStringLiteral(
"0.0" ) ).toDouble() );
167 r->
setLabelDistanceFactor( symbologyElem.attribute( QStringLiteral(
"labelDistanceFactor" ), QStringLiteral(
"0.5" ) ).toDouble() );
168 r->
setMinimumLabelScale( symbologyElem.attribute( QStringLiteral(
"maxLabelScaleDenominator" ), QStringLiteral(
"-1" ) ).toDouble() );
169 r->
setTolerance( symbologyElem.attribute( QStringLiteral(
"tolerance" ), QStringLiteral(
"0.00001" ) ).toDouble() );
174 QDomElement embeddedRendererElem = symbologyElem.firstChildElement( QStringLiteral(
"renderer-v2" ) );
175 if ( !embeddedRendererElem.isNull() )
181 const QDomElement centerSymbolElem = symbologyElem.firstChildElement( QStringLiteral(
"symbol" ) );
182 if ( !centerSymbolElem.isNull() )
184 r->
setCenterSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( centerSymbolElem, context ) );
191 return mCenterSymbol.get();
197 rendererElement.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"pointDisplacement" ) );
198 rendererElement.setAttribute( QStringLiteral(
"labelAttributeName" ),
mLabelAttributeName );
200 rendererElement.setAttribute( QStringLiteral(
"circleWidth" ), QString::number( mCircleWidth ) );
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 ) );
213 const QDomElement embeddedRendererElem =
mRenderer->save( doc, context );
214 rendererElement.appendChild( embeddedRendererElem );
219 rendererElement.appendChild( centerSymbolElem );
224 return rendererElement;
231 attr.unite( mCenterSymbol->usedAttributes( context ) );
252 mCenterSymbol.reset( symbol );
255 void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions(
QgsSymbolRenderContext &symbolContext, QPointF centerPoint,
int nPosition,
256 double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts,
double &circleRadius,
double &gridRadius,
257 int &gridSize, QVector<double> &diagonals )
const
259 symbolPositions.clear();
266 else if ( nPosition == 1 )
268 const double side = std::sqrt( std::pow( symbolDiagonal, 2 ) / 2.0 );
269 symbolPositions.append( centerPoint );
270 labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
276 switch ( mPlacement )
280 const double minDiameterToFitSymbols = nPosition * symbolDiagonal / ( 2.0 * M_PI );
281 const double radius = std::max( symbolDiagonal / 2, minDiameterToFitSymbols ) + circleAdditionPainterUnits;
283 const double angleStep = 2 * M_PI / nPosition;
284 double currentAngle = 0.0;
285 for (
int featureIndex = 0; featureIndex < nPosition; currentAngle += angleStep, featureIndex++ )
287 const double sinusCurrentAngle = std::sin( currentAngle );
288 const double cosinusCurrentAngle = std::cos( currentAngle );
289 const QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
291 const QPointF labelShift( ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
292 symbolPositions.append( centerPoint + positionShift );
293 labelShifts.append( labelShift );
295 circleRadius = radius;
300 const double centerDiagonal = mCenterSymbol->size( symbolContext.
renderContext() ) * M_SQRT2;
302 int pointsRemaining = nPosition;
304 const double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
305 int featureIndex = 0;
306 while ( pointsRemaining > 0 )
308 const double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
309 const int maxPointsCurrentRing = std::max( std::floor( 2 * M_PI * radiusCurrentRing / symbolDiagonal ), 1.0 );
310 const int actualPointsCurrentRing = std::min( maxPointsCurrentRing, pointsRemaining );
312 const double angleStep = 2 * M_PI / actualPointsCurrentRing;
313 double currentAngle = 0.0;
314 for (
int i = 0; i < actualPointsCurrentRing; ++i )
316 const double sinusCurrentAngle = std::sin( currentAngle );
317 const double cosinusCurrentAngle = std::cos( currentAngle );
318 const QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
319 const QPointF labelShift( ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals.at( featureIndex ) * mLabelDistanceFactor ) * cosinusCurrentAngle );
320 symbolPositions.append( centerPoint + positionShift );
321 labelShifts.append( labelShift );
322 currentAngle += angleStep;
326 pointsRemaining -= actualPointsCurrentRing;
328 circleRadius = radiusCurrentRing;
334 const double centerDiagonal = mCenterSymbol->size( symbolContext.
renderContext() ) * M_SQRT2;
335 int pointsRemaining = nPosition;
336 gridSize = std::ceil( std::sqrt( pointsRemaining ) );
337 if ( pointsRemaining - std::pow( gridSize - 1, 2 ) < gridSize )
339 const double originalPointRadius = ( ( centerDiagonal / 2.0 + symbolDiagonal / 2.0 ) + symbolDiagonal ) / 2;
340 const double userPointRadius = originalPointRadius + circleAdditionPainterUnits;
343 while ( pointsRemaining > 0 )
345 for (
int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
347 const QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
348 symbolPositions.append( centerPoint + positionShift );
354 centralizeGrid( symbolPositions, userPointRadius, gridSize );
359 for (
int symbolIndex = 0; symbolIndex < symbolPositions.size(); ++symbolIndex )
361 if ( symbolPositions.at( symbolIndex ).x() < centerPoint.x() )
370 if ( symbolPositions.at( symbolIndex ).y() < centerPoint.y() )
379 side = std::sqrt( std::pow( diagonals.at( symbolIndex ), 2 ) / 2.0 );
380 const QPointF labelShift( ( side * mLabelDistanceFactor * xFactor ), ( -side * mLabelDistanceFactor * yFactor ) );
381 labelShifts.append( symbolPositions.at( symbolIndex ) - centerPoint + labelShift );
384 gridRadius = userPointRadius;
390 void QgsPointDisplacementRenderer::centralizeGrid( QList<QPointF> &pointSymbolPositions,
double radius,
int size )
const
392 const double shiftAmount = -radius * ( size - 1.0 ) / 2.0;
393 const QPointF centralShift( shiftAmount, shiftAmount );
394 for (
int i = 0; i < pointSymbolPositions.size(); ++i )
396 pointSymbolPositions[i] += centralShift;
401 QList<QPointF> pointSymbolPositions,
int nSymbols )
const
404 if ( nSymbols < 2 || !p )
409 QPen gridPen( mCircleColor );
411 p->setPen( gridPen );
413 for (
int i = 0; i < pointSymbolPositions.size(); ++i )
415 if ( i + 1 < pointSymbolPositions.size() && 0 != ( i + 1 ) % gridSizeUnits )
417 const QLineF gridLineRow( pointSymbolPositions[i], pointSymbolPositions[i + 1] );
418 p->drawLine( gridLineRow );
421 if ( i + gridSizeUnits < pointSymbolPositions.size() )
423 const QLineF gridLineColumn( pointSymbolPositions[i], pointSymbolPositions[i + gridSizeUnits] );
424 p->drawLine( gridLineColumn );
429 void QgsPointDisplacementRenderer::drawCircle(
double radiusPainterUnits,
QgsSymbolRenderContext &context, QPointF centerPoint,
int nSymbols )
const
432 if ( nSymbols < 2 || !p )
438 QPen circlePen( mCircleColor );
440 p->setPen( circlePen );
441 p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
444 void QgsPointDisplacementRenderer::drawSymbols(
const ClusteredGroup &group,
QgsRenderContext &context,
const QList<QPointF> &symbolPositions )
const
446 QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
447 ClusteredGroup::const_iterator groupIt = group.constBegin();
448 for ( ; symbolPosIt != symbolPositions.constEnd() && groupIt != group.constEnd();
449 ++symbolPosIt, ++groupIt )
452 groupIt->symbol()->startRender( context );
453 groupIt->symbol()->renderPoint( *symbolPosIt, &( groupIt->feature ), context, -1, groupIt->isSelected );
460 handler->handleRenderedFeature( groupIt->feature, bounds, featureContext );
462 groupIt->symbol()->stopRender( context );
468 if ( renderer->
type() == QLatin1String(
"pointDisplacement" ) )
472 else if ( renderer->
type() == QLatin1String(
"singleSymbol" ) ||
473 renderer->
type() == QLatin1String(
"categorizedSymbol" ) ||
474 renderer->
type() == QLatin1String(
"graduatedSymbol" ) ||
475 renderer->
type() == QLatin1String(
"RuleRenderer" ) )
480 return pointRenderer;
482 else if ( renderer->
type() == QLatin1String(
"pointCluster" ) )
494 return pointRenderer;