[labeling] Fix curved labels sometimes placed below line even when

set to above line only
This commit is contained in:
Nyall Dawson 2019-05-28 16:13:26 +10:00
parent 50315c4a33
commit 10c4bb9f9b
4 changed files with 83 additions and 7 deletions

View File

@ -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;
}
@ -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

View File

@ -56,6 +56,7 @@ class TestQgsLabelingEngine : public QObject
void testTouchingParts();
void testMergingLinesWithForks();
void testCurvedLabelsWithTinySegments();
void testCurvedLabelCorrectLinePlacement();
void testLabelBoundary();
void testLabelBlockingRegion();
void testLabelRotationWithReprojection();
@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB