QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgstextlabelfeature.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstextlabelfeature.cpp
3  ---------------------
4  begin : December 2015
5  copyright : (C) 2015 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgstextlabelfeature.h"
17 
18 #include "qgsgeometry.h"
19 #include "qgspallabeling.h"
20 #include "qgsmaptopixel.h"
21 #include "pal/feature.h"
22 #include "qgstextcharacterformat.h"
23 #include "qgstextfragment.h"
24 #include "qgstextblock.h"
25 
27  : QgsLabelFeature( id, std::move( geometry ), size )
28 {
29  mDefinedFont = QFont();
30 }
31 
33 
34 QString QgsTextLabelFeature::text( int partId ) const
35 {
36  if ( partId == -1 )
37  return mLabelText;
38  else
39  return mTextMetrics->grapheme( partId );
40 }
41 
43 {
44  return mTextMetrics.has_value() ? mTextMetrics->graphemeFormat( partId ) : QgsTextCharacterFormat();
45 }
46 
48 {
49  return mTextMetrics.has_value() && partId < mTextMetrics->graphemeFormatCount();
50 }
51 
52 void QgsTextLabelFeature::setFontMetrics( const QFontMetricsF &metrics )
53 {
54  mFontMetrics = metrics; // duplicate metrics for when drawing label
55 }
56 
57 QgsPrecalculatedTextMetrics QgsTextLabelFeature::calculateTextMetrics( const QgsMapToPixel *xform, const QFontMetricsF &fontMetrics, double letterSpacing, double wordSpacing, const QString &text, QgsTextDocument *document )
58 {
59  // create label info!
60  const double mapScale = xform->mapUnitsPerPixel();
61  const double characterHeight = mapScale * fontMetrics.height();
62  QStringList graphemes;
63  QVector< QgsTextCharacterFormat > graphemeFormats;
64 
65  if ( document )
66  {
67  for ( const QgsTextBlock &block : std::as_const( *document ) )
68  {
69  for ( const QgsTextFragment &fragment : block )
70  {
71  const QStringList fragmentGraphemes = QgsPalLabeling::splitToGraphemes( fragment.text() );
72  for ( const QString &grapheme : fragmentGraphemes )
73  {
74  graphemes.append( grapheme );
75  graphemeFormats.append( fragment.characterFormat() );
76  }
77  }
78  }
79  }
80  else
81  {
82  //split string by valid grapheme boundaries - required for certain scripts (see #6883)
84  }
85 
86  QVector< double > characterWidths( graphemes.count() );
87  for ( int i = 0; i < graphemes.count(); i++ )
88  {
89  // reconstruct how Qt creates word spacing, then adjust per individual stored character
90  // this will allow PAL to create each candidate width = character width + correct spacing
91 
92  qreal wordSpaceFix = qreal( 0.0 );
93  if ( graphemes[i] == QLatin1String( " " ) )
94  {
95  // word spacing only gets added once at end of consecutive run of spaces, see QTextEngine::shapeText()
96  int nxt = i + 1;
97  wordSpaceFix = ( nxt < graphemes.count() && graphemes[nxt] != QLatin1String( " " ) ) ? wordSpacing : qreal( 0.0 );
98  }
99  // this workaround only works for clusters with a single character. Not sure how it should be handled
100  // with multi-character clusters.
101  if ( graphemes[i].length() == 1 &&
102  !qgsDoubleNear( fontMetrics.horizontalAdvance( QString( graphemes[i].at( 0 ) ) ), fontMetrics.horizontalAdvance( graphemes[i].at( 0 ) ) + letterSpacing ) )
103  {
104  // word spacing applied when it shouldn't be
105  wordSpaceFix -= wordSpacing;
106  }
107 
108  const double charWidth = fontMetrics.horizontalAdvance( QString( graphemes[i] ) ) + wordSpaceFix;
109  characterWidths[i] = mapScale * charWidth;
110  }
111 
112  QgsPrecalculatedTextMetrics res( graphemes, characterHeight, std::move( characterWidths ) );
113  res.setGraphemeFormats( graphemeFormats );
114  return res;
115 }
116 
118 {
119  return mDocument;
120 }
121 
123 {
125 }
The QgsLabelFeature class describes a feature that should be used within the labeling engine.
QString mLabelText
text of the label
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
double mapUnitsPerPixel() const
Returns current map units per pixel.
static QStringList splitToGraphemes(const QString &text)
Splits a text string to a list of graphemes, which are the smallest allowable character divisions in ...
Contains precalculated properties regarding text metrics for text to be renderered at a later stage.
void setGraphemeFormats(const QVector< QgsTextCharacterFormat > &formats)
Sets the character formats associated with the text graphemes().
Represents a block of text consisting of one or more QgsTextFragment objects.
Definition: qgstextblock.h:36
Stores information relating to individual character formatting.
Represents a document consisting of one or more QgsTextBlock objects.
Stores a fragment of text along with formatting overrides to be used when rendering the fragment.
void setDocument(const QgsTextDocument &document)
Sets the document for the label.
void setFontMetrics(const QFontMetricsF &metrics)
Sets the font metrics.
QgsTextLabelFeature(QgsFeatureId id, geos::unique_ptr geometry, QSizeF size)
Construct text label feature.
QgsTextDocument document() const
Returns the document for the label.
static QgsPrecalculatedTextMetrics calculateTextMetrics(const QgsMapToPixel *xform, const QFontMetricsF &fontMetrics, double letterSpacing, double wordSpacing, const QString &text=QString(), QgsTextDocument *document=nullptr)
Calculate text metrics for later retrieval via textMetrics().
QgsTextDocument mDocument
~QgsTextLabelFeature() override
Clean up.
QgsTextCharacterFormat characterFormat(int partId) const
Returns the character format corresponding to the specified label part.
QFont mDefinedFont
Font for rendering.
QString text(int partId) const
Returns the text component corresponding to a specified label part.
std::optional< QFontMetricsF > mFontMetrics
Metrics of the font for rendering.
bool hasCharacterFormat(int partId) const
Returns true if the feature contains specific character formatting for the part with matching ID.
std::optional< QgsPrecalculatedTextMetrics > mTextMetrics
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Definition: qgsgeos.h:79
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28