Skip to content

Commit 6fb0673

Browse files
henriknyalldawson
authored andcommitted
[FEATURE] [needs-docs] Point Displacement label distance factor
Adds label distance factor spinbox to Point Displacement symbology window. Calculates label distance based on the current symbology diagonal instead of a general maximum diagonal. Replaces the hard coded distance "symbolDiagonal/2.0" with "symbolDiagonal*mLabelDistanceFactor", where mLabelDistanceFactor is set to the spinbox value. It's an old feature request (Point displacement labels adjustable offsets "https://issues.qgis.org/issues/5945").
1 parent 09fe865 commit 6fb0673

File tree

7 files changed

+147
-55
lines changed

7 files changed

+147
-55
lines changed

python/core/auto_generated/symbology/qgspointdisplacementrenderer.sip.in

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ Sets a factor for increasing the ring size of displacement groups.
104104
Returns the factor for increasing the ring size of displacement groups.
105105

106106
.. seealso:: :py:func:`setCircleRadiusAddition`
107+
%End
108+
109+
void setLabelDistanceFactor( double factor );
110+
%Docstring
111+
Sets a factor for increasing the label distances from the symbol.
112+
113+
:param factor: addition factor
114+
115+
.. seealso:: :py:func:`labelDistanceFactor`
116+
%End
117+
118+
double labelDistanceFactor() const;
119+
%Docstring
120+
Returns the factor for label distance from the symbol.
121+
122+
.. seealso:: :py:func:`setLabelDistanceFactor`
107123
%End
108124

109125
Placement placement() const;

src/core/symbology/qgspointdisplacementrenderer.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ QgsPointDisplacementRenderer *QgsPointDisplacementRenderer::clone() const
4343
r->setLabelColor( mLabelColor );
4444
r->setPlacement( mPlacement );
4545
r->setCircleRadiusAddition( mCircleRadiusAddition );
46+
r->setLabelDistanceFactor( mLabelDistanceFactor );
4647
r->setMinimumLabelScale( mMinLabelScale );
4748
r->setTolerance( mTolerance );
4849
r->setToleranceUnit( mToleranceUnit );
@@ -60,12 +61,21 @@ void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderCont
6061

6162
//calculate max diagonal size from all symbols in group
6263
double diagonal = 0;
64+
QList<double> diagonals;
65+
double currentDiagonal;
6366

6467
for ( const GroupedFeature &feature : group )
6568
{
6669
if ( QgsMarkerSymbol *symbol = feature.symbol() )
6770
{
68-
diagonal = std::max( diagonal, M_SQRT2 * symbol->size( context ) );
71+
currentDiagonal = M_SQRT2 * symbol->size( context );
72+
diagonals.append( currentDiagonal );
73+
diagonal = std::max( diagonal, currentDiagonal );
74+
75+
}
76+
else
77+
{
78+
diagonals.append( 0.0 );
6979
}
7080
}
7181

@@ -77,7 +87,7 @@ void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderCont
7787
double gridRadius = -1.0;
7888
int gridSize = -1;
7989

80-
calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize );
90+
calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );
8191

