QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 
23 
25  : QgsLabelFeature( id, std::move( geometry ), size )
26 
27 {
28  mDefinedFont = QFont();
29 }
30 
31 
33 {
34  delete mFontMetrics;
35 }
36 
37 
38 QString QgsTextLabelFeature::text( int partId ) const
39 {
40  if ( partId == -1 )
41  return mLabelText;
42  else
43  return mClusters.at( partId );
44 }
45 
46 
47 void QgsTextLabelFeature::calculateInfo( bool curvedLabeling, QFontMetricsF *fm, const QgsMapToPixel *xform, double maxinangle, double maxoutangle )
48 {
49  if ( mInfo )
50  return;
51 
52  mFontMetrics = new QFontMetricsF( *fm ); // duplicate metrics for when drawing label
53 
54  qreal letterSpacing = mDefinedFont.letterSpacing();
55  qreal wordSpacing = mDefinedFont.wordSpacing();
56 
57  // max angle between curved label characters (20.0/-20.0 was default in QGIS <= 1.8)
58  if ( maxinangle < 20.0 )
59  maxinangle = 20.0;
60  if ( 60.0 < maxinangle )
61  maxinangle = 60.0;
62  if ( maxoutangle > -20.0 )
63  maxoutangle = -20.0;
64  if ( -95.0 > maxoutangle )
65  maxoutangle = -95.0;
66 
67  // create label info!
68  double mapScale = xform->mapUnitsPerPixel();
69  double labelHeight = mapScale * fm->height();
70 
71  // mLetterSpacing/mWordSpacing = 0.0 is default for non-curved labels
72  // (non-curved spacings handled by Qt in QgsPalLayerSettings/QgsPalLabeling)
73  qreal charWidth;
74  qreal wordSpaceFix;
75 
76  //split string by valid grapheme boundaries - required for certain scripts (see #6883)
78 
79  mInfo = new pal::LabelInfo( mClusters.count(), labelHeight, maxinangle, maxoutangle );
80  for ( int i = 0; i < mClusters.count(); i++ )
81  {
82  // reconstruct how Qt creates word spacing, then adjust per individual stored character
83  // this will allow PAL to create each candidate width = character width + correct spacing
84  charWidth = fm->width( mClusters[i] );
85  if ( curvedLabeling )
86  {
87  wordSpaceFix = qreal( 0.0 );
88  if ( mClusters[i] == QLatin1String( " " ) )
89  {
90  // word spacing only gets added once at end of consecutive run of spaces, see QTextEngine::shapeText()
91  int nxt = i + 1;
92  wordSpaceFix = ( nxt < mClusters.count() && mClusters[nxt] != QLatin1String( " " ) ) ? wordSpacing : qreal( 0.0 );
93  }
94  // this workaround only works for clusters with a single character. Not sure how it should be handled
95  // with multi-character clusters.
96  if ( mClusters[i].length() == 1 &&
97  !qgsDoubleNear( fm->width( QString( mClusters[i].at( 0 ) ) ), fm->width( mClusters[i].at( 0 ) ) + letterSpacing ) )
98  {
99  // word spacing applied when it shouldn't be
100  wordSpaceFix -= wordSpacing;
101  }
102 
103  charWidth = fm->width( QString( mClusters[i] ) ) + wordSpaceFix;
104  }
105 
106  double labelWidth = mapScale * charWidth;
107  mInfo->char_info[i].width = labelWidth;
108  }
109 }
QFontMetricsF * mFontMetrics
Metrics of the font for rendering.
QgsTextLabelFeature(QgsFeatureId id, GEOSGeometry *geometry, const QSizeF &size)
Construct text label feature.
QString mLabelText
text of the label
QStringList mClusters
List of graphemes (used for curved labels)
~QgsTextLabelFeature()
Clean up.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:278
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
pal::LabelInfo * mInfo
extra information for curved labels (may be null)
CharacterInfo * char_info
Definition: feature.h:83
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Definition: qgsgeos.h:79
Optional additional info about label (for curved labels)
Definition: feature.h:55
void calculateInfo(bool curvedLabeling, QFontMetricsF *fm, const QgsMapToPixel *xform, double fontScale, double maxinangle, double maxoutangle)
calculate data for info(). setDefinedFont() must have been called already.
double mapUnitsPerPixel() const
Returns current map units per pixel.
QString text(int partId) const
Returns the text component corresponding to a specified label part.
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
static QStringList splitToGraphemes(const QString &text)
Splits a text string to a list of graphemes, which are the smallest allowable character divisions in ...
QFont mDefinedFont
Font for rendering.