Skip to content

Commit

Permalink
[FEATURE] [needs-docs] Point Displacement label distance factor
Browse files Browse the repository at this point in the history
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").
  • Loading branch information
henrik authored and nyalldawson committed Mar 26, 2019
1 parent 09fe865 commit 6fb0673
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,22 @@ Sets a factor for increasing the ring size of displacement groups.
Returns the factor for increasing the ring size of displacement groups.

.. seealso:: :py:func:`setCircleRadiusAddition`
%End

void setLabelDistanceFactor( double factor );
%Docstring
Sets a factor for increasing the label distances from the symbol.

:param factor: addition factor

.. seealso:: :py:func:`labelDistanceFactor`
%End

double labelDistanceFactor() const;
%Docstring
Returns the factor for label distance from the symbol.

.. seealso:: :py:func:`setLabelDistanceFactor`
%End

Placement placement() const;
Expand Down
38 changes: 29 additions & 9 deletions src/core/symbology/qgspointdisplacementrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ QgsPointDisplacementRenderer *QgsPointDisplacementRenderer::clone() const
r->setLabelColor( mLabelColor );
r->setPlacement( mPlacement );
r->setCircleRadiusAddition( mCircleRadiusAddition );
r->setLabelDistanceFactor( mLabelDistanceFactor );
r->setMinimumLabelScale( mMinLabelScale );
r->setTolerance( mTolerance );
r->setToleranceUnit( mToleranceUnit );
Expand All @@ -60,12 +61,21 @@ void QgsPointDisplacementRenderer::drawGroup( QPointF centerPoint, QgsRenderCont

//calculate max diagonal size from all symbols in group
double diagonal = 0;
QList<double> diagonals;
double currentDiagonal;

for ( const GroupedFeature &feature : group )
{
if ( QgsMarkerSymbol *symbol = feature.symbol() )
{
diagonal = std::max( diagonal, M_SQRT2 * symbol->size( context ) );
currentDiagonal = M_SQRT2 * symbol->size( context );
diagonals.append( currentDiagonal );
diagonal = std::max( diagonal, currentDiagonal );

}
else
{
diagonals.append( 0.0 );
}
}

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

calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize );
calculateSymbolAndLabelPositions( symbolContext, centerPoint, group.size(), diagonal, symbolPositions, labelPositions, circleRadius, gridRadius, gridSize, diagonals );

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

void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition,
double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius, double &gridRadius,
int &gridSize ) const
int &gridSize, QList<double> &diagonals ) const
{
symbolPositions.clear();
labelShifts.clear();
Expand All @@ -243,8 +255,9 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
}
else if ( nPosition == 1 ) //If there is only one feature, draw it exactly at the center position
{
double side = sqrt( pow( symbolDiagonal, 2 ) / 2.0 );
symbolPositions.append( centerPoint );
labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) );
labelShifts.append( QPointF( side * mLabelDistanceFactor, -side * mLabelDistanceFactor ) );
return;
}

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

double fullPerimeter = 2 * M_PI;
double angleStep = fullPerimeter / nPosition;
for ( double currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep )

