Skip to content

Commit

Permalink
Fix callout rendering to rotated labels
Browse files Browse the repository at this point in the history
Fixes #36681
  • Loading branch information
nyalldawson committed Jun 11, 2020
1 parent ef19911 commit 2bb4aad
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 12 deletions.
45 changes: 33 additions & 12 deletions src/core/callouts/qgscallout.cpp
Expand Up @@ -254,32 +254,53 @@ QgsCallout::LabelAnchorPoint QgsCallout::decodeLabelAnchorPoint( const QString &
return LabelPointOnExterior;
}

QgsGeometry QgsCallout::labelAnchorGeometry( QRectF rect, const double, LabelAnchorPoint anchor ) const
QgsGeometry QgsCallout::labelAnchorGeometry( QRectF rect, const double angle, LabelAnchorPoint anchor ) const
{
QgsGeometry label( QgsGeometry::fromRect( rect ) );
QgsGeometry label;
switch ( anchor )
{
case LabelPointOnExterior:
return label;
label = QgsGeometry::fromRect( rect );
break;

case LabelCentroid:
return label.centroid();
label = QgsGeometry::fromRect( rect ).centroid();
break;

case LabelTopLeft:
return QgsGeometry::fromPointXY( QgsPointXY( rect.bottomLeft() ) );
label = QgsGeometry::fromPointXY( QgsPointXY( rect.bottomLeft() ) );
break;

case LabelTopMiddle:
return QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.bottom() ) );
label = QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.bottom() ) );
break;

case LabelTopRight:
return QgsGeometry::fromPointXY( QgsPointXY( rect.bottomRight() ) );
label = QgsGeometry::fromPointXY( QgsPointXY( rect.bottomRight() ) );
break;

case LabelMiddleLeft:
return QgsGeometry::fromPointXY( QgsPointXY( rect.left(), ( rect.top() + rect.bottom() ) / 2.0 ) );
label = QgsGeometry::fromPointXY( QgsPointXY( rect.left(), ( rect.top() + rect.bottom() ) / 2.0 ) );
break;

case LabelMiddleRight:
return QgsGeometry::fromPointXY( QgsPointXY( rect.right(), ( rect.top() + rect.bottom() ) / 2.0 ) );
label = QgsGeometry::fromPointXY( QgsPointXY( rect.right(), ( rect.top() + rect.bottom() ) / 2.0 ) );
break;

case LabelBottomLeft:
return QgsGeometry::fromPointXY( QgsPointXY( rect.topLeft() ) );
label = QgsGeometry::fromPointXY( QgsPointXY( rect.topLeft() ) );
break;

case LabelBottomMiddle:
return QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.top() ) );
label = QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.top() ) );
break;

case LabelBottomRight:
return QgsGeometry::fromPointXY( QgsPointXY( rect.topRight() ) );
label = QgsGeometry::fromPointXY( QgsPointXY( rect.topRight() ) );
break;
}

label.rotate( angle, rect.topLeft() );
return label;
}

Expand Down
145 changes: 145 additions & 0 deletions tests/src/core/testqgscallout.cpp
Expand Up @@ -999,6 +999,23 @@ void TestQgsCallout::calloutLabelAnchorTopRight()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_top_right", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_top_right_rotated", img, 20 ) );

}

void TestQgsCallout::calloutLabelAnchorTopLeft()
Expand Down Expand Up @@ -1051,6 +1068,22 @@ void TestQgsCallout::calloutLabelAnchorTopLeft()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_top_left", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_top_left_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorTop()
Expand Down Expand Up @@ -1103,6 +1136,22 @@ void TestQgsCallout::calloutLabelAnchorTop()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_top_middle", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_top_middle_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorBottomLeft()
Expand Down Expand Up @@ -1155,6 +1204,22 @@ void TestQgsCallout::calloutLabelAnchorBottomLeft()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_bottom_left", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_bottom_left_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorBottom()
Expand Down Expand Up @@ -1207,6 +1272,22 @@ void TestQgsCallout::calloutLabelAnchorBottom()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_bottom_middle", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_bottom_middle_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorBottomRight()
Expand Down Expand Up @@ -1259,6 +1340,22 @@ void TestQgsCallout::calloutLabelAnchorBottomRight()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_bottom_right", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_bottom_right_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorLeft()
Expand Down Expand Up @@ -1311,6 +1408,22 @@ void TestQgsCallout::calloutLabelAnchorLeft()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_left", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_left_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorRight()
Expand Down Expand Up @@ -1363,6 +1476,22 @@ void TestQgsCallout::calloutLabelAnchorRight()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_right", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_right_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelAnchorCentroid()
Expand Down Expand Up @@ -1415,6 +1544,22 @@ void TestQgsCallout::calloutLabelAnchorCentroid()
p.end();

QVERIFY( imageCheck( "callout_label_anchor_centroid", img, 20 ) );

img = job.renderedImage();
p.begin( &img );
settings.placement = QgsPalLayerSettings::OverPoint;
settings.xOffset = 6;
settings.yOffset = -6;
settings.dataDefinedProperties().setProperty( QgsPalLayerSettings::LabelRotation, QgsProperty::fromValue( 15 ) );
vl->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsDefaultLabelingEngine engine2;
engine2.setMapSettings( mapSettings );
engine2.addProvider( new QgsVectorLayerLabelProvider( vl, QString(), true, &settings ) );
//engine.setFlags( QgsLabelingEngine::RenderOutlineLabels | QgsLabelingEngine::DrawLabelRectOnly );
engine2.run( context );
p.end();
QVERIFY( imageCheck( "callout_label_anchor_centroid_rotated", img, 20 ) );
}

void TestQgsCallout::calloutLabelDataDefinedAnchor()
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2bb4aad

Please sign in to comment.