[FEATURE] When the "show pinned labels" option is enabled, also

highlight any pinned callout start or end points

This allows users to immediately see which callouts points have
been manually placed vs are automatically placed.
This commit is contained in:
Nyall Dawson 2021-03-18 09:47:52 +10:00
parent e8280d29bc
commit 5d06c1d48d
8 changed files with 223 additions and 35 deletions

View File

@ -409,20 +409,24 @@ Returns the anchor point geometry for a label with the given bounding box and ``
QGIS 3.20 use :py:func:`~QgsCallout.calloutLabelPoint` instead
%End
QgsGeometry calloutLabelPoint( QRectF bodyBoundingBox, double angle, LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCalloutContext &calloutContext ) const;
QgsGeometry calloutLabelPoint( QRectF bodyBoundingBox, double angle, LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const;
%Docstring
Returns the anchor point geometry for a label with the given bounding box and ``anchor`` point mode.
The ``pinned`` argument will be set to ``True`` if the callout label point is pinned (manually placed).
.. versionadded:: 3.20
%End
QgsGeometry calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext ) const;
QgsGeometry calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const;
%Docstring
Calculates the direct line from a label geometry to an anchor geometry part, respecting the various
callout settings which influence how the callout end should be placed in the anchor geometry.
Returns a null geometry if the callout line cannot be calculated.
The ``pinned`` argument will be set to ``True`` if the callout anchor point is pinned (manually placed).
.. versionadded:: 3.20
%End

View File

@ -85,6 +85,50 @@ The destination of the callout line is the line point associated with the featur
.. seealso:: :py:func:`destination`
.. seealso:: :py:func:`setOrigin`
%End
bool originIsPinned() const;
%Docstring
Returns ``True`` if the origin of the callout has pinned (manually placed).
The origin of the callout line is the line point associated with the label text.
.. seealso:: :py:func:`destinationIsPinned`
.. seealso:: :py:func:`setOriginIsPinned`
%End
void setOriginIsPinned( bool pinned );
%Docstring
Sets whether the origin of the callout has pinned (manually placed).
The origin of the callout line is the line point associated with the label text.
.. seealso:: :py:func:`setDestinationIsPinned`
.. seealso:: :py:func:`originIsPinned`
%End
bool destinationIsPinned() const;
%Docstring
Returns ``True`` if the destination of the callout has pinned (manually placed).
The destination of the callout line is the line point associated with the feature's geometry.
.. seealso:: :py:func:`originIsPinned`
.. seealso:: :py:func:`setDestinationIsPinned`
%End
void setDestinationIsPinned( bool pinned );
%Docstring
Sets whether the destination of the callout has pinned (manually placed).
The destination of the callout line is the line point associated with the feature's geometry.
.. seealso:: :py:func:`setOriginIsPinned`
.. seealso:: :py:func:`destinationIsPinned`
%End
};

View File

