Skip to content

Commit

Permalink
[labeling] Fix curved labels sometimes placed below line even when
Browse files Browse the repository at this point in the history
set to above line only
  • Loading branch information
nyalldawson committed May 30, 2019
1 parent 50315c4 commit 10c4bb9
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 7 deletions.
23 changes: 16 additions & 7 deletions src/core/pal/feature.cpp
Expand Up @@ -998,22 +998,31 @@ LabelPosition *FeaturePart::curvedPlacementAtOffset( PointSet *path_positions, d
double _distance = offsetAlongSegment;
int endindex = index;

double startLabelX = 0;
double startLabelY = 0;
double endLabelX = 0;
double endLabelY = 0;
for ( int i = 0; i < li->char_num; i++ )
{
LabelInfo::CharacterInfo &ci = li->char_info[i];
double start_x, start_y, end_x, end_y;
if ( !nextCharPosition( ci.width, path_distances[endindex], path_positions, endindex, _distance, start_x, start_y, end_x, end_y ) )
double start_x, start_y;
if ( !nextCharPosition( ci.width, path_distances[endindex], path_positions, endindex, _distance, start_x, start_y, endLabelX, endLabelY ) )
{
return nullptr;
}
if ( i == 0 )
{
startLabelX = start_x;
startLabelY = start_y;
}
}

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

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

unsigned long flags = mLF->layer()->arrangementFlags();
pal::LineArrangementFlags flags = mLF->layer()->arrangementFlags();
if ( flags == 0 )
flags = FLAG_ON_LINE; // default flag

Expand Down
67 changes: 67 additions & 0 deletions tests/src/core/testqgslabelingengine.cpp
Expand Up @@ -56,6 +56,7 @@ class TestQgsLabelingEngine : public QObject
void testTouchingParts();
void testMergingLinesWithForks();
void testCurvedLabelsWithTinySegments();
void testCurvedLabelCorrectLinePlacement();
void testLabelBoundary();
void testLabelBlockingRegion();
void testLabelRotationWithReprojection();
Expand Down Expand Up @@ -1037,6 +1038,72 @@ void TestQgsLabelingEngine::testCurvedLabelsWithTinySegments()
QVERIFY( imageCheck( QStringLiteral( "label_curved_label_small_segments" ), img, 20 ) );
}

void TestQgsLabelingEngine::testCurvedLabelCorrectLinePlacement()
{
// test drawing curved labels when input linestring has many small segments
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );

QgsTextFormat format = settings.format();
format.setSize( 20 );
format.setColor( QColor( 0, 0, 0 ) );
settings.setFormat( format );

settings.fieldName = QStringLiteral( "'XXXXXXXXXXXXXXXXXXXXXXXXXX'" );
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::Curved;
settings.placementFlags = QgsPalLayerSettings::AboveLine | QgsPalLayerSettings::MapOrientation;
settings.maxCurvedCharAngleIn = 99;
settings.maxCurvedCharAngleOut = 99;

std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:4326&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );

QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
// Geometry which roughly curves around from "1 oclock" anticlockwise to 6 oclock.
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)" ) ) );
f.setGeometry( g );
QVERIFY( vl2->dataProvider()->addFeature( f ) );

vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );

// make a fake render context
QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setDestinationCrs( vl2->crs() );

mapSettings.setOutputSize( size );
mapSettings.setExtent( g.boundingBox() );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );

QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( QgsLabelingEngineSettings::UsePartialCandidates, false );
engineSettings.setFlag( QgsLabelingEngineSettings::DrawLabelRectOnly, true );
//engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );

QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();

QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_curved_label_above_1" ), img, 20 ) );

// and below...
settings.placementFlags = QgsPalLayerSettings::BelowLine | QgsPalLayerSettings::MapOrientation;
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!

QgsMapRendererSequentialJob job2( mapSettings );
job2.start();
job2.waitForFinished();

img = job2.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_curved_label_below_1" ), img, 20 ) );
}

void TestQgsLabelingEngine::testLabelBoundary()
{
// test that no labels are drawn outside of the specified label boundary
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.

0 comments on commit 10c4bb9

Please sign in to comment.