Skip to content
Permalink
Browse files

[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").
  • Loading branch information
henrik authored and nyalldawson committed Feb 2, 2019
1 parent 09fe865 commit 6fb06738ecfa9960ca673923be1bd42531dcdc75
@@ -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;
@@ -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 );
@@ -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 );
}
}

@@ -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 )
@@ -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" ) ) ) );
@@ -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 ) );
@@ -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();
@@ -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;
}

@@ -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;
}
@@ -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 );
@@ -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;
@@ -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++;
}
@@ -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()
@@ -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,
@@ -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 );
@@ -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() );
@@ -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 )
@@ -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 );
@@ -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();

0 comments on commit 6fb0673

Please sign in to comment.
You can’t perform that action at this time.