33 #include <QApplication> 36 #include <QFontMetrics> 62 #include <QMessageBox> 107 : upsidedownLabels( Upright )
108 , mCurFeat( nullptr )
111 , extentGeom( nullptr )
112 , mFeaturesToLabel( 0 )
113 , mFeatsSendingToPal( 0 )
115 , expression( nullptr )
127 blendMode = QPainter::CompositionMode_SourceOver;
364 , expression( nullptr )
514 mDataDefinedNames = s.mDataDefinedNames;
559 return QColor( r, g, b, a );
573 if ( str.
compare(
"Point", Qt::CaseInsensitive ) == 0
575 if ( str.
compare(
"MapUnit", Qt::CaseInsensitive ) == 0
583 if ( str.
compare(
"Miter", Qt::CaseInsensitive ) == 0 )
return Qt::MiterJoin;
584 if ( str.
compare(
"Round", Qt::CaseInsensitive ) == 0 )
return Qt::RoundJoin;
585 return Qt::BevelJoin;
591 if ( !layer && !parentElem )
603 readDataDefinedProperty( layer, i.
key(), propertyMap );
605 else if ( parentElem )
624 if ( !layer && !parentElem )
633 QString newPropertyName =
"labeling/dataDefined/" + i.
value().first;
647 bool defaultVals = ( !active && !useExpr && expr.
isEmpty() && field.
isEmpty() );
653 values << ( active ?
"1" :
"0" );
654 values << ( useExpr ?
"1" :
"0" );
696 void QgsPalLayerSettings::readDataDefinedProperty(
QgsVectorLayer* layer,
700 QString newPropertyName =
"labeling/dataDefined/" + mDataDefinedNames.
value( p ).first;
704 if ( newPropertyField.
isValid() )
706 ddString = newPropertyField.
toString();
710 int oldIndx = mDataDefinedNames.
value( p ).second;
720 if ( !oldPropertyField.
isValid() )
727 int indx = oldPropertyField.
toInt( &conversionOk );
737 if ( !oldIndicesToNames.
isEmpty() )
739 ddString = oldIndicesToNames.
value( indx );
744 if ( indx < fields.
size() )
746 ddString = fields.
at( indx ).
name();
764 if ( oldIndx == 16 || oldIndx == 17 )
782 propertyMap.
insert( p, dd );
826 fontFamily = appFont.
family();
843 textFont =
QFont( fontFamily, fontSize, fontWeight, fontItalic );
886 else if ( bufSize != 0.0 )
1082 else if ( scalemn > 0 || scalemx > 0 )
1146 replacementElem.
save( stream, -1 );
1289 fontFamily = appFont.
family();
1294 if ( !textStyleElem.
hasAttribute(
"fontSizeMapUnitScale" ) )
1304 int fontWeight = textStyleElem.
attribute(
"fontWeight" ).
toInt();
1305 bool fontItalic = textStyleElem.
attribute(
"fontItalic" ).
toInt();
1306 textFont =
QFont( fontFamily, fontSize, fontWeight, fontItalic );
1348 else if ( bufSize != 0.0 )
1360 if ( !textBufferElem.
hasAttribute(
"bufferSizeMapUnitScale" ) )
1386 if ( !backgroundElem.
hasAttribute(
"shapeSizeMapUnitScale" ) )
1401 if ( !backgroundElem.
hasAttribute(
"shapeOffsetMapUnitScale" ) )
1414 if ( !backgroundElem.
hasAttribute(
"shapeRadiiMapUnitScale" ) )
1428 if ( !backgroundElem.
hasAttribute(
"shapeBorderWidthMapUnitScale" ) )
1450 if ( !shadowElem.
hasAttribute(
"shadowOffsetMapUnitScale" ) )
1463 if ( !shadowElem.
hasAttribute(
"shadowRadiusMapUnitScale" ) )
1492 if ( !placementElem.
hasAttribute(
"distMapUnitScale" ) )
1507 if ( !placementElem.
hasAttribute(
"labelOffsetMapUnitScale" ) )
1524 if ( !placementElem.
hasAttribute(
"repeatDistanceMapUnitScale" ) )
1537 scaleMin = renderingElem.attribute(
"scaleMin",
"0" ).toInt();
1538 scaleMax = renderingElem.attribute(
"scaleMax",
"0" ).toInt();
1539 scaleVisibility = renderingElem.attribute(
"scaleVisibility" ).toInt();
1542 fontMinPixelSize = renderingElem.attribute(
"fontMinPixelSize",
"0" ).toInt();
1543 fontMaxPixelSize = renderingElem.attribute(
"fontMaxPixelSize",
"10000" ).toInt();
1544 displayAll = renderingElem.attribute(
"displayAll",
"0" ).toInt();
1547 labelPerPart = renderingElem.attribute(
"labelPerPart" ).toInt();
1548 mergeLines = renderingElem.attribute(
"mergeLines" ).toInt();
1549 minFeatureSize = renderingElem.attribute(
"minFeatureSize" ).toDouble();
1550 limitNumLabels = renderingElem.attribute(
"limitNumLabels",
"0" ).toInt();
1551 maxNumLabels = renderingElem.attribute(
"maxNumLabels",
"2000" ).toInt();
1552 obstacle = renderingElem.attribute(
"obstacle",
"1" ).toInt();
1553 obstacleFactor = renderingElem.attribute(
"obstacleFactor",
"1" ).toDouble();
1555 zIndex = renderingElem.attribute(
"zIndex",
"0.0" ).toDouble();
1728 bool active,
bool useExpr,
const QString& expr,
const QString& field )
1730 bool defaultVals = ( !active && !useExpr && expr.
isEmpty() && field.
isEmpty() );
1744 else if ( !defaultVals )
1756 delete( it.
value() );
1778 newValue = values.
join(
"~~" );
1803 return it.
value()->toMap();
1820 scopedEc->setFeature( f );
1821 scopedEc->setFields( fields );
1863 else if ( !useExpression && !field.
isEmpty() )
1911 bool isActive =
false;
1916 isActive = it.
value()->isActive();
1927 bool useExpression =
false;
1931 useExpression = it.
value()->useExpression();
1934 return useExpression;
1955 scopedRc->expressionContext().setFeature( *f );
2018 double size = exprVal.
toDouble( &ok );
2030 addDirSymb = exprVal.
toBool();
2055 int enmint = exprVal.
toInt( &ok );
2076 if ( fm->
width( rightDirSymb ) > fm->
width( dirSym ) )
2077 dirSym = rightDirSymb;
2089 double w = 0.0, h = 0.0;
2091 int lines = multiLineSplit.
size();
2095 h += fm->
height() +
static_cast< double >(( lines - 1 ) * labelHeight * multilineH );
2098 for (
int i = 0; i < lines; ++i )
2100 double width = fm->
width( multiLineSplit.
at( i ) );
2110 labelX = qAbs( ptSize.
x() -
ptZero.
x() );
2111 labelY = qAbs( ptSize.
y() -
ptZero.
y() );
2122 Q_ASSERT( labelFeature );
2131 isObstacle = exprVal.
toBool();
2138 registerObstacleFeature( f, context, labelFeature, obstacleGeometry );
2146 dataDefinedValues.
clear();
2152 showLabel &= exprVal.
toBool();
2165 useScaleVisibility = exprVal.
toBool();
2168 if ( useScaleVisibility )
2176 double mins = exprVal.
toDouble( &conversionOk );
2186 minScale = 1 / qAbs( minScale );
2200 double maxs = exprVal.
toDouble( &conversionOk );
2210 maxScale = 1 / qAbs( maxScale );
2240 double size = exprVal.
toDouble( &ok );
2246 if ( fontSize <= 0.0 )
2253 if ( fontPixelSize < 1 )
2268 useFontLimitPixelSize = exprVal.
toBool();
2271 if ( useFontLimitPixelSize )
2277 int sizeInt = exprVal.
toInt( &ok );
2281 fontMinPixel = sizeInt;
2289 int sizeInt = exprVal.
toInt( &ok );
2293 fontMaxPixel = sizeInt;
2310 parseTextStyle( labelFont, fontunits, context );
2311 parseTextFormatting( context );
2312 parseTextBuffer( context );
2313 parseShapeBackground( context );
2314 parseDropShadow( context );
2364 if ( fcase.
compare(
"NoChange", Qt::CaseInsensitive ) == 0 )
2368 else if ( fcase.
compare(
"Upper", Qt::CaseInsensitive ) == 0 )
2372 else if ( fcase.
compare(
"Lower", Qt::CaseInsensitive ) == 0 )
2376 else if ( fcase.
compare(
"Capitalize", Qt::CaseInsensitive ) == 0 )
2388 formatnum = exprVal.
toBool();
2400 int dInt = exprVal.
toInt( &ok );
2402 if ( ok && dInt > 0 )
2404 decimalPlaces = dInt;
2412 signPlus = exprVal.
toBool();
2422 if ( d > 0 && signPlus )
2424 numberFormat.
append(
'+' );
2426 numberFormat.
append(
"%1" );
2427 labelText = numberFormat.
arg( d, 0,
'f', decimalPlaces );
2433 double labelX, labelY;
2439 double maxcharanglein = 20.0;
2440 double maxcharangleout = -20.0;
2456 maxcharanglein = qBound( 20.0, static_cast< double >( maxcharanglePt.
x() ), 60.0 );
2457 maxcharangleout = qBound( 20.0, static_cast< double >( maxcharanglePt.
y() ), 95.0 );
2461 maxcharangleout = -( qAbs( maxcharangleout ) );
2473 if ( str.
compare(
"Visible", Qt::CaseInsensitive ) == 0 )
2475 wholeCentroid =
false;
2477 else if ( str.
compare(
"Whole", Qt::CaseInsensitive ) == 0 )
2479 wholeCentroid =
true;
2502 scopedClonedGeom.
reset( g );
2517 bool doClip =
false;
2518 if ( !centroidPoly || !wholeCentroid )
2528 permissibleZone = *geom;
2536 permissibleZone = *preparedZone;
2537 delete preparedZone;
2548 geom = boundaryGeom;
2549 scopedClonedGeom.
reset( boundaryGeom );
2552 const GEOSGeometry* geos_geom =
nullptr;
2559 if ( !scopedPreparedGeom.
data() )
2561 preparedGeom = scopedPreparedGeom.
data();
2562 geos_geom = scopedPreparedGeom.
data()->asGeos();
2566 geos_geom = geom->
asGeos();
2568 const GEOSGeometry* geosObstacleGeom =
nullptr;
2575 obstacleGeometry = scopedObstacleGeom.
data();
2577 if ( obstacleGeometry )
2579 geosObstacleGeom = obstacleGeometry->
asGeos();
2615 GEOSGeometry* geosObstacleGeomClone =
nullptr;
2616 if ( geosObstacleGeom )
2623 bool dataDefinedPosition =
false;
2624 bool layerDefinedRotation =
false;
2625 bool dataDefinedRotation =
false;
2626 double xPos = 0.0, yPos = 0.0,
angle = 0.0;
2627 bool ddXPos =
false, ddYPos =
false;
2628 double quadOffsetX = 0.0, quadOffsetY = 0.0;
2629 double offsetX = 0.0, offsetY = 0.0;
2632 bool ddFixedQuad =
false;
2637 int quadInt = exprVal.
toInt( &ok );
2639 if ( ok && 0 <= quadInt && quadInt <= 8 )
2720 if ( !offinmapunits )
2722 offsetX *= mapUntsPerMM;
2728 if ( !offinmapunits )
2730 offsetY *= mapUntsPerMM;
2738 layerDefinedRotation =
true;
2747 double rotD = exprVal.
toDouble( &ok );
2751 dataDefinedRotation =
true;
2762 xPos = exprVal.
toDouble( &ddXPos );
2769 yPos = exprVal.
toDouble( &ddYPos );
2772 if ( ddXPos && ddYPos )
2774 dataDefinedPosition =
true;
2776 if ( layerDefinedRotation && !dataDefinedRotation )
2790 if ( haliString.
compare(
"Center", Qt::CaseInsensitive ) == 0 )
2792 xdiff -= labelX / 2.0;
2794 else if ( haliString.
compare(
"Right", Qt::CaseInsensitive ) == 0 )
2806 if ( valiString.
compare(
"Bottom", Qt::CaseInsensitive ) != 0 )
2808 if ( valiString.
compare(
"Top", Qt::CaseInsensitive ) == 0 )
2814 double descentRatio = labelFontMetrics->descent() / labelFontMetrics->height();
2815 if ( valiString.
compare(
"Base", Qt::CaseInsensitive ) == 0 )
2817 ydiff -= labelY * descentRatio;
2821 double capHeightRatio = ( labelFontMetrics->boundingRect(
'H' ).height() + 1 + labelFontMetrics->descent() ) / labelFontMetrics->height();
2822 ydiff -= labelY * capHeightRatio;
2823 if ( valiString.
compare(
"Half", Qt::CaseInsensitive ) == 0 )
2825 ydiff += labelY * ( capHeightRatio - descentRatio ) / 2.0;
2832 if ( dataDefinedRotation )
2835 double xd = xdiff * cos(
angle ) - ydiff * sin(
angle );
2836 double yd = xdiff * sin(
angle ) + ydiff * cos(
angle );
2866 bool alwaysShow =
false;
2869 alwaysShow = exprVal.
toBool();
2878 double distD = exprVal.
toDouble( &ok );
2899 if ( !repeatdistinmapunit )
2901 repeatDist *= mapUntsPerMM;
2911 ( *labelFeature )->setFixedPosition(
QgsPoint( xPos, yPos ) );
2913 ( *labelFeature )->setHasFixedAngle( dataDefinedRotation || ( !dataDefinedPosition && !
qgsDoubleNear(
angle, 0.0 ) ) );
2914 ( *labelFeature )->setFixedAngle(
angle );
2915 ( *labelFeature )->setQuadOffset(
QPointF( quadOffsetX, quadOffsetY ) );
2916 ( *labelFeature )->setPositionOffset(
QgsPoint( offsetX, offsetY ) );
2917 ( *labelFeature )->setOffsetType(
offsetType );
2918 ( *labelFeature )->setAlwaysShow( alwaysShow );
2919 ( *labelFeature )->setRepeatDistance( repeatDist );
2920 ( *labelFeature )->setLabelText( labelText );
2921 ( *labelFeature )->setPermissibleZone( permissibleZone );
2922 if ( geosObstacleGeomClone )
2924 ( *labelFeature )->setObstacleGeometry( geosObstacleGeomClone );
2936 double topMargin = qMax( 0.25 * labelFontMetrics->ascent(), 0.0 );
2937 double bottomMargin = 1.0 + labelFontMetrics->descent();
2940 ( *labelFeature )->setVisualMargin( vm );
2955 double distance =
dist;
2959 double distD = exprVal.
toDouble( &ok );
2978 if ( distinmapunit )
2991 distance = qMax( distance, 1.0 );
2997 ( *labelFeature )->setDistLabel( d );
3002 ( *labelFeature )->setHasFixedQuadrant(
true );
3010 double zIndexD = exprVal.
toDouble( &ok );
3016 ( *labelFeature )->setZIndex( z );
3022 double priorityD = exprVal.
toDouble( &ok );
3025 priorityD = qBound( 0.0, priorityD, 10.0 );
3026 priorityD = 1 - priorityD / 10.0;
3027 ( *labelFeature )->setPriority( priorityD );
3031 ( *labelFeature )->setIsObstacle( isObstacle );
3037 double factorD = exprVal.
toDouble( &ok );
3040 factorD = qBound( 0.0, factorD, 10.0 );
3041 factorD = factorD / 5.0 + 0.0001;
3042 featObstacleFactor = factorD;
3045 ( *labelFeature )->setObstacleFactor( featObstacleFactor );
3048 if ( positionOrder.
isEmpty() )
3049 positionOrder = QgsPalLayerSettings::DEFAULT_PLACEMENT_ORDER;
3056 ( *labelFeature )->setPredefinedPositionOrder( positionOrder );
3067 if ( obstacleGeometry )
3069 geom = obstacleGeometry;
3093 scopedClonedGeom.
reset( g );
3101 const GEOSGeometry* geos_geom =
nullptr;
3107 if ( !scopedPreparedGeom.
data() )
3109 geos_geom = scopedPreparedGeom.
data()->asGeos();
3113 geos_geom = geom->
asGeos();
3119 GEOSGeometry* geos_geom_clone;
3128 bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
3142 bool bol = exprVal.
toBool();
3150 int size = exprVal.
toInt( &ok );
3163 int size = exprVal.
toInt( &ok );
3166 if ( ok && size > 0 )
3176 double size = exprVal.
toDouble( &ok );
3189 double size = exprVal.
toDouble( &ok );
3192 if ( ok && size > 0.0 )
3202 double rot = exprVal.
toDouble( &ok );
3206 if ( rot < -180.0 && rot >= -360 )
3210 if ( rot > 180.0 && rot <= 360 )
3214 if ( rot >= -180 && rot <= 180 )
3222 case DDTransparency:
3225 int size = exprVal.
toInt( &ok );
3227 if ( ok && size >= 0 && size <= 100 )
3260 if ( color.isValid() )
3308 void QgsPalLayerSettings::parseTextStyle(
QFont& labelFont,
3327 if ( labelFont.
family() != family )
3333 ddFontFamily = family;
3344 ddFontStyle = fontstyle;
3348 bool ddBold =
false;
3351 bool bold = exprVal.
toBool();
3357 bool ddItalic =
false;
3360 bool italic = exprVal.
toBool();
3369 bool newFontBuilt =
false;
3370 if ( ddBold || ddItalic )
3374 newFontBuilt =
true;
3378 else if ( !ddFontStyle.
isEmpty()
3379 && ddFontStyle.
compare(
"Ignore", Qt::CaseInsensitive ) != 0 )
3381 if ( !ddFontFamily.
isEmpty() )
3385 if ( appFont != styledfont )
3387 newFont = styledfont;
3388 newFontBuilt =
true;
3395 else if ( !ddFontFamily.
isEmpty() )
3397 if ( ddFontStyle.
compare(
"Ignore", Qt::CaseInsensitive ) != 0 )
3401 if ( appFont != styledfont )
3403 newFont = styledfont;
3404 newFontBuilt =
true;
3409 newFont =
QFont( ddFontFamily );
3410 newFontBuilt =
true;
3424 labelFont = newFont;
3432 double wspacing = exprVal.
toDouble( &ok );
3436 wordspace = wspacing;
3446 double lspacing = exprVal.
toDouble( &ok );
3450 letterspace = lspacing;
3458 bool strikeout = exprVal.
toBool();
3466 bool underline = exprVal.
toBool();
3492 drawBuffer = exprVal.
toBool();
3511 bufTransp = exprVal.
toInt();
3514 drawBuffer = ( drawBuffer && bufrSize > 0.0 && bufTransp < 100 );
3562 if ( str.
compare(
"Center", Qt::CaseInsensitive ) == 0 )
3566 else if ( str.
compare(
"Right", Qt::CaseInsensitive ) == 0 )
3570 else if ( str.
compare(
"Follow", Qt::CaseInsensitive ) == 0 )
3582 drawDirSymb = exprVal.
toBool();
3604 if ( str.
compare(
"Above", Qt::CaseInsensitive ) == 0 )
3608 else if ( str.
compare(
"Below", Qt::CaseInsensitive ) == 0 )
3623 void QgsPalLayerSettings::parseShapeBackground(
QgsRenderContext &context )
3631 drawShape = exprVal.
toBool();
3643 shapeTransp = exprVal.
toInt();
3646 drawShape = ( drawShape && shapeTransp < 100 );
3667 if ( skind.
compare(
"Square", Qt::CaseInsensitive ) == 0 )
3671 else if ( skind.
compare(
"Ellipse", Qt::CaseInsensitive ) == 0 )
3675 else if ( skind.
compare(
"Circle", Qt::CaseInsensitive ) == 0 )
3679 else if ( skind.
compare(
"SVG", Qt::CaseInsensitive ) == 0 )
3683 shapeKind = shpkind;
3712 if ( stype.
compare(
"Fixed", Qt::CaseInsensitive ) == 0 )
3716 shpSizeType = sizType;
3741 && ddShpSizeX == 0.0 ) ) )
3747 && ( ddShpSizeX == 0.0 || ddShpSizeY == 0.0 ) )
3777 if ( rotstr.
compare(
"Offset", Qt::CaseInsensitive ) == 0 )
3781 else if ( rotstr.
compare(
"Fixed", Qt::CaseInsensitive ) == 0 )
3832 drawShadow = exprVal.
toBool();
3844 shadowTransp = exprVal.
toInt();
3851 shadowOffDist = exprVal.
toDouble();
3861 drawShadow = ( drawShadow && shadowTransp < 100 && !( shadowOffDist == 0.0 && shadowRad == 0.0 ) );
3883 if ( str.
compare(
"Text", Qt::CaseInsensitive ) == 0 )
3887 else if ( str.
compare(
"Buffer", Qt::CaseInsensitive ) == 0 )
3891 else if ( str.
compare(
"Background", Qt::CaseInsensitive ) == 0 )