Skip to content
Permalink
Browse files

Expose control over balloon wedge width

  • Loading branch information
nyalldawson committed Mar 21, 2021
1 parent 2b0a2bf commit 704b280065e38c0850e22db511ba91ac30e3e18c
@@ -64,6 +64,7 @@ relevant symbology elements to render them.
Curvature,
Orientation,
Margins,
WedgeWidth,
};

enum DrawOrder
@@ -986,6 +987,69 @@ Returns the units for the margins between the outside of the callout frame and t
.. seealso:: :py:func:`margins`
%End


double wedgeWidth() const;
%Docstring
Returns the width of the wedge shape at the side it connects with the label.

Units are specified through :py:func:`~QgsBalloonCallout.wedgeWidthUnit`.

.. seealso:: :py:func:`setWedgeWidth`

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

void setWedgeWidth( double width );
%Docstring
Returns the ``width`` of the wedge shape at the side it connects with the label.

Units are specified through :py:func:`~QgsBalloonCallout.setWedgeWidthUnit`.

.. seealso:: :py:func:`wedgeWidth`

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

void setWedgeWidthUnit( QgsUnitTypes::RenderUnit unit );
%Docstring
Sets the ``unit`` for the wedge width.

.. seealso:: :py:func:`wedgeWidthUnit`

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

QgsUnitTypes::RenderUnit wedgeWidthUnit() const;
%Docstring
Returns the units for the wedge width.

.. seealso:: :py:func:`setWedgeWidthUnit`

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

void setWedgeWidthMapUnitScale( const QgsMapUnitScale &scale );
%Docstring
Sets the map unit ``scale`` for the wedge width.

.. seealso:: :py:func:`wedgeWidthMapUnitScale`

.. seealso:: :py:func:`setWedgeWidthUnit`

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

const QgsMapUnitScale &wedgeWidthMapUnitScale() const;
%Docstring
Returns the map unit scale for the wedge width.

.. seealso:: :py:func:`setWedgeWidthMapUnitScale`

.. seealso:: :py:func:`wedgeWidthUnit`

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

protected:
virtual void draw( QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext );

@@ -62,6 +62,7 @@ void QgsCallout::initPropertyDefinitions()
{
QgsCallout::Margins, QgsPropertyDefinition( "Margins", QgsPropertyDefinition::DataTypeString, QObject::tr( "Margins" ), QObject::tr( "string of four doubles '<b>top,right,bottom,left</b>' or array of doubles <b>[top, right, bottom, left]</b>" ) )
},
{ QgsCallout::WedgeWidth, QgsPropertyDefinition( "WedgeWidth", QObject::tr( "Wedge width" ), QgsPropertyDefinition::DoublePositive, origin ) },
};
}

@@ -1020,6 +1021,9 @@ QgsBalloonCallout::QgsBalloonCallout( const QgsBalloonCallout &other )
, mOffsetFromAnchorScale( other.mOffsetFromAnchorScale )
, mMargins( other.mMargins )
, mMarginUnit( other.mMarginUnit )
, mWedgeWidth( other.mWedgeWidth )
, mWedgeWidthUnit( other.mWedgeWidthUnit )
, mWedgeWidthScale( other.mWedgeWidthScale )
{

}
@@ -1057,6 +1061,10 @@ QVariantMap QgsBalloonCallout::properties( const QgsReadWriteContext &context )
props[ QStringLiteral( "margins" ) ] = mMargins.toString();
props[ QStringLiteral( "marginsUnit" ) ] = QgsUnitTypes::encodeUnit( mMarginUnit );

props[ QStringLiteral( "wedgeWidth" ) ] = mWedgeWidth;
props[ QStringLiteral( "wedgeWidthUnit" ) ] = QgsUnitTypes::encodeUnit( mWedgeWidthUnit );
props[ QStringLiteral( "wedgeWidthMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mWedgeWidthScale );

return props;
}

@@ -1078,6 +1086,10 @@ void QgsBalloonCallout::readProperties( const QVariantMap &props, const QgsReadW

mMargins = QgsMargins::fromString( props.value( QStringLiteral( "margins" ) ).toString() );
mMarginUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "marginsUnit" ) ).toString() );

mWedgeWidth = props.value( QStringLiteral( "wedgeWidth" ), 2.64 ).toDouble();
mWedgeWidthUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "wedgeWidthUnit" ) ).toString() );
mWedgeWidthScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "wedgeWidthMapUnitScale" ) ).toString() );
}