@ -154,6 +154,20 @@ void QgsMapToolPinLabels::highlightLabel( const QgsLabelPosition &labelpos,
mHighlights.insert( id, rb );
}
void QgsMapToolPinLabels::highlightCallout( bool isOrigin, const QgsCalloutPosition &calloutPosition, const QString &id, const QColor &color )
{
double scaleFactor = mCanvas->fontMetrics().xHeight();
QgsRubberBand *rb = new QgsRubberBand( mCanvas, QgsWkbTypes::PointGeometry );
rb->setWidth( 2 );
rb->setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
rb->setColor( color );
rb->setIcon( QgsRubberBand::ICON_X );
rb->setIconSize( scaleFactor );
rb->addPoint( isOrigin ? calloutPosition.origin() : calloutPosition.destination() );
mHighlights.insert( id, rb );
}
// public slot to render highlight rectangles around pinned labels
void QgsMapToolPinLabels::highlightPinnedLabels()
{
@ -164,7 +178,7 @@ void QgsMapToolPinLabels::highlightPinnedLabels()
return;
}
QgsDebugMsg( QStringLiteral( "Highlighting pinned labels" ) );
QgsDebugMsgLevel( QStringLiteral( "Highlighting pinned labels" ), 2 );
// get list of all drawn labels from all layers within given extent
const QgsLabelingResults *labelingResults = mCanvas->labelingResults( false );
@ -174,16 +188,14 @@ void QgsMapToolPinLabels::highlightPinnedLabels()
}
QgsRectangle ext = mCanvas->extent();
QgsDebugMsg( QStringLiteral( "Getting labels from canvas extent" ) );
QgsDebugMsgLevel( QStringLiteral( "Getting labels from canvas extent" ), 2 );
QList<QgsLabelPosition> labelPosList = labelingResults->labelsWithinRect( ext );
const QList<QgsLabelPosition> labelPosList = labelingResults->labelsWithinRect( ext );
QApplication::setOverrideCursor( Qt::WaitCursor );
QList<QgsLabelPosition>::const_iterator it;
for ( it = labelPosList.constBegin() ; it != labelPosList.constEnd(); ++it )
for ( const QgsLabelPosition &pos : labelPosList )
{
const QgsLabelPosition &pos = *it;
mCurrentLabel = LabelDetails( pos );
if ( isPinned() )
@ -216,14 +228,38 @@ void QgsMapToolPinLabels::highlightPinnedLabels()
highlightLabel( pos, labelStringID, lblcolor );
}
}
// highlight pinned callouts
const QList<QgsCalloutPosition> calloutPosList = labelingResults->calloutsWithinRectangle( ext );
const QColor calloutColor = QColor( 54, 129, 255, 160 );
for ( const QgsCalloutPosition &callout : calloutPosList )
{
if ( callout.originIsPinned() )
{
QString calloutStringID = QStringLiteral( "callout|%1|%2|origin" ).arg( callout.layerID, QString::number( callout.featureId ) );
// don't highlight again
if ( mHighlights.contains( calloutStringID ) )
continue;
highlightCallout( true, callout, calloutStringID, calloutColor );
}
if ( callout.destinationIsPinned() )
{
QString calloutStringID = QStringLiteral( "callout|%1|%2|destination" ).arg( callout.layerID, QString::number( callout.featureId ) );
// don't highlight again
if ( mHighlights.contains( calloutStringID ) )
continue;
highlightCallout( false, callout, calloutStringID, calloutColor );
}
}
QApplication::restoreOverrideCursor();
}
void QgsMapToolPinLabels::removePinnedHighlights()
{
QApplication::setOverrideCursor( Qt::BusyCursor );
const auto constMHighlights = mHighlights;
for ( QgsRubberBand *rb : constMHighlights )
for ( QgsRubberBand *rb : qgis::as_const( mHighlights ) )
{
delete rb;
}

View File

@ -82,6 +82,11 @@ class APP_EXPORT QgsMapToolPinLabels: public QgsMapToolLabel
const QString &id,
const QColor &color );
//! Highlights a given callout relative to whether its pinned and editable
void highlightCallout( bool isOrigin, const QgsCalloutPosition &labelpos,
const QString &id,
const QColor &color );
//! Select valid labels to pin or unpin
void pinUnpinLabels( const QgsRectangle &ext, QMouseEvent *e );

View File

