32#include <QApplication>
35#include <QFontMetrics>
40#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 )
158 "<b>Ellipse</b>|<b>Circle</b>|<b>SVG</b>]" ), origin )
182 "<b>Buffer</b>|<b>Background</b>]" ), origin )
198 "<b>3</b>=Left|<b>4</b>=Over|<b>5</b>=Right|<br>"
199 "<b>6</b>=Below Left|<b>7</b>=Below|<b>8</b>=Below Right]" ), origin )
219 + QStringLiteral(
"[<b>TL</b>=Top left|<b>TSL</b>=Top, slightly left|<b>T</b>=Top middle|<br>"
220 "<b>TSR</b>=Top, slightly right|<b>TR</b>=Top right|<br>"
221 "<b>L</b>=Left|<b>R</b>=Right|<br>"
222 "<b>BL</b>=Bottom left|<b>BSL</b>=Bottom, slightly left|<b>B</b>=Bottom middle|<br>"
223 "<b>BSR</b>=Bottom, slightly right|<b>BR</b>=Bottom right]" ), origin )
227 + QStringLiteral(
"[<b>OL</b>=On line|<b>AL</b>=Above line|<b>BL</b>=Below line|<br>"
228 "<b>LO</b>=Respect line orientation]" ), origin )
237 "<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ), origin )
262 : predefinedPositionOrder( *DEFAULT_PLACEMENT_ORDER() )
265 initPropertyDefinitions();
274 , mDataDefinedProperties( s.mDataDefinedProperties )
309 mPolygonPlacementFlags = s.mPolygonPlacementFlags;
325 mRotationUnit = s.mRotationUnit;
346 mDataDefinedProperties = s.mDataDefinedProperties;
348 mCallout.reset( s.mCallout ? s.mCallout->clone() : nullptr );
350 mPlacementSettings = s.mPlacementSettings;
351 mLineSettings = s.mLineSettings;
352 mObstacleSettings = s.mObstacleSettings;
353 mThinningSettings = s.mThinningSettings;
360 mLegendString = s.mLegendString;
362 mUnplacedVisibility = s.mUnplacedVisibility;
412 for (
const QString &name : referencedColumns )
414 attributeNames.insert( name );
473 for (
const QString &name : referencedColumns )
475 attributeNames.insert( name );
482 const auto referencedColumns = mCallout->referencedFields( context );
483 for (
const QString &name : referencedColumns )
485 attributeNames.insert( name );
494 QSet<QString> referenced;
522 referenced.unite( mCallout->referencedFields( context ) );
530 if ( mRenderStarted )
532 qWarning(
"Start render called for when a previous render was already underway!!" );
559 mCallout->startRender( context );
562 mRenderStarted =
true;
567 if ( !mRenderStarted )
569 qWarning(
"Stop render called for QgsPalLayerSettings without a startRender call!" );
575 mCallout->stopRender( context );
578 mRenderStarted =
false;
588 if ( mRenderStarted )
590 qWarning(
"stopRender was not called on QgsPalLayerSettings object!" );
601 initPropertyDefinitions();
602 return *sPropertyDefinitions();
616 return mRotationUnit;
621 mRotationUnit = angleUnit;
627 QString newValue = value;
628 if ( !value.isEmpty() && !value.contains( QLatin1String(
"~~" ) ) )
631 values << QStringLiteral(
"1" );
632 values << QStringLiteral(
"0" );
635 newValue = values.join( QLatin1String(
"~~" ) );
643 QString newPropertyName =
"labeling/dataDefined/" + sPropertyDefinitions()->value( p ).name();
644 QVariant newPropertyField = layer->
customProperty( newPropertyName, QVariant() );
646 if ( !newPropertyField.isValid() )
649 QString ddString = newPropertyField.toString();
651 if ( !ddString.isEmpty() && ddString != QLatin1String(
"0~~0~~~~" ) )
655 QStringList ddv = newStyleString.split( QStringLiteral(
"~~" ) );
657 bool active = ddv.at( 0 ).toInt();
658 if ( ddv.at( 1 ).toInt() )
674void QgsPalLayerSettings::readOldDataDefinedPropertyMap(
QgsVectorLayer *layer, QDomElement *parentElem )
676 if ( !layer && !parentElem )
681 QgsPropertiesDefinition::const_iterator i = sPropertyDefinitions()->constBegin();
682 for ( ; i != sPropertyDefinitions()->constEnd(); ++i )
687 readOldDataDefinedProperty( layer,
static_cast< Property >( i.key() ) );
689 else if ( parentElem )
692 QDomElement e = parentElem->firstChildElement( i.value().name() );
695 bool active = e.attribute( QStringLiteral(
"active" ) ).compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
696 bool isExpression = e.attribute( QStringLiteral(
"useExpr" ) ).compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
710void QgsPalLayerSettings::readFromLayerCustomProperties(
QgsVectorLayer *layer )
712 if ( layer->
customProperty( QStringLiteral(
"labeling" ) ).toString() != QLatin1String(
"pal" ) )
737 QDomDocument doc( QStringLiteral(
"substitutions" ) );
738 doc.setContent( layer->
customProperty( QStringLiteral(
"labeling/substitutions" ) ).toString() );
739 QDomElement replacementElem = doc.firstChildElement( QStringLiteral(
"substitutions" ) );
760 mLineSettings.
setPlacementFlags(
static_cast< Qgis::LabelLinePlacementFlags
>( layer->
customProperty( QStringLiteral(
"labeling/placementFlags" ) ).toUInt() ) );
769 if ( layer->
customProperty( QStringLiteral(
"labeling/distMapUnitScale" ) ).toString().isEmpty() )
772 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/distMapUnitMinScale" ), 0.0 ).toDouble();
774 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/distMapUnitMaxScale" ), 0.0 ).toDouble();
785 if ( layer->
customProperty( QStringLiteral(
"labeling/labelOffsetInMapUnits" ), QVariant(
true ) ).toBool() )
790 if ( layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitScale" ) ).toString().isEmpty() )
793 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitMinScale" ), 0.0 ).toDouble();
795 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitMaxScale" ), 0.0 ).toDouble();
803 QVariant tempAngle = layer->
customProperty( QStringLiteral(
"labeling/angleOffset" ), QVariant() );
804 if ( tempAngle.isValid() )
806 double oldAngle = layer->
customProperty( QStringLiteral(
"labeling/angleOffset" ), QVariant( 0.0 ) ).toDouble();
820 switch ( layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceUnit" ), QVariant( 1 ) ).toUInt() )
835 if ( layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitScale" ) ).toString().isEmpty() )
838 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitMinScale" ), 0.0 ).toDouble();
840 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitMaxScale" ), 0.0 ).toDouble();
849 double scalemn = layer->
customProperty( QStringLiteral(
"labeling/scaleMin" ), QVariant( 0 ) ).toDouble();
850 double scalemx = layer->
customProperty( QStringLiteral(
"labeling/scaleMax" ), QVariant( 0 ) ).toDouble();
853 QVariant scalevis = layer->
customProperty( QStringLiteral(
"labeling/scaleVisibility" ), QVariant() );
854 if ( scalevis.isValid() )
860 else if ( scalemn > 0 || scalemx > 0 )
876 if ( layer->
customProperty( QStringLiteral(
"labeling/displayAll" ), QVariant(
false ) ).toBool() )
894 mObstacleSettings.
setFactor( layer->
customProperty( QStringLiteral(
"labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble() );
896 zIndex = layer->
customProperty( QStringLiteral(
"labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();
898 mDataDefinedProperties.
clear();
899 if ( layer->
customProperty( QStringLiteral(
"labeling/ddProperties" ) ).isValid() )
901 QDomDocument doc( QStringLiteral(
"dd" ) );
902 doc.setContent( layer->
customProperty( QStringLiteral(
"labeling/ddProperties" ) ).toString() );
903 QDomElement elem = doc.firstChildElement( QStringLiteral(
"properties" ) );
904 mDataDefinedProperties.
readXml( elem, *sPropertyDefinitions() );
909 readOldDataDefinedPropertyMap( layer,
nullptr );
953 QDomElement textStyleElem = elem.firstChildElement( QStringLiteral(
"text-style" ) );
954 fieldName = textStyleElem.attribute( QStringLiteral(
"fieldName" ) );
955 isExpression = textStyleElem.attribute( QStringLiteral(
"isExpression" ) ).toInt();
957 mFormat.
readXml( elem, context );
959 previewBkgrdColor = QColor( textStyleElem.attribute( QStringLiteral(
"previewBkgrdColor" ), QStringLiteral(
"#ffffff" ) ) );
962 useSubstitutions = textStyleElem.attribute( QStringLiteral(
"useSubstitutions" ) ).toInt();
963 mLegendString = textStyleElem.attribute( QStringLiteral(
"legendString" ), QObject::tr(
"Aa" ) );
966 QDomElement textFormatElem = elem.firstChildElement( QStringLiteral(
"text-format" ) );
967 wrapChar = textFormatElem.attribute( QStringLiteral(
"wrapChar" ) );
968 autoWrapLength = textFormatElem.attribute( QStringLiteral(
"autoWrapLength" ), QStringLiteral(
"0" ) ).toInt();
969 useMaxLineLengthForAutoWrap = textFormatElem.attribute( QStringLiteral(
"useMaxLineLengthForAutoWrap" ), QStringLiteral(
"1" ) ).toInt();
971 mLineSettings.
setAddDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"addDirectionSymbol" ) ).toInt() );
972 mLineSettings.
setLeftDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"leftDirectionSymbol" ), QStringLiteral(
"<" ) ) );
973 mLineSettings.
setRightDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"rightDirectionSymbol" ), QStringLiteral(
">" ) ) );
974 mLineSettings.
setReverseDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"reverseDirectionSymbol" ) ).toInt() );
976 formatNumbers = textFormatElem.attribute( QStringLiteral(
"formatNumbers" ) ).toInt();
977 decimals = textFormatElem.attribute( QStringLiteral(
"decimals" ) ).toInt();
978 plusSign = textFormatElem.attribute( QStringLiteral(
"plussign" ) ).toInt();
981 QDomElement placementElem = elem.firstChildElement( QStringLiteral(
"placement" ) );
983 mLineSettings.
setPlacementFlags(
static_cast< Qgis::LabelLinePlacementFlags
>( placementElem.attribute( QStringLiteral(
"placementFlags" ) ).toUInt() ) );
986 centroidWhole = placementElem.attribute( QStringLiteral(
"centroidWhole" ), QStringLiteral(
"0" ) ).toInt();
987 centroidInside = placementElem.attribute( QStringLiteral(
"centroidInside" ), QStringLiteral(
"0" ) ).toInt();
991 fitInPolygonOnly = placementElem.attribute( QStringLiteral(
"fitInPolygonOnly" ), QStringLiteral(
"0" ) ).toInt();
992 dist = placementElem.attribute( QStringLiteral(
"dist" ) ).toDouble();
993 if ( !placementElem.hasAttribute( QStringLiteral(
"distUnits" ) ) )
995 if ( placementElem.attribute( QStringLiteral(
"distInMapUnits" ) ).toInt() )
1004 if ( !placementElem.hasAttribute( QStringLiteral(
"distMapUnitScale" ) ) )
1007 double oldMin = placementElem.attribute( QStringLiteral(
"distMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1009 double oldMax = placementElem.attribute( QStringLiteral(
"distMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1018 xOffset = placementElem.attribute( QStringLiteral(
"xOffset" ), QStringLiteral(
"0" ) ).toDouble();
1019 yOffset = placementElem.attribute( QStringLiteral(
"yOffset" ), QStringLiteral(
"0" ) ).toDouble();
1020 if ( !placementElem.hasAttribute( QStringLiteral(
"offsetUnits" ) ) )
1028 if ( !placementElem.hasAttribute( QStringLiteral(
"labelOffsetMapUnitScale" ) ) )
1031 double oldMin = placementElem.attribute( QStringLiteral(
"labelOffsetMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1033 double oldMax = placementElem.attribute( QStringLiteral(
"labelOffsetMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1041 if ( placementElem.hasAttribute( QStringLiteral(
"angleOffset" ) ) )
1043 double oldAngle = placementElem.attribute( QStringLiteral(
"angleOffset" ), QStringLiteral(
"0" ) ).toDouble();
1048 angleOffset = placementElem.attribute( QStringLiteral(
"rotationAngle" ), QStringLiteral(
"0" ) ).toDouble();
1051 preserveRotation = placementElem.attribute( QStringLiteral(
"preserveRotation" ), QStringLiteral(
"1" ) ).toInt();
1054 if ( rotationUnitString.startsWith( QLatin1String(
"Angle" ) ) )
1057 rotationUnitString = rotationUnitString.mid( 5 );
1062 maxCurvedCharAngleIn = placementElem.attribute( QStringLiteral(
"maxCurvedCharAngleIn" ), QStringLiteral(
"25" ) ).toDouble();
1063 maxCurvedCharAngleOut = placementElem.attribute( QStringLiteral(
"maxCurvedCharAngleOut" ), QStringLiteral(
"-25" ) ).toDouble();
1064 priority = placementElem.attribute( QStringLiteral(
"priority" ) ).toInt();
1065 repeatDistance = placementElem.attribute( QStringLiteral(
"repeatDistance" ), QStringLiteral(
"0" ) ).toDouble();
1066 if ( !placementElem.hasAttribute( QStringLiteral(
"repeatDistanceUnits" ) ) )
1069 switch ( placementElem.attribute( QStringLiteral(
"repeatDistanceUnit" ), QString::number( 1 ) ).toUInt() )
1089 if ( !placementElem.hasAttribute( QStringLiteral(
"repeatDistanceMapUnitScale" ) ) )
1092 double oldMin = placementElem.attribute( QStringLiteral(
"repeatDistanceMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1094 double oldMax = placementElem.attribute( QStringLiteral(
"repeatDistanceMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1102 mLineSettings.
setOverrunDistance( placementElem.attribute( QStringLiteral(
"overrunDistance" ), QStringLiteral(
"0" ) ).toDouble() );
1105 mLineSettings.
setLineAnchorPercent( placementElem.attribute( QStringLiteral(
"lineAnchorPercent" ), QStringLiteral(
"0.5" ) ).toDouble() );
1111 geometryGenerator = placementElem.attribute( QStringLiteral(
"geometryGenerator" ) );
1114 QString geometryTypeKey = placementElem.attribute( QStringLiteral(
"geometryGeneratorType" ) );
1116 if ( geometryTypeKey.endsWith( QLatin1String(
"Geometry" ) ) )
1117 geometryTypeKey.chop( 8 );
1122 QString layerTypeKey = placementElem.attribute( QStringLiteral(
"layerType" ) );
1124 if ( layerTypeKey.endsWith( QLatin1String(
"Geometry" ) ) )
1125 layerTypeKey.chop( 8 );
1130 mPlacementSettings.
setAllowDegradedPlacement( placementElem.attribute( QStringLiteral(
"allowDegraded" ), QStringLiteral(
"0" ) ).toInt() );
1133 QDomElement renderingElem = elem.firstChildElement( QStringLiteral(
"rendering" ) );
1135 drawLabels = renderingElem.attribute( QStringLiteral(
"drawLabels" ), QStringLiteral(
"1" ) ).toInt();
1137 maximumScale = renderingElem.attribute( QStringLiteral(
"scaleMin" ), QStringLiteral(
"0" ) ).toDouble();
1138 minimumScale = renderingElem.attribute( QStringLiteral(
"scaleMax" ), QStringLiteral(
"0" ) ).toDouble();
1139 scaleVisibility = renderingElem.attribute( QStringLiteral(
"scaleVisibility" ) ).toInt();
1141 fontLimitPixelSize = renderingElem.attribute( QStringLiteral(
"fontLimitPixelSize" ), QStringLiteral(
"0" ) ).toInt();
1142 fontMinPixelSize = renderingElem.attribute( QStringLiteral(
"fontMinPixelSize" ), QStringLiteral(
"0" ) ).toInt();
1143 fontMaxPixelSize = renderingElem.attribute( QStringLiteral(
"fontMaxPixelSize" ), QStringLiteral(
"10000" ) ).toInt();
1145 if ( placementElem.hasAttribute( QStringLiteral(
"overlapHandling" ) ) )
1152 if ( renderingElem.attribute( QStringLiteral(
"displayAll" ), QStringLiteral(
"0" ) ).toInt() )
1165 labelPerPart = renderingElem.attribute( QStringLiteral(
"labelPerPart" ) ).toInt();
1166 mLineSettings.
setMergeLines( renderingElem.attribute( QStringLiteral(
"mergeLines" ) ).toInt() );
1167 mThinningSettings.
setMinimumFeatureSize( renderingElem.attribute( QStringLiteral(
"minFeatureSize" ) ).toDouble() );
1168 mThinningSettings.
setLimitNumberLabelsEnabled( renderingElem.attribute( QStringLiteral(
"limitNumLabels" ), QStringLiteral(
"0" ) ).toInt() );
1169 mThinningSettings.
setMaximumNumberLabels( renderingElem.attribute( QStringLiteral(
"maxNumLabels" ), QStringLiteral(
"2000" ) ).toInt() );
1170 mObstacleSettings.
setIsObstacle( renderingElem.attribute( QStringLiteral(
"obstacle" ), QStringLiteral(
"1" ) ).toInt() );
1171 mObstacleSettings.
setFactor( renderingElem.attribute( QStringLiteral(
"obstacleFactor" ), QStringLiteral(
"1" ) ).toDouble() );
1173 zIndex = renderingElem.attribute( QStringLiteral(
"zIndex" ), QStringLiteral(
"0.0" ) ).toDouble();
1176 QDomElement ddElem = elem.firstChildElement( QStringLiteral(
"dd_properties" ) );
1177 if ( !ddElem.isNull() )
1179 mDataDefinedProperties.
readXml( ddElem, *sPropertyDefinitions() );
1184 mDataDefinedProperties.
clear();
1185 QDomElement ddElem = elem.firstChildElement( QStringLiteral(
"data-defined" ) );
1186 readOldDataDefinedPropertyMap(
nullptr, &ddElem );
1227 const QString calloutType = elem.attribute( QStringLiteral(
"calloutType" ) );
1228 if ( calloutType.isEmpty() )
1240 QDomElement textStyleElem = mFormat.
writeXml( doc, context );
1243 textStyleElem.setAttribute( QStringLiteral(
"fieldName" ),
fieldName );
1244 textStyleElem.setAttribute( QStringLiteral(
"isExpression" ),
isExpression );
1245 QDomElement replacementElem = doc.createElement( QStringLiteral(
"substitutions" ) );
1247 textStyleElem.appendChild( replacementElem );
1248 textStyleElem.setAttribute( QStringLiteral(
"useSubstitutions" ),
useSubstitutions );
1249 textStyleElem.setAttribute( QStringLiteral(
"legendString" ), mLegendString );
1252 QDomElement textFormatElem = doc.createElement( QStringLiteral(
"text-format" ) );
1253 textFormatElem.setAttribute( QStringLiteral(
"wrapChar" ),
wrapChar );
1254 textFormatElem.setAttribute( QStringLiteral(
"autoWrapLength" ),
autoWrapLength );
1256 textFormatElem.setAttribute( QStringLiteral(
"multilineAlign" ),
static_cast< unsigned int >(
multilineAlign ) );
1257 textFormatElem.setAttribute( QStringLiteral(
"addDirectionSymbol" ), mLineSettings.
addDirectionSymbol() );
1258 textFormatElem.setAttribute( QStringLiteral(
"leftDirectionSymbol" ), mLineSettings.
leftDirectionSymbol() );
1259 textFormatElem.setAttribute( QStringLiteral(
"rightDirectionSymbol" ), mLineSettings.
rightDirectionSymbol() );
1260 textFormatElem.setAttribute( QStringLiteral(
"reverseDirectionSymbol" ), mLineSettings.
reverseDirectionSymbol() );
1261 textFormatElem.setAttribute( QStringLiteral(
"placeDirectionSymbol" ),
static_cast< unsigned int >( mLineSettings.
directionSymbolPlacement() ) );
1262 textFormatElem.setAttribute( QStringLiteral(
"formatNumbers" ),
formatNumbers );
1263 textFormatElem.setAttribute( QStringLiteral(
"decimals" ),
decimals );
1264 textFormatElem.setAttribute( QStringLiteral(
"plussign" ),
plusSign );
1267 QDomElement placementElem = doc.createElement( QStringLiteral(
"placement" ) );
1268 placementElem.setAttribute( QStringLiteral(
"placement" ),
static_cast< int >(
placement ) );
1269 placementElem.setAttribute( QStringLiteral(
"polygonPlacementFlags" ),
static_cast< int >( mPolygonPlacementFlags ) );
1270 placementElem.setAttribute( QStringLiteral(
"placementFlags" ),
static_cast< unsigned int >( mLineSettings.
placementFlags() ) );
1271 placementElem.setAttribute( QStringLiteral(
"centroidWhole" ),
centroidWhole );
1272 placementElem.setAttribute( QStringLiteral(
"centroidInside" ),
centroidInside );
1274 placementElem.setAttribute( QStringLiteral(
"fitInPolygonOnly" ),
fitInPolygonOnly );
1275 placementElem.setAttribute( QStringLiteral(
"dist" ),
dist );
1278 placementElem.setAttribute( QStringLiteral(
"offsetType" ),
static_cast< unsigned int >(
offsetType ) );
1279 placementElem.setAttribute( QStringLiteral(
"quadOffset" ),
static_cast< unsigned int >(
quadOffset ) );
1280 placementElem.setAttribute( QStringLiteral(
"xOffset" ),
xOffset );
1281 placementElem.setAttribute( QStringLiteral(
"yOffset" ),
yOffset );
1284 placementElem.setAttribute( QStringLiteral(
"rotationAngle" ),
angleOffset );
1285 placementElem.setAttribute( QStringLiteral(
"preserveRotation" ),
preserveRotation );
1288 const QString rotationUnitString = QStringLiteral(
"Angle" ) +
qgsEnumValueToKey( mRotationUnit );
1289 placementElem.setAttribute( QStringLiteral(
"rotationUnit" ), rotationUnitString );
1293 placementElem.setAttribute( QStringLiteral(
"priority" ),
priority );
1294 placementElem.setAttribute( QStringLiteral(
"repeatDistance" ),
repeatDistance );
1297 placementElem.setAttribute( QStringLiteral(
"overrunDistance" ), mLineSettings.
overrunDistance() );
1300 placementElem.setAttribute( QStringLiteral(
"lineAnchorPercent" ), mLineSettings.
lineAnchorPercent() );
1301 placementElem.setAttribute( QStringLiteral(
"lineAnchorType" ),
static_cast< int >( mLineSettings.
anchorType() ) );
1302 placementElem.setAttribute( QStringLiteral(
"lineAnchorClipping" ),
static_cast< int >( mLineSettings.
anchorClipping() ) );
1305 placementElem.setAttribute( QStringLiteral(
"geometryGenerator" ),
geometryGenerator );
1312 placementElem.setAttribute( QStringLiteral(
"allowDegraded" ), mPlacementSettings.
allowDegradedPlacement() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1315 QDomElement renderingElem = doc.createElement( QStringLiteral(
"rendering" ) );
1316 renderingElem.setAttribute( QStringLiteral(
"drawLabels" ),
drawLabels );
1317 renderingElem.setAttribute( QStringLiteral(
"scaleVisibility" ),
scaleVisibility );
1318 renderingElem.setAttribute( QStringLiteral(
"scaleMin" ),
maximumScale );
1319 renderingElem.setAttribute( QStringLiteral(
"scaleMax" ),
minimumScale );
1320 renderingElem.setAttribute( QStringLiteral(
"fontLimitPixelSize" ),
fontLimitPixelSize );
1321 renderingElem.setAttribute( QStringLiteral(
"fontMinPixelSize" ),
fontMinPixelSize );
1322 renderingElem.setAttribute( QStringLiteral(
"fontMaxPixelSize" ),
fontMaxPixelSize );
1323 renderingElem.setAttribute( QStringLiteral(
"upsidedownLabels" ),
static_cast< unsigned int >(
upsidedownLabels ) );
1325 renderingElem.setAttribute( QStringLiteral(
"labelPerPart" ),
labelPerPart );
1326 renderingElem.setAttribute( QStringLiteral(
"mergeLines" ), mLineSettings.
mergeLines() );
1327 renderingElem.setAttribute( QStringLiteral(
"minFeatureSize" ), mThinningSettings.
minimumFeatureSize() );
1329 renderingElem.setAttribute( QStringLiteral(
"maxNumLabels" ), mThinningSettings.
maximumNumberLabels() );
1330 renderingElem.setAttribute( QStringLiteral(
"obstacle" ), mObstacleSettings.
isObstacle() );
1331 renderingElem.setAttribute( QStringLiteral(
"obstacleFactor" ), mObstacleSettings.
factor() );
1332 renderingElem.setAttribute( QStringLiteral(
"obstacleType" ),
static_cast< unsigned int >( mObstacleSettings.
type() ) );
1333 renderingElem.setAttribute( QStringLiteral(
"zIndex" ),
zIndex );
1334 renderingElem.setAttribute( QStringLiteral(
"unplacedVisibility" ),
static_cast< int >( mUnplacedVisibility ) );
1336 QDomElement ddElem = doc.createElement( QStringLiteral(
"dd_properties" ) );
1337 mDataDefinedProperties.
writeXml( ddElem, *sPropertyDefinitions() );
1339 QDomElement elem = doc.createElement( QStringLiteral(
"settings" ) );
1340 elem.appendChild( textStyleElem );
1341 elem.appendChild( textFormatElem );
1342 elem.appendChild( placementElem );
1343 elem.appendChild( renderingElem );
1344 elem.appendChild( ddElem );
1348 elem.setAttribute( QStringLiteral(
"calloutType" ), mCallout->type() );
1349 mCallout->saveProperties( doc, elem, context );
1366 QPixmap pixmap( size * devicePixelRatio );
1367 pixmap.fill( Qt::transparent );
1368 pixmap.setDevicePixelRatio( devicePixelRatio );
1370 painter.begin( &pixmap );
1372 painter.setRenderHint( QPainter::Antialiasing );
1374 const QRectF rect( 0, 0, size.width(), size.height() );
1377 painter.setPen( Qt::NoPen );
1379 if ( ( background1.lightnessF() < 0.7 ) )
1381 background1 = background1.darker( 125 );
1385 background1 = background1.lighter( 125 );
1388 QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1389 linearGrad.setColorAt( 0, background1 );
1390 linearGrad.setColorAt( 1, background2 );
1391 painter.setBrush( QBrush( linearGrad ) );
1392 if ( size.width() > 30 )
1394 painter.drawRoundedRect( rect, 6, 6 );
1399 painter.drawRect( rect );
1401 painter.setBrush( Qt::NoBrush );
1402 painter.setPen( Qt::NoPen );
1417 QWidget *activeWindow = QApplication::activeWindow();
1418 if ( QScreen *screen = activeWindow ? activeWindow->screen() : nullptr )
1438 ? fontSize * tempFormat.
buffer().
size() / 100
1443 double ytrans = 0.0;
1446 ? fontSize * tempFormat.
buffer().
size() / 100
1451 const QStringList text = QStringList() << ( previewText.isEmpty() ? settings.
legendString() : previewText );
1453 QRectF textRect = rect;
1454 textRect.setLeft( xtrans + padding );
1455 textRect.setWidth( rect.width() - xtrans - 2 * padding );
1457 if ( textRect.width() > 2000 )
1458 textRect.setWidth( 2000 - 2 * padding );
1460 const double bottom = textRect.height() / 2 + textHeight / 2;
1461 textRect.setTop( bottom - textHeight );
1462 textRect.setBottom( bottom );
1473 QRectF labelRect( textRect.left() + ( textRect.width() - textWidth ) / 2.0, textRect.top(), textWidth, textRect.height() );
1480 if ( size.width() > 30 )
1485 rect.width() - iconWidth * 3, rect.height() - iconWidth * 3,
1486 iconWidth * 2, iconWidth * 2 ), Qt::AlignRight | Qt::AlignBottom );
1490 painter.setBrush( Qt::NoBrush );
1492 if ( size.width() > 30 )
1494 painter.drawRoundedRect( rect, 6, 6 );
1499 painter.drawRect( rect );
1508 return mUnplacedVisibility;
1513 mUnplacedVisibility = visibility;
1518 return QgsPalLabeling::checkMinimumSizeMM(
ct, geom, minSize );
1521void QgsPalLayerSettings::calculateLabelSize(
const QFontMetricsF *fm,
const QString &text,
double &labelX,
double &labelY,
const QgsFeature *f,
QgsRenderContext *context,
double *rotatedLabelX,
double *rotatedLabelY,
QgsTextDocument *document,
QgsTextDocumentMetrics *documentMetrics, QRectF *outerBounds )
1528 QString textCopy( text );
1531 std::unique_ptr< QgsRenderContext > scopedRc;
1536 scopedRc->expressionContext().setFeature( *f );
1652 if ( wrapchr.isEmpty() )
1654 wrapchr = QStringLiteral(
"\n" );
1659 && ( !leftDirSymb.isEmpty() || !rightDirSymb.isEmpty() ) )
1661 QString dirSym = leftDirSymb;
1663 if ( fm->horizontalAdvance( rightDirSymb ) > fm->horizontalAdvance( dirSym ) )
1664 dirSym = rightDirSymb;
1666 switch ( placeDirSymb )
1669 textCopy.append( dirSym );
1674 textCopy.prepend( dirSym + QStringLiteral(
"\n" ) );
1679 double w = 0.0, h = 0.0, rw = 0.0, rh = 0.0;
1680 double labelHeight = fm->ascent() + fm->descent();
1694 const int lines = multiLineSplit.size();
1698 switch ( orientation )
1704 for (
const QString &line : std::as_const( multiLineSplit ) )
1706 w = std::max( w, fm->horizontalAdvance( line ) );
1713 double letterSpacing = mFormat.
scaledFont( *context ).letterSpacing();
1714 double labelWidth = fm->maxWidth();
1717 int maxLineLength = 0;
1718 for (
const QString &line : std::as_const( multiLineSplit ) )
1720 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
1722 h = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1728 double widthHorizontal = 0.0;
1729 for (
const QString &line : std::as_const( multiLineSplit ) )
1731 widthHorizontal = std::max( w, fm->horizontalAdvance( line ) );
1734 double widthVertical = 0.0;
1735 double letterSpacing = mFormat.
scaledFont( *context ).letterSpacing();
1736 double labelWidth = fm->maxWidth();
1739 double heightHorizontal = 0.0;
1742 double heightVertical = 0.0;
1743 int maxLineLength = 0;
1744 for (
const QString &line : std::as_const( multiLineSplit ) )
1746 maxLineLength = std::max( maxLineLength,
static_cast<int>( line.length() ) );
1748 heightVertical = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1750 w = widthHorizontal;
1751 rw = heightVertical;
1752 h = heightHorizontal;
1761 labelX = std::fabs( ptSize.
x() -
ptZero.
x() );
1762 labelY = std::fabs( ptSize.
y() -
ptZero.
y() );
1767 if ( rotatedLabelX && rotatedLabelY )
1769 *rotatedLabelX = rw * uPP;
1770 *rotatedLabelY = rh * uPP;
1774 if ( outerBounds && documentMetrics )
1778 *outerBounds = QRectF( outerBoundsPixels.left() * uPP,
1779 outerBoundsPixels.top() * uPP,
1780 outerBoundsPixels.width() * uPP,
1781 outerBoundsPixels.height() * uPP );
1796 bool isObstacle = mObstacleSettings.
isObstacle();
1804 return registerObstacleFeature( f, context, obstacleGeometry );
1819 if ( obstacleGeometry.
isNull() )
1832 dataDefinedValues.clear();
1849 if ( useScaleVisibility )
1862 maxScale = 1 / std::fabs( maxScale );
1881 minScale = 1 / std::fabs( minScale );
1890 QFont labelFont = mFormat.
font();
1898 QString units = exprVal.toString();
1899 if ( !units.isEmpty() )
1909 double fontSize = mFormat.
size();
1915 if ( fontSize <= 0.0 )
1922 if ( fontPixelSize < 1 )
1926 labelFont.setPixelSize( fontPixelSize );
1938 if ( fontMinPixel > labelFont.pixelSize() || labelFont.pixelSize() > fontMaxPixel )
1950 labelFont.setCapitalization( QFont::MixedCase );
1952 parseTextStyle( labelFont, fontunits, context );
1955 parseTextFormatting( context );
1956 parseTextBuffer( context );
1957 parseTextMask( context );
1958 parseShapeBackground( context );
1959 parseDropShadow( context );
2007 QString fcase = exprVal.toString().trimmed();
2008 QgsDebugMsgLevel( QStringLiteral(
"exprVal FontCase:%1" ).arg( fcase ), 4 );
2010 if ( !fcase.isEmpty() )
2012 if ( fcase.compare( QLatin1String(
"NoChange" ), Qt::CaseInsensitive ) == 0 )
2016 else if ( fcase.compare( QLatin1String(
"Upper" ), Qt::CaseInsensitive ) == 0 )
2020 else if ( fcase.compare( QLatin1String(
"Lower" ), Qt::CaseInsensitive ) == 0 )
2024 else if ( fcase.compare( QLatin1String(
"Capitalize" ), Qt::CaseInsensitive ) == 0 )
2028 else if ( fcase.compare( QLatin1String(
"Title" ), Qt::CaseInsensitive ) == 0 )
2032#if defined(HAS_KDE_QT5_SMALL_CAPS_FIX) || QT_VERSION >= QT_VERSION_CHECK(6, 3, 0)
2033 else if ( fcase.compare( QLatin1String(
"SmallCaps" ), Qt::CaseInsensitive ) == 0 )
2037 else if ( fcase.compare( QLatin1String(
"AllSmallCaps" ), Qt::CaseInsensitive ) == 0 )
2053 if ( evalFormatNumbers )
2057 if ( decimalPlaces <= 0 )
2063 QVariant textV( labelText );
2065 double d = textV.toDouble( &ok );
2068 QString numberFormat;
2069 if ( d > 0 && signPlus )
2071 numberFormat.append(
'+' );
2073 numberFormat.append(
"%1" );
2074 labelText = numberFormat.arg( QLocale().toString( d,
'f', decimalPlaces ) );
2079 std::unique_ptr<QFontMetricsF> labelFontMetrics(
new QFontMetricsF( labelFont ) );
2082 double rotatedLabelX;
2083 double rotatedLabelY;
2088 if (
format().allowHtmlFormatting() && !labelText.isEmpty() )
2092 calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight,
mCurFeat, &context, &rotatedLabelX, &rotatedLabelY, &doc, &documentMetrics, &outerBounds );
2096 calculateLabelSize( labelFontMetrics.get(), labelText, labelWidth, labelHeight,
mCurFeat, &context, &rotatedLabelX, &rotatedLabelY,
nullptr,
nullptr, &outerBounds );
2101 double maxcharanglein = 20.0;
2102 double maxcharangleout = -20.0;
2120 maxcharanglein = std::clamp(
static_cast< double >( maxcharanglePt.x() ), 20.0, 60.0 );
2121 maxcharangleout = std::clamp(
static_cast< double >( maxcharanglePt.y() ), 20.0, 95.0 );
2125 maxcharangleout = -( std::fabs( maxcharangleout ) );
2146 QString
str = exprVal.toString().trimmed();
2149 if ( !
str.isEmpty() )
2151 if (
str.compare( QLatin1String(
"Visible" ), Qt::CaseInsensitive ) == 0 )
2153 wholeCentroid =
false;
2155 else if (
str.compare( QLatin1String(
"Whole" ), Qt::CaseInsensitive ) == 0 )
2157 wholeCentroid =
true;
2171 std::unique_ptr<QgsGeometry> scopedClonedGeom;
2177 geom = simplifier.
simplify( geom );
2194 bool doClip =
false;
2195 if ( !centroidPoly || !wholeCentroid )
2201 Qgis::LabelPolygonPlacementFlags polygonPlacement = mPolygonPlacementFlags;
2207 if ( dataDefinedOutside.type() == QVariant::String )
2209 const QString value = dataDefinedOutside.toString().trimmed();
2210 if ( value.compare( QLatin1String(
"force" ), Qt::CaseInsensitive ) == 0 )
2216 else if ( value.compare( QLatin1String(
"yes" ), Qt::CaseInsensitive ) == 0 )
2221 else if ( value.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
2229 if ( dataDefinedOutside.toBool() )
2265 permissibleZone = geom;
2301 double minimumSize = 0.0;
2311 if ( !checkMinimumSizeMM( context, geom, featureThinningSettings.
minimumFeatureSize() ) )
2316 if ( !geos_geom_clone )
2345 bool layerDefinedRotation =
false;
2346 bool dataDefinedRotation =
false;
2347 double xPos = 0.0, yPos = 0.0;
2348 double angleInRadians = 0.0;
2349 double quadOffsetX = 0.0, quadOffsetY = 0.0;
2350 double offsetX = 0.0, offsetY = 0.0;
2362 bool ddFixedQuad =
false;
2371 int quadInt = exprVal.toInt( &ok );
2372 if ( ok && 0 <= quadInt && quadInt <= 8 )
2442 QString units = exprVal.toString().trimmed();
2443 if ( !units.isEmpty() )
2449 offUnit = decodedUnits;
2464 layerDefinedRotation =
true;
2465 angleInRadians = ( 360 -
angleOffset ) * M_PI / 180;
2477 const double rotation = exprVal.toDouble( &ok );
2480 dataDefinedRotation =
true;
2488 angleInRadians = ( 360 - rotationDegrees ) * M_PI / 180.0;
2493 bool hasDataDefinedPosition =
false;
2495 bool ddPosition =
false;
2507 bool ddXPos =
false, ddYPos =
false;
2508 xPos = xPosProperty.toDouble( &ddXPos );
2509 yPos = yPosProperty.toDouble( &ddYPos );
2510 if ( ddXPos && ddYPos )
2511 hasDataDefinedPosition =
true;
2522 if ( pointPosProperty.userType() == QMetaType::type(
"QgsReferencedGeometry" ) )
2527 if ( !referencedGeometryPoint.
isNull()
2531 else if ( pointPosProperty.userType() == QMetaType::type(
"QgsGeometry" ) )
2538 hasDataDefinedPosition =
true;
2549 if ( hasDataDefinedPosition )
2552 if ( layerDefinedRotation && !dataDefinedRotation )
2554 angleInRadians = 0.0;
2563 QString haliString = exprVal.toString();
2564 if ( haliString.compare( QLatin1String(
"Center" ), Qt::CaseInsensitive ) == 0 )
2566 xdiff -= labelWidth / 2.0;
2568 else if ( haliString.compare( QLatin1String(
"Right" ), Qt::CaseInsensitive ) == 0 )
2570 xdiff -= labelWidth;
2581 QString valiString = exprVal.toString();
2582 if ( valiString.compare( QLatin1String(
"Bottom" ), Qt::CaseInsensitive ) != 0 )
2584 if ( valiString.compare( QLatin1String(
"Top" ), Qt::CaseInsensitive ) == 0 )
2586 ydiff -= labelHeight;;
2590 double descentRatio = labelFontMetrics->descent() / labelFontMetrics->height();
2591 if ( valiString.compare( QLatin1String(
"Base" ), Qt::CaseInsensitive ) == 0 )
2593 ydiff -= labelHeight * descentRatio;
2597 double capHeightRatio = ( labelFontMetrics->boundingRect(
'H' ).height() + 1 + labelFontMetrics->descent() ) / labelFontMetrics->height();
2598 ydiff -= labelHeight * capHeightRatio;
2599 if ( valiString.compare( QLatin1String(
"Half" ), Qt::CaseInsensitive ) == 0 )
2601 ydiff += labelHeight * ( capHeightRatio - descentRatio ) / 2.0;
2609 if ( dataDefinedRotation )
2612 double xd = xdiff * std::cos( angleInRadians ) - ydiff * std::sin( angleInRadians );
2613 double yd = xdiff * std::sin( angleInRadians ) + ydiff * std::cos( angleInRadians );
2623 if (
const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( ddPoint.
constGet() ) )
2631 QgsMessageLog::logMessage( QObject::tr(
"Invalid data defined label position (%1, %2)" ).arg( xPos ).arg( yPos ), QObject::tr(
"Labeling" ) );
2632 hasDataDefinedPosition =
false;
2651 bool alwaysShow =
false;
2673 QString units = exprVal.toString().trimmed();
2674 if ( !units.isEmpty() )
2680 repeatUnits = decodedUnits;
2706 bool labelAll =
labelPerPart && !hasDataDefinedPosition;
2707 if ( !hasDataDefinedPosition )
2717 std::unique_ptr< QgsTextLabelFeature > labelFeature = std::make_unique< QgsTextLabelFeature>( feature.
id(), std::move( geos_geom_clone ), QSizeF( labelWidth, labelHeight ) );
2718 labelFeature->setAnchorPosition( anchorPosition );
2719 labelFeature->setFeature( feature );
2720 labelFeature->setSymbol( symbol );
2721 labelFeature->setDocument( doc, documentMetrics );
2723 labelFeature->setRotatedSize( QSizeF( rotatedLabelX, rotatedLabelY ) );
2726 labelFeature->setHasFixedPosition( hasDataDefinedPosition );
2727 labelFeature->setFixedPosition(
QgsPointXY( xPos, yPos ) );
2729 labelFeature->setHasFixedAngle( dataDefinedRotation || ( !hasDataDefinedPosition && !
qgsDoubleNear( angleInRadians, 0.0 ) ) );
2730 labelFeature->setFixedAngle( angleInRadians );
2731 labelFeature->setQuadOffset( QPointF( quadOffsetX, quadOffsetY ) );
2732 labelFeature->setPositionOffset(
QgsPointXY( offsetX, offsetY ) );
2734 labelFeature->setAlwaysShow( alwaysShow );
2735 labelFeature->setRepeatDistance( repeatDist );
2736 labelFeature->setLabelText( labelText );
2737 labelFeature->setPermissibleZone( permissibleZone );
2738 labelFeature->setOverrunDistance( overrunDistanceEval );
2739 labelFeature->setOverrunSmoothDistance( overrunSmoothDist );
2743 labelFeature->setLabelAllParts( labelAll );
2745 labelFeature->setMinimumSize( minimumSize );
2749 labelFeature->setSymbolSize( QSizeF( obstacleGeometry.
boundingBox().
width(),
2753 if ( outerBounds.left() != 0 || outerBounds.top() != 0 || !
qgsDoubleNear( outerBounds.width(), labelWidth ) || !
qgsDoubleNear( outerBounds.height(), labelHeight ) )
2755 labelFeature->setOuterBounds( outerBounds );
2760 double topMargin = std::max( 0.25 * labelFontMetrics->ascent(), 0.0 );
2761 double bottomMargin = 1.0 + labelFontMetrics->descent();
2762 QgsMargins vm( 0.0, topMargin, 0.0, bottomMargin );
2764 labelFeature->setVisualMargin( vm );
2767 QgsDebugMsgLevel( QStringLiteral(
"PAL font stored definedFont: %1, Style: %2" ).arg( labelFont.toString(), labelFont.styleName() ), 4 );
2768 labelFeature->setDefinedFont( labelFont );
2770 labelFeature->setMaximumCharacterAngleInside( std::clamp( maxcharanglein, 20.0, 60.0 ) * M_PI / 180 );
2771 labelFeature->setMaximumCharacterAngleOutside( std::clamp( maxcharangleout, -95.0, -20.0 ) * M_PI / 180 );
2795 double distance =
dist;
2809 QString units = exprVal.toString().trimmed();
2810 QgsDebugMsgLevel( QStringLiteral(
"exprVal DistanceUnits:%1" ).arg( units ), 4 );
2811 if ( !units.isEmpty() )
2817 distUnit = decodedUnits;
2831 distance = ( distance < 0 ? -1 : 1 ) * std::max( std::fabs( distance ), 1.0 );
2843 distance = std::max( distance, 2.0 );
2848 distance = std::max( distance, 2.0 );
2855 labelFeature->setDistLabel( d );
2860 labelFeature->setHasFixedQuadrant(
true );
2865 labelFeature->setPolygonPlacementFlags( polygonPlacement );
2874 labelFeature->setZIndex( z );
2884 double priorityD = exprVal.toDouble( &ok );
2887 priorityD = std::clamp( priorityD, 0.0, 10.0 );
2888 priorityD = 1 - priorityD / 10.0;
2889 labelFeature->setPriority( priorityD );
2902 labelFeature->setAllowDegradedPlacement( allowDegradedPlacement );
2911 const QString cleanedString = handlingString.trimmed();
2912 if ( cleanedString.compare( QLatin1String(
"prevent" ), Qt::CaseInsensitive ) == 0 )
2914 else if ( cleanedString.compare( QLatin1String(
"allowifneeded" ), Qt::CaseInsensitive ) == 0 )
2916 else if ( cleanedString.compare( QLatin1String(
"alwaysallow" ), Qt::CaseInsensitive ) == 0 )
2919 labelFeature->setOverlapHandling( overlapHandling );
2926 labelFeature->setObstacleSettings( os );
2929 if ( positionOrder.isEmpty() )
2930 positionOrder = *DEFAULT_PLACEMENT_ORDER();
2936 if ( !dataDefinedOrder.isEmpty() )
2941 labelFeature->setPredefinedPositionOrder( positionOrder );
2944 labelFeature->setDataDefinedValues( dataDefinedValues );
2946 return labelFeature;
2954 if ( !obstacleGeometry.
isNull() )
2956 geom = obstacleGeometry;
2971 if ( ls->numPoints() < 2 )
2977 std::unique_ptr<QgsGeometry> scopedClonedGeom;
2983 geom = simplifier.
simplify( geom );
2987 std::unique_ptr<QgsGeometry> scopedPreparedGeom;
2995 if ( !geos_geom_clone )
2999 std::unique_ptr< QgsLabelFeature > obstacleFeature = std::make_unique< QgsLabelFeature >( f.
id(), std::move( geos_geom_clone ), QSizeF( 0, 0 ) );
3000 obstacleFeature->setFeature( f );
3005 obstacleFeature->setObstacleSettings( os );
3008 return obstacleFeature;
3011bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
3015 if ( !mDataDefinedProperties.
isActive( p ) )
3019 exprVal = mDataDefinedProperties.
value( p, context );
3026 bool bol = exprVal.toBool();
3027 dataDefinedValues.insert( p, QVariant( bol ) );
3033 int size = exprVal.toInt( &ok );
3037 dataDefinedValues.insert( p, QVariant( size ) );
3045 int size = exprVal.toInt( &ok );
3047 if ( ok && size > 0 )
3049 dataDefinedValues.insert( p, QVariant( size ) );
3057 double size = exprVal.toDouble( &ok );
3061 dataDefinedValues.insert( p, QVariant( size ) );
3069 double size = exprVal.toDouble( &ok );
3071 if ( ok && size > 0.0 )
3073 dataDefinedValues.insert( p, QVariant( size ) );
3081 double rot = exprVal.toDouble( &ok );
3084 if ( rot < -180.0 && rot >= -360 )
3088 if ( rot > 180.0 && rot <= 360 )
3092 if ( rot >= -180 && rot <= 180 )
3094 dataDefinedValues.insert( p, QVariant( rot ) );
3103 int size = exprVal.toInt( &ok );
3104 if ( ok && size >= 0 && size <= 100 )
3106 dataDefinedValues.insert( p, QVariant( size ) );
3113 QString
str = exprVal.toString();
3115 dataDefinedValues.insert( p, QVariant(
str ) );
3120 QString unitstr = exprVal.toString().trimmed();
3122 if ( !unitstr.isEmpty() )
3131 QString colorstr = exprVal.toString().trimmed();
3134 if ( color.isValid() )
3136 dataDefinedValues.insert( p, QVariant( color ) );
3143 QString joinstr = exprVal.toString().trimmed();
3145 if ( !joinstr.isEmpty() )
3154 QString blendstr = exprVal.toString().trimmed();
3156 if ( !blendstr.isEmpty() )
3169 dataDefinedValues.insert( p, res );
3180 dataDefinedValues.insert( p, res );
3190void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
3203 QString ddFontFamily;
3210 QString family = exprVal.toString().trimmed();
3211 QgsDebugMsgLevel( QStringLiteral(
"exprVal Font family:%1" ).arg( family ), 4 );
3214 if ( labelFont.family() != family )
3220 ddFontFamily = family;
3227 QString ddFontStyle;
3233 QString fontstyle = exprVal.toString().trimmed();
3234 QgsDebugMsgLevel( QStringLiteral(
"exprVal Font style:%1" ).arg( fontstyle ), 4 );
3235 ddFontStyle = fontstyle;
3240 bool ddBold =
false;
3248 bool ddItalic =
false;
3258 QFont appFont = QApplication::font();
3259 bool newFontBuilt =
false;
3260 if ( ddBold || ddItalic )
3263 newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : labelFont.family() );
3264 newFontBuilt =
true;
3265 newFont.setBold( ddBold );
3266 newFont.setItalic( ddItalic );
3268 else if ( !ddFontStyle.isEmpty()
3269 && ddFontStyle.compare( QLatin1String(
"Ignore" ), Qt::CaseInsensitive ) != 0 )
3271 if ( !ddFontFamily.isEmpty() )
3275 mFontDB = std::make_unique< QFontDatabase >();
3277 QFont styledfont = mFontDB->font( ddFontFamily, ddFontStyle, appFont.pointSize() );
3278 if ( appFont != styledfont )
3280 newFont = styledfont;
3281 newFontBuilt =
true;
3288 else if ( !ddFontFamily.isEmpty() )
3290 if ( ddFontStyle.compare( QLatin1String(
"Ignore" ), Qt::CaseInsensitive ) != 0 )
3294 mFontDB = std::make_unique< QFontDatabase >();
3295 QFont styledfont = mFontDB->font( ddFontFamily, mFormat.
namedStyle(), appFont.pointSize() );
3296 if ( appFont != styledfont )
3298 newFont = styledfont;
3299 newFontBuilt =
true;
3304 newFont = QFont( ddFontFamily );
3305 newFontBuilt =
true;
3313 newFont.setPixelSize( labelFont.pixelSize() );
3314 newFont.setUnderline( labelFont.underline() );
3315 newFont.setStrikeOut( labelFont.strikeOut() );
3316 newFont.setWordSpacing( labelFont.wordSpacing() );
3317 newFont.setLetterSpacing( QFont::AbsoluteSpacing, labelFont.letterSpacing() );
3319 labelFont = newFont;
3323 double wordspace = labelFont.wordSpacing();
3332 double letterspace = labelFont.letterSpacing();
3345 labelFont.setStrikeOut( strikeout );
3360 labelFont.setUnderline( underline );
3386 drawBuffer = exprVal.toBool();
3399 double bufrSize = buffer.
size();
3402 bufrSize = exprVal.toDouble();
3406 double bufferOpacity = buffer.
opacity() * 100;
3409 bufferOpacity = exprVal.toDouble();
3412 drawBuffer = ( drawBuffer && bufrSize > 0.0 && bufferOpacity > 0 );
3442 bool maskEnabled = mask.
enabled();
3445 maskEnabled = exprVal.toBool();
3454 double bufrSize = mask.
size();
3457 bufrSize = exprVal.toDouble();
3461 double opacity = mask.
opacity() * 100;
3464 opacity = exprVal.toDouble();
3467 maskEnabled = ( maskEnabled && bufrSize > 0.0 && opacity > 0 );
3492 wrapchr = exprVal.toString();
3498 evalAutoWrapLength = exprVal.toInt();
3511 QString
str = exprVal.toString().trimmed();
3514 if ( !
str.isEmpty() )
3519 if (
str.compare( QLatin1String(
"Center" ), Qt::CaseInsensitive ) == 0 )
3523 else if (
str.compare( QLatin1String(
"Right" ), Qt::CaseInsensitive ) == 0 )
3527 else if (
str.compare( QLatin1String(
"Follow" ), Qt::CaseInsensitive ) == 0 )
3531 else if (
str.compare( QLatin1String(
"Justify" ), Qt::CaseInsensitive ) == 0 )
3548 QString
str = exprVal.toString().trimmed();
3549 if ( !
str.isEmpty() )
3558 drawDirSymb = exprVal.toBool();
3573 QString
str = exprVal.toString().trimmed();
3576 if ( !
str.isEmpty() )
3581 if (
str.compare( QLatin1String(
"Above" ), Qt::CaseInsensitive ) == 0 )
3585 else if (
str.compare( QLatin1String(
"Below" ), Qt::CaseInsensitive ) == 0 )
3607 bool drawShape = background.
enabled();
3610 drawShape = exprVal.toBool();
3619 double shapeOpacity = background.
opacity() * 100;
3622 shapeOpacity = 100.0 * exprVal.toDouble();
3625 drawShape = ( drawShape && shapeOpacity > 0 );
3641 QString skind = exprVal.toString().trimmed();
3642 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeKind:%1" ).arg( skind ), 4 );
3644 if ( !skind.isEmpty() )
3653 QString svgPath = background.
svgFile();
3660 QString svgfile = exprVal.toString().trimmed();
3661 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeSVGFile:%1" ).arg( svgfile ), 4 );
3676 QString stype = exprVal.toString().trimmed();
3677 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeSizeType:%1" ).arg( stype ), 4 );
3679 if ( !stype.isEmpty() )
3688 double ddShpSizeX = background.
size().width();
3691 ddShpSizeX = exprVal.toDouble();
3695 double ddShpSizeY = background.
size().height();
3698 ddShpSizeY = exprVal.toDouble();
3704 && ( svgPath.isEmpty()
3705 || ( !svgPath.isEmpty()
3707 && ddShpSizeX == 0.0 ) ) )
3715 && ddShpSizeX == 0.0 ) ) )
3722 && ( ddShpSizeX == 0.0 || ddShpSizeY == 0.0 ) )
3747 QString rotstr = exprVal.toString().trimmed();
3748 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeRotationType:%1" ).arg( rotstr ), 4 );
3750 if ( !rotstr.isEmpty() )
3801 bool drawShadow = shadow.
enabled();
3804 drawShadow = exprVal.toBool();
3813 double shadowOpacity = shadow.
opacity() * 100;
3816 shadowOpacity = exprVal.toDouble();
3823 shadowOffDist = exprVal.toDouble();
3830 shadowRad = exprVal.toDouble();
3833 drawShadow = ( drawShadow && shadowOpacity > 0 && !( shadowOffDist == 0.0 && shadowRad == 0.0 ) );
3850 QString
str = exprVal.toString().trimmed();
3853 if ( !
str.isEmpty() )
3888 switch ( layer->
type() )
3892 const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer );
3903 return !labeling->styles().empty();
3953QStringList
QgsPalLabeling::splitToLines(
const QString &text,
const QString &wrapCharacter,
const int autoWrapLength,
const bool useMaxLineLengthWhenAutoWrapping )
3955 QStringList multiLineSplit;
3956 if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String(
"\n" ) )
3959 const QStringList lines = text.split( wrapCharacter );
3960 for (
const QString &line : lines )
3962 multiLineSplit.append( line.split(
'\n' ) );
3967 multiLineSplit = text.split(
'\n' );
3971 if ( autoWrapLength != 0 )
3973 QStringList autoWrappedLines;
3974 autoWrappedLines.reserve( multiLineSplit.count() );
3975 for (
const QString &line : std::as_const( multiLineSplit ) )
3977 autoWrappedLines.append(
QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split(
'\n' ) );
3979 multiLineSplit = autoWrappedLines;
3981 return multiLineSplit;
3986 QStringList graphemes;
3987 QTextBoundaryFinder boundaryFinder( QTextBoundaryFinder::Grapheme, text );
3988 int currentBoundary = -1;
3989 int previousBoundary = 0;
3990 while ( ( currentBoundary = boundaryFinder.toNextBoundary() ) > 0 )
3992 graphemes << text.mid( previousBoundary, currentBoundary - previousBoundary );
3993 previousBoundary = currentBoundary;
4023 QgsDebugMsgLevel( QStringLiteral(
"Ignoring feature due to transformation exception" ), 4 );
4029 return std::isfinite( point.
x() ) && std::isfinite( point.
y() );
4033 cp->removeInvalidRings();
4035 else if (
QgsMultiSurface *ms = qgsgeometry_cast< QgsMultiSurface * >( geom.
get() ) )
4037 for (
int i = 0; i < ms->numGeometries(); ++i )
4039 if (
QgsCurvePolygon *cp = qgsgeometry_cast< QgsCurvePolygon * >( ms->geometryN( i ) ) )
4040 cp->removeInvalidRings();
4057 const bool mustClip = ( !clipGeometry.
isNull() &&
4061 bool mustClipExact =
false;
4085 QVector< QgsGeometry> parts;
4086 parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.
constGet() )->numGeometries() );
4095 parts.append( partGeom );
4103 if ( bufferGeom.
isNull() )
4112 if ( mustClipExact )
4147 double length = geom.
length();
4148 if ( length >= 0.0 )
4150 return ( length >= ( minSize * mapUnitsPerMM ) );
4155 double area = geom.
area();
4158 return ( std::sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
4166 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4169 bool changed =
false;
4175 format.
setColor( ddColor.value<QColor>() );
4200 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4262 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4265 bool changed =
false;
4313 buffer.
setColor( ddColor.value<QColor>() );
4340 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4342 if ( ddValues.isEmpty() )
4346 bool changed =
false;
4406 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4409 bool changed =
false;
4449 QSizeF size = background.
size();
4456 QSizeF size = background.
size();
4557 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4560 bool changed =
false;
4619 shadow.
setColor( ddColor.value<QColor>() );
4659 double cx = lp->
getX() + w / 2.0;
4660 double cy = lp->
getY() + h / 2.0;
4662 double rotation = xform->