Skip to content

Commit c8db000

Browse files
committedMar 31, 2023
Refactor curved text placement generation to use a flag approach
1 parent cd3a1bf commit c8db000

File tree

6 files changed

+51
-21
lines changed

6 files changed

+51
-21
lines changed
 

‎src/core/pal/feature.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,7 +1309,7 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
13091309
return lPos.size();
13101310
}
13111311

1312-
std::unique_ptr< LabelPosition > FeaturePart::curvedPlacementAtOffset( PointSet *mapShape, const std::vector< double> &pathDistances, QgsTextRendererUtils::LabelLineDirection direction, const double offsetAlongLine, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints, bool uprightOnly )
1312+
std::unique_ptr< LabelPosition > FeaturePart::curvedPlacementAtOffset( PointSet *mapShape, const std::vector< double> &pathDistances, QgsTextRendererUtils::LabelLineDirection direction, const double offsetAlongLine, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints, QgsTextRendererUtils::CurvedTextFlags flags )
13131313
{
13141314
const QgsPrecalculatedTextMetrics *metrics = qgis::down_cast< QgsTextLabelFeature * >( mLF )->textMetrics();
13151315
Q_ASSERT( metrics );
@@ -1318,10 +1318,10 @@ std::unique_ptr< LabelPosition > FeaturePart::curvedPlacementAtOffset( PointSet
13181318
const double maximumCharacterAngleOutside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( mLF )->maximumCharacterAngleOutside() ) : -1;
13191319

13201320
std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > placement(
1321-
QgsTextRendererUtils::generateCurvedTextPlacement( *metrics, mapShape->x.data(), mapShape->y.data(), mapShape->nbPoints, pathDistances, offsetAlongLine, direction, maximumCharacterAngleInside, maximumCharacterAngleOutside, uprightOnly )
1321+
QgsTextRendererUtils::generateCurvedTextPlacement( *metrics, mapShape->x.data(), mapShape->y.data(), mapShape->nbPoints, pathDistances, offsetAlongLine, direction, maximumCharacterAngleInside, maximumCharacterAngleOutside, flags )
13221322
);
13231323

1324-
labeledLineSegmentIsRightToLeft = !uprightOnly ? placement->labeledLineSegmentIsRightToLeft : placement->flippedCharacterPlacementToGetUprightLabels;
1324+
labeledLineSegmentIsRightToLeft = !( flags & QgsTextRendererUtils::CurvedTextFlag::UprightCharactersOnly ) ? placement->labeledLineSegmentIsRightToLeft : placement->flippedCharacterPlacementToGetUprightLabels;
13251325

13261326
if ( placement->graphemePlacement.empty() )
13271327
return nullptr;
@@ -1548,9 +1548,11 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
15481548
// placements may need to be reversed if using map orientation and the line has right-to-left direction
15491549
bool labeledLineSegmentIsRightToLeft = false;
15501550
const QgsTextRendererUtils::LabelLineDirection direction = ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ? QgsTextRendererUtils::RespectPainterOrientation : QgsTextRendererUtils::FollowLineDirection;
1551-
std::unique_ptr< LabelPosition > labelPosition = curvedPlacementAtOffset( currentMapShape, pathDistances, direction, distanceAlongLineToStartCandidate, labeledLineSegmentIsRightToLeft, !singleCandidateOnly,
1552-
onlyShowUprightLabels() && ( !singleCandidateOnly || !( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ) );
1551+
QgsTextRendererUtils::CurvedTextFlags curvedTextFlags;
1552+
if ( onlyShowUprightLabels() && ( !singleCandidateOnly || !( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ) )
1553+
curvedTextFlags |= QgsTextRendererUtils::CurvedTextFlag::UprightCharactersOnly;
15531554

1555+
std::unique_ptr< LabelPosition > labelPosition = curvedPlacementAtOffset( currentMapShape, pathDistances, direction, distanceAlongLineToStartCandidate, labeledLineSegmentIsRightToLeft, !singleCandidateOnly, curvedTextFlags );
15541556
if ( !labelPosition )
15551557
{
15561558
continue;

‎src/core/pal/feature.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ namespace pal
224224
* \returns calculated label position
225225
*/
226226
std::unique_ptr< LabelPosition > curvedPlacementAtOffset( PointSet *mapShape, const std::vector<double> &pathDistances,
227-
QgsTextRendererUtils::LabelLineDirection direction, double distance, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints, bool uprightOnly );
227+
QgsTextRendererUtils::LabelLineDirection direction, double distance, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints,
228+
QgsTextRendererUtils::CurvedTextFlags flags );
228229

229230
/**
230231
* Generate curved candidates for line features.

‎src/core/textrenderer/qgstextrenderer.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,13 @@ void QgsTextRenderer::drawDocumentOnLine( const QPolygonF &line, const QgsTextFo
290290
QgsPrecalculatedTextMetrics metrics( graphemes, std::move( characterWidths ), std::move( characterHeights ), std::move( characterDescents ) );
291291
metrics.setGraphemeFormats( graphemeFormats );
292292

293-
std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > placement = QgsTextRendererUtils::generateCurvedTextPlacement( metrics, labelBaselineCurve, offsetAlongLine );
293+
std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > placement = QgsTextRendererUtils::generateCurvedTextPlacement(
294+
metrics, labelBaselineCurve, offsetAlongLine,
295+
QgsTextRendererUtils::RespectPainterOrientation,
296+
-1, -1,
297+
QgsTextRendererUtils::CurvedTextFlag::UseBaselinePlacement
298+
| QgsTextRendererUtils::CurvedTextFlag::UprightCharactersOnly );
299+
294300
if ( placement->graphemePlacement.empty() )
295301
return;
296302

‎src/core/textrenderer/qgstextrendererutils.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ QColor QgsTextRendererUtils::readColor( QgsVectorLayer *layer, const QString &pr
151151
return QColor( r, g, b, a );
152152
}
153153

154-
std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > QgsTextRendererUtils::generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const QPolygonF &line, double offsetAlongLine, LabelLineDirection direction, double maxConcaveAngle, double maxConvexAngle, bool uprightOnly )
154+
std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > QgsTextRendererUtils::generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const QPolygonF &line, double offsetAlongLine, LabelLineDirection direction, double maxConcaveAngle, double maxConvexAngle, CurvedTextFlags flags )
155155
{
156156
const int numPoints = line.size();
157157
std::vector<double> pathDistances( numPoints );
@@ -182,15 +182,15 @@ std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > QgsTextRendere
182182
y[i] = prevY;
183183
}
184184

185-
return generateCurvedTextPlacementPrivate( metrics, x.data(), y.data(), numPoints, pathDistances, offsetAlongLine, direction, maxConcaveAngle, maxConvexAngle, uprightOnly, false, true );
185+
return generateCurvedTextPlacementPrivate( metrics, x.data(), y.data(), numPoints, pathDistances, offsetAlongLine, direction, flags, maxConcaveAngle, maxConvexAngle, false );
186186
}
187187

188-
std::unique_ptr< 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 )
188+
std::unique_ptr< 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, CurvedTextFlags flags )
189189
{
190-
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, maxConcaveAngle, maxConvexAngle, uprightOnly );
190+
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, flags, maxConcaveAngle, maxConvexAngle, uprightOnly );
191191
}
192192

193-
std::unique_ptr< 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, bool calculateBaselinePlacement )
193+
std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > QgsTextRendererUtils::generateCurvedTextPlacementPrivate( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector<double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, CurvedTextFlags flags, double maxConcaveAngle, double maxConvexAngle, bool isSecondAttempt )
194194
{
195195
std::unique_ptr< CurvePlacementProperties > output = std::make_unique< CurvePlacementProperties >();
196196
output->graphemePlacement.reserve( metrics.count() );
@@ -314,7 +314,7 @@ std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > QgsTextRendere
314314
}
315315
}
316316

317-
if ( !calculateBaselinePlacement )
317+
if ( !( flags & CurvedTextFlag::UseBaselinePlacement ) )
318318
{
319319
// Shift the character downwards since the draw position is specified at the baseline
320320
// and we're calculating the mean line here
@@ -354,11 +354,11 @@ std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > QgsTextRendere
354354
output->upsideDownCharCount++;
355355
}
356356

357-
if ( !isSecondAttempt && uprightOnly && output->upsideDownCharCount >= characterCount / 2.0 )
357+
if ( !isSecondAttempt && ( flags & QgsTextRendererUtils::CurvedTextFlag::UprightCharactersOnly ) && output->upsideDownCharCount >= characterCount / 2.0 )
358358
{
359359
// more of text is upside down then right side up...
360360
// if text should be shown upright then retry with the opposite orientation
361-
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, maxConcaveAngle, maxConvexAngle, uprightOnly, true );
361+
return generateCurvedTextPlacementPrivate( metrics, x, y, numPoints, pathDistances, offsetAlongLine, direction, flags, maxConcaveAngle, maxConvexAngle, true );
362362
}
363363

364364
return output;

‎src/core/textrenderer/qgstextrendererutils.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,24 @@ class CORE_EXPORT QgsTextRendererUtils
141141
FollowLineDirection //!< Curved text placement will respect the line direction and ignore painter orientation
142142
};
143143

144+
/**
145+
* Flags controlling behavior of curved text generation.
146+
*
147+
* \since QGIS 3.2
148+
*/
149+
enum class CurvedTextFlag : int
150+
{
151+
UseBaselinePlacement = 1 << 1, //!< Generate placement based on the character baselines instead of centers
152+
UprightCharactersOnly = 1 << 2, //!< Permit upright characters only. If not present then upside down text placement is permitted.
153+
};
154+
155+
/**
156+
* Flags controlling behavior of curved text generation.
157+
*
158+
* \since QGIS 3.2
159+
*/
160+
Q_DECLARE_FLAGS( CurvedTextFlags, CurvedTextFlag )
161+
144162
/**
145163
* Calculates curved text placement properties.
146164
*
@@ -150,12 +168,12 @@ class CORE_EXPORT QgsTextRendererUtils
150168
* \param direction controls placement of text with respect to painter orientation or line direction
151169
* \param maxConcaveAngle maximum angle between characters for concave text, or -1 if not set
152170
* \param maxConvexAngle maximum angle between characters for convex text, or -1 if not set
153-
* \param uprightOnly set to TRUE if text should be placed in an upright orientation only, or FALSE to allow upside down text placement
171+
* \param flags flags controlling behavior of curved text generation
154172
*
155173
* \returns calculated placement properties, or NULLPTR if placement could not be calculated. Caller takes ownership of the returned placement.
156174
* \since QGIS 3.20
157175
*/
158-
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const QPolygonF &line, double offsetAlongLine, LabelLineDirection direction = RespectPainterOrientation, double maxConcaveAngle = -1, double maxConvexAngle = -1, bool uprightOnly = true ) SIP_SKIP;
176+
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const QPolygonF &line, double offsetAlongLine, LabelLineDirection direction = RespectPainterOrientation, double maxConcaveAngle = -1, double maxConvexAngle = -1, CurvedTextFlags flags = CurvedTextFlags() ) SIP_SKIP;
159177

160178
/**
161179
* Calculates curved text placement properties.
@@ -169,17 +187,17 @@ class CORE_EXPORT QgsTextRendererUtils
169187
* \param direction controls placement of text with respect to painter orientation or line direction
170188
* \param maxConcaveAngle maximum angle between characters for concave text, or -1 if not set
171189
* \param maxConvexAngle maximum angle between characters for convex text, or -1 if not set
172-
* \param uprightOnly set to TRUE if text should be placed in an upright orientation only, or FALSE to allow upside down text placement
190+
* \param flags flags controlling behavior of curved text generation
173191
*
174192
* \returns calculated placement properties, or NULLPTR if placement could not be calculated. Caller takes ownership of the returned placement.
175193
* \since QGIS 3.20
176194
*/
177-
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector< double> &pathDistances, double offsetAlongLine, LabelLineDirection direction = RespectPainterOrientation, double maxConcaveAngle = -1, double maxConvexAngle = -1, bool uprightOnly = true ) SIP_SKIP;
195+
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacement( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector< double> &pathDistances, double offsetAlongLine, LabelLineDirection direction = RespectPainterOrientation, double maxConcaveAngle = -1, double maxConvexAngle = -1, bool uprightOnly = true, CurvedTextFlags flags = CurvedTextFlags() ) SIP_SKIP;
178196
#endif
179197

