Skip to content
Permalink
Browse files

[labeling] Fix some valid curved label placements are rejected

because we fail to correctly determine character angles, and
instead reject the placement as violating the max character in/out
angles

This happens predominantly in maps with geographic CRS, but is
also seen in large scale projected maps. The calculation for
line circle intersections used to determine curved label character
placement becomes numerically unstable when the map extent width/height
is small.
  • Loading branch information
nyalldawson committed Apr 5, 2021
1 parent 9960b15 commit 79b00fd5e987ece725428fe93df1abc199615c9f
@@ -1405,10 +1405,12 @@ static std::unique_ptr< LabelPosition > _createCurvedCandidate( LabelPosition *l
std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal )
{
LabelInfo *li = mLF->curvedLabelInfo();

// label info must be present
if ( !li )
return 0;

const int characterCount = li->count();
if ( !li || characterCount == 0 )
if ( characterCount == 0 )
return 0;

// TODO - we may need an explicit penalty for overhanging labels. Currently, they are penalized just because they
@@ -56,6 +56,13 @@ namespace pal
{
public:

/**
* Constructor for LabelInfo
* \param characterHeight height of characters
* \param characterWidths vector of character widths
* \param maxinangle maximum acceptable in angle (in degrees)
* \param maxoutangle maximum acceptable out angle (in degrees)
*/
LabelInfo( double characterHeight, std::vector< double > characterWidths, double maxinangle = 20.0, double maxoutangle = -20.0 )
: maxCharAngleInsideRadians( maxinangle * M_PI / 180 )
// outside angle should be negative
@@ -378,6 +378,21 @@ void GeomFunction::findLineCircleIntersection( double cx, double cy, double radi
double x1, double y1, double x2, double y2,
double &xRes, double &yRes )
{
double multiplier = 1;
if ( radius < 10 )
{
// these calculations get unstable for small coordinates differences, e.g. as a result of map labeling in a geographic
// CRS
multiplier = 10000;
x1 *= multiplier;
y1 *= multiplier;
x2 *= multiplier;
y2 *= multiplier;
cx *= multiplier;
cy *= multiplier;
radius *= multiplier;
}

double dx = x2 - x1;
double dy = y2 - y1;

@@ -406,4 +421,10 @@ void GeomFunction::findLineCircleIntersection( double cx, double cy, double radi
xRes = x1 + t * dx;
yRes = y1 + t * dy;
}

if ( multiplier != 1 )
{
xRes /= multiplier;
yRes /= multiplier;
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit 79b00fd

Please sign in to comment.