void QgsBalloonCallout::startRender( QgsRenderContext &context )
@@ -1164,7 +1176,13 @@ void QgsBalloonCallout::draw( QgsRenderContext &context, const QRectF &rect, con

QPolygonF QgsBalloonCallout::getPoints( QgsRenderContext &context, QgsPointXY origin, QRectF rect ) const
{
double segmentPointWidth = context.convertToPainterUnits( 2.64, QgsUnitTypes::RenderMillimeters );
double segmentPointWidth = mWedgeWidth;
if ( dataDefinedProperties().isActive( QgsCallout::WedgeWidth ) )
{
context.expressionContext().setOriginalValueVariable( segmentPointWidth );
segmentPointWidth = dataDefinedProperties().valueAsDouble( QgsCallout::WedgeWidth, context.expressionContext(), segmentPointWidth );
}
segmentPointWidth = context.convertToPainterUnits( segmentPointWidth, mWedgeWidthUnit, mWedgeWidthScale );

double left = mMargins.left();
double right = mMargins.right();
@@ -92,6 +92,7 @@ class CORE_EXPORT QgsCallout
Curvature, //!< Curvature of curved line callouts (since QGIS 3.20)
Orientation, //!< Orientation of curved line callouts (since QGIS 3.20)
Margins, //!< Margin from text (since QGIS 3.20)
WedgeWidth, //!< Balloon callout wedge width (since QGIS 3.20)
};

//! Options for draw order (stacking) of callouts
@@ -990,6 +991,61 @@ class CORE_EXPORT QgsBalloonCallout : public QgsCallout
*/
QgsUnitTypes::RenderUnit marginsUnit() const { return mMarginUnit; }


/**
* Returns the width of the wedge shape at the side it connects with the label.
*
* Units are specified through wedgeWidthUnit().
*
* \see setWedgeWidth()
* \see wedgeWidthUnit()
*/
double wedgeWidth() const { return mWedgeWidth; }

/**
* Returns the \a width of the wedge shape at the side it connects with the label.
*
* Units are specified through setWedgeWidthUnit().
*
* \see wedgeWidth()
* \see setWedgeWidthUnit()
*/
void setWedgeWidth( double width ) { mWedgeWidth = width; }

/**
* Sets the \a unit for the wedge width.
*
* \see wedgeWidthUnit()
* \see setWedgeWidth()
*/
void setWedgeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mWedgeWidthUnit = unit; }

/**
* Returns the units for the wedge width.
*
* \see setWedgeWidthUnit()
* \see wedgeWidth()
*/
QgsUnitTypes::RenderUnit wedgeWidthUnit() const { return mWedgeWidthUnit; }

/**
* Sets the map unit \a scale for the wedge width.
*
* \see wedgeWidthMapUnitScale()
* \see setWedgeWidthUnit()
* \see setWedgeWidth()
*/
void setWedgeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mWedgeWidthScale = scale; }

/**
* Returns the map unit scale for the wedge width.
*
* \see setWedgeWidthMapUnitScale()
* \see wedgeWidthUnit()
* \see wedgeWidth()
*/
const QgsMapUnitScale &wedgeWidthMapUnitScale() const { return mWedgeWidthScale; }

protected:
void draw( QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext ) override;

@@ -1011,6 +1067,10 @@ class CORE_EXPORT QgsBalloonCallout : public QgsCallout
QgsMargins mMargins;
QgsUnitTypes::RenderUnit mMarginUnit = QgsUnitTypes::RenderMillimeters;

double mWedgeWidth = 2.64;
QgsUnitTypes::RenderUnit mWedgeWidthUnit = QgsUnitTypes::RenderMillimeters;
QgsMapUnitScale mWedgeWidthScale;

};


@@ -19,6 +19,7 @@
#include "qgsgeometryutils.h"
#include <QLineF>
#include <QList>
#include <algorithm>