@ -309,8 +309,9 @@ QgsGeometry QgsCallout::labelAnchorGeometry( QRectF rect, const double angle, La
return label;
}
QgsGeometry QgsCallout::calloutLabelPoint( QRectF rect, const double angle, QgsCallout::LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCallout::QgsCalloutContext &calloutContext ) const
QgsGeometry QgsCallout::calloutLabelPoint( QRectF rect, const double angle, QgsCallout::LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCallout::QgsCalloutContext &calloutContext, bool &pinned ) const
{
pinned = false;
if ( dataDefinedProperties().isActive( QgsCallout::OriginX ) && dataDefinedProperties().isActive( QgsCallout::OriginY ) )
{
bool ok = false;
@ -320,6 +321,7 @@ QgsGeometry QgsCallout::calloutLabelPoint( QRectF rect, const double angle, QgsC
const double y = dataDefinedProperties().valueAsDouble( QgsCallout::OriginY, context.expressionContext(), 0, &ok );
if ( ok )
{
pinned = true;
// data defined label point, use it directly
QgsGeometry labelPoint = QgsGeometry::fromPointXY( QgsPointXY( x, y ) );
try
@ -384,8 +386,9 @@ QgsGeometry QgsCallout::calloutLabelPoint( QRectF rect, const double angle, QgsC
return label;
}
QgsGeometry QgsCallout::calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext ) const
QgsGeometry QgsCallout::calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const
{
pinned = false;
AnchorPoint anchor = anchorPoint();
const QgsAbstractGeometry *evaluatedPartAnchor = partGeometry;
std::unique_ptr< QgsAbstractGeometry > tempPartAnchor;
@ -399,6 +402,7 @@ QgsGeometry QgsCallout::calloutLineToPart( const QgsGeometry &labelGeometry, con
const double y = dataDefinedProperties().valueAsDouble( QgsCallout::DestinationY, context.expressionContext(), 0, &ok );
if ( ok )
{
pinned = true;
tempPartAnchor = std::make_unique< QgsPoint >( QgsWkbTypes::Point, x, y );
evaluatedPartAnchor = tempPartAnchor.get();
try
@ -603,13 +607,16 @@ void QgsSimpleLineCallout::draw( QgsRenderContext &context, QRectF rect, const d
context.expressionContext().setOriginalValueVariable( encodedAnchor );
labelAnchor = decodeLabelAnchorPoint( dataDefinedProperties().valueAsString( QgsCallout::LabelAnchorPointPosition, context.expressionContext(), encodedAnchor ) );
}
const QgsGeometry label = calloutLabelPoint( rect, angle, labelAnchor, context, calloutContext );
bool originPinned = false;
const QgsGeometry label = calloutLabelPoint( rect, angle, labelAnchor, context, calloutContext, originPinned );
if ( label.isNull() )
return;
auto drawCalloutLine = [this, &context, &calloutContext, &label]( const QgsAbstractGeometry * partAnchor )
auto drawCalloutLine = [this, &context, &calloutContext, &label, originPinned]( const QgsAbstractGeometry * partAnchor )
{
QgsGeometry line = calloutLineToPart( label, partAnchor, context, calloutContext );
bool destinationPinned = false;
QgsGeometry line = calloutLineToPart( label, partAnchor, context, calloutContext, destinationPinned );
if ( line.isEmpty() )
return;
@ -657,7 +664,9 @@ void QgsSimpleLineCallout::draw( QgsRenderContext &context, QRectF rect, const d
QgsCalloutPosition position;
position.setOrigin( context.mapToPixel().toMapCoordinates( points.at( 0 ).x(), points.at( 0 ).y() ).toQPointF() );
position.setOriginIsPinned( originPinned );
position.setDestination( context.mapToPixel().toMapCoordinates( points.constLast().x(), points.constLast().y() ).toQPointF() );
position.setDestinationIsPinned( destinationPinned );
calloutContext.addCalloutPosition( position );
mLineSymbol->renderPolyline( points, nullptr, context );
@ -722,13 +731,15 @@ void QgsManhattanLineCallout::draw( QgsRenderContext &context, QRectF rect, cons
context.expressionContext().setOriginalValueVariable( encodedAnchor );
labelAnchor = decodeLabelAnchorPoint( dataDefinedProperties().valueAsString( QgsCallout::LabelAnchorPointPosition, context.expressionContext(), encodedAnchor ) );
}
const QgsGeometry label = calloutLabelPoint( rect, angle, labelAnchor, context, calloutContext );
bool originPinned = false;
const QgsGeometry label = calloutLabelPoint( rect, angle, labelAnchor, context, calloutContext, originPinned );
if ( label.isNull() )
return;
auto drawCalloutLine = [this, &context, &calloutContext, &label]( const QgsAbstractGeometry * partAnchor )
auto drawCalloutLine = [this, &context, &calloutContext, &label, originPinned]( const QgsAbstractGeometry * partAnchor )
{
QgsGeometry line = calloutLineToPart( label, partAnchor, context, calloutContext );
bool destinationPinned = false;
QgsGeometry line = calloutLineToPart( label, partAnchor, context, calloutContext, destinationPinned );
if ( line.isEmpty() )
return;
@ -779,7 +790,9 @@ void QgsManhattanLineCallout::draw( QgsRenderContext &context, QRectF rect, cons
QgsCalloutPosition position;
position.setOrigin( context.mapToPixel().toMapCoordinates( points.at( 0 ).x(), points.at( 0 ).y() ).toQPointF() );
position.setOriginIsPinned( originPinned );
position.setDestination( context.mapToPixel().toMapCoordinates( points.constLast().x(), points.constLast().y() ).toQPointF() );
position.setDestinationIsPinned( destinationPinned );
calloutContext.addCalloutPosition( position );
lineSymbol()->renderPolyline( points, nullptr, context );

View File

@ -424,9 +424,12 @@ class CORE_EXPORT QgsCallout
/**
* Returns the anchor point geometry for a label with the given bounding box and \a anchor point mode.
*
* The \a pinned argument will be set to TRUE if the callout label point is pinned (manually placed).
*
* \since QGIS 3.20
*/
QgsGeometry calloutLabelPoint( QRectF bodyBoundingBox, double angle, LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCalloutContext &calloutContext ) const;
QgsGeometry calloutLabelPoint( QRectF bodyBoundingBox, double angle, LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const;
/**
* Calculates the direct line from a label geometry to an anchor geometry part, respecting the various
@ -434,9 +437,11 @@ class CORE_EXPORT QgsCallout
*
* Returns a null geometry if the callout line cannot be calculated.
*
* The \a pinned argument will be set to TRUE if the callout anchor point is pinned (manually placed).
*
* \since QGIS 3.20
*/
QgsGeometry calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext ) const;
QgsGeometry calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const;
private:

View File

@ -103,11 +103,54 @@ class CORE_EXPORT QgsCalloutPosition
*/
void setDestination( const QPointF &destination ) { mDestination = destination; }
/**
* Returns TRUE if the origin of the callout has pinned (manually placed).
*
* The origin of the callout line is the line point associated with the label text.
*
* \see destinationIsPinned()
* \see setOriginIsPinned()
*/
bool originIsPinned() const { return mOriginIsPinned; }
/**
* Sets whether the origin of the callout has pinned (manually placed).
*
* The origin of the callout line is the line point associated with the label text.
*
* \see setDestinationIsPinned()
* \see originIsPinned()
*/
void setOriginIsPinned( bool pinned ) { mOriginIsPinned = pinned; }
/**
* Returns TRUE if the destination of the callout has pinned (manually placed).
*
* The destination of the callout line is the line point associated with the feature's geometry.
*
* \see originIsPinned()
* \see setDestinationIsPinned()
*/
bool destinationIsPinned() const { return mDestinationIsPinned; }
/**
* Sets whether the destination of the callout has pinned (manually placed).
*
* The destination of the callout line is the line point associated with the feature's geometry.
*
* \see setOriginIsPinned()
* \see destinationIsPinned()
*/
void setDestinationIsPinned( bool pinned ) { mDestinationIsPinned = pinned; }
private:
QPointF mOrigin;
QPointF mDestination;
bool mOriginIsPinned = false;
bool mDestinationIsPinned = false;
};
#endif // QGSCALLOUTPOSITION_H

View File

@ -2039,6 +2039,11 @@ void TestQgsLabelingEngine::labelingResultsWithCallouts()
f.setAttributes( QgsAttributes() << 2 << -3424024 << 7849709 << -2713442 << 7628322 << -2567040 << 6974872 );
f.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( -2995532, 7242679 ) ) );
QVERIFY( vl3->dataProvider()->addFeature( f ) );
f.setAttributes( QgsAttributes() << 3 << -4024024 << 7849709 << QVariant() << QVariant() << QVariant() << QVariant() );
f.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( -2995532, 7242679 ) ) );
QVERIFY( vl3->dataProvider()->addFeature( f ) );
vl3->updateExtents();
vl3->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
@ -2081,6 +2086,8 @@ void TestQgsLabelingEngine::labelingResultsWithCallouts()
QGSCOMPARENEAR( callouts.at( 0 ).origin().y(), 7628322.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().x(), -2567040.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().y(), 6974872.0, 10 );
QVERIFY( callouts.at( 0 ).originIsPinned() );
QVERIFY( callouts.at( 0 ).destinationIsPinned() );
callouts = results->calloutsWithinRectangle( QgsRectangle( -2567340, 6974572, -2566740, 6975172 ) );
QCOMPARE( callouts.count(), 1 );
@ -2090,6 +2097,8 @@ void TestQgsLabelingEngine::labelingResultsWithCallouts()
QGSCOMPARENEAR( callouts.at( 0 ).origin().y(), 7628322.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().x(), -2567040.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().y(), 6974872.0, 10 );
QVERIFY( callouts.at( 0 ).originIsPinned() );
QVERIFY( callouts.at( 0 ).destinationIsPinned() );
callouts = results->calloutsWithinRectangle( QgsRectangle( -1242625, 7967227, -1242025, 7967827 ) );
QCOMPARE( callouts.count(), 1 );
@ -2099,6 +2108,8 @@ void TestQgsLabelingEngine::labelingResultsWithCallouts()
QGSCOMPARENEAR( callouts.at( 0 ).origin().y(), 7967527.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().x(), -424572.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().y(), 7567578.0, 10 );
QVERIFY( callouts.at( 0 ).originIsPinned() );
QVERIFY( callouts.at( 0 ).destinationIsPinned() );
callouts = results->calloutsWithinRectangle( QgsRectangle( -424872, 7567278, -424272, 7567878 ) );
QCOMPARE( callouts.count(), 1 );
@ -2108,22 +2119,49 @@ void TestQgsLabelingEngine::labelingResultsWithCallouts()
QGSCOMPARENEAR( callouts.at( 0 ).origin().y(), 7967527.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().x(), -424572.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().y(), 7567578.0, 10 );
QVERIFY( callouts.at( 0 ).originIsPinned() );
QVERIFY( callouts.at( 0 ).destinationIsPinned() );
callouts = results->calloutsWithinRectangle( QgsRectangle( -4104024, 7609709, -3804024, 8249709 ) );
QCOMPARE( callouts.count(), 1 );
QCOMPARE( callouts.at( 0 ).featureId, 2 );
QCOMPARE( callouts.at( 0 ).layerID, vl3->id() );
QGSCOMPARENEAR( callouts.at( 0 ).origin().x(), -3856062.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).origin().y(), 7849709.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().x(), -2995532.0, 10 );
QGSCOMPARENEAR( callouts.at( 0 ).destination().y(), 7242679.0, 10 );
QVERIFY( !callouts.at( 0 ).originIsPinned() );
QVERIFY( !callouts.at( 0 ).destinationIsPinned() );
callouts = results->calloutsWithinRectangle( mapSettings.visibleExtent() );
QCOMPARE( callouts.count(), 2 );
bool callout1IsFirstLayer = callouts.at( 0 ).layerID == vl2->id();
QCOMPARE( callouts.at( callout1IsFirstLayer ? 0 : 1 ).featureId, 1 );
QCOMPARE( callouts.at( callout1IsFirstLayer ? 0 : 1 ).layerID, vl2->id() );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 0 : 1 ).origin().x(), -1242325.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 0 : 1 ).origin().y(), 7967527.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 0 : 1 ).destination().x(), -424572.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 0 : 1 ).destination().y(), 7567578.0, 10 );
QCOMPARE( callouts.at( callout1IsFirstLayer ? 1 : 0 ).featureId, 1 );
QCOMPARE( callouts.at( callout1IsFirstLayer ? 1 : 0 ).layerID, vl3->id() );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 1 : 0 ).origin().x(), -2713442.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 1 : 0 ).origin().y(), 7628322.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 1 : 0 ).destination().x(), -2567040.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 1 : 0 ).destination().y(), 6974872.0, 10 );
QCOMPARE( callouts.count(), 3 );
int callout1Index = callouts.at( 0 ).layerID == vl2->id() ? 0 : callouts.at( 1 ).layerID == vl2->id() ? 1 : 2;
int callout2Index = callouts.at( 0 ).layerID == vl3->id() && callouts.at( 0 ).featureId == 1 ? 0 : callouts.at( 1 ).layerID == vl3->id() && callouts.at( 1 ).featureId == 1 ? 1 : 2;
int callout3Index = callouts.at( 0 ).layerID == vl3->id() && callouts.at( 0 ).featureId == 2 ? 0 : callouts.at( 1 ).layerID == vl3->id() && callouts.at( 1 ).featureId == 2 ? 1 : 2;
QCOMPARE( callouts.at( callout1Index ).featureId, 1 );
QCOMPARE( callouts.at( callout1Index ).layerID, vl2->id() );
QGSCOMPARENEAR( callouts.at( callout1Index ).origin().x(), -1242325.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1Index ).origin().y(), 7967527.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1Index ).destination().x(), -424572.0, 10 );
QGSCOMPARENEAR( callouts.at( callout1Index ).destination().y(), 7567578.0, 10 );
QVERIFY( callouts.at( callout1Index ).originIsPinned() );
QVERIFY( callouts.at( callout1Index ).destinationIsPinned() );
QCOMPARE( callouts.at( callout2Index ).featureId, 1 );
QCOMPARE( callouts.at( callout2Index ).layerID, vl3->id() );
QGSCOMPARENEAR( callouts.at( callout2Index ).origin().x(), -2713442.0, 10 );
QGSCOMPARENEAR( callouts.at( callout2Index ).origin().y(), 7628322.0, 10 );
QGSCOMPARENEAR( callouts.at( callout2Index ).destination().x(), -2567040.0, 10 );
QGSCOMPARENEAR( callouts.at( callout2Index ).destination().y(), 6974872.0, 10 );
QVERIFY( callouts.at( callout2Index ).originIsPinned() );
QVERIFY( callouts.at( callout2Index ).destinationIsPinned() );
QCOMPARE( callouts.at( callout3Index ).featureId, 2 );
QCOMPARE( callouts.at( callout3Index ).layerID, vl3->id() );
QGSCOMPARENEAR( callouts.at( callout3Index ).origin().x(), -3856062.0, 10 );
QGSCOMPARENEAR( callouts.at( callout3Index ).origin().y(), 7849709.0, 10 );
QGSCOMPARENEAR( callouts.at( callout3Index ).destination().x(), -2995532.0, 10 );
QGSCOMPARENEAR( callouts.at( callout3Index ).destination().y(), 7242679.0, 10 );
QVERIFY( !callouts.at( callout3Index ).originIsPinned() );
QVERIFY( !callouts.at( callout3Index ).destinationIsPinned() );
// with rotation
mapSettings.setRotation( 60 );
@ -2172,7 +2210,7 @@ void TestQgsLabelingEngine::labelingResultsWithCallouts()
callouts = results->calloutsWithinRectangle( mapSettings.visibleExtent() );
QCOMPARE( callouts.count(), 2 );
callout1IsFirstLayer = callouts.at( 0 ).layerID == vl2->id();
bool callout1IsFirstLayer = callouts.at( 0 ).layerID == vl2->id();
QCOMPARE( callouts.at( callout1IsFirstLayer ? 0 : 1 ).featureId, 1 );
QCOMPARE( callouts.at( callout1IsFirstLayer ? 0 : 1 ).layerID, vl2->id() );
QGSCOMPARENEAR( callouts.at( callout1IsFirstLayer ? 0 : 1 ).origin().x(), -1242325.0, 10 );