180198
private:
181199

182-
static std::unique_ptr< 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, bool calculateBaselinePlacement = false ) SIP_SKIP;
200+
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacementPrivate( const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector< double> &pathDistances, double offsetAlongLine, LabelLineDirection direction, CurvedTextFlags flags, double maxConcaveAngle = -1, double maxConvexAngle = -1, bool isSecondAttempt = false ) SIP_SKIP;
183201

184202
//! Returns TRUE if the next char position is found. The referenced parameters are updated.
185203
static bool nextCharPosition( double charWidth, double segmentLength, const double *x, const double *y, int numPoints, int &index, double &currentDistanceAlongSegment,
@@ -189,6 +207,9 @@ class CORE_EXPORT QgsTextRendererUtils
189207
double x1, double y1, double x2, double y2,
190208
double &xRes, double &yRes );
191209
};
210+
#ifndef SIP_RUN
211+
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsTextRendererUtils::CurvedTextFlags );
212+
#endif
192213

193214

194215
#endif // QGSTEXTRENDERERUTILS_H

‎tests/src/python/test_qgsannotationlinetextitem.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def testRenderWithTransform(self):
272272
def imageCheck(self, name, reference_image, image):
273273
TestQgsAnnotationLineTextItem.report += f"<h2>Render {name}</h2>\n"
274274
temp_dir = QDir.tempPath() + '/'
275-
file_name = temp_dir + 'patch_' + name + ".png"
275+
file_name = temp_dir + 'annotation_' + name + ".png"
276276
image.save(file_name, "PNG")
277277
checker = QgsRenderChecker()
278278
checker.setControlPathPrefix("annotation_layer")

0 commit comments

Comments
 (0)
Please sign in to comment.