30#include <QApplication>
33#include <QFontMetrics>
38#include <QTextBoundaryFinder>
98 if ( !sPropertyDefinitions()->isEmpty() )
101 const QString origin = QStringLiteral(
"labeling" );
113 "e.g. Helvetica or Helvetica [Cronyx]" ), origin )
117 "e.g. Bold Condensed or Light Italic" ), origin )
159 "<b>Ellipse</b>|<b>Circle</b>|<b>SVG</b>]" ), origin )
183 "<b>Buffer</b>|<b>Background</b>]" ), origin )
199 "<b>3</b>=Left|<b>4</b>=Over|<b>5</b>=Right|<br>"
200 "<b>6</b>=Below Left|<b>7</b>=Below|<b>8</b>=Below Right]" ), origin )
220 + QStringLiteral(
"[<b>TL</b>=Top left|<b>TSL</b>=Top, slightly left|<b>T</b>=Top middle|<br>"
221 "<b>TSR</b>=Top, slightly right|<b>TR</b>=Top right|<br>"
222 "<b>L</b>=Left|<b>R</b>=Right|<br>"
223 "<b>BL</b>=Bottom left|<b>BSL</b>=Bottom, slightly left|<b>B</b>=Bottom middle|<br>"
224 "<b>BSR</b>=Bottom, slightly right|<b>BR</b>=Bottom right|<b>O</b>=Over point]" ), origin )
228 + QStringLiteral(
"[<b>OL</b>=On line|<b>AL</b>=Above line|<b>BL</b>=Below line|<br>"
229 "<b>LO</b>=Respect line orientation]" ), origin )
238 "<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ), origin )
268 initPropertyDefinitions();
277 , mDataDefinedProperties( s.mDataDefinedProperties )
312 mPolygonPlacementFlags = s.mPolygonPlacementFlags;
326 mRotationUnit = s.mRotationUnit;
347 mDataDefinedProperties = s.mDataDefinedProperties;
349 mCallout.reset( s.mCallout ? s.mCallout->clone() : nullptr );
351 mPlacementSettings = s.mPlacementSettings;
352 mLineSettings = s.mLineSettings;
353 mPointSettings = s.mPointSettings;
354 mObstacleSettings = s.mObstacleSettings;
355 mThinningSettings = s.mThinningSettings;
362 mLegendString = s.mLegendString;
364 mUnplacedVisibility = s.mUnplacedVisibility;
414 for (
const QString &name : referencedColumns )
416 attributeNames.insert( name );
480 for (
const QString &name : referencedColumns )
482 attributeNames.insert( name );
489 const auto referencedColumns = mCallout->referencedFields( context );
490 for (
const QString &name : referencedColumns )
492 attributeNames.insert( name );
501 QSet<QString> referenced;
529 referenced.unite( mCallout->referencedFields( context ) );
537 if ( mRenderStarted )
539 qWarning(
"Start render called for when a previous render was already underway!!" );
566 mCallout->startRender( context );
569 mRenderStarted =
true;
574 if ( !mRenderStarted )
576 qWarning(
"Stop render called for QgsPalLayerSettings without a startRender call!" );
582 mCallout->stopRender( context );
585 mRenderStarted =
false;
595 if ( mRenderStarted )
597 qWarning(
"stopRender was not called on QgsPalLayerSettings object!" );
608 initPropertyDefinitions();
609 return *sPropertyDefinitions();
623 return mRotationUnit;
628 mRotationUnit = angleUnit;
634 QString newValue = value;
635 if ( !value.isEmpty() && !value.contains( QLatin1String(
"~~" ) ) )
638 values << QStringLiteral(
"1" );
639 values << QStringLiteral(
"0" );
642 newValue = values.join( QLatin1String(
"~~" ) );
650 QString newPropertyName =
"labeling/dataDefined/" + sPropertyDefinitions()->value(
static_cast< int >( p ) ).name();
651 QVariant newPropertyField = layer->
customProperty( newPropertyName, QVariant() );
653 if ( !newPropertyField.isValid() )
656 QString ddString = newPropertyField.toString();
658 if ( !ddString.isEmpty() && ddString != QLatin1String(
"0~~0~~~~" ) )
662 QStringList ddv = newStyleString.split( QStringLiteral(
"~~" ) );
664 bool active = ddv.at( 0 ).toInt();
665 if ( ddv.at( 1 ).toInt() )
681void QgsPalLayerSettings::readOldDataDefinedPropertyMap(
QgsVectorLayer *layer, QDomElement *parentElem )
683 if ( !layer && !parentElem )
688 QgsPropertiesDefinition::const_iterator i = sPropertyDefinitions()->constBegin();
689 for ( ; i != sPropertyDefinitions()->constEnd(); ++i )
694 readOldDataDefinedProperty( layer,
static_cast< Property >( i.key() ) );
696 else if ( parentElem )
699 QDomElement e = parentElem->firstChildElement( i.value().name() );
702 bool active = e.attribute( QStringLiteral(
"active" ) ).compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
703 bool isExpression = e.attribute( QStringLiteral(
"useExpr" ) ).compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
717void QgsPalLayerSettings::readFromLayerCustomProperties(
QgsVectorLayer *layer )
719 if ( layer->
customProperty( QStringLiteral(
"labeling" ) ).toString() != QLatin1String(
"pal" ) )
744 QDomDocument doc( QStringLiteral(
"substitutions" ) );
745 doc.setContent( layer->
customProperty( QStringLiteral(
"labeling/substitutions" ) ).toString() );
746 QDomElement replacementElem = doc.firstChildElement( QStringLiteral(
"substitutions" ) );
772 if ( predefinedPositionOrder.isEmpty() )
773 predefinedPositionOrder = *DEFAULT_PLACEMENT_ORDER();
779 if ( layer->
customProperty( QStringLiteral(
"labeling/distMapUnitScale" ) ).toString().isEmpty() )
782 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/distMapUnitMinScale" ), 0.0 ).toDouble();
784 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/distMapUnitMaxScale" ), 0.0 ).toDouble();
795 if ( layer->
customProperty( QStringLiteral(
"labeling/labelOffsetInMapUnits" ), QVariant(
true ) ).toBool() )
800 if ( layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitScale" ) ).toString().isEmpty() )
803 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitMinScale" ), 0.0 ).toDouble();
805 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitMaxScale" ), 0.0 ).toDouble();
813 QVariant tempAngle = layer->
customProperty( QStringLiteral(
"labeling/angleOffset" ), QVariant() );
814 if ( tempAngle.isValid() )
816 double oldAngle = layer->
customProperty( QStringLiteral(
"labeling/angleOffset" ), QVariant( 0.0 ) ).toDouble();
830 switch ( layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceUnit" ), QVariant( 1 ) ).toUInt() )
845 if ( layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitScale" ) ).toString().isEmpty() )
848 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitMinScale" ), 0.0 ).toDouble();
850 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitMaxScale" ), 0.0 ).toDouble();
859 double scalemn = layer->
customProperty( QStringLiteral(
"labeling/scaleMin" ), QVariant( 0 ) ).toDouble();
860 double scalemx = layer->
customProperty( QStringLiteral(
"labeling/scaleMax" ), QVariant( 0 ) ).toDouble();
863 QVariant scalevis = layer->
customProperty( QStringLiteral(
"labeling/scaleVisibility" ), QVariant() );
864 if ( scalevis.isValid() )
870 else if ( scalemn > 0 || scalemx > 0 )
886 if ( layer->
customProperty( QStringLiteral(
"labeling/displayAll" ), QVariant(
false ) ).toBool() )
904 mObstacleSettings.
setFactor( layer->
customProperty( QStringLiteral(
"labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble() );
906 zIndex = layer->
customProperty( QStringLiteral(
"labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();
908 mDataDefinedProperties.
clear();
909 if ( layer->
customProperty( QStringLiteral(
"labeling/ddProperties" ) ).isValid() )
911 QDomDocument doc( QStringLiteral(
"dd" ) );
912 doc.setContent( layer->
customProperty( QStringLiteral(
"labeling/ddProperties" ) ).toString() );
913 QDomElement elem = doc.firstChildElement( QStringLiteral(
"properties" ) );
914 mDataDefinedProperties.
readXml( elem, *sPropertyDefinitions() );
919 readOldDataDefinedPropertyMap( layer,
nullptr );
963 QDomElement textStyleElem = elem.firstChildElement( QStringLiteral(
"text-style" ) );
964 fieldName = textStyleElem.attribute( QStringLiteral(
"fieldName" ) );
965 isExpression = textStyleElem.attribute( QStringLiteral(
"isExpression" ) ).toInt();
967 mFormat.
readXml( elem, context );
969 previewBkgrdColor = QColor( textStyleElem.attribute( QStringLiteral(
"previewBkgrdColor" ), QStringLiteral(
"#ffffff" ) ) );
972 useSubstitutions = textStyleElem.attribute( QStringLiteral(
"useSubstitutions" ) ).toInt();
973 mLegendString = textStyleElem.attribute( QStringLiteral(
"legendString" ), QObject::tr(
"Aa" ) );
976 QDomElement textFormatElem = elem.firstChildElement( QStringLiteral(
"text-format" ) );
977 wrapChar = textFormatElem.attribute( QStringLiteral(
"wrapChar" ) );
978 autoWrapLength = textFormatElem.attribute( QStringLiteral(
"autoWrapLength" ), QStringLiteral(
"0" ) ).toInt();
979 useMaxLineLengthForAutoWrap = textFormatElem.attribute( QStringLiteral(
"useMaxLineLengthForAutoWrap" ), QStringLiteral(
"1" ) ).toInt();
981 mLineSettings.
setAddDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"addDirectionSymbol" ) ).toInt() );
982 mLineSettings.
setLeftDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"leftDirectionSymbol" ), QStringLiteral(
"<" ) ) );
983 mLineSettings.
setRightDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"rightDirectionSymbol" ), QStringLiteral(
">" ) ) );
984 mLineSettings.
setReverseDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"reverseDirectionSymbol" ) ).toInt() );
986 formatNumbers = textFormatElem.attribute( QStringLiteral(
"formatNumbers" ) ).toInt();
987 decimals = textFormatElem.attribute( QStringLiteral(
"decimals" ) ).toInt();
988 plusSign = textFormatElem.attribute( QStringLiteral(
"plussign" ) ).toInt();
991 QDomElement placementElem = elem.firstChildElement( QStringLiteral(
"placement" ) );
996 centroidWhole = placementElem.attribute( QStringLiteral(
"centroidWhole" ), QStringLiteral(
"0" ) ).toInt();
997 centroidInside = placementElem.attribute( QStringLiteral(
"centroidInside" ), QStringLiteral(
"0" ) ).toInt();
1000 if ( predefinedPositionOrder.isEmpty() )
1001 predefinedPositionOrder = *DEFAULT_PLACEMENT_ORDER();
1004 fitInPolygonOnly = placementElem.attribute( QStringLiteral(
"fitInPolygonOnly" ), QStringLiteral(
"0" ) ).toInt();
1005 dist = placementElem.attribute( QStringLiteral(
"dist" ) ).toDouble();
1006 if ( !placementElem.hasAttribute( QStringLiteral(
"distUnits" ) ) )
1008 if ( placementElem.attribute( QStringLiteral(
"distInMapUnits" ) ).toInt() )
1017 if ( !placementElem.hasAttribute( QStringLiteral(
"distMapUnitScale" ) ) )
1020 double oldMin = placementElem.attribute( QStringLiteral(
"distMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1022 double oldMax = placementElem.attribute( QStringLiteral(
"distMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1031 xOffset = placementElem.attribute( QStringLiteral(
"xOffset" ), QStringLiteral(
"0" ) ).toDouble();
1032 yOffset = placementElem.attribute( QStringLiteral(
"yOffset" ), QStringLiteral(
"0" ) ).toDouble();
1033 if ( !placementElem.hasAttribute( QStringLiteral(
"offsetUnits" ) ) )
1041 if ( !placementElem.hasAttribute( QStringLiteral(
"labelOffsetMapUnitScale" ) ) )
1044 double oldMin = placementElem.attribute( QStringLiteral(
"labelOffsetMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1046 double oldMax = placementElem.attribute( QStringLiteral(
"labelOffsetMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1054 if ( placementElem.hasAttribute( QStringLiteral(
"angleOffset" ) ) )
1056 double oldAngle = placementElem.attribute( QStringLiteral(
"angleOffset" ), QStringLiteral(
"0" ) ).toDouble();
1061 angleOffset = placementElem.attribute( QStringLiteral(
"rotationAngle" ), QStringLiteral(
"0" ) ).toDouble();
1064 preserveRotation = placementElem.attribute( QStringLiteral(
"preserveRotation" ), QStringLiteral(
"1" ) ).toInt();
1067 if ( rotationUnitString.startsWith( QLatin1String(
"Angle" ) ) )
1070 rotationUnitString = rotationUnitString.mid( 5 );
1075 maxCurvedCharAngleIn = placementElem.attribute( QStringLiteral(
"maxCurvedCharAngleIn" ), QStringLiteral(
"25" ) ).toDouble();
1076 maxCurvedCharAngleOut = placementElem.attribute( QStringLiteral(
"maxCurvedCharAngleOut" ), QStringLiteral(
"-25" ) ).toDouble();
1077 priority = placementElem.attribute( QStringLiteral(
"priority" ) ).toInt();
1078 repeatDistance = placementElem.attribute( QStringLiteral(
"repeatDistance" ), QStringLiteral(
"0" ) ).toDouble();
1079 if ( !placementElem.hasAttribute( QStringLiteral(
"repeatDistanceUnits" ) ) )
1082 switch ( placementElem.attribute( QStringLiteral(
"repeatDistanceUnit" ), QString::number( 1 ) ).toUInt() )
1102 if ( !placementElem.hasAttribute( QStringLiteral(
"repeatDistanceMapUnitScale" ) ) )
1105 double oldMin = placementElem.attribute( QStringLiteral(
"repeatDistanceMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1107 double oldMax = placementElem.attribute( QStringLiteral(
"repeatDistanceMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1115 mLineSettings.
setOverrunDistance( placementElem.attribute( QStringLiteral(
"overrunDistance" ), QStringLiteral(
"0" ) ).toDouble() );
1118 mLineSettings.
setLineAnchorPercent( placementElem.attribute( QStringLiteral(
"lineAnchorPercent" ), QStringLiteral(
"0.5" ) ).toDouble() );
1124 mPointSettings.
setMaximumDistance( placementElem.attribute( QStringLiteral(
"maximumDistance" ), QStringLiteral(
"0" ) ).toDouble() );
1128 geometryGenerator = placementElem.attribute( QStringLiteral(
"geometryGenerator" ) );
1131 QString geometryTypeKey = placementElem.attribute( QStringLiteral(
"geometryGeneratorType" ) );
1133 if ( geometryTypeKey.endsWith( QLatin1String(
"Geometry" ) ) )
1134 geometryTypeKey.chop( 8 );
1139 QString layerTypeKey = placementElem.attribute( QStringLiteral(
"layerType" ) );
1141 if ( layerTypeKey.endsWith( QLatin1String(
"Geometry" ) ) )
1142 layerTypeKey.chop( 8 );
1147 mPlacementSettings.
setAllowDegradedPlacement( placementElem.attribute( QStringLiteral(
"allowDegraded" ), QStringLiteral(
"0" ) ).toInt() );
1150 QDomElement renderingElem = elem.firstChildElement( QStringLiteral(
"rendering" ) );
1152 drawLabels = renderingElem.attribute( QStringLiteral(
"drawLabels" ), QStringLiteral(
"1" ) ).toInt();
1154 maximumScale = renderingElem.attribute( QStringLiteral(
"scaleMin" ), QStringLiteral(
"0" ) ).toDouble();
1155 minimumScale = renderingElem.attribute( QStringLiteral(
"scaleMax" ), QStringLiteral(
"0" ) ).toDouble();
1156 scaleVisibility = renderingElem.attribute( QStringLiteral(
"scaleVisibility" ) ).toInt();
1158 fontLimitPixelSize = renderingElem.attribute( QStringLiteral(
"fontLimitPixelSize" ), QStringLiteral(
"0" ) ).toInt();
1159 fontMinPixelSize = renderingElem.attribute( QStringLiteral(
"fontMinPixelSize" ), QStringLiteral(
"0" ) ).toInt();
1160 fontMaxPixelSize = renderingElem.attribute( QStringLiteral(
"fontMaxPixelSize" ), QStringLiteral(
"10000" ) ).toInt();
1162 if ( placementElem.hasAttribute( QStringLiteral(
"overlapHandling" ) ) )
1169 if ( renderingElem.attribute( QStringLiteral(
"displayAll" ), QStringLiteral(
"0" ) ).toInt() )
1185 labelPerPart = renderingElem.attribute( QStringLiteral(
"labelPerPart" ) ).toInt();
1186 mLineSettings.
setMergeLines( renderingElem.attribute( QStringLiteral(
"mergeLines" ) ).toInt() );
1187 mThinningSettings.
setMinimumFeatureSize( renderingElem.attribute( QStringLiteral(
"minFeatureSize" ) ).toDouble() );
1188 mThinningSettings.
setLimitNumberLabelsEnabled( renderingElem.attribute( QStringLiteral(
"limitNumLabels" ), QStringLiteral(
"0" ) ).toInt() );
1189 mThinningSettings.
setMaximumNumberLabels( renderingElem.attribute( QStringLiteral(
"maxNumLabels" ), QStringLiteral(
"2000" ) ).toInt() );
1190 mObstacleSettings.
setIsObstacle( renderingElem.attribute( QStringLiteral(
"obstacle" ), QStringLiteral(
"1" ) ).toInt() );
1191 mObstacleSettings.
setFactor( renderingElem.attribute( QStringLiteral(
"obstacleFactor" ), QStringLiteral(
"1" ) ).toDouble() );
1193 zIndex = renderingElem.attribute( QStringLiteral(
"zIndex" ), QStringLiteral(
"0.0" ) ).toDouble();
1196 QDomElement ddElem = elem.firstChildElement( QStringLiteral(
"dd_properties" ) );
1197 if ( !ddElem.isNull() )
1199 mDataDefinedProperties.
readXml( ddElem, *sPropertyDefinitions() );
1204 mDataDefinedProperties.
clear();
1205 QDomElement ddElem = elem.firstChildElement( QStringLiteral(
"data-defined" ) );
1206 readOldDataDefinedPropertyMap(
nullptr, &ddElem );
1247 const QString calloutType = elem.attribute( QStringLiteral(
"calloutType" ) );
1248 if ( calloutType.isEmpty() )
1260 QDomElement textStyleElem = mFormat.
writeXml( doc, context );
1263 textStyleElem.setAttribute( QStringLiteral(
"fieldName" ),
fieldName );
1264 textStyleElem.setAttribute( QStringLiteral(
"isExpression" ),
isExpression );
1265 QDomElement replacementElem = doc.createElement( QStringLiteral(
"substitutions" ) );
1267 textStyleElem.appendChild( replacementElem );
1268 textStyleElem.setAttribute( QStringLiteral(
"useSubstitutions" ),
useSubstitutions );
1269 textStyleElem.setAttribute( QStringLiteral(
"legendString" ), mLegendString );
1272 QDomElement textFormatElem = doc.createElement( QStringLiteral(
"text-format" ) );
1273 textFormatElem.setAttribute( QStringLiteral(
"wrapChar" ),
wrapChar );
1274 textFormatElem.setAttribute( QStringLiteral(
"autoWrapLength" ),
autoWrapLength );
1276 textFormatElem.setAttribute( QStringLiteral(
"multilineAlign" ),
static_cast< unsigned int >(
multilineAlign ) );
1277 textFormatElem.setAttribute( QStringLiteral(
"addDirectionSymbol" ), mLineSettings.
addDirectionSymbol() );
1278 textFormatElem.setAttribute( QStringLiteral(
"leftDirectionSymbol" ), mLineSettings.
leftDirectionSymbol() );
1279 textFormatElem.setAttribute( QStringLiteral(
"rightDirectionSymbol" ), mLineSettings.
rightDirectionSymbol() );
1280 textFormatElem.setAttribute( QStringLiteral(
"reverseDirectionSymbol" ), mLineSettings.
reverseDirectionSymbol() );
1281 textFormatElem.setAttribute( QStringLiteral(
"placeDirectionSymbol" ),
static_cast< unsigned int >( mLineSettings.
directionSymbolPlacement() ) );
1282 textFormatElem.setAttribute( QStringLiteral(
"formatNumbers" ),
formatNumbers );
1283 textFormatElem.setAttribute( QStringLiteral(
"decimals" ),
decimals );
1284 textFormatElem.setAttribute( QStringLiteral(
"plussign" ),
plusSign );
1287 QDomElement placementElem = doc.createElement( QStringLiteral(
"placement" ) );
1288 placementElem.setAttribute( QStringLiteral(
"placement" ),
static_cast< int >(
placement ) );
1289 placementElem.setAttribute( QStringLiteral(
"polygonPlacementFlags" ),
static_cast< int >( mPolygonPlacementFlags ) );
1290 placementElem.setAttribute( QStringLiteral(
"placementFlags" ),
static_cast< unsigned int >( mLineSettings.
placementFlags() ) );
1291 placementElem.setAttribute( QStringLiteral(
"centroidWhole" ),
centroidWhole );
1292 placementElem.setAttribute( QStringLiteral(
"centroidInside" ),
centroidInside );
1294 placementElem.setAttribute( QStringLiteral(
"fitInPolygonOnly" ),
fitInPolygonOnly );
1295 placementElem.setAttribute( QStringLiteral(
"dist" ),
dist );
1298 placementElem.setAttribute( QStringLiteral(
"offsetType" ),
static_cast< unsigned int >(
offsetType ) );
1299 placementElem.setAttribute( QStringLiteral(
"quadOffset" ),
static_cast< unsigned int >( mPointSettings.
quadrant() ) );
1300 placementElem.setAttribute( QStringLiteral(
"xOffset" ),
xOffset );
1301 placementElem.setAttribute( QStringLiteral(
"yOffset" ),
yOffset );
1304 placementElem.setAttribute( QStringLiteral(
"rotationAngle" ),
angleOffset );
1305 placementElem.setAttribute( QStringLiteral(
"preserveRotation" ),
preserveRotation );
1308 const QString rotationUnitString = QStringLiteral(
"Angle" ) +
qgsEnumValueToKey( mRotationUnit );
1309 placementElem.setAttribute( QStringLiteral(
"rotationUnit" ), rotationUnitString );
1313 placementElem.setAttribute( QStringLiteral(
"priority" ),
priority );
1314 placementElem.setAttribute( QStringLiteral(
"repeatDistance" ),
repeatDistance );
1317 placementElem.setAttribute( QStringLiteral(
"overrunDistance" ), mLineSettings.
overrunDistance() );
1320 placementElem.setAttribute( QStringLiteral(
"lineAnchorPercent" ), mLineSettings.
lineAnchorPercent() );
1321 placementElem.setAttribute( QStringLiteral(
"lineAnchorType" ),
static_cast< int >( mLineSettings.
anchorType() ) );
1322 placementElem.setAttribute( QStringLiteral(
"lineAnchorClipping" ),
static_cast< int >( mLineSettings.
anchorClipping() ) );
1325 placementElem.setAttribute( QStringLiteral(
"maximumDistance" ), mPointSettings.
maximumDistance() );
1329 placementElem.setAttribute( QStringLiteral(
"geometryGenerator" ),
geometryGenerator );
1337 placementElem.setAttribute( QStringLiteral(
"allowDegraded" ), mPlacementSettings.
allowDegradedPlacement() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1340 QDomElement renderingElem = doc.createElement( QStringLiteral(
"rendering" ) );
1341 renderingElem.setAttribute( QStringLiteral(
"drawLabels" ),
drawLabels );
1342 renderingElem.setAttribute( QStringLiteral(
"scaleVisibility" ),
scaleVisibility );
1343 renderingElem.setAttribute( QStringLiteral(
"scaleMin" ),
maximumScale );
1344 renderingElem.setAttribute( QStringLiteral(
"scaleMax" ),
minimumScale );
1345 renderingElem.setAttribute( QStringLiteral(
"fontLimitPixelSize" ),
fontLimitPixelSize );
1346 renderingElem.setAttribute( QStringLiteral(
"fontMinPixelSize" ),
fontMinPixelSize );
1347 renderingElem.setAttribute( QStringLiteral(
"fontMaxPixelSize" ),
fontMaxPixelSize );
1348 renderingElem.setAttribute( QStringLiteral(
"upsidedownLabels" ),
static_cast< unsigned int >(
upsidedownLabels ) );
1350 renderingElem.setAttribute( QStringLiteral(
"labelPerPart" ),
labelPerPart );
1351 renderingElem.setAttribute( QStringLiteral(
"mergeLines" ), mLineSettings.
mergeLines() );
1352 renderingElem.setAttribute( QStringLiteral(
"minFeatureSize" ), mThinningSettings.
minimumFeatureSize() );
1354 renderingElem.setAttribute( QStringLiteral(
"maxNumLabels" ), mThinningSettings.
maximumNumberLabels() );
1355 renderingElem.setAttribute( QStringLiteral(
"obstacle" ), mObstacleSettings.
isObstacle() );
1356 renderingElem.setAttribute( QStringLiteral(
"obstacleFactor" ), mObstacleSettings.
factor() );
1357 renderingElem.setAttribute( QStringLiteral(
"obstacleType" ),
static_cast< unsigned int >( mObstacleSettings.
type() ) );
1358 renderingElem.setAttribute( QStringLiteral(
"zIndex" ),
zIndex );
1359 renderingElem.setAttribute( QStringLiteral(
"unplacedVisibility" ),
static_cast< int >( mUnplacedVisibility ) );
1361 QDomElement ddElem = doc.createElement( QStringLiteral(
"dd_properties" ) );
1362 mDataDefinedProperties.
writeXml( ddElem, *sPropertyDefinitions() );
1364 QDomElement elem = doc.createElement( QStringLiteral(
"settings" ) );
1365 elem.appendChild( textStyleElem );
1366 elem.appendChild( textFormatElem );
1367 elem.appendChild( placementElem );
1368 elem.appendChild( renderingElem );
1369 elem.appendChild( ddElem );
1373 elem.setAttribute( QStringLiteral(
"calloutType" ), mCallout->type() );
1374 mCallout->saveProperties( doc, elem, context );
1391 QPixmap pixmap( size * devicePixelRatio );
1392 pixmap.fill( Qt::transparent );
1393 pixmap.setDevicePixelRatio( devicePixelRatio );
1395 painter.begin( &pixmap );
1397 painter.setRenderHint( QPainter::Antialiasing );
1399 const QRectF rect( 0, 0, size.width(), size.height() );
1402 painter.setPen( Qt::NoPen );
1404 if ( ( background1.lightnessF() < 0.7 ) )
1406 background1 = background1.darker( 125 );
1410 background1 = background1.lighter( 125 );
1413 QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1414 linearGrad.setColorAt( 0, background1 );
1415 linearGrad.setColorAt( 1, background2 );
1416 painter.setBrush( QBrush( linearGrad ) );
1417 if ( size.width() > 30 )
1419 painter.drawRoundedRect( rect, 6, 6 );
1424 painter.drawRect( rect );
1426 painter.setBrush( Qt::NoBrush );
1427 painter.setPen( Qt::NoPen );
1442 QWidget *activeWindow = QApplication::activeWindow();
1443 if ( QScreen *screen = activeWindow ? activeWindow->screen() : nullptr )
1463 ? fontSize * tempFormat.
buffer().
size() / 100
1468 double ytrans = 0.0;
1471 ? fontSize * tempFormat.
buffer().
size() / 100
1476 const QStringList text = QStringList() << ( previewText.isEmpty() ? settings.
legendString() : previewText );
1478 QRectF textRect = rect;
1479 textRect.setLeft( xtrans + padding );
1480 textRect.setWidth( rect.width() - xtrans - 2 * padding );
1482 if ( textRect.width() > 2000 )
1483 textRect.setWidth( 2000 - 2 * padding );
1485 const double bottom = textRect.height() / 2 + textHeight / 2;
1486 textRect.setTop( bottom - textHeight );
1487 textRect.setBottom( bottom );
1498 QRectF labelRect( textRect.left() + ( textRect.width() - textWidth ) / 2.0, textRect.top(), textWidth, textRect.height() );
1505 if ( size.width() > 30 )
1510 rect.width() - iconWidth * 3, rect.height() - iconWidth * 3,
1511 iconWidth * 2, iconWidth * 2 ), Qt::AlignRight | Qt::AlignBottom );
1515 painter.setBrush( Qt::NoBrush );
1517 if ( size.width() > 30 )
1519 painter.drawRoundedRect( rect, 6, 6 );
1524 painter.drawRect( rect );
1533 return mUnplacedVisibility;
1538 mUnplacedVisibility = visibility;
1543 return QgsPalLabeling::checkMinimumSizeMM(
ct, geom, minSize );
1555 QString textCopy( text );
1558 std::unique_ptr< QgsRenderContext > scopedRc;
1563 scopedRc->expressionContext().setFeature( *f );
1679 if ( wrapchr.isEmpty() )
1681 wrapchr = QStringLiteral(
"\n" );
1686 && ( !leftDirSymb.isEmpty() || !rightDirSymb.isEmpty() ) )
1688 QString dirSym = leftDirSymb;
1690 if ( fm->horizontalAdvance( rightDirSymb ) > fm->horizontalAdvance( dirSym ) )
1691 dirSym = rightDirSymb;
1693 switch ( placeDirSymb )
1696 textCopy.append( dirSym );
1701 textCopy.prepend( dirSym + QStringLiteral(
"\n" ) );
1706 double w = 0.0, h = 0.0, rw = 0.0, rh = 0.0;
1707 double labelHeight = fm->ascent() + fm->descent();
1710 const int lines = multiLineSplit.size();
1714 switch ( orientation )
1720 for (
const QString &line : std::as_const( multiLineSplit ) )
1722 w = std::max( w, fm->horizontalAdvance( line ) );
1729 double letterSpacing = mFormat.
scaledFont( *context ).letterSpacing();
1730 double labelWidth = fm->maxWidth();
1733 int maxLineLength = 0;
1734 for (
const QString &line : std::as_const( multiLineSplit ) )
1736 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
1738 h = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1744 double widthHorizontal = 0.0;
1745 for (
const QString &line : std::as_const( multiLineSplit ) )
1747 widthHorizontal = std::max( w, fm->horizontalAdvance( line ) );
1750 double widthVertical = 0.0;
1751 double letterSpacing = mFormat.
scaledFont( *context ).letterSpacing();
1752 double labelWidth = fm->maxWidth();
1755 double heightHorizontal = 0.0;
1758 double heightVertical = 0.0;
1759 int maxLineLength = 0;
1760 for (
const QString &line : std::as_const( multiLineSplit ) )
1762 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
1764 heightVertical = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1766 w = widthHorizontal;
1767 rw = heightVertical;
1768 h = heightHorizontal;
1777 if ( rotatedLabelX && rotatedLabelY )
1779 *rotatedLabelX = rw * uPP;
1780 *rotatedLabelY = rh * uPP;
1844 if ( wrapchr.isEmpty() )
1846 wrapchr = QStringLiteral(
"\n" );
1852 QSizeF maximumExtraSpaceAllowance( 0, 0 );
1853 QSizeF minimumSize( 0, 0 );
1855 && ( !leftDirSymb.isEmpty() || !rightDirSymb.isEmpty() ) )
1859 const QString dirSym = fm.horizontalAdvance( rightDirSymb ) > fm.horizontalAdvance( leftDirSymb )
1860 ? rightDirSymb : leftDirSymb;
1862 switch ( placeDirSymb )
1865 maximumExtraSpaceAllowance = QSizeF( fm.horizontalAdvance( dirSym ), 0 );
1871 minimumSize = QSizeF( fm.horizontalAdvance( dirSym ), 0 );
1887 w = std::max( minimumSize.width(), size.width() + maximumExtraSpaceAllowance.width() );
1888 h = std::max( minimumSize.height(), size.height() + maximumExtraSpaceAllowance.height() );
1893 rh = std::max( minimumSize.width(), rotatedSize.width() + maximumExtraSpaceAllowance.width() );
1894 rw = std::max( minimumSize.height(), rotatedSize.height() + maximumExtraSpaceAllowance.height() );
1906 w = fm.horizontalAdvance( text );
1910 size = QSizeF( w * uPP, h * uPP );
1911 rotatedSize = QSizeF( rw * uPP, rh * uPP );
1913 if ( documentMetrics )
1919 outerBounds = QRectF( outerBoundsPixels.left() * uPP,
1920 outerBoundsPixels.top() * uPP,
1921 outerBoundsPixels.width() * uPP,
1922 outerBoundsPixels.height() * uPP );
1937 bool isObstacle = mObstacleSettings.
isObstacle();
1945 return registerObstacleFeature( f, context, obstacleGeometry );
1960 if ( obstacleGeometry.
isNull() )
1973 dataDefinedValues.clear();
1990 if ( useScaleVisibility )
2003 maxScale = 1 / std::fabs( maxScale );
2023 minScale = 1 / std::fabs( minScale );
2035 QFont labelFont = evaluatedFormat.
font();
2043 QString units = exprVal.toString();
2044 if ( !units.isEmpty() )
2054 double fontSize = evaluatedFormat.
size();
2060 if ( fontSize <= 0.0 )
2067 if ( fontPixelSize < 1 )
2071 labelFont.setPixelSize( fontPixelSize );
2083 if ( fontMinPixel > labelFont.pixelSize() || labelFont.pixelSize() > fontMaxPixel )
2095 labelFont.setCapitalization( QFont::MixedCase );
2097 parseTextStyle( labelFont, fontunits, context );
2100 parseTextFormatting( context );
2101 parseTextBuffer( context );
2102 parseTextMask( context );
2103 parseShapeBackground( context );
2104 parseDropShadow( context );
2109 QList<QgsTextFormat::Tab> tabPositions;
2113 for (
const QVariant &part : parts )
2122 for (
const QString &part : parts )
2135 evaluatedFormat.
setFont( labelFont );
2139 evaluatedFormat.
setSize( labelFont.pixelSize() / symbologyReferenceScaleFactor );
2188 QString fcase = exprVal.toString().trimmed();
2189 QgsDebugMsgLevel( QStringLiteral(
"exprVal FontCase:%1" ).arg( fcase ), 4 );
2191 if ( !fcase.isEmpty() )
2193 if ( fcase.compare( QLatin1String(
"NoChange" ), Qt::CaseInsensitive ) == 0 )
2197 else if ( fcase.compare( QLatin1String(
"Upper" ), Qt::CaseInsensitive ) == 0 )
2201 else if ( fcase.compare( QLatin1String(
"Lower" ), Qt::CaseInsensitive ) == 0 )
2205 else if ( fcase.compare( QLatin1String(
"Capitalize" ), Qt::CaseInsensitive ) == 0 )
2209 else if ( fcase.compare( QLatin1String(
"Title" ), Qt::CaseInsensitive ) == 0 )
2213#if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
2214 else if ( fcase.compare( QLatin1String(
"SmallCaps" ), Qt::CaseInsensitive ) == 0 )
2218 else if ( fcase.compare( QLatin1String(
"AllSmallCaps" ), Qt::CaseInsensitive ) == 0 )
2234 if ( evalFormatNumbers )
2238 if ( decimalPlaces <= 0 )
2244 QVariant textV( labelText );
2246 double d = textV.toDouble( &ok );
2249 QString numberFormat;
2250 if ( d > 0 && signPlus )
2252 numberFormat.append(
'+' );
2254 numberFormat.append(
"%1" );
2255 labelText = numberFormat.arg( QLocale().toString( d,
'f', decimalPlaces ) );
2260 const QFontMetricsF labelFontMetrics( labelFont );
2277 calculateLabelSize( labelFontMetrics, labelText, context, evaluatedFormat, &doc, &documentMetrics, labelSize, rotatedSize, outerBounds );
2281 calculateLabelSize( labelFontMetrics, labelText, context, evaluatedFormat,
nullptr,
nullptr, labelSize, rotatedSize, outerBounds );
2296 calculateLabelSize( labelFontMetrics, labelText, context, evaluatedFormat, &doc, &documentMetrics, labelSize, rotatedSize, outerBounds );
2303 double maxcharanglein = 20.0;
2304 double maxcharangleout = -20.0;
2322 maxcharanglein = std::clamp(
static_cast< double >( maxcharanglePt.x() ), 20.0, 60.0 );
2323 maxcharangleout = std::clamp(
static_cast< double >( maxcharanglePt.y() ), 20.0, 95.0 );
2327 maxcharangleout = -( std::fabs( maxcharangleout ) );
2348 QString str = exprVal.toString().trimmed();
2349 QgsDebugMsgLevel( QStringLiteral(
"exprVal CentroidWhole:%1" ).arg( str ), 4 );
2351 if ( !str.isEmpty() )
2353 if ( str.compare( QLatin1String(
"Visible" ), Qt::CaseInsensitive ) == 0 )
2355 wholeCentroid =
false;
2357 else if ( str.compare( QLatin1String(
"Whole" ), Qt::CaseInsensitive ) == 0 )
2359 wholeCentroid =
true;
2373 std::unique_ptr<QgsGeometry> scopedClonedGeom;
2379 geom = simplifier.
simplify( geom );
2396 bool doClip =
false;
2397 if ( !centroidPoly || !wholeCentroid )
2409 if ( dataDefinedOutside.userType() == QMetaType::Type::QString )
2411 const QString value = dataDefinedOutside.toString().trimmed();
2412 if ( value.compare( QLatin1String(
"force" ), Qt::CaseInsensitive ) == 0 )
2418 else if ( value.compare( QLatin1String(
"yes" ), Qt::CaseInsensitive ) == 0 )
2423 else if ( value.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
2431 if ( dataDefinedOutside.toBool() )
2470 permissibleZone = geom;
2485 geos::unique_ptr geos_geom_clone;
2506 double minimumSize = 0.0;
2516 if ( !checkMinimumSizeMM( context, geom, featureThinningSettings.
minimumFeatureSize() ) )
2521 if ( !geos_geom_clone )
2550 bool layerDefinedRotation =
false;
2551 bool dataDefinedRotation =
false;
2552 double xPos = 0.0, yPos = 0.0;
2553 double angleInRadians = 0.0;
2554 double quadOffsetX = 0.0, quadOffsetY = 0.0;
2555 double offsetX = 0.0, offsetY = 0.0;
2567 bool ddFixedQuad =
false;
2576 int quadInt = exprVal.toInt( &ok );
2577 if ( ok && 0 <= quadInt && quadInt <= 8 )
2647 QString units = exprVal.toString().trimmed();
2648 if ( !units.isEmpty() )
2654 offUnit = decodedUnits;
2669 layerDefinedRotation =
true;
2670 angleInRadians = ( 360 -
angleOffset ) * M_PI / 180;
2682 const double rotation = exprVal.toDouble( &ok );
2685 dataDefinedRotation =
true;
2693 angleInRadians = ( 360 - rotationDegrees ) * M_PI / 180.0;
2698 bool hasDataDefinedPosition =
false;
2700 bool ddPosition =
false;
2712 bool ddXPos =
false, ddYPos =
false;
2713 xPos = xPosProperty.toDouble( &ddXPos );
2714 yPos = yPosProperty.toDouble( &ddYPos );
2715 if ( ddXPos && ddYPos )
2716 hasDataDefinedPosition =
true;
2727 if ( pointPosProperty.userType() == qMetaTypeId<QgsReferencedGeometry>() )
2732 if ( !referencedGeometryPoint.
isNull()
2736 else if ( pointPosProperty.userType() == qMetaTypeId< QgsGeometry>() )
2743 hasDataDefinedPosition =
true;
2754 if ( hasDataDefinedPosition )
2757 if ( layerDefinedRotation && !dataDefinedRotation )
2759 angleInRadians = 0.0;
2768 QString haliString = exprVal.toString();
2769 if ( haliString.compare( QLatin1String(
"Center" ), Qt::CaseInsensitive ) == 0 )
2771 xdiff -= labelSize.width() / 2.0;
2773 else if ( haliString.compare( QLatin1String(
"Right" ), Qt::CaseInsensitive ) == 0 )
2775 xdiff -= labelSize.width();
2786 QString valiString = exprVal.toString();
2787 if ( valiString.compare( QLatin1String(
"Bottom" ), Qt::CaseInsensitive ) != 0 )
2789 if ( valiString.compare( QLatin1String(
"Top" ), Qt::CaseInsensitive ) == 0 )
2791 ydiff -= labelSize.height();
2795 double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
2796 if ( valiString.compare( QLatin1String(
"Base" ), Qt::CaseInsensitive ) == 0 )
2798 ydiff -= labelSize.height() * descentRatio;
2802 double capHeightRatio = ( labelFontMetrics.boundingRect(
'H' ).height() + 1 + labelFontMetrics.descent() ) / labelFontMetrics.height();
2803 ydiff -= labelSize.height() * capHeightRatio;
2804 if ( valiString.compare( QLatin1String(
"Half" ), Qt::CaseInsensitive ) == 0 )
2806 ydiff += labelSize.height() * ( capHeightRatio - descentRatio ) / 2.0;
2814 if ( dataDefinedRotation )
2817 double xd = xdiff * std::cos( angleInRadians ) - ydiff * std::sin( angleInRadians );
2818 double yd = xdiff * std::sin( angleInRadians ) + ydiff * std::cos( angleInRadians );
2828 if (
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( ddPoint.
constGet() ) )
2836 QgsMessageLog::logMessage( QObject::tr(
"Invalid data defined label position (%1, %2)" ).arg( xPos ).arg( yPos ), QObject::tr(
"Labeling" ) );
2837 hasDataDefinedPosition =
false;
2856 bool alwaysShow =
false;
2878 QString units = exprVal.toString().trimmed();
2879 if ( !units.isEmpty() )
2885 repeatUnits = decodedUnits;
2911 bool labelAll =
labelPerPart && !hasDataDefinedPosition;
2912 if ( !hasDataDefinedPosition )
2929 auto labelFeature = std::make_unique< QgsTextLabelFeature>( feature.
id(), std::move( geos_geom_clone ), labelSize );
2930 labelFeature->setAnchorPosition( anchorPosition );
2931 labelFeature->setFeature( feature );
2932 labelFeature->setSymbol( symbol );
2933 labelFeature->setDocument( doc, documentMetrics );
2935 labelFeature->setRotatedSize( rotatedSize );
2938 labelFeature->setHasFixedPosition( hasDataDefinedPosition );
2939 labelFeature->setFixedPosition(
QgsPointXY( xPos, yPos ) );
2941 labelFeature->setHasFixedAngle( dataDefinedRotation || ( !hasDataDefinedPosition && !
qgsDoubleNear( angleInRadians, 0.0 ) ) );
2942 labelFeature->setFixedAngle( angleInRadians );
2943 labelFeature->setQuadOffset( QPointF( quadOffsetX, quadOffsetY ) );
2944 labelFeature->setPositionOffset(
QgsPointXY( offsetX, offsetY ) );
2946 labelFeature->setAlwaysShow( alwaysShow );
2947 labelFeature->setRepeatDistance( repeatDist );
2948 labelFeature->setLabelText( labelText );
2949 labelFeature->setPermissibleZone( permissibleZone );
2950 labelFeature->setOverrunDistance( overrunDistanceEval );
2951 labelFeature->setOverrunSmoothDistance( overrunSmoothDist );
2952 labelFeature->setMaximumDistance( maximumDistanceEval );
2956 labelFeature->setLabelAllParts( labelAll );
2958 labelFeature->setMinimumSize( minimumSize );
2962 labelFeature->setSymbolSize( QSizeF( obstacleGeometry.
boundingBox().
width(),
2966 if ( outerBounds.left() != 0 || outerBounds.top() != 0 || !
qgsDoubleNear( outerBounds.width(), labelSize.width() ) || !
qgsDoubleNear( outerBounds.height(), labelSize.height() ) )
2968 labelFeature->setOuterBounds( outerBounds );
2973 double topMargin = std::max( 0.25 * labelFontMetrics.ascent(), 0.0 );
2974 double bottomMargin = 1.0 + labelFontMetrics.descent();
2975 QgsMargins vm( 0.0, topMargin, 0.0, bottomMargin );
2977 labelFeature->setVisualMargin( vm );
2980 QgsDebugMsgLevel( QStringLiteral(
"PAL font stored definedFont: %1, Style: %2" ).arg( labelFont.toString(), labelFont.styleName() ), 4 );
2981 labelFeature->setDefinedFont( labelFont );
2983 labelFeature->setMaximumCharacterAngleInside( std::clamp( maxcharanglein, 20.0, 60.0 ) * M_PI / 180 );
2984 labelFeature->setMaximumCharacterAngleOutside( std::clamp( maxcharangleout, -95.0, -20.0 ) * M_PI / 180 );
3008 double distance =
dist;
3022 QString units = exprVal.toString().trimmed();
3023 QgsDebugMsgLevel( QStringLiteral(
"exprVal DistanceUnits:%1" ).arg( units ), 4 );
3024 if ( !units.isEmpty() )
3030 distUnit = decodedUnits;
3044 distance = ( distance < 0 ? -1 : 1 ) * std::max( std::fabs( distance ), 1.0 );
3056 distance = std::max( distance, 2.0 );
3061 distance = std::max( distance, 2.0 );
3068 labelFeature->setDistLabel( d );
3073 labelFeature->setHasFixedQuadrant(
true );
3078 labelFeature->setPolygonPlacementFlags( polygonPlacement );
3087 labelFeature->setZIndex( z );
3097 double priorityD = exprVal.toDouble( &ok );
3100 priorityD = std::clamp( priorityD, 0.0, 10.0 );
3101 priorityD = 1 - priorityD / 10.0;
3102 labelFeature->setPriority( priorityD );
3115 labelFeature->setAllowDegradedPlacement( allowDegradedPlacement );
3124 const QString cleanedString = handlingString.trimmed();
3125 if ( cleanedString.compare( QLatin1String(
"prevent" ), Qt::CaseInsensitive ) == 0 )
3127 else if ( cleanedString.compare( QLatin1String(
"allowifneeded" ), Qt::CaseInsensitive ) == 0 )
3129 else if ( cleanedString.compare( QLatin1String(
"alwaysallow" ), Qt::CaseInsensitive ) == 0 )
3132 labelFeature->setOverlapHandling( overlapHandling );
3135 labelFeature->setPrioritization( mPlacementSettings.
prioritization() );
3141 labelFeature->setObstacleSettings( os );
3144 if ( positionOrder.isEmpty() )
3145 positionOrder = *DEFAULT_PLACEMENT_ORDER();
3151 if ( !dataDefinedOrder.isEmpty() )
3156 labelFeature->setPredefinedPositionOrder( positionOrder );
3159 labelFeature->setDataDefinedValues( dataDefinedValues );
3161 return labelFeature;
3169 if ( !obstacleGeometry.
isNull() )
3171 geom = obstacleGeometry;
3186 if ( ls->numPoints() < 2 )
3192 std::unique_ptr<QgsGeometry> scopedClonedGeom;
3198 geom = simplifier.
simplify( geom );
3201 geos::unique_ptr geos_geom_clone;
3202 std::unique_ptr<QgsGeometry> scopedPreparedGeom;
3210 if ( !geos_geom_clone )
3214 auto obstacleFeature = std::make_unique< QgsLabelFeature >( f.
id(), std::move( geos_geom_clone ), QSizeF( 0, 0 ) );
3215 obstacleFeature->setFeature( f );
3220 obstacleFeature->setObstacleSettings( os );
3223 return obstacleFeature;
3226bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
3230 if ( !mDataDefinedProperties.
isActive( p ) )
3234 exprVal = mDataDefinedProperties.
value( p, context );
3241 bool bol = exprVal.toBool();
3242 dataDefinedValues.insert( p, QVariant( bol ) );
3248 int size = exprVal.toInt( &ok );
3252 dataDefinedValues.insert( p, QVariant( size ) );
3260 int size = exprVal.toInt( &ok );
3262 if ( ok && size > 0 )
3264 dataDefinedValues.insert( p, QVariant( size ) );
3272 double size = exprVal.toDouble( &ok );
3276 dataDefinedValues.insert( p, QVariant( size ) );
3284 double size = exprVal.toDouble( &ok );
3286 if ( ok && size > 0.0 )
3288 dataDefinedValues.insert( p, QVariant( size ) );
3296 double rot = exprVal.toDouble( &ok );
3299 if ( rot < -180.0 && rot >= -360 )
3303 if ( rot > 180.0 && rot <= 360 )
3307 if ( rot >= -180 && rot <= 180 )
3309 dataDefinedValues.insert( p, QVariant( rot ) );
3318 int size = exprVal.toInt( &ok );
3319 if ( ok && size >= 0 && size <= 100 )
3321 dataDefinedValues.insert( p, QVariant( size ) );
3328 QString str = exprVal.toString();
3330 dataDefinedValues.insert( p, QVariant( str ) );
3335 QString unitstr = exprVal.toString().trimmed();
3337 if ( !unitstr.isEmpty() )
3346 QString colorstr = exprVal.toString().trimmed();
3349 if ( color.isValid() )
3351 dataDefinedValues.insert( p, QVariant( color ) );
3358 QString joinstr = exprVal.toString().trimmed();
3360 if ( !joinstr.isEmpty() )
3369 QString blendstr = exprVal.toString().trimmed();
3371 if ( !blendstr.isEmpty() )
3384 dataDefinedValues.insert( p, res );
3395 dataDefinedValues.insert( p, res );
3405void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
3418 QString ddFontFamily;
3425 QString family = exprVal.toString().trimmed();
3426 QgsDebugMsgLevel( QStringLiteral(
"exprVal Font family:%1" ).arg( family ), 4 );
3429 if ( labelFont.family() != family )
3435 ddFontFamily = family;
3442 QString ddFontStyle;
3448 QString fontstyle = exprVal.toString().trimmed();
3449 QgsDebugMsgLevel( QStringLiteral(
"exprVal Font style:%1" ).arg( fontstyle ), 4 );
3450 ddFontStyle = fontstyle;
3455 bool ddBold =
false;
3463 bool ddItalic =
false;
3473 QFont appFont = QApplication::font();
3474 bool newFontBuilt =
false;
3475 if ( ddBold || ddItalic )
3479 newFontBuilt =
true;
3480 newFont.setBold( ddBold );
3481 newFont.setItalic( ddItalic );
3483 else if ( !ddFontStyle.isEmpty()
3484 && ddFontStyle.compare( QLatin1String(
"Ignore" ), Qt::CaseInsensitive ) != 0 )
3486 if ( !ddFontFamily.isEmpty() )
3490 mFontDB = std::make_unique< QFontDatabase >();
3492 QFont styledfont = mFontDB->font( ddFontFamily, ddFontStyle, appFont.pointSize() );
3493 if ( appFont != styledfont )
3495 newFont = styledfont;
3496 newFontBuilt =
true;
3503 else if ( !ddFontFamily.isEmpty() )
3505 if ( ddFontStyle.compare( QLatin1String(
"Ignore" ), Qt::CaseInsensitive ) != 0 )
3509 mFontDB = std::make_unique< QFontDatabase >();
3510 QFont styledfont = mFontDB->font( ddFontFamily, mFormat.
namedStyle(), appFont.pointSize() );
3511 if ( appFont != styledfont )
3513 newFont = styledfont;
3514 newFontBuilt =
true;
3520 newFontBuilt =
true;
3528 newFont.setPixelSize( labelFont.pixelSize() );
3529 newFont.setUnderline( labelFont.underline() );
3530 newFont.setStrikeOut( labelFont.strikeOut() );
3531 newFont.setWordSpacing( labelFont.wordSpacing() );
3532 newFont.setLetterSpacing( QFont::AbsoluteSpacing, labelFont.letterSpacing() );
3534 labelFont = newFont;
3538 double wordspace = labelFont.wordSpacing();
3547 double letterspace = labelFont.letterSpacing();
3560 labelFont.setStrikeOut( strikeout );
3575 labelFont.setUnderline( underline );
3601 drawBuffer = exprVal.toBool();
3614 double bufrSize = buffer.
size();
3617 bufrSize = exprVal.toDouble();
3621 double bufferOpacity = buffer.
opacity() * 100;
3624 bufferOpacity = exprVal.toDouble();
3627 drawBuffer = ( drawBuffer && bufrSize > 0.0 && bufferOpacity > 0 );
3657 bool maskEnabled = mask.
enabled();
3660 maskEnabled = exprVal.toBool();
3669 double bufrSize = mask.
size();
3672 bufrSize = exprVal.toDouble();
3676 double opacity = mask.
opacity() * 100;
3679 opacity = exprVal.toDouble();
3682 maskEnabled = ( maskEnabled && bufrSize > 0.0 && opacity > 0 );
3707 wrapchr = exprVal.toString();
3713 evalAutoWrapLength = exprVal.toInt();
3734 QString str = exprVal.toString().trimmed();
3735 QgsDebugMsgLevel( QStringLiteral(
"exprVal MultiLineAlignment:%1" ).arg( str ), 4 );
3737 if ( !str.isEmpty() )
3742 if ( str.compare( QLatin1String(
"Center" ), Qt::CaseInsensitive ) == 0 )
3746 else if ( str.compare( QLatin1String(
"Right" ), Qt::CaseInsensitive ) == 0 )
3750 else if ( str.compare( QLatin1String(
"Follow" ), Qt::CaseInsensitive ) == 0 )
3754 else if ( str.compare( QLatin1String(
"Justify" ), Qt::CaseInsensitive ) == 0 )
3771 QString str = exprVal.toString().trimmed();
3772 if ( !str.isEmpty() )
3781 drawDirSymb = exprVal.toBool();
3796 QString str = exprVal.toString().trimmed();
3797 QgsDebugMsgLevel( QStringLiteral(
"exprVal DirSymbPlacement:%1" ).arg( str ), 4 );
3799 if ( !str.isEmpty() )
3804 if ( str.compare( QLatin1String(
"Above" ), Qt::CaseInsensitive ) == 0 )
3808 else if ( str.compare( QLatin1String(
"Below" ), Qt::CaseInsensitive ) == 0 )
3830 bool drawShape = background.
enabled();
3833 drawShape = exprVal.toBool();
3842 double shapeOpacity = background.
opacity() * 100;
3845 shapeOpacity = 100.0 * exprVal.toDouble();
3848 drawShape = ( drawShape && shapeOpacity > 0 );
3864 QString skind = exprVal.toString().trimmed();
3865 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeKind:%1" ).arg( skind ), 4 );
3867 if ( !skind.isEmpty() )
3876 QString svgPath = background.
svgFile();
3883 QString svgfile = exprVal.toString().trimmed();
3884 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeSVGFile:%1" ).arg( svgfile ), 4 );
3899 QString stype = exprVal.toString().trimmed();
3900 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeSizeType:%1" ).arg( stype ), 4 );
3902 if ( !stype.isEmpty() )
3911 double ddShpSizeX = background.
size().width();
3914 ddShpSizeX = exprVal.toDouble();
3918 double ddShpSizeY = background.
size().height();
3921 ddShpSizeY = exprVal.toDouble();
3927 && ( svgPath.isEmpty()
3928 || ( !svgPath.isEmpty()
3930 && ddShpSizeX == 0.0 ) ) )
3938 && ddShpSizeX == 0.0 ) ) )
3945 && ( ddShpSizeX == 0.0 || ddShpSizeY == 0.0 ) )
3970 QString rotstr = exprVal.toString().trimmed();
3971 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeRotationType:%1" ).arg( rotstr ), 4 );
3973 if ( !rotstr.isEmpty() )
4024 bool drawShadow = shadow.
enabled();
4027 drawShadow = exprVal.toBool();
4036 double shadowOpacity = shadow.
opacity() * 100;
4039 shadowOpacity = exprVal.toDouble();
4046 shadowOffDist = exprVal.toDouble();
4053 shadowRad = exprVal.toDouble();
4056 drawShadow = ( drawShadow && shadowOpacity > 0 && !( shadowOffDist == 0.0 && shadowRad == 0.0 ) );
4073 QString str = exprVal.toString().trimmed();
4074 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShadowUnder:%1" ).arg( str ), 4 );
4076 if ( !str.isEmpty() )
4111 switch ( layer->
type() )
4115 const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer );
4126 return !labeling->styles().empty();
4133 const QgsMeshLayer *ml = qobject_cast< const QgsMeshLayer * >( layer );
4139 const QgsRasterLayer *rl = qobject_cast< const QgsRasterLayer * >( layer );
4186QStringList
QgsPalLabeling::splitToLines(
const QString &text,
const QString &wrapCharacter,
const int autoWrapLength,
const bool useMaxLineLengthWhenAutoWrapping )
4188 QStringList multiLineSplit;
4189 if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String(
"\n" ) )
4192 const QStringList lines = text.split( wrapCharacter );
4193 for (
const QString &line : lines )
4195 multiLineSplit.append( line.split(
'\n' ) );
4200 multiLineSplit = text.split(
'\n' );
4204 if ( autoWrapLength != 0 )
4206 QStringList autoWrappedLines;
4207 autoWrappedLines.reserve( multiLineSplit.count() );
4208 for (
const QString &line : std::as_const( multiLineSplit ) )
4210 autoWrappedLines.append(
QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split(
'\n' ) );
4212 multiLineSplit = autoWrappedLines;
4214 return multiLineSplit;
4219 QStringList graphemes;
4220 QTextBoundaryFinder boundaryFinder( QTextBoundaryFinder::Grapheme, text );
4221 int currentBoundary = -1;
4222 int previousBoundary = 0;
4223 while ( ( currentBoundary = boundaryFinder.toNextBoundary() ) > 0 )
4225 graphemes << text.mid( previousBoundary, currentBoundary - previousBoundary );
4226 previousBoundary = currentBoundary;
4256 QgsDebugMsgLevel( QStringLiteral(
"Ignoring feature due to transformation exception" ), 4 );
4262 return std::isfinite( point.
x() ) && std::isfinite( point.
y() );
4266 cp->removeInvalidRings();
4268 else if (
QgsMultiSurface *ms = qgsgeometry_cast< QgsMultiSurface * >( geom.
get() ) )
4270 for (
int i = 0; i < ms->numGeometries(); ++i )
4272 if (
QgsCurvePolygon *cp = qgsgeometry_cast< QgsCurvePolygon * >( ms->geometryN( i ) ) )
4273 cp->removeInvalidRings();
4290 const bool mustClip = ( !clipGeometry.
isNull() &&
4294 bool mustClipExact =
false;
4318 QVector< QgsGeometry> parts;
4319 parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.
constGet() )->numGeometries() );
4328 parts.append( partGeom );
4336 if ( bufferGeom.
isNull() )
4345 if ( mustClipExact )
4380 double length = geom.
length();
4381 if ( length >= 0.0 )
4383 return ( length >= ( minSize * mapUnitsPerMM ) );
4388 double area = geom.
area();
4391 return ( std::sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
4399 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4402 bool changed =
false;
4408 format.
setColor( ddColor.value<QColor>() );
4433 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4455 QList<QgsTextFormat::Tab> tabPositions;
4459 for (
const QVariant &part : parts )
4468 for (
const QString &part : parts )
4524 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4527 bool changed =
false;