Skip to content
Permalink
Browse files
Followup curved text placement refactoring -- further simplification …
…of logic
  • Loading branch information
nyalldawson committed Apr 9, 2021
1 parent 7126faf commit 80964bb6b1789bbdc0ef8ad107c2b6e68e1d14ea
Showing with 19 additions and 29 deletions.
  1. +16 −22 src/core/textrenderer/qgstextrendererutils.cpp
  2. +3 −7 src/core/textrenderer/qgstextrendererutils.h
@@ -176,16 +176,16 @@ QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCu
prevY = *y++;
}

return generateCurvedTextPlacementPrivate( metrics, line->xData(), line->yData(), numPoints, pathDistances, offsetAlongLine, direction, LeftToRight, maxConcaveAngle, maxConvexAngle, uprightOnly );
return generateCurvedTextPlacementPrivate( metrics, line->xData(), line->yData(), numPoints, pathDistances, offsetAlongLine, direction, maxConcaveAngle, maxConvexAngle, uprightOnly );
}
#endif

QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector<double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, double maxConcaveAngle, double maxConvexAngle, bool uprightOnly )
{
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, LeftToRight, maxConcaveAngle, maxConvexAngle, uprightOnly );
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, maxConcaveAngle, maxConvexAngle, uprightOnly );
}

QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCurvedTextPlacementPrivate( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector<double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, LineOrientationAtLabelPosition orientation, double maxConcaveAngle, double maxConvexAngle, bool uprightOnly, bool isSecondAttempt )
QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCurvedTextPlacementPrivate( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector<double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, double maxConcaveAngle, double maxConvexAngle, bool uprightOnly, bool isSecondAttempt )
{
std::unique_ptr< CurvePlacementProperties > output = std::make_unique< CurvePlacementProperties >();
output->graphemePlacement.reserve( metrics.count() );
@@ -245,24 +245,18 @@ QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCu
double dy = endLabelY - startLabelY;
const double lineAngle = std::atan2( -dy, dx ) * 180 / M_PI;

orientation = ( lineAngle > 90 || lineAngle < -90 ) ? RightToLeft : LeftToRight;
if ( orientation == RightToLeft )
if ( lineAngle > 90 || lineAngle < -90 )
{
output->labeledLineSegmentIsRightToLeft = true;
}
}

if ( orientation == RightToLeft )
if ( isSecondAttempt )
{
if ( !isSecondAttempt )
{
// first pass - we try treating the segment as running from right to left, and see how many upside down characters we get
orientation = LeftToRight;
}
else
{
// we know that treating the segment as running from right to left gave too many upside down characters, so try again treating the
// segment as left to right
output->labeledLineSegmentIsRightToLeft = false;
}
// we know that treating the segment as running from right to left gave too many upside down characters, so try again treating the
// segment as left to right
output->labeledLineSegmentIsRightToLeft = false;
output->flippedCharacterPlacementToGetUprightLabels = true;
}

double dx = x[index] - x[index - 1];
@@ -275,7 +269,7 @@ QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCu
double lastCharacterAngle = angle;

// grab the next character according to the orientation
const double characterWidth = ( orientation == LeftToRight ? metrics.characterWidth( i ) : metrics.characterWidth( characterCount - i - 1 ) );
const double characterWidth = !output->flippedCharacterPlacementToGetUprightLabels ? metrics.characterWidth( i ) : metrics.characterWidth( characterCount - i - 1 );
if ( qgsDoubleNear( characterWidth, 0.0 ) )
// Certain scripts rely on zero-width character, skip those to prevent failure (see #15801)
continue;
@@ -314,7 +308,7 @@ QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCu
// Shift the character downwards since the draw position is specified at the baseline
// and we're calculating the mean line here
double dist = 0.9 * metrics.characterHeight() / 2;
if ( orientation == RightToLeft )
if ( output->flippedCharacterPlacementToGetUprightLabels )
{
dist = -dist;
}
@@ -323,12 +317,12 @@ QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCu

double renderAngle = angle;
CurvedGraphemePlacement placement;
placement.graphemeIndex = orientation == LeftToRight ? i : characterCount - i - 1;
placement.graphemeIndex = !output->flippedCharacterPlacementToGetUprightLabels ? i : characterCount - i - 1;
placement.x = characterStartX;
placement.y = characterStartY;
placement.width = characterWidth;
placement.height = characterHeight;
if ( orientation == RightToLeft )
if ( output->flippedCharacterPlacementToGetUprightLabels )
{
// rotate in place
placement.x += characterWidth * std::cos( renderAngle );
@@ -352,7 +346,7 @@ QgsTextRendererUtils::CurvePlacementProperties *QgsTextRendererUtils::generateCu
{
// more of text is upside down then right side up...
// if text should be shown upright then retry with the opposite orientation
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, QgsTextRendererUtils::RightToLeft, maxConcaveAngle, maxConvexAngle, uprightOnly, true );
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, maxConcaveAngle, maxConvexAngle, uprightOnly, true );
}

return output.release();
@@ -129,6 +129,8 @@ class CORE_EXPORT QgsTextRendererUtils
int upsideDownCharCount = 0;
//! TRUE if labeled section of line is calculated to be of right-to-left orientation
bool labeledLineSegmentIsRightToLeft = false;
//! TRUE if the character placement had to be reversed in order to obtain upright labels on the segment
bool flippedCharacterPlacementToGetUprightLabels = false;
};

/**
@@ -167,13 +169,7 @@ class CORE_EXPORT QgsTextRendererUtils

private:

enum LineOrientationAtLabelPosition
{
LeftToRight,
RightToLeft
};

static CurvePlacementProperties *generateCurvedTextPlacementPrivate( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector< double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, LineOrientationAtLabelPosition orientation, double maxConcaveAngle = -1, double maxConvexAngle = -1, bool uprightOnly = true, bool isSecondAttempt = false ) SIP_SKIP;
static CurvePlacementProperties *generateCurvedTextPlacementPrivate( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector< double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, double maxConcaveAngle = -1, double maxConvexAngle = -1, bool uprightOnly = true, bool isSecondAttempt = false ) SIP_SKIP;

//! Returns TRUE if the next char position is found. The referenced parameters are updated.
static bool nextCharPosition( double charWidth, double segmentLength, const double *x, const double *y, int numPoints, int &index, double &currentDistanceAlongSegment,

0 comments on commit 80964bb

Please sign in to comment.