Skip to content

Commit 10c4bb9

Browse files
committedMay 30, 2019
[labeling] Fix curved labels sometimes placed below line even when
set to above line only
1 parent 50315c4 commit 10c4bb9

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed
 

‎src/core/pal/feature.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -998,22 +998,31 @@ LabelPosition *FeaturePart::curvedPlacementAtOffset( PointSet *path_positions, d
998998
double _distance = offsetAlongSegment;
999999
int endindex = index;
10001000

1001+
double startLabelX = 0;
1002+
double startLabelY = 0;
1003+
double endLabelX = 0;
1004+
double endLabelY = 0;
10011005
for ( int i = 0; i < li->char_num; i++ )
10021006
{
10031007
LabelInfo::CharacterInfo &ci = li->char_info[i];
1004-
double start_x, start_y, end_x, end_y;
1005-
if ( !nextCharPosition( ci.width, path_distances[endindex], path_positions, endindex, _distance, start_x, start_y, end_x, end_y ) )
1008+
double start_x, start_y;
1009+
if ( !nextCharPosition( ci.width, path_distances[endindex], path_positions, endindex, _distance, start_x, start_y, endLabelX, endLabelY ) )
10061010
{
10071011
return nullptr;
10081012
}
1013+
if ( i == 0 )
1014+
{
1015+
startLabelX = start_x;
1016+
startLabelY = start_y;
1017+
}
10091018
}
10101019

10111020
// Determine the angle of the path segment under consideration
1012-
double dx = path_positions->x[endindex] - path_positions->x[index];
1013-
double dy = path_positions->y[endindex] - path_positions->y[index];
1014-
double line_angle = std::atan2( -dy, dx );
1021+
double dx = endLabelX - startLabelX;
1022+
double dy = endLabelY - startLabelY;
1023+
const double lineAngle = std::atan2( -dy, dx ) * 180 / M_PI;
10151024

1016-
bool isRightToLeft = ( line_angle > 0.55 * M_PI || line_angle < -0.45 * M_PI );
1025+
bool isRightToLeft = ( lineAngle > 90 || lineAngle < -90 );
10171026
reversed = isRightToLeft;
10181027
orientation = isRightToLeft ? -1 : 1;
10191028
}
@@ -1175,7 +1184,7 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition * > &lPos
11751184
QLinkedList<LabelPosition *> positions;
11761185
double delta = std::max( li->label_height, total_distance / mLF->layer()->pal->line_p );
11771186

1178-
unsigned long flags = mLF->layer()->arrangementFlags();
1187+
pal::LineArrangementFlags flags = mLF->layer()->arrangementFlags();
11791188
if ( flags == 0 )
11801189
flags = FLAG_ON_LINE; // default flag
11811190

‎tests/src/core/testqgslabelingengine.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class TestQgsLabelingEngine : public QObject
5656
void testTouchingParts();
5757
void testMergingLinesWithForks();
5858
void testCurvedLabelsWithTinySegments();
59+
void testCurvedLabelCorrectLinePlacement();
5960
void testLabelBoundary();
6061
void testLabelBlockingRegion();
6162
void testLabelRotationWithReprojection();
@@ -1037,6 +1038,72 @@ void TestQgsLabelingEngine::testCurvedLabelsWithTinySegments()
10371038
QVERIFY( imageCheck( QStringLiteral( "label_curved_label_small_segments" ), img, 20 ) );
10381039
}
10391040

1041+
void TestQgsLabelingEngine::testCurvedLabelCorrectLinePlacement()
1042+
{
1043+
// test drawing curved labels when input linestring has many small segments
1044+
QgsPalLayerSettings settings;
1045+
setDefaultLabelParams( settings );
1046+
1047+
QgsTextFormat format = settings.format();
1048+
format.setSize( 20 );
1049+
format.setColor( QColor( 0, 0, 0 ) );
1050+
settings.setFormat( format );
1051+
1052+
settings.fieldName = QStringLiteral( "'XXXXXXXXXXXXXXXXXXXXXXXXXX'" );
1053+
settings.isExpression = true;
1054+
settings.placement = QgsPalLayerSettings::Curved;
1055+
settings.placementFlags = QgsPalLayerSettings::AboveLine | QgsPalLayerSettings::MapOrientation;
1056+
settings.maxCurvedCharAngleIn = 99;
1057+
settings.maxCurvedCharAngleOut = 99;
1058+
1059+
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:4326&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
1060+
vl2->setRenderer( new QgsNullSymbolRenderer() );
1061+
1062+
QgsFeature f;
1063+
f.setAttributes( QgsAttributes() << 1 );
1064+
// Geometry which roughly curves around from "1 oclock" anticlockwise to 6 oclock.
1065+
QgsGeometry g( QgsGeometry::fromWkt( QStringLiteral( "LineString (0.30541596873255172 0.3835845896147404, -0.08989391401451696 0.21831379117811278, -0.33668341708542704 -0.01619207146845336, -0.156895589056393 -0.20714684533780003, 0.02735901730876611 -0.21496370742601911)" ) ) );
1066+
f.setGeometry( g );
1067+
QVERIFY( vl2->dataProvider()->addFeature( f ) );
1068+
1069+
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
1070+
vl2->setLabelsEnabled( true );
1071+
1072+
// make a fake render context
1073+
QSize size( 640, 480 );
1074+
QgsMapSettings mapSettings;
1075+
mapSettings.setDestinationCrs( vl2->crs() );
1076+
1077+
mapSettings.setOutputSize( size );
1078+
mapSettings.setExtent( g.boundingBox() );
1079+
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
1080+
mapSettings.setOutputDpi( 96 );
1081+
1082+
QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
1083+
engineSettings.setFlag( QgsLabelingEngineSettings::UsePartialCandidates, false );
1084+
engineSettings.setFlag( QgsLabelingEngineSettings::DrawLabelRectOnly, true );
1085+
//engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, true );
1086+
mapSettings.setLabelingEngineSettings( engineSettings );
1087+
1088+
QgsMapRendererSequentialJob job( mapSettings );
1089+
job.start();
1090+
job.waitForFinished();
1091+
1092+
QImage img = job.renderedImage();
1093+
QVERIFY( imageCheck( QStringLiteral( "label_curved_label_above_1" ), img, 20 ) );
1094+
1095+
// and below...
1096+
settings.placementFlags = QgsPalLayerSettings::BelowLine | QgsPalLayerSettings::MapOrientation;
1097+
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
1098+
1099+
QgsMapRendererSequentialJob job2( mapSettings );
1100+
job2.start();
1101+
job2.waitForFinished();
1102+
1103+
img = job2.renderedImage();
1104+
QVERIFY( imageCheck( QStringLiteral( "label_curved_label_below_1" ), img, 20 ) );
1105+
}
1106+
10401107
void TestQgsLabelingEngine::testLabelBoundary()
10411108
{
10421109
// test that no labels are drawn outside of the specified label boundary

0 commit comments

Comments
 (0)
Please sign in to comment.