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