QLineF segment( int index, QRectF rect )
{
@@ -111,18 +112,21 @@ QPolygonF QgsShapeGenerator::createBalloon( const QgsPointXY &origin, const QRec
balloonSegment = minEdgeIndex;
QPointF minEdgeEnd = minEdge.p2();
balloonSegmentPoint1 = QPointF( minEdgePoint.x(), minEdgePoint.y() );
if ( std::sqrt( minEdgePoint.sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < wedgeWidth )

const double segmentLength = minEdge.length();
const double clampedWedgeWidth = std::clamp( wedgeWidth, 0.0, segmentLength );
if ( std::sqrt( minEdgePoint.sqrDist( minEdgeEnd.x(), minEdgeEnd.y() ) ) < clampedWedgeWidth )
{
double x = 0;
double y = 0;
QgsGeometryUtils::pointOnLineWithDistance( minEdge.p2().x(), minEdge.p2().y(), minEdge.p1().x(), minEdge.p1().y(), wedgeWidth, x, y );
QgsGeometryUtils::pointOnLineWithDistance( minEdge.p2().x(), minEdge.p2().y(), minEdge.p1().x(), minEdge.p1().y(), clampedWedgeWidth, x, y );
balloonSegmentPoint1 = QPointF( x, y );
}

{
double x = 0;
double y = 0;
QgsGeometryUtils::pointOnLineWithDistance( balloonSegmentPoint1.x(), balloonSegmentPoint1.y(), minEdge.p2().x(), minEdge.p2().y(), wedgeWidth, x, y );
QgsGeometryUtils::pointOnLineWithDistance( balloonSegmentPoint1.x(), balloonSegmentPoint1.y(), minEdge.p2().x(), minEdge.p2().y(), clampedWedgeWidth, x, y );
balloonSegmentPoint2 = QPointF( x, y );
}
}
@@ -539,11 +539,14 @@ QgsBalloonCalloutWidget::QgsBalloonCalloutWidget( QgsVectorLayer *vl, QWidget *p
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mMarginUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );
mWedgeWidthUnitWidget->setUnits( QgsUnitTypes::RenderUnitList() << QgsUnitTypes::RenderMillimeters << QgsUnitTypes::RenderMetersInMapUnits << QgsUnitTypes::RenderMapUnits << QgsUnitTypes::RenderPixels
<< QgsUnitTypes::RenderPoints << QgsUnitTypes::RenderInches );

mSpinBottomMargin->setClearValue( 0 );
mSpinTopMargin->setClearValue( 0 );
mSpinRightMargin->setClearValue( 0 );
mSpinLeftMargin->setClearValue( 0 );
mWedgeWidthSpin->setClearValue( 2.64 );

connect( mOffsetFromAnchorUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsBalloonCalloutWidget::offsetFromAnchorUnitWidgetChanged );
connect( mOffsetFromAnchorSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsBalloonCalloutWidget::offsetFromAnchorChanged );
@@ -591,6 +594,17 @@ QgsBalloonCalloutWidget::QgsBalloonCalloutWidget( QgsVectorLayer *vl, QWidget *p
emit changed();
} );

connect( mWedgeWidthUnitWidget, &QgsUnitSelectionWidget::changed, this, [ = ]
{
mCallout->setWedgeWidthUnit( mWedgeWidthUnitWidget->unit() );
mCallout->setWedgeWidthMapUnitScale( mWedgeWidthUnitWidget->getMapUnitScale() );
emit changed();
} );
connect( mWedgeWidthSpin, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, [ = ]( double value )
{
mCallout->setWedgeWidth( value );
emit changed();
} );
}

void QgsBalloonCalloutWidget::setCallout( QgsCallout *callout )
@@ -614,6 +628,12 @@ void QgsBalloonCalloutWidget::setCallout( QgsCallout *callout )
whileBlocking( mSpinRightMargin )->setValue( mCallout->margins().right() );
whileBlocking( mMarginUnitWidget )->setUnit( mCallout->marginsUnit() );

mWedgeWidthUnitWidget->blockSignals( true );
mWedgeWidthUnitWidget->setUnit( mCallout->wedgeWidthUnit() );
mWedgeWidthUnitWidget->setMapUnitScale( mCallout->wedgeWidthMapUnitScale() );
mWedgeWidthUnitWidget->blockSignals( false );
whileBlocking( mWedgeWidthSpin )->setValue( mCallout->wedgeWidth() );

whileBlocking( mCalloutFillStyleButton )->setSymbol( mCallout->fillSymbol()->clone() );

whileBlocking( mAnchorPointComboBox )->setCurrentIndex( mAnchorPointComboBox->findData( static_cast< int >( callout->anchorPoint() ) ) );
@@ -624,6 +644,7 @@ void QgsBalloonCalloutWidget::setCallout( QgsCallout *callout )
registerDataDefinedButton( mDestXDDBtn, QgsCallout::DestinationX );
registerDataDefinedButton( mDestYDDBtn, QgsCallout::DestinationY );
registerDataDefinedButton( mMarginsDDBtn, QgsCallout::Margins );
registerDataDefinedButton( mWedgeWidthDDBtn, QgsCallout::WedgeWidth );
}

void QgsBalloonCalloutWidget::setGeometryType( QgsWkbTypes::GeometryType type )

0 comments on commit 704b280

Please sign in to comment.