int featureIndex;
double currentAngle;
for ( currentAngle = 0.0, featureIndex = 0; currentAngle < fullPerimeter; currentAngle += angleStep, featureIndex++ )
{
double sinusCurrentAngle = std::sin( currentAngle );
double cosinusCurrentAngle = std::cos( currentAngle );
QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
QPointF labelShift( ( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle );

QPointF labelShift( ( radius + diagonals[featureIndex] * mLabelDistanceFactor ) * sinusCurrentAngle, ( radius + diagonals[featureIndex] * mLabelDistanceFactor ) * cosinusCurrentAngle );
symbolPositions.append( centerPoint + positionShift );
labelShifts.append( labelShift );
}

circleRadius = radius;
break;
}
Expand All @@ -279,6 +295,7 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
int pointsRemaining = nPosition;
int ringNumber = 1;
double firstRingRadius = centerDiagonal / 2.0 + symbolDiagonal / 2.0;
int featureIndex = 0;
while ( pointsRemaining > 0 )
{
double radiusCurrentRing = std::max( firstRingRadius + ( ringNumber - 1 ) * symbolDiagonal + ringNumber * circleAdditionPainterUnits, 0.0 );
Expand All @@ -292,10 +309,11 @@ void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions( QgsSymbolRe
double sinusCurrentAngle = std::sin( currentAngle );
double cosinusCurrentAngle = std::cos( currentAngle );
QPointF positionShift( radiusCurrentRing * sinusCurrentAngle, radiusCurrentRing * cosinusCurrentAngle );
QPointF labelShift( ( radiusCurrentRing + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radiusCurrentRing + symbolDiagonal / 2 ) * cosinusCurrentAngle );
QPointF labelShift( ( radiusCurrentRing + diagonals[featureIndex] * mLabelDistanceFactor ) * sinusCurrentAngle, ( radiusCurrentRing + diagonals[featureIndex] * mLabelDistanceFactor ) * cosinusCurrentAngle );
symbolPositions.append( centerPoint + positionShift );
labelShifts.append( labelShift );
currentAngle += angleStep;
featureIndex++;
}

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

int yIndex = 0;
int featureIndex = 0;
while ( pointsRemaining > 0 )
{
for ( int xIndex = 0; xIndex < gridSize && pointsRemaining > 0; ++xIndex )
{
QPointF positionShift( userPointRadius * xIndex, userPointRadius * yIndex );
QPointF labelShift( ( userPointRadius + symbolDiagonal / 2 ) * xIndex, ( userPointRadius + symbolDiagonal / 2 ) * yIndex );
QPointF labelShift( ( userPointRadius + diagonals[featureIndex] * mLabelDistanceFactor ) * xIndex, ( userPointRadius + diagonals[featureIndex] * mLabelDistanceFactor ) * yIndex );
symbolPositions.append( centerPoint + positionShift );
labelShifts.append( labelShift );
pointsRemaining--;
featureIndex++;
}
yIndex++;
}
Expand Down
17 changes: 16 additions & 1 deletion src/core/symbology/qgspointdisplacementrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,19 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsPointDistanceRenderer
*/
double circleRadiusAddition() const { return mCircleRadiusAddition; }

/**
* Sets a factor for increasing the label distances from the symbol.
* \param factor addition factor
* \see labelDistanceFactor()
*/
void setLabelDistanceFactor( double factor ) { mLabelDistanceFactor = factor; }

/**
* Returns the factor for label distance from the symbol.
* \see setLabelDistanceFactor()
*/
double labelDistanceFactor() const { return mLabelDistanceFactor; }

/**
* Returns the placement method used for dispersing the points.
* \see setPlacement()
Expand Down Expand Up @@ -152,12 +165,14 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsPointDistanceRenderer
QColor mCircleColor;
//! Addition to the default circle radius
double mCircleRadiusAddition = 0;
//! Factor for label distance
double mLabelDistanceFactor = 0.5;

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

//helper functions
void calculateSymbolAndLabelPositions( QgsSymbolRenderContext &symbolContext, QPointF centerPoint, int nPosition, double symbolDiagonal, QList<QPointF> &symbolPositions, QList<QPointF> &labelShifts, double &circleRadius,
double &gridRadius, int &gridSize ) const;
double &gridRadius, int &gridSize, QList<double> &diagonals ) const;
void drawCircle( double radiusPainterUnits, QgsSymbolRenderContext &context, QPointF centerPoint, int nSymbols );
void drawSymbols( const ClusteredGroup &group, QgsRenderContext &context, const QList<QPointF> &symbolPositions );
void drawGrid( int gridSizeUnits, QgsSymbolRenderContext &context,
Expand Down
15 changes: 15 additions & 0 deletions src/gui/symbology/qgspointdisplacementrendererwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ QgsPointDisplacementRendererWidget::QgsPointDisplacementRendererWidget( QgsVecto
connect( mDistanceUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed );
connect( mLabelColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged );
connect( mCircleModificationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged );
connect( mLabelDistanceFactorSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged );
connect( mScaleDependentLabelsCheckBox, &QCheckBox::stateChanged, this, &QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged );
connect( mRendererSettingsButton, &QPushButton::clicked, this, &QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked );
this->layout()->setContentsMargins( 0, 0, 0, 0 );
Expand Down Expand Up @@ -130,6 +131,8 @@ QgsPointDisplacementRendererWidget::QgsPointDisplacementRendererWidget( QgsVecto
mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
mCircleModificationSpinBox->setClearValue( 0.0 );
mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
mLabelDistanceFactorSpinBox->setClearValue( 0.5 );
mLabelDistanceFactorSpinBox->setValue( mRenderer->labelDistanceFactor() );
mDistanceSpinBox->setValue( mRenderer->tolerance() );
mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
Expand Down Expand Up @@ -336,6 +339,17 @@ void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged
emit widgetChanged();
}

void QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged( double d )
{
if ( !mRenderer )
{
return;
}

mRenderer->setLabelDistanceFactor( d );
emit widgetChanged();
}

void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
{
if ( mRenderer )
Expand Down Expand Up @@ -388,6 +402,7 @@ void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
mRendererComboBox->blockSignals( block );
mLabelColorButton->blockSignals( block );
mCircleModificationSpinBox->blockSignals( block );
mLabelDistanceFactorSpinBox->blockSignals( block );
mScaleDependentLabelsCheckBox->blockSignals( block );
mMinLabelScaleWidget->blockSignals( block );
mCenterSymbolToolButton->blockSignals( block );
Expand Down
1 change: 1 addition & 0 deletions src/gui/symbology/qgspointdisplacementrendererwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class GUI_EXPORT QgsPointDisplacementRendererWidget: public QgsRendererWidget, p
void mDistanceUnitWidget_changed();
void mLabelColorButton_colorChanged( const QColor &newColor );
void mCircleModificationSpinBox_valueChanged( double d );
void mLabelDistanceFactorSpinBox_valueChanged( double d );
void mScaleDependentLabelsCheckBox_stateChanged( int state );
void minLabelScaleChanged( double scale );
void mRendererSettingsButton_clicked();
Expand Down
Loading

0 comments on commit 6fb0673

Please sign in to comment.