8292
//only draw circle/grid if there's a pen present - otherwise skip drawing transparent grids
8393
if ( mCircleColor.isValid() && mCircleColor.alpha() > 0 )
@@ -149,6 +159,7 @@ QgsFeatureRenderer *QgsPointDisplacementRenderer::create( QDomElement &symbology
149159
r->setCircleColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "circleColor" ), QString() ) ) );
150160
r->setLabelColor( QgsSymbolLayerUtils::decodeColor( symbologyElem.attribute( QStringLiteral( "labelColor" ), QString() ) ) );
151161
r->setCircleRadiusAddition( symbologyElem.attribute( QStringLiteral( "circleRadiusAddition" ), QStringLiteral( "0.0" ) ).toDouble() );
162+
r->setLabelDistanceFactor( symbologyElem.attribute( QStringLiteral( "labelDistanceFactor" ), QStringLiteral( "0.5" ) ).toDouble() );
152163
r->setMinimumLabelScale( symbologyElem.attribute( QStringLiteral( "maxLabelScaleDenominator" ), QStringLiteral( "-1" ) ).toDouble() );
153164
r->setTolerance( symbologyElem.attribute( QStringLiteral( "tolerance" ), QStringLiteral( "0.00001" ) ).toDouble() );
154165
r->setToleranceUnit( QgsUnitTypes::decodeRenderUnit( symbologyElem.attribute( QStringLiteral( "toleranceUnit" ), QStringLiteral( "MapUnit" ) ) ) );
@@ -186,6 +197,7 @@ QDomElement QgsPointDisplacementRenderer::save( QDomDocument &doc, const QgsRead
186197
rendererElement.setAttribute( QStringLiteral( "circleColor" ), QgsSymbolLayerUtils::encodeColor( mCircleColor ) );
187198
rendererElement.setAttribute( QStringLiteral( "labelColor" ), QgsSymbolLayerUtils::encodeColor( mLabelColor ) );
188199
rendererElement.setAttribute( QStringLiteral( "circleRadiusAddition" ), QString::number( mCircleRadiusAddition ) );
200+
rendererElement.setAttribute( QStringLiteral( "labelDistanceFactor" ), QString::number( mLabelDistanceFactor ) );
189201
rendererElement.setAttribute( QStringLiteral( "placement" ), static_cast< int >( mPlacement ) );
190202
rendererElement.setAttribute( QStringLiteral( "maxLabelScaleDenominator" ), QString::number( mMinLabelScale ) );
191203
rendererElement.setAttribute( QStringLiteral( "tolerance" ), QString::number( mTolerance ) );
@@ -232,7 +244,7 @@ void QgsPointDisplacementRenderer::setCenterSymbol( QgsMarkerSymbol *symbol )
232244

233245
void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
234246
double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
235-
int &gridSize ) const
247+
int &gridSize, QList<double> &diagonals ) const
236248
{
237249
symbolPositions.clear();
238250
labelShifts.clear();
@@ -243,8 +255,9 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
243255
}
244256
else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
245257
{
258+
double side = sqrt( pow( symbolDiagonal, 2 ) / 2.0 );
246259
symbolPositions.append( centerPoint );
247-
labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) );
260+
labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
248261
return;
249262
}
250263

@@ -259,16 +272,19 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
259272

