QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgspallabeling.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspallabeling.cpp
3  Smart labeling for vector layers
4  -------------------
5  begin : June 2009
6  copyright : (C) Martin Dobias
7  email : wonder dot sk at gmail dot com
8 
9  ***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgspallabeling.h"
19 #include "qgstextlabelfeature.h"
20 #include "qgsunittypes.h"
21 #include "qgsexception.h"
22 #include "qgsapplication.h"
23 #include "qgsstyle.h"
24 
25 #include <list>
26 
27 #include "pal/pal.h"
28 #include "pal/feature.h"
29 #include "pal/layer.h"
30 #include "pal/palexception.h"
31 #include "pal/problem.h"
32 #include "pal/labelposition.h"
33 
34 #include <cmath>
35 
36 #include <QApplication>
37 #include <QByteArray>
38 #include <QString>
39 #include <QFontMetrics>
40 #include <QTime>
41 #include <QPainter>
42 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
43 #include <QDesktopWidget>
44 #else
45 #include <QScreen>
46 #include <QWidget>
47 #endif
48 #include <QTextBoundaryFinder>
49 
50 #include "diagram/qgsdiagram.h"
51 #include "qgsdiagramrenderer.h"
52 #include "qgsfontutils.h"
53 #include "qgslabelsearchtree.h"
54 #include "qgsexpression.h"
55 #include "qgslabelingengine.h"
56 #include "qgsvectorlayerlabeling.h"
57 #include "qgstextrendererutils.h"
58 #include "qgstextfragment.h"
59 #include "qgsmultisurface.h"
60 #include "qgslogger.h"
61 #include "qgsvectorlayer.h"
62 #include "qgsvectordataprovider.h"
65 #include "qgsgeometry.h"
66 #include "qgsreferencedgeometry.h"
67 #include "qgsmarkersymbollayer.h"
68 #include "qgspainting.h"
69 #include "qgsproject.h"
70 #include "qgsproperty.h"
71 #include "qgssymbollayerutils.h"
73 #include "qgscurvepolygon.h"
74 #include "qgsmessagelog.h"
75 #include "qgsgeometrycollection.h"
76 #include "callouts/qgscallout.h"
78 #include "qgsvectortilelayer.h"
80 
81 using namespace pal;
82 
83 // -------------
84 
85 /* ND: Default point label position priority. These are set to match variants of the ideal placement priority described
86  in "Making Maps", Krygier & Wood (2011) (p216),
87  "Elements of Cartography", Robinson et al (1995)
88  and "Designing Better Maps", Brewer (2005) (p76)
89  Note that while they agree on positions 1-4, 5-8 are more contentious so I've selected these placements
90  based on my preferences, and to follow Krygier and Wood's placements more closer. (I'm not going to disagree
91  with Denis Wood on anything cartography related...!)
92 */
93 typedef QVector< Qgis::LabelPredefinedPointPosition > PredefinedPointPositionVector;
95 {
104 } ) )
105 //debugging only - don't use these placements by default
106 /* << QgsPalLayerSettings::TopSlightlyLeft
107 << QgsPalLayerSettings::BottomSlightlyLeft;
108 << QgsPalLayerSettings::TopMiddle
109 << QgsPalLayerSettings::BottomMiddle;*/
110 
111 Q_GLOBAL_STATIC( QgsPropertiesDefinition, sPropertyDefinitions )
112 
113 void QgsPalLayerSettings::initPropertyDefinitions()
114 {
115  if ( !sPropertyDefinitions()->isEmpty() )
116  return;
117 
118  const QString origin = QStringLiteral( "labeling" );
119 
120  *sPropertyDefinitions() = QgsPropertiesDefinition
121  {
122  { QgsPalLayerSettings::Size, QgsPropertyDefinition( "Size", QObject::tr( "Font size" ), QgsPropertyDefinition::DoublePositive, origin ) },
123  { QgsPalLayerSettings::Bold, QgsPropertyDefinition( "Bold", QObject::tr( "Bold style" ), QgsPropertyDefinition::Boolean, origin ) },
124  { QgsPalLayerSettings::Italic, QgsPropertyDefinition( "Italic", QObject::tr( "Italic style" ), QgsPropertyDefinition::Boolean, origin ) },
125  { QgsPalLayerSettings::Underline, QgsPropertyDefinition( "Underline", QObject::tr( "Draw underline" ), QgsPropertyDefinition::Boolean, origin ) },
126  { QgsPalLayerSettings::Color, QgsPropertyDefinition( "Color", QObject::tr( "Text color" ), QgsPropertyDefinition::ColorNoAlpha, origin ) },
127  { QgsPalLayerSettings::Strikeout, QgsPropertyDefinition( "Strikeout", QObject::tr( "Draw strikeout" ), QgsPropertyDefinition::Boolean, origin ) },
128  {
129  QgsPalLayerSettings::Family, QgsPropertyDefinition( "Family", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font family" ), QObject::tr( "string " ) + QObject::tr( "[<b>family</b>|<b>family[foundry]</b>],<br>"
130  "e.g. Helvetica or Helvetica [Cronyx]" ), origin )
131  },
132  {
133  QgsPalLayerSettings::FontStyle, QgsPropertyDefinition( "FontStyle", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font style" ), QObject::tr( "string " ) + QObject::tr( "[<b>font style name</b>|<b>Ignore</b>],<br>"
134  "e.g. Bold Condensed or Light Italic" ), origin )
135  },
136  { QgsPalLayerSettings::FontSizeUnit, QgsPropertyDefinition( "FontSizeUnit", QObject::tr( "Font size units" ), QgsPropertyDefinition::RenderUnits, origin ) },
137  { QgsPalLayerSettings::FontTransp, QgsPropertyDefinition( "FontTransp", QObject::tr( "Text transparency" ), QgsPropertyDefinition::Opacity, origin ) },
138  { QgsPalLayerSettings::FontOpacity, QgsPropertyDefinition( "FontOpacity", QObject::tr( "Text opacity" ), QgsPropertyDefinition::Opacity, origin ) },
139  { QgsPalLayerSettings::FontStretchFactor, QgsPropertyDefinition( "FontStretchFactor", QObject::tr( "Font stretch factor" ), QgsPropertyDefinition::IntegerPositiveGreaterZero, origin ) },
140  { QgsPalLayerSettings::FontCase, QgsPropertyDefinition( "FontCase", QgsPropertyDefinition::DataTypeString, QObject::tr( "Font case" ), QObject::tr( "string " ) + QStringLiteral( "[<b>NoChange</b>|<b>Upper</b>|<br><b>Lower</b>|<b>Title</b>|<b>Capitalize</b>|<b>SmallCaps</b>|<b>AllSmallCaps</b>]" ), origin ) },
141  { QgsPalLayerSettings::FontLetterSpacing, QgsPropertyDefinition( "FontLetterSpacing", QObject::tr( "Letter spacing" ), QgsPropertyDefinition::Double, origin ) },
142  { QgsPalLayerSettings::FontWordSpacing, QgsPropertyDefinition( "FontWordSpacing", QObject::tr( "Word spacing" ), QgsPropertyDefinition::Double, origin ) },
143  { QgsPalLayerSettings::FontBlendMode, QgsPropertyDefinition( "FontBlendMode", QObject::tr( "Text blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
144  { QgsPalLayerSettings::MultiLineWrapChar, QgsPropertyDefinition( "MultiLineWrapChar", QObject::tr( "Wrap character" ), QgsPropertyDefinition::String, origin ) },
145  { QgsPalLayerSettings::AutoWrapLength, QgsPropertyDefinition( "AutoWrapLength", QObject::tr( "Automatic word wrap line length" ), QgsPropertyDefinition::IntegerPositive, origin ) },
146  { QgsPalLayerSettings::MultiLineHeight, QgsPropertyDefinition( "MultiLineHeight", QObject::tr( "Line height" ), QgsPropertyDefinition::DoublePositive, origin ) },
147  { QgsPalLayerSettings::MultiLineAlignment, QgsPropertyDefinition( "MultiLineAlignment", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line alignment" ), QObject::tr( "string " ) + "[<b>Left</b>|<b>Center</b>|<b>Right</b>|<b>Follow</b>]", origin ) },
148  { QgsPalLayerSettings::TextOrientation, QgsPropertyDefinition( "TextOrientation", QgsPropertyDefinition::DataTypeString, QObject::tr( "Text orientation" ), QObject::tr( "string " ) + "[<b>horizontal</b>|<b>vertical</b>]", origin ) },
149  { QgsPalLayerSettings::DirSymbDraw, QgsPropertyDefinition( "DirSymbDraw", QObject::tr( "Draw direction symbol" ), QgsPropertyDefinition::Boolean, origin ) },
150  { QgsPalLayerSettings::DirSymbLeft, QgsPropertyDefinition( "DirSymbLeft", QObject::tr( "Left direction symbol" ), QgsPropertyDefinition::String, origin ) },
151  { QgsPalLayerSettings::DirSymbRight, QgsPropertyDefinition( "DirSymbRight", QObject::tr( "Right direction symbol" ), QgsPropertyDefinition::String, origin ) },
152  { QgsPalLayerSettings::DirSymbPlacement, QgsPropertyDefinition( "DirSymbPlacement", QgsPropertyDefinition::DataTypeString, QObject::tr( "Direction symbol placement" ), QObject::tr( "string " ) + "[<b>LeftRight</b>|<b>Above</b>|<b>Below</b>]", origin ) },
153  { QgsPalLayerSettings::DirSymbReverse, QgsPropertyDefinition( "DirSymbReverse", QObject::tr( "Reverse direction symbol" ), QgsPropertyDefinition::Boolean, origin ) },
154  { QgsPalLayerSettings::NumFormat, QgsPropertyDefinition( "NumFormat", QObject::tr( "Format as number" ), QgsPropertyDefinition::Boolean, origin ) },
155  { QgsPalLayerSettings::NumDecimals, QgsPropertyDefinition( "NumDecimals", QObject::tr( "Number of decimal places" ), QgsPropertyDefinition::IntegerPositive, origin ) },
156  { QgsPalLayerSettings::NumPlusSign, QgsPropertyDefinition( "NumPlusSign", QObject::tr( "Draw + sign" ), QgsPropertyDefinition::Boolean, origin ) },
157  { QgsPalLayerSettings::BufferDraw, QgsPropertyDefinition( "BufferDraw", QObject::tr( "Draw buffer" ), QgsPropertyDefinition::Boolean, origin ) },
158  { QgsPalLayerSettings::BufferSize, QgsPropertyDefinition( "BufferSize", QObject::tr( "Symbol size" ), QgsPropertyDefinition::DoublePositive, origin ) },
159  { QgsPalLayerSettings::BufferUnit, QgsPropertyDefinition( "BufferUnit", QObject::tr( "Buffer units" ), QgsPropertyDefinition::RenderUnits, origin ) },
160  { QgsPalLayerSettings::BufferColor, QgsPropertyDefinition( "BufferColor", QObject::tr( "Buffer color" ), QgsPropertyDefinition::ColorNoAlpha, origin ) },
161  { QgsPalLayerSettings::BufferTransp, QgsPropertyDefinition( "BufferTransp", QObject::tr( "Buffer transparency" ), QgsPropertyDefinition::Opacity, origin ) },
162  { QgsPalLayerSettings::BufferOpacity, QgsPropertyDefinition( "BufferOpacity", QObject::tr( "Buffer opacity" ), QgsPropertyDefinition::Opacity, origin ) },
163  { QgsPalLayerSettings::BufferJoinStyle, QgsPropertyDefinition( "BufferJoinStyle", QObject::tr( "Buffer join style" ), QgsPropertyDefinition::PenJoinStyle, origin ) },
164  { QgsPalLayerSettings::BufferBlendMode, QgsPropertyDefinition( "BufferBlendMode", QObject::tr( "Buffer blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
165 
166  { QgsPalLayerSettings::MaskEnabled, QgsPropertyDefinition( "MaskEnabled", QObject::tr( "Enable mask" ), QgsPropertyDefinition::Boolean, origin ) },
167  { QgsPalLayerSettings::MaskBufferSize, QgsPropertyDefinition( "MaskBufferSize", QObject::tr( "Mask buffer size" ), QgsPropertyDefinition::DoublePositive, origin ) },
168  { QgsPalLayerSettings::MaskBufferUnit, QgsPropertyDefinition( "MaskBufferUnit", QObject::tr( "Mask buffer unit" ), QgsPropertyDefinition::RenderUnits, origin ) },
169  { QgsPalLayerSettings::MaskOpacity, QgsPropertyDefinition( "MaskOpacity", QObject::tr( "Mask opacity" ), QgsPropertyDefinition::Opacity, origin ) },
170  { QgsPalLayerSettings::MaskJoinStyle, QgsPropertyDefinition( "MaskJoinStyle", QObject::tr( "Mask join style" ), QgsPropertyDefinition::PenJoinStyle, origin ) },
171 
172  { QgsPalLayerSettings::ShapeDraw, QgsPropertyDefinition( "ShapeDraw", QObject::tr( "Draw shape" ), QgsPropertyDefinition::Boolean, origin ) },
173  {
174  QgsPalLayerSettings::ShapeKind, QgsPropertyDefinition( "ShapeKind", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape type" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Rectangle</b>|<b>Square</b>|<br>"
175  "<b>Ellipse</b>|<b>Circle</b>|<b>SVG</b>]" ), origin )
176  },
177  { QgsPalLayerSettings::ShapeSVGFile, QgsPropertyDefinition( "ShapeSVGFile", QObject::tr( "Shape SVG path" ), QgsPropertyDefinition::SvgPath, origin ) },
178  { QgsPalLayerSettings::ShapeSizeType, QgsPropertyDefinition( "ShapeSizeType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape size type" ), QObject::tr( "string " ) + "[<b>Buffer</b>|<b>Fixed</b>]", origin ) },
179  { QgsPalLayerSettings::ShapeSizeX, QgsPropertyDefinition( "ShapeSizeX", QObject::tr( "Shape size (X)" ), QgsPropertyDefinition::Double, origin ) },
180  { QgsPalLayerSettings::ShapeSizeY, QgsPropertyDefinition( "ShapeSizeY", QObject::tr( "Shape size (Y)" ), QgsPropertyDefinition::Double, origin ) },
181  { QgsPalLayerSettings::ShapeSizeUnits, QgsPropertyDefinition( "ShapeSizeUnits", QObject::tr( "Shape size units" ), QgsPropertyDefinition::RenderUnits, origin ) },
182  { QgsPalLayerSettings::ShapeRotationType, QgsPropertyDefinition( "ShapeRotationType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Shape rotation type" ), QObject::tr( "string " ) + "[<b>Sync</b>|<b>Offset</b>|<b>Fixed</b>]", origin ) },
183  { QgsPalLayerSettings::ShapeRotation, QgsPropertyDefinition( "ShapeRotation", QObject::tr( "Shape rotation" ), QgsPropertyDefinition::Rotation, origin ) },
184  { QgsPalLayerSettings::ShapeOffset, QgsPropertyDefinition( "ShapeOffset", QObject::tr( "Shape offset" ), QgsPropertyDefinition::Offset, origin ) },
185  { QgsPalLayerSettings::ShapeOffsetUnits, QgsPropertyDefinition( "ShapeOffsetUnits", QObject::tr( "Shape offset units" ), QgsPropertyDefinition::RenderUnits, origin ) },
186  { QgsPalLayerSettings::ShapeRadii, QgsPropertyDefinition( "ShapeRadii", QObject::tr( "Shape radii" ), QgsPropertyDefinition::Size2D, origin ) },
187  { QgsPalLayerSettings::ShapeRadiiUnits, QgsPropertyDefinition( "ShapeRadiiUnits", QObject::tr( "Symbol radii units" ), QgsPropertyDefinition::RenderUnits, origin ) },
188  { QgsPalLayerSettings::ShapeTransparency, QgsPropertyDefinition( "ShapeTransparency", QObject::tr( "Shape transparency" ), QgsPropertyDefinition::Opacity, origin ) },
189  { QgsPalLayerSettings::ShapeOpacity, QgsPropertyDefinition( "ShapeOpacity", QObject::tr( "Shape opacity" ), QgsPropertyDefinition::Opacity, origin ) },
190  { QgsPalLayerSettings::ShapeBlendMode, QgsPropertyDefinition( "ShapeBlendMode", QObject::tr( "Shape blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
191  { QgsPalLayerSettings::ShapeFillColor, QgsPropertyDefinition( "ShapeFillColor", QObject::tr( "Shape fill color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
192  { QgsPalLayerSettings::ShapeStrokeColor, QgsPropertyDefinition( "ShapeBorderColor", QObject::tr( "Shape stroke color" ), QgsPropertyDefinition::ColorWithAlpha, origin ) },
193  { QgsPalLayerSettings::ShapeStrokeWidth, QgsPropertyDefinition( "ShapeBorderWidth", QObject::tr( "Shape stroke width" ), QgsPropertyDefinition::StrokeWidth, origin ) },
194  { QgsPalLayerSettings::ShapeStrokeWidthUnits, QgsPropertyDefinition( "ShapeBorderWidthUnits", QObject::tr( "Shape stroke width units" ), QgsPropertyDefinition::RenderUnits, origin ) },
195  { QgsPalLayerSettings::ShapeJoinStyle, QgsPropertyDefinition( "ShapeJoinStyle", QObject::tr( "Shape join style" ), QgsPropertyDefinition::PenJoinStyle, origin ) },
196  { QgsPalLayerSettings::ShadowDraw, QgsPropertyDefinition( "ShadowDraw", QObject::tr( "Draw shadow" ), QgsPropertyDefinition::Boolean, origin ) },
197  {
198  QgsPalLayerSettings::ShadowUnder, QgsPropertyDefinition( "ShadowUnder", QgsPropertyDefinition::DataTypeString, QObject::tr( "Symbol size" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Lowest</b>|<b>Text</b>|<br>"
199  "<b>Buffer</b>|<b>Background</b>]" ), origin )
200  },
201  { QgsPalLayerSettings::ShadowOffsetAngle, QgsPropertyDefinition( "ShadowOffsetAngle", QObject::tr( "Shadow offset angle" ), QgsPropertyDefinition::Rotation, origin ) },
202  { QgsPalLayerSettings::ShadowOffsetDist, QgsPropertyDefinition( "ShadowOffsetDist", QObject::tr( "Shadow offset distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
203  { QgsPalLayerSettings::ShadowOffsetUnits, QgsPropertyDefinition( "ShadowOffsetUnits", QObject::tr( "Shadow offset units" ), QgsPropertyDefinition::RenderUnits, origin ) },
204  { QgsPalLayerSettings::ShadowRadius, QgsPropertyDefinition( "ShadowRadius", QObject::tr( "Shadow blur radius" ), QgsPropertyDefinition::DoublePositive, origin ) },
205  { QgsPalLayerSettings::ShadowRadiusUnits, QgsPropertyDefinition( "ShadowRadiusUnits", QObject::tr( "Shadow blur units" ), QgsPropertyDefinition::RenderUnits, origin ) },
206  { QgsPalLayerSettings::ShadowTransparency, QgsPropertyDefinition( "ShadowTransparency", QObject::tr( "Shadow transparency" ), QgsPropertyDefinition::Opacity, origin ) },
207  { QgsPalLayerSettings::ShadowOpacity, QgsPropertyDefinition( "ShadowOpacity", QObject::tr( "Shadow opacity" ), QgsPropertyDefinition::Opacity, origin ) },
208  { QgsPalLayerSettings::ShadowScale, QgsPropertyDefinition( "ShadowScale", QObject::tr( "Shadow scale" ), QgsPropertyDefinition::IntegerPositive, origin ) },
209  { QgsPalLayerSettings::ShadowColor, QgsPropertyDefinition( "ShadowColor", QObject::tr( "Shadow color" ), QgsPropertyDefinition::ColorNoAlpha, origin ) },
210  { QgsPalLayerSettings::ShadowBlendMode, QgsPropertyDefinition( "ShadowBlendMode", QObject::tr( "Shadow blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
211 
212  { QgsPalLayerSettings::CentroidWhole, QgsPropertyDefinition( "CentroidWhole", QgsPropertyDefinition::DataTypeString, QObject::tr( "Centroid of whole shape" ), QObject::tr( "string " ) + "[<b>Visible</b>|<b>Whole</b>]", origin ) },
213  {
214  QgsPalLayerSettings::OffsetQuad, QgsPropertyDefinition( "OffsetQuad", QgsPropertyDefinition::DataTypeString, QObject::tr( "Offset quadrant" ), QObject::tr( "int<br>" ) + QStringLiteral( "[<b>0</b>=Above Left|<b>1</b>=Above|<b>2</b>=Above Right|<br>"
215  "<b>3</b>=Left|<b>4</b>=Over|<b>5</b>=Right|<br>"
216  "<b>6</b>=Below Left|<b>7</b>=Below|<b>8</b>=Below Right]" ), origin )
217  },
218  { QgsPalLayerSettings::OffsetXY, QgsPropertyDefinition( "OffsetXY", QObject::tr( "Offset" ), QgsPropertyDefinition::Offset, origin ) },
219  { QgsPalLayerSettings::OffsetUnits, QgsPropertyDefinition( "OffsetUnits", QObject::tr( "Offset units" ), QgsPropertyDefinition::RenderUnits, origin ) },
220  { QgsPalLayerSettings::LabelDistance, QgsPropertyDefinition( "LabelDistance", QObject::tr( "Label distance" ), QgsPropertyDefinition::Double, origin ) },
221  { QgsPalLayerSettings::DistanceUnits, QgsPropertyDefinition( "DistanceUnits", QObject::tr( "Label distance units" ), QgsPropertyDefinition::RenderUnits, origin ) },
222  { QgsPalLayerSettings::OffsetRotation, QgsPropertyDefinition( "OffsetRotation", QObject::tr( "Offset rotation" ), QgsPropertyDefinition::Rotation, origin ) },
223  { QgsPalLayerSettings::CurvedCharAngleInOut, QgsPropertyDefinition( "CurvedCharAngleInOut", QgsPropertyDefinition::DataTypeString, QObject::tr( "Curved character angles" ), QObject::tr( "double coord [<b>in,out</b> as 20.0-60.0,20.0-95.0]" ), origin ) },
224  { QgsPalLayerSettings::RepeatDistance, QgsPropertyDefinition( "RepeatDistance", QObject::tr( "Repeat distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
225  { QgsPalLayerSettings::RepeatDistanceUnit, QgsPropertyDefinition( "RepeatDistanceUnit", QObject::tr( "Repeat distance unit" ), QgsPropertyDefinition::RenderUnits, origin ) },
226  { QgsPalLayerSettings::OverrunDistance, QgsPropertyDefinition( "OverrunDistance", QObject::tr( "Overrun distance" ), QgsPropertyDefinition::DoublePositive, origin ) },
227  { QgsPalLayerSettings::LineAnchorPercent, QgsPropertyDefinition( "LineAnchorPercent", QObject::tr( "Line anchor percentage, as fraction from 0.0 to 1.0" ), QgsPropertyDefinition::Double0To1, origin ) },
228  { QgsPalLayerSettings::LineAnchorClipping, QgsPropertyDefinition( "LineAnchorClipping", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor clipping mode" ), QObject::tr( "string " ) + QStringLiteral( "[<b>visible</b>|<b>entire</b>]" ), origin ) },
229  { QgsPalLayerSettings::LineAnchorType, QgsPropertyDefinition( "LineAnchorType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor type" ), QObject::tr( "string " ) + QStringLiteral( "[<b>hint</b>|<b>strict</b>]" ), origin ) },
230  { QgsPalLayerSettings::LineAnchorTextPoint, QgsPropertyDefinition( "LineAnchorTextPoint", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line anchor text point" ), QObject::tr( "string " ) + QStringLiteral( "[<b>follow</b>|<b>start</b>|<b>center</b>|<b>end</b>]" ), origin ) },
231  { QgsPalLayerSettings::Priority, QgsPropertyDefinition( "Priority", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Label priority" ), QObject::tr( "double [0.0-10.0]" ), origin ) },
232  { QgsPalLayerSettings::IsObstacle, QgsPropertyDefinition( "IsObstacle", QObject::tr( "Feature is a label obstacle" ), QgsPropertyDefinition::Boolean, origin ) },
233  { QgsPalLayerSettings::ObstacleFactor, QgsPropertyDefinition( "ObstacleFactor", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Obstacle factor" ), QObject::tr( "double [0.0-10.0]" ), origin ) },
234  {
235  QgsPalLayerSettings::PredefinedPositionOrder, QgsPropertyDefinition( "PredefinedPositionOrder", QgsPropertyDefinition::DataTypeString, QObject::tr( "Predefined position order" ), QObject::tr( "Comma separated list of placements in order of priority<br>" )
236  + QStringLiteral( "[<b>TL</b>=Top left|<b>TSL</b>=Top, slightly left|<b>T</b>=Top middle|<br>"
237  "<b>TSR</b>=Top, slightly right|<b>TR</b>=Top right|<br>"
238  "<b>L</b>=Left|<b>R</b>=Right|<br>"
239  "<b>BL</b>=Bottom left|<b>BSL</b>=Bottom, slightly left|<b>B</b>=Bottom middle|<br>"
240  "<b>BSR</b>=Bottom, slightly right|<b>BR</b>=Bottom right]" ), origin )
241  },
242  {
243  QgsPalLayerSettings::LinePlacementOptions, QgsPropertyDefinition( "LinePlacementFlags", QgsPropertyDefinition::DataTypeString, QObject::tr( "Line placement options" ), QObject::tr( "Comma separated list of placement options<br>" )
244  + QStringLiteral( "[<b>OL</b>=On line|<b>AL</b>=Above line|<b>BL</b>=Below line|<br>"
245  "<b>LO</b>=Respect line orientation]" ), origin )
246  },
247  { QgsPalLayerSettings::PolygonLabelOutside, QgsPropertyDefinition( "PolygonLabelOutside", QgsPropertyDefinition::DataTypeString, QObject::tr( "Label outside polygons" ), QObject::tr( "string " ) + "[<b>yes</b> (allow placing outside)|<b>no</b> (never place outside)|<b>force</b> (always place outside)]", origin ) },
248  { QgsPalLayerSettings::PositionX, QgsPropertyDefinition( "PositionX", QObject::tr( "Position (X)" ), QgsPropertyDefinition::Double, origin ) },
249  { QgsPalLayerSettings::PositionY, QgsPropertyDefinition( "PositionY", QObject::tr( "Position (Y)" ), QgsPropertyDefinition::Double, origin ) },
250  { QgsPalLayerSettings::PositionPoint, QgsPropertyDefinition( "PositionPoint", QgsPropertyDefinition::DataTypeString, QObject::tr( "Position (point)" ), QObject::tr( "A point geometry" ), origin ) },
251  { QgsPalLayerSettings::Hali, QgsPropertyDefinition( "Hali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Horizontal alignment" ), QObject::tr( "string " ) + "[<b>Left</b>|<b>Center</b>|<b>Right</b>]", origin ) },
252  {
253  QgsPalLayerSettings::Vali, QgsPropertyDefinition( "Vali", QgsPropertyDefinition::DataTypeString, QObject::tr( "Vertical alignment" ), QObject::tr( "string " ) + QStringLiteral( "[<b>Bottom</b>|<b>Base</b>|<br>"
254  "<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ), origin )
255  },
256  { QgsPalLayerSettings::Rotation, QgsPropertyDefinition( "Rotation", QObject::tr( "Label rotation (deprecated)" ), QgsPropertyDefinition::Rotation, origin ) },
257  { QgsPalLayerSettings::LabelRotation, QgsPropertyDefinition( "LabelRotation", QObject::tr( "Label rotation" ), QgsPropertyDefinition::Rotation, origin ) },
258  { QgsPalLayerSettings::ScaleVisibility, QgsPropertyDefinition( "ScaleVisibility", QObject::tr( "Scale based visibility" ), QgsPropertyDefinition::Boolean, origin ) },
259  { QgsPalLayerSettings::MinScale, QgsPropertyDefinition( "MinScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
260  { QgsPalLayerSettings::MaxScale, QgsPropertyDefinition( "MaxScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
261  { QgsPalLayerSettings::MinimumScale, QgsPropertyDefinition( "MinimumScale", QObject::tr( "Minimum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
262  { QgsPalLayerSettings::MaximumScale, QgsPropertyDefinition( "MaximumScale", QObject::tr( "Maximum scale (denominator)" ), QgsPropertyDefinition::Double, origin ) },
263 
264  { QgsPalLayerSettings::FontLimitPixel, QgsPropertyDefinition( "FontLimitPixel", QObject::tr( "Limit font pixel size" ), QgsPropertyDefinition::Boolean, origin ) },
265  { QgsPalLayerSettings::FontMinPixel, QgsPropertyDefinition( "FontMinPixel", QObject::tr( "Minimum pixel size" ), QgsPropertyDefinition::IntegerPositive, origin ) },
266  { QgsPalLayerSettings::FontMaxPixel, QgsPropertyDefinition( "FontMaxPixel", QObject::tr( "Maximum pixel size" ), QgsPropertyDefinition::IntegerPositive, origin ) },
267  { QgsPalLayerSettings::ZIndex, QgsPropertyDefinition( "ZIndex", QObject::tr( "Label z-index" ), QgsPropertyDefinition::Double, origin ) },
268  { QgsPalLayerSettings::Show, QgsPropertyDefinition( "Show", QObject::tr( "Show label" ), QgsPropertyDefinition::Boolean, origin ) },
269  { QgsPalLayerSettings::AlwaysShow, QgsPropertyDefinition( "AlwaysShow", QObject::tr( "Always show label" ), QgsPropertyDefinition::Boolean, origin ) },
270  { QgsPalLayerSettings::CalloutDraw, QgsPropertyDefinition( "CalloutDraw", QObject::tr( "Draw callout" ), QgsPropertyDefinition::Boolean, origin ) },
271  { QgsPalLayerSettings::LabelAllParts, QgsPropertyDefinition( "LabelAllParts", QObject::tr( "Label all parts" ), QgsPropertyDefinition::Boolean, origin ) },
272  { QgsPalLayerSettings::AllowDegradedPlacement, QgsPropertyDefinition( "AllowDegradedPlacement", QObject::tr( "Allow inferior fallback placements" ), QgsPropertyDefinition::Boolean, origin ) },
273  { QgsPalLayerSettings::OverlapHandling, QgsPropertyDefinition( "OverlapHandling", QgsPropertyDefinition::DataTypeString, QObject::tr( "Overlap handing" ), QObject::tr( "string " ) + "[<b>Prevent</b>|<b>AllowIfNeeded</b>|<b>AlwaysAllow</b>]", origin ) },
274  };
275 }
276 
277 Q_NOWARN_DEPRECATED_PUSH // because of deprecated members
279  : predefinedPositionOrder( *DEFAULT_PLACEMENT_ORDER() )
280  , mCallout( QgsCalloutRegistry::defaultCallout() )
281 {
282  initPropertyDefinitions();
283 
285 }
287 
288 Q_NOWARN_DEPRECATED_PUSH // because of deprecated members
290  : fieldIndex( 0 )
291  , mDataDefinedProperties( s.mDataDefinedProperties )
292 {
293  *this = s;
294 }
296 
298 {
299  if ( this == &s )
300  return *this;
301 
302  // copy only permanent stuff
303 
305 
306  // text style
307  fieldName = s.fieldName;
314 
315  // text formatting
316  wrapChar = s.wrapChar;
321  decimals = s.decimals;
322  plusSign = s.plusSign;
323 
324  // placement
325  placement = s.placement;
326  mPolygonPlacementFlags = s.mPolygonPlacementFlags;
332  xOffset = s.xOffset;
333  yOffset = s.yOffset;
336  dist = s.dist;
338  distUnits = s.distUnits;
342  mRotationUnit = s.mRotationUnit;
345  priority = s.priority;
349 
350  // rendering
358 
360  zIndex = s.zIndex;
361 
362  mFormat = s.mFormat;
363  mDataDefinedProperties = s.mDataDefinedProperties;
364 
365  mCallout.reset( s.mCallout ? s.mCallout->clone() : nullptr );
366 
367  mPlacementSettings = s.mPlacementSettings;
368  mLineSettings = s.mLineSettings;
369  mObstacleSettings = s.mObstacleSettings;
370  mThinningSettings = s.mThinningSettings;
371 
375  layerType = s.layerType;
376 
377  mLegendString = s.mLegendString;
378 
379  mUnplacedVisibility = s.mUnplacedVisibility;
380 
381  return *this;
382 }
383 
384 bool QgsPalLayerSettings::prepare( QgsRenderContext &context, QSet<QString> &attributeNames, const QgsFields &fields, const QgsMapSettings &mapSettings, const QgsCoordinateReferenceSystem &crs )
385 {
386  if ( drawLabels )
387  {
388  if ( fieldName.isEmpty() )
389  {
390  return false;
391  }
392 
393  if ( isExpression )
394  {
395  QgsExpression exp( fieldName );
396  if ( exp.hasEvalError() )
397  {
398  QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
399  return false;
400  }
401  }
402  else
403  {
404  // If we aren't an expression, we check to see if we can find the column.
405  if ( fields.lookupField( fieldName ) == -1 )
406  {
407  return false;
408  }
409  }
410  }
411 
412  mCurFields = fields;
413 
414  if ( drawLabels || mObstacleSettings.isObstacle() )
415  {
416  if ( drawLabels )
417  {
418  // add field indices for label's text, from expression or field
419  if ( isExpression )
420  {
421  // prepare expression for use in QgsPalLayerSettings::registerFeature()
423  exp->prepare( &context.expressionContext() );
424  if ( exp->hasEvalError() )
425  {
426  QgsDebugMsgLevel( "Prepare error:" + exp->evalErrorString(), 4 );
427  }
428  const auto referencedColumns = exp->referencedColumns();
429  for ( const QString &name : referencedColumns )
430  {
431  attributeNames.insert( name );
432  }
433  }
434  else
435  {
436  attributeNames.insert( fieldName );
437  }
438  }
439 
440  mDataDefinedProperties.prepare( context.expressionContext() );
441  // add field indices of data defined expression or field
442  attributeNames.unite( dataDefinedProperties().referencedFields( context.expressionContext() ) );
443  }
444 
445  // NOW INITIALIZE QgsPalLayerSettings
446 
447  // TODO: ideally these (non-configuration) members should get out of QgsPalLayerSettings to QgsVectorLayerLabelProvider::prepare
448  // (together with registerFeature() & related methods) and QgsPalLayerSettings just stores config
449 
450  // save the pal layer to our layer context (with some additional info)
451  fieldIndex = fields.lookupField( fieldName );
452 
453  xform = &mapSettings.mapToPixel();
455  if ( context.coordinateTransform().isValid() )
456  // this is context for layer rendering
457  ct = context.coordinateTransform();
458  else
459  {
460  // otherwise fall back to creating our own CT
461  ct = QgsCoordinateTransform( crs, mapSettings.destinationCrs(), mapSettings.transformContext() );
462  }
463  ptZero = xform->toMapCoordinates( 0, 0 );
464  ptOne = xform->toMapCoordinates( 1, 0 );
465 
466  // rect for clipping
467  QgsRectangle r1 = mapSettings.visibleExtent();
468  r1.grow( mapSettings.extentBuffer() );
470 
471  if ( !qgsDoubleNear( mapSettings.rotation(), 0.0 ) )
472  {
473  //PAL features are prerotated, so extent also needs to be unrotated
474  extentGeom.rotate( -mapSettings.rotation(), mapSettings.visibleExtent().center() );
475  }
476 
477  mFeatsSendingToPal = 0;
478 
480  {
481  mGeometryGeneratorExpression = QgsExpression( geometryGenerator );
482  mGeometryGeneratorExpression.prepare( &context.expressionContext() );
483  if ( mGeometryGeneratorExpression.hasParserError() )
484  {
485  QgsMessageLog::logMessage( mGeometryGeneratorExpression.parserErrorString(), QObject::tr( "Labeling" ) );
486  return false;
487  }
488 
489  const auto referencedColumns = mGeometryGeneratorExpression.referencedColumns();
490  for ( const QString &name : referencedColumns )
491  {
492  attributeNames.insert( name );
493  }
494  }
495  attributeNames.unite( mFormat.referencedFields( context ) );
496 
497  if ( mCallout )
498  {
499  const auto referencedColumns = mCallout->referencedFields( context );
500  for ( const QString &name : referencedColumns )
501  {
502  attributeNames.insert( name );
503  }
504  }
505 
506  return true;
507 }
508 
509 QSet<QString> QgsPalLayerSettings::referencedFields( const QgsRenderContext &context ) const
510 {
511  QSet<QString> referenced;
512  if ( drawLabels )
513  {
514  if ( isExpression )
515  {
516  referenced.unite( QgsExpression( fieldName ).referencedColumns() );
517  }
518  else
519  {
520  referenced.insert( fieldName );
521  }
522  }
523 
524  referenced.unite( mFormat.referencedFields( context ) );
525 
526  // calling referencedFields() with ignoreContext=true because in our expression context
527  // we do not have valid QgsFields yet - because of that the field names from expressions
528  // wouldn't get reported
529  referenced.unite( mDataDefinedProperties.referencedFields( context.expressionContext(), true ) );
530 
532  {
533  QgsExpression geomGeneratorExpr( geometryGenerator );
534  referenced.unite( geomGeneratorExpr.referencedColumns() );
535  }
536 
537  if ( mCallout )
538  {
539  referenced.unite( mCallout->referencedFields( context ) );
540  }
541 
542  return referenced;
543 }
544 
546 {
547  if ( mRenderStarted )
548  {
549  qWarning( "Start render called for when a previous render was already underway!!" );
550  return;
551  }
552 
554  {
555  // force horizontal orientation, other orientation modes aren't unsupported for curved placement
557  mDataDefinedProperties.property( QgsPalLayerSettings::TextOrientation ).setActive( false );
558  }
559 
560  if ( mCallout )
561  {
562  mCallout->startRender( context );
563  }
564 
565  mRenderStarted = true;
566 }
567 
569 {
570  if ( !mRenderStarted )
571  {
572  qWarning( "Stop render called for QgsPalLayerSettings without a startRender call!" );
573  return;
574  }
575 
576  if ( mCallout )
577  {
578  mCallout->stopRender( context );
579  }
580 
581  mRenderStarted = false;
582 }
583 
585 {
586  return mFormat.containsAdvancedEffects() || mCallout->containsAdvancedEffects();
587 }
588 
590 {
591  if ( mRenderStarted )
592  {
593  qWarning( "stopRender was not called on QgsPalLayerSettings object!" );
594  }
595 
596  // pal layer is deleted internally in PAL
597 
598  delete expression;
599 }
600 
601 
603 {
604  initPropertyDefinitions();
605  return *sPropertyDefinitions();
606 }
607 
609 {
610  if ( !expression )
611  {
612  expression = new QgsExpression( fieldName );
613  }
614  return expression;
615 }
616 
618 {
619  return mRotationUnit;
620 }
621 
623 {
624  mRotationUnit = angleUnit;
625 }
626 
627 QString updateDataDefinedString( const QString &value )
628 {
629  // TODO: update or remove this when project settings for labeling are migrated to better XML layout
630  QString newValue = value;
631  if ( !value.isEmpty() && !value.contains( QLatin1String( "~~" ) ) )
632  {
633  QStringList values;
634  values << QStringLiteral( "1" ); // all old-style values are active if not empty
635  values << QStringLiteral( "0" );
636  values << QString();
637  values << value; // all old-style values are only field names
638  newValue = values.join( QLatin1String( "~~" ) );
639  }
640 
641  return newValue;
642 }
643 
644 void QgsPalLayerSettings::readOldDataDefinedProperty( QgsVectorLayer *layer, QgsPalLayerSettings::Property p )
645 {
646  QString newPropertyName = "labeling/dataDefined/" + sPropertyDefinitions()->value( p ).name();
647  QVariant newPropertyField = layer->customProperty( newPropertyName, QVariant() );
648 
649  if ( !newPropertyField.isValid() )
650  return;
651 
652  QString ddString = newPropertyField.toString();
653 
654  if ( !ddString.isEmpty() && ddString != QLatin1String( "0~~0~~~~" ) )
655  {
656  // TODO: update this when project settings for labeling are migrated to better XML layout
657  QString newStyleString = updateDataDefinedString( ddString );
658  QStringList ddv = newStyleString.split( QStringLiteral( "~~" ) );
659 
660  bool active = ddv.at( 0 ).toInt();
661  if ( ddv.at( 1 ).toInt() )
662  {
663  mDataDefinedProperties.setProperty( p, QgsProperty::fromExpression( ddv.at( 2 ), active ) );
664  }
665  else
666  {
667  mDataDefinedProperties.setProperty( p, QgsProperty::fromField( ddv.at( 3 ), active ) );
668  }
669  }
670  else
671  {
672  // remove unused properties
673  layer->removeCustomProperty( newPropertyName );
674  }
675 }
676 
677 void QgsPalLayerSettings::readOldDataDefinedPropertyMap( QgsVectorLayer *layer, QDomElement *parentElem )
678 {
679  if ( !layer && !parentElem )
680  {
681  return;
682  }
683 
684  QgsPropertiesDefinition::const_iterator i = sPropertyDefinitions()->constBegin();
685  for ( ; i != sPropertyDefinitions()->constEnd(); ++i )
686  {
687  if ( layer )
688  {
689  // reading from layer's custom properties
690  readOldDataDefinedProperty( layer, static_cast< Property >( i.key() ) );
691  }
692  else if ( parentElem )
693  {
694  // reading from XML
695  QDomElement e = parentElem->firstChildElement( i.value().name() );
696  if ( !e.isNull() )
697  {
698  bool active = e.attribute( QStringLiteral( "active" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
699  bool isExpression = e.attribute( QStringLiteral( "useExpr" ) ).compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
700  if ( isExpression )
701  {
702  mDataDefinedProperties.setProperty( i.key(), QgsProperty::fromExpression( e.attribute( QStringLiteral( "expr" ) ), active ) );
703  }
704  else
705  {
706  mDataDefinedProperties.setProperty( i.key(), QgsProperty::fromField( e.attribute( QStringLiteral( "field" ) ), active ) );
707  }
708  }
709  }
710  }
711 }
712 
713 void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
714 {
715  if ( layer->customProperty( QStringLiteral( "labeling" ) ).toString() != QLatin1String( "pal" ) )
716  {
717  if ( layer->geometryType() == QgsWkbTypes::PointGeometry )
719 
720  // for polygons the "over point" (over centroid) placement is better than the default
721  // "around point" (around centroid) which is more suitable for points
722  if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
724 
725  return; // there's no information available
726  }
727 
728  // NOTE: set defaults for newly added properties, for backwards compatibility
729 
730  drawLabels = layer->customProperty( QStringLiteral( "labeling/drawLabels" ), true ).toBool();
731 
732  mFormat.readFromLayer( layer );
733 
734  // text style
735  fieldName = layer->customProperty( QStringLiteral( "labeling/fieldName" ) ).toString();
736  isExpression = layer->customProperty( QStringLiteral( "labeling/isExpression" ) ).toBool();
738  previewBkgrdColor = QColor( layer->customProperty( QStringLiteral( "labeling/previewBkgrdColor" ), QVariant( "#ffffff" ) ).toString() );
740  QDomDocument doc( QStringLiteral( "substitutions" ) );
741  doc.setContent( layer->customProperty( QStringLiteral( "labeling/substitutions" ) ).toString() );
742  QDomElement replacementElem = doc.firstChildElement( QStringLiteral( "substitutions" ) );
743  substitutions.readXml( replacementElem );
744  useSubstitutions = layer->customProperty( QStringLiteral( "labeling/useSubstitutions" ) ).toBool();
745 
746  // text formatting
747  wrapChar = layer->customProperty( QStringLiteral( "labeling/wrapChar" ) ).toString();
748  autoWrapLength = layer->customProperty( QStringLiteral( "labeling/autoWrapLength" ) ).toInt();
749  useMaxLineLengthForAutoWrap = layer->customProperty( QStringLiteral( "labeling/useMaxLineLengthForAutoWrap" ), QStringLiteral( "1" ) ).toBool();
750 
751  multilineAlign = static_cast< Qgis::LabelMultiLineAlignment >( layer->customProperty( QStringLiteral( "labeling/multilineAlign" ), QVariant( static_cast< int >( Qgis::LabelMultiLineAlignment::FollowPlacement ) ) ).toUInt() );
752  mLineSettings.setAddDirectionSymbol( layer->customProperty( QStringLiteral( "labeling/addDirectionSymbol" ) ).toBool() );
753  mLineSettings.setLeftDirectionSymbol( layer->customProperty( QStringLiteral( "labeling/leftDirectionSymbol" ), QVariant( "<" ) ).toString() );
754  mLineSettings.setRightDirectionSymbol( layer->customProperty( QStringLiteral( "labeling/rightDirectionSymbol" ), QVariant( ">" ) ).toString() );
755  mLineSettings.setReverseDirectionSymbol( layer->customProperty( QStringLiteral( "labeling/reverseDirectionSymbol" ) ).toBool() );
756  mLineSettings.setDirectionSymbolPlacement( static_cast< QgsLabelLineSettings::DirectionSymbolPlacement >( layer->customProperty( QStringLiteral( "labeling/placeDirectionSymbol" ), QVariant( static_cast< int >( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolLeftRight ) ) ).toUInt() ) );
757  formatNumbers = layer->customProperty( QStringLiteral( "labeling/formatNumbers" ) ).toBool();
758  decimals = layer->customProperty( QStringLiteral( "labeling/decimals" ) ).toInt();
759  plusSign = layer->customProperty( QStringLiteral( "labeling/plussign" ) ).toBool();
760 
761  // placement
762  placement = static_cast< Qgis::LabelPlacement >( layer->customProperty( QStringLiteral( "labeling/placement" ) ).toInt() );
763  mLineSettings.setPlacementFlags( static_cast< QgsLabeling::LinePlacementFlags >( layer->customProperty( QStringLiteral( "labeling/placementFlags" ) ).toUInt() ) );
764  centroidWhole = layer->customProperty( QStringLiteral( "labeling/centroidWhole" ), QVariant( false ) ).toBool();
765  centroidInside = layer->customProperty( QStringLiteral( "labeling/centroidInside" ), QVariant( false ) ).toBool();
766  predefinedPositionOrder = QgsLabelingUtils::decodePredefinedPositionOrder( layer->customProperty( QStringLiteral( "labeling/predefinedPositionOrder" ) ).toString() );
767  if ( predefinedPositionOrder.isEmpty() )
768  predefinedPositionOrder = *DEFAULT_PLACEMENT_ORDER();
769  fitInPolygonOnly = layer->customProperty( QStringLiteral( "labeling/fitInPolygonOnly" ), QVariant( false ) ).toBool();
770  dist = layer->customProperty( QStringLiteral( "labeling/dist" ) ).toDouble();
771  distUnits = layer->customProperty( QStringLiteral( "labeling/distInMapUnits" ) ).toBool() ? QgsUnitTypes::RenderMapUnits : QgsUnitTypes::RenderMillimeters;
772  if ( layer->customProperty( QStringLiteral( "labeling/distMapUnitScale" ) ).toString().isEmpty() )
773  {
774  //fallback to older property
775  double oldMin = layer->customProperty( QStringLiteral( "labeling/distMapUnitMinScale" ), 0.0 ).toDouble();
776  distMapUnitScale.minScale = !qgsDoubleNear( oldMin, 0.0 ) ? 1.0 / oldMin : 0;
777  double oldMax = layer->customProperty( QStringLiteral( "labeling/distMapUnitMaxScale" ), 0.0 ).toDouble();
778  distMapUnitScale.maxScale = !qgsDoubleNear( oldMax, 0.0 ) ? 1.0 / oldMax : 0;
779  }
780  else
781  {
782  distMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/distMapUnitScale" ) ).toString() );
783  }
784  offsetType = static_cast< Qgis::LabelOffsetType >( layer->customProperty( QStringLiteral( "labeling/offsetType" ), QVariant( static_cast< int >( Qgis::LabelOffsetType::FromPoint ) ) ).toUInt() );
785  quadOffset = static_cast< Qgis::LabelQuadrantPosition >( layer->customProperty( QStringLiteral( "labeling/quadOffset" ), QVariant( static_cast< int >( Qgis::LabelQuadrantPosition::Over ) ) ).toUInt() );
786  xOffset = layer->customProperty( QStringLiteral( "labeling/xOffset" ), QVariant( 0.0 ) ).toDouble();
787  yOffset = layer->customProperty( QStringLiteral( "labeling/yOffset" ), QVariant( 0.0 ) ).toDouble();
788  if ( layer->customProperty( QStringLiteral( "labeling/labelOffsetInMapUnits" ), QVariant( true ) ).toBool() )
790  else
792 
793  if ( layer->customProperty( QStringLiteral( "labeling/labelOffsetMapUnitScale" ) ).toString().isEmpty() )
794  {
795  //fallback to older property
796  double oldMin = layer->customProperty( QStringLiteral( "labeling/labelOffsetMapUnitMinScale" ), 0.0 ).toDouble();
797  labelOffsetMapUnitScale.minScale = !qgsDoubleNear( oldMin, 0.0 ) ? 1.0 / oldMin : 0;
798  double oldMax = layer->customProperty( QStringLiteral( "labeling/labelOffsetMapUnitMaxScale" ), 0.0 ).toDouble();
799  labelOffsetMapUnitScale.maxScale = !qgsDoubleNear( oldMax, 0 ) ? 1.0 / oldMax : 0;
800  }
801  else
802  {
803  labelOffsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/labelOffsetMapUnitScale" ) ).toString() );
804  }
805 
806  QVariant tempAngle = layer->customProperty( QStringLiteral( "labeling/angleOffset" ), QVariant() );
807  if ( tempAngle.isValid() )
808  {
809  double oldAngle = layer->customProperty( QStringLiteral( "labeling/angleOffset" ), QVariant( 0.0 ) ).toDouble();
810  angleOffset = std::fmod( 360 - oldAngle, 360.0 );
811  }
812  else
813  {
814  angleOffset = layer->customProperty( QStringLiteral( "labeling/rotationAngle" ), QVariant( 0.0 ) ).toDouble();
815  }
816 
817  preserveRotation = layer->customProperty( QStringLiteral( "labeling/preserveRotation" ), QVariant( true ) ).toBool();
818  mRotationUnit = layer->customEnumProperty( QStringLiteral( "labeling/rotationUnit" ), QgsUnitTypes::AngleDegrees );
819  maxCurvedCharAngleIn = layer->customProperty( QStringLiteral( "labeling/maxCurvedCharAngleIn" ), QVariant( 25.0 ) ).toDouble();
820  maxCurvedCharAngleOut = layer->customProperty( QStringLiteral( "labeling/maxCurvedCharAngleOut" ), QVariant( -25.0 ) ).toDouble();
821  priority = layer->customProperty( QStringLiteral( "labeling/priority" ) ).toInt();
822  repeatDistance = layer->customProperty( QStringLiteral( "labeling/repeatDistance" ), 0.0 ).toDouble();
823  switch ( layer->customProperty( QStringLiteral( "labeling/repeatDistanceUnit" ), QVariant( 1 ) ).toUInt() )
824  {
825  case 0:
827  break;
828  case 1:
830  break;
831  case 2:
833  break;
834  case 3:
836  break;
837  }
838  if ( layer->customProperty( QStringLiteral( "labeling/repeatDistanceMapUnitScale" ) ).toString().isEmpty() )
839  {
840  //fallback to older property
841  double oldMin = layer->customProperty( QStringLiteral( "labeling/repeatDistanceMapUnitMinScale" ), 0.0 ).toDouble();
842  repeatDistanceMapUnitScale.minScale = !qgsDoubleNear( oldMin, 0 ) ? 1.0 / oldMin : 0;
843  double oldMax = layer->customProperty( QStringLiteral( "labeling/repeatDistanceMapUnitMaxScale" ), 0.0 ).toDouble();
844  repeatDistanceMapUnitScale.maxScale = !qgsDoubleNear( oldMax, 0 ) ? 1.0 / oldMax : 0;
845  }
846  else
847  {
848  repeatDistanceMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( layer->customProperty( QStringLiteral( "labeling/repeatDistanceMapUnitScale" ) ).toString() );
849  }
850 
851  // rendering
852  double scalemn = layer->customProperty( QStringLiteral( "labeling/scaleMin" ), QVariant( 0 ) ).toDouble();
853  double scalemx = layer->customProperty( QStringLiteral( "labeling/scaleMax" ), QVariant( 0 ) ).toDouble();
854 
855  // fix for scale visibility limits being keyed off of just its values in the past (<2.0)
856  QVariant scalevis = layer->customProperty( QStringLiteral( "labeling/scaleVisibility" ), QVariant() );
857  if ( scalevis.isValid() )
858  {
859  scaleVisibility = scalevis.toBool();
860  maximumScale = scalemn;
861  minimumScale = scalemx;
862  }
863  else if ( scalemn > 0 || scalemx > 0 )
864  {
865  scaleVisibility = true;
866  maximumScale = scalemn;
867  minimumScale = scalemx;
868  }
869  else
870  {
871  // keep scaleMin and scaleMax at new 1.0 defaults (1 and 10000000, were 0 and 0)
872  scaleVisibility = false;
873  }
874 
875 
876  fontLimitPixelSize = layer->customProperty( QStringLiteral( "labeling/fontLimitPixelSize" ), QVariant( false ) ).toBool();
877  fontMinPixelSize = layer->customProperty( QStringLiteral( "labeling/fontMinPixelSize" ), QVariant( 0 ) ).toInt();
878  fontMaxPixelSize = layer->customProperty( QStringLiteral( "labeling/fontMaxPixelSize" ), QVariant( 10000 ) ).toInt();
879  if ( layer->customProperty( QStringLiteral( "labeling/displayAll" ), QVariant( false ) ).toBool() )
880  {
882  mPlacementSettings.setAllowDegradedPlacement( true );
883  }
884  else
885  {
887  mPlacementSettings.setAllowDegradedPlacement( false );
888  }
889  upsidedownLabels = static_cast< Qgis::UpsideDownLabelHandling >( layer->customProperty( QStringLiteral( "labeling/upsidedownLabels" ), QVariant( static_cast< int >( Qgis::UpsideDownLabelHandling::FlipUpsideDownLabels ) ) ).toUInt() );
890 
891  labelPerPart = layer->customProperty( QStringLiteral( "labeling/labelPerPart" ) ).toBool();
892  mLineSettings.setMergeLines( layer->customProperty( QStringLiteral( "labeling/mergeLines" ) ).toBool() );
893  mThinningSettings.setMinimumFeatureSize( layer->customProperty( QStringLiteral( "labeling/minFeatureSize" ) ).toDouble() );
894  mThinningSettings.setLimitNumberLabelsEnabled( layer->customProperty( QStringLiteral( "labeling/limitNumLabels" ), QVariant( false ) ).toBool() );
895  mThinningSettings.setMaximumNumberLabels( layer->customProperty( QStringLiteral( "labeling/maxNumLabels" ), QVariant( 2000 ) ).toInt() );
896  mObstacleSettings.setIsObstacle( layer->customProperty( QStringLiteral( "labeling/obstacle" ), QVariant( true ) ).toBool() );
897  mObstacleSettings.setFactor( layer->customProperty( QStringLiteral( "labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble() );
898  mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() ) );
899  zIndex = layer->customProperty( QStringLiteral( "labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();
900 
901  mDataDefinedProperties.clear();
902  if ( layer->customProperty( QStringLiteral( "labeling/ddProperties" ) ).isValid() )
903  {
904  QDomDocument doc( QStringLiteral( "dd" ) );
905  doc.setContent( layer->customProperty( QStringLiteral( "labeling/ddProperties" ) ).toString() );
906  QDomElement elem = doc.firstChildElement( QStringLiteral( "properties" ) );
907  mDataDefinedProperties.readXml( elem, *sPropertyDefinitions() );
908  }
909  else
910  {
911  // read QGIS 2.x style data defined properties
912  readOldDataDefinedPropertyMap( layer, nullptr );
913  }
914  // upgrade older data defined settings
915  if ( mDataDefinedProperties.isActive( FontTransp ) )
916  {
917  mDataDefinedProperties.setProperty( FontOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( FontTransp ).asExpression() ) ) );
918  mDataDefinedProperties.setProperty( FontTransp, QgsProperty() );
919  }
920  if ( mDataDefinedProperties.isActive( BufferTransp ) )
921  {
922  mDataDefinedProperties.setProperty( BufferOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( BufferTransp ).asExpression() ) ) );
923  mDataDefinedProperties.setProperty( BufferTransp, QgsProperty() );
924  }
925  if ( mDataDefinedProperties.isActive( ShapeTransparency ) )
926  {
927  mDataDefinedProperties.setProperty( ShapeOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( ShapeTransparency ).asExpression() ) ) );
928  mDataDefinedProperties.setProperty( ShapeTransparency, QgsProperty() );
929  }
930  if ( mDataDefinedProperties.isActive( ShadowTransparency ) )
931  {
932  mDataDefinedProperties.setProperty( ShadowOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( ShadowTransparency ).asExpression() ) ) );
933  mDataDefinedProperties.setProperty( ShadowTransparency, QgsProperty() );
934  }
935  if ( mDataDefinedProperties.isActive( Rotation ) )
936  {
937  mDataDefinedProperties.setProperty( LabelRotation, QgsProperty::fromExpression( QStringLiteral( "360 - (%1)" ).arg( mDataDefinedProperties.property( Rotation ).asExpression() ) ) );
938  mDataDefinedProperties.setProperty( Rotation, QgsProperty() );
939  }
940  // older 2.x projects had min/max scale flipped - so change them here.
941  if ( mDataDefinedProperties.isActive( MinScale ) )
942  {
943  mDataDefinedProperties.setProperty( MaximumScale, mDataDefinedProperties.property( MinScale ) );
944  mDataDefinedProperties.setProperty( MinScale, QgsProperty() );
945  }
946  if ( mDataDefinedProperties.isActive( MaxScale ) )
947  {
948  mDataDefinedProperties.setProperty( MinimumScale, mDataDefinedProperties.property( MaxScale ) );
949  mDataDefinedProperties.setProperty( MaxScale, QgsProperty() );
950  }
951 }
952 
953 void QgsPalLayerSettings::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
954 {
955  // text style
956  QDomElement textStyleElem = elem.firstChildElement( QStringLiteral( "text-style" ) );
957  fieldName = textStyleElem.attribute( QStringLiteral( "fieldName" ) );
958  isExpression = textStyleElem.attribute( QStringLiteral( "isExpression" ) ).toInt();
959 
960  mFormat.readXml( elem, context );
962  previewBkgrdColor = QColor( textStyleElem.attribute( QStringLiteral( "previewBkgrdColor" ), QStringLiteral( "#ffffff" ) ) );
964  substitutions.readXml( textStyleElem.firstChildElement( QStringLiteral( "substitutions" ) ) );
965  useSubstitutions = textStyleElem.attribute( QStringLiteral( "useSubstitutions" ) ).toInt();
966  mLegendString = textStyleElem.attribute( QStringLiteral( "legendString" ), QObject::tr( "Aa" ) );
967 
968  // text formatting
969  QDomElement textFormatElem = elem.firstChildElement( QStringLiteral( "text-format" ) );
970  wrapChar = textFormatElem.attribute( QStringLiteral( "wrapChar" ) );
971  autoWrapLength = textFormatElem.attribute( QStringLiteral( "autoWrapLength" ), QStringLiteral( "0" ) ).toInt();
972  useMaxLineLengthForAutoWrap = textFormatElem.attribute( QStringLiteral( "useMaxLineLengthForAutoWrap" ), QStringLiteral( "1" ) ).toInt();
973  multilineAlign = static_cast< Qgis::LabelMultiLineAlignment >( textFormatElem.attribute( QStringLiteral( "multilineAlign" ), QString::number( static_cast< int >( Qgis::LabelMultiLineAlignment::FollowPlacement ) ) ).toUInt() );
974  mLineSettings.setAddDirectionSymbol( textFormatElem.attribute( QStringLiteral( "addDirectionSymbol" ) ).toInt() );
975  mLineSettings.setLeftDirectionSymbol( textFormatElem.attribute( QStringLiteral( "leftDirectionSymbol" ), QStringLiteral( "<" ) ) );
976  mLineSettings.setRightDirectionSymbol( textFormatElem.attribute( QStringLiteral( "rightDirectionSymbol" ), QStringLiteral( ">" ) ) );
977  mLineSettings.setReverseDirectionSymbol( textFormatElem.attribute( QStringLiteral( "reverseDirectionSymbol" ) ).toInt() );
978  mLineSettings.setDirectionSymbolPlacement( static_cast< QgsLabelLineSettings::DirectionSymbolPlacement >( textFormatElem.attribute( QStringLiteral( "placeDirectionSymbol" ), QString::number( static_cast< int >( QgsLabelLineSettings::DirectionSymbolPlacement::SymbolLeftRight ) ) ).toUInt() ) );
979  formatNumbers = textFormatElem.attribute( QStringLiteral( "formatNumbers" ) ).toInt();
980  decimals = textFormatElem.attribute( QStringLiteral( "decimals" ) ).toInt();
981  plusSign = textFormatElem.attribute( QStringLiteral( "plussign" ) ).toInt();
982 
983  // placement
984  QDomElement placementElem = elem.firstChildElement( QStringLiteral( "placement" ) );
985  placement = static_cast< Qgis::LabelPlacement >( placementElem.attribute( QStringLiteral( "placement" ) ).toInt() );
986  mLineSettings.setPlacementFlags( static_cast< QgsLabeling::LinePlacementFlags >( placementElem.attribute( QStringLiteral( "placementFlags" ) ).toUInt() ) );
987  mPolygonPlacementFlags = static_cast< QgsLabeling::PolygonPlacementFlags >( placementElem.attribute( QStringLiteral( "polygonPlacementFlags" ), QString::number( static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon ) ) ).toInt() );
988 
989  centroidWhole = placementElem.attribute( QStringLiteral( "centroidWhole" ), QStringLiteral( "0" ) ).toInt();
990  centroidInside = placementElem.attribute( QStringLiteral( "centroidInside" ), QStringLiteral( "0" ) ).toInt();
991  predefinedPositionOrder = QgsLabelingUtils::decodePredefinedPositionOrder( placementElem.attribute( QStringLiteral( "predefinedPositionOrder" ) ) );
992  if ( predefinedPositionOrder.isEmpty() )
993  predefinedPositionOrder = *DEFAULT_PLACEMENT_ORDER();
994  fitInPolygonOnly = placementElem.attribute( QStringLiteral( "fitInPolygonOnly" ), QStringLiteral( "0" ) ).toInt();
995  dist = placementElem.attribute( QStringLiteral( "dist" ) ).toDouble();
996  if ( !placementElem.hasAttribute( QStringLiteral( "distUnits" ) ) )
997  {
998  if ( placementElem.attribute( QStringLiteral( "distInMapUnits" ) ).toInt() )
1000  else
1002  }
1003  else
1004  {
1005  distUnits = QgsUnitTypes::decodeRenderUnit( placementElem.attribute( QStringLiteral( "distUnits" ) ) );
1006  }
1007  if ( !placementElem.hasAttribute( QStringLiteral( "distMapUnitScale" ) ) )
1008  {
1009  //fallback to older property
1010  double oldMin = placementElem.attribute( QStringLiteral( "distMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
1011  distMapUnitScale.minScale = !qgsDoubleNear( oldMin, 0 ) ? 1.0 / oldMin : 0;
1012  double oldMax = placementElem.attribute( QStringLiteral( "distMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
1013  distMapUnitScale.maxScale = !qgsDoubleNear( oldMax, 0 ) ? 1.0 / oldMax : 0;
1014  }
1015  else
1016  {
1017  distMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( placementElem.attribute( QStringLiteral( "distMapUnitScale" ) ) );
1018  }
1019  offsetType = static_cast< Qgis::LabelOffsetType >( placementElem.attribute( QStringLiteral( "offsetType" ), QString::number( static_cast< int >( Qgis::LabelOffsetType::FromPoint ) ) ).toUInt() );
1020  quadOffset = static_cast< Qgis::LabelQuadrantPosition >( placementElem.attribute( QStringLiteral( "quadOffset" ), QString::number( static_cast< int >( Qgis::LabelQuadrantPosition::Over ) ) ).toUInt() );
1021  xOffset = placementElem.attribute( QStringLiteral( "xOffset" ), QStringLiteral( "0" ) ).toDouble();
1022  yOffset = placementElem.attribute( QStringLiteral( "yOffset" ), QStringLiteral( "0" ) ).toDouble();
1023  if ( !placementElem.hasAttribute( QStringLiteral( "offsetUnits" ) ) )
1024  {
1025  offsetUnits = placementElem.attribute( QStringLiteral( "labelOffsetInMapUnits" ), QStringLiteral( "1" ) ).toInt() ? QgsUnitTypes::RenderMapUnits : QgsUnitTypes::RenderMillimeters;
1026  }
1027  else
1028  {
1029  offsetUnits = QgsUnitTypes::decodeRenderUnit( placementElem.attribute( QStringLiteral( "offsetUnits" ) ) );
1030  }
1031  if ( !placementElem.hasAttribute( QStringLiteral( "labelOffsetMapUnitScale" ) ) )
1032  {
1033  //fallback to older property
1034  double oldMin = placementElem.attribute( QStringLiteral( "labelOffsetMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
1035  labelOffsetMapUnitScale.minScale = !qgsDoubleNear( oldMin, 0.0 ) ? 1.0 / oldMin : 0;
1036  double oldMax = placementElem.attribute( QStringLiteral( "labelOffsetMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
1037  labelOffsetMapUnitScale.maxScale = !qgsDoubleNear( oldMax, 0.0 ) ? 1.0 / oldMax : 0;
1038  }
1039  else
1040  {
1041  labelOffsetMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( placementElem.attribute( QStringLiteral( "labelOffsetMapUnitScale" ) ) );
1042  }
1043 
1044  if ( placementElem.hasAttribute( QStringLiteral( "angleOffset" ) ) )
1045  {
1046  double oldAngle = placementElem.attribute( QStringLiteral( "angleOffset" ), QStringLiteral( "0" ) ).toDouble();
1047  angleOffset = std::fmod( 360 - oldAngle, 360.0 );
1048  }
1049  else
1050  {
1051  angleOffset = placementElem.attribute( QStringLiteral( "rotationAngle" ), QStringLiteral( "0" ) ).toDouble();
1052  }
1053 
1054  preserveRotation = placementElem.attribute( QStringLiteral( "preserveRotation" ), QStringLiteral( "1" ) ).toInt();
1055  mRotationUnit = qgsEnumKeyToValue( placementElem.attribute( QStringLiteral( "rotationUnit" ), qgsEnumValueToKey( QgsUnitTypes::AngleDegrees ) ), QgsUnitTypes::AngleDegrees );
1056  maxCurvedCharAngleIn = placementElem.attribute( QStringLiteral( "maxCurvedCharAngleIn" ), QStringLiteral( "25" ) ).toDouble();
1057  maxCurvedCharAngleOut = placementElem.attribute( QStringLiteral( "maxCurvedCharAngleOut" ), QStringLiteral( "-25" ) ).toDouble();
1058  priority = placementElem.attribute( QStringLiteral( "priority" ) ).toInt();
1059  repeatDistance = placementElem.attribute( QStringLiteral( "repeatDistance" ), QStringLiteral( "0" ) ).toDouble();
1060  if ( !placementElem.hasAttribute( QStringLiteral( "repeatDistanceUnits" ) ) )
1061  {
1062  // upgrade old setting
1063  switch ( placementElem.attribute( QStringLiteral( "repeatDistanceUnit" ), QString::number( 1 ) ).toUInt() )
1064  {
1065  case 0:
1067  break;
1068  case 1:
1070  break;
1071  case 2:
1073  break;
1074  case 3:
1076  break;
1077  }
1078  }
1079  else
1080  {
1081  repeatDistanceUnit = QgsUnitTypes::decodeRenderUnit( placementElem.attribute( QStringLiteral( "repeatDistanceUnits" ) ) );
1082  }
1083  if ( !placementElem.hasAttribute( QStringLiteral( "repeatDistanceMapUnitScale" ) ) )
1084  {
1085  //fallback to older property
1086  double oldMin = placementElem.attribute( QStringLiteral( "repeatDistanceMapUnitMinScale" ), QStringLiteral( "0" ) ).toDouble();
1087  repeatDistanceMapUnitScale.minScale = !qgsDoubleNear( oldMin, 0.0 ) ? 1.0 / oldMin : 0;
1088  double oldMax = placementElem.attribute( QStringLiteral( "repeatDistanceMapUnitMaxScale" ), QStringLiteral( "0" ) ).toDouble();
1089  repeatDistanceMapUnitScale.maxScale = !qgsDoubleNear( oldMax, 0.0 ) ? 1.0 / oldMax : 0;
1090  }
1091  else
1092  {
1093  repeatDistanceMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( placementElem.attribute( QStringLiteral( "repeatDistanceMapUnitScale" ) ) );
1094  }
1095 
1096  mLineSettings.setOverrunDistance( placementElem.attribute( QStringLiteral( "overrunDistance" ), QStringLiteral( "0" ) ).toDouble() );
1097  mLineSettings.setOverrunDistanceUnit( QgsUnitTypes::decodeRenderUnit( placementElem.attribute( QStringLiteral( "overrunDistanceUnit" ) ) ) );
1098  mLineSettings.setOverrunDistanceMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( placementElem.attribute( QStringLiteral( "overrunDistanceMapUnitScale" ) ) ) );
1099  mLineSettings.setLineAnchorPercent( placementElem.attribute( QStringLiteral( "lineAnchorPercent" ), QStringLiteral( "0.5" ) ).toDouble() );
1100  mLineSettings.setAnchorType( static_cast< QgsLabelLineSettings::AnchorType >( placementElem.attribute( QStringLiteral( "lineAnchorType" ), QStringLiteral( "0" ) ).toInt() ) );
1101  mLineSettings.setAnchorClipping( static_cast< QgsLabelLineSettings::AnchorClipping >( placementElem.attribute( QStringLiteral( "lineAnchorClipping" ), QStringLiteral( "0" ) ).toInt() ) );
1102  // when reading the anchor text point we default to center mode, to keep same result as for proejcts created in < 3.26
1103  mLineSettings.setAnchorTextPoint( qgsEnumKeyToValue( placementElem.attribute( QStringLiteral( "lineAnchorTextPoint" ) ), QgsLabelLineSettings::AnchorTextPoint::CenterOfText ) );
1104 
1105  geometryGenerator = placementElem.attribute( QStringLiteral( "geometryGenerator" ) );
1106  geometryGeneratorEnabled = placementElem.attribute( QStringLiteral( "geometryGeneratorEnabled" ) ).toInt();
1107  geometryGeneratorType = qgsEnumKeyToValue( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ), QgsWkbTypes::PointGeometry );
1108 
1109  layerType = qgsEnumKeyToValue( placementElem.attribute( QStringLiteral( "layerType" ) ), QgsWkbTypes::UnknownGeometry );
1110 
1111  mPlacementSettings.setAllowDegradedPlacement( placementElem.attribute( QStringLiteral( "allowDegraded" ), QStringLiteral( "0" ) ).toInt() );
1112 
1113  // rendering
1114  QDomElement renderingElem = elem.firstChildElement( QStringLiteral( "rendering" ) );
1115 
1116  drawLabels = renderingElem.attribute( QStringLiteral( "drawLabels" ), QStringLiteral( "1" ) ).toInt();
1117 
1118  maximumScale = renderingElem.attribute( QStringLiteral( "scaleMin" ), QStringLiteral( "0" ) ).toDouble();
1119  minimumScale = renderingElem.attribute( QStringLiteral( "scaleMax" ), QStringLiteral( "0" ) ).toDouble();
1120  scaleVisibility = renderingElem.attribute( QStringLiteral( "scaleVisibility" ) ).toInt();
1121 
1122  fontLimitPixelSize = renderingElem.attribute( QStringLiteral( "fontLimitPixelSize" ), QStringLiteral( "0" ) ).toInt();
1123  fontMinPixelSize = renderingElem.attribute( QStringLiteral( "fontMinPixelSize" ), QStringLiteral( "0" ) ).toInt();
1124  fontMaxPixelSize = renderingElem.attribute( QStringLiteral( "fontMaxPixelSize" ), QStringLiteral( "10000" ) ).toInt();
1125 
1126  if ( placementElem.hasAttribute( QStringLiteral( "overlapHandling" ) ) )
1127  {
1128  mPlacementSettings.setOverlapHandling( qgsEnumKeyToValue( placementElem.attribute( QStringLiteral( "overlapHandling" ) ), Qgis::LabelOverlapHandling::PreventOverlap ) );
1129  }
1130  else
1131  {
1132  // legacy setting
1133  if ( renderingElem.attribute( QStringLiteral( "displayAll" ), QStringLiteral( "0" ) ).toInt() )
1134  {
1136  mPlacementSettings.setAllowDegradedPlacement( true );
1137  }
1138  else
1139  {
1141  mPlacementSettings.setAllowDegradedPlacement( false );
1142  }
1143  }
1144  upsidedownLabels = static_cast< Qgis::UpsideDownLabelHandling >( renderingElem.attribute( QStringLiteral( "upsidedownLabels" ), QString::number( static_cast< int >( Qgis::UpsideDownLabelHandling::FlipUpsideDownLabels ) ) ).toUInt() );
1145 
1146  labelPerPart = renderingElem.attribute( QStringLiteral( "labelPerPart" ) ).toInt();
1147  mLineSettings.setMergeLines( renderingElem.attribute( QStringLiteral( "mergeLines" ) ).toInt() );
1148  mThinningSettings.setMinimumFeatureSize( renderingElem.attribute( QStringLiteral( "minFeatureSize" ) ).toDouble() );
1149  mThinningSettings.setLimitNumberLabelsEnabled( renderingElem.attribute( QStringLiteral( "limitNumLabels" ), QStringLiteral( "0" ) ).toInt() );
1150  mThinningSettings.setMaximumNumberLabels( renderingElem.attribute( QStringLiteral( "maxNumLabels" ), QStringLiteral( "2000" ) ).toInt() );
1151  mObstacleSettings.setIsObstacle( renderingElem.attribute( QStringLiteral( "obstacle" ), QStringLiteral( "1" ) ).toInt() );
1152  mObstacleSettings.setFactor( renderingElem.attribute( QStringLiteral( "obstacleFactor" ), QStringLiteral( "1" ) ).toDouble() );
1153  mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( renderingElem.attribute( QStringLiteral( "obstacleType" ), QString::number( PolygonInterior ) ).toUInt() ) );
1154  zIndex = renderingElem.attribute( QStringLiteral( "zIndex" ), QStringLiteral( "0.0" ) ).toDouble();
1155  mUnplacedVisibility = static_cast< Qgis::UnplacedLabelVisibility >( renderingElem.attribute( QStringLiteral( "unplacedVisibility" ), QString::number( static_cast< int >( Qgis::UnplacedLabelVisibility::FollowEngineSetting ) ) ).toInt() );
1156 
1157  QDomElement ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
1158  if ( !ddElem.isNull() )
1159  {
1160  mDataDefinedProperties.readXml( ddElem, *sPropertyDefinitions() );
1161  }
1162  else
1163  {
1164  // upgrade 2.x style dd project
1165  mDataDefinedProperties.clear();
1166  QDomElement ddElem = elem.firstChildElement( QStringLiteral( "data-defined" ) );
1167  readOldDataDefinedPropertyMap( nullptr, &ddElem );
1168  }
1169  // upgrade older data defined settings
1170  if ( mDataDefinedProperties.isActive( FontTransp ) )
1171  {
1172  mDataDefinedProperties.setProperty( FontOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( FontTransp ).asExpression() ) ) );
1173  mDataDefinedProperties.setProperty( FontTransp, QgsProperty() );
1174  }
1175  if ( mDataDefinedProperties.isActive( BufferTransp ) )
1176  {
1177  mDataDefinedProperties.setProperty( BufferOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( BufferTransp ).asExpression() ) ) );
1178  mDataDefinedProperties.setProperty( BufferTransp, QgsProperty() );
1179  }
1180  if ( mDataDefinedProperties.isActive( ShapeTransparency ) )
1181  {
1182  mDataDefinedProperties.setProperty( ShapeOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( ShapeTransparency ).asExpression() ) ) );
1183  mDataDefinedProperties.setProperty( ShapeTransparency, QgsProperty() );
1184  }
1185  if ( mDataDefinedProperties.isActive( ShadowTransparency ) )
1186  {
1187  mDataDefinedProperties.setProperty( ShadowOpacity, QgsProperty::fromExpression( QStringLiteral( "100 - (%1)" ).arg( mDataDefinedProperties.property( ShadowTransparency ).asExpression() ) ) );
1188  mDataDefinedProperties.setProperty( ShadowTransparency, QgsProperty() );
1189  }
1190  if ( mDataDefinedProperties.isActive( Rotation ) )
1191  {
1192  mDataDefinedProperties.setProperty( LabelRotation, QgsProperty::fromExpression( QStringLiteral( "360 - (%1)" ).arg( mDataDefinedProperties.property( Rotation ).asExpression() ) ) );
1193  mDataDefinedProperties.setProperty( Rotation, QgsProperty() );
1194  }
1195  // older 2.x projects had min/max scale flipped - so change them here.
1196  if ( mDataDefinedProperties.isActive( MinScale ) )
1197  {
1198  mDataDefinedProperties.setProperty( MaximumScale, mDataDefinedProperties.property( MinScale ) );
1199  mDataDefinedProperties.setProperty( MinScale, QgsProperty() );
1200  }
1201  if ( mDataDefinedProperties.isActive( MaxScale ) )
1202  {
1203  mDataDefinedProperties.setProperty( MinimumScale, mDataDefinedProperties.property( MaxScale ) );
1204  mDataDefinedProperties.setProperty( MaxScale, QgsProperty() );
1205  }
1206 
1207  // TODO - replace with registry when multiple callout styles exist
1208  const QString calloutType = elem.attribute( QStringLiteral( "calloutType" ) );
1209  if ( calloutType.isEmpty() )
1210  mCallout.reset( QgsCalloutRegistry::defaultCallout() );
1211  else
1212  {
1213  mCallout.reset( QgsApplication::calloutRegistry()->createCallout( calloutType, elem.firstChildElement( QStringLiteral( "callout" ) ), context ) );
1214  if ( !mCallout )
1215  mCallout.reset( QgsCalloutRegistry::defaultCallout() );
1216  }
1217 }
1218 
1219 QDomElement QgsPalLayerSettings::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
1220 {
1221  QDomElement textStyleElem = mFormat.writeXml( doc, context );
1222 
1223  // text style
1224  textStyleElem.setAttribute( QStringLiteral( "fieldName" ), fieldName );
1225  textStyleElem.setAttribute( QStringLiteral( "isExpression" ), isExpression );
1226  QDomElement replacementElem = doc.createElement( QStringLiteral( "substitutions" ) );
1227  substitutions.writeXml( replacementElem, doc );
1228  textStyleElem.appendChild( replacementElem );
1229  textStyleElem.setAttribute( QStringLiteral( "useSubstitutions" ), useSubstitutions );
1230  textStyleElem.setAttribute( QStringLiteral( "legendString" ), mLegendString );
1231 
1232  // text formatting
1233  QDomElement textFormatElem = doc.createElement( QStringLiteral( "text-format" ) );
1234  textFormatElem.setAttribute( QStringLiteral( "wrapChar" ), wrapChar );
1235  textFormatElem.setAttribute( QStringLiteral( "autoWrapLength" ), autoWrapLength );
1236  textFormatElem.setAttribute( QStringLiteral( "useMaxLineLengthForAutoWrap" ), useMaxLineLengthForAutoWrap );
1237  textFormatElem.setAttribute( QStringLiteral( "multilineAlign" ), static_cast< unsigned int >( multilineAlign ) );
1238  textFormatElem.setAttribute( QStringLiteral( "addDirectionSymbol" ), mLineSettings.addDirectionSymbol() );
1239  textFormatElem.setAttribute( QStringLiteral( "leftDirectionSymbol" ), mLineSettings.leftDirectionSymbol() );
1240  textFormatElem.setAttribute( QStringLiteral( "rightDirectionSymbol" ), mLineSettings.rightDirectionSymbol() );
1241  textFormatElem.setAttribute( QStringLiteral( "reverseDirectionSymbol" ), mLineSettings.reverseDirectionSymbol() );
1242  textFormatElem.setAttribute( QStringLiteral( "placeDirectionSymbol" ), static_cast< unsigned int >( mLineSettings.directionSymbolPlacement() ) );
1243  textFormatElem.setAttribute( QStringLiteral( "formatNumbers" ), formatNumbers );
1244  textFormatElem.setAttribute( QStringLiteral( "decimals" ), decimals );
1245  textFormatElem.setAttribute( QStringLiteral( "plussign" ), plusSign );
1246 
1247  // placement
1248  QDomElement placementElem = doc.createElement( QStringLiteral( "placement" ) );
1249  placementElem.setAttribute( QStringLiteral( "placement" ), static_cast< int >( placement ) );
1250  placementElem.setAttribute( QStringLiteral( "polygonPlacementFlags" ), static_cast< int >( mPolygonPlacementFlags ) );
1251  placementElem.setAttribute( QStringLiteral( "placementFlags" ), static_cast< unsigned int >( mLineSettings.placementFlags() ) );
1252  placementElem.setAttribute( QStringLiteral( "centroidWhole" ), centroidWhole );
1253  placementElem.setAttribute( QStringLiteral( "centroidInside" ), centroidInside );
1254  placementElem.setAttribute( QStringLiteral( "predefinedPositionOrder" ), QgsLabelingUtils::encodePredefinedPositionOrder( predefinedPositionOrder ) );
1255  placementElem.setAttribute( QStringLiteral( "fitInPolygonOnly" ), fitInPolygonOnly );
1256  placementElem.setAttribute( QStringLiteral( "dist" ), dist );
1257  placementElem.setAttribute( QStringLiteral( "distUnits" ), QgsUnitTypes::encodeUnit( distUnits ) );
1258  placementElem.setAttribute( QStringLiteral( "distMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( distMapUnitScale ) );
1259  placementElem.setAttribute( QStringLiteral( "offsetType" ), static_cast< unsigned int >( offsetType ) );
1260  placementElem.setAttribute( QStringLiteral( "quadOffset" ), static_cast< unsigned int >( quadOffset ) );
1261  placementElem.setAttribute( QStringLiteral( "xOffset" ), xOffset );
1262  placementElem.setAttribute( QStringLiteral( "yOffset" ), yOffset );
1263  placementElem.setAttribute( QStringLiteral( "offsetUnits" ), QgsUnitTypes::encodeUnit( offsetUnits ) );
1264  placementElem.setAttribute( QStringLiteral( "labelOffsetMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( labelOffsetMapUnitScale ) );
1265  placementElem.setAttribute( QStringLiteral( "rotationAngle" ), angleOffset );
1266  placementElem.setAttribute( QStringLiteral( "preserveRotation" ), preserveRotation );
1267  placementElem.setAttribute( QStringLiteral( "rotationUnit" ), qgsEnumValueToKey( mRotationUnit ) );
1268  placementElem.setAttribute( QStringLiteral( "maxCurvedCharAngleIn" ), maxCurvedCharAngleIn );
1269  placementElem.setAttribute( QStringLiteral( "maxCurvedCharAngleOut" ), maxCurvedCharAngleOut );
1270  placementElem.setAttribute( QStringLiteral( "priority" ), priority );
1271  placementElem.setAttribute( QStringLiteral( "repeatDistance" ), repeatDistance );
1272  placementElem.setAttribute( QStringLiteral( "repeatDistanceUnits" ), QgsUnitTypes::encodeUnit( repeatDistanceUnit ) );
1273  placementElem.setAttribute( QStringLiteral( "repeatDistanceMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( repeatDistanceMapUnitScale ) );
1274  placementElem.setAttribute( QStringLiteral( "overrunDistance" ), mLineSettings.overrunDistance() );
1275  placementElem.setAttribute( QStringLiteral( "overrunDistanceUnit" ), QgsUnitTypes::encodeUnit( mLineSettings.overrunDistanceUnit() ) );
1276  placementElem.setAttribute( QStringLiteral( "overrunDistanceMapUnitScale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mLineSettings.overrunDistanceMapUnitScale() ) );
1277  placementElem.setAttribute( QStringLiteral( "lineAnchorPercent" ), mLineSettings.lineAnchorPercent() );
1278  placementElem.setAttribute( QStringLiteral( "lineAnchorType" ), static_cast< int >( mLineSettings.anchorType() ) );
1279  placementElem.setAttribute( QStringLiteral( "lineAnchorClipping" ), static_cast< int >( mLineSettings.anchorClipping() ) );
1280  placementElem.setAttribute( QStringLiteral( "lineAnchorTextPoint" ), qgsEnumValueToKey( mLineSettings.anchorTextPoint() ) );
1281 
1282  placementElem.setAttribute( QStringLiteral( "geometryGenerator" ), geometryGenerator );
1283  placementElem.setAttribute( QStringLiteral( "geometryGeneratorEnabled" ), geometryGeneratorEnabled );
1284  const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() );
1285  placementElem.setAttribute( QStringLiteral( "geometryGeneratorType" ), metaEnum.valueToKey( geometryGeneratorType ) );
1286 
1287  placementElem.setAttribute( QStringLiteral( "layerType" ), metaEnum.valueToKey( layerType ) );
1288 
1289  placementElem.setAttribute( QStringLiteral( "overlapHandling" ), qgsEnumValueToKey( mPlacementSettings.overlapHandling() ) );
1290  placementElem.setAttribute( QStringLiteral( "allowDegraded" ), mPlacementSettings.allowDegradedPlacement() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
1291 
1292  // rendering
1293  QDomElement renderingElem = doc.createElement( QStringLiteral( "rendering" ) );
1294  renderingElem.setAttribute( QStringLiteral( "drawLabels" ), drawLabels );
1295  renderingElem.setAttribute( QStringLiteral( "scaleVisibility" ), scaleVisibility );
1296  renderingElem.setAttribute( QStringLiteral( "scaleMin" ), maximumScale );
1297  renderingElem.setAttribute( QStringLiteral( "scaleMax" ), minimumScale );
1298  renderingElem.setAttribute( QStringLiteral( "fontLimitPixelSize" ), fontLimitPixelSize );
1299  renderingElem.setAttribute( QStringLiteral( "fontMinPixelSize" ), fontMinPixelSize );
1300  renderingElem.setAttribute( QStringLiteral( "fontMaxPixelSize" ), fontMaxPixelSize );
1301  renderingElem.setAttribute( QStringLiteral( "upsidedownLabels" ), static_cast< unsigned int >( upsidedownLabels ) );
1302 
1303  renderingElem.setAttribute( QStringLiteral( "labelPerPart" ), labelPerPart );
1304  renderingElem.setAttribute( QStringLiteral( "mergeLines" ), mLineSettings.mergeLines() );
1305  renderingElem.setAttribute( QStringLiteral( "minFeatureSize" ), mThinningSettings.minimumFeatureSize() );
1306  renderingElem.setAttribute( QStringLiteral( "limitNumLabels" ), mThinningSettings.limitNumberOfLabelsEnabled() );
1307  renderingElem.setAttribute( QStringLiteral( "maxNumLabels" ), mThinningSettings.maximumNumberLabels() );
1308  renderingElem.setAttribute( QStringLiteral( "obstacle" ), mObstacleSettings.isObstacle() );
1309  renderingElem.setAttribute( QStringLiteral( "obstacleFactor" ), mObstacleSettings.factor() );
1310  renderingElem.setAttribute( QStringLiteral( "obstacleType" ), static_cast< unsigned int >( mObstacleSettings.type() ) );
1311  renderingElem.setAttribute( QStringLiteral( "zIndex" ), zIndex );
1312  renderingElem.setAttribute( QStringLiteral( "unplacedVisibility" ), static_cast< int >( mUnplacedVisibility ) );
1313 
1314  QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
1315  mDataDefinedProperties.writeXml( ddElem, *sPropertyDefinitions() );
1316 
1317  QDomElement elem = doc.createElement( QStringLiteral( "settings" ) );
1318  elem.appendChild( textStyleElem );
1319  elem.appendChild( textFormatElem );
1320  elem.appendChild( placementElem );
1321  elem.appendChild( renderingElem );
1322  elem.appendChild( ddElem );
1323 
1324  if ( mCallout )
1325  {
1326  elem.setAttribute( QStringLiteral( "calloutType" ), mCallout->type() );
1327  mCallout->saveProperties( doc, elem, context );
1328  }
1329 
1330  return elem;
1331 }
1332 
1334 {
1335  mCallout.reset( callout );
1336 }
1337 
1338 QPixmap QgsPalLayerSettings::labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText, int padding )
1339 {
1340  // for now, just use format
1341  QgsTextFormat tempFormat = settings.format();
1342  QPixmap pixmap( size );
1343  pixmap.fill( Qt::transparent );
1344  QPainter painter;
1345  painter.begin( &pixmap );
1346 
1347  painter.setRenderHint( QPainter::Antialiasing );
1348 
1349  QRect rect( 0, 0, size.width(), size.height() );
1350 
1351  // shameless eye candy - use a subtle gradient when drawing background
1352  painter.setPen( Qt::NoPen );
1353  QColor background1 = tempFormat.previewBackgroundColor();
1354  if ( ( background1.lightnessF() < 0.7 ) )
1355  {
1356  background1 = background1.darker( 125 );
1357  }
1358  else
1359  {
1360  background1 = background1.lighter( 125 );
1361  }
1362  QColor background2 = tempFormat.previewBackgroundColor();
1363  QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1364  linearGrad.setColorAt( 0, background1 );
1365  linearGrad.setColorAt( 1, background2 );
1366  painter.setBrush( QBrush( linearGrad ) );
1367  if ( size.width() > 30 )
1368  {
1369  painter.drawRoundedRect( rect, 6, 6 );
1370  }
1371  else
1372  {
1373  // don't use rounded rect for small previews
1374  painter.drawRect( rect );
1375  }
1376  painter.setBrush( Qt::NoBrush );
1377  painter.setPen( Qt::NoPen );
1378  padding += 1; // move text away from background border
1379 
1380  QgsRenderContext context;
1381  QgsMapToPixel newCoordXForm;
1382  newCoordXForm.setParameters( 1, 0, 0, 0, 0, 0 );
1383  context.setMapToPixel( newCoordXForm );
1385 
1386 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
1387  const double logicalDpiX = QgsApplication::desktop()->logicalDpiX();
1388 #else
1389  QWidget *activeWindow = QApplication::activeWindow();
1390  const double logicalDpiX = activeWindow && activeWindow->screen() ? activeWindow->screen()->logicalDotsPerInchX() : 96.0;
1391 #endif
1392  context.setScaleFactor( logicalDpiX / 25.4 );
1393 
1394  context.setUseAdvancedEffects( true );
1395  context.setPainter( &painter );
1396 
1397  // slightly inset text to account for buffer/background
1398  const double fontSize = context.convertToPainterUnits( tempFormat.size(), tempFormat.sizeUnit(), tempFormat.sizeMapUnitScale() );
1399  double xtrans = 0;
1400  if ( tempFormat.buffer().enabled() )
1401  xtrans = tempFormat.buffer().sizeUnit() == QgsUnitTypes::RenderPercentage
1402  ? fontSize * tempFormat.buffer().size() / 100
1403  : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() );
1404  if ( tempFormat.background().enabled() && tempFormat.background().sizeType() != QgsTextBackgroundSettings::SizeFixed )
1405  xtrans = std::max( xtrans, context.convertToPainterUnits( tempFormat.background().size().width(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1406 
1407  double ytrans = 0.0;
1408  if ( tempFormat.buffer().enabled() )
1409  ytrans = std::max( ytrans, tempFormat.buffer().sizeUnit() == QgsUnitTypes::RenderPercentage
1410  ? fontSize * tempFormat.buffer().size() / 100
1411  : context.convertToPainterUnits( tempFormat.buffer().size(), tempFormat.buffer().sizeUnit(), tempFormat.buffer().sizeMapUnitScale() ) );
1412  if ( tempFormat.background().enabled() )
1413  ytrans = std::max( ytrans, context.convertToPainterUnits( tempFormat.background().size().height(), tempFormat.background().sizeUnit(), tempFormat.background().sizeMapUnitScale() ) );
1414 
1415  const QStringList text = QStringList() << ( previewText.isEmpty() ? settings.legendString() : previewText );
1416  const double textHeight = QgsTextRenderer::textHeight( context, tempFormat, text, QgsTextRenderer::Rect );
1417  QRectF textRect = rect;
1418  textRect.setLeft( xtrans + padding );
1419  textRect.setWidth( rect.width() - xtrans - 2 * padding );
1420 
1421  if ( textRect.width() > 2000 )
1422  textRect.setWidth( 2000 - 2 * padding );
1423 
1424  const double bottom = textRect.height() / 2 + textHeight / 2;
1425  textRect.setTop( bottom - textHeight );
1426  textRect.setBottom( bottom );
1427 
1428  const double iconWidth = QFontMetricsF( QFont() ).horizontalAdvance( 'X' ) * Qgis::UI_SCALE_FACTOR;
1429 
1430  if ( settings.callout() && settings.callout()->enabled() )
1431  {
1432  // draw callout preview
1433  const double textWidth = QgsTextRenderer::textWidth( context, tempFormat, text );
1434  QgsCallout *callout = settings.callout();
1435  callout->startRender( context );
1436  QgsCallout::QgsCalloutContext calloutContext;
1437  QRectF labelRect( textRect.left() + ( textRect.width() - textWidth ) / 2.0, textRect.top(), textWidth, textRect.height() );
1438  callout->render( context, labelRect, 0, QgsGeometry::fromPointXY( QgsPointXY( labelRect.left() - iconWidth * 1.5, labelRect.bottom() + iconWidth ) ), calloutContext );
1439  callout->stopRender( context );
1440  }
1441 
1442  QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::AlignCenter, text, context, tempFormat );
1443 
1444  if ( size.width() > 30 )
1445  {
1446  // draw a label icon
1447 
1448  QgsApplication::getThemeIcon( QStringLiteral( "labelingSingle.svg" ) ).paint( &painter, QRect(
1449  rect.width() - iconWidth * 3, rect.height() - iconWidth * 3,
1450  iconWidth * 2, iconWidth * 2 ), Qt::AlignRight | Qt::AlignBottom );
1451  }
1452 
1453  // draw border on top of text
1454  painter.setBrush( Qt::NoBrush );
1455  painter.setPen( QPen( tempFormat.previewBackgroundColor().darker( 150 ), 0 ) );
1456  if ( size.width() > 30 )
1457  {
1458  painter.drawRoundedRect( rect, 6, 6 );
1459  }
1460  else
1461  {
1462  // don't use rounded rect for small previews
1463  painter.drawRect( rect );
1464  }
1465 
1466  painter.end();
1467  return pixmap;
1468 }
1469 
1471 {
1472  return mUnplacedVisibility;
1473 }
1474 
1476 {
1477  mUnplacedVisibility = visibility;
1478 }
1479 
1480 bool QgsPalLayerSettings::checkMinimumSizeMM( const QgsRenderContext &ct, const QgsGeometry &geom, double minSize ) const
1481 {
1482  return QgsPalLabeling::checkMinimumSizeMM( ct, geom, minSize );
1483 }
1484 
1485 void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF *fm, const QString &text, double &labelX, double &labelY, const QgsFeature *f, QgsRenderContext *context, double *rotatedLabelX, double *rotatedLabelY, QgsTextDocument *document )
1486 {
1487  if ( !fm || !f )
1488  {
1489  return;
1490  }
1491 
1492  QString textCopy( text );
1493 
1494  //try to keep < 2.12 API - handle no passed render context
1495  std::unique_ptr< QgsRenderContext > scopedRc;
1496  if ( !context )
1497  {
1498  scopedRc.reset( new QgsRenderContext() );
1499  if ( f )
1500  scopedRc->expressionContext().setFeature( *f );
1501  }
1502  QgsRenderContext *rc = context ? context : scopedRc.get();
1503 
1504  QString wrapchr = wrapChar;
1505  int evalAutoWrapLength = autoWrapLength;
1506  double multilineH = mFormat.lineHeight();
1507  QgsTextFormat::TextOrientation orientation = mFormat.orientation();
1508 
1509  bool addDirSymb = mLineSettings.addDirectionSymbol();
1510  QString leftDirSymb = mLineSettings.leftDirectionSymbol();
1511  QString rightDirSymb = mLineSettings.rightDirectionSymbol();
1513 
1514  if ( f == mCurFeat ) // called internally, use any stored data defined values
1515  {
1516  if ( dataDefinedValues.contains( QgsPalLayerSettings::MultiLineWrapChar ) )
1517  {
1518  wrapchr = dataDefinedValues.value( QgsPalLayerSettings::MultiLineWrapChar ).toString();
1519  }
1520 
1521  if ( dataDefinedValues.contains( QgsPalLayerSettings::AutoWrapLength ) )
1522  {
1523  evalAutoWrapLength = dataDefinedValues.value( QgsPalLayerSettings::AutoWrapLength, evalAutoWrapLength ).toInt();
1524  }
1525 
1526  if ( dataDefinedValues.contains( QgsPalLayerSettings::MultiLineHeight ) )
1527  {
1528  multilineH = dataDefinedValues.value( QgsPalLayerSettings::MultiLineHeight ).toDouble();
1529  }
1530 
1531  if ( dataDefinedValues.contains( QgsPalLayerSettings::TextOrientation ) )
1532  {
1533  orientation = QgsTextRendererUtils::decodeTextOrientation( dataDefinedValues.value( QgsPalLayerSettings::TextOrientation ).toString() );
1534  }
1535 
1536  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbDraw ) )
1537  {
1538  addDirSymb = dataDefinedValues.value( QgsPalLayerSettings::DirSymbDraw ).toBool();
1539  }
1540 
1541  if ( addDirSymb )
1542  {
1543 
1544  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbLeft ) )
1545  {
1546  leftDirSymb = dataDefinedValues.value( QgsPalLayerSettings::DirSymbLeft ).toString();
1547  }
1548  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbRight ) )
1549  {
1550  rightDirSymb = dataDefinedValues.value( QgsPalLayerSettings::DirSymbRight ).toString();
1551  }
1552 
1553  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbPlacement ) )
1554  {
1555  placeDirSymb = static_cast< QgsLabelLineSettings::DirectionSymbolPlacement >( dataDefinedValues.value( QgsPalLayerSettings::DirSymbPlacement ).toInt() );
1556  }
1557 
1558  }
1559 
1560  }
1561  else // called externally with passed-in feature, evaluate data defined
1562  {
1563  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::MultiLineWrapChar ) )
1564  {
1566  wrapchr = mDataDefinedProperties.value( QgsPalLayerSettings::MultiLineWrapChar, rc->expressionContext(), wrapchr ).toString();
1567  }
1568 
1569  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::AutoWrapLength ) )
1570  {
1571  rc->expressionContext().setOriginalValueVariable( evalAutoWrapLength );
1572  evalAutoWrapLength = mDataDefinedProperties.value( QgsPalLayerSettings::AutoWrapLength, rc->expressionContext(), evalAutoWrapLength ).toInt();
1573  }
1574 
1575  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::MultiLineHeight ) )
1576  {
1577  rc->expressionContext().setOriginalValueVariable( multilineH );
1578  multilineH = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::MultiLineHeight, rc->expressionContext(), multilineH );
1579  }
1580 
1581  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::TextOrientation ) )
1582  {
1583  QString encoded = QgsTextRendererUtils::encodeTextOrientation( orientation );
1586  }
1587 
1588  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::DirSymbDraw ) )
1589  {
1590  rc->expressionContext().setOriginalValueVariable( addDirSymb );
1591  addDirSymb = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::DirSymbDraw, rc->expressionContext(), addDirSymb );
1592  }
1593 
1594  if ( addDirSymb ) // don't do extra evaluations if not adding a direction symbol
1595  {
1596  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::DirSymbLeft ) )
1597  {
1598  rc->expressionContext().setOriginalValueVariable( leftDirSymb );
1599  leftDirSymb = mDataDefinedProperties.value( QgsPalLayerSettings::DirSymbLeft, rc->expressionContext(), leftDirSymb ).toString();
1600  }
1601 
1602  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::DirSymbRight ) )
1603  {
1604  rc->expressionContext().setOriginalValueVariable( rightDirSymb );
1605  rightDirSymb = mDataDefinedProperties.value( QgsPalLayerSettings::DirSymbRight, rc->expressionContext(), rightDirSymb ).toString();
1606  }
1607 
1608  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::DirSymbPlacement ) )
1609  {
1610  rc->expressionContext().setOriginalValueVariable( static_cast< int >( placeDirSymb ) );
1611  placeDirSymb = static_cast< QgsLabelLineSettings::DirectionSymbolPlacement >( mDataDefinedProperties.valueAsInt( QgsPalLayerSettings::DirSymbPlacement, rc->expressionContext(), static_cast< int >( placeDirSymb ) ) );
1612  }
1613  }
1614  }
1615 
1616  if ( wrapchr.isEmpty() )
1617  {
1618  wrapchr = QStringLiteral( "\n" ); // default to new line delimiter
1619  }
1620 
1621  //consider the space needed for the direction symbol
1622  if ( addDirSymb && placement == Qgis::LabelPlacement::Line
1623  && ( !leftDirSymb.isEmpty() || !rightDirSymb.isEmpty() ) )
1624  {
1625  QString dirSym = leftDirSymb;
1626 
1627  if ( fm->horizontalAdvance( rightDirSymb ) > fm->horizontalAdvance( dirSym ) )
1628  dirSym = rightDirSymb;
1629 
1630  switch ( placeDirSymb )
1631  {
1633  textCopy.append( dirSym );
1634  break;
1635 
1638  textCopy.prepend( dirSym + QStringLiteral( "\n" ) );
1639  break;
1640  }
1641  }
1642 
1643  double w = 0.0, h = 0.0, rw = 0.0, rh = 0.0;
1644  double labelHeight = fm->ascent() + fm->descent(); // ignore +1 for baseline
1645 
1646  QStringList multiLineSplit;
1647 
1648  if ( document )
1649  {
1650  document->splitLines( wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap );
1651  multiLineSplit = document->toPlainText();
1652  }
1653  else
1654  {
1655  multiLineSplit = QgsPalLabeling::splitToLines( textCopy, wrapchr, evalAutoWrapLength, useMaxLineLengthForAutoWrap );
1656  }
1657 
1658  int lines = multiLineSplit.size();
1659 
1660  switch ( orientation )
1661  {
1663  {
1664  h += fm->height() + static_cast< double >( ( lines - 1 ) * labelHeight * multilineH );
1665 
1666  for ( const auto &line : multiLineSplit )
1667  {
1668  w = std::max( w, fm->horizontalAdvance( line ) );
1669  }
1670  break;
1671  }
1672 
1674  {
1675  double letterSpacing = mFormat.scaledFont( *context ).letterSpacing();
1676  double labelWidth = fm->maxWidth();
1677  w = labelWidth + ( lines - 1 ) * labelWidth * multilineH;
1678 
1679  int maxLineLength = 0;
1680  for ( const auto &line : multiLineSplit )
1681  {
1682  maxLineLength = std::max( maxLineLength, static_cast<int>( line.length() ) );
1683  }
1684  h = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1685  break;
1686  }
1687 
1689  {
1690  double widthHorizontal = 0.0;
1691  for ( const auto &line : multiLineSplit )
1692  {
1693  widthHorizontal = std::max( w, fm->horizontalAdvance( line ) );
1694  }
1695 
1696  double widthVertical = 0.0;
1697  double letterSpacing = mFormat.scaledFont( *context ).letterSpacing();
1698  double labelWidth = fm->maxWidth();
1699  widthVertical = labelWidth + ( lines - 1 ) * labelWidth * multilineH;
1700 
1701  double heightHorizontal = 0.0;
1702  heightHorizontal += fm->height() + static_cast< double >( ( lines - 1 ) * labelHeight * multilineH );
1703 
1704  double heightVertical = 0.0;
1705  int maxLineLength = 0;
1706  for ( const auto &line : multiLineSplit )
1707  {
1708  maxLineLength = std::max( maxLineLength, static_cast<int>( line.length() ) );
1709  }
1710  heightVertical = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1711 
1712  w = widthHorizontal;
1713  rw = heightVertical;
1714  h = heightHorizontal;
1715  rh = widthVertical;
1716  break;
1717  }
1718  }
1719 
1720 #if 0 // XXX strk
1721  QgsPointXY ptSize = xform->toMapCoordinatesF( w, h );
1722  labelX = std::fabs( ptSize.x() - ptZero.x() );
1723  labelY = std::fabs( ptSize.y() - ptZero.y() );
1724 #else
1725  double uPP = xform->mapUnitsPerPixel();
1726  labelX = w * uPP;
1727  labelY = h * uPP;
1728  if ( rotatedLabelX && rotatedLabelY )
1729  {
1730  *rotatedLabelX = rw * uPP;
1731  *rotatedLabelY = rh * uPP;
1732  }
1733 #endif
1734 }
1735 
1737 {
1738  registerFeatureWithDetails( f, context, QgsGeometry(), nullptr );
1739 }
1740 
1741 std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerFeatureWithDetails( const QgsFeature &f, QgsRenderContext &context, QgsGeometry obstacleGeometry, const QgsSymbol *symbol )
1742 {
1743  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
1744  mCurFeat = &f;
1745 
1746  // data defined is obstacle? calculate this first, to avoid wasting time working with obstacles we don't require
1747  bool isObstacle = mObstacleSettings.isObstacle();
1748  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::IsObstacle ) )
1749  isObstacle = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::IsObstacle, context.expressionContext(), isObstacle ); // default to layer default
1750 
1751  if ( !drawLabels )
1752  {
1753  if ( isObstacle )
1754  {
1755  return registerObstacleFeature( f, context, obstacleGeometry );
1756  }
1757  else
1758  {
1759  return nullptr;
1760  }
1761  }
1762 
1763  QgsFeature feature = f;
1765  {
1766  const QgsGeometry geometry = mGeometryGeneratorExpression.evaluate( &context.expressionContext() ).value<QgsGeometry>();
1767  if ( mGeometryGeneratorExpression.hasEvalError() )
1768  QgsMessageLog::logMessage( mGeometryGeneratorExpression.evalErrorString(), QObject::tr( "Labeling" ) );
1769 
1770  if ( obstacleGeometry.isNull() )
1771  {
1772  // if an explicit obstacle geometry hasn't been set, we must always use the original feature geometry
1773  // as the obstacle -- because we want to use the geometry which was used to render the symbology
1774  // for the feature as the obstacle for other layers' labels, NOT the generated geometry which is used
1775  // only to place labels for this layer.
1776  obstacleGeometry = f.geometry();
1777  }
1778 
1779  feature.setGeometry( geometry );
1780  }
1781 
1782  // store data defined-derived values for later adding to label feature for use during rendering
1783  dataDefinedValues.clear();
1784 
1785  // data defined show label? defaults to show label if not set
1786  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Show ) )
1787  {
1788  context.expressionContext().setOriginalValueVariable( true );
1789  if ( !mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Show, context.expressionContext(), true ) )
1790  {
1791  return nullptr;
1792  }
1793  }
1794 
1795  // data defined scale visibility?
1796  bool useScaleVisibility = scaleVisibility;
1797  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ScaleVisibility ) )
1798  useScaleVisibility = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::ScaleVisibility, context.expressionContext(), scaleVisibility );
1799 
1800  if ( useScaleVisibility )
1801  {
1802  // data defined min scale?
1803  double maxScale = maximumScale;
1804  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::MaximumScale ) )
1805  {
1807  maxScale = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::MaximumScale, context.expressionContext(), maxScale );
1808  }
1809 
1810  // scales closer than 1:1
1811  if ( maxScale < 0 )
1812  {
1813  maxScale = 1 / std::fabs( maxScale );
1814  }
1815 
1816  if ( !qgsDoubleNear( maxScale, 0.0 ) && context.rendererScale() < maxScale )
1817  {
1818  return nullptr;
1819  }
1820 
1821  // data defined min scale?
1822  double minScale = minimumScale;
1823  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::MinimumScale ) )
1824  {
1826  minScale = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::MinimumScale, context.expressionContext(), minScale );
1827  }
1828 
1829  // scales closer than 1:1
1830  if ( minScale < 0 )
1831  {
1832  minScale = 1 / std::fabs( minScale );
1833  }
1834 
1835  if ( !qgsDoubleNear( minScale, 0.0 ) && context.rendererScale() > minScale )
1836  {
1837  return nullptr;
1838  }
1839  }
1840 
1841  QFont labelFont = mFormat.font();
1842  // labelFont will be added to label feature for use during label painting
1843 
1844  // data defined font units?
1845  QgsUnitTypes::RenderUnit fontunits = mFormat.sizeUnit();
1846  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::FontSizeUnit, context.expressionContext() );
1847  if ( !exprVal.isNull() )
1848  {
1849  QString units = exprVal.toString();
1850  if ( !units.isEmpty() )
1851  {
1852  bool ok;
1854  if ( ok )
1855  fontunits = res;
1856  }
1857  }
1858 
1859  //data defined label size?
1860  double fontSize = mFormat.size();
1861  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Size ) )
1862  {
1863  context.expressionContext().setOriginalValueVariable( fontSize );
1864  fontSize = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::Size, context.expressionContext(), fontSize );
1865  }
1866  if ( fontSize <= 0.0 )
1867  {
1868  return nullptr;
1869  }
1870 
1871  int fontPixelSize = QgsTextRenderer::sizeToPixel( fontSize, context, fontunits, mFormat.sizeMapUnitScale() );
1872  // don't try to show font sizes less than 1 pixel (Qt complains)
1873  if ( fontPixelSize < 1 )
1874  {
1875  return nullptr;
1876  }
1877  labelFont.setPixelSize( fontPixelSize );
1878 
1879  // NOTE: labelFont now always has pixelSize set, so pointSize or pointSizeF might return -1
1880 
1881  // defined 'minimum/maximum pixel font size'?
1882  if ( fontunits == QgsUnitTypes::RenderMapUnits )
1883  {
1884  if ( mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::FontLimitPixel, context.expressionContext(), fontLimitPixelSize ) )
1885  {
1886  int fontMinPixel = mDataDefinedProperties.valueAsInt( QgsPalLayerSettings::FontMinPixel, context.expressionContext(), fontMinPixelSize );
1887  int fontMaxPixel = mDataDefinedProperties.valueAsInt( QgsPalLayerSettings::FontMaxPixel, context.expressionContext(), fontMaxPixelSize );
1888 
1889  if ( fontMinPixel > labelFont.pixelSize() || labelFont.pixelSize() > fontMaxPixel )
1890  {
1891  return nullptr;
1892  }
1893  }
1894  }
1895 
1896  // NOTE: the following parsing functions calculate and store any data defined values for later use in QgsPalLabeling::drawLabeling
1897  // this is done to provide clarity, and because such parsing is not directly related to PAL feature registration calculations
1898 
1899  // calculate rest of font attributes and store any data defined values
1900  // this is done here for later use in making label backgrounds part of collision management (when implemented)
1901  labelFont.setCapitalization( QFont::MixedCase ); // reset this - we don't use QFont's handling as it breaks with curved labels
1902 
1903  parseTextStyle( labelFont, fontunits, context );
1904  if ( mDataDefinedProperties.hasActiveProperties() )
1905  {
1906  parseTextFormatting( context );
1907  parseTextBuffer( context );
1908  parseTextMask( context );
1909  parseShapeBackground( context );
1910  parseDropShadow( context );
1911  }
1912 
1913  QString labelText;
1914 
1915  // Check to see if we are a expression string.
1916  if ( isExpression )
1917  {
1919  if ( exp->hasParserError() )
1920  {
1921  QgsDebugMsgLevel( QStringLiteral( "Expression parser error:%1" ).arg( exp->parserErrorString() ), 4 );
1922  return nullptr;
1923  }
1924 
1925  QVariant result = exp->evaluate( &context.expressionContext() ); // expression prepared in QgsPalLabeling::prepareLayer()
1926  if ( exp->hasEvalError() )
1927  {
1928  QgsDebugMsgLevel( QStringLiteral( "Expression parser eval error:%1" ).arg( exp->evalErrorString() ), 4 );
1929  return nullptr;
1930  }
1931  labelText = result.isNull() ? QString() : result.toString();
1932  }
1933  else
1934  {
1935  const QVariant &v = feature.attribute( fieldIndex );
1936  labelText = v.isNull() ? QString() : v.toString();
1937  }
1938 
1939  // apply text replacements
1940  if ( useSubstitutions )
1941  {
1942  labelText = substitutions.process( labelText );
1943  }
1944 
1945  // apply capitalization
1946  Qgis::Capitalization capitalization = mFormat.capitalization();
1947  // maintain API - capitalization may have been set in textFont
1948  if ( capitalization == Qgis::Capitalization::MixedCase && mFormat.font().capitalization() != QFont::MixedCase )
1949  {
1950  capitalization = static_cast< Qgis::Capitalization >( mFormat.font().capitalization() );
1951  }
1952  // data defined font capitalization?
1953  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontCase ) )
1954  {
1955  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::FontCase, context.expressionContext() );
1956  if ( !exprVal.isNull() )
1957  {
1958  QString fcase = exprVal.toString().trimmed();
1959  QgsDebugMsgLevel( QStringLiteral( "exprVal FontCase:%1" ).arg( fcase ), 4 );
1960 
1961  if ( !fcase.isEmpty() )
1962  {
1963  if ( fcase.compare( QLatin1String( "NoChange" ), Qt::CaseInsensitive ) == 0 )
1964  {
1965  capitalization = Qgis::Capitalization::MixedCase;
1966  }
1967  else if ( fcase.compare( QLatin1String( "Upper" ), Qt::CaseInsensitive ) == 0 )
1968  {
1969  capitalization = Qgis::Capitalization::AllUppercase;
1970  }
1971  else if ( fcase.compare( QLatin1String( "Lower" ), Qt::CaseInsensitive ) == 0 )
1972  {
1973  capitalization = Qgis::Capitalization::AllLowercase;
1974  }
1975  else if ( fcase.compare( QLatin1String( "Capitalize" ), Qt::CaseInsensitive ) == 0 )
1976  {
1978  }
1979  else if ( fcase.compare( QLatin1String( "Title" ), Qt::CaseInsensitive ) == 0 )
1980  {
1981  capitalization = Qgis::Capitalization::TitleCase;
1982  }
1983 #if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
1984  else if ( fcase.compare( QLatin1String( "SmallCaps" ), Qt::CaseInsensitive ) == 0 )
1985  {
1986  capitalization = Qgis::Capitalization::SmallCaps;
1987  }
1988  else if ( fcase.compare( QLatin1String( "AllSmallCaps" ), Qt::CaseInsensitive ) == 0 )
1989  {
1990  capitalization = Qgis::Capitalization::AllSmallCaps;
1991  }
1992 #endif
1993  }
1994  }
1995  }
1996  labelText = QgsStringUtils::capitalize( labelText, capitalization );
1997 
1998  // format number if label text is coercible to a number
1999  bool evalFormatNumbers = formatNumbers;
2000  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::NumFormat ) )
2001  {
2002  evalFormatNumbers = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::NumFormat, context.expressionContext(), evalFormatNumbers );
2003  }
2004  if ( evalFormatNumbers )
2005  {
2006  // data defined decimal places?
2007  int decimalPlaces = mDataDefinedProperties.valueAsInt( QgsPalLayerSettings::NumDecimals, context.expressionContext(), decimals );
2008  if ( decimalPlaces <= 0 ) // needs to be positive
2009  decimalPlaces = decimals;
2010 
2011  // data defined plus sign?
2012  bool signPlus = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::NumPlusSign, context.expressionContext(), plusSign );
2013 
2014  QVariant textV( labelText );
2015  bool ok;
2016  double d = textV.toDouble( &ok );
2017  if ( ok )
2018  {
2019  QString numberFormat;
2020  if ( d > 0 && signPlus )
2021  {
2022  numberFormat.append( '+' );
2023  }
2024  numberFormat.append( "%1" );
2025  labelText = numberFormat.arg( d, 0, 'f', decimalPlaces );
2026  }
2027  }
2028 
2029  // NOTE: this should come AFTER any option that affects font metrics
2030  std::unique_ptr<QFontMetricsF> labelFontMetrics( new QFontMetricsF( labelFont ) );
2031  double labelX, labelY, rotatedLabelX, rotatedLabelY; // will receive label size
2032 
2033  QgsTextDocument doc;
2034  if ( format().allowHtmlFormatting() )
2035  doc = QgsTextDocument::fromHtml( QStringList() << labelText );
2036 
2037  // also applies the line split to doc!
2038  calculateLabelSize( labelFontMetrics.get(), labelText, labelX, labelY, mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, format().allowHtmlFormatting() ? &doc : nullptr );
2039 
2040  // maximum angle between curved label characters (hardcoded defaults used in QGIS <2.0)
2041  //
2042  double maxcharanglein = 20.0; // range 20.0-60.0
2043  double maxcharangleout = -20.0; // range 20.0-95.0
2044 
2046  {
2047  maxcharanglein = maxCurvedCharAngleIn;
2048  maxcharangleout = maxCurvedCharAngleOut;
2049 
2050  //data defined maximum angle between curved label characters?
2051  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::CurvedCharAngleInOut ) )
2052  {
2053  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::CurvedCharAngleInOut, context.expressionContext() );
2054  bool ok = false;
2055  const QPointF maxcharanglePt = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
2056  if ( ok )
2057  {
2058  maxcharanglein = std::clamp( static_cast< double >( maxcharanglePt.x() ), 20.0, 60.0 );
2059  maxcharangleout = std::clamp( static_cast< double >( maxcharanglePt.y() ), 20.0, 95.0 );
2060  }
2061  }
2062  // make sure maxcharangleout is always negative
2063  maxcharangleout = -( std::fabs( maxcharangleout ) );
2064  }
2065 
2066  // data defined centroid whole or clipped?
2067  bool wholeCentroid = centroidWhole;
2068  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::CentroidWhole ) )
2069  {
2070  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::CentroidWhole, context.expressionContext() );
2071  if ( !exprVal.isNull() )
2072  {
2073  QString str = exprVal.toString().trimmed();
2074  QgsDebugMsgLevel( QStringLiteral( "exprVal CentroidWhole:%1" ).arg( str ), 4 );
2075 
2076  if ( !str.isEmpty() )
2077  {
2078  if ( str.compare( QLatin1String( "Visible" ), Qt::CaseInsensitive ) == 0 )
2079  {
2080  wholeCentroid = false;
2081  }
2082  else if ( str.compare( QLatin1String( "Whole" ), Qt::CaseInsensitive ) == 0 )
2083  {
2084  wholeCentroid = true;
2085  }
2086  }
2087  }
2088  }
2089 
2090  QgsGeometry geom = feature.geometry();
2091  if ( geom.isNull() )
2092  {
2093  return nullptr;
2094  }
2095 
2096  // simplify?
2097  const QgsVectorSimplifyMethod &simplifyMethod = context.vectorSimplifyMethod();
2098  std::unique_ptr<QgsGeometry> scopedClonedGeom;
2099  if ( simplifyMethod.simplifyHints() != QgsVectorSimplifyMethod::NoSimplification && simplifyMethod.forceLocalOptimization() )
2100  {
2101  unsigned int simplifyHints = simplifyMethod.simplifyHints() | QgsMapToPixelSimplifier::SimplifyEnvelope;
2103  QgsMapToPixelSimplifier simplifier( simplifyHints, simplifyMethod.tolerance(), simplifyAlgorithm );
2104  geom = simplifier.simplify( geom );
2105  }
2106 
2107  if ( !context.featureClipGeometry().isEmpty() )
2108  {
2109  const QgsWkbTypes::GeometryType expectedType = geom.type();
2110  geom = geom.intersection( context.featureClipGeometry() );
2111  geom.convertGeometryCollectionToSubclass( expectedType );
2112  }
2113 
2114  // whether we're going to create a centroid for polygon
2115  bool centroidPoly = ( ( placement == Qgis::LabelPlacement::AroundPoint
2117  && geom.type() == QgsWkbTypes::PolygonGeometry );
2118 
2119  // CLIP the geometry if it is bigger than the extent
2120  // don't clip if centroid is requested for whole feature
2121  bool doClip = false;
2122  if ( !centroidPoly || !wholeCentroid )
2123  {
2124  doClip = true;
2125  }
2126 
2127 
2128  QgsLabeling::PolygonPlacementFlags polygonPlacement = mPolygonPlacementFlags;
2129  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::PolygonLabelOutside ) )
2130  {
2131  const QVariant dataDefinedOutside = mDataDefinedProperties.value( QgsPalLayerSettings::PolygonLabelOutside, context.expressionContext() );
2132  if ( !dataDefinedOutside.isNull() )
2133  {
2134  if ( dataDefinedOutside.type() == QVariant::String )
2135  {
2136  const QString value = dataDefinedOutside.toString().trimmed();
2137  if ( value.compare( QLatin1String( "force" ), Qt::CaseInsensitive ) == 0 )
2138  {
2139  // forced outside placement -- remove inside flag, add outside flag
2140  polygonPlacement &= ~static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon );
2141  polygonPlacement |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
2142  }
2143  else if ( value.compare( QLatin1String( "yes" ), Qt::CaseInsensitive ) == 0 )
2144  {
2145  // permit outside placement
2146  polygonPlacement |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
2147  }
2148  else if ( value.compare( QLatin1String( "no" ), Qt::CaseInsensitive ) == 0 )
2149  {
2150  // block outside placement
2151  polygonPlacement &= ~static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon );
2152  }
2153  }
2154  else
2155  {
2156  if ( dataDefinedOutside.toBool() )
2157  {
2158  // permit outside placement
2159  polygonPlacement |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
2160  }
2161  else
2162  {
2163  // block outside placement
2164  polygonPlacement &= ~static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon );
2165  }
2166  }
2167  }
2168  }
2169 
2170  QgsLabelLineSettings lineSettings = mLineSettings;
2171  lineSettings.updateDataDefinedProperties( mDataDefinedProperties, context.expressionContext() );
2172 
2173  if ( geom.type() == QgsWkbTypes::LineGeometry )
2174  {
2175  switch ( lineSettings.anchorClipping() )
2176  {
2178  break;
2179 
2181  doClip = false;
2182  break;
2183  }
2184  }
2185 
2186  // if using fitInPolygonOnly option, generate the permissible zone (must happen before geometry is modified - e.g.,
2187  // as a result of using perimeter based labeling and the geometry is converted to a boundary)
2188  // note that we also force this if we are permitting labels to be placed outside of polygons too!
2189  QgsGeometry permissibleZone;
2190  if ( geom.type() == QgsWkbTypes::PolygonGeometry && ( fitInPolygonOnly || polygonPlacement & QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon ) )
2191  {
2192  permissibleZone = geom;
2193  if ( QgsPalLabeling::geometryRequiresPreparation( permissibleZone, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) )
2194  {
2195  permissibleZone = QgsPalLabeling::prepareGeometry( permissibleZone, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() );
2196  }
2197  }
2198 
2199  // if using perimeter based labeling for polygons, get the polygon's
2200  // linear boundary and use that for the label geometry
2201  if ( ( geom.type() == QgsWkbTypes::PolygonGeometry )
2203  {
2204  geom = QgsGeometry( geom.constGet()->boundary() );
2205  }
2206 
2207  geos::unique_ptr geos_geom_clone;
2209  {
2210  geom = QgsPalLabeling::prepareGeometry( geom, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() );
2211 
2212  if ( geom.isEmpty() )
2213  return nullptr;
2214  }
2215  geos_geom_clone = QgsGeos::asGeos( geom );
2216 
2218  {
2219  if ( !obstacleGeometry.isNull() && QgsPalLabeling::geometryRequiresPreparation( obstacleGeometry, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) )
2220  {
2221  obstacleGeometry = QgsGeometry( QgsPalLabeling::prepareGeometry( obstacleGeometry, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) );
2222  }
2223  }
2224 
2225  QgsLabelThinningSettings featureThinningSettings = mThinningSettings;
2226  featureThinningSettings.updateDataDefinedProperties( mDataDefinedProperties, context.expressionContext() );
2227 
2228  double minimumSize = 0.0;
2229  if ( featureThinningSettings.minimumFeatureSize() > 0 )
2230  {
2231  // for minimum feature size on merged lines, we need to delay the filtering after the merging occurred in PAL
2232  if ( geom.type() == QgsWkbTypes::LineGeometry && mLineSettings.mergeLines() )
2233  {
2234  minimumSize = context.convertToMapUnits( featureThinningSettings.minimumFeatureSize(), QgsUnitTypes::RenderMillimeters );
2235  }
2236  else
2237  {
2238  if ( !checkMinimumSizeMM( context, geom, featureThinningSettings.minimumFeatureSize() ) )
2239  return nullptr;
2240  }
2241  }
2242 
2243  if ( !geos_geom_clone )
2244  return nullptr; // invalid geometry
2245 
2246  // likelihood exists label will be registered with PAL and may be drawn
2247  // check if max number of features to label (already registered with PAL) has been reached
2248  // Debug output at end of QgsPalLabeling::drawLabeling(), when deleting temp geometries
2249  if ( featureThinningSettings.limitNumberOfLabelsEnabled() )
2250  {
2251  if ( !featureThinningSettings.maximumNumberLabels() )
2252  {
2253  return nullptr;
2254  }
2255  if ( mFeatsRegPal >= featureThinningSettings.maximumNumberLabels() )
2256  {
2257  return nullptr;
2258  }
2259 
2260  int divNum = static_cast< int >( ( static_cast< double >( mFeaturesToLabel ) / featureThinningSettings.maximumNumberLabels() ) + 0.5 ); // NOLINT
2261  if ( divNum && ( mFeatsRegPal == static_cast< int >( mFeatsSendingToPal / divNum ) ) )
2262  {
2263  mFeatsSendingToPal += 1;
2264  if ( divNum && mFeatsSendingToPal % divNum )
2265  {
2266  return nullptr;
2267  }
2268  }
2269  }
2270 
2271  //data defined position / alignment / rotation?
2272  bool layerDefinedRotation = false;
2273  bool dataDefinedRotation = false;
2274  double xPos = 0.0, yPos = 0.0, angle = 0.0;
2275  double quadOffsetX = 0.0, quadOffsetY = 0.0;
2276  double offsetX = 0.0, offsetY = 0.0;
2277  QgsPointXY anchorPosition;
2278 
2280  {
2281  anchorPosition = geom.centroid().asPoint();
2282  }
2283  //x/y shift in case of alignment
2284  double xdiff = 0.0;
2285  double ydiff = 0.0;
2286 
2287  //data defined quadrant offset?
2288  bool ddFixedQuad = false;
2290  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::OffsetQuad ) )
2291  {
2292  context.expressionContext().setOriginalValueVariable( static_cast< int >( quadOff ) );
2293  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::OffsetQuad, context.expressionContext() );
2294  if ( !exprVal.isNull() )
2295  {
2296  bool ok;
2297  int quadInt = exprVal.toInt( &ok );
2298  if ( ok && 0 <= quadInt && quadInt <= 8 )
2299  {
2300  quadOff = static_cast< Qgis::LabelQuadrantPosition >( quadInt );
2301  ddFixedQuad = true;
2302  }
2303  }
2304  }
2305 
2306  // adjust quadrant offset of labels
2307  switch ( quadOff )
2308  {
2309  case Qgis::LabelQuadrantPosition::AboveLeft:
2310  quadOffsetX = -1.0;
2311  quadOffsetY = 1.0;
2312  break;
2313  case Qgis::LabelQuadrantPosition::Above:
2314  quadOffsetX = 0.0;
2315  quadOffsetY = 1.0;
2316  break;
2317  case Qgis::LabelQuadrantPosition::AboveRight:
2318  quadOffsetX = 1.0;
2319  quadOffsetY = 1.0;
2320  break;
2321  case Qgis::LabelQuadrantPosition::Left:
2322  quadOffsetX = -1.0;
2323  quadOffsetY = 0.0;
2324  break;
2325  case Qgis::LabelQuadrantPosition::Right:
2326  quadOffsetX = 1.0;
2327  quadOffsetY = 0.0;
2328  break;
2329  case Qgis::LabelQuadrantPosition::BelowLeft:
2330  quadOffsetX = -1.0;
2331  quadOffsetY = -1.0;
2332  break;
2333  case Qgis::LabelQuadrantPosition::Below:
2334  quadOffsetX = 0.0;
2335  quadOffsetY = -1.0;
2336  break;
2337  case Qgis::LabelQuadrantPosition::BelowRight:
2338  quadOffsetX = 1.0;
2339  quadOffsetY = -1.0;
2340  break;
2341  case Qgis::LabelQuadrantPosition::Over:
2342  break;
2343  }
2344 
2345  //data defined label offset?
2346  double xOff = xOffset;
2347  double yOff = yOffset;
2348  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::OffsetXY ) )
2349  {
2351  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::OffsetXY, context.expressionContext() );
2352  bool ok = false;
2353  const QPointF ddOffPt = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
2354  if ( ok )
2355  {
2356  xOff = ddOffPt.x();
2357  yOff = ddOffPt.y();
2358  }
2359  }
2360 
2361  // data defined label offset units?
2363  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::OffsetUnits ) )
2364  {
2365  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::OffsetUnits, context.expressionContext() );
2366  if ( !exprVal.isNull() )
2367  {
2368  QString units = exprVal.toString().trimmed();
2369  if ( !units.isEmpty() )
2370  {
2371  bool ok = false;
2372  QgsUnitTypes::RenderUnit decodedUnits = QgsUnitTypes::decodeRenderUnit( units, &ok );
2373  if ( ok )
2374  {
2375  offUnit = decodedUnits;
2376  }
2377  }
2378  }
2379  }
2380 
2381  // adjust offset of labels to match chosen unit and map scale
2382  // offsets match those of symbology: -x = left, -y = up
2383  offsetX = context.convertToMapUnits( xOff, offUnit, labelOffsetMapUnitScale );
2384  // must be negative to match symbology offset direction
2385  offsetY = context.convertToMapUnits( -yOff, offUnit, labelOffsetMapUnitScale );
2386 
2387  // layer defined rotation?
2388  if ( !qgsDoubleNear( angleOffset, 0.0 ) )
2389  {
2390  layerDefinedRotation = true;
2391  angle = ( 360 - angleOffset ) * M_PI / 180; // convert to radians counterclockwise
2392  }
2393 
2394  const QgsMapToPixel &m2p = context.mapToPixel();
2395  //data defined rotation?
2396  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::LabelRotation ) )
2397  {
2399  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::LabelRotation, context.expressionContext() );
2400  if ( !exprVal.isNull() )
2401  {
2402  bool ok;
2403  const double rotation = exprVal.toDouble( &ok );
2404  if ( ok )
2405  {
2406  dataDefinedRotation = true;
2407 
2408  double rotationDegrees = rotation * QgsUnitTypes::fromUnitToUnitFactor( mRotationUnit,
2410 
2411  // TODO: add setting to disable having data defined rotation follow
2412  // map rotation ?
2413  rotationDegrees += m2p.mapRotation();
2414  angle = ( 360 - rotationDegrees ) * M_PI / 180.0;
2415  }
2416  }
2417  }
2418 
2419  bool hasDataDefinedPosition = false;
2420  {
2421  bool ddPosition = false;
2422 
2423  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::PositionX )
2424  && mDataDefinedProperties.isActive( QgsPalLayerSettings::PositionY ) )
2425  {
2426  const QVariant xPosProperty = mDataDefinedProperties.value( QgsPalLayerSettings::PositionX, context.expressionContext() );
2427  const QVariant yPosProperty = mDataDefinedProperties.value( QgsPalLayerSettings::PositionY, context.expressionContext() );
2428  if ( !xPosProperty.isNull()
2429  && !yPosProperty.isNull() )
2430  {
2431  ddPosition = true;
2432 
2433  bool ddXPos = false, ddYPos = false;
2434  xPos = xPosProperty.toDouble( &ddXPos );
2435  yPos = yPosProperty.toDouble( &ddYPos );
2436  if ( ddXPos && ddYPos )
2437  hasDataDefinedPosition = true;
2438  }
2439  }
2440  else if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::PositionPoint ) )
2441  {
2442  const QVariant pointPosProperty = mDataDefinedProperties.value( QgsPalLayerSettings::PositionPoint, context.expressionContext() );
2443  if ( !pointPosProperty.isNull() )
2444  {
2445  ddPosition = true;
2446 
2447  QgsPoint point;
2448  if ( pointPosProperty.canConvert<QgsReferencedGeometry>() )
2449  {
2450  QgsReferencedGeometry referencedGeometryPoint = pointPosProperty.value<QgsReferencedGeometry>();
2451  point = QgsPoint( referencedGeometryPoint.asPoint() );
2452 
2453  if ( !referencedGeometryPoint.isNull()
2454  && ct.sourceCrs() != referencedGeometryPoint.crs() )
2455  QgsMessageLog::logMessage( QObject::tr( "Label position geometry is not in layer coordinates reference system. Layer CRS: '%1', Geometry CRS: '%2'" ).arg( ct.sourceCrs().userFriendlyIdentifier(), referencedGeometryPoint.crs().userFriendlyIdentifier() ), QObject::tr( "Labeling" ), Qgis::Warning );
2456  }
2457  else if ( pointPosProperty.canConvert<QgsGeometry>() )
2458  {
2459  point = QgsPoint( pointPosProperty.value<QgsGeometry>().asPoint() );
2460  }
2461 
2462  if ( !point.isEmpty() )
2463  {
2464  hasDataDefinedPosition = true;
2465 
2466  xPos = point.x();
2467  yPos = point.y();
2468  }
2469  }
2470  }
2471 
2472  if ( ddPosition )
2473  {
2474  //data defined position. But field values could be NULL -> positions will be generated by PAL
2475  if ( hasDataDefinedPosition )
2476  {
2477  // layer rotation set, but don't rotate pinned labels unless data defined
2478  if ( layerDefinedRotation && !dataDefinedRotation )
2479  {
2480  angle = 0.0;
2481  }
2482 
2483  //horizontal alignment
2484  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Hali ) )
2485  {
2486  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Hali, context.expressionContext() );
2487  if ( !exprVal.isNull() )
2488  {
2489  QString haliString = exprVal.toString();
2490  if ( haliString.compare( QLatin1String( "Center" ), Qt::CaseInsensitive ) == 0 )
2491  {
2492  xdiff -= labelX / 2.0;
2493  }
2494  else if ( haliString.compare( QLatin1String( "Right" ), Qt::CaseInsensitive ) == 0 )
2495  {
2496  xdiff -= labelX;
2497  }
2498  }
2499  }
2500 
2501  //vertical alignment
2502  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Vali ) )
2503  {
2504  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Vali, context.expressionContext() );
2505  if ( !exprVal.isNull() )
2506  {
2507  QString valiString = exprVal.toString();
2508  if ( valiString.compare( QLatin1String( "Bottom" ), Qt::CaseInsensitive ) != 0 )
2509  {
2510  if ( valiString.compare( QLatin1String( "Top" ), Qt::CaseInsensitive ) == 0 )
2511  {
2512  ydiff -= labelY;
2513  }
2514  else
2515  {
2516  double descentRatio = labelFontMetrics->descent() / labelFontMetrics->height();
2517  if ( valiString.compare( QLatin1String( "Base" ), Qt::CaseInsensitive ) == 0 )
2518  {
2519  ydiff -= labelY * descentRatio;
2520  }
2521  else //'Cap' or 'Half'
2522  {
2523  double capHeightRatio = ( labelFontMetrics->boundingRect( 'H' ).height() + 1 + labelFontMetrics->descent() ) / labelFontMetrics->height();
2524  ydiff -= labelY * capHeightRatio;
2525  if ( valiString.compare( QLatin1String( "Half" ), Qt::CaseInsensitive ) == 0 )
2526  {
2527  ydiff += labelY * ( capHeightRatio - descentRatio ) / 2.0;
2528  }
2529  }
2530  }
2531  }
2532  }
2533  }
2534 
2535  if ( dataDefinedRotation )
2536  {
2537  //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center
2538  double xd = xdiff * std::cos( angle ) - ydiff * std::sin( angle );
2539  double yd = xdiff * std::sin( angle ) + ydiff * std::cos( angle );
2540  xdiff = xd;
2541  ydiff = yd;
2542  }
2543 
2544  //project xPos and yPos from layer to map CRS, handle rotation
2545  QgsGeometry ddPoint( new QgsPoint( xPos, yPos ) );
2546  if ( QgsPalLabeling::geometryRequiresPreparation( ddPoint, context, ct ) )
2547  {
2548  ddPoint = QgsPalLabeling::prepareGeometry( ddPoint, context, ct );
2549  if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( ddPoint.constGet() ) )
2550  {
2551  xPos = point->x();
2552  yPos = point->y();
2553  anchorPosition = QgsPointXY( xPos, yPos );
2554  }
2555  else
2556  {
2557  QgsMessageLog::logMessage( QObject::tr( "Invalid data defined label position (%1, %2)" ).arg( xPos ).arg( yPos ), QObject::tr( "Labeling" ) );
2558  hasDataDefinedPosition = false;
2559  }
2560  }
2561  else
2562  {
2563  anchorPosition = QgsPointXY( xPos, yPos );
2564  }
2565 
2566  xPos += xdiff;
2567  yPos += ydiff;
2568  }
2569  else
2570  {
2571  anchorPosition = QgsPointXY( xPos, yPos );
2572  }
2573  }
2574  }
2575 
2576  // data defined always show?
2577  bool alwaysShow = false;
2578  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::AlwaysShow ) )
2579  {
2580  alwaysShow = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::AlwaysShow, context.expressionContext(), false );
2581  }
2582 
2583  // set repeat distance
2584  // data defined repeat distance?
2585  double repeatDist = repeatDistance;
2586  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::RepeatDistance ) )
2587  {
2588  context.expressionContext().setOriginalValueVariable( repeatDist );
2589  repeatDist = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::RepeatDistance, context.expressionContext(), repeatDist );
2590  }
2591 
2592  // data defined label-repeat distance units?
2594  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::RepeatDistanceUnit ) )
2595  {
2596  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::RepeatDistanceUnit, context.expressionContext() );
2597  if ( !exprVal.isNull() )
2598  {
2599  QString units = exprVal.toString().trimmed();
2600  if ( !units.isEmpty() )
2601  {
2602  bool ok = false;
2603  QgsUnitTypes::RenderUnit decodedUnits = QgsUnitTypes::decodeRenderUnit( units, &ok );
2604  if ( ok )
2605  {
2606  repeatUnits = decodedUnits;
2607  }
2608  }
2609  }
2610  }
2611 
2612  if ( !qgsDoubleNear( repeatDist, 0.0 ) )
2613  {
2614  if ( repeatUnits != QgsUnitTypes::RenderMapUnits )
2615  {
2616  repeatDist = context.convertToMapUnits( repeatDist, repeatUnits, repeatDistanceMapUnitScale );
2617  }
2618  }
2619 
2620  // overrun distance
2621  double overrunDistanceEval = lineSettings.overrunDistance();
2622  if ( !qgsDoubleNear( overrunDistanceEval, 0.0 ) )
2623  {
2624  overrunDistanceEval = context.convertToMapUnits( overrunDistanceEval, lineSettings.overrunDistanceUnit(), lineSettings.overrunDistanceMapUnitScale() );
2625  }
2626 
2627  // we smooth out the overrun label extensions by 1 mm, to avoid little jaggies right at the start or end of the lines
2628  // causing the overrun extension to extend out in an undesirable direction. This is hard coded, we don't want to overload
2629  // users with options they likely don't need to see...
2630  const double overrunSmoothDist = context.convertToMapUnits( 1, QgsUnitTypes::RenderMillimeters );
2631 
2632  bool labelAll = labelPerPart && !hasDataDefinedPosition;
2633  if ( !hasDataDefinedPosition )
2634  {
2635  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::LabelAllParts ) )
2636  {
2638  labelAll = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::LabelAllParts, context.expressionContext(), labelPerPart );
2639  }
2640  }
2641 
2642  // feature to the layer
2643  std::unique_ptr< QgsTextLabelFeature > labelFeature = std::make_unique< QgsTextLabelFeature>( feature.id(), std::move( geos_geom_clone ), QSizeF( labelX, labelY ) );
2644  labelFeature->setAnchorPosition( anchorPosition );
2645  labelFeature->setFeature( feature );
2646  labelFeature->setSymbol( symbol );
2647  labelFeature->setDocument( doc );
2648  if ( !qgsDoubleNear( rotatedLabelX, 0.0 ) && !qgsDoubleNear( rotatedLabelY, 0.0 ) )
2649  labelFeature->setRotatedSize( QSizeF( rotatedLabelX, rotatedLabelY ) );
2650  mFeatsRegPal++;
2651 
2652  labelFeature->setHasFixedPosition( hasDataDefinedPosition );
2653  labelFeature->setFixedPosition( QgsPointXY( xPos, yPos ) );
2654  // use layer-level defined rotation, but not if position fixed
2655  labelFeature->setHasFixedAngle( dataDefinedRotation || ( !hasDataDefinedPosition && !qgsDoubleNear( angle, 0.0 ) ) );
2656  labelFeature->setFixedAngle( angle );
2657  labelFeature->setQuadOffset( QPointF( quadOffsetX, quadOffsetY ) );
2658  labelFeature->setPositionOffset( QgsPointXY( offsetX, offsetY ) );
2659  labelFeature->setOffsetType( offsetType );
2660  labelFeature->setAlwaysShow( alwaysShow );
2661  labelFeature->setRepeatDistance( repeatDist );
2662  labelFeature->setLabelText( labelText );
2663  labelFeature->setPermissibleZone( permissibleZone );
2664  labelFeature->setOverrunDistance( overrunDistanceEval );
2665  labelFeature->setOverrunSmoothDistance( overrunSmoothDist );
2666  labelFeature->setLineAnchorPercent( lineSettings.lineAnchorPercent() );
2667  labelFeature->setLineAnchorType( lineSettings.anchorType() );
2668  labelFeature->setLineAnchorTextPoint( lineSettings.anchorTextPoint() );
2669  labelFeature->setLabelAllParts( labelAll );
2670  labelFeature->setOriginalFeatureCrs( context.coordinateTransform().sourceCrs() );
2671  labelFeature->setMinimumSize( minimumSize );
2672  if ( geom.type() == QgsWkbTypes::PointGeometry && !obstacleGeometry.isNull() )
2673  {
2674  //register symbol size
2675  labelFeature->setSymbolSize( QSizeF( obstacleGeometry.boundingBox().width(),
2676  obstacleGeometry.boundingBox().height() ) );
2677  }
2678 
2679  //set label's visual margin so that top visual margin is the leading, and bottom margin is the font's descent
2680  //this makes labels align to the font's baseline or highest character
2681  double topMargin = std::max( 0.25 * labelFontMetrics->ascent(), 0.0 );
2682  double bottomMargin = 1.0 + labelFontMetrics->descent();
2683  QgsMargins vm( 0.0, topMargin, 0.0, bottomMargin );
2684  vm *= xform->mapUnitsPerPixel();
2685  labelFeature->setVisualMargin( vm );
2686 
2687  // store the label's calculated font for later use during painting
2688  QgsDebugMsgLevel( QStringLiteral( "PAL font stored definedFont: %1, Style: %2" ).arg( labelFont.toString(), labelFont.styleName() ), 4 );
2689  labelFeature->setDefinedFont( labelFont );
2690  labelFeature->setFontMetrics( *labelFontMetrics );
2691 
2692  labelFeature->setMaximumCharacterAngleInside( std::clamp( maxcharanglein, 20.0, 60.0 ) * M_PI / 180 );
2693  labelFeature->setMaximumCharacterAngleOutside( std::clamp( maxcharangleout, -95.0, -20.0 ) * M_PI / 180 );
2694  switch ( placement )
2695  {
2703  // these placements don't require text metrics
2704  break;
2705 
2708  labelFeature->setTextMetrics( QgsTextLabelFeature::calculateTextMetrics( xform, *labelFontMetrics, labelFont.letterSpacing(), labelFont.wordSpacing(), labelText, format().allowHtmlFormatting() ? &doc : nullptr ) );
2709  break;
2710  }
2711 
2712  // for labelFeature the LabelInfo is passed to feat when it is registered
2713 
2714  // TODO: allow layer-wide feature dist in PAL...?
2715 
2716  // data defined label-feature distance?
2717  double distance = dist;
2718  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::LabelDistance ) )
2719  {
2720  context.expressionContext().setOriginalValueVariable( distance );
2721  distance = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::LabelDistance, context.expressionContext(), distance );
2722  }
2723 
2724  // data defined label-feature distance units?
2726  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::DistanceUnits ) )
2727  {
2728  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::DistanceUnits, context.expressionContext() );
2729  if ( !exprVal.isNull() )
2730  {
2731  QString units = exprVal.toString().trimmed();
2732  QgsDebugMsgLevel( QStringLiteral( "exprVal DistanceUnits:%1" ).arg( units ), 4 );
2733  if ( !units.isEmpty() )
2734  {
2735  bool ok = false;
2736  QgsUnitTypes::RenderUnit decodedUnits = QgsUnitTypes::decodeRenderUnit( units, &ok );
2737  if ( ok )
2738  {
2739  distUnit = decodedUnits;
2740  }
2741  }
2742  }
2743  }
2744  distance = context.convertToPainterUnits( distance, distUnit, distMapUnitScale );
2745 
2746  // when using certain placement modes, we force a tiny minimum distance. This ensures that
2747  // candidates are created just offset from a border and avoids candidates being incorrectly flagged as colliding with neighbours
2751  {
2752  distance = ( distance < 0 ? -1 : 1 ) * std::max( std::fabs( distance ), 1.0 );
2753  }
2758  placement == Qgis::LabelPlacement::Free ) && polygonPlacement & QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon ) )
2759  {
2760  distance = std::max( distance, 2.0 );
2761  }
2762 
2763  if ( !qgsDoubleNear( distance, 0.0 ) )
2764  {
2765  double d = ptOne.distance( ptZero ) * distance;
2766  labelFeature->setDistLabel( d );
2767  }
2768 
2769  if ( ddFixedQuad )
2770  {
2771  labelFeature->setHasFixedQuadrant( true );
2772  }
2773 
2774  labelFeature->setArrangementFlags( lineSettings.placementFlags() );
2775 
2776  labelFeature->setPolygonPlacementFlags( polygonPlacement );
2777 
2778  // data defined z-index?
2779  double z = zIndex;
2780  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ZIndex ) )
2781  {
2783  z = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::ZIndex, context.expressionContext(), z );
2784  }
2785  labelFeature->setZIndex( z );
2786 
2787  // data defined priority?
2788  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Priority ) )
2789  {
2791  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Priority, context.expressionContext() );
2792  if ( !exprVal.isNull() )
2793  {
2794  bool ok;
2795  double priorityD = exprVal.toDouble( &ok );
2796  if ( ok )
2797  {
2798  priorityD = std::clamp( priorityD, 0.0, 10.0 );
2799  priorityD = 1 - priorityD / 10.0; // convert 0..10 --> 1..0
2800  labelFeature->setPriority( priorityD );
2801  }
2802  }
2803  }
2804 
2805  // data defined allow degraded placement
2806  {
2807  double allowDegradedPlacement = mPlacementSettings.allowDegradedPlacement();
2808  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::AllowDegradedPlacement ) )
2809  {
2810  context.expressionContext().setOriginalValueVariable( allowDegradedPlacement );
2811  allowDegradedPlacement = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::AllowDegradedPlacement, context.expressionContext(), allowDegradedPlacement );
2812  }
2813  labelFeature->setAllowDegradedPlacement( allowDegradedPlacement );
2814  }
2815 
2816  // data defined overlap handling
2817  {
2818  Qgis::LabelOverlapHandling overlapHandling = mPlacementSettings.overlapHandling();
2819  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::OverlapHandling ) )
2820  {
2821  const QString handlingString = mDataDefinedProperties.valueAsString( QgsPalLayerSettings::OverlapHandling, context.expressionContext() );
2822  const QString cleanedString = handlingString.trimmed();
2823  if ( cleanedString.compare( QLatin1String( "prevent" ), Qt::CaseInsensitive ) == 0 )
2825  else if ( cleanedString.compare( QLatin1String( "allowifneeded" ), Qt::CaseInsensitive ) == 0 )
2827  else if ( cleanedString.compare( QLatin1String( "alwaysallow" ), Qt::CaseInsensitive ) == 0 )
2829  }
2830  labelFeature->setOverlapHandling( overlapHandling );
2831  }
2832 
2833  QgsLabelObstacleSettings os = mObstacleSettings;
2834  os.setIsObstacle( isObstacle );
2835  os.updateDataDefinedProperties( mDataDefinedProperties, context.expressionContext() );
2836  os.setObstacleGeometry( obstacleGeometry );
2837  labelFeature->setObstacleSettings( os );
2838 
2839  QVector< Qgis::LabelPredefinedPointPosition > positionOrder = predefinedPositionOrder;
2840  if ( positionOrder.isEmpty() )
2841  positionOrder = *DEFAULT_PLACEMENT_ORDER();
2842 
2843  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::PredefinedPositionOrder ) )
2844  {
2846  QString dataDefinedOrder = mDataDefinedProperties.valueAsString( QgsPalLayerSettings::PredefinedPositionOrder, context.expressionContext() );
2847  if ( !dataDefinedOrder.isEmpty() )
2848  {
2849  positionOrder = QgsLabelingUtils::decodePredefinedPositionOrder( dataDefinedOrder );
2850  }
2851  }
2852  labelFeature->setPredefinedPositionOrder( positionOrder );
2853 
2854  // add parameters for data defined labeling to label feature
2855  labelFeature->setDataDefinedValues( dataDefinedValues );
2856 
2857  return labelFeature;
2858 }
2859 
2860 std::unique_ptr<QgsLabelFeature> QgsPalLayerSettings::registerObstacleFeature( const QgsFeature &f, QgsRenderContext &context, const QgsGeometry &obstacleGeometry )
2861 {
2862  mCurFeat = &f;
2863 
2864  QgsGeometry geom;
2865  if ( !obstacleGeometry.isNull() )
2866  {
2867  geom = obstacleGeometry;
2868  }
2869  else
2870  {
2871  geom = f.geometry();
2872  }
2873 
2874  if ( geom.isNull() )
2875  {
2876  return nullptr;
2877  }
2878 
2879  // don't even try to register linestrings with only one vertex as an obstacle
2880  if ( const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( geom.constGet() ) )
2881  {
2882  if ( ls->numPoints() < 2 )
2883  return nullptr;
2884  }
2885 
2886  // simplify?
2887  const QgsVectorSimplifyMethod &simplifyMethod = context.vectorSimplifyMethod();
2888  std::unique_ptr<QgsGeometry> scopedClonedGeom;
2889  if ( simplifyMethod.simplifyHints() != QgsVectorSimplifyMethod::NoSimplification && simplifyMethod.forceLocalOptimization() )
2890  {
2891  int simplifyHints = simplifyMethod.simplifyHints() | QgsMapToPixelSimplifier::SimplifyEnvelope;
2893  QgsMapToPixelSimplifier simplifier( simplifyHints, simplifyMethod.tolerance(), simplifyAlgorithm );
2894  geom = simplifier.simplify( geom );
2895  }
2896 
2897  geos::unique_ptr geos_geom_clone;
2898  std::unique_ptr<QgsGeometry> scopedPreparedGeom;
2899 
2900  if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, ct, extentGeom, mLineSettings.mergeLines() ) )
2901  {
2902  geom = QgsPalLabeling::prepareGeometry( geom, context, ct, extentGeom, mLineSettings.mergeLines() );
2903  }
2904  geos_geom_clone = QgsGeos::asGeos( geom );
2905 
2906  if ( !geos_geom_clone )
2907  return nullptr; // invalid geometry
2908 
2909  // feature to the layer
2910  std::unique_ptr< QgsLabelFeature > obstacleFeature = std::make_unique< QgsLabelFeature >( f.id(), std::move( geos_geom_clone ), QSizeF( 0, 0 ) );
2911  obstacleFeature->setFeature( f );
2912 
2913  QgsLabelObstacleSettings os = mObstacleSettings;
2914  os.setIsObstacle( true );
2915  os.updateDataDefinedProperties( mDataDefinedProperties, context.expressionContext() );
2916  obstacleFeature->setObstacleSettings( os );
2917 
2918  mFeatsRegPal++;
2919  return obstacleFeature;
2920 }
2921 
2922 bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
2924  QVariant &exprVal, QgsExpressionContext &context, const QVariant &originalValue )
2925 {
2926  if ( !mDataDefinedProperties.isActive( p ) )
2927  return false;
2928 
2929  context.setOriginalValueVariable( originalValue );
2930  exprVal = mDataDefinedProperties.value( p, context );
2931  if ( !exprVal.isNull() )
2932  {
2933  switch ( valType )
2934  {
2935  case DDBool:
2936  {
2937  bool bol = exprVal.toBool();
2938  dataDefinedValues.insert( p, QVariant( bol ) );
2939  return true;
2940  }
2941  case DDInt:
2942  {
2943  bool ok;
2944  int size = exprVal.toInt( &ok );
2945 
2946  if ( ok )
2947  {
2948  dataDefinedValues.insert( p, QVariant( size ) );
2949  return true;
2950  }
2951  return false;
2952  }
2953  case DDIntPos:
2954  {
2955  bool ok;
2956  int size = exprVal.toInt( &ok );
2957 
2958  if ( ok && size > 0 )
2959  {
2960  dataDefinedValues.insert( p, QVariant( size ) );
2961  return true;
2962  }
2963  return false;
2964  }
2965  case DDDouble:
2966  {
2967  bool ok;
2968  double size = exprVal.toDouble( &ok );
2969 
2970  if ( ok )
2971  {
2972  dataDefinedValues.insert( p, QVariant( size ) );
2973  return true;
2974  }
2975  return false;
2976  }
2977  case DDDoublePos:
2978  {
2979  bool ok;
2980  double size = exprVal.toDouble( &ok );
2981 
2982  if ( ok && size > 0.0 )
2983  {
2984  dataDefinedValues.insert( p, QVariant( size ) );
2985  return true;
2986  }
2987  return false;
2988  }
2989  case DDRotation180:
2990  {
2991  bool ok;
2992  double rot = exprVal.toDouble( &ok );
2993  if ( ok )
2994  {
2995  if ( rot < -180.0 && rot >= -360 )
2996  {
2997  rot += 360;
2998  }
2999  if ( rot > 180.0 && rot <= 360 )
3000  {
3001  rot -= 360;
3002  }
3003  if ( rot >= -180 && rot <= 180 )
3004  {
3005  dataDefinedValues.insert( p, QVariant( rot ) );
3006  return true;
3007  }
3008  }
3009  return false;
3010  }
3011  case DDOpacity:
3012  {
3013  bool ok;
3014  int size = exprVal.toInt( &ok );
3015  if ( ok && size >= 0 && size <= 100 )
3016  {
3017  dataDefinedValues.insert( p, QVariant( size ) );
3018  return true;
3019  }
3020  return false;
3021  }
3022  case DDString:
3023  {
3024  QString str = exprVal.toString(); // don't trim whitespace
3025 
3026  dataDefinedValues.insert( p, QVariant( str ) ); // let it stay empty if it is
3027  return true;
3028  }
3029  case DDUnits:
3030  {
3031  QString unitstr = exprVal.toString().trimmed();
3032 
3033  if ( !unitstr.isEmpty() )
3034  {
3035  dataDefinedValues.insert( p, QVariant( static_cast< int >( QgsUnitTypes::decodeRenderUnit( unitstr ) ) ) );
3036  return true;
3037  }
3038  return false;
3039  }
3040  case DDColor:
3041  {
3042  QString colorstr = exprVal.toString().trimmed();
3043  QColor color = QgsSymbolLayerUtils::decodeColor( colorstr );
3044 
3045  if ( color.isValid() )
3046  {
3047  dataDefinedValues.insert( p, QVariant( color ) );
3048  return true;
3049  }
3050  return false;
3051  }
3052  case DDJoinStyle:
3053  {
3054  QString joinstr = exprVal.toString().trimmed();
3055 
3056  if ( !joinstr.isEmpty() )
3057  {
3058  dataDefinedValues.insert( p, QVariant( static_cast< int >( QgsSymbolLayerUtils::decodePenJoinStyle( joinstr ) ) ) );
3059  return true;
3060  }
3061  return false;
3062  }
3063  case DDBlendMode:
3064  {
3065  QString blendstr = exprVal.toString().trimmed();
3066 
3067  if ( !blendstr.isEmpty() )
3068  {
3069  dataDefinedValues.insert( p, QVariant( static_cast< int >( QgsSymbolLayerUtils::decodeBlendMode( blendstr ) ) ) );
3070  return true;
3071  }
3072  return false;
3073  }
3074  case DDPointF:
3075  {
3076  bool ok = false;
3077  const QPointF res = QgsSymbolLayerUtils::toPoint( exprVal, &ok );
3078  if ( ok )
3079  {
3080  dataDefinedValues.insert( p, res );
3081  return true;
3082  }
3083  return false;
3084  }
3085  case DDSizeF:
3086  {
3087  bool ok = false;
3088  const QSizeF res = QgsSymbolLayerUtils::toSize( exprVal, &ok );
3089  if ( ok )
3090  {
3091  dataDefinedValues.insert( p, res );
3092  return true;
3093  }
3094  return false;
3095  }
3096  }
3097  }
3098  return false;
3099 }
3100 
3101 void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
3102  QgsUnitTypes::RenderUnit fontunits,
3103  QgsRenderContext &context )
3104 {
3105  // NOTE: labelFont already has pixelSize set, so pointSize or pointSizeF might return -1
3106 
3107  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3108 
3109  // Two ways to generate new data defined font:
3110  // 1) Family + [bold] + [italic] (named style is ignored and font is built off of base family)
3111  // 2) Family + named style (bold or italic is ignored)
3112 
3113  // data defined font family?
3114  QString ddFontFamily;
3115  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Family ) )
3116  {
3117  context.expressionContext().setOriginalValueVariable( labelFont.family() );
3118  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::Family, context.expressionContext() );
3119  if ( !exprVal.isNull() )
3120  {
3121  QString family = exprVal.toString().trimmed();
3122  QgsDebugMsgLevel( QStringLiteral( "exprVal Font family:%1" ).arg( family ), 4 );
3123 
3124  if ( labelFont.family() != family )
3125  {
3126  // testing for ddFontFamily in QFontDatabase.families() may be slow to do for every feature
3127  // (i.e. don't use QgsFontUtils::fontFamilyMatchOnSystem( family ) here)
3128  if ( QgsFontUtils::fontFamilyOnSystem( family ) )
3129  {
3130  ddFontFamily = family;
3131  }
3132  }
3133  }
3134  }
3135 
3136  // data defined named font style?
3137  QString ddFontStyle;
3138  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontStyle ) )
3139  {
3140  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::FontStyle, context.expressionContext() );
3141  if ( !exprVal.isNull() )
3142  {
3143  QString fontstyle = exprVal.toString().trimmed();
3144  QgsDebugMsgLevel( QStringLiteral( "exprVal Font style:%1" ).arg( fontstyle ), 4 );
3145  ddFontStyle = fontstyle;
3146  }
3147  }
3148 
3149  // data defined bold font style?
3150  bool ddBold = false;
3151  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Bold ) )
3152  {
3153  context.expressionContext().setOriginalValueVariable( labelFont.bold() );
3154  ddBold = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Bold, context.expressionContext(), false );
3155  }
3156 
3157  // data defined italic font style?
3158  bool ddItalic = false;
3159  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Italic ) )
3160  {
3161  context.expressionContext().setOriginalValueVariable( labelFont.italic() );
3162  ddItalic = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Italic, context.expressionContext(), false );
3163  }
3164 
3165  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
3166  // (currently defaults to what has been read in from layer settings)
3167  QFont newFont;
3168  QFont appFont = QApplication::font();
3169  bool newFontBuilt = false;
3170  if ( ddBold || ddItalic )
3171  {
3172  // new font needs built, since existing style needs removed
3173  newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : labelFont.family() );
3174  newFontBuilt = true;
3175  newFont.setBold( ddBold );
3176  newFont.setItalic( ddItalic );
3177  }
3178  else if ( !ddFontStyle.isEmpty()
3179  && ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
3180  {
3181  if ( !ddFontFamily.isEmpty() )
3182  {
3183  // both family and style are different, build font from database
3184  if ( !mFontDB )
3185  mFontDB = std::make_unique< QFontDatabase >();
3186 
3187  QFont styledfont = mFontDB->font( ddFontFamily, ddFontStyle, appFont.pointSize() );
3188  if ( appFont != styledfont )
3189  {
3190  newFont = styledfont;
3191  newFontBuilt = true;
3192  }
3193  }
3194 
3195  // update the font face style
3196  QgsFontUtils::updateFontViaStyle( newFontBuilt ? newFont : labelFont, ddFontStyle );
3197  }
3198  else if ( !ddFontFamily.isEmpty() )
3199  {
3200  if ( ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
3201  {
3202  // just family is different, build font from database
3203  if ( !mFontDB )
3204  mFontDB = std::make_unique< QFontDatabase >();
3205  QFont styledfont = mFontDB->font( ddFontFamily, mFormat.namedStyle(), appFont.pointSize() );
3206  if ( appFont != styledfont )
3207  {
3208  newFont = styledfont;
3209  newFontBuilt = true;
3210  }
3211  }
3212  else
3213  {
3214  newFont = QFont( ddFontFamily );
3215  newFontBuilt = true;
3216  }
3217  }
3218 
3219  if ( newFontBuilt )
3220  {
3221  // copy over existing font settings
3222  //newFont = newFont.resolve( labelFont ); // should work, but let's be sure what's being copied
3223  newFont.setPixelSize( labelFont.pixelSize() );
3224  newFont.setUnderline( labelFont.underline() );
3225  newFont.setStrikeOut( labelFont.strikeOut() );
3226  newFont.setWordSpacing( labelFont.wordSpacing() );
3227  newFont.setLetterSpacing( QFont::AbsoluteSpacing, labelFont.letterSpacing() );
3228 
3229  labelFont = newFont;
3230  }
3231 
3232  // data defined word spacing?
3233  double wordspace = labelFont.wordSpacing();
3234  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontWordSpacing ) )
3235  {
3236  context.expressionContext().setOriginalValueVariable( wordspace );
3237  wordspace = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::FontWordSpacing, context.expressionContext(), wordspace );
3238  }
3239  labelFont.setWordSpacing( context.convertToPainterUnits( wordspace, fontunits, mFormat.sizeMapUnitScale() ) );
3240 
3241  // data defined letter spacing?
3242  double letterspace = labelFont.letterSpacing();
3243  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontLetterSpacing ) )
3244  {
3245  context.expressionContext().setOriginalValueVariable( letterspace );
3246  letterspace = mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::FontLetterSpacing, context.expressionContext(), letterspace );
3247  }
3248  labelFont.setLetterSpacing( QFont::AbsoluteSpacing, context.convertToPainterUnits( letterspace, fontunits, mFormat.sizeMapUnitScale() ) );
3249 
3250  // data defined strikeout font style?
3251  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Strikeout ) )
3252  {
3253  context.expressionContext().setOriginalValueVariable( labelFont.strikeOut() );
3254  bool strikeout = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Strikeout, context.expressionContext(), false );
3255  labelFont.setStrikeOut( strikeout );
3256  }
3257 
3258  // data defined stretch
3259  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::FontStretchFactor ) )
3260  {
3262  labelFont.setStretch( mDataDefinedProperties.valueAsInt( QgsPalLayerSettings::FontStretchFactor, context.expressionContext(), mFormat.stretchFactor() ) );
3263  }
3264 
3265  // data defined underline font style?
3266  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::Underline ) )
3267  {
3268  context.expressionContext().setOriginalValueVariable( labelFont.underline() );
3269  bool underline = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Underline, context.expressionContext(), false );
3270  labelFont.setUnderline( underline );
3271  }
3272 
3273  // pass the rest on to QgsPalLabeling::drawLabeling
3274 
3275  // data defined font color?
3276  dataDefinedValEval( DDColor, QgsPalLayerSettings::Color, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodeColor( mFormat.color() ) );
3277 
3278  // data defined font opacity?
3279  dataDefinedValEval( DDOpacity, QgsPalLayerSettings::FontOpacity, exprVal, context.expressionContext(), mFormat.opacity() * 100 );
3280 
3281  // data defined font blend mode?
3282  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::FontBlendMode, exprVal, context.expressionContext() );
3283 
3284 }
3285 
3286 void QgsPalLayerSettings::parseTextBuffer( QgsRenderContext &context )
3287 {
3288  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3289 
3290  QgsTextBufferSettings buffer = mFormat.buffer();
3291 
3292  // data defined draw buffer?
3293  bool drawBuffer = mFormat.buffer().enabled();
3294  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::BufferDraw, exprVal, context.expressionContext(), buffer.enabled() ) )
3295  {
3296  drawBuffer = exprVal.toBool();
3297  }
3298  else if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::BufferDraw ) && exprVal.isNull() )
3299  {
3300  dataDefinedValues.insert( QgsPalLayerSettings::BufferDraw, QVariant( drawBuffer ) );
3301  }
3302 
3303  if ( !drawBuffer )
3304  {
3305  return;
3306  }
3307 
3308  // data defined buffer size?
3309  double bufrSize = buffer.size();
3310  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::BufferSize, exprVal, context.expressionContext(), buffer.size() ) )
3311  {
3312  bufrSize = exprVal.toDouble();
3313  }
3314 
3315  // data defined buffer transparency?
3316  double bufferOpacity = buffer.opacity() * 100;
3317  if ( dataDefinedValEval( DDOpacity, QgsPalLayerSettings::BufferOpacity, exprVal, context.expressionContext(), bufferOpacity ) )
3318  {
3319  bufferOpacity = exprVal.toDouble();
3320  }
3321 
3322  drawBuffer = ( drawBuffer && bufrSize > 0.0 && bufferOpacity > 0 );
3323 
3324  if ( !drawBuffer )
3325  {
3326  dataDefinedValues.insert( QgsPalLayerSettings::BufferDraw, QVariant( false ) ); // trigger value
3327  dataDefinedValues.remove( QgsPalLayerSettings::BufferSize );
3328  dataDefinedValues.remove( QgsPalLayerSettings::BufferOpacity );
3329  return; // don't bother evaluating values that won't be used
3330  }
3331 
3332  // data defined buffer units?
3333  dataDefinedValEval( DDUnits, QgsPalLayerSettings::BufferUnit, exprVal, context.expressionContext() );
3334 
3335  // data defined buffer color?
3336  dataDefinedValEval( DDColor, QgsPalLayerSettings::BufferColor, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodeColor( buffer.color() ) );
3337 
3338  // data defined buffer pen join style?
3339  dataDefinedValEval( DDJoinStyle, QgsPalLayerSettings::BufferJoinStyle, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodePenJoinStyle( buffer.joinStyle() ) );
3340 
3341  // data defined buffer blend mode?
3342  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::BufferBlendMode, exprVal, context.expressionContext() );
3343 }
3344 
3345 void QgsPalLayerSettings::parseTextMask( QgsRenderContext &context )
3346 {
3347  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3348 
3349  QgsTextMaskSettings mask = mFormat.mask();
3350 
3351  // data defined enabled mask?
3352  bool maskEnabled = mask.enabled();
3353  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::MaskEnabled, exprVal, context.expressionContext(), mask.enabled() ) )
3354  {
3355  maskEnabled = exprVal.toBool();
3356  }
3357 
3358  if ( !maskEnabled )
3359  {
3360  return;
3361  }
3362 
3363  // data defined buffer size?
3364  double bufrSize = mask.size();
3365  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::MaskBufferSize, exprVal, context.expressionContext(), mask.size() ) )
3366  {
3367  bufrSize = exprVal.toDouble();
3368  }
3369 
3370  // data defined opacity?
3371  double opacity = mask.opacity() * 100;
3372  if ( dataDefinedValEval( DDOpacity, QgsPalLayerSettings::MaskOpacity, exprVal, context.expressionContext(), opacity ) )
3373  {
3374  opacity = exprVal.toDouble();
3375  }
3376 
3377  maskEnabled = ( maskEnabled && bufrSize > 0.0 && opacity > 0 );
3378 
3379  if ( !maskEnabled )
3380  {
3381  dataDefinedValues.insert( QgsPalLayerSettings::MaskEnabled, QVariant( false ) ); // trigger value
3382  dataDefinedValues.remove( QgsPalLayerSettings::MaskBufferSize );
3383  dataDefinedValues.remove( QgsPalLayerSettings::MaskOpacity );
3384  return; // don't bother evaluating values that won't be used
3385  }
3386 
3387  // data defined buffer units?
3388  dataDefinedValEval( DDUnits, QgsPalLayerSettings::MaskBufferUnit, exprVal, context.expressionContext() );
3389 
3390  // data defined buffer pen join style?
3391  dataDefinedValEval( DDJoinStyle, QgsPalLayerSettings::MaskJoinStyle, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodePenJoinStyle( mask.joinStyle() ) );
3392 }
3393 
3394 void QgsPalLayerSettings::parseTextFormatting( QgsRenderContext &context )
3395 {
3396  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3397 
3398  // data defined multiline wrap character?
3399  QString wrapchr = wrapChar;
3400  if ( dataDefinedValEval( DDString, QgsPalLayerSettings::MultiLineWrapChar, exprVal, context.expressionContext(), wrapChar ) )
3401  {
3402  wrapchr = exprVal.toString();
3403  }
3404 
3405  int evalAutoWrapLength = autoWrapLength;
3406  if ( dataDefinedValEval( DDInt, QgsPalLayerSettings::AutoWrapLength, exprVal, context.expressionContext(), evalAutoWrapLength ) )
3407  {
3408  evalAutoWrapLength = exprVal.toInt();
3409  }
3410 
3411  // data defined multiline height?
3412  dataDefinedValEval( DDDouble, QgsPalLayerSettings::MultiLineHeight, exprVal, context.expressionContext() );
3413 
3414  // data defined multiline text align?
3415  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::MultiLineAlignment ) )
3416  {
3417  context.expressionContext().setOriginalValueVariable( mFormat.lineHeight() );
3418  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::MultiLineAlignment, context.expressionContext() );
3419  if ( !exprVal.isNull() )
3420  {
3421  QString str = exprVal.toString().trimmed();
3422  QgsDebugMsgLevel( QStringLiteral( "exprVal MultiLineAlignment:%1" ).arg( str ), 4 );
3423 
3424  if ( !str.isEmpty() )
3425  {
3426  // "Left"
3427  Qgis::LabelMultiLineAlignment aligntype = Qgis::LabelMultiLineAlignment::Left;
3428 
3429  if ( str.compare( QLatin1String( "Center" ), Qt::CaseInsensitive ) == 0 )
3430  {
3431  aligntype = Qgis::LabelMultiLineAlignment::Center;
3432  }
3433  else if ( str.compare( QLatin1String( "Right" ), Qt::CaseInsensitive ) == 0 )
3434  {
3435  aligntype = Qgis::LabelMultiLineAlignment::Right;
3436  }
3437  else if ( str.compare( QLatin1String( "Follow" ), Qt::CaseInsensitive ) == 0 )
3438  {
3439  aligntype = Qgis::LabelMultiLineAlignment::FollowPlacement;
3440  }
3441  else if ( str.compare( QLatin1String( "Justify" ), Qt::CaseInsensitive ) == 0 )
3442  {
3443  aligntype = Qgis::LabelMultiLineAlignment::Justify;
3444  }
3445  dataDefinedValues.insert( QgsPalLayerSettings::MultiLineAlignment, QVariant( static_cast< int >( aligntype ) ) );
3446  }
3447  }
3448  }
3449 
3450  // text orientation
3451  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::TextOrientation ) )
3452  {
3453  const QString encoded = QgsTextRendererUtils::encodeTextOrientation( mFormat.orientation() );
3454  context.expressionContext().setOriginalValueVariable( encoded );
3455  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::TextOrientation, context.expressionContext() );
3456  if ( !exprVal.isNull() )
3457  {
3458  QString str = exprVal.toString().trimmed();
3459  if ( !str.isEmpty() )
3460  dataDefinedValues.insert( QgsPalLayerSettings::TextOrientation, str );
3461  }
3462  }
3463 
3464  // data defined direction symbol?
3465  bool drawDirSymb = mLineSettings.addDirectionSymbol();
3466  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::DirSymbDraw, exprVal, context.expressionContext(), drawDirSymb ) )
3467  {
3468  drawDirSymb = exprVal.toBool();
3469  }
3470 
3471  if ( drawDirSymb )
3472  {
3473  // data defined direction left symbol?
3474  dataDefinedValEval( DDString, QgsPalLayerSettings::DirSymbLeft, exprVal, context.expressionContext(), mLineSettings.leftDirectionSymbol() );
3475 
3476  // data defined direction right symbol?
3477  dataDefinedValEval( DDString, QgsPalLayerSettings::DirSymbRight, exprVal, context.expressionContext(), mLineSettings.rightDirectionSymbol() );
3478 
3479  // data defined direction symbol placement?
3480  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::DirSymbPlacement, context.expressionContext() );
3481  if ( !exprVal.isNull() )
3482  {
3483  QString str = exprVal.toString().trimmed();
3484  QgsDebugMsgLevel( QStringLiteral( "exprVal DirSymbPlacement:%1" ).arg( str ), 4 );
3485 
3486  if ( !str.isEmpty() )
3487  {
3488  // "LeftRight"
3490 
3491  if ( str.compare( QLatin1String( "Above" ), Qt::CaseInsensitive ) == 0 )
3492  {
3494  }
3495  else if ( str.compare( QLatin1String( "Below" ), Qt::CaseInsensitive ) == 0 )
3496  {
3498  }
3499  dataDefinedValues.insert( QgsPalLayerSettings::DirSymbPlacement, QVariant( static_cast< int >( placetype ) ) );
3500  }
3501  }
3502 
3503  // data defined direction symbol reversed?
3504  dataDefinedValEval( DDBool, QgsPalLayerSettings::DirSymbReverse, exprVal, context.expressionContext(), mLineSettings.reverseDirectionSymbol() );
3505  }
3506 
3507  // formatting for numbers is inline with generation of base label text and not passed to label painting
3508 }
3509 
3510 void QgsPalLayerSettings::parseShapeBackground( QgsRenderContext &context )
3511 {
3512  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3513 
3514  QgsTextBackgroundSettings background = mFormat.background();
3515 
3516  // data defined draw shape?
3517  bool drawShape = background.enabled();
3518  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::ShapeDraw, exprVal, context.expressionContext(), drawShape ) )
3519  {
3520  drawShape = exprVal.toBool();
3521  }
3522 
3523  if ( !drawShape )
3524  {
3525  return;
3526  }
3527 
3528  // data defined shape transparency?
3529  double shapeOpacity = background.opacity() * 100;
3530  if ( dataDefinedValEval( DDOpacity, QgsPalLayerSettings::ShapeOpacity, exprVal, context.expressionContext(), shapeOpacity ) )
3531  {
3532  shapeOpacity = 100.0 * exprVal.toDouble();
3533  }
3534 
3535  drawShape = ( drawShape && shapeOpacity > 0 ); // size is not taken into account (could be)
3536 
3537  if ( !drawShape )
3538  {
3539  dataDefinedValues.insert( QgsPalLayerSettings::ShapeDraw, QVariant( false ) ); // trigger value
3540  dataDefinedValues.remove( QgsPalLayerSettings::ShapeOpacity );
3541  return; // don't bother evaluating values that won't be used
3542  }
3543 
3544  // data defined shape kind?
3545  QgsTextBackgroundSettings::ShapeType shapeKind = background.type();
3546  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ShapeKind ) )
3547  {
3548  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::ShapeKind, context.expressionContext() );
3549  if ( !exprVal.isNull() )
3550  {
3551  QString skind = exprVal.toString().trimmed();
3552  QgsDebugMsgLevel( QStringLiteral( "exprVal ShapeKind:%1" ).arg( skind ), 4 );
3553 
3554  if ( !skind.isEmpty() )
3555  {
3556  shapeKind = QgsTextRendererUtils::decodeShapeType( skind );
3557  dataDefinedValues.insert( QgsPalLayerSettings::ShapeKind, QVariant( static_cast< int >( shapeKind ) ) );
3558  }
3559  }
3560  }
3561 
3562  // data defined shape SVG path?
3563  QString svgPath = background.svgFile();
3564  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ShapeSVGFile ) )
3565  {
3566  context.expressionContext().setOriginalValueVariable( svgPath );
3567  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::ShapeSVGFile, context.expressionContext() );
3568  if ( !exprVal.isNull() )
3569  {
3570  QString svgfile = exprVal.toString().trimmed();
3571  QgsDebugMsgLevel( QStringLiteral( "exprVal ShapeSVGFile:%1" ).arg( svgfile ), 4 );
3572 
3573  // '' empty paths are allowed
3574  svgPath = QgsSymbolLayerUtils::svgSymbolNameToPath( svgfile, context.pathResolver() );
3575  dataDefinedValues.insert( QgsPalLayerSettings::ShapeSVGFile, QVariant( svgPath ) );
3576  }
3577  }
3578 
3579  // data defined shape size type?
3580  QgsTextBackgroundSettings::SizeType shpSizeType = background.sizeType();
3581  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ShapeSizeType ) )
3582  {
3583  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::ShapeSizeType, context.expressionContext() );
3584  if ( !exprVal.isNull() )
3585  {
3586  QString stype = exprVal.toString().trimmed();
3587  QgsDebugMsgLevel( QStringLiteral( "exprVal ShapeSizeType:%1" ).arg( stype ), 4 );
3588 
3589  if ( !stype.isEmpty() )
3590  {
3591  shpSizeType = QgsTextRendererUtils::decodeBackgroundSizeType( stype );
3592  dataDefinedValues.insert( QgsPalLayerSettings::ShapeSizeType, QVariant( static_cast< int >( shpSizeType ) ) );
3593  }
3594  }
3595  }
3596 
3597  // data defined shape size X? (SVGs only use X for sizing)
3598  double ddShpSizeX = background.size().width();
3599  if ( dataDefinedValEval( DDDouble, QgsPalLayerSettings::ShapeSizeX, exprVal, context.expressionContext(), ddShpSizeX ) )
3600  {
3601  ddShpSizeX = exprVal.toDouble();
3602  }
3603 
3604  // data defined shape size Y?
3605  double ddShpSizeY = background.size().height();
3606  if ( dataDefinedValEval( DDDouble, QgsPalLayerSettings::ShapeSizeY, exprVal, context.expressionContext(), ddShpSizeY ) )
3607  {
3608  ddShpSizeY = exprVal.toDouble();
3609  }
3610 
3611  // don't continue under certain circumstances (e.g. size is fixed)
3612  bool skip = false;
3613  if ( shapeKind == QgsTextBackgroundSettings::ShapeSVG
3614  && ( svgPath.isEmpty()
3615  || ( !svgPath.isEmpty()
3616  && shpSizeType == QgsTextBackgroundSettings::SizeFixed
3617  && ddShpSizeX == 0.0 ) ) )
3618  {
3619  skip = true;
3620  }
3622  && ( !background.markerSymbol()
3623  || ( background.markerSymbol()
3624  && shpSizeType == QgsTextBackgroundSettings::SizeFixed
3625  && ddShpSizeX == 0.0 ) ) )
3626  {
3627  skip = true;
3628  }
3629  if ( shapeKind != QgsTextBackgroundSettings::ShapeSVG
3631  && shpSizeType == QgsTextBackgroundSettings::SizeFixed
3632  && ( ddShpSizeX == 0.0 || ddShpSizeY == 0.0 ) )
3633  {
3634  skip = true;
3635  }
3636 
3637  if ( skip )
3638  {
3639  dataDefinedValues.insert( QgsPalLayerSettings::ShapeDraw, QVariant( false ) ); // trigger value
3640  dataDefinedValues.remove( QgsPalLayerSettings::ShapeOpacity );
3641  dataDefinedValues.remove( QgsPalLayerSettings::ShapeKind );
3642  dataDefinedValues.remove( QgsPalLayerSettings::ShapeSVGFile );
3643  dataDefinedValues.remove( QgsPalLayerSettings::ShapeSizeX );
3644  dataDefinedValues.remove( QgsPalLayerSettings::ShapeSizeY );
3645  return; // don't bother evaluating values that won't be used
3646  }
3647 
3648  // data defined shape size units?
3649  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeSizeUnits, exprVal, context.expressionContext() );
3650 
3651  // data defined shape rotation type?
3652  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ShapeRotationType ) )
3653  {
3654  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::ShapeRotationType, context.expressionContext() );
3655  if ( !exprVal.isNull() )
3656  {
3657  QString rotstr = exprVal.toString().trimmed();
3658  QgsDebugMsgLevel( QStringLiteral( "exprVal ShapeRotationType:%1" ).arg( rotstr ), 4 );
3659 
3660  if ( !rotstr.isEmpty() )
3661  {
3662  // "Sync"
3664  dataDefinedValues.insert( QgsPalLayerSettings::ShapeRotationType, QVariant( static_cast< int >( rottype ) ) );
3665  }
3666  }
3667  }
3668 
3669  // data defined shape rotation?
3670  dataDefinedValEval( DDRotation180, QgsPalLayerSettings::ShapeRotation, exprVal, context.expressionContext(), background.rotation() );
3671 
3672  // data defined shape offset?
3673  dataDefinedValEval( DDPointF, QgsPalLayerSettings::ShapeOffset, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodePoint( background.offset() ) );
3674 
3675  // data defined shape offset units?
3676  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeOffsetUnits, exprVal, context.expressionContext() );
3677 
3678  // data defined shape radii?
3679  dataDefinedValEval( DDSizeF, QgsPalLayerSettings::ShapeRadii, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodeSize( background.radii() ) );
3680 
3681  // data defined shape radii units?
3682  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeRadiiUnits, exprVal, context.expressionContext() );
3683 
3684  // data defined shape blend mode?
3685  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::ShapeBlendMode, exprVal, context.expressionContext() );
3686 
3687  // data defined shape fill color?
3688  dataDefinedValEval( DDColor, QgsPalLayerSettings::ShapeFillColor, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodeColor( background.fillColor() ) );
3689 
3690  // data defined shape stroke color?
3691  dataDefinedValEval( DDColor, QgsPalLayerSettings::ShapeStrokeColor, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodeColor( background.strokeColor() ) );
3692 
3693  // data defined shape stroke width?
3694  dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::ShapeStrokeWidth, exprVal, context.expressionContext(), background.strokeWidth() );
3695 
3696  // data defined shape stroke width units?
3697  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeStrokeWidthUnits, exprVal, context.expressionContext() );
3698 
3699  // data defined shape join style?
3700  dataDefinedValEval( DDJoinStyle, QgsPalLayerSettings::ShapeJoinStyle, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodePenJoinStyle( background.joinStyle() ) );
3701 
3702 }
3703 
3704 void QgsPalLayerSettings::parseDropShadow( QgsRenderContext &context )
3705 {
3706  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3707 
3708  QgsTextShadowSettings shadow = mFormat.shadow();
3709 
3710  // data defined draw shadow?
3711  bool drawShadow = shadow.enabled();
3712  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::ShadowDraw, exprVal, context.expressionContext(), drawShadow ) )
3713  {
3714  drawShadow = exprVal.toBool();
3715  }
3716 
3717  if ( !drawShadow )
3718  {
3719  return;
3720  }
3721 
3722  // data defined shadow transparency?
3723  double shadowOpacity = shadow.opacity() * 100;
3724  if ( dataDefinedValEval( DDOpacity, QgsPalLayerSettings::ShadowOpacity, exprVal, context.expressionContext(), shadowOpacity ) )
3725  {
3726  shadowOpacity = exprVal.toDouble();
3727  }
3728 
3729  // data defined shadow offset distance?
3730  double shadowOffDist = shadow.offsetDistance();
3731  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::ShadowOffsetDist, exprVal, context.expressionContext(), shadowOffDist ) )
3732  {
3733  shadowOffDist = exprVal.toDouble();
3734  }
3735 
3736  // data defined shadow offset distance?
3737  double shadowRad = shadow.blurRadius();
3738  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::ShadowRadius, exprVal, context.expressionContext(), shadowRad ) )
3739  {
3740  shadowRad = exprVal.toDouble();
3741  }
3742 
3743  drawShadow = ( drawShadow && shadowOpacity > 0 && !( shadowOffDist == 0.0 && shadowRad == 0.0 ) );
3744 
3745  if ( !drawShadow )
3746  {
3747  dataDefinedValues.insert( QgsPalLayerSettings::ShadowDraw, QVariant( false ) ); // trigger value
3748  dataDefinedValues.remove( QgsPalLayerSettings::ShadowOpacity );
3749  dataDefinedValues.remove( QgsPalLayerSettings::ShadowOffsetDist );
3750  dataDefinedValues.remove( QgsPalLayerSettings::ShadowRadius );
3751  return; // don't bother evaluating values that won't be used
3752  }
3753 
3754  // data defined shadow under type?
3755  if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ShadowUnder ) )
3756  {
3757  exprVal = mDataDefinedProperties.value( QgsPalLayerSettings::ShadowUnder, context.expressionContext() );
3758  if ( !exprVal.isNull() )
3759  {
3760  QString str = exprVal.toString().trimmed();
3761  QgsDebugMsgLevel( QStringLiteral( "exprVal ShadowUnder:%1" ).arg( str ), 4 );
3762 
3763  if ( !str.isEmpty() )
3764  {
3766  dataDefinedValues.insert( QgsPalLayerSettings::ShadowUnder, QVariant( static_cast< int >( shdwtype ) ) );
3767  }
3768  }
3769  }
3770 
3771  // data defined shadow offset angle?
3772  dataDefinedValEval( DDRotation180, QgsPalLayerSettings::ShadowOffsetAngle, exprVal, context.expressionContext(), shadow.offsetAngle() );
3773 
3774  // data defined shadow offset units?
3775  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShadowOffsetUnits, exprVal, context.expressionContext() );
3776 
3777  // data defined shadow radius?
3778  dataDefinedValEval( DDDouble, QgsPalLayerSettings::ShadowRadius, exprVal, context.expressionContext(), shadow.blurRadius() );
3779 
3780  // data defined shadow radius units?
3781  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShadowRadiusUnits, exprVal, context.expressionContext() );
3782 
3783  // data defined shadow scale? ( gui bounds to 0-2000, no upper bound here )
3784  dataDefinedValEval( DDIntPos, QgsPalLayerSettings::ShadowScale, exprVal, context.expressionContext(), shadow.scale() );
3785 
3786  // data defined shadow color?
3787  dataDefinedValEval( DDColor, QgsPalLayerSettings::ShadowColor, exprVal, context.expressionContext(), QgsSymbolLayerUtils::encodeColor( shadow.color() ) );
3788 
3789  // data defined shadow blend mode?
3790  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::ShadowBlendMode, exprVal, context.expressionContext() );
3791 }
3792 
3793 // -------------
3794 
3795 
3797 {
3798  switch ( layer->type() )
3799  {
3801  {
3802  const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer );
3803  return vl->labelsEnabled() || vl->diagramsEnabled();
3804  }
3805 
3807  {
3808  const QgsVectorTileLayer *vl = qobject_cast< const QgsVectorTileLayer * >( layer );
3809  if ( !vl->labeling() )
3810  return false;
3811 
3812  if ( const QgsVectorTileBasicLabeling *labeling = dynamic_cast< const QgsVectorTileBasicLabeling *>( vl->labeling() ) )
3813  return !labeling->styles().empty();
3814 
3815  return false;
3816  }
3817 
3824  return false;
3825  }
3826  return false;
3827 }
3828 
3829 
3830 bool QgsPalLabeling::geometryRequiresPreparation( const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry, bool mergeLines )
3831 {
3832  if ( geometry.isNull() )
3833  {
3834  return false;
3835  }
3836 
3837  if ( geometry.type() == QgsWkbTypes::LineGeometry && geometry.isMultipart() && mergeLines )
3838  {
3839  return true;
3840  }
3841 
3842  //requires reprojection
3843  if ( ct.isValid() && !ct.isShortCircuited() )
3844  return true;
3845 
3846  //requires rotation
3847  const QgsMapToPixel &m2p = context.mapToPixel();
3848  if ( !qgsDoubleNear( m2p.mapRotation(), 0 ) )
3849  return true;
3850 
3851  //requires clip
3852  if ( !clipGeometry.isNull() && !clipGeometry.boundingBox().contains( geometry.boundingBox() ) )
3853  return true;
3854 
3855  //requires fixing
3856  if ( geometry.type() == QgsWkbTypes::PolygonGeometry && !geometry.isGeosValid() )
3857  return true;
3858 
3859  return false;
3860 }
3861 
3862 QStringList QgsPalLabeling::splitToLines( const QString &text, const QString &wrapCharacter, const int autoWrapLength, const bool useMaxLineLengthWhenAutoWrapping )
3863 {
3864  QStringList multiLineSplit;
3865  if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
3866  {
3867  //wrap on both the wrapchr and new line characters
3868  const QStringList lines = text.split( wrapCharacter );
3869  for ( const QString &line : lines )
3870  {
3871  multiLineSplit.append( line.split( '\n' ) );
3872  }
3873  }
3874  else
3875  {
3876  multiLineSplit = text.split( '\n' );
3877  }
3878 
3879  // apply auto wrapping to each manually created line
3880  if ( autoWrapLength != 0 )
3881  {
3882  QStringList autoWrappedLines;
3883  autoWrappedLines.reserve( multiLineSplit.count() );
3884  for ( const QString &line : std::as_const( multiLineSplit ) )
3885  {
3886  autoWrappedLines.append( QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split( '\n' ) );
3887  }
3888  multiLineSplit = autoWrappedLines;
3889  }
3890  return multiLineSplit;
3891 }
3892 
3893 QStringList QgsPalLabeling::splitToGraphemes( const QString &text )
3894 {
3895  QStringList graphemes;
3896  QTextBoundaryFinder boundaryFinder( QTextBoundaryFinder::Grapheme, text );
3897  int currentBoundary = -1;
3898  int previousBoundary = 0;
3899  while ( ( currentBoundary = boundaryFinder.toNextBoundary() ) > 0 )
3900  {
3901  graphemes << text.mid( previousBoundary, currentBoundary - previousBoundary );
3902  previousBoundary = currentBoundary;
3903  }
3904  return graphemes;
3905 }
3906 
3907 QgsGeometry QgsPalLabeling::prepareGeometry( const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry, bool mergeLines )
3908 {
3909  if ( geometry.isNull() )
3910  {
3911  return QgsGeometry();
3912  }
3913 
3914  //don't modify the feature's geometry so that geometry based expressions keep working
3915  QgsGeometry geom = geometry;
3916 
3917  if ( geom.type() == QgsWkbTypes::LineGeometry && geom.isMultipart() && mergeLines )
3918  {
3919  geom = geom.mergeLines();
3920  }
3921 
3922  //reproject the geometry if necessary
3923  if ( ct.isValid() && !ct.isShortCircuited() )
3924  {
3925  try
3926  {
3927  geom.transform( ct );
3928  }
3929  catch ( QgsCsException &cse )
3930  {
3931  Q_UNUSED( cse )
3932  QgsDebugMsgLevel( QStringLiteral( "Ignoring feature due to transformation exception" ), 4 );
3933  return QgsGeometry();
3934  }
3935  // geometry transforms may result in nan points, remove these
3936  geom.filterVertices( []( const QgsPoint & point )->bool
3937  {
3938  return std::isfinite( point.x() ) && std::isfinite( point.y() );
3939  } );
3940  if ( QgsCurvePolygon *cp = qgsgeometry_cast< QgsCurvePolygon * >( geom.get() ) )
3941  {
3942  cp->removeInvalidRings();
3943  }
3944  else if ( QgsMultiSurface *ms = qgsgeometry_cast< QgsMultiSurface * >( geom.get() ) )
3945  {
3946  for ( int i = 0; i < ms->numGeometries(); ++i )
3947  {
3948  if ( QgsCurvePolygon *cp = qgsgeometry_cast< QgsCurvePolygon * >( ms->geometryN( i ) ) )
3949  cp->removeInvalidRings();
3950  }
3951  }
3952  }
3953 
3954  // Rotate the geometry if needed, before clipping
3955  const QgsMapToPixel &m2p = context.mapToPixel();
3956  if ( !qgsDoubleNear( m2p.mapRotation(), 0 ) )
3957  {
3958  QgsPointXY center = context.mapExtent().center();
3959  if ( geom.rotate( m2p.mapRotation(), center ) != Qgis::GeometryOperationResult::Success )
3960  {
3961  QgsDebugMsg( QStringLiteral( "Error rotating geometry" ).arg( geom.asWkt() ) );
3962  return QgsGeometry();
3963  }
3964  }
3965 
3966 #if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=9 )
3967  // much faster code path for GEOS 3.9+
3968  const bool mustClip = ( !clipGeometry.isNull() &&
3969  ( ( qgsDoubleNear( m2p.mapRotation(), 0 ) && !clipGeometry.boundingBox().contains( geom.boundingBox() ) )
3970  || ( !qgsDoubleNear( m2p.mapRotation(), 0 ) && !clipGeometry.contains( geom ) ) ) );
3971 
3972  bool mustClipExact = false;
3973  if ( mustClip )
3974  {
3975  // nice and fast, but can result in invalid geometries. At least it will potentially strip out a bunch of unwanted vertices upfront!
3976  QgsGeometry clipGeom = geom.clipped( clipGeometry.boundingBox() );
3977  if ( clipGeom.isEmpty() )
3978  return QgsGeometry();
3979 
3980  geom = clipGeom;
3981 
3982  // we've now clipped against the BOUNDING BOX of clipGeometry. But if clipGeometry is an axis parallel rectangle, then there's no
3983  // need to do an exact (potentially costly) intersection clip as well!
3984  mustClipExact = !clipGeometry.isAxisParallelRectangle( 0.001 );
3985  }
3986 
3987  // fix invalid polygons
3988  if ( geom.type() == QgsWkbTypes::PolygonGeometry )
3989  {
3990  if ( geom.isMultipart() )
3991  {
3992  // important -- we need to treat ever part in isolation here. We can't test the validity of the whole geometry
3993  // at once, because touching parts would result in an invalid geometry, and buffering this "dissolves" the parts.
3994  // because the actual label engine treats parts as separate entities, we aren't bound by the usual "touching parts are invalid" rule
3995  // see https://github.com/qgis/QGIS/issues/26763
3996  QVector< QgsGeometry> parts;
3997  parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() )->numGeometries() );
3998  for ( auto it = geom.const_parts_begin(); it != geom.const_parts_end(); ++it )
3999  {
4000  QgsGeometry partGeom( ( *it )->clone() );
4001  if ( !partGeom.isGeosValid() )
4002  {
4003 
4004  partGeom = partGeom.makeValid();
4005  }
4006  parts.append( partGeom );
4007  }
4008  geom = QgsGeometry::collectGeometry( parts );
4009  }
4010  else if ( !geom.isGeosValid() )
4011  {
4012 
4013  QgsGeometry bufferGeom = geom.makeValid();
4014  if ( bufferGeom.isNull() )
4015  {
4016  QgsDebugMsg( QStringLiteral( "Could not repair geometry: %1" ).arg( bufferGeom.lastError() ) );
4017  return QgsGeometry();
4018  }
4019  geom = bufferGeom;
4020  }
4021  }
4022 
4023  if ( mustClipExact )
4024  {
4025  // now do the real intersection against the actual clip geometry
4026  QgsGeometry clipGeom = geom.intersection( clipGeometry );
4027  if ( clipGeom.isEmpty() )
4028  {
4029  return QgsGeometry();
4030  }
4031  geom = clipGeom;
4032  }
4033 #else
4034  // fix invalid polygons
4035  if ( geom.type() == QgsWkbTypes::PolygonGeometry )
4036  {
4037  if ( geom.isMultipart() )
4038  {
4039  // important -- we need to treat ever part in isolation here. We can't test the validity of the whole geometry
4040  // at once, because touching parts would result in an invalid geometry, and buffering this "dissolves" the parts.
4041  // because the actual label engine treats parts as separate entities, we aren't bound by the usual "touching parts are invalid" rule
4042  // see https://github.com/qgis/QGIS/issues/26763
4043  QVector< QgsGeometry> parts;
4044  parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() )->numGeometries() );
4045  for ( auto it = geom.const_parts_begin(); it != geom.const_parts_end(); ++it )
4046  {
4047  QgsGeometry partGeom( ( *it )->clone() );
4048  if ( !partGeom.isGeosValid() )
4049  {
4050  partGeom = partGeom.buffer( 0, 0 );
4051  }
4052  parts.append( partGeom );
4053  }
4054  geom = QgsGeometry::collectGeometry( parts );
4055  }
4056  else if ( !geom.isGeosValid() )
4057  {
4058  QgsGeometry bufferGeom = geom.buffer( 0, 0 );
4059  if ( bufferGeom.isNull() )
4060  {
4061  QgsDebugMsg( QStringLiteral( "Could not repair geometry: %1" ).arg( bufferGeom.lastError() ) );
4062  return QgsGeometry();
4063  }
4064  geom = bufferGeom;
4065  }
4066  }
4067 
4068  if ( !clipGeometry.isNull() &&
4069  ( ( qgsDoubleNear( m2p.mapRotation(), 0 ) && !clipGeometry.boundingBox().contains( geom.boundingBox() ) )
4070  || ( !qgsDoubleNear( m2p.mapRotation(), 0 ) && !clipGeometry.contains( geom ) ) ) )
4071  {
4072  QgsGeometry clipGeom = geom.intersection( clipGeometry ); // creates new geometry
4073  if ( clipGeom.isEmpty() )
4074  {
4075  return QgsGeometry();
4076  }
4077  geom = clipGeom;
4078  }
4079 #endif
4080 
4081  return geom;
4082 }
4083 
4084 bool QgsPalLabeling::checkMinimumSizeMM( const QgsRenderContext &context, const QgsGeometry &geom, double minSize )
4085 {
4086  if ( minSize <= 0 )
4087  {
4088  return true;
4089  }
4090 
4091  if ( geom.isNull() )
4092  {
4093  return false;
4094  }
4095 
4096  QgsWkbTypes::GeometryType featureType = geom.type();
4097  if ( featureType == QgsWkbTypes::PointGeometry ) //minimum size does not apply to point features
4098  {
4099  return true;
4100  }
4101 
4102  double mapUnitsPerMM = context.mapToPixel().mapUnitsPerPixel() * context.scaleFactor();
4103  if ( featureType == QgsWkbTypes::LineGeometry )
4104  {
4105  double length = geom.length();
4106  if ( length >= 0.0 )
4107  {
4108  return ( length >= ( minSize * mapUnitsPerMM ) );
4109  }
4110  }
4111  else if ( featureType == QgsWkbTypes::PolygonGeometry )
4112  {
4113  double area = geom.area();
4114  if ( area >= 0.0 )
4115  {
4116  return ( std::sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
4117  }
4118  }
4119  return true; //should never be reached. Return true in this case to label such geometries anyway.
4120 }
4121 
4122 
4123 void QgsPalLabeling::dataDefinedTextStyle( QgsPalLayerSettings &tmpLyr,
4124  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4125 {
4126  QgsTextFormat format = tmpLyr.format();
4127  bool changed = false;
4128 
4129  //font color
4130  if ( ddValues.contains( QgsPalLayerSettings::Color ) )
4131  {
4132  QVariant ddColor = ddValues.value( QgsPalLayerSettings::Color );
4133  format.setColor( ddColor.value<QColor>() );
4134  changed = true;
4135  }
4136 
4137  //font transparency
4138  if ( ddValues.contains( QgsPalLayerSettings::FontOpacity ) )
4139  {
4140  format.setOpacity( ddValues.value( QgsPalLayerSettings::FontOpacity ).toDouble() / 100.0 );
4141  changed = true;
4142  }
4143 
4144  //font blend mode
4145  if ( ddValues.contains( QgsPalLayerSettings::FontBlendMode ) )
4146  {
4147  format.setBlendMode( static_cast< QPainter::CompositionMode >( ddValues.value( QgsPalLayerSettings::FontBlendMode ).toInt() ) );
4148  changed = true;
4149  }
4150 
4151  if ( changed )
4152  {
4153  tmpLyr.setFormat( format );
4154  }
4155 }
4156 
4157 void QgsPalLabeling::dataDefinedTextFormatting( QgsPalLayerSettings &tmpLyr,
4158  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4159 {
4160  if ( ddValues.contains( QgsPalLayerSettings::MultiLineWrapChar ) )
4161  {
4162  tmpLyr.wrapChar = ddValues.value( QgsPalLayerSettings::MultiLineWrapChar ).toString();
4163  }
4164 
4165  if ( ddValues.contains( QgsPalLayerSettings::AutoWrapLength ) )
4166  {
4167  tmpLyr.autoWrapLength = ddValues.value( QgsPalLayerSettings::AutoWrapLength ).toInt();
4168  }
4169 
4170  if ( ddValues.contains( QgsPalLayerSettings::MultiLineHeight ) )
4171  {
4172  QgsTextFormat format = tmpLyr.format();
4173  format.setLineHeight( ddValues.value( QgsPalLayerSettings::MultiLineHeight ).toDouble() );
4174  tmpLyr.setFormat( format );
4175  }
4176 
4177  if ( ddValues.contains( QgsPalLayerSettings::MultiLineAlignment ) )
4178  {
4179  tmpLyr.multilineAlign = static_cast< Qgis::LabelMultiLineAlignment >( ddValues.value( QgsPalLayerSettings::MultiLineAlignment ).toInt() );
4180  }
4181 
4182  if ( ddValues.contains( QgsPalLayerSettings::TextOrientation ) )
4183  {
4184  QgsTextFormat format = tmpLyr.format();
4186  tmpLyr.setFormat( format );
4187  }
4188 
4189  if ( ddValues.contains( QgsPalLayerSettings::DirSymbDraw ) )
4190  {
4191  tmpLyr.lineSettings().setAddDirectionSymbol( ddValues.value( QgsPalLayerSettings::DirSymbDraw ).toBool() );
4192  }
4193 
4194  if ( tmpLyr.lineSettings().addDirectionSymbol() )
4195  {
4196 
4197  if ( ddValues.contains( QgsPalLayerSettings::DirSymbLeft ) )
4198  {
4199  tmpLyr.lineSettings().setLeftDirectionSymbol( ddValues.value( QgsPalLayerSettings::DirSymbLeft ).toString() );
4200  }
4201  if ( ddValues.contains( QgsPalLayerSettings::DirSymbRight ) )
4202  {
4203  tmpLyr.lineSettings().setRightDirectionSymbol( ddValues.value( QgsPalLayerSettings::DirSymbRight ).toString() );
4204  }
4205 
4206  if ( ddValues.contains( QgsPalLayerSettings::DirSymbPlacement ) )
4207  {
4209  }
4210 
4211  if ( ddValues.contains( QgsPalLayerSettings::DirSymbReverse ) )
4212  {
4213  tmpLyr.lineSettings().setReverseDirectionSymbol( ddValues.value( QgsPalLayerSettings::DirSymbReverse ).toBool() );
4214  }
4215 
4216  }
4217 }
4218 
4219 void QgsPalLabeling::dataDefinedTextBuffer( QgsPalLayerSettings &tmpLyr,
4220  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4221 {
4222  QgsTextBufferSettings buffer = tmpLyr.format().buffer();
4223  bool changed = false;
4224 
4225  //buffer draw
4226  if ( ddValues.contains( QgsPalLayerSettings::BufferDraw ) )
4227  {
4228  buffer.setEnabled( ddValues.value( QgsPalLayerSettings::BufferDraw ).toBool() );
4229  changed = true;
4230  }
4231 
4232  if ( !buffer.enabled() )
4233  {
4234  if ( changed )
4235  {
4236  QgsTextFormat format = tmpLyr.format();
4237  format.setBuffer( buffer );
4238  tmpLyr.setFormat( format );
4239  }
4240 
4241  // tmpLyr.bufferSize > 0.0 && tmpLyr.bufferTransp < 100 figured in during evaluation
4242  return; // don't continue looking for unused values
4243  }
4244 
4245  //buffer size
4246  if ( ddValues.contains( QgsPalLayerSettings::BufferSize ) )
4247  {
4248  buffer.setSize( ddValues.value( QgsPalLayerSettings::BufferSize ).toDouble() );
4249  changed = true;
4250  }
4251 
4252  //buffer opacity
4253  if ( ddValues.contains( QgsPalLayerSettings::BufferOpacity ) )
4254  {
4255  buffer.setOpacity( ddValues.value( QgsPalLayerSettings::BufferOpacity ).toDouble() / 100.0 );
4256  changed = true;
4257  }
4258 
4259  //buffer size units
4260  if ( ddValues.contains( QgsPalLayerSettings::BufferUnit ) )
4261  {
4262  QgsUnitTypes::RenderUnit bufunit = static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::BufferUnit ).toInt() );
4263  buffer.setSizeUnit( bufunit );
4264  changed = true;
4265  }
4266 
4267  //buffer color
4268  if ( ddValues.contains( QgsPalLayerSettings::BufferColor ) )
4269  {
4270  QVariant ddColor = ddValues.value( QgsPalLayerSettings::BufferColor );
4271  buffer.setColor( ddColor.value<QColor>() );
4272  changed = true;
4273  }
4274 
4275  //buffer pen join style
4276  if ( ddValues.contains( QgsPalLayerSettings::BufferJoinStyle ) )
4277  {
4278  buffer.setJoinStyle( static_cast< Qt::PenJoinStyle >( ddValues.value( QgsPalLayerSettings::BufferJoinStyle ).toInt() ) );
4279  changed = true;
4280  }
4281 
4282  //buffer blend mode
4283  if ( ddValues.contains( QgsPalLayerSettings::BufferBlendMode ) )
4284  {
4285  buffer.setBlendMode( static_cast< QPainter::CompositionMode >( ddValues.value( QgsPalLayerSettings::BufferBlendMode ).toInt() ) );
4286  changed = true;
4287  }
4288 
4289  if ( changed )
4290  {
4291  QgsTextFormat format = tmpLyr.format();
4292  format.setBuffer( buffer );
4293  tmpLyr.setFormat( format );
4294  }
4295 }
4296 
4297 void QgsPalLabeling::dataDefinedTextMask( QgsPalLayerSettings &tmpLyr,
4298  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4299 {
4300  if ( ddValues.isEmpty() )
4301  return;
4302 
4303  QgsTextMaskSettings mask = tmpLyr.format().mask();
4304  bool changed = false;
4305 
4306  // enabled ?
4307  if ( ddValues.contains( QgsPalLayerSettings::MaskEnabled ) )
4308  {
4309  mask.setEnabled( ddValues.value( QgsPalLayerSettings::MaskEnabled ).toBool() );
4310  changed = true;
4311  }
4312 
4313  if ( !mask.enabled() )
4314  {
4315  if ( changed )
4316  {
4317  QgsTextFormat format = tmpLyr.format();
4318  format.setMask( mask );
4319  tmpLyr.setFormat( format );
4320  }
4321 
4322  // tmpLyr.bufferSize > 0.0 && tmpLyr.bufferTransp < 100 figured in during evaluation
4323  return; // don't continue looking for unused values
4324  }
4325 
4326  // buffer size
4327  if ( ddValues.contains( QgsPalLayerSettings::MaskBufferSize ) )
4328  {
4329  mask.setSize( ddValues.value( QgsPalLayerSettings::MaskBufferSize ).toDouble() );
4330  changed = true;
4331  }
4332 
4333  // opacity
4334  if ( ddValues.contains( QgsPalLayerSettings::MaskOpacity ) )
4335  {
4336  mask.setOpacity( ddValues.value( QgsPalLayerSettings::MaskOpacity ).toDouble() / 100.0 );
4337  changed = true;
4338  }
4339 
4340  // buffer size units
4341  if ( ddValues.contains( QgsPalLayerSettings::MaskBufferUnit ) )
4342  {
4343  QgsUnitTypes::RenderUnit bufunit = static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::MaskBufferUnit ).toInt() );
4344  mask.setSizeUnit( bufunit );
4345  changed = true;
4346  }
4347 
4348  // pen join style
4349  if ( ddValues.contains( QgsPalLayerSettings::MaskJoinStyle ) )
4350  {
4351  mask.setJoinStyle( static_cast< Qt::PenJoinStyle >( ddValues.value( QgsPalLayerSettings::MaskJoinStyle ).toInt() ) );
4352  changed = true;
4353  }
4354 
4355  if ( changed )
4356  {
4357  QgsTextFormat format = tmpLyr.format();
4358  format.setMask( mask );
4359  tmpLyr.setFormat( format );
4360  }
4361 }
4362 
4363 void QgsPalLabeling::dataDefinedShapeBackground( QgsPalLayerSettings &tmpLyr,
4364  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4365 {
4366  QgsTextBackgroundSettings background = tmpLyr.format().background();
4367  bool changed = false;
4368 
4369  //shape draw
4370  if ( ddValues.contains( QgsPalLayerSettings::ShapeDraw ) )
4371  {
4372  background.setEnabled( ddValues.value( QgsPalLayerSettings::ShapeDraw ).toBool() );
4373  changed = true;
4374  }
4375 
4376  if ( !background.enabled() )
4377  {
4378  if ( changed )
4379  {
4380  QgsTextFormat format = tmpLyr.format();
4381  format.setBackground( background );
4382  tmpLyr.setFormat( format );
4383  }
4384  return; // don't continue looking for unused values
4385  }
4386 
4387  if ( ddValues.contains( QgsPalLayerSettings::ShapeKind ) )
4388  {
4389  background.setType( static_cast< QgsTextBackgroundSettings::ShapeType >( ddValues.value( QgsPalLayerSettings::ShapeKind ).toInt() ) );
4390  changed = true;
4391  }
4392 
4393  if ( ddValues.contains( QgsPalLayerSettings::ShapeSVGFile ) )
4394  {
4395  background.setSvgFile( ddValues.value( QgsPalLayerSettings::ShapeSVGFile ).toString() );
4396  changed = true;
4397  }
4398 
4399  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeType ) )
4400  {
4401  background.setSizeType( static_cast< QgsTextBackgroundSettings::SizeType >( ddValues.value( QgsPalLayerSettings::ShapeSizeType ).toInt() ) );
4402  changed = true;
4403  }
4404 
4405  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeX ) )
4406  {
4407  QSizeF size = background.size();
4408  size.setWidth( ddValues.value( QgsPalLayerSettings::ShapeSizeX ).toDouble() );
4409  background.setSize( size );
4410  changed = true;
4411  }
4412  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeY ) )
4413  {
4414  QSizeF size = background.size();
4415  size.setHeight( ddValues.value( QgsPalLayerSettings::ShapeSizeY ).toDouble() );
4416  background.setSize( size );
4417  changed = true;
4418  }
4419 
4420  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeUnits ) )
4421  {
4422  background.setSizeUnit( static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::ShapeSizeUnits ).toInt() ) );
4423  changed = true;
4424  }
4425 
4426  if ( ddValues.contains( QgsPalLayerSettings::ShapeRotationType ) )
4427  {
4428  background.setRotationType( static_cast< QgsTextBackgroundSettings::RotationType >( ddValues.value( QgsPalLayerSettings::ShapeRotationType ).toInt() ) );
4429  changed = true;
4430  }
4431 
4432  if ( ddValues.contains( QgsPalLayerSettings::ShapeRotation ) )
4433  {
4434  background.setRotation( ddValues.value( QgsPalLayerSettings::ShapeRotation ).toDouble() );
4435  changed = true;
4436  }
4437 
4438  if ( ddValues.contains( QgsPalLayerSettings::ShapeOffset ) )
4439  {
4440  background.setOffset( ddValues.value( QgsPalLayerSettings::ShapeOffset ).toPointF() );
4441  changed = true;
4442  }
4443 
4444  if ( ddValues.contains( QgsPalLayerSettings::ShapeOffsetUnits ) )
4445  {
4446  background.setOffsetUnit( static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::ShapeOffsetUnits ).toInt() ) );
4447  changed = true;
4448  }
4449 
4450  if ( ddValues.contains( QgsPalLayerSettings::ShapeRadii ) )
4451  {
4452  background.setRadii( ddValues.value( QgsPalLayerSettings::ShapeRadii ).toSizeF() );
4453  changed = true;
4454  }
4455 
4456  if ( ddValues.contains( QgsPalLayerSettings::ShapeRadiiUnits ) )
4457  {
4458  background.setRadiiUnit( static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::ShapeRadiiUnits ).toInt() ) );
4459  changed = true;
4460  }
4461 
4462  if ( ddValues.contains( QgsPalLayerSettings::ShapeBlendMode ) )
4463  {
4464  background.setBlendMode( static_cast< QPainter::CompositionMode >( ddValues.value( QgsPalLayerSettings::ShapeBlendMode ).toInt() ) );
4465  changed = true;
4466  }
4467 
4468  if ( ddValues.contains( QgsPalLayerSettings::ShapeFillColor ) )
4469  {
4470  QVariant ddColor = ddValues.value( QgsPalLayerSettings::ShapeFillColor );
4471  background.setFillColor( ddColor.value<QColor>() );
4472  changed = true;
4473  }
4474 
4475  if ( ddValues.contains( QgsPalLayerSettings::ShapeStrokeColor ) )
4476  {
4477  QVariant ddColor = ddValues.value( QgsPalLayerSettings::ShapeStrokeColor );
4478  background.setStrokeColor( ddColor.value<QColor>() );
4479  changed = true;
4480  }
4481 
4482  if ( ddValues.contains( QgsPalLayerSettings::ShapeOpacity ) )
4483  {
4484  background.setOpacity( ddValues.value( QgsPalLayerSettings::ShapeOpacity ).toDouble() / 100.0 );
4485  changed = true;
4486  }
4487 
4488  if ( ddValues.contains( QgsPalLayerSettings::ShapeStrokeWidth ) )
4489  {
4490  background.setStrokeWidth( ddValues.value( QgsPalLayerSettings::ShapeStrokeWidth ).toDouble() );
4491  changed = true;
4492  }
4493 
4494  if ( ddValues.contains( QgsPalLayerSettings::ShapeStrokeWidthUnits ) )
4495  {
4496  background.setStrokeWidthUnit( static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::ShapeStrokeWidthUnits ).toInt() ) );
4497  changed = true;
4498  }
4499 
4500  if ( ddValues.contains( QgsPalLayerSettings::ShapeJoinStyle ) )
4501  {
4502  background.setJoinStyle( static_cast< Qt::PenJoinStyle >( ddValues.value( QgsPalLayerSettings::ShapeJoinStyle ).toInt() ) );
4503  changed = true;
4504  }
4505 
4506  if ( changed )
4507  {
4508  QgsTextFormat format = tmpLyr.format();
4509  format.setBackground( background );
4510  tmpLyr.setFormat( format );
4511  }
4512 }
4513 
4514 void QgsPalLabeling::dataDefinedDropShadow( QgsPalLayerSettings &tmpLyr,
4515  const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4516 {
4517  QgsTextShadowSettings shadow = tmpLyr.format().shadow();
4518  bool changed = false;
4519 
4520  //shadow draw
4521  if ( ddValues.contains( QgsPalLayerSettings::ShadowDraw ) )
4522  {
4523  shadow.setEnabled( ddValues.value( QgsPalLayerSettings::ShadowDraw ).toBool() );
4524  changed = true;
4525  }
4526 
4527  if ( !shadow.enabled() )
4528  {
4529  if ( changed )
4530  {
4531  QgsTextFormat format = tmpLyr.format();
4532  format.setShadow( shadow );
4533  tmpLyr.setFormat( format );
4534  }
4535  return; // don't continue looking for unused values
4536  }
4537 
4538  if ( ddValues.contains( QgsPalLayerSettings::ShadowUnder ) )
4539  {
4540  shadow.setShadowPlacement( static_cast< QgsTextShadowSettings::ShadowPlacement >( ddValues.value( QgsPalLayerSettings::ShadowUnder ).toInt() ) );
4541  changed = true;
4542  }
4543 
4544  if ( ddValues.contains( QgsPalLayerSettings::ShadowOffsetAngle ) )
4545  {
4546  shadow.setOffsetAngle( ddValues.value( QgsPalLayerSettings::ShadowOffsetAngle ).toInt() );
4547  changed = true;
4548  }
4549 
4550  if ( ddValues.contains( QgsPalLayerSettings::ShadowOffsetDist ) )
4551  {
4552  shadow.setOffsetDistance( ddValues.value( QgsPalLayerSettings::ShadowOffsetDist ).toDouble() );
4553  changed = true;
4554  }
4555 
4556  if ( ddValues.contains( QgsPalLayerSettings::ShadowOffsetUnits ) )
4557  {
4558  shadow.setOffsetUnit( static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::ShadowOffsetUnits ).toInt() ) );
4559  changed = true;
4560  }
4561 
4562  if ( ddValues.contains( QgsPalLayerSettings::ShadowRadius ) )
4563  {
4564  shadow.setBlurRadius( ddValues.value( QgsPalLayerSettings::ShadowRadius ).toDouble() );
4565  changed = true;
4566  }
4567 
4568  if ( ddValues.contains( QgsPalLayerSettings::ShadowRadiusUnits ) )
4569  {
4570  shadow.setBlurRadiusUnit( static_cast< QgsUnitTypes::RenderUnit >( ddValues.value( QgsPalLayerSettings::ShadowRadiusUnits ).toInt() ) );
4571  changed = true;
4572  }
4573 
4574  if ( ddValues.contains( QgsPalLayerSettings::ShadowColor ) )
4575  {
4576  QVariant ddColor = ddValues.value( QgsPalLayerSettings::ShadowColor );
4577  shadow.setColor( ddColor.value<QColor>() );
4578  changed = true;
4579  }
4580 
4581  if ( ddValues.contains( QgsPalLayerSettings::ShadowOpacity ) )
4582  {
4583  shadow.setOpacity( ddValues.value( QgsPalLayerSettings::ShadowOpacity ).toDouble() / 100.0 );
4584  changed = true;
4585  }
4586 
4587  if ( ddValues.contains( QgsPalLayerSettings::ShadowScale ) )
4588  {
4589  shadow.setScale( ddValues.value( QgsPalLayerSettings::ShadowScale ).toInt() );
4590  changed = true;
4591  }
4592 
4593 
4594  if ( ddValues.contains( QgsPalLayerSettings::ShadowBlendMode ) )
4595  {
4596  shadow.setBlendMode( static_cast< QPainter::CompositionMode >( ddValues.value( QgsPalLayerSettings::ShadowBlendMode ).toInt() ) );
4597  changed = true;
4598  }
4599 
4600  if ( changed )
4601  {
4602  QgsTextFormat format = tmpLyr.format();
4603  format.setShadow( shadow );
4604  tmpLyr.setFormat( format );
4605  }
4606 }
4607 
4608 void QgsPalLabeling::drawLabelCandidateRect( pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList<QgsLabelCandidate> *candidates )
4609 {
4610  QgsPointXY outPt = xform->transform( lp->getX(), lp->getY() );
4611 
4612  painter->save();
4613 
4614 #if 0 // TODO: generalize some of this
4615  double w = lp->getWidth();
4616  double h = lp->getHeight();
4617  double cx = lp->getX() + w / 2.0;
4618  double cy = lp->getY() + h / 2.0;
4619  double scale = 1.0 / xform->mapUnitsPerPixel();
4620  double rotation = xform->mapRotation();
4621  double sw = w * scale;
4622  double sh = h * scale;
4623  QRectF rect( -sw / 2, -sh / 2, sw, sh );
4624 
4625  painter->translate( xform->transform( QPointF( cx, cy ) ).toQPointF() );
4626  if ( rotation )
4627  {
4628  // Only if not horizontal
4629  if ( lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT &&
4630  lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT_OVER &&
4631  lp->getFeaturePart()->getLayer()->getArrangement() != P_HORIZ )
4632  {
4633  painter->rotate( rotation );
4634  }
4635  }
4636  painter->translate( rect.bottomLeft() );
4637  painter->rotate( -lp->getAlpha() * 180 / M_PI );
4638  painter->translate( -rect.bottomLeft() );
4639 #else
4640  QgsPointXY outPt2 = xform->transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
4641  QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
4642  painter->translate( QPointF( outPt.x(), outPt.y() ) );
4643  painter->rotate( -lp->getAlpha() * 180 / M_PI );
4644 #endif
4645 
4646  if ( lp->conflictsWithObstacle() )
4647  {
4648  painter->setPen( QColor( 255, 0, 0, 64 ) );
4649  }
4650  else
4651  {
4652  painter->setPen( QColor( 0, 0, 0, 64 ) );
4653  }
4654  painter->drawRect( rect );
4655  painter->restore();
4656 
4657  // save the rect
4658  rect.moveTo( outPt.x(), outPt.y() );
4659  if ( candidates )
4660  candidates->append( QgsLabelCandidate( rect, lp->cost() * 1000 ) );
4661 
4662  // show all parts of the multipart label
4663  if ( lp->nextPart() )
4664  drawLabelCandidateRect( lp->nextPart(), painter, xform, candidates );
4665 }
QgsLabelLineSettings::setDirectionSymbolPlacement
void setDirectionSymbolPlacement(DirectionSymbolPlacement placement)
Sets the placement for direction symbols.
Definition: qgslabellinesettings.h:224
QgsTextMaskSettings::setSize
void setSize(double size)
Sets the size of the buffer.
Definition: qgstextmasksettings.cpp:90
QgsPropertyDefinition::RenderUnits
@ RenderUnits
Render units (eg mm/pixels/map units)
Definition: qgsproperty.h:63
QgsPalLayerSettings::previewBkgrdColor
Q_DECL_DEPRECATED QColor previewBkgrdColor
Definition: qgspallabeling.h:370
QgsPalLayerSettings::ShadowBlendMode
@ ShadowBlendMode
Definition: qgspallabeling.h:231
QgsGeometry::lastError
QString lastError() const SIP_HOLDGIL
Returns an error string referring to the last error encountered either when this geometry was created...
Definition: qgsgeometry.cpp:3308
QgsPalLayerSettings::BufferBlendMode
@ BufferBlendMode
Definition: qgspallabeling.h:187
QgsLabelLineSettings::AnchorClipping::UseEntireLine
@ UseEntireLine
Entire original feature line geometry is used when calculating the line anchor for labels.
QgsTextBufferSettings::setSizeUnit
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
Definition: qgstextbuffersettings.cpp:97
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsPalLayerSettings::ShadowRadius
@ ShadowRadius
Definition: qgspallabeling.h:225
QgsPalLayerSettings::useSubstitutions
bool useSubstitutions
True if substitutions should be applied.
Definition: qgspallabeling.h:375
QgsPalLayerSettings::preserveRotation
bool preserveRotation
True if label rotation should be preserved during label pin/unpin operations.
Definition: qgspallabeling.h:564
QgsPalLayerSettings::OffsetUnits
@ OffsetUnits
Definition: qgspallabeling.h:237
QgsPointXY::distance
double distance(double x, double y) const SIP_HOLDGIL
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspointxy.h:211
QgsLabelLineSettings::updateDataDefinedProperties
void updateDataDefinedProperties(const QgsPropertyCollection &properties, QgsExpressionContext &context)
Updates the thinning settings to respect any data defined properties set within the specified propert...
Definition: qgslabellinesettings.cpp:23
QgsLabelObstacleSettings::updateDataDefinedProperties
void updateDataDefinedProperties(const QgsPropertyCollection &properties, QgsExpressionContext &context)
Updates the obstacle settings to respect any data defined properties set within the specified propert...
Definition: qgslabelobstaclesettings.cpp:31
QgsTextMaskSettings::enabled
bool enabled() const
Returns whether the mask is enabled.
Definition: qgstextmasksettings.cpp:64
QgsPalLayerSettings::placement
Qgis::LabelPlacement placement
Label placement mode.
Definition: qgspallabeling.h:434
Qgis::LabelPredefinedPointPosition::BottomSlightlyRight
@ BottomSlightlyRight
Label below point, slightly right of center.
QgsPalLayerSettings::DistanceUnits
@ DistanceUnits
Definition: qgspallabeling.h:239
QgsPalLayerSettings::ct
QgsCoordinateTransform ct
Definition: qgspallabeling.h:996
QgsVectorLayer::diagramsEnabled
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
Definition: qgsvectorlayer.cpp:799
QgsLabelObstacleSettings::setObstacleGeometry
void setObstacleGeometry(const QgsGeometry &obstacleGeom)
Sets the label's obstacle geometry, if different to the feature geometry.
Definition: qgslabelobstaclesettings.cpp:21
QgsPalLayerSettings::scaleVisibility
bool scaleVisibility
Set to true to limit label visibility to a range of scales.
Definition: qgspallabeling.h:605
QgsTextBackgroundSettings::setStrokeColor
void setStrokeColor(const QColor &color)
Sets the color used for outlining the background shape.
Definition: qgstextbackgroundsettings.cpp:316
QgsTextRendererUtils::decodeBackgroundSizeType
static QgsTextBackgroundSettings::SizeType decodeBackgroundSizeType(const QString &string)
Decodes a string representation of a background size type to a type.
Definition: qgstextrendererutils.cpp:48
QgsVectorSimplifyMethod
This class contains information how to simplify geometries fetched from a vector layer.
Definition: qgsvectorsimplifymethod.h:29
QgsPalLayerSettings::MaskEnabled
@ MaskEnabled
Whether the mask is enabled.
Definition: qgspallabeling.h:190
QgsVectorSimplifyMethod::NoSimplification
@ NoSimplification
No simplification can be applied.
Definition: qgsvectorsimplifymethod.h:52
QgsPalLayerSettings::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgspallabeling.cpp:953
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
QgsPropertyCollection::prepare
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
Definition: qgspropertycollection.cpp:240
QgsStringReplacementCollection::readXml
void readXml(const QDomElement &elem)
Reads the collection state from an XML element.
Definition: qgsstringutils.cpp:828
Qgis::LabelPlacement::Free
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
QgsPalLayerSettings::distUnits
QgsUnitTypes::RenderUnit distUnits
Units the distance from feature to the label.
Definition: qgspallabeling.h:490
pal::LabelPosition::getY
double getY(int i=0) const
Returns the down-left y coordinate.
Definition: labelposition.cpp:343
QgsPalLayerSettings::mFeaturesToLabel
int mFeaturesToLabel
Definition: qgspallabeling.h:1001
QgsProperty::fromField
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
Definition: qgsproperty.cpp:245
QgsAbstractPropertyCollection::valueAsDouble
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Definition: qgspropertycollection.cpp:66
QgsPalLayerSettings::MaskBufferSize
@ MaskBufferSize
Mask buffer size.
Definition: qgspallabeling.h:191
QgsSymbolLayerUtils::encodeColor
static QString encodeColor(const QColor &color)
Definition: qgssymbollayerutils.cpp:64
QgsPalLayerSettings::Hali
@ Hali
Horizontal alignment for data defined label position (Left, Center, Right)
Definition: qgspallabeling.h:246
QgsPalLayerSettings::NumFormat
@ NumFormat
Definition: qgspallabeling.h:175
QgsTextShadowSettings::setOpacity
void setOpacity(double opacity)
Sets the shadow's opacity.
Definition: qgstextshadowsettings.cpp:188
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsPropertyDefinition::Offset
@ Offset
2D offset
Definition: qgsproperty.h:78
qgspallabeling.h
QgsSymbolLayerUtils::decodeBlendMode
static QPainter::CompositionMode decodeBlendMode(const QString &s)
Definition: qgssymbollayerutils.cpp:854
QgsTextBufferSettings::setOpacity
void setOpacity(double opacity)
Sets the buffer opacity.
Definition: qgstextbuffersettings.cpp:137
QgsTextFormat::namedStyle
QString namedStyle() const
Returns the named style for the font used for rendering text (e.g., "bold").
Definition: qgstextformat.cpp:213
QgsTextBackgroundSettings::setRotationType
void setRotationType(RotationType type)
Sets the method used for rotating the background shape.
Definition: qgstextbackgroundsettings.cpp:202
qgsEnumValueToKey
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
Definition: qgis.h:2440
QgsTextShadowSettings::offsetDistance
double offsetDistance() const
Returns the distance for offsetting the position of the shadow from the text.
Definition: qgstextshadowsettings.cpp:103
QgsVectorTileLayer
Implements a map layer that is dedicated to rendering of vector tiles. Vector tiles compared to "ordi...
Definition: qgsvectortilelayer.h:84
QgsGeometry::convertGeometryCollectionToSubclass
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
Definition: qgsgeometry.cpp:1625
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:258
QgsStringUtils::capitalize
static QString capitalize(const QString &string, Qgis::Capitalization capitalization)
Converts a string by applying capitalization rules to the string.
Definition: qgsstringutils.cpp:24
qgslabelsearchtree.h
QgsPalLayerSettings::angleOffset
double angleOffset
Label rotation, in degrees clockwise.
Definition: qgspallabeling.h:561
QgsProperty
A store for object properties.
Definition: qgsproperty.h:230
QgsTextShadowSettings::setEnabled
void setEnabled(bool enabled)
Sets whether the text shadow will be drawn.
Definition: qgstextshadowsettings.cpp:78
Qgis::LabelPredefinedPointPosition::TopLeft
@ TopLeft
Label on top-left of point.
QgsTextBufferSettings::sizeMapUnitScale
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the buffer size.
Definition: qgstextbuffersettings.cpp:102
QgsPalLayerSettings::decimals
int decimals
Number of decimal places to show for numeric labels.
Definition: qgspallabeling.h:422
QgsPalLayerSettings::OffsetXY
@ OffsetXY
Definition: qgspallabeling.h:236
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
QgsPalLabeling::staticWillUseLayer
static bool staticWillUseLayer(const QgsMapLayer *layer)
Called to find out whether a specified layer is used for labeling.
Definition: qgspallabeling.cpp:3796
QgsCalloutRegistry::defaultCallout
static QgsCallout * defaultCallout()
Create a new instance of a callout with default settings.
Definition: qgscalloutsregistry.cpp:88
QgsGeometry::isAxisParallelRectangle
bool isAxisParallelRectangle(double maximumDeviation, bool simpleRectanglesOnly=false) const
Returns true if the geometry is a polygon that is almost an axis-parallel rectangle.
Definition: qgsgeometry.cpp:3039
QgsRenderContext::featureClipGeometry
QgsGeometry featureClipGeometry() const
Returns the geometry to use to clip features at render time.
Definition: qgsrendercontext.cpp:630
QgsAbstractPropertyCollection::valueAsInt
int valueAsInt(int key, const QgsExpressionContext &context, int defaultValue=0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an integer.
Definition: qgspropertycollection.cpp:77
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsMapToPixel::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns the current map units per pixel.
Definition: qgsmaptopixel.h:229
QgsMapLayerType::MeshLayer
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
QgsGeometry::filterVertices
void filterVertices(const std::function< bool(const QgsPoint &) > &filter)
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
Definition: qgsgeometry.cpp:3313
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsTextBackgroundSettings::enabled
bool enabled() const
Returns whether the background is enabled.
Definition: qgstextbackgroundsettings.cpp:107
QgsPalLayerSettings::maxCurvedCharAngleOut
double maxCurvedCharAngleOut
Maximum angle between outside curved label characters (valid range -20.0 to -95.0)
Definition: qgspallabeling.h:590
Qgis::LabelPlacement::OrderedPositionsAroundPoint
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
QgsExpression::evalErrorString
QString evalErrorString() const
Returns evaluation error.
Definition: qgsexpression.cpp:383
QgsTextFormat::shadow
QgsTextShadowSettings & shadow()
Returns a reference to the text drop shadow settings.
Definition: qgstextformat.cpp:136
QgsLabelLineSettings::setRightDirectionSymbol
void setRightDirectionSymbol(const QString &symbol)
Sets the string to use for right direction arrows.
Definition: qgslabellinesettings.h:190
QgsPalLayerSettings::offsetType
Qgis::LabelOffsetType offsetType
Offset type for layer (only applies in certain placement modes)
Definition: qgspallabeling.h:500
QgsPalLayerSettings::RepeatDistanceUnit
@ RepeatDistanceUnit
Definition: qgspallabeling.h:251
QgsMapLayerType::VectorLayer
@ VectorLayer
Vector layer.
QgsCallout
Abstract base class for callout renderers.
Definition: qgscallout.h:52
QgsTextFormat::previewBackgroundColor
QColor previewBackgroundColor() const
Returns the background color for text previews.
Definition: qgstextformat.cpp:393
QgsPropertyDefinition::BlendMode
@ BlendMode
Blend mode.
Definition: qgsproperty.h:67
QgsPalLayerSettings::MaximumScale
@ MaximumScale
Maximum map scale (ie most "zoomed in")
Definition: qgspallabeling.h:268
QgsExpression::referencedColumns
QSet< QString > referencedColumns() const
Gets list of columns referenced by the expression.
Definition: qgsexpression.cpp:221
QgsMapSettings::extentBuffer
double extentBuffer() const
Returns the buffer in map units to use around the visible extent for rendering symbols whose correspo...
Definition: qgsmapsettings.cpp:92
QgsPalLayerSettings::ShapeSizeType
@ ShapeSizeType
Definition: qgspallabeling.h:200
QgsPalLayerSettings::BufferSize
@ BufferSize
Definition: qgspallabeling.h:181
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:666
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
qgstextfragment.h
QgsTextBackgroundSettings::setSizeType
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
Definition: qgstextbackgroundsettings.cpp:162
QgsCoordinateReferenceSystem::userFriendlyIdentifier
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1212
QgsPalLayerSettings::Color
@ Color
Text color.
Definition: qgspallabeling.h:151
QgsTextBufferSettings::joinStyle
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
Definition: qgstextbuffersettings.cpp:142
QgsGeometry::const_parts_end
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry.
Definition: qgsgeometry.cpp:2026
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsGeometry::transform
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:3128
QgsTextBackgroundSettings::setStrokeWidth
void setStrokeWidth(double width)
Sets the width of the shape's stroke (stroke).
Definition: qgstextbackgroundsettings.cpp:330
labelposition.h
QgsPalLayerSettings
Contains settings for how a map layer will be labeled.
Definition: qgspallabeling.h:86
QgsMapToPixel::setParameters
void setParameters(double mapUnitsPerPixel, double centerX, double centerY, int widthPixels, int heightPixels, double rotation)
Sets parameters for use in transforming coordinates.
Definition: qgsmaptopixel.cpp:168
QgsLabelLineSettings::anchorTextPoint
AnchorTextPoint anchorTextPoint() const
Returns the line anchor text point, which dictates which part of the label text should be placed at t...
Definition: qgslabellinesettings.h:356
QgsPalLayerSettings::mFeatsSendingToPal
int mFeatsSendingToPal
Definition: qgspallabeling.h:1002
QgsTextLabelFeature::calculateTextMetrics
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().
Definition: qgstextlabelfeature.cpp:57
pal::LabelPosition::cost
double cost() const
Returns the candidate label position's geographical cost.
Definition: labelposition.h:206
qgsexpression.h
Qgis::Capitalization::AllUppercase
@ AllUppercase
Convert all characters to uppercase.
QgsPalLayerSettings::zIndex
double zIndex
Z-Index of label, where labels with a higher z-index are rendered on top of labels with a lower z-ind...
Definition: qgspallabeling.h:724
Qgis::LabelPlacement::OutsidePolygons
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only....
QgsPalLayerSettings::labelPerPart
bool labelPerPart
true if every part of a multi-part feature should be labeled.
Definition: qgspallabeling.h:659
QgsTextBackgroundSettings::setJoinStyle
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the background shape.
Definition: qgstextbackgroundsettings.cpp:374
QgsPropertyDefinition::DataTypeString
@ DataTypeString
Property requires a string value.
Definition: qgsproperty.h:92
QgsPalLayerSettings::PositionY
@ PositionY
Y-coordinate data defined label position.
Definition: qgspallabeling.h:244
QgsTextBufferSettings::setEnabled
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
Definition: qgstextbuffersettings.cpp:77
QgsTextFormat::orientation
TextOrientation orientation() const
Returns the orientation of the text.
Definition: qgstextformat.cpp:352
Qgis::UpsideDownLabelHandling
UpsideDownLabelHandling
Handling techniques for upside down labels.
Definition: qgis.h:642
QgsLabelLineSettings::setOverrunDistance
void setOverrunDistance(double distance)
Sets the distance which labels are allowed to overrun past the start or end of line features.
Definition: qgslabellinesettings.h:240
QgsPalLayerSettings::FontOpacity
@ FontOpacity
Text opacity.
Definition: qgspallabeling.h:157
QgsTextRendererUtils::decodeBackgroundRotationType
static QgsTextBackgroundSettings::RotationType decodeBackgroundRotationType(const QString &string)
Decodes a string representation of a background rotation type to a type.
Definition: qgstextrendererutils.cpp:61
QgsPalLayerSettings::MultiLineHeight
@ MultiLineHeight
Definition: qgspallabeling.h:167
QgsTextFormat::buffer
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
Definition: qgstextformat.cpp:112
QgsRectangle::center
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
QgsPalLayerSettings::ShapeOffsetUnits
@ ShapeOffsetUnits
Definition: qgspallabeling.h:207
QgsTextRenderer::AlignCenter
@ AlignCenter
Center align.
Definition: qgstextrenderer.h:61
crs
const QgsCoordinateReferenceSystem & crs
Definition: qgswfsgetfeature.cpp:105
QgsLabelThinningSettings::setMinimumFeatureSize
void setMinimumFeatureSize(double size)
Sets the minimum feature size (in millimeters) for a feature to be labelled.
Definition: qgslabelthinningsettings.h:78
pal::LabelPosition
LabelPosition is a candidate feature label position.
Definition: labelposition.h:55
QgsLabelLineSettings::setOverrunDistanceUnit
void setOverrunDistanceUnit(const QgsUnitTypes::RenderUnit &unit)
Sets the unit for label overrun distance.
Definition: qgslabellinesettings.h:256
QgsPalLayerSettings::BufferUnit
@ BufferUnit
Definition: qgspallabeling.h:182
QgsCurvePolygon
Curve polygon geometry type.
Definition: qgscurvepolygon.h:34
QgsMapLayerType::AnnotationLayer
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
QgsPalLayerSettings::ShapeFillColor
@ ShapeFillColor
Definition: qgspallabeling.h:213
QgsPalLayerSettings::getLabelExpression
QgsExpression * getLabelExpression()
Returns the QgsExpression for this label settings.
Definition: qgspallabeling.cpp:608
QgsRenderContext::setPainter
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
Definition: qgsrendercontext.h:512
QgsUnitTypes::RenderPoints
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
Qgis::Warning
@ Warning
Warning message.
Definition: qgis.h:117
QgsLabelThinningSettings::setMaximumNumberLabels
void setMaximumNumberLabels(int number)
Sets the maximum number of labels which should be drawn for this layer.
Definition: qgslabelthinningsettings.h:66
QgsExpressionContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Definition: qgsexpressioncontext.cpp:600
qgssymbollayerutils.h
QgsTextDocument::splitLines
void splitLines(const QString &wrapCharacter, int autoWrapLength=0, bool useMaxLineLengthWhenAutoWrapping=true)
Splits lines of text in the document to separate lines, using a specified wrap character (wrapCharact...
Definition: qgstextdocument.cpp:131
QgsAbstractPropertyCollection::readXml
virtual bool readXml(const QDomElement &collectionElem, const QgsPropertiesDefinition &definitions)
Reads property collection state from an XML element.
Definition: qgspropertycollection.cpp:108
QgsPalLayerSettings::BufferOpacity
@ BufferOpacity
Buffer opacity.
Definition: qgspallabeling.h:185
QgsPalLayerSettings::FontMaxPixel
@ FontMaxPixel
Definition: qgspallabeling.h:271
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsPalLayerSettings::fontMaxPixelSize
int fontMaxPixelSize
Maximum pixel size for showing rendered map unit labels (1 - 10000).
Definition: qgspallabeling.h:650
QgsGeometry::fromPointXY
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
Creates a new geometry from a QgsPointXY object.
Definition: qgsgeometry.cpp:176
QgsPalLayerSettings::CurvedCharAngleInOut
@ CurvedCharAngleInOut
Definition: qgspallabeling.h:241
QgsTextFormat::background
QgsTextBackgroundSettings & background()
Returns a reference to the text background settings.
Definition: qgstextformat.cpp:124
QgsPalLayerSettings::Strikeout
@ Strikeout
Use strikeout.
Definition: qgspallabeling.h:152
QgsPalLayerSettings::BufferJoinStyle
@ BufferJoinStyle
Definition: qgspallabeling.h:186
QgsPalLayerSettings::xform
const QgsMapToPixel * xform
Definition: qgspallabeling.h:995
QgsGeometry::centroid
QgsGeometry centroid() const
Returns the center of mass of a geometry.
Definition: qgsgeometry.cpp:2284
QgsProperty::asExpression
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
Definition: qgsproperty.cpp:398
QgsPalLayerSettings::yOffset
double yOffset
Vertical offset of label.
Definition: qgspallabeling.h:542
QgsPalLayerSettings::FontLimitPixel
@ FontLimitPixel
Definition: qgspallabeling.h:269
QgsPropertyDefinition::IntegerPositiveGreaterZero
@ IntegerPositiveGreaterZero
Non-zero positive integer values.
Definition: qgsproperty.h:56
QgsTextFormat::sizeUnit
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
Definition: qgstextformat.cpp:264
qgsmarkersymbollayer.h
QgsTextBackgroundSettings::fillColor
QColor fillColor() const
Returns the color used for filing the background shape.
Definition: qgstextbackgroundsettings.cpp:297
QgsTextBackgroundSettings
Container for settings relating to a text background object.
Definition: qgstextbackgroundsettings.h:46
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsVectorSimplifyMethod::simplifyAlgorithm
SimplifyAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:79
QgsPalLabeling::prepareGeometry
static QgsGeometry prepareGeometry(const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry=QgsGeometry(), bool mergeLines=false)
Prepares a geometry for registration with PAL.
Definition: qgspallabeling.cpp:3907
QgsLabelingUtils::encodePredefinedPositionOrder
static QString encodePredefinedPositionOrder(const QVector< Qgis::LabelPredefinedPointPosition > &positions)
Encodes an ordered list of predefined point label positions to a string.
Definition: qgslabelingengine.cpp:681
QgsUnitTypes::RenderPercentage
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
Definition: qgsunittypes.h:172
QgsRenderContext::convertToMapUnits
double convertToMapUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
Definition: qgsrendercontext.cpp:475
QgsTextShadowSettings::scale
int scale() const
Returns the scaling used for the drop shadow (in percentage of original size).
Definition: qgstextshadowsettings.cpp:193
QgsTextBufferSettings::opacity
double opacity() const
Returns the buffer opacity.
Definition: qgstextbuffersettings.cpp:132
QgsLabelThinningSettings::minimumFeatureSize
double minimumFeatureSize() const
Returns the minimum feature size (in millimeters) for a feature to be labelled.
Definition: qgslabelthinningsettings.h:72
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsLabelPlacementSettings::setAllowDegradedPlacement
void setAllowDegradedPlacement(bool allow)
Sets whether labels can be placed in inferior fallback positions if they cannot otherwise be placed.
Definition: qgslabelplacementsettings.h:70
QgsPalLayerSettings::PredefinedPositionOrder
@ PredefinedPositionOrder
Definition: qgspallabeling.h:253
QgsTextBackgroundSettings::SizeType
SizeType
Methods for determining the background shape size.
Definition: qgstextbackgroundsettings.h:66
QgsReferencedGeometry
A QgsGeometry with associated coordinate reference system.
Definition: qgsreferencedgeometry.h:155
QgsPropertyDefinition::DataTypeNumeric
@ DataTypeNumeric
Property requires a numeric value.
Definition: qgsproperty.h:99
QgsPropertyDefinition::Double
@ Double
Double value (including negative values)
Definition: qgsproperty.h:57
QgsPalLayerSettings::geometryGeneratorType
QgsWkbTypes::GeometryType geometryGeneratorType
The type of the result geometry of the geometry generator.
Definition: qgspallabeling.h:730
qgsunittypes.h
QgsVectorTileBasicLabeling
Basic labeling configuration for vector tile layers. It contains a definition of a list of labeling s...
Definition: qgsvectortilebasiclabeling.h:107
QgsTextMaskSettings::setSizeUnit
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
Definition: qgstextmasksettings.cpp:100
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
QgsPropertyDefinition::PenJoinStyle
@ PenJoinStyle
Pen join style.
Definition: qgsproperty.h:66
QgsTextBackgroundSettings::offset
QPointF offset() const
Returns the offset used for drawing the background shape.
Definition: qgstextbackgroundsettings.cpp:217
QgsTextRendererUtils::decodeTextOrientation
static QgsTextFormat::TextOrientation decodeTextOrientation(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a text orientation.
Definition: qgstextrendererutils.cpp:113
qgsdiagram.h
QgsGeometry::const_parts_begin
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
Definition: qgsgeometry.cpp:2019
QgsPalLayerSettings::Vali
@ Vali
Vertical alignment for data defined label position (Bottom, Base, Half, Cap, Top)
Definition: qgspallabeling.h:247
QgsPalLayerSettings::quadOffset
Qgis::LabelQuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
Definition: qgspallabeling.h:526
QgsTextBackgroundSettings::opacity
double opacity() const
Returns the background shape's opacity.
Definition: qgstextbackgroundsettings.cpp:277
QgsLabelObstacleSettings::setIsObstacle
void setIsObstacle(bool isObstacle)
Sets whether features are obstacles to labels of other layers.
Definition: qgslabelobstaclesettings.h:71
QgsSymbolLayerUtils::toSize
static QSizeF toSize(const QVariant &value, bool *ok=nullptr)
Converts a value to a size.
Definition: qgssymbollayerutils.cpp:615
layer.h
QgsPalLayerSettings::ShadowOffsetUnits
@ ShadowOffsetUnits
Definition: qgspallabeling.h:224
QgsPalLayerSettings::ShapeOpacity
@ ShapeOpacity
Shape opacity.
Definition: qgspallabeling.h:211
QgsTextRendererUtils::encodeTextOrientation
static QString encodeTextOrientation(QgsTextFormat::TextOrientation orientation)
Encodes a text orientation.
Definition: qgstextrendererutils.cpp:99
QgsPalLayerSettings::ShapeBlendMode
@ ShapeBlendMode
Definition: qgspallabeling.h:212
QgsPalLayerSettings::minimumScale
double minimumScale
The minimum map scale (i.e.
Definition: qgspallabeling.h:629
QgsPalLayerSettings::multilineAlign
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
Definition: qgspallabeling.h:407
QgsPalLayerSettings::substitutions
QgsStringReplacementCollection substitutions
Substitution collection for automatic text substitution with labels.
Definition: qgspallabeling.h:373
QgsLabelObstacleSettings
Contains settings related to how the label engine treats features as obstacles.
Definition: qgslabelobstaclesettings.h:34
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:92
QgsMultiSurface
Multi surface geometry collection.
Definition: qgsmultisurface.h:32
QgsProperty::fromExpression
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
Definition: qgsproperty.cpp:237
Qgis::Capitalization::TitleCase
@ TitleCase
Simple title case conversion - does not fully grammatically parse the text and uses simple rules only...
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
qgsfontutils.h
QgsTextBackgroundSettings::setBlendMode
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the background shape.
Definition: qgstextbackgroundsettings.cpp:292
QgsPalLayerSettings::referencedFields
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
Definition: qgspallabeling.cpp:509
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsRenderContext::scaleFactor
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:266
QgsMapToPixel::toMapCoordinates
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
Definition: qgsmaptopixel.h:173
QgsPalLayerSettings::DirSymbDraw
@ DirSymbDraw
Definition: qgspallabeling.h:170
QgsPalLayerSettings::DirSymbReverse
@ DirSymbReverse
Definition: qgspallabeling.h:174
pal::LabelPosition::nextPart
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
Definition: labelposition.h:277
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:900
QgsPropertyCollection::clear
void clear() override
Removes all properties from the collection.
Definition: qgspropertycollection.cpp:178
QgsPalLayerSettings::legendString
QString legendString() const
legendString
Definition: qgspallabeling.h:751
QgsTextShadowSettings::blurRadius
double blurRadius() const
Returns the blur radius for the shadow.
Definition: qgstextshadowsettings.cpp:143
QgsPalLayerSettings::maximumScale
double maximumScale
The maximum map scale (i.e.
Definition: qgspallabeling.h:617
QgsPalLayerSettings::MultiLineWrapChar
@ MultiLineWrapChar
Definition: qgspallabeling.h:165
QgsPalLayerSettings::LabelDistance
@ LabelDistance
Definition: qgspallabeling.h:238
QgsSymbolLayerUtils::decodeColor
static QColor decodeColor(const QString &str)
Definition: qgssymbollayerutils.cpp:69
Qgis::LabelOverlapHandling::AllowOverlapIfRequired
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
QgsTextShadowSettings::setOffsetDistance
void setOffsetDistance(double distance)
Sets the distance for offsetting the position of the shadow from the text.
Definition: qgstextshadowsettings.cpp:108
QgsTextBackgroundSettings::setOpacity
void setOpacity(double opacity)
Sets the background shape's opacity.
Definition: qgstextbackgroundsettings.cpp:282
QgsGeometry::buffer
QgsGeometry buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
Definition: qgsgeometry.cpp:2050
QgsLabelLineSettings::setMergeLines
void setMergeLines(bool merge)
Sets whether connected line features with identical label text should be merged prior to generating l...
Definition: qgslabellinesettings.h:122
QgsTextBackgroundSettings::setStrokeWidthUnit
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's stroke width.
Definition: qgstextbackgroundsettings.cpp:346
QgsTextBackgroundSettings::sizeType
SizeType sizeType() const
Returns the method used to determine the size of the background shape (e.g., fixed size or buffer aro...
Definition: qgstextbackgroundsettings.cpp:157
QgsLabelLineSettings::reverseDirectionSymbol
bool reverseDirectionSymbol() const
Returns true if direction symbols should be reversed.
Definition: qgslabellinesettings.h:197
Q_GLOBAL_STATIC
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
Qgis::LabelPredefinedPointPosition::MiddleLeft
@ MiddleLeft
Label on left of point.
QgsLabelLineSettings::setAnchorTextPoint
void setAnchorTextPoint(AnchorTextPoint point)
Sets the line anchor text point, which dictates which part of the label text should be placed at the ...
Definition: qgslabellinesettings.h:366
Qgis::LabelPredefinedPointPosition::TopRight
@ TopRight
Label on top-right of point.
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsPalLayerSettings::dist
double dist
Distance from feature to the label.
Definition: qgspallabeling.h:483
Qgis::UnplacedLabelVisibility::FollowEngineSetting
@ FollowEngineSetting
Respect the label engine setting.
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsPalLayerSettings::registerFeatureWithDetails
std::unique_ptr< QgsLabelFeature > registerFeatureWithDetails(const QgsFeature &feature, QgsRenderContext &context, QgsGeometry obstacleGeometry=QgsGeometry(), const QgsSymbol *symbol=nullptr)
Registers a feature for labeling.
Definition: qgspallabeling.cpp:1741
QgsTextShadowSettings::setOffsetAngle
void setOffsetAngle(int angle)
Sets the angle for offsetting the position of the shadow from the text.
Definition: qgstextshadowsettings.cpp:98
pal::LabelPosition::getFeaturePart
FeaturePart * getFeaturePart() const
Returns the feature corresponding to this labelposition.
Definition: labelposition.cpp:361
QgsPalLayerSettings::Show
@ Show
Definition: qgspallabeling.h:281
QgsTextShadowSettings::enabled
bool enabled() const
Returns whether the shadow is enabled.
Definition: qgstextshadowsettings.cpp:73
QgsLabelLineSettings::setAnchorClipping
void setAnchorClipping(AnchorClipping clipping)
Sets the line anchor clipping mode, which dictates how line strings are clipped before calculating th...
Definition: qgslabellinesettings.h:346
QgsLabelObstacleSettings::setType
void setType(ObstacleType type)
Controls how features act as obstacles for labels.
Definition: qgslabelobstaclesettings.h:119
QgsTextMaskSettings::size
double size() const
Returns the size of the buffer.
Definition: qgstextmasksettings.cpp:85
QgsGeometry::mergeLines
QgsGeometry mergeLines() const
Merges any connected lines in a LineString/MultiLineString geometry and converts them to single line ...
Definition: qgsgeometry.cpp:2657
QgsProperty::setActive
void setActive(bool active)
Sets whether the property is currently active.
Definition: qgsproperty.cpp:328
QgsLabelCandidate
Represents a label candidate.
Definition: qgspallabeling.h:1111
QgsPalLayerSettings::ShapeKind
@ ShapeKind
Definition: qgspallabeling.h:198
pal
Definition: qgsdiagramrenderer.h:50
QgsGeometry::intersection
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
Definition: qgsgeometry.cpp:2616
QgsLabelLineSettings::leftDirectionSymbol
QString leftDirectionSymbol() const
Returns the string to use for left direction arrows.
Definition: qgslabellinesettings.h:163
QgsPropertyCollection::property
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
Definition: qgspropertycollection.cpp:214
QgsPropertyDefinition::String
@ String
Any string value.
Definition: qgsproperty.h:61
QgsLabelLineSettings::overrunDistanceMapUnitScale
QgsMapUnitScale overrunDistanceMapUnitScale() const
Returns the map unit scale for label overrun distance.
Definition: qgslabellinesettings.h:264
QgsTextRenderer::textHeight
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
Definition: qgstextrenderer.cpp:620
QgsTextFormat::VerticalOrientation
@ VerticalOrientation
Horizontally oriented text.
Definition: qgstextformat.h:48
QgsGeometry::isMultipart
bool isMultipart() const SIP_HOLDGIL
Returns true if WKB of the geometry is of WKBMulti* type.
Definition: qgsgeometry.cpp:389
Qgis::LabelOffsetType
LabelOffsetType
Behavior modifier for label offset and distance, only applies in some label placement modes.
Definition: qgis.h:607
QgsTextFormat::color
QColor color() const
Returns the color that text will be rendered in.
Definition: qgstextformat.cpp:297
Qgis::LabelQuadrantPosition
LabelQuadrantPosition
Label quadrant positions.
Definition: qgis.h:621
QgsStyle::defaultStyle
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
QgsTextRenderer::textWidth
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
Definition: qgstextrenderer.cpp:545
QgsTextRenderer::Rect
@ Rect
Text within rectangle draw mode.
Definition: qgstextrenderer.h:43
QgsCalloutRegistry
Registry of available callout classes.
Definition: qgscalloutsregistry.h:155
qgsapplication.h
QgsUnitTypes::decodeRenderUnit
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Definition: qgsunittypes.cpp:2948
problem.h
QgsPalLayerSettings::ObstacleFactor
@ ObstacleFactor
Definition: qgspallabeling.h:273
geos::unique_ptr
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Definition: qgsgeos.h:79
QgsPropertyDefinition::Rotation
@ Rotation
Rotation (value between 0-360 degrees)
Definition: qgsproperty.h:60
QgsPalLayerSettings::FontWordSpacing
@ FontWordSpacing
Word spacing.
Definition: qgspallabeling.h:160
QgsTextBackgroundSettings::setRadiiUnit
void setRadiiUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's radii.
Definition: qgstextbackgroundsettings.cpp:262
QgsPalLayerSettings::repeatDistance
double repeatDistance
Distance for repeating labels for a single feature.
Definition: qgspallabeling.h:507
qgsvectortilelayer.h
QgsPalLayerSettings::formatNumbers
bool formatNumbers
Set to true to format numeric label text as numbers (e.g.
Definition: qgspallabeling.h:415
QgsPalLayerSettings::PolygonLabelOutside
@ PolygonLabelOutside
Whether labels outside a polygon feature are permitted, or should be forced (since QGIS 3....
Definition: qgspallabeling.h:257
QgsSymbolLayerUtils::toPoint
static QPointF toPoint(const QVariant &value, bool *ok=nullptr)
Converts a value to a point.
Definition: qgssymbollayerutils.cpp:551
QgsPalLayerSettings::labelSettingsPreviewPixmap
static QPixmap labelSettingsPreviewPixmap(const QgsPalLayerSettings &settings, QSize size, const QString &previewText=QString(), int padding=0)
Returns a pixmap preview for label settings.
Definition: qgspallabeling.cpp:1338
QgsLabelLineSettings::setOverrunDistanceMapUnitScale
void setOverrunDistanceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for label overrun distance.
Definition: qgslabellinesettings.h:272
Qgis::LabelPredefinedPointPosition::BottomLeft
@ BottomLeft
Label on bottom-left of point.
QgsTextFormat::setBackground
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
Definition: qgstextformat.cpp:130
QgsPalLayerSettings::repeatDistanceUnit
QgsUnitTypes::RenderUnit repeatDistanceUnit
Units for repeating labels for a single feature.
Definition: qgspallabeling.h:514
QgsPalLayerSettings::xOffset
double xOffset
Horizontal offset of label.
Definition: qgspallabeling.h:534
qgsvectorlayerdiagramprovider.h
QgsPalLayerSettings::MaxScale
@ MaxScale
Max scale (deprecated, for old project compatibility only)
Definition: qgspallabeling.h:267
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsTextBackgroundSettings::sizeMapUnitScale
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the shape size.
Definition: qgstextbackgroundsettings.cpp:187
QgsLabelLineSettings::lineAnchorPercent
double lineAnchorPercent() const
Returns the percent along the line at which labels should be placed.
Definition: qgslabellinesettings.h:287
QgsUnitTypes::fromUnitToUnitFactor
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
Definition: qgsunittypes.cpp:352
QgsFeature::id
QgsFeatureId id
Definition: qgsfeature.h:68
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:178
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsCoordinateTransform::sourceCrs
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source coordinate reference system, which the transform will transform coordinates from.
Definition: qgscoordinatetransform.cpp:262
Qgis::LabelMultiLineAlignment
LabelMultiLineAlignment
Text alignment for multi-line labels.
Definition: qgis.h:657
QgsTextFormat
Container for all settings relating to text rendering.
Definition: qgstextformat.h:40
QgsTextBackgroundSettings::RotationType
RotationType
Methods for determining the rotation of the background shape.
Definition: qgstextbackgroundsettings.h:76
QgsTextFormat::setColor
void setColor(const QColor &color)
Sets the color that text will be rendered in.
Definition: qgstextformat.cpp:302
QgsLabelThinningSettings::updateDataDefinedProperties
void updateDataDefinedProperties(const QgsPropertyCollection &properties, QgsExpressionContext &context)
Updates the thinning settings to respect any data defined properties set within the specified propert...
Definition: qgslabelthinningsettings.cpp:22
QgsLabelObstacleSettings::setFactor
void setFactor(double factor)
Sets the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
Definition: qgslabelobstaclesettings.h:97
QgsPalLayerSettings::MultiLineAlignment
@ MultiLineAlignment
Definition: qgspallabeling.h:168
QgsPropertiesDefinition
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Definition: qgspropertycollection.h:29
QgsPalLayerSettings::rotationUnit
QgsUnitTypes::AngleUnit rotationUnit() const
Unit for rotation of labels.
Definition: qgspallabeling.cpp:617
feature.h
QgsTextBackgroundSettings::size
QSizeF size() const
Returns the size of the background shape.
Definition: qgstextbackgroundsettings.cpp:167
QgsTextFormat::sizeMapUnitScale
QgsMapUnitScale sizeMapUnitScale() const
Returns the map unit scale object for the size.
Definition: qgstextformat.cpp:275
QgsPalLayerSettings::fontLimitPixelSize
bool fontLimitPixelSize
true if label sizes should be limited by pixel size.
Definition: qgspallabeling.h:636
QgsGeos::asGeos
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
Definition: qgsgeos.cpp:181
QgsExpression::hasEvalError
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Definition: qgsexpression.cpp:378
QgsPalLayerSettings::DirSymbRight
@ DirSymbRight
Definition: qgspallabeling.h:172
qgstextrendererutils.h
QgsTextShadowSettings::ShadowPlacement
ShadowPlacement
Placement positions for text shadow.
Definition: qgstextshadowsettings.h:44
QgsTextBackgroundSettings::setOffset
void setOffset(QPointF offset)
Sets the offset used for drawing the background shape.
Definition: qgstextbackgroundsettings.cpp:222
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsLabelLineSettings::mergeLines
bool mergeLines() const
Returns true if connected line features with identical label text should be merged prior to generatin...
Definition: qgslabellinesettings.h:114
QgsTextBackgroundSettings::joinStyle
Qt::PenJoinStyle joinStyle() const
Returns the join style used for drawing the background shape.
Definition: qgstextbackgroundsettings.cpp:369
QgsPalLayerSettings::FontLetterSpacing
@ FontLetterSpacing
Letter spacing.
Definition: qgspallabeling.h:159
QgsLabelLineSettings::overrunDistance
double overrunDistance() const
Returns the distance which labels are allowed to overrun past the start or end of line features.
Definition: qgslabellinesettings.h:232
QgsCoordinateTransform::isShortCircuited
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
Definition: qgscoordinatetransform.cpp:905
QgsPalLabeling::geometryRequiresPreparation
static bool geometryRequiresPreparation(const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry=QgsGeometry(), bool mergeLines=false)
Checks whether a geometry requires preparation before registration with PAL.
Definition: qgspallabeling.cpp:3830
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsMapLayer::customEnumProperty
T customEnumProperty(const QString &key, const T &defaultValue)
Returns the property value for a property based on an enum.
Definition: qgsmaplayer.h:736
QgsLabelLineSettings::anchorClipping
AnchorClipping anchorClipping() const
Returns the line anchor clipping mode, which dictates how line strings are clipped before calculating...
Definition: qgslabellinesettings.h:334
QgsMapSettings::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
Definition: qgsmapsettings.cpp:463
Qgis::LabelPlacement::Horizontal
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
QgsMapSettings::rotation
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
Definition: qgsmapsettings.cpp:102
QgsPalLayerSettings::Bold
@ Bold
Use bold style.
Definition: qgspallabeling.h:148
QgsTextRendererUtils::decodeShadowPlacementType
static QgsTextShadowSettings::ShadowPlacement decodeShadowPlacementType(const QString &string)
Decodes a string representation of a shadow placement type to a type.
Definition: qgstextrendererutils.cpp:78
QgsFeature::setGeometry
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Definition: qgsfeature.cpp:170
QgsPalLayerSettings::QgsPalLayerSettings
QgsPalLayerSettings()
Definition: qgspallabeling.cpp:278
QgsPalLayerSettings::unplacedVisibility
Qgis::UnplacedLabelVisibility unplacedVisibility() const
Returns the layer's unplaced label visibility.
Definition: qgspallabeling.cpp:1470
QgsPalLayerSettings::stopRender
void stopRender(QgsRenderContext &context)
Finalises the label settings after use.
Definition: qgspallabeling.cpp:568
QgsExpression::parserErrorString
QString parserErrorString() const
Returns parser error.
Definition: qgsexpression.cpp:211
QgsUnitTypes::AngleUnit
AngleUnit
Units of angles.
Definition: qgsunittypes.h:131
QgsMapToPixelSimplifier::SimplifyAlgorithm
SimplifyAlgorithm
Types of simplification algorithms that can be used.
Definition: qgsmaptopixelgeometrysimplifier.h:42
QgsTextRendererUtils::decodeShapeType
static QgsTextBackgroundSettings::ShapeType decodeShapeType(const QString &string)
Decodes a string representation of a background shape type to a type.
Definition: qgstextrendererutils.cpp:20
QgsPalLayerSettings::plusSign
bool plusSign
Whether '+' signs should be prepended to positive numeric labels.
Definition: qgspallabeling.h:429
QgsPalLayerSettings::ShadowUnder
@ ShadowUnder
Definition: qgspallabeling.h:221
QgsPropertyCollection::hasActiveProperties
bool hasActiveProperties() const override
Returns true if the collection has any active properties, or false if all properties within the colle...
Definition: qgspropertycollection.cpp:304
QgsMapLayerType::GroupLayer
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
QgsTextShadowSettings::setColor
void setColor(const QColor &color)
Sets the color for the drop shadow.
Definition: qgstextshadowsettings.cpp:208
QgsTextDocument::toPlainText
QStringList toPlainText() const
Returns a list of plain text lines of text representing the document.
Definition: qgstextdocument.cpp:115
QgsPalLayerSettings::DirSymbPlacement
@ DirSymbPlacement
Definition: qgspallabeling.h:173
QgsPalLayerSettings::wrapChar
QString wrapChar
Wrapping character string.
Definition: qgspallabeling.h:383
Qgis::LabelPredefinedPointPosition::TopSlightlyRight
@ TopSlightlyRight
Label on top of point, slightly right of center.
QgsTextMaskSettings
Container for settings relating to a selective masking around a text. A selective masking only makes ...
Definition: qgstextmasksettings.h:41
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsTextMaskSettings::setJoinStyle
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
Definition: qgstextmasksettings.cpp:120
QgsPropertyDefinition::ColorWithAlpha
@ ColorWithAlpha
Color with alpha channel.
Definition: qgsproperty.h:64
QgsPalLayerSettings::BufferColor
@ BufferColor
Definition: qgspallabeling.h:183
qgscalloutsregistry.h
QgsRenderContext::setFlag
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:216
QgsPalLayerSettings::autoWrapLength
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
Definition: qgspallabeling.h:392
QgsMapToPixel::mapRotation
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
Definition: qgsmaptopixel.h:269
QgsPalLayerSettings::Priority
@ Priority
Definition: qgspallabeling.h:252
QgsPalLayerSettings::LabelAllParts
@ LabelAllParts
Whether all parts of multi-part features should be labeled.
Definition: qgspallabeling.h:256
QgsStringReplacementCollection::process
QString process(const QString &input) const
Processes a given input string, applying any valid replacements which should be made using QgsStringR...
Definition: qgsstringutils.cpp:803
QgsPalLayerSettings::MaskOpacity
@ MaskOpacity
Mask opacity.
Definition: qgspallabeling.h:193
QgsPalLayerSettings::format
const QgsTextFormat & format() const
Returns the label text formatting settings, e.g., font settings, buffer settings, etc.
Definition: qgspallabeling.h:841
palexception.h
QgsPalLayerSettings::CalloutDraw
@ CalloutDraw
Show callout.
Definition: qgspallabeling.h:275
QgsTextBackgroundSettings::strokeWidth
double strokeWidth() const
Returns the width of the shape's stroke (stroke).
Definition: qgstextbackgroundsettings.cpp:325
QgsMapLayerType::RasterLayer
@ RasterLayer
Raster layer.
QgsPalLayerSettings::TextOrientation
@ TextOrientation
Definition: qgspallabeling.h:169
QgsRectangle::contains
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:363
QgsLabelLineSettings::AnchorClipping::UseVisiblePartsOfLine
@ UseVisiblePartsOfLine
Only visible parts of lines are considered when calculating the line anchor for labels.
QgsPalLayerSettings::drawLabels
bool drawLabels
Whether to draw labels for this layer.
Definition: qgspallabeling.h:345
QgsPalLayerSettings::FontBlendMode
@ FontBlendMode
Text blend mode.
Definition: qgspallabeling.h:161
QgsPalLayerSettings::setFormat
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
Definition: qgspallabeling.h:849
QgsStyle::defaultTextFormat
QgsTextFormat defaultTextFormat(QgsStyle::TextFormatContext context=QgsStyle::TextFormatContext::Labeling) const
Returns the default text format to use for new text based objects in the specified context.
Definition: qgsstyle.cpp:1212
Qgis::Capitalization::AllLowercase
@ AllLowercase
Convert all characters to lowercase.
QgsPalLayerSettings::mCurFeat
const QgsFeature * mCurFeat
Definition: qgspallabeling.h:992
Qgis::LabelPredefinedPointPosition::MiddleRight
@ MiddleRight
Label on right of point.
QgsGeometry::rotate
Qgis::GeometryOperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Definition: qgsgeometry.cpp:910
QgsPalLayerSettings::repeatDistanceMapUnitScale
QgsMapUnitScale repeatDistanceMapUnitScale
Map unit scale for repeating labels for a single feature.
Definition: qgspallabeling.h:521
QgsTextFormat::capitalization
Qgis::Capitalization capitalization() const
Returns the text capitalization style.
Definition: qgstextformat.cpp:363
QgsPalLayerSettings::startRender
void startRender(QgsRenderContext &context)
Prepares the label settings for rendering.
Definition: qgspallabeling.cpp:545
QgsPalLayerSettings::LabelRotation
@ LabelRotation
Label rotation.
Definition: qgspallabeling.h:249
QgsTextShadowSettings::color
QColor color() const
Returns the color of the drop shadow.
Definition: qgstextshadowsettings.cpp:203
QgsPalLayerSettings::RepeatDistance
@ RepeatDistance
Definition: qgspallabeling.h:250
QgsPalLayerSettings::NumPlusSign
@ NumPlusSign
Definition: qgspallabeling.h:177
qgsvectordataprovider.h
QgsPalLayerSettings::registerFeature
void registerFeature(const QgsFeature &f, QgsRenderContext &context)
Registers a feature for labeling.
Definition: qgspallabeling.cpp:1736
QgsPalLayerSettings::PolygonInterior
@ PolygonInterior
Definition: qgspallabeling.h:133
QgsTextFormat::setBlendMode
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the text.
Definition: qgstextformat.cpp:335
QgsTextShadowSettings::setBlurRadius
void setBlurRadius(double blurRadius)
Sets the blur radius for the shadow.
Definition: qgstextshadowsettings.cpp:148
QgsPalLabeling::splitToLines
static QStringList splitToLines(const QString &text, const QString &wrapCharacter, int autoWrapLength=0, bool useMaxLineLengthWhenAutoWrapping=true)
Splits a text string to a list of separate lines, using a specified wrap character (wrapCharacter).
Definition: qgspallabeling.cpp:3862
QgsTextRenderer::drawText
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws text within a rectangle using the specified settings.
Definition: qgstextrenderer.cpp:81
qgspainting.h
QgsRenderContext::setMapToPixel
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
Definition: qgsrendercontext.h:412
QgsLabelLineSettings::rightDirectionSymbol
QString rightDirectionSymbol() const
Returns the string to use for right direction arrows.
Definition: qgslabellinesettings.h:181
QgsPalLayerSettings::ZIndex
@ ZIndex
Definition: qgspallabeling.h:274
QgsMapToPixelSimplifier::SimplifyEnvelope
@ SimplifyEnvelope
The geometries can be fully simplified by its BoundingBox.
Definition: qgsmaptopixelgeometrysimplifier.h:58
Qgis::Capitalization::MixedCase
@ MixedCase
Mixed case, ie no change.
QgsLabelLineSettings::AnchorTextPoint::CenterOfText
@ CenterOfText
Anchor using center of text.
QgsPalLayerSettings::ShapeSizeY
@ ShapeSizeY
Definition: qgspallabeling.h:202
QgsMargins
The QgsMargins class defines the four margins of a rectangle.
Definition: qgsmargins.h:37
QgsMessageLog::logMessage
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Definition: qgsmessagelog.cpp:27
QgsTextFormat::lineHeight
double lineHeight() const
Returns the line height for text.
Definition: qgstextformat.cpp:341
Qgis::LabelPlacement::OverPoint
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
QgsPropertyDefinition
Definition for a property.
Definition: qgsproperty.h:46
QgsPalLayerSettings::ScaleVisibility
@ ScaleVisibility
Definition: qgspallabeling.h:264
QgsPalLayerSettings::MaskBufferUnit
@ MaskBufferUnit
Mask buffer size unit.
Definition: qgspallabeling.h:192
QgsPalLayerSettings::setUnplacedVisibility
void setUnplacedVisibility(Qgis::UnplacedLabelVisibility visibility)
Sets the layer's unplaced label visibility.
Definition: qgspallabeling.cpp:1475
QgsGeometry::length
double length() const
Returns the planar, 2-dimensional length of geometry.
Definition: qgsgeometry.cpp:1890
QgsTextBackgroundSettings::rotation
double rotation() const
Returns the rotation for the background shape, in degrees clockwise.
Definition: qgstextbackgroundsettings.cpp:207
QgsPalLayerSettings::fitInPolygonOnly
bool fitInPolygonOnly
true if only labels which completely fit within a polygon are allowed.
Definition: qgspallabeling.h:476
Qgis::Capitalization
Capitalization
String capitalization options.
Definition: qgis.h:1592
QgsPalLayerSettings::lineSettings
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
Definition: qgspallabeling.h:879
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:327
QgsTextMaskSettings::opacity
double opacity() const
Returns the mask's opacity.
Definition: qgstextmasksettings.cpp:125
QgsTextFormat::opacity
double opacity() const
Returns the text's opacity.
Definition: qgstextformat.cpp:308
Qgis::UI_SCALE_FACTOR
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:2043
QgsPalLayerSettings::OverrunDistance
@ OverrunDistance
Distance which labels can extend past either end of linear features.
Definition: qgspallabeling.h:255
QgsGeometry::isEmpty
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Definition: qgsgeometry.cpp:379
QgsTextShadowSettings::setShadowPlacement
void setShadowPlacement(QgsTextShadowSettings::ShadowPlacement placement)
Sets the placement for the drop shadow.
Definition: qgstextshadowsettings.cpp:88
QgsPalLayerSettings::DirSymbLeft
@ DirSymbLeft
Definition: qgspallabeling.h:171
QgsPalLayerSettings::ShapeDraw
@ ShapeDraw
Definition: qgspallabeling.h:197
QgsPalLayerSettings::AutoWrapLength
@ AutoWrapLength
Definition: qgspallabeling.h:166
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:127
Qgis::Capitalization::SmallCaps
@ SmallCaps
Mixed case small caps (since QGIS 3.24)
QgsGeometry::clipped
QgsGeometry clipped(const QgsRectangle &rectangle)
Clips the geometry using the specified rectangle.
Definition: qgsgeometry.cpp:3161
QgsLabelLineSettings::anchorType
AnchorType anchorType() const
Returns the line anchor type, which dictates how the lineAnchorPercent() setting is handled.
Definition: qgslabellinesettings.h:312
QgsPalLayerSettings::OverlapHandling
@ OverlapHandling
Overlap handling technique (since QGIS 3.26)
Definition: qgspallabeling.h:278
QgsPalLayerSettings::propertyDefinitions
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the labeling property definitions.
Definition: qgspallabeling.cpp:602
QgsTextFormat::readXml
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
Definition: qgstextformat.cpp:488
QgsTextDocument::fromHtml
static QgsTextDocument fromHtml(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of HTML formatted lines.
Definition: qgstextdocument.cpp:47
QgsLabelObstacleSettings::type
ObstacleType type() const
Returns how features act as obstacles for labels.
Definition: qgslabelobstaclesettings.h:108
QgsTextShadowSettings::setScale
void setScale(int scale)
Sets the scaling used for the drop shadow (in percentage of original size).
Definition: qgstextshadowsettings.cpp:198
QgsVectorSimplifyMethod::tolerance
double tolerance() const
Gets the tolerance of simplification in map units. Represents the maximum distance in map units betwe...
Definition: qgsvectorsimplifymethod.h:84
QgsPalLayerSettings::FontCase
@ FontCase
Label text case.
Definition: qgspallabeling.h:158
QgsPalLayerSettings::ShapeOffset
@ ShapeOffset
Definition: qgspallabeling.h:206
QgsLabelThinningSettings
Contains settings related to how the label engine removes candidate label positions and reduces the n...
Definition: qgslabelthinningsettings.h:34
QgsTextFormat::setOrientation
void setOrientation(TextOrientation orientation)
Sets the orientation for the text.
Definition: qgstextformat.cpp:357
QgsTextBackgroundSettings::setSizeUnit
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the shape's size.
Definition: qgstextbackgroundsettings.cpp:182
QgsLabelThinningSettings::maximumNumberLabels
int maximumNumberLabels() const
Returns the maximum number of labels which should be drawn for this layer.
Definition: qgslabelthinningsettings.h:58
QgsPalLayerSettings::setCallout
void setCallout(QgsCallout *callout)
Sets the label callout renderer, responsible for drawing label callouts.
Definition: qgspallabeling.cpp:1333
QgsTextBufferSettings
Container for settings relating to a text buffer.
Definition: qgstextbuffersettings.h:42
QgsPalLayerSettings::MaskJoinStyle
@ MaskJoinStyle
Mask join style.
Definition: qgspallabeling.h:194
QgsPalLayerSettings::ptOne
QgsPointXY ptOne
Definition: qgspallabeling.h:999
QgsPalLayerSettings::BufferDraw
@ BufferDraw
Definition: qgspallabeling.h:180
QgsTextFormat::scaledFont
QFont scaledFont(const QgsRenderContext &context, double scaleFactor=1.0, bool *isZeroSize=nullptr) const
Returns a font with the size scaled to match the format's size settings (including units and map unit...
Definition: qgstextformat.cpp:165
QgsPalLayerSettings::ShadowColor
@ ShadowColor
Definition: qgspallabeling.h:230
QgsTextBufferSettings::sizeUnit
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units for the buffer size.
Definition: qgstextbuffersettings.cpp:92
QgsMapLayer::removeCustomProperty
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
Definition: qgsmaplayer.cpp:2004
QgsPropertyCollection::referencedFields
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the collection.
Definition: qgspropertycollection.cpp:254
QgsFontUtils::fontFamilyOnSystem
static bool fontFamilyOnSystem(const QString &family)
Check whether font family is on system in a quick manner, which does not compare [foundry].
Definition: qgsfontutils.cpp:38
QgsPalLayerSettings::LineAnchorPercent
@ LineAnchorPercent
Portion along line at which labels should be anchored (since QGIS 3.16)
Definition: qgspallabeling.h:258
qgsdiagramrenderer.h
QgsExpression::prepare
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
Definition: qgsexpression.cpp:327
QgsPalLayerSettings::LineAnchorClipping
@ LineAnchorClipping
Clipping mode for line anchor calculation (since QGIS 3.20)
Definition: qgspallabeling.h:259
QgsPalLayerSettings::ShapeRadiiUnits
@ ShapeRadiiUnits
Definition: qgspallabeling.h:209
qgscurvepolygon.h
QgsLabelThinningSettings::limitNumberOfLabelsEnabled
bool limitNumberOfLabelsEnabled() const
Returns true if the number of labels drawn for the layer should be limited.
Definition: qgslabelthinningsettings.h:43
QgsPalLayerSettings::ShapeSizeUnits
@ ShapeSizeUnits
Definition: qgspallabeling.h:203
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:136
Qgis::Capitalization::AllSmallCaps
@ AllSmallCaps
Force all characters to small caps (since QGIS 3.24)
Qgis::LabelOverlapHandling::AllowOverlapAtNoCost
@ AllowOverlapAtNoCost
Labels may freely overlap other labels, at no cost.
QgsPalLayerSettings::NumDecimals
@ NumDecimals
Definition: qgspallabeling.h:176
QgsVectorSimplifyMethod::forceLocalOptimization
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
Definition: qgsvectorsimplifymethod.h:94
Qgis::LabelOffsetType::FromPoint
@ FromPoint
Offset distance applies from point geometry.
QgsTextBackgroundSettings::type
ShapeType type() const
Returns the type of background shape (e.g., square, ellipse, SVG).
Definition: qgstextbackgroundsettings.cpp:117
QgsTextShadowSettings::setOffsetUnit
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shadow's offset.
Definition: qgstextshadowsettings.cpp:118
QgsTextBackgroundSettings::svgFile
QString svgFile() const
Returns the absolute path to the background SVG file, if set.
Definition: qgstextbackgroundsettings.cpp:127
QgsPalLayerSettings::LineAnchorTextPoint
@ LineAnchorTextPoint
Line anchor text point (since QGIS 3.26)
Definition: qgspallabeling.h:261
QgsCoordinateReferenceSystem
This class represents a coordinate reference system (CRS).
Definition: qgscoordinatereferencesystem.h:211
QgsSymbolLayerUtils::encodePoint
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
Definition: qgssymbollayerutils.cpp:538
QgsMapToPixel::transform
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
QgsExpression::evaluate
QVariant evaluate()
Evaluate the feature and return the result.
Definition: qgsexpression.cpp:350
QgsSymbolLayerUtils::encodeSize
static QString encodeSize(QSizeF size)
Encodes a QSizeF to a string.
Definition: qgssymbollayerutils.cpp:602
QgsTextBackgroundSettings::setFillColor
void setFillColor(const QColor &color)
Sets the color used for filing the background shape.
Definition: qgstextbackgroundsettings.cpp:302
QgsGeometry::simplify
QgsGeometry simplify(double tolerance) const
Returns a simplified version of this geometry using a specified tolerance value.
Definition: qgsgeometry.cpp:2244
QgsLabelLineSettings::AnchorType
AnchorType
Line anchor types.
Definition: qgslabellinesettings.h:59
QgsRenderContext::vectorSimplifyMethod
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
Definition: qgsrendercontext.h:594
QgsPalLayerSettings::ShadowTransparency
@ ShadowTransparency
Shadow transparency (deprecated)
Definition: qgspallabeling.h:227
QgsAbstractPropertyCollection::valueAsString
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
Definition: qgspropertycollection.cpp:42
Qgis::Capitalization::ForceFirstLetterToCapital
@ ForceFirstLetterToCapital
Convert just the first letter of each word to uppercase, leave the rest untouched.
QgsPropertyDefinition::Double0To1
@ Double0To1
Double value between 0-1 (inclusive)
Definition: qgsproperty.h:59
QgsCallout::render
void render(QgsRenderContext &context, const QRectF &rect, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext)
Renders the callout onto the specified render context.
Definition: qgscallout.cpp:148
qgsstyle.h
QgsTextBufferSettings::size
double size() const
Returns the size of the buffer.
Definition: qgstextbuffersettings.cpp:82
QgsTextShadowSettings::offsetAngle
int offsetAngle() const
Returns the angle for offsetting the position of the shadow from the text.
Definition: qgstextshadowsettings.cpp:93
QgsPalLayerSettings::upsidedownLabels
Qgis::UpsideDownLabelHandling upsidedownLabels
Controls whether upside down labels are displayed and how they are handled.
Definition: qgspallabeling.h:653
QgsMapToPixelSimplifier
Implementation of GeometrySimplifier using the "MapToPixel" algorithm.
Definition: qgsmaptopixelgeometrysimplifier.h:38
QgsLabelLineSettings::setLineAnchorPercent
void setLineAnchorPercent(double percent)
Sets the percent along the line at which labels should be placed.
Definition: qgslabellinesettings.h:302
QgsLabelObstacleSettings::isObstacle
bool isObstacle() const
Returns true if the features are obstacles to labels of other layers.
Definition: qgslabelobstaclesettings.h:60
QgsPalLayerSettings::ShapeStrokeWidth
@ ShapeStrokeWidth
Definition: qgspallabeling.h:215
QgsPalLayerSettings::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgspallabeling.cpp:1219
qgsvectorlayer.h
QgsTextFormat::mask
QgsTextMaskSettings & mask()
Returns a reference to the masking settings.
Definition: qgstextformat.cpp:148
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsRenderContext::convertToPainterUnits
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
Definition: qgsrendercontext.cpp:367
QgsPropertyDefinition::IntegerPositive
@ IntegerPositive
Positive integer values (including 0)
Definition: qgsproperty.h:55
QgsTextFormat::size
double size() const
Returns the size for rendered text.
Definition: qgstextformat.cpp:286
QgsPalLayerSettings::CentroidWhole
@ CentroidWhole
Definition: qgspallabeling.h:234
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Definition: qgsmapsettings.cpp:358
QgsPalLayerSettings::ShadowScale
@ ShadowScale
Definition: qgspallabeling.h:229
QgsGeometry::asPoint
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Definition: qgsgeometry.cpp:1662
QgsPalLayerSettings::PositionX
@ PositionX
X-coordinate data defined label position.
Definition: qgspallabeling.h:243
QgsPalLayerSettings::prepare
bool prepare(QgsRenderContext &context, QSet< QString > &attributeNames, const QgsFields &fields, const QgsMapSettings &mapSettings, const QgsCoordinateReferenceSystem &crs)
Prepare for registration of features.
Definition: qgspallabeling.cpp:384
QgsTextBackgroundSettings::setRadii
void setRadii(QSizeF radii)
Sets the radii used for rounding the corners of shapes.
Definition: qgstextbackgroundsettings.cpp:252
QgsTextShadowSettings::setBlurRadiusUnit
void setBlurRadiusUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shadow's blur radius.
Definition: qgstextshadowsettings.cpp:158
QgsPalLayerSettings::Size
@ Size
Label size.
Definition: qgspallabeling.h:147
QgsReferencedGeometryBase::crs
QgsCoordinateReferenceSystem crs() const
Returns the associated coordinate reference system, or an invalid CRS if no reference system is set.
Definition: qgsreferencedgeometry.h:53
QgsTextRenderer::sizeToPixel
static int sizeToPixel(double size, const QgsRenderContext &c, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale())
Calculates pixel size (considering output size should be in pixel or map units, scale factors and opt...
Definition: qgstextrenderer.cpp:76
QgsPalLayerSettings::ShadowOffsetAngle
@ ShadowOffsetAngle
Definition: qgspallabeling.h:222
qgsreferencedgeometry.h
QgsPalLayerSettings::ShapeTransparency
@ ShapeTransparency
Shape transparency (deprecated)
Definition: qgspallabeling.h:210
QgsTextFormat::readFromLayer
void readFromLayer(QgsVectorLayer *layer)
Reads settings from a layer's custom properties (for QGIS 2.x projects).
Definition: qgstextformat.cpp:404
QgsGeometry::get
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:141
QgsPalLayerSettings::calculateLabelSize
void calculateLabelSize(const QFontMetricsF *fm, const QString &text, double &labelX, double &labelY, const QgsFeature *f=nullptr, QgsRenderContext *context=nullptr, double *rotatedLabelX=nullptr, double *rotatedLabelY=nullptr, QgsTextDocument *document=nullptr)
Calculates the space required to render the provided text in map units.
Definition: qgspallabeling.cpp:1485
QgsTextShadowSettings
Container for settings relating to a text shadow.
Definition: qgstextshadowsettings.h:37
Qgis::RenderContextFlag::Antialiasing
@ Antialiasing
Use antialiasing while drawing.
QgsPalLayerSettings::priority
int priority
Label priority.
Definition: qgspallabeling.h:596
QgsTextBufferSettings::enabled
bool enabled() const
Returns whether the buffer is enabled.
Definition: qgstextbuffersettings.cpp:72
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
Qgis::LabelOverlapHandling::PreventOverlap
@ PreventOverlap
Do not allow labels to overlap other labels.
QgsGeometry::asWkt
QString asWkt(int precision=17) const
Exports the geometry to WKT.
Definition: qgsgeometry.cpp:1407
QgsLabelLineSettings
Contains settings related to how the label engine places and formats labels for line features (or pol...
Definition: qgslabellinesettings.h:39
QgsLabelLineSettings::DirectionSymbolPlacement::SymbolLeftRight
@ SymbolLeftRight
Place direction symbols on left/right of label.
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
qgscallout.h
QgsTextFormat::setBuffer
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
Definition: qgstextformat.cpp:118
QgsPalLayerSettings::fieldName
QString fieldName
Name of field (or an expression) to use for label text.
Definition: qgspallabeling.h:354
QgsLabelLineSettings::overrunDistanceUnit
QgsUnitTypes::RenderUnit overrunDistanceUnit() const
Returns the units for label overrun distance.
Definition: qgslabellinesettings.h:248
QgsLabelLineSettings::setAddDirectionSymbol
void setAddDirectionSymbol(bool enabled)
Sets whether '<' or '>' (or custom strings set via leftDirectionSymbol and rightDirectionSymbol) will...
Definition: qgslabellinesettings.h:154
QgsRenderContext::mapExtent
QgsRectangle mapExtent() const
Returns the original extent of the map being rendered.
Definition: qgsrendercontext.h:251
QgsPalLayerSettings::ShadowOffsetDist
@ ShadowOffsetDist
Definition: qgspallabeling.h:223
QgsTextBackgroundSettings::setType
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
Definition: qgstextbackgroundsettings.cpp:122
QgsPalLayerSettings::ShapeSizeX
@ ShapeSizeX
Definition: qgspallabeling.h:201
QgsMapLayer::customProperty
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
Definition: qgsmaplayer.cpp:1999
QgsGeometry::makeValid
QgsGeometry makeValid() const
Attempts to make an invalid geometry valid without losing vertices.
Definition: qgsgeometry.cpp:2860
qgsgeometry.h
QgsPalLayerSettings::Italic
@ Italic
Use italic style.
Definition: qgspallabeling.h:149
QgsWkbTypes::GeometryType
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:140
pal::LabelPosition::getHeight
double getHeight() const
Definition: labelposition.h:261
QgsTextFormat::RotationBasedOrientation
@ RotationBasedOrientation
Horizontally or vertically oriented text based on rotation (only available for map labeling)
Definition: qgstextformat.h:49
QgsTextFormat::setShadow
void setShadow(const QgsTextShadowSettings &shadowSettings)
Sets the text's drop shadow settings.
Definition: qgstextformat.cpp:142
QgsVectorTileLayer::labeling
QgsVectorTileLabeling * labeling() const
Returns currently assigned labeling.
Definition: qgsvectortilelayer.cpp:902
QgsTextBackgroundSettings::ShapeSVG
@ ShapeSVG
SVG file.
Definition: qgstextbackgroundsettings.h:59
QgsPalLayerSettings::ShapeRotation
@ ShapeRotation
Definition: qgspallabeling.h:205
pal::LabelPosition::conflictsWithObstacle
bool conflictsWithObstacle() const
Returns whether the position is marked as conflicting with an obstacle feature.
Definition: labelposition.h:227
QgsPropertyDefinition::Boolean
@ Boolean
Boolean value.
Definition: qgsproperty.h:53
QgsPalLayerSettings::BufferTransp
@ BufferTransp
Buffer transparency (deprecated)
Definition: qgspallabeling.h:184
QgsPalLayerSettings::ShapeRotationType
@ ShapeRotationType
Definition: qgspallabeling.h:204
QgsPalLayerSettings::AllowDegradedPlacement
@ AllowDegradedPlacement
Allow degraded label placements (since QGIS 3.26)
Definition: qgspallabeling.h:277
QgsPropertyCollection::value
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
Definition: qgspropertycollection.cpp:228
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsAbstractPropertyCollection::valueAsBool
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
Definition: qgspropertycollection.cpp:88
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsPalLayerSettings::ShapeStrokeWidthUnits
@ ShapeStrokeWidthUnits
Definition: qgspallabeling.h:216
QgsPalLayerSettings::AlwaysShow
@ AlwaysShow
Definition: qgspallabeling.h:282
QgsPalLayerSettings::ShapeStrokeColor
@ ShapeStrokeColor
Definition: qgspallabeling.h:214
QgsTextFormat::setLineHeight
void setLineHeight(double height)
Sets the line height for text.
Definition: qgstextformat.cpp:346
QgsPalLayerSettings::geometryGenerator
QString geometryGenerator
The geometry generator expression. Null if disabled.
Definition: qgspallabeling.h:727
QgsLabelLineSettings::DirectionSymbolPlacement::SymbolAbove
@ SymbolAbove
Place direction symbols on above label.
QgsTextBackgroundSettings::SizeFixed
@ SizeFixed
Fixed size.
Definition: qgstextbackgroundsettings.h:69
str
#define str(x)
Definition: qgis.cpp:37
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsPalLayerSettings::FontStretchFactor
@ FontStretchFactor
Font stretch factor, since QGIS 3.24.
Definition: qgspallabeling.h:162
QgsPropertyDefinition::Size2D
@ Size2D
2D size (width/height different)
Definition: qgsproperty.h:70
QgsPalLayerSettings::fieldIndex
int fieldIndex
Definition: qgspallabeling.h:994
QgsPalLayerSettings::Family
@ Family
Font family.
Definition: qgspallabeling.h:153
QgsTextMaskSettings::setEnabled
void setEnabled(bool)
Returns whether the mask is enabled.
Definition: qgstextmasksettings.cpp:69
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsLabelLineSettings::setAnchorType
void setAnchorType(AnchorType type)
Sets the line anchor type, which dictates how the lineAnchorPercent() setting is handled.
Definition: qgslabellinesettings.h:322
QgsSymbolLayerUtils::svgSymbolNameToPath
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
Definition: qgssymbollayerutils.cpp:4237
QgsTextFormat::setOpacity
void setOpacity(double opacity)
Sets the text's opacity.
Definition: qgstextformat.cpp:313
QgsTextBufferSettings::setBlendMode
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the buffer.
Definition: qgstextbuffersettings.cpp:157
QgsTextFormat::setMask
void setMask(const QgsTextMaskSettings &maskSettings)
Sets the text's masking settings.
Definition: qgstextformat.cpp:154
Qgis::GeometryOperationResult::Success
@ Success
Operation succeeded.
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsMapToPixelSimplifier::simplify
QgsGeometry simplify(const QgsGeometry &geometry) const override
Returns a simplified version the specified geometry.
Definition: qgsmaptopixelgeometrysimplifier.cpp:382
QgsTextDocument
Represents a document consisting of one or more QgsTextBlock objects.
Definition: qgstextdocument.h:38
pal::LabelPosition::getX
double getX(int i=0) const
Returns the down-left x coordinate.
Definition: labelposition.cpp:338
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:241
QgsPalLayerSettings::extentGeom
QgsGeometry extentGeom
Definition: qgspallabeling.h:1000
qgsmaptopixelgeometrysimplifier.h
qgsEnumKeyToValue
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:2459
QgsLabelLineSettings::DirectionSymbolPlacement::SymbolBelow
@ SymbolBelow
Place direction symbols on below label.
QgsPalLayerSettings::LineAnchorType
@ LineAnchorType
Line anchor type (since QGIS 3.26)
Definition: qgspallabeling.h:260
QgsPalLayerSettings::FontStyle
@ FontStyle
Font style name.
Definition: qgspallabeling.h:154
Qgis::LabelPredefinedPointPosition::BottomRight
@ BottomRight
Label on bottom right of point.
QgsTextBufferSettings::setSize
void setSize(double size)
Sets the size of the buffer.
Definition: qgstextbuffersettings.cpp:87
QgsTextBackgroundSettings::ShapeType
ShapeType
Background shape types.
Definition: qgstextbackgroundsettings.h:53
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
QgsPalLayerSettings::maxCurvedCharAngleIn
double maxCurvedCharAngleIn
Maximum angle between inside curved label characters (valid range 20.0 to 60.0).
Definition: qgspallabeling.h:584
qgsproperty.h
QgsRenderContext::pathResolver
const QgsPathResolver & pathResolver() const
Returns the path resolver for conversion between relative and absolute paths during rendering operati...
Definition: qgsrendercontext.h:213
QgsPalLayerSettings::ShadowOpacity
@ ShadowOpacity
Shadow opacity.
Definition: qgspallabeling.h:228
QgsPalLayerSettings::callout
QgsCallout * callout() const
Returns the label callout renderer, responsible for drawing label callouts.
Definition: qgspallabeling.h:859
QgsTextBackgroundSettings::setSvgFile
void setSvgFile(const QString &file)
Sets the path to the background SVG file.
Definition: qgstextbackgroundsettings.cpp:132
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:145
QgsStringUtils::wordWrap
static QString wordWrap(const QString &string, int length, bool useMaxLineLength=true, const QString &customDelimiter=QString())
Automatically wraps a string by inserting new line characters at appropriate locations in the string.
Definition: qgsstringutils.cpp:602
QgsLabelLineSettings::setLeftDirectionSymbol
void setLeftDirectionSymbol(const QString &symbol)
Sets the string to use for left direction arrows.
Definition: qgslabellinesettings.h:172
QgsPalLayerSettings::isExpression
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
Definition: qgspallabeling.h:360
QgsPalLayerSettings::ShapeRadii
@ ShapeRadii
Definition: qgspallabeling.h:208
QgsPalLayerSettings::mCurFields
QgsFields mCurFields
Definition: qgspallabeling.h:993
QgsPalLayerSettings::useMaxLineLengthForAutoWrap
bool useMaxLineLengthForAutoWrap
If true, indicates that when auto wrapping label text the autoWrapLength length indicates the maximum...
Definition: qgspallabeling.h:404
QgsTextFormat::stretchFactor
int stretchFactor() const
Returns the text's stretch factor.
Definition: qgstextformat.cpp:319
QgsTextMaskSettings::setOpacity
void setOpacity(double opacity)
Sets the mask's opacity.
Definition: qgstextmasksettings.cpp:130
QgsTextBufferSettings::setColor
void setColor(const QColor &color)
Sets the color for the buffer.
Definition: qgstextbuffersettings.cpp:117
QgsApplication::calloutRegistry
static QgsCalloutRegistry * calloutRegistry()
Returns the application's callout registry, used for managing callout types.
Definition: qgsapplication.cpp:2390
QgsPalLayerSettings::geometryGeneratorEnabled
bool geometryGeneratorEnabled
Defines if the geometry generator is enabled or not. If disabled, the standard geometry will be taken...
Definition: qgspallabeling.h:733
QgsSymbolLayerUtils::decodePenJoinStyle
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
Definition: qgssymbollayerutils.cpp:200
QgsPalLayerSettings::OffsetQuad
@ OffsetQuad
Definition: qgspallabeling.h:235
QgsTextFormat::font
QFont font() const
Returns the font used for rendering text.
Definition: qgstextformat.cpp:160
QgsPalLayerSettings::labelOffsetMapUnitScale
QgsMapUnitScale labelOffsetMapUnitScale
Map unit scale for label offset.
Definition: qgspallabeling.h:558
QgsPalLayerSettings::offsetUnits
QgsUnitTypes::RenderUnit offsetUnits
Units for offsets of label.
Definition: qgspallabeling.h:550
QgsStyle::TextFormatContext::Labeling
@ Labeling
Text format used in labeling.
QgsAbstractGeometry::boundary
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
qgsvectorlayerlabelprovider.h
QgsCallout::QgsCalloutContext
Contains additional contextual information about the context in which a callout is being rendered.
Definition: qgscallout.h:245
Qgis::LabelOffsetType::FromSymbolBounds
@ FromSymbolBounds
Offset distance applies from rendered symbol bounds.
QgsPalLayerSettings::LinePlacementOptions
@ LinePlacementOptions
Line placement flags.
Definition: qgspallabeling.h:254
QgsTextFormat::referencedFields
QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns all field names referenced by the configuration (e.g.
Definition: qgstextformat.cpp:845
updateDataDefinedString
QString updateDataDefinedString(const QString &value)
Definition: qgspallabeling.cpp:627
QgsPalLayerSettings::~QgsPalLayerSettings
~QgsPalLayerSettings()
Definition: qgspallabeling.cpp:589
QgsTextBufferSettings::setJoinStyle
void setJoinStyle(Qt::PenJoinStyle style)
Sets the join style used for drawing the buffer.
Definition: qgstextbuffersettings.cpp:147
QgsPalLayerSettings::ptZero
QgsPointXY ptZero
Definition: qgspallabeling.h:998
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:1080
QgsPalLayerSettings::FontTransp
@ FontTransp
Text transparency (deprecated)
Definition: qgspallabeling.h:156
QgsTextBackgroundSettings::sizeUnit
QgsUnitTypes::RenderUnit sizeUnit() const
Returns the units used for the shape's size.
Definition: qgstextbackgroundsettings.cpp:177
QgsPalLayerSettings::ShapeSVGFile
@ ShapeSVGFile
Definition: qgspallabeling.h:199
qgsgeometrycollection.h
QgsVectorSimplifyMethod::simplifyHints
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
Definition: qgsvectorsimplifymethod.h:64
qgsexception.h
pal.h
QgsLabelingUtils::decodePredefinedPositionOrder
static QVector< Qgis::LabelPredefinedPointPosition > decodePredefinedPositionOrder(const QString &positionString)
Decodes a string to an ordered list of predefined point label positions.
Definition: qgslabelingengine.cpp:730
QgsSymbolLayerUtils::encodePenJoinStyle
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
Definition: qgssymbollayerutils.cpp:185
QgsTextShadowSettings::opacity
double opacity() const
Returns the shadow's opacity.
Definition: qgstextshadowsettings.cpp:183
QgsPropertyDefinition::SvgPath
@ SvgPath
Path to an SVG file.
Definition: qgsproperty.h:77
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsPoint::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspoint.cpp:767
QgsPropertyCollection::setProperty
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
Definition: qgspropertycollection.cpp:187
QgsCallout::startRender
virtual void startRender(QgsRenderContext &context)
Prepares the callout for rendering on the specified render context.
Definition: qgscallout.cpp:123
QgsLabelLineSettings::placementFlags
QgsLabeling::LinePlacementFlags placementFlags() const
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
Definition: qgslabellinesettings.h:98
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsPropertyDefinition::Opacity
@ Opacity
Opacity (0-100)
Definition: qgsproperty.h:62
QgsGeometry::contains
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
Definition: qgsgeometry.cpp:1303
QgsCallout::stopRender
virtual void stopRender(QgsRenderContext &context)
Finalises the callout after a set of rendering operations on the specified render context.
Definition: qgscallout.cpp:127
qgsvectorlayerlabeling.h
QgsTextBackgroundSettings::setSize
void setSize(QSizeF size)
Sets the size of the background shape.
Definition: qgstextbackgroundsettings.cpp:172
QgsPalLayerSettings::mFeatsRegPal
int mFeatsRegPal
Definition: qgspallabeling.h:1003
Qgis::LabelPlacement::PerimeterCurved
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
QgsRenderContext::setUseAdvancedEffects
void setUseAdvancedEffects(bool enabled)
Used to enable or disable advanced effects such as blend modes.
Definition: qgsrendercontext.cpp:305
QgsLabelLineSettings::directionSymbolPlacement
DirectionSymbolPlacement directionSymbolPlacement() const
Returns the placement for direction symbols.
Definition: qgslabellinesettings.h:214
Qgis::UnplacedLabelVisibility
UnplacedLabelVisibility
Unplaced label visibility.
Definition: qgis.h:533
QgsLabelThinningSettings::setLimitNumberLabelsEnabled
void setLimitNumberLabelsEnabled(bool enabled)
Sets whether the the number of labels drawn for the layer should be limited.
Definition: qgslabelthinningsettings.h:50
QgsExpression::hasParserError
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
Definition: qgsexpression.cpp:206
QgsPalLayerSettings::ShadowRadiusUnits
@ ShadowRadiusUnits
Definition: qgspallabeling.h:226
QgsPalLayerSettings::Property
Property
Data definable properties.
Definition: qgspallabeling.h:144
QgsPalLayerSettings::containsAdvancedEffects
bool containsAdvancedEffects() const
Returns true if any component of the label settings requires advanced effects such as blend modes,...
Definition: qgspallabeling.cpp:584
QgsLabelObstacleSettings::ObstacleType
ObstacleType
Valid obstacle types, which affect how features within the layer will act as obstacles for labels.
Definition: qgslabelobstaclesettings.h:42
QgsPalLayerSettings::MinimumScale
@ MinimumScale
Minimum map scale (ie most "zoomed out")
Definition: qgspallabeling.h:266
QgsTextBackgroundSettings::setRotation
void setRotation(double rotation)
Sets the rotation for the background shape, in degrees clockwise.
Definition: qgstextbackgroundsettings.cpp:212
QgsRectangle::grow
void grow(double delta)
Grows the rectangle in place by the specified amount.
Definition: qgsrectangle.h:296
QgsPalLayerSettings::Underline
@ Underline
Use underline.
Definition: qgspallabeling.h:150
QgsMapUnitScale::minScale
double minScale
The minimum scale, or 0.0 if unset.
Definition: qgsmapunitscale.h:55
QgsStringReplacementCollection::writeXml
void writeXml(QDomElement &elem, QDomDocument &doc) const
Writes the collection state to an XML element.
Definition: qgsstringutils.cpp:813
qgslogger.h
pal::LabelPosition::getAlpha
double getAlpha() const
Returns the angle to rotate text (in rad).
Definition: labelposition.cpp:348
QgsTextShadowSettings::setBlendMode
void setBlendMode(QPainter::CompositionMode mode)
Sets the blending mode used for drawing the drop shadow.
Definition: qgstextshadowsettings.cpp:218
QgsMapUnitScale::maxScale
double maxScale
The maximum scale, or 0.0 if unset.
Definition: qgsmapunitscale.h:61
QgsLabelLineSettings::addDirectionSymbol
bool addDirectionSymbol() const
Returns true if '<' or '>' (or custom strings set via leftDirectionSymbol and rightDirectionSymbol) w...
Definition: qgslabellinesettings.h:141
QgsTextBackgroundSettings::ShapeMarkerSymbol
@ ShapeMarkerSymbol
Marker symbol.
Definition: qgstextbackgroundsettings.h:60
QgsFields::lookupField
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:349
QgsRenderContext::rendererScale
double rendererScale() const
Returns the renderer map scale.
Definition: qgsrendercontext.h:344
QgsTextBufferSettings::color
QColor color() const
Returns the color of the buffer.
Definition: qgstextbuffersettings.cpp:112
Qgis::LabelPlacement::Line
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
QgsLabelPlacementSettings::overlapHandling
Qgis::LabelOverlapHandling overlapHandling() const
Returns the technique used to handle overlapping labels.
Definition: qgslabelplacementsettings.h:42
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsMapSettings
The QgsMapSettings class contains configuration for rendering of the map. The rendering itself is don...
Definition: qgsmapsettings.h:88
QgsPalLayerSettings::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the label's property collection, used for data defined overrides.
Definition: qgspallabeling.h:816
QgsPalLayerSettings::fontMinPixelSize
int fontMinPixelSize
Minimum pixel size for showing rendered map unit labels (1 - 1000).
Definition: qgspallabeling.h:643
QgsMapSettings::visibleExtent
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
Definition: qgsmapsettings.cpp:411
PredefinedPointPositionVector
QVector< Qgis::LabelPredefinedPointPosition > PredefinedPointPositionVector
Definition: qgspallabeling.cpp:93
QgsTextBackgroundSettings::markerSymbol
QgsMarkerSymbol * markerSymbol() const
Returns the marker symbol to be rendered in the background.
Definition: qgstextbackgroundsettings.cpp:137
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:268
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsPalLayerSettings::setRotationUnit
void setRotationUnit(QgsUnitTypes::AngleUnit angleUnit)
Set unit for rotation of labels.
Definition: qgspallabeling.cpp:622
QgsPalLayerSettings::FontMinPixel
@ FontMinPixel
Definition: qgspallabeling.h:270
QgsGeometry::type
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:128
QgsPalLayerSettings::ShapeJoinStyle
@ ShapeJoinStyle
Definition: qgspallabeling.h:217
QgsPalLayerSettings::operator=
QgsPalLayerSettings & operator=(const QgsPalLayerSettings &s)
copy operator - only copies the permanent members
Definition: qgspallabeling.cpp:297
QgsPalLayerSettings::FontSizeUnit
@ FontSizeUnit
Font size units.
Definition: qgspallabeling.h:155
QgsVectorLayer::geometryType
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Definition: qgsvectorlayer.cpp:720
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsMapLayerType::PointCloudLayer
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
qgsvectortilebasiclabeling.h
QgsTextBackgroundSettings::setOffsetUnit
void setOffsetUnit(QgsUnitTypes::RenderUnit units)
Sets the units used for the shape's offset.
Definition: qgstextbackgroundsettings.cpp:232
QgsLabelPlacementSettings::allowDegradedPlacement
bool allowDegradedPlacement() const
Returns true if labels can be placed in inferior fallback positions if they cannot otherwise be place...
Definition: qgslabelplacementsettings.h:59
QgsTextFormat::HorizontalOrientation
@ HorizontalOrientation
Vertically oriented text.
Definition: qgstextformat.h:47
QgsPalLayerSettings::ShadowDraw
@ ShadowDraw
Definition: qgspallabeling.h:220
MathUtils::angle
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsGeometry::area
double area() const
Returns the planar, 2-dimensional area of the geometry.
Definition: qgsgeometry.cpp:1880
qgstextlabelfeature.h
QgsLabelLineSettings::AnchorClipping
AnchorClipping
Clipping behavior for line anchor calculation.
Definition: qgslabellinesettings.h:71
QgsPropertyDefinition::StrokeWidth
@ StrokeWidth
Line stroke width.
Definition: qgsproperty.h:72
Q_GLOBAL_STATIC_WITH_ARGS
Q_GLOBAL_STATIC_WITH_ARGS(PredefinedPointPositionVector, DEFAULT_PLACEMENT_ORDER,({ Qgis::LabelPredefinedPointPosition::TopRight, Qgis::LabelPredefinedPointPosition::TopLeft, Qgis::LabelPredefinedPointPosition::BottomRight, Qgis::LabelPredefinedPointPosition::BottomLeft, Qgis::LabelPredefinedPointPosition::MiddleRight, Qgis::LabelPredefinedPointPosition::MiddleLeft, Qgis::LabelPredefinedPointPosition::TopSlightlyRight, Qgis::LabelPredefinedPointPosition::BottomSlightlyRight })) void QgsPalLayerSettings
Definition: qgspallabeling.cpp:94
QgsLabelPlacementSettings::setOverlapHandling
void setOverlapHandling(Qgis::LabelOverlapHandling handling)
Sets the technique used to handle overlapping labels.
Definition: qgslabelplacementsettings.h:48
QgsTextFormat::writeXml
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Definition: qgstextformat.cpp:671
QgsPalLayerSettings::MinScale
@ MinScale
Min scale (deprecated, for old project compatibility only)
Definition: qgspallabeling.h:265
QgsLabelLineSettings::setPlacementFlags
void setPlacementFlags(QgsLabeling::LinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
Definition: qgslabellinesettings.h:106
QgsPalLayerSettings::Rotation
@ Rotation
Label rotation (deprecated, for old project compatibility only)
Definition: qgspallabeling.h:248
QgsPalLayerSettings::layerType
QgsWkbTypes::GeometryType layerType
Geometry type of layers associated with these settings.
Definition: qgspallabeling.h:739
QgsMapSettings::mapToPixel
const QgsMapToPixel & mapToPixel() const
Definition: qgsmapsettings.h:527
QgsLabelLineSettings::DirectionSymbolPlacement
DirectionSymbolPlacement
Placement options for direction symbols.
Definition: qgslabellinesettings.h:48
Qgis::LabelOverlapHandling
LabelOverlapHandling
Label overlap handling.
Definition: qgis.h:545
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
QgsPoint::x
double x
Definition: qgspoint.h:69
qgsmultisurface.h
QgsTextFormat::TextOrientation
TextOrientation
Text orientation.
Definition: qgstextformat.h:45
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:676
QgsTextBackgroundSettings::strokeColor
QColor strokeColor() const
Returns the color used for outlining the background shape.
Definition: qgstextbackgroundsettings.cpp:311
qgsproject.h
QgsRenderContext::setScaleFactor
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
Definition: qgsrendercontext.h:472
QgsPalLayerSettings::OffsetRotation
@ OffsetRotation
Definition: qgspallabeling.h:240
QgsPropertyDefinition::ColorNoAlpha
@ ColorNoAlpha
Color with no alpha channel.
Definition: qgsproperty.h:65
QgsMapLayerType::PluginLayer
@ PluginLayer
Plugin based layer.
Qgis::LabelPlacement::AroundPoint
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
QgsTextBackgroundSettings::setEnabled
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
Definition: qgstextbackgroundsettings.cpp:112
QgsLabelObstacleSettings::factor
double factor() const
Returns the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
Definition: qgslabelobstaclesettings.h:84
QgsCallout::enabled
bool enabled() const
Returns true if the the callout is enabled.
Definition: qgscallout.h:319
QgsPalLayerSettings::centroidInside
bool centroidInside
true if centroid positioned labels must be placed inside their corresponding feature polygon,...
Definition: qgspallabeling.h:463
QgsUnitTypes::AngleDegrees
@ AngleDegrees
Degrees.
Definition: qgsunittypes.h:133
QgsPalLayerSettings::PositionPoint
@ PositionPoint
Point-coordinate data defined label position.
Definition: qgspallabeling.h:245
QgsVectorLayer::labelsEnabled
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
Definition: qgsvectorlayer.cpp:789
qgslabelingengine.h
QgsFontUtils::updateFontViaStyle
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
Definition: qgsfontutils.cpp:153
QgsTextMaskSettings::joinStyle
Qt::PenJoinStyle joinStyle() const
Returns the buffer join style.
Definition: qgstextmasksettings.cpp:115
QgsTextBackgroundSettings::radii
QSizeF radii() const
Returns the radii used for rounding the corners of shapes.
Definition: qgstextbackgroundsettings.cpp:247
QgsAbstractPropertyCollection::writeXml
virtual bool writeXml(QDomElement &collectionElem, const QgsPropertiesDefinition &definitions) const
Writes the current state of the property collection into an XML element.
Definition: qgspropertycollection.cpp:99
QgsPalLayerSettings::centroidWhole
bool centroidWhole
true if feature centroid should be calculated from the whole feature, or false if only the visible pa...
Definition: qgspallabeling.h:456
QgsGeometry::collectGeometry
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
Definition: qgsgeometry.cpp:259
QgsPalLayerSettings::distMapUnitScale
QgsMapUnitScale distMapUnitScale
Map unit scale for label feature distance.
Definition: qgspallabeling.h:497
QgsPalLabeling::drawLabelCandidateRect
static void drawLabelCandidateRect(pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList< QgsLabelCandidate > *candidates=nullptr)
Definition: qgspallabeling.cpp:4608
Qgis::LabelPlacement
LabelPlacement
Placement modes which determine how label candidates are generated for a feature.
Definition: qgis.h:560
qgsmessagelog.h
QgsGeometry::isGeosValid
bool isGeosValid(Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const
Checks validity of the geometry using GEOS.
Definition: qgsgeometry.cpp:3019
QgsTextFormat::containsAdvancedEffects
bool containsAdvancedEffects() const
Returns true if any component of the font format requires advanced effects such as blend modes,...
Definition: qgstextformat.cpp:817
QgsPropertyDefinition::DoublePositive
@ DoublePositive
Positive double value (including 0)
Definition: qgsproperty.h:58
pal::LabelPosition::getWidth
double getWidth() const
Definition: labelposition.h:260
QgsLabelLineSettings::setReverseDirectionSymbol
void setReverseDirectionSymbol(bool reversed)
Sets whether the direction symbols should be reversed.
Definition: qgslabellinesettings.h:204
QgsPalLayerSettings::predefinedPositionOrder
QVector< Qgis::LabelPredefinedPointPosition > predefinedPositionOrder
Ordered list of predefined label positions for points.
Definition: qgspallabeling.h:471
Qgis::LabelPlacement::Curved
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
QgsPalLayerSettings::IsObstacle
@ IsObstacle
Definition: qgspallabeling.h:272
QgsPalLabeling::splitToGraphemes
static QStringList splitToGraphemes(const QString &text)
Splits a text string to a list of graphemes, which are the smallest allowable character divisions in ...
Definition: qgspallabeling.cpp:3893
QgsMapLayer::type
QgsMapLayerType type
Definition: qgsmaplayer.h:80