Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6b8115a

Browse files
committedFeb 4, 2022
[labeling] Fix line anchor placements are reversed for labels which
sit below lines (cherry picked from commit b39288b)
1 parent 7bd931c commit 6b8115a

File tree

39 files changed

+93
-5
lines changed

39 files changed

+93
-5
lines changed
 

‎src/core/pal/feature.cpp

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,7 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
13251325
expanded = mapShape->clone();
13261326
expanded->extendLineByDistance( overrun, overrun, mLF->overrunSmoothDistance() );
13271327
mapShape = expanded.get();
1328+
shapeLength += 2 * overrun;
13281329
}
13291330

13301331
QgsLabeling::LinePlacementFlags flags = mLF->arrangementFlags();
@@ -1364,6 +1365,9 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
13641365
}
13651366
}
13661367

1368+
// calculate the anchor point for the original line shape as a GEOS point
1369+
const geos::unique_ptr originalPoint = mapShape->interpolatePoint( shapeLength * mLF->lineAnchorPercent() );
1370+
13671371
std::vector< std::unique_ptr< LabelPosition >> positions;
13681372
for ( PathOffset offset : { PositiveOffset, NoOffset, NegativeOffset } )
13691373
{
@@ -1388,7 +1392,20 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
13881392
if ( qgsDoubleNear( totalDistance, 0.0 ) )
13891393
continue;
13901394

1391-
const double lineAnchorPoint = totalDistance * mLF->lineAnchorPercent();
1395+
double lineAnchorPoint = 0;
1396+
if ( originalPoint && offset != NoOffset )
1397+
{
1398+
// the actual anchor point for the offset curves is the closest point on those offset curves
1399+
// to the anchor point on the original line. This avoids anchor points which differ greatly
1400+
// on the positive/negative offset lines due to line curvature.
1401+
lineAnchorPoint = currentMapShape->lineLocatePoint( originalPoint.get() );
1402+
}
1403+
else
1404+
{
1405+
lineAnchorPoint = totalDistance * mLF->lineAnchorPercent();
1406+
if ( offset == NegativeOffset )
1407+
lineAnchorPoint = totalDistance - lineAnchorPoint;
1408+
}
13921409

13931410
if ( pal->isCanceled() )
13941411
return 0;
@@ -1405,16 +1422,21 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
14051422
break;
14061423

14071424
case QgsLabelLineSettings::AnchorType::Strict:
1408-
distanceAlongLineToStartCandidate = std::min( lineAnchorPoint, totalDistance * 0.99 - getLabelWidth() );
1425+
distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - getLabelWidth() / 2, 0.0, totalDistance * 0.99 - getLabelWidth() );
14091426
singleCandidateOnly = true;
14101427
break;
14111428
}
14121429

1430+
bool hasTestedFirstPlacement = false;
14131431
for ( ; distanceAlongLineToStartCandidate <= totalDistance; distanceAlongLineToStartCandidate += delta )
14141432
{
1433+
if ( singleCandidateOnly && hasTestedFirstPlacement )
1434+
break;
1435+
14151436
if ( pal->isCanceled() )
14161437
return 0;
14171438

1439+
hasTestedFirstPlacement = true;
14181440
// placements may need to be reversed if using map orientation and the line has right-to-left direction
14191441
bool labeledLineSegmentIsRightToLeft = false;
14201442
const QgsTextRendererUtils::LabelLineDirection direction = ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ? QgsTextRendererUtils::RespectPainterOrientation : QgsTextRendererUtils::FollowLineDirection;
@@ -1475,9 +1497,6 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
14751497

14761498
if ( p )
14771499
positions.emplace_back( std::move( p ) );
1478-
1479-
if ( singleCandidateOnly )
1480-
break;
14811500
}
14821501
}
14831502

‎src/core/pal/pointset.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,44 @@ void PointSet::getPointByDistance( double *d, double *ad, double dl, double *px,
10361036
}
10371037
}
10381038

1039+
geos::unique_ptr PointSet::interpolatePoint( double distance ) const
1040+
{
1041+
const GEOSGeometry *thisGeos = geos();
1042+
if ( !thisGeos )
1043+
return nullptr;
1044+
1045+
try
1046+
{
1047+
geos::unique_ptr res( GEOSInterpolate_r( QgsGeos::getGEOSHandler(), thisGeos, distance ) );
1048+
return res;
1049+
}
1050+
catch ( GEOSException &e )
1051+
{
1052+
qWarning( "GEOS exception: %s", e.what() );
1053+
return nullptr;
1054+
}
1055+
}
1056+
1057+
double PointSet::lineLocatePoint( const GEOSGeometry *point ) const
1058+
{
1059+
const GEOSGeometry *thisGeos = geos();
1060+
if ( !thisGeos )
1061+
return -1;
1062+
1063+
double distance = -1;
1064+
try
1065+
{
1066+
distance = GEOSProject_r( QgsGeos::getGEOSHandler(), thisGeos, point );
1067+
}
1068+
catch ( GEOSException &e )
1069+
{
1070+
qWarning( "GEOS exception: %s", e.what() );
1071+
return -1;
1072+
}
1073+
1074+
return distance;
1075+
}
1076+
10391077
const GEOSGeometry *PointSet::geos() const
10401078
{
10411079
if ( !mGeos )

‎src/core/pal/pointset.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
#include "qgis_core.h"
4444
#include "qgsrectangle.h"
45+
#include "qgsgeos.h"
4546

4647
namespace pal
4748
{
@@ -185,6 +186,16 @@ namespace pal
185186
*/
186187
void getPointByDistance( double *d, double *ad, double dl, double *px, double *py );
187188

189+
/**
190+
* Returns a GEOS geometry representing the point interpolated on the shape by distance.
191+
*/
192+
geos::unique_ptr interpolatePoint( double distance ) const;
193+
194+
/**
195+
* Returns the distance along the geometry closest to the specified GEOS \a point.
196+
*/
197+
double lineLocatePoint( const GEOSGeometry *point ) const;
198+
188199
/**
189200
* Returns the point set's GEOS geometry.
190201
*/

‎tests/src/core/testqgslabelingengine.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3456,6 +3456,26 @@ void TestQgsLabelingEngine::testLineAnchorCurved()
34563456

34573457
img = job2.renderedImage();
34583458
QVERIFY( imageCheck( QStringLiteral( "curved_anchor_end" ), img, 20 ) );
3459+
3460+
settings.lineSettings().setLineAnchorPercent( 0.3 );
3461+
settings.lineSettings().setAnchorType( QgsLabelLineSettings::AnchorType::Strict );
3462+
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
3463+
QgsMapRendererSequentialJob job3( mapSettings );
3464+
job3.start();
3465+
job3.waitForFinished();
3466+
3467+
img = job3.renderedImage();
3468+
QVERIFY( imageCheck( QStringLiteral( "curved_anchor_30_above" ), img, 20 ) );
3469+
3470+
settings.lineSettings().setPlacementFlags( QgsLabeling::LinePlacementFlag::BelowLine );
3471+
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );
3472+
QgsMapRendererSequentialJob job4( mapSettings );
3473+
job4.start();
3474+
job4.waitForFinished();
3475+
3476+
img = job4.renderedImage();
3477+
QVERIFY( imageCheck( QStringLiteral( "curved_anchor_30_below" ), img, 20 ) );
3478+
34593479
}
34603480

34613481
void TestQgsLabelingEngine::testLineAnchorCurvedConstraints()

0 commit comments

Comments
 (0)
Please sign in to comment.