260273
double fullPerimeter = 2 * M_PI;
261274
double angleStep = fullPerimeter / nPosition;
262-
for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep )
275+
276+
int featureIndex;
277+
double currentAngle;
278+
for ( currentAngle = 0.0, featureIndex = 0; currentAngle < fullPerimeter; currentAngle += angleStep, featureIndex++ )
263279
{
264280
double sinusCurrentAngle = std::sin( currentAngle );
265281
double cosinusCurrentAngle = std::cos( currentAngle );
266282
QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
267-
QPointF labelShift( ( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle );
283+
284+
QPointF labelShift( ( radius + diagonals[featureIndex] * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals[featureIndex] * mLabelDistanceFactor ) * cosinusCurrentAngle );
268285
symbolPositions.append( centerPoint + positionShift );
269286
labelShifts.append( labelShift );
270287
}
271-
272288
circleRadius = radius;
273289
break;
274290
}
@@ -279,6 +295,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
279295
int pointsRemaining = nPosition;
280296
int ringNumber = 1;
281297
double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
298+
int featureIndex = 0;
282299
while ( pointsRemaining > 0 )
283300
{
284301
double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
@@ -292,10 +309,11 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
292309
double sinusCurrentAngle = std::sin( currentAngle );
293310
double cosinusCurrentAngle = std::cos( currentAngle );
294311
QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
295-
QPointF labelShift( ( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle );
312+
QPointF labelShift( ( radiusCurrentRing + diagonals[featureIndex] * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals[featureIndex] * mLabelDistanceFactor ) * cosinusCurrentAngle );
296313
symbolPositions.append( centerPoint + positionShift );
297314
labelShifts.append( labelShift );
298315
currentAngle += angleStep;
316+
featureIndex++;
299317
}
300318

301319
pointsRemaining -= actualPointsCurrentRing;
@@ -315,15 +333,17 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
315333
double userPointRadius = originalPointRadius + circleAdditionPainterUnits;
316334

317335
int yIndex = 0;
336+
int featureIndex = 0;
318337
while ( pointsRemaining > 0 )
319338
{
320339
for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
321340
{
322341
QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
323-
QPointF labelShift( ( userPointRadius + symbolDiagonal / 2 ) * xIndex, ( userPointRadius + symbolDiagonal / 2 ) * yIndex );
342+
QPointF labelShift( ( userPointRadius + diagonals[featureIndex] * mLabelDistanceFactor ) * xIndex, ( userPointRadius + diagonals[featureIndex] * mLabelDistanceFactor ) * yIndex );
324343
symbolPositions.append( centerPoint + positionShift );
325344
labelShifts.append( labelShift );
326345
pointsRemaining--;
346+
featureIndex++;
327347
}
328348
yIndex++;
329349
}

src/core/symbology/qgspointdisplacementrenderer.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsPointDistanceRenderer
9999
*/
100100
double circleRadiusAddition() const { return mCircleRadiusAddition; }
101101

102+
/**
103+
* Sets a factor for increasing the label distances from the symbol.
104+
* \param factor addition factor
105+
* \see labelDistanceFactor()
106+
*/
107+
void setLabelDistanceFactor( double factor ) { mLabelDistanceFactor = factor; }
108+
109+
/**
110+
* Returns the factor for label distance from the symbol.
111+
* \see setLabelDistanceFactor()
112+
*/
113+
double labelDistanceFactor() const { return mLabelDistanceFactor; }
114+
102115
/**
103116
* Returns the placement method used for dispersing the points.
104117
* \see setPlacement()
@@ -152,12 +165,14 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsPointDistanceRenderer
152165
QColor mCircleColor;
153166
//! Addition to the default circle radius
154167
double mCircleRadiusAddition = 0;
168+
//! Factor for label distance
169+
double mLabelDistanceFactor = 0.5;
155170

156171
void drawGroup( QPointF centerPoint, QgsRenderContext &context, const QgsPointDistanceRenderer::ClusteredGroup &group ) override SIP_FORCE;
157172

158173
//helper functions
159174
void calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius,
160-
double &gridRadius, int &gridSize ) const;
175+
double &gridRadius, int &gridSize, QList<double> &diagonals ) const;
161176
void drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols );
162177
void drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions );
163178
void drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,

src/gui/symbology/qgspointdisplacementrendererwidget.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ QgsPointDisplacementRendererWidget::QgsPointDisplacementRendererWidget( QgsVecto
5858
connect( mDistanceUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed );
5959
connect( mLabelColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged );
6060
connect( mCircleModificationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged );
61+
connect( mLabelDistanceFactorSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged );
6162
connect( mScaleDependentLabelsCheckBox, &QCheckBox::stateChanged, this, &QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged );
6263
connect( mRendererSettingsButton, &QPushButton::clicked, this, &QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked );
6364
this->layout()->setContentsMargins( 0, 0, 0, 0 );
@@ -130,6 +131,8 @@ QgsPointDisplacementRendererWidget::QgsPointDisplacementRendererWidget( QgsVecto
130131
mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
131132
mCircleModificationSpinBox->setClearValue( 0.0 );
132133
mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
134+
mLabelDistanceFactorSpinBox->setClearValue( 0.5 );
135+
mLabelDistanceFactorSpinBox->setValue( mRenderer->labelDistanceFactor() );
133136
mDistanceSpinBox->setValue( mRenderer->tolerance() );
134137
mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
135138
mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
@@ -336,6 +339,17 @@ void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged
336339
emit widgetChanged();
337340
}
338341

342+
void QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged( double d )
343+
{
344+
if ( !mRenderer )
345+
{
346+
return;
347+
}
348+
349+
mRenderer->setLabelDistanceFactor( d );
350+
emit widgetChanged();
351+
}
352+
339353
void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
340354
{
341355
if ( mRenderer )
@@ -388,6 +402,7 @@ void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
388402
mRendererComboBox->blockSignals( block );
389403
mLabelColorButton->blockSignals( block );
390404
mCircleModificationSpinBox->blockSignals( block );
405+
mLabelDistanceFactorSpinBox->blockSignals( block );
391406
mScaleDependentLabelsCheckBox->blockSignals( block );
392407
mMinLabelScaleWidget->blockSignals( block );
393408
mCenterSymbolToolButton->blockSignals( block );

src/gui/symbology/qgspointdisplacementrendererwidget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class GUI_EXPORT QgsPointDisplacementRendererWidget: public QgsRendererWidget, p
6060
void mDistanceUnitWidget_changed();
6161
void mLabelColorButton_colorChanged( const QColor &newColor );
6262
void mCircleModificationSpinBox_valueChanged( double d );
63+
void mLabelDistanceFactorSpinBox_valueChanged( double d );
6364
void mScaleDependentLabelsCheckBox_stateChanged( int state );
6465
void minLabelScaleChanged( double scale );
6566
void mRendererSettingsButton_clicked();

0 commit comments

Comments
 (0)