47#include <QRegularExpression>
58 if ( style.contains( QStringLiteral(
"sources" ) ) )
60 parseSources( style.value( QStringLiteral(
"sources" ) ).toMap(), context );
63 if ( style.contains( QStringLiteral(
"layers" ) ) )
65 parseLayers( style.value( QStringLiteral(
"layers" ) ).toList(), context );
69 mError = QObject::tr(
"Could not find layers list in JSON" );
82 qDeleteAll( mSources );
87 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
90 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
91 context = tmpContext.get();
94 QList<QgsVectorTileBasicRendererStyle> rendererStyles;
95 QList<QgsVectorTileBasicLabelingStyle> labelingStyles;
98 bool hasRendererBackgroundStyle =
false;
100 for (
const QVariant &layer : layers )
102 const QVariantMap jsonLayer = layer.toMap();
104 const QString layerType = jsonLayer.value( QStringLiteral(
"type" ) ).toString();
105 if ( layerType == QLatin1String(
"background" ) )
107 hasRendererBackgroundStyle =
parseFillLayer( jsonLayer, rendererBackgroundStyle, *context,
true );
108 if ( hasRendererBackgroundStyle )
118 const QString styleId = jsonLayer.value( QStringLiteral(
"id" ) ).toString();
121 if ( layerType.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
124 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
125 if ( jsonPaint.contains( QStringLiteral(
"raster-opacity" ) ) )
127 const QVariant jsonRasterOpacity = jsonPaint.value( QStringLiteral(
"raster-opacity" ) );
128 double defaultOpacity = 1;
132 mRasterSubLayers.append( raster );
136 const QString layerName = jsonLayer.value( QStringLiteral(
"source-layer" ) ).toString();
138 const int minZoom = jsonLayer.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"-1" ) ).toInt();
139 const int maxZoom = jsonLayer.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"-1" ) ).toInt();
141 const bool enabled = jsonLayer.value( QStringLiteral(
"visibility" ) ).toString() != QLatin1String(
"none" );
143 QString filterExpression;
144 if ( jsonLayer.contains( QStringLiteral(
"filter" ) ) )
146 filterExpression =
parseExpression( jsonLayer.value( QStringLiteral(
"filter" ) ).toList(), *context );
152 bool hasRendererStyle =
false;
153 bool hasLabelingStyle =
false;
154 if ( layerType == QLatin1String(
"fill" ) )
156 hasRendererStyle =
parseFillLayer( jsonLayer, rendererStyle, *context );
158 else if ( layerType == QLatin1String(
"line" ) )
160 hasRendererStyle =
parseLineLayer( jsonLayer, rendererStyle, *context );
162 else if ( layerType == QLatin1String(
"circle" ) )
166 else if ( layerType == QLatin1String(
"symbol" ) )
168 parseSymbolLayer( jsonLayer, rendererStyle, hasRendererStyle, labelingStyle, hasLabelingStyle, *context );
172 mWarnings << QObject::tr(
"%1: Skipping unknown layer type %2" ).arg( context->
layerId(), layerType );
177 if ( hasRendererStyle )
185 rendererStyles.append( rendererStyle );
188 if ( hasLabelingStyle )
196 labelingStyles.append( labelingStyle );
199 mWarnings.append( context->
warnings() );
203 if ( hasRendererBackgroundStyle )
204 rendererStyles.prepend( rendererBackgroundStyle );
206 mRenderer = std::make_unique< QgsVectorTileBasicRenderer >();
208 renderer->setStyles( rendererStyles );
210 mLabeling = std::make_unique< QgsVectorTileBasicLabeling >();
212 labeling->setStyles( labelingStyles );
217 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
222 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsFillSymbol >() );
226 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) ) )
228 const QVariant jsonFillColor = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) );
229 switch ( jsonFillColor.type() )
236 case QVariant::StringList:
240 case QVariant::String:
241 fillColor =
parseColor( jsonFillColor.toString(), context );
254 fillColor = QColor( 0, 0, 0 );
257 QColor fillOutlineColor;
258 if ( !isBackgroundStyle )
260 if ( !jsonPaint.contains( QStringLiteral(
"fill-outline-color" ) ) )
262 if ( fillColor.isValid() )
263 fillOutlineColor = fillColor;
271 const QVariant jsonFillOutlineColor = jsonPaint.value( QStringLiteral(
"fill-outline-color" ) );
272 switch ( jsonFillOutlineColor.type() )
279 case QVariant::StringList:
283 case QVariant::String:
284 fillOutlineColor =
parseColor( jsonFillOutlineColor.toString(), context );
294 double fillOpacity = -1.0;
295 double rasterOpacity = -1.0;
296 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) ) )
298 const QVariant jsonFillOpacity = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) );
299 switch ( jsonFillOpacity.type() )
302 case QVariant::LongLong:
303 case QVariant::Double:
304 fillOpacity = jsonFillOpacity.toDouble();
305 rasterOpacity = fillOpacity;
322 case QVariant::StringList:
342 QPointF fillTranslate;
343 if ( jsonPaint.contains( QStringLiteral(
"fill-translate" ) ) )
345 const QVariant jsonFillTranslate = jsonPaint.value( QStringLiteral(
"fill-translate" ) );
346 switch ( jsonFillTranslate.type() )
354 case QVariant::StringList:
366 Q_ASSERT( fillSymbol );
369 symbol->setOutputUnit( context.
targetUnit() );
372 if ( !fillTranslate.isNull() )
378 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) ) )
382 const QVariant fillPatternJson = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) );
385 fillColor = QColor();
386 fillOutlineColor = QColor();
393 QString spriteProperty, spriteSizeProperty;
394 const QString sprite =
retrieveSpriteAsBase64( fillPatternJson, context, spriteSize, spriteProperty, spriteSizeProperty );
395 if ( !sprite.isEmpty() )
400 rasterFill->
setWidth( spriteSize.width() );
404 if ( rasterOpacity >= 0 )
409 if ( !spriteProperty.isEmpty() )
416 symbol->appendSymbolLayer( rasterFill );
422 if ( fillOpacity != -1 )
424 symbol->setOpacity( fillOpacity );
427 if ( fillOutlineColor.isValid() )
436 if ( fillColor.isValid() )
452 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
454 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
459 QString rasterLineSprite;
461 const QVariantMap jsonPaint = jsonLayer.
value( QStringLiteral(
"paint" ) ).toMap();
462 if ( jsonPaint.contains( QStringLiteral(
"line-pattern" ) ) )
464 const QVariant jsonLinePattern = jsonPaint.value( QStringLiteral(
"line-pattern" ) );
465 switch ( jsonLinePattern.type() )
468 case QVariant::String:
471 QString spriteProperty, spriteSizeProperty;
472 rasterLineSprite =
retrieveSpriteAsBase64( jsonLinePattern, context, spriteSize, spriteProperty, spriteSizeProperty );
478 case QVariant::StringList:
483 if ( rasterLineSprite.isEmpty() )
486 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
493 if ( jsonPaint.contains( QStringLiteral(
"line-color" ) ) )
495 const QVariant jsonLineColor = jsonPaint.value( QStringLiteral(
"line-color" ) );
496 switch ( jsonLineColor.type() )
504 case QVariant::StringList:
509 case QVariant::String:
510 lineColor =
parseColor( jsonLineColor.toString(), context );
521 lineColor = QColor( 0, 0, 0 );
525 double lineWidth = 1.0;
527 if ( jsonPaint.contains( QStringLiteral(
"line-width" ) ) )
529 const QVariant jsonLineWidth = jsonPaint.
value( QStringLiteral(
"line-width" ) );
530 switch ( jsonLineWidth.type() )
533 case QVariant::LongLong:
534 case QVariant::Double:
545 case QVariant::StringList:
556 double lineOffset = 0.0;
557 if ( jsonPaint.contains( QStringLiteral(
"line-offset" ) ) )
559 const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral(
"line-offset" ) );
560 switch ( jsonLineOffset.type() )
563 case QVariant::LongLong:
564 case QVariant::Double:
574 case QVariant::StringList:
584 double lineOpacity = -1.0;
585 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
587 const QVariant jsonLineOpacity = jsonPaint.value( QStringLiteral(
"line-opacity" ) );
588 switch ( jsonLineOpacity.type() )
591 case QVariant::LongLong:
592 case QVariant::Double:
593 lineOpacity = jsonLineOpacity.toDouble();
599 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
608 case QVariant::StringList:
611 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
625 QVector< double > dashVector;
626 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
628 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
629 switch ( jsonLineDashArray.type() )
633 QString arrayExpression;
636 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
637 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
642 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
646 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
647 for (
const QVariant &v : dashSource )
649 dashVector << v.toDouble() * lineWidth;
655 case QVariant::StringList:
657 const QVariantList dashSource = jsonLineDashArray.toList();
659 QVector< double > rawDashVectorSizes;
660 rawDashVectorSizes.reserve( dashSource.size() );
661 for (
const QVariant &v : dashSource )
663 rawDashVectorSizes << v.toDouble();
667 if ( rawDashVectorSizes.size() == 1 )
670 rawDashVectorSizes.clear();
672 else if ( rawDashVectorSizes.size() % 2 == 1 )
676 rawDashVectorSizes[0] = rawDashVectorSizes[0] + rawDashVectorSizes[rawDashVectorSizes.size() - 1];
677 rawDashVectorSizes.resize( rawDashVectorSizes.size() - 1 );
680 if ( !rawDashVectorSizes.isEmpty() && ( !lineWidthProperty.
asExpression().isEmpty() ) )
682 QStringList dashArrayStringParts;
683 dashArrayStringParts.reserve( rawDashVectorSizes.size() );
684 for (
double v : std::as_const( rawDashVectorSizes ) )
689 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
690 .arg( dashArrayStringParts.join(
',' ),
696 for (
double v : std::as_const( rawDashVectorSizes ) )
698 dashVector << v *lineWidth;
710 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
711 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
712 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
714 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
715 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
717 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
719 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
721 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
725 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
726 symbol->setOutputUnit( context.
targetUnit() );
728 if ( !rasterLineSprite.isEmpty() )
738 if ( lineOpacity != -1 )
740 symbol->setOpacity( lineOpacity );
742 if ( lineWidth != -1 )
746 symbol->changeSymbolLayer( 0, lineSymbol );
751 Q_ASSERT( lineSymbol );
761 if ( lineOpacity != -1 )
763 symbol->setOpacity( lineOpacity );
765 if ( lineColor.isValid() )
769 if ( lineWidth != -1 )
773 if ( !dashVector.empty() )
787 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
789 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
793 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
797 QColor circleFillColor;
798 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
800 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
801 switch ( jsonCircleColor.type() )
808 case QVariant::StringList:
812 case QVariant::String:
813 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
824 circleFillColor = QColor( 0, 0, 0 );
828 double circleDiameter = 10.0;
829 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
831 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
832 switch ( jsonCircleRadius.type() )
835 case QVariant::LongLong:
836 case QVariant::Double:
846 case QVariant::StringList:
856 double circleOpacity = -1.0;
857 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
859 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
860 switch ( jsonCircleOpacity.type() )
863 case QVariant::LongLong:
864 case QVariant::Double:
865 circleOpacity = jsonCircleOpacity.toDouble();
873 case QVariant::StringList:
882 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
884 circleFillColor.setAlphaF( circleOpacity );
888 QColor circleStrokeColor;
889 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
891 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
892 switch ( jsonCircleStrokeColor.type() )
899 case QVariant::StringList:
903 case QVariant::String:
904 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
914 double circleStrokeWidth = -1.0;
915 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
917 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
918 switch ( circleStrokeWidthJson.type() )
921 case QVariant::LongLong:
922 case QVariant::Double:
927 circleStrokeWidth = -1.0;
932 case QVariant::StringList:
942 double circleStrokeOpacity = -1.0;
943 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
945 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
946 switch ( jsonCircleStrokeOpacity.type() )
949 case QVariant::LongLong:
950 case QVariant::Double:
951 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
959 case QVariant::StringList:
968 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
970 circleStrokeColor.setAlphaF( circleStrokeOpacity );
974 QPointF circleTranslate;
975 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
977 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
978 switch ( jsonCircleTranslate.type() )
986 case QVariant::StringList:
997 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
999 Q_ASSERT( markerSymbolLayer );
1002 symbol->setOutputUnit( context.
targetUnit() );
1003 symbol->setDataDefinedProperties( ddProperties );
1005 if ( !circleTranslate.isNull() )
1007 markerSymbolLayer->
setOffset( circleTranslate );
1011 if ( circleFillColor.isValid() )
1015 if ( circleDiameter != -1 )
1017 markerSymbolLayer->
setSize( circleDiameter );
1020 if ( circleStrokeColor.isValid() )
1024 if ( circleStrokeWidth != -1 )
1037 hasLabeling =
false;
1038 hasRenderer =
false;
1040 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1042 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1045 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1046 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1052 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1058 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
1060 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
1061 switch ( jsonTextSize.type() )
1064 case QVariant::LongLong:
1065 case QVariant::Double:
1075 case QVariant::List:
1076 case QVariant::StringList:
1086 if ( textSizeProperty )
1093 constexpr double EM_TO_CHARS = 2.0;
1095 double textMaxWidth = -1;
1096 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
1098 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
1099 switch ( jsonTextMaxWidth.type() )
1102 case QVariant::LongLong:
1103 case QVariant::Double:
1104 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1111 case QVariant::List:
1112 case QVariant::StringList:
1124 textMaxWidth = 10 * EM_TO_CHARS;
1127 double textLetterSpacing = -1;
1128 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1130 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1131 switch ( jsonTextLetterSpacing.type() )
1134 case QVariant::LongLong:
1135 case QVariant::Double:
1136 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1143 case QVariant::List:
1144 case QVariant::StringList:
1155 bool foundFont =
false;
1157 QString fontStyleName;
1159 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1161 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1163 QString matchedFamily;
1164 const QStringList textFontParts = fontName.split(
' ' );
1165 for (
int i = textFontParts.size() - 1; i >= 1; --i )
1167 const QString candidateFontFamily = textFontParts.mid( 0, i ).join(
' ' );
1168 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1173 family = processedFontFamily;
1174 style = candidateFontStyle;
1179 if ( processedFontFamily == matchedFamily )
1181 family = processedFontFamily;
1182 style = candidateFontStyle;
1186 family = matchedFamily;
1187 style = processedFontFamily;
1188 style.replace( matchedFamily, QString() );
1189 style = style.trimmed();
1190 if ( !style.isEmpty() && !candidateFontStyle.isEmpty() )
1192 style += QStringLiteral(
" %1" ).arg( candidateFontStyle );
1200 if ( QFontDatabase().hasFamily( processedFontFamily ) )
1203 family = processedFontFamily;
1209 family = matchedFamily;
1216 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1217 if ( jsonTextFont.type() != QVariant::List && jsonTextFont.type() != QVariant::StringList && jsonTextFont.type() != QVariant::String
1218 && jsonTextFont.type() != QVariant::Map )
1224 switch ( jsonTextFont.type() )
1226 case QVariant::List:
1227 case QVariant::StringList:
1228 fontName = jsonTextFont.toList().value( 0 ).toString();
1231 case QVariant::String:
1232 fontName = jsonTextFont.toString();
1237 QString familyCaseString = QStringLiteral(
"CASE " );
1238 QString styleCaseString = QStringLiteral(
"CASE " );
1240 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1243 for (
int i = 0; i < stops.length() - 1; ++i )
1246 const QVariant bz = stops.value( i ).toList().value( 0 );
1247 const QString bv = stops.value( i ).toList().value( 1 ).type() == QVariant::String ? stops.value( i ).toList().value( 1 ).toString() : stops.value( i ).toList().value( 1 ).toList().value( 0 ).toString();
1248 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
1250 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1256 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1257 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
1259 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1264 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1266 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1267 "THEN %3 " ).arg( bz.toString(),
1270 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1271 "THEN %3 " ).arg( bz.toString(),
1277 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1283 const QString bv = stops.constLast().toList().value( 1 ).type() == QVariant::String ? stops.constLast().toList().value( 1 ).toString() : stops.constLast().toList().value( 1 ).toList().value( 0 ).toString();
1284 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1291 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1298 fontName = fontFamily;
1308 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1310 textFont = QFont( fontFamily );
1311 if ( !fontStyleName.isEmpty() )
1312 textFont.setStyleName( fontStyleName );
1322 fontName = QStringLiteral(
"Open Sans" );
1323 textFont = QFont( fontName );
1324 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1325 fontStyleName = QStringLiteral(
"Regular" );
1330 fontName = QStringLiteral(
"Arial Unicode MS" );
1331 textFont = QFont( fontName );
1332 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1333 fontStyleName = QStringLiteral(
"Regular" );
1338 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1341 if ( !foundFont && !fontName.isEmpty() )
1343 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1348 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1350 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1351 switch ( jsonTextColor.type() )
1357 case QVariant::List:
1358 case QVariant::StringList:
1362 case QVariant::String:
1363 textColor =
parseColor( jsonTextColor.toString(), context );
1374 textColor = QColor( 0, 0, 0 );
1379 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1381 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1382 switch ( jsonBufferColor.type() )
1388 case QVariant::List:
1389 case QVariant::StringList:
1393 case QVariant::String:
1394 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1403 double bufferSize = 0.0;
1407 constexpr double BUFFER_SIZE_SCALE = 2.0;
1408 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1410 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1411 switch ( jsonHaloWidth.type() )
1414 case QVariant::LongLong:
1415 case QVariant::Double:
1424 case QVariant::List:
1425 case QVariant::StringList:
1436 double haloBlurSize = 0;
1437 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1439 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1440 switch ( jsonTextHaloBlur.type() )
1443 case QVariant::LongLong:
1444 case QVariant::Double:
1458 if ( textColor.isValid() )
1460 if ( textSize >= 0 )
1465 if ( !fontStyleName.isEmpty() )
1468 if ( textLetterSpacing > 0 )
1470 QFont f = format.
font();
1471 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1475 if ( bufferSize > 0 )
1482 if ( haloBlurSize > 0 )
1498 if ( textMaxWidth > 0 )
1504 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1506 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1507 switch ( jsonTextField.type() )
1509 case QVariant::String:
1511 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1515 case QVariant::List:
1516 case QVariant::StringList:
1518 const QVariantList textFieldList = jsonTextField.toList();
1526 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1529 for (
int i = 1; i < textFieldList.size(); ++i )
1531 bool isExpression =
false;
1532 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1533 if ( !isExpression )
1540 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1557 const QVariantList stops = jsonTextField.toMap().value( QStringLiteral(
"stops" ) ).toList();
1558 if ( !stops.empty() )
1565 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field dictionary" ).arg( context.
layerId() ) );
1576 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1578 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1579 if ( textTransform == QLatin1String(
"uppercase" ) )
1583 else if ( textTransform == QLatin1String(
"lowercase" ) )
1592 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1594 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1595 if ( symbolPlacement == QLatin1String(
"line" ) )
1599 geometryType = Qgis::GeometryType::Line;
1601 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1603 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1604 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1614 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1616 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1619 switch ( jsonTextOffset.type() )
1622 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1623 if ( !textSizeProperty )
1634 case QVariant::List:
1635 case QVariant::StringList:
1636 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1637 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1645 if ( !textOffset.isNull() )
1648 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1650 if ( textSizeProperty && !textOffsetProperty )
1657 if ( textOffset.isNull() )
1665 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1667 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1670 QString textAlign = QStringLiteral(
"center" );
1672 const QVariantMap conversionMap
1674 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1675 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1676 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1677 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1680 switch ( jsonTextJustify.type() )
1682 case QVariant::String:
1683 textAlign = jsonTextJustify.toString();
1686 case QVariant::List:
1699 if ( textAlign == QLatin1String(
"left" ) )
1700 labelSettings.
multilineAlign = Qgis::LabelMultiLineAlignment::Left;
1701 else if ( textAlign == QLatin1String(
"right" ) )
1702 labelSettings.
multilineAlign = Qgis::LabelMultiLineAlignment::Right;
1703 else if ( textAlign == QLatin1String(
"center" ) )
1704 labelSettings.
multilineAlign = Qgis::LabelMultiLineAlignment::Center;
1705 else if ( textAlign == QLatin1String(
"follow" ) )
1706 labelSettings.
multilineAlign = Qgis::LabelMultiLineAlignment::FollowPlacement;
1710 labelSettings.
multilineAlign = Qgis::LabelMultiLineAlignment::Center;
1715 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1717 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1720 const QVariantMap conversionMap
1722 { QStringLiteral(
"center" ), 4 },
1723 { QStringLiteral(
"left" ), 5 },
1724 { QStringLiteral(
"right" ), 3 },
1725 { QStringLiteral(
"top" ), 7 },
1726 { QStringLiteral(
"bottom" ), 1 },
1727 { QStringLiteral(
"top-left" ), 8 },
1728 { QStringLiteral(
"top-right" ), 6 },
1729 { QStringLiteral(
"bottom-left" ), 2 },
1730 { QStringLiteral(
"bottom-right" ), 0 },
1733 switch ( jsonTextAnchor.type() )
1735 case QVariant::String:
1736 textAnchor = jsonTextAnchor.toString();
1739 case QVariant::List:
1752 if ( textAnchor == QLatin1String(
"center" ) )
1753 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::Over;
1754 else if ( textAnchor == QLatin1String(
"left" ) )
1755 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::Right;
1756 else if ( textAnchor == QLatin1String(
"right" ) )
1757 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::Left;
1758 else if ( textAnchor == QLatin1String(
"top" ) )
1759 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::Below;
1760 else if ( textAnchor == QLatin1String(
"bottom" ) )
1761 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::Above;
1762 else if ( textAnchor == QLatin1String(
"top-left" ) )
1763 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::BelowRight;
1764 else if ( textAnchor == QLatin1String(
"top-right" ) )
1765 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::BelowLeft;
1766 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1767 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::AboveRight;
1768 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1769 labelSettings.
quadOffset = Qgis::LabelQuadrantPosition::AboveLeft;
1773 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1775 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1778 switch ( jsonTextOffset.type() )
1784 case QVariant::List:
1785 case QVariant::StringList:
1786 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1787 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1795 if ( !textOffset.isNull() )
1798 labelSettings.
xOffset = textOffset.x();
1799 labelSettings.
yOffset = textOffset.y();
1804 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1808 QString spriteProperty, spriteSizeProperty;
1809 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1810 if ( !sprite.isEmpty() )
1813 markerLayer->
setPath( sprite );
1814 markerLayer->
setSize( spriteSize.width() );
1817 if ( !spriteProperty.isEmpty() )
1829 backgroundSettings.
setSize( spriteSize );
1837 if ( textSize >= 0 )
1860 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1862 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1865 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1867 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1871 double spacing = -1.0;
1872 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
1874 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
1875 switch ( jsonSpacing.type() )
1878 case QVariant::LongLong:
1879 case QVariant::Double:
1887 case QVariant::List:
1888 case QVariant::StringList:
1903 bool rotateMarkers =
true;
1904 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
1906 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
1907 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
1909 rotateMarkers =
true;
1911 else if ( alignment == QLatin1String(
"viewport" ) )
1913 rotateMarkers =
false;
1918 double rotation = 0.0;
1919 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
1921 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
1922 switch ( jsonIconRotate.type() )
1925 case QVariant::LongLong:
1926 case QVariant::Double:
1927 rotation = jsonIconRotate.toDouble();
1934 case QVariant::List:
1935 case QVariant::StringList:
1956 QString spriteProperty, spriteSizeProperty;
1957 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1958 if ( !sprite.isNull() )
1960 markerLayer->
setPath( sprite );
1961 markerLayer->
setSize( spriteSize.width() );
1964 if ( !spriteProperty.isEmpty() )
1971 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1973 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
1976 switch ( jsonIconSize.type() )
1979 case QVariant::LongLong:
1980 case QVariant::Double:
1982 size = jsonIconSize.toDouble();
1983 if ( !spriteSizeProperty.isEmpty() )
1986 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
1995 case QVariant::List:
1996 case QVariant::StringList:
2001 markerLayer->
setSize( size * spriteSize.width() );
2004 if ( !spriteSizeProperty.isEmpty() )
2021 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
2024 symbol->setOutputUnit( context.
targetUnit() );
2028 rendererStyle.
setSymbol( symbol.release() );
2031 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
2033 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
2036 QString spriteProperty, spriteSizeProperty;
2037 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
2038 if ( !sprite.isEmpty() )
2041 rasterMarker->
setPath( sprite );
2042 rasterMarker->
setSize( spriteSize.width() );
2046 if ( !spriteProperty.isEmpty() )
2052 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2054 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2057 switch ( jsonIconSize.type() )
2060 case QVariant::LongLong:
2061 case QVariant::Double:
2063 size = jsonIconSize.toDouble();
2064 if ( !spriteSizeProperty.isEmpty() )
2067 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2076 case QVariant::List:
2077 case QVariant::StringList:
2082 rasterMarker->
setSize( size * spriteSize.width() );
2085 if ( !spriteSizeProperty.isEmpty() )
2098 double rotation = 0.0;
2099 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2101 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
2102 switch ( jsonIconRotate.type() )
2105 case QVariant::LongLong:
2106 case QVariant::Double:
2107 rotation = jsonIconRotate.toDouble();
2114 case QVariant::List:
2115 case QVariant::StringList:
2125 double iconOpacity = -1.0;
2126 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2128 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2129 switch ( jsonIconOpacity.type() )
2132 case QVariant::LongLong:
2133 case QVariant::Double:
2134 iconOpacity = jsonIconOpacity.toDouble();
2141 case QVariant::List:
2142 case QVariant::StringList:
2153 rasterMarker->
setAngle( rotation );
2154 if ( iconOpacity >= 0 )
2158 rendererStyle.
setSymbol( markerSymbol );
2169 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2170 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2171 if ( stops.empty() )
2174 QString caseString = QStringLiteral(
"CASE " );
2175 const QString colorComponent(
"color_part(%1,'%2')" );
2177 for (
int i = 0; i < stops.length() - 1; ++i )
2180 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2182 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2184 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2185 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2187 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2188 const QColor topColor =
parseColor( tcVariant.toString(), context );
2190 if ( i == 0 && bottomColor.isValid() )
2197 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2198 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2201 if ( bottomColor.isValid() && topColor.isValid() )
2213 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2214 "%3, %4, %5, %6) " ).arg( bz, tz,
2225 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2226 "%3, %4, %5, %6) " ).arg( bz, tz,
2227 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2228 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2229 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2230 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2235 const QString tz = stops.last().toList().value( 0 ).toString();
2236 const QVariant tcVariant = stops.last().toList().value( 1 );
2237 const QColor topColor =
parseColor( stops.last().toList().value( 1 ), context );
2238 if ( topColor.isValid() )
2245 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2246 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2252 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2253 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2254 .arg( colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ) ).arg( colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ) ).arg( colorComponent.arg( topColorExpr ).arg(
"lightness" ) ).arg( colorComponent.arg( topColorExpr ).arg(
"alpha" ) );
2257 if ( !stops.empty() && defaultColor )
2258 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2265 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2266 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2267 if ( stops.empty() )
2270 QString scaleExpression;
2271 if ( stops.size() <= 2 )
2274 stops.last().toList().value( 0 ).toDouble(),
2275 stops.value( 0 ).toList().value( 1 ),
2276 stops.last().toList().value( 1 ), base, multiplier, &context );
2280 scaleExpression =
parseStops( base, stops, multiplier, context );
2283 if ( !stops.empty() && defaultNumber )
2284 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2294 context = *contextPtr;
2296 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2297 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2298 if ( stops.empty() )
2301 QString scaleExpression;
2302 if ( stops.length() <= 2 )
2304 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2305 const QVariant tv = stops.last().toList().value( 1 );
2306 double bottom = 0.0;
2308 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2309 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2311 stops.last().toList().value( 0 ).toDouble(),
2312 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2313 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2324 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2325 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2326 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2328 for (
int i = 0; i < stops.size() - 1; ++i )
2330 const QVariant bv = stops.value( i ).toList().value( 1 );
2331 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2332 double bottom = 0.0;
2334 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2336 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2337 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2338 .arg( stops.value( i ).toList().value( 0 ).toString(),
2339 stops.value( i + 1 ).toList().value( 0 ).toString(),
2341 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2342 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2343 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2344 base, 1, &context ) );
2347 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2348 "THEN set_color_part(@symbol_color, 'alpha', %2) END" )
2349 .arg( stops.last().toList().value( 0 ).toString() )
2350 .arg( stops.last().toList().value( 1 ).toDouble() * maxOpacity );
2356 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2357 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2358 if ( stops.empty() )
2361 QString scaleExpression;
2362 if ( stops.size() <= 2 )
2364 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2365 stops.last().toList().value( 0 ).toDouble(),
2366 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2367 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2369 stops.last().toList().value( 0 ).toDouble(),
2370 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2371 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2376 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2379 if ( !stops.empty() && defaultPoint )
2380 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2381 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2387 const QVariantMap &conversionMap, QString *defaultString )
2389 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2390 if ( stops.empty() )
2393 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2400 QString caseString = QStringLiteral(
"CASE " );
2402 for (
int i = 0; i < stops.length() - 1; ++i )
2405 const QVariant bz = stops.value( i ).toList().value( 0 );
2406 const QVariant bv = stops.value( i ).toList().value( 1 );
2407 if ( bv.type() != QVariant::List && bv.type() != QVariant::StringList )
2414 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2415 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2416 if ( tv.type() != QVariant::List && tv.type() != QVariant::StringList )
2422 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2423 "THEN array(%3,%4)" ).arg( bz.toString(),
2425 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2426 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2428 caseString += QLatin1String(
"END" );
2434 if ( stops.length() < 2 )
2437 QString caseString = QStringLiteral(
"CASE " );
2439 for (
int i = 0; i < stops.length() - 1; ++i )
2442 const QVariant bz = stops.value( i ).toList().value( 0 );
2443 const QList<QVariant> bv = stops.value( i ).toList().value( 1 ).toList();
2446 for (
const QVariant &value : bv )
2448 const double number = value.toDouble( &ok );
2450 bl << QString::number( number * multiplier );
2454 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2455 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2456 "THEN array(%3) " ).arg( bz.toString(),
2460 const QVariant lz = stops.value( stops.length() - 1 ).toList().value( 0 );
2461 const QList<QVariant> lv = stops.value( stops.length() - 1 ).toList().value( 1 ).toList();
2464 for (
const QVariant &value : lv )
2466 const double number = value.toDouble( &ok );
2468 ll << QString::number( number * multiplier );
2470 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2471 "THEN array(%2) " ).arg( lz.toString(),
2473 caseString += QLatin1String(
"END" );
2479 QString caseString = QStringLiteral(
"CASE " );
2481 for (
int i = 0; i < stops.length() - 1; ++i )
2484 const QVariant bz = stops.value( i ).toList().value( 0 );
2485 const QVariant bv = stops.value( i ).toList().value( 1 );
2486 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2488 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2493 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2494 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2495 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2497 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2501 const QString lowerComparator = i == 0 ? QStringLiteral(
">=" ) : QStringLiteral(
">" );
2503 caseString += QStringLiteral(
"WHEN @vector_tile_zoom %1 %2 AND @vector_tile_zoom <= %3 "
2504 "THEN %4 " ).arg( lowerComparator,
2510 const QVariant z = stops.last().toList().value( 0 );
2511 const QVariant v = stops.last().toList().value( 1 );
2512 QString vStr = v.toString();
2513 if ( ( QMetaType::Type )v.type() == QMetaType::QVariantList )
2516 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2517 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2521 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2522 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2530 QString caseString = QStringLiteral(
"CASE " );
2532 for (
int i = 0; i < stops.length() - 1; ++i )
2535 const QVariant bz = stops.value( i ).toList().value( 0 );
2536 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2537 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2539 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2544 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2545 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2547 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2551 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2552 "THEN %3 " ).arg( bz.toString(),
2556 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2557 stops.constLast().toList().value( 1 ) ) ) );
2558 if ( defaultString )
2559 *defaultString = stops.constLast().toList().value( 1 ).toString();
2565 QString caseString = QStringLiteral(
"CASE " );
2567 bool isExpression =
false;
2568 for (
int i = 0; i < stops.length() - 1; ++i )
2571 const QVariant bz = stops.value( i ).toList().value( 0 );
2572 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2574 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2579 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2580 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2582 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2586 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2587 if ( fieldPart.isEmpty() )
2588 fieldPart = QStringLiteral(
"''" );
2589 else if ( !isExpression )
2592 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom < %2 "
2593 "THEN %3 " ).arg( bz.toString(),
2599 const QVariant bz = stops.constLast().toList().value( 0 );
2600 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2602 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2606 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2607 if ( fieldPart.isEmpty() )
2608 fieldPart = QStringLiteral(
"''" );
2609 else if ( !isExpression )
2612 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 "
2613 "THEN %3 " ).arg( bz.toString(),
2617 QString defaultPart = processLabelField( stops.constFirst().toList().value( 1 ).toString(), isExpression );
2618 if ( defaultPart.isEmpty() )
2619 defaultPart = QStringLiteral(
"''" );
2620 else if ( !isExpression )
2622 caseString += QStringLiteral(
"ELSE %1 END" ).arg( defaultPart );
2629 const QString method = json.
value( 0 ).toString();
2630 if ( method == QLatin1String(
"interpolate" ) )
2634 else if ( method == QLatin1String(
"match" ) )
2636 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2646 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2647 if ( attribute.isEmpty() )
2649 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2653 QString caseString = QStringLiteral(
"CASE " );
2655 for (
int i = 2; i < json.length() - 1; i += 2 )
2657 const QVariantList keys = json.value( i ).toList();
2659 QStringList matchString;
2660 for (
const QVariant &key : keys )
2665 const QVariant value = json.value( i + 1 );
2667 QString valueString;
2672 const QColor color =
parseColor( value, context );
2679 const double v = value.toDouble() * multiplier;
2680 valueString = QString::number( v );
2686 const double v = value.toDouble() * maxOpacity;
2687 valueString = QString::number( v );
2693 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2694 value.toList().value( 0 ).toDouble() * multiplier );
2700 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
2701 matchString.join(
',' ), valueString );
2710 const QColor color =
parseColor( json.constLast(), context );
2712 *defaultColor = color;
2720 const double v = json.constLast().toDouble() * multiplier;
2721 if ( defaultNumber )
2723 elseValue = QString::number( v );
2729 const double v = json.constLast().toDouble() * maxOpacity;
2730 if ( defaultNumber )
2732 elseValue = QString::number( v );
2738 elseValue = QStringLiteral(
"array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
2739 json.constLast().toList().value( 0 ).toDouble() * multiplier );
2745 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
2751 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
2753 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
2758 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
2759 if ( technique == QLatin1String(
"linear" ) )
2761 else if ( technique == QLatin1String(
"exponential" ) )
2762 base = json.value( 1 ).toList(). value( 1 ).toDouble();
2763 else if ( technique == QLatin1String(
"cubic-bezier" ) )
2765 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
2770 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
2774 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
2776 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
2782 for (
int i = 3; i < json.length(); i += 2 )
2784 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
2788 props.insert( QStringLiteral(
"stops" ), stops );
2789 props.insert( QStringLiteral(
"base" ), base );
2809 if ( ( QMetaType::Type )colorExpression.type() == QMetaType::QVariantList )
2813 return parseValue( colorExpression, context,
true );
2818 if ( color.type() != QVariant::String )
2820 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
2829 hue = std::max( 0, color.hslHue() );
2830 saturation = color.hslSaturation() / 255.0 * 100;
2831 lightness = color.lightness() / 255.0 * 100;
2832 alpha = color.alpha();
2840 context = *contextPtr;
2844 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
2846 bool minDoubleOk =
true;
2847 const double min = valueMin.toDouble( &minDoubleOk );
2848 bool maxDoubleOk =
true;
2849 const double max = valueMax.toDouble( &maxDoubleOk );
2850 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
2852 return QString::number( min * multiplier );
2856 QString minValueExpr = valueMin.toString();
2857 QString maxValueExpr = valueMax.toString();
2858 if ( ( QMetaType::Type )valueMin.type() == QMetaType::QVariantList )
2862 if ( ( QMetaType::Type )valueMax.type() == QMetaType::QVariantList )
2867 if ( minValueExpr == maxValueExpr )
2869 return minValueExpr;
2875 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin )
2877 .arg( minValueExpr )
2878 .arg( maxValueExpr );
2882 expression = QStringLiteral(
"scale_exp(@vector_tile_zoom,%1,%2,%3,%4,%5)" ).arg( zoomMin )
2884 .arg( minValueExpr )
2885 .arg( maxValueExpr )
2889 if ( multiplier != 1 )
2890 return QStringLiteral(
"%1 * %2" ).arg( expression ).arg( multiplier );
2897 if ( style == QLatin1String(
"round" ) )
2898 return Qt::RoundCap;
2899 else if ( style == QLatin1String(
"square" ) )
2900 return Qt::SquareCap;
2907 if ( style == QLatin1String(
"bevel" ) )
2908 return Qt::BevelJoin;
2909 else if ( style == QLatin1String(
"round" ) )
2910 return Qt::RoundJoin;
2912 return Qt::MiterJoin;
2917 QString op = expression.value( 0 ).toString();
2918 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
2920 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ) ).arg( op ).arg( parseValue( expression.value( 2 ), context ) );
2922 else if ( op == QLatin1String(
"to-number" ) )
2924 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
2926 if ( op == QLatin1String(
"literal" ) )
2928 return expression.value( 1 ).toString();
2930 else if ( op == QLatin1String(
"all" )
2931 || op == QLatin1String(
"any" )
2932 || op == QLatin1String(
"none" ) )
2935 for (
int i = 1; i < expression.size(); ++i )
2937 const QString part = parseValue( expression.at( i ), context );
2938 if ( part.isEmpty() )
2940 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2946 if ( op == QLatin1String(
"none" ) )
2947 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
2949 QString operatorString;
2950 if ( op == QLatin1String(
"all" ) )
2951 operatorString = QStringLiteral(
") AND (" );
2952 else if ( op == QLatin1String(
"any" ) )
2953 operatorString = QStringLiteral(
") OR (" );
2955 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
2957 else if ( op ==
'!' )
2960 QVariantList contraJsonExpr = expression.value( 1 ).toList();
2961 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
2963 return parseKey( contraJsonExpr, context );
2965 else if ( op == QLatin1String(
"==" )
2966 || op == QLatin1String(
"!=" )
2967 || op == QLatin1String(
">=" )
2969 || op == QLatin1String(
"<=" )
2973 if ( op == QLatin1String(
"==" ) )
2974 op = QStringLiteral(
"IS" );
2975 else if ( op == QLatin1String(
"!=" ) )
2976 op = QStringLiteral(
"IS NOT" );
2977 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
2978 op, parseValue( expression.value( 2 ), context ) );
2980 else if ( op == QLatin1String(
"has" ) )
2982 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
2984 else if ( op == QLatin1String(
"!has" ) )
2986 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
2988 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
2990 const QString key = parseKey( expression.value( 1 ), context );
2992 for (
int i = 2; i < expression.size(); ++i )
2994 const QString part = parseValue( expression.at( i ), context );
2995 if ( part.isEmpty() )
2997 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3002 if ( op == QLatin1String(
"in" ) )
3003 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3005 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3007 else if ( op == QLatin1String(
"get" ) )
3009 return parseKey( expression.value( 1 ), context );
3011 else if ( op == QLatin1String(
"match" ) )
3013 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
3015 if ( expression.size() == 5
3016 && expression.at( 3 ).type() == QVariant::Bool && expression.at( 3 ).toBool() ==
true
3017 && expression.at( 4 ).type() == QVariant::Bool && expression.at( 4 ).toBool() ==
false )
3020 if ( expression.at( 2 ).type() == QVariant::List || expression.at( 2 ).type() == QVariant::StringList )
3023 for (
const QVariant &p : expression.at( 2 ).toList() )
3025 parts << parseValue( p, context );
3028 if ( parts.size() > 1 )
3033 else if ( expression.at( 2 ).type() == QVariant::String || expression.at( 2 ).type() == QVariant::Int
3034 || expression.at( 2 ).type() == QVariant::Double || expression.at( 2 ).type() == QVariant::LongLong )
3040 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3046 QString caseString = QStringLiteral(
"CASE " );
3047 for (
int i = 2; i < expression.size() - 2; i += 2 )
3049 if ( expression.at( i ).type() == QVariant::List || expression.at( i ).type() == QVariant::StringList )
3052 for (
const QVariant &p : expression.at( i ).toList() )
3057 if ( parts.size() > 1 )
3062 else if ( expression.at( i ).type() == QVariant::String || expression.at( i ).type() == QVariant::Int
3063 || expression.at( i ).type() == QVariant::Double || expression.at( i ).type() == QVariant::LongLong )
3068 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
3070 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
3074 else if ( op == QLatin1String(
"to-string" ) )
3076 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3080 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3089 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3093 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
3094 if ( spriteDefinition.size() == 0 )
3096 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3100 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
3101 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
3102 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
3103 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
3104 if ( sprite.isNull() )
3106 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3110 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
3118 auto prepareBase64 = [](
const QImage & sprite )
3121 if ( !sprite.isNull() )
3124 QBuffer buffer( &blob );
3125 buffer.open( QIODevice::WriteOnly );
3126 sprite.save( &buffer,
"PNG" );
3128 const QByteArray encoded = blob.toBase64();
3129 path = QString( encoded );
3130 path.prepend( QLatin1String(
"base64:" ) );
3135 switch ( value.type() )
3137 case QVariant::String:
3139 QString spriteName = value.toString();
3140 const QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
3141 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
3142 if ( match.hasMatch() )
3144 const QString fieldName = match.captured( 1 );
3145 spriteProperty = QStringLiteral(
"CASE" );
3146 spriteSizeProperty = QStringLiteral(
"CASE" );
3148 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
3149 spriteName.replace(
")", QLatin1String(
"\\)" ) );
3150 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
3151 const QRegularExpression fieldValueMatch( spriteName );
3153 for (
const QString &name : spriteNames )
3155 match = fieldValueMatch.match( name );
3156 if ( match.hasMatch() )
3160 const QString fieldValue = match.captured( 1 );
3162 path = prepareBase64( sprite );
3163 if ( spritePath.isEmpty() && !path.isEmpty() )
3169 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
3170 .arg( fieldName, fieldValue, path );
3171 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
3172 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
3176 spriteProperty += QLatin1String(
" END" );
3177 spriteSizeProperty += QLatin1String(
" END" );
3181 spriteProperty.clear();
3182 spriteSizeProperty.clear();
3183 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
3184 spritePath = prepareBase64( sprite );
3191 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3192 if ( stops.size() == 0 )
3199 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3200 spritePath = prepareBase64( sprite );
3202 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3203 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3205 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3206 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3207 .arg( spriteSize.width() );
3209 for (
int i = 0; i < stops.size() - 1; ++i )
3212 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3213 path = prepareBase64( sprite );
3215 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3217 .arg( stops.value( i ).toList().value( 0 ).toString(),
3218 stops.value( i + 1 ).toList().value( 0 ).toString(),
3220 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3222 .arg( stops.value( i ).toList().value( 0 ).toString(),
3223 stops.value( i + 1 ).toList().value( 0 ).toString() )
3224 .arg( size.width() );
3226 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3227 path = prepareBase64( sprite );
3229 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3231 .arg( stops.last().toList().value( 0 ).toString() )
3233 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3235 .arg( stops.last().toList().value( 0 ).toString() )
3236 .arg( size.width() );
3240 case QVariant::List:
3242 const QVariantList json = value.toList();
3243 const QString method = json.value( 0 ).toString();
3244 if ( method != QLatin1String(
"match" ) )
3246 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3250 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3251 if ( attribute.isEmpty() )
3253 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3257 spriteProperty = QStringLiteral(
"CASE " );
3258 spriteSizeProperty = QStringLiteral(
"CASE " );
3260 for (
int i = 2; i < json.length() - 1; i += 2 )
3262 const QVariantList keys = json.value( i ).toList();
3264 QStringList matchString;
3265 for (
const QVariant &key : keys )
3270 const QVariant value = json.value( i + 1 );
3272 const QImage sprite =
retrieveSprite( value.toString(), context, spriteSize );
3273 spritePath = prepareBase64( sprite );
3275 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3276 "THEN '%3' " ).arg( attribute,
3277 matchString.join(
',' ),
3280 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3281 "THEN %3 " ).arg( attribute,
3282 matchString.join(
',' ) ).arg( spriteSize.width() );
3285 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3286 spritePath = prepareBase64( sprite );
3288 spriteProperty += QStringLiteral(
"ELSE %1 END" ).arg( spritePath );
3289 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3304 switch ( value.type() )
3306 case QVariant::List:
3307 case QVariant::StringList:
3310 case QVariant::Bool:
3311 case QVariant::String:
3312 if ( colorExpected )
3317 return parseValue(
c, context );
3323 case QVariant::LongLong:
3324 case QVariant::Double:
3325 return value.toString();
3327 case QVariant::Color:
3328 c = value.value<QColor>();
3329 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3332 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3340 if ( value.toString() == QLatin1String(
"$type" ) )
3342 return QStringLiteral(
"_geom_type" );
3344 if ( value.toString() == QLatin1String(
"level" ) )
3346 return QStringLiteral(
"level" );
3348 else if ( ( value.type() == QVariant::List && value.toList().size() == 1 ) || value.type() == QVariant::StringList )
3350 if ( value.toList().size() > 1 )
3351 return value.toList().at( 1 ).toString();
3354 QString valueString = value.toList().value( 0 ).toString();
3355 if ( valueString == QLatin1String(
"geometry-type" ) )
3357 return QStringLiteral(
"_geom_type" );
3362 else if ( value.type() == QVariant::List && value.toList().size() > 1 )
3369QString QgsMapBoxGlStyleConverter::processLabelField(
const QString &
string,
bool &isExpression )
3373 const QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
3374 const QRegularExpressionMatch match = singleFieldRx.match(
string );
3375 if ( match.hasMatch() )
3377 isExpression =
false;
3378 return match.captured( 1 );
3381 const QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
3382 const QStringList parts =
string.split( multiFieldRx );
3383 if ( parts.size() > 1 )
3385 isExpression =
true;
3388 for (
const QString &part : parts )
3390 if ( part.isEmpty() )
3393 if ( !part.contains(
'{' ) )
3400 const QStringList split = part.split(
'}' );
3402 if ( !split.at( 1 ).isEmpty() )
3405 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
3409 isExpression =
false;
3416 return mRenderer ? mRenderer->clone() :
nullptr;
3421 return mLabeling ? mLabeling->clone() :
nullptr;
3431 return mRasterSubLayers;
3436 QList<QgsMapLayer *> subLayers;
3439 const QString sourceName = subLayer.source();
3440 std::unique_ptr< QgsRasterLayer > rl;
3447 rl->pipe()->setDataDefinedProperties( subLayer.dataDefinedProperties() );
3454 subLayers.append( rl.release() );
3463 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3466 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3467 context = tmpContext.get();
3472 if (
string.compare( QLatin1String(
"vector" ), Qt::CaseInsensitive ) == 0 )
3474 else if (
string.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
3476 else if (
string.compare( QLatin1String(
"raster-dem" ), Qt::CaseInsensitive ) == 0 )
3478 else if (
string.compare( QLatin1String(
"geojson" ), Qt::CaseInsensitive ) == 0 )
3480 else if (
string.compare( QLatin1String(
"image" ), Qt::CaseInsensitive ) == 0 )
3482 else if (
string.compare( QLatin1String(
"video" ), Qt::CaseInsensitive ) == 0 )
3484 context->
pushWarning( QObject::tr(
"Invalid source type \"%1\" for source \"%2\"" ).arg(
string, name ) );
3490 const QString name = it.key();
3491 const QVariantMap jsonSource = it.value().toMap();
3492 const QString typeString = jsonSource.value( QStringLiteral(
"type" ) ).toString();
3515 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3518 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3519 context = tmpContext.get();
3522 std::unique_ptr< QgsMapBoxGlStyleRasterSource > raster = std::make_unique< QgsMapBoxGlStyleRasterSource >( name );
3523 if ( raster->setFromJson( source, context ) )
3524 mSources.append( raster.release() );
3527bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
3529 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
3531 bool bDoubleOk, tDoubleOk;
3532 bottom = bottomVariant.toDouble( &bDoubleOk );
3533 top = topVariant.toDouble( &tDoubleOk );
3534 return ( bDoubleOk && tDoubleOk );
3545 mWarnings << warning;
3560 return mSizeConversionFactor;
3565 mSizeConversionFactor = sizeConversionFactor;
3570 return mSpriteImage;
3575 return mSpriteDefinitions;
3580 mSpriteImage = image;
3581 mSpriteDefinitions = definitions;
3631 mAttribution = json.value( QStringLiteral(
"attribution" ) ).toString();
3633 const QString scheme = json.value( QStringLiteral(
"scheme" ), QStringLiteral(
"xyz" ) ).toString();
3634 if ( scheme.compare( QLatin1String(
"xyz" ) ) == 0 )
3640 context->
pushWarning( QObject::tr(
"%1 scheme is not supported for raster source %2" ).arg( scheme,
name() ) );
3644 mMinZoom = json.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"0" ) ).toInt();
3645 mMaxZoom = json.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"22" ) ).toInt();
3646 mTileSize = json.value( QStringLiteral(
"tileSize" ), QStringLiteral(
"512" ) ).toInt();
3648 const QVariantList
tiles = json.value( QStringLiteral(
"tiles" ) ).toList();
3649 for (
const QVariant &tile :
tiles )
3651 mTiles.append( tile.toString() );
3660 parts.insert( QStringLiteral(
"type" ), QStringLiteral(
"xyz" ) );
3661 parts.insert( QStringLiteral(
"url" ), mTiles.value( 0 ) );
3663 if ( mTileSize == 256 )
3664 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"1" ) );
3665 else if ( mTileSize == 512 )
3666 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"2" ) );
3668 parts.insert( QStringLiteral(
"zmax" ), QString::number( mMaxZoom ) );
3669 parts.insert( QStringLiteral(
"zmin" ), QString::number( mMinZoom ) );
3671 std::unique_ptr< QgsRasterLayer > rl = std::make_unique< QgsRasterLayer >(
QgsProviderRegistry::instance()->encodeUri( QStringLiteral(
"wms" ), parts ),
name(), QStringLiteral(
"wms" ) );
3672 return rl.release();
@ CentralPoint
Place symbols at the mid point of the line.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
RenderUnit
Rendering size units.
MapBoxGlStyleSourceType
Flags which control project capabilities.
@ RasterDem
Raster DEM source.
@ Unknown
Other/unknown source type.
@ Viewport
Relative to the whole viewport/output device.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
A paint effect which blurs a source picture, using a number of different blur methods.
void setBlurUnit(const Qgis::RenderUnit unit)
Sets the units used for the blur level (radius).
@ StackBlur
Stack blur, a fast but low quality blur. Valid blur level values are between 0 - 16.
void setBlurMethod(const BlurMethod method)
Sets the blur method (algorithm) to use for performing the blur.
void setBlurLevel(const double level)
Sets blur level (radius)
A paint effect which consists of a stack of other chained paint effects.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
Create an expression allowing to evaluate if a field is equal to a value.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QString processFontFamilyName(const QString &name) const
Processes a font family name, applying any matching fontFamilyReplacements() to the name.
static bool fontFamilyHasStyle(const QString &family, const QString &style)
Check whether font family on system has specific style.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
void setPlacementFlags(QgsLabeling::LinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setFactor(double factor)
Sets the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ OnLine
Labels can be placed directly over a line feature.
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setOffset(double offset)
Sets the line's offset.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the line's offset.
Abstract base class for MapBox GL style sources.
QString name() const
Returns the source's name.
virtual ~QgsMapBoxGlStyleAbstractSource()
QgsMapBoxGlStyleAbstractSource(const QString &name)
Constructor for QgsMapBoxGlStyleAbstractSource.
Context for a MapBox GL style conversion operation.
void setLayerId(const QString &value)
Sets the layer ID of the layer currently being converted.
QStringList warnings() const
Returns a list of warning messages generated during the conversion.
void pushWarning(const QString &warning)
Pushes a warning message generated during the conversion.
double pixelSizeConversionFactor() const
Returns the pixel size conversion factor, used to scale the original pixel sizes when converting styl...
void setTargetUnit(Qgis::RenderUnit targetUnit)
Sets the target unit type.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
Qgis::RenderUnit targetUnit() const
Returns the target unit type.
void setSprites(const QImage &image, const QVariantMap &definitions)
Sets the sprite image and definitions JSON to use during conversion.
QString layerId() const
Returns the layer ID of the layer currently being converted.
QImage spriteImage() const
Returns the sprite image to use during conversion, or an invalid image if this is not set.
void clearWarnings()
Clears the list of warning messages.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
static QString parseOpacityStops(double base, const QVariantList &stops, int maxOpacity, QgsMapBoxGlStyleConversionContext &context)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate alpha ...
static QString parseColorExpression(const QVariant &colorExpression, QgsMapBoxGlStyleConversionContext &context)
Converts an expression representing a color to a string (can be color string or an expression where a...
static QString parseStops(double base, const QVariantList &stops, double multiplier, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
static QString parseExpression(const QVariantList &expression, QgsMapBoxGlStyleConversionContext &context, bool colorExpected=false)
Converts a MapBox GL expression to a QGIS expression.
PropertyType
Property types, for interpolated value conversion.
@ Point
Point/offset property.
@ Numeric
Numeric property (e.g. line width, text size)
@ Opacity
Opacity property.
QList< QgsMapBoxGlStyleAbstractSource * > sources()
Returns the list of converted sources.
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
QList< QgsMapBoxGlStyleRasterSubLayer > rasterSubLayers() const
Returns a list of raster sub layers contained in the style.
static QgsProperty parseInterpolateByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, double *defaultNumber=nullptr)
Parses a numeric value which is interpolated by zoom range.
static Qt::PenJoinStyle parseJoinStyle(const QString &style)
Converts a value to Qt::PenJoinStyle enum from JSON value.
static QgsProperty parseInterpolateStringByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Interpolates a string by zoom.
static QString interpolateExpression(double zoomMin, double zoomMax, QVariant valueMin, QVariant valueMax, double base, double multiplier=1, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Generates an interpolation for values between valueMin and valueMax, scaled between the ranges zoomMi...
static QgsProperty parseInterpolatePointByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, QPointF *defaultPoint=nullptr)
Interpolates a point/offset with either scale_linear() or scale_exp() (depending on base value).
static bool parseCircleLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a circle layer.
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
static QgsProperty parseInterpolateListByZoom(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Interpolates a list which starts with the interpolate function.
~QgsMapBoxGlStyleConverter()
QList< QgsMapLayer * > createSubLayers() const
Returns a list of new map layers corresponding to sublayers of the style, e.g.
Result
Result of conversion.
@ Success
Conversion was successful.
@ NoLayerList
No layer list was found in JSON input.
QgsMapBoxGlStyleConverter()
Constructor for QgsMapBoxGlStyleConverter.
static QImage retrieveSprite(const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize)
Retrieves the sprite image with the specified name, taken from the specified context.
static QString parseLabelStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops containing label values.
void parseLayers(const QVariantList &layers, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of layers from JSON.
static QgsProperty parseInterpolateColorByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, QColor *defaultColor=nullptr)
Parses a color value which is interpolated by zoom range.
static QgsProperty parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
static QString retrieveSpriteAsBase64(const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize, QString &spriteProperty, QString &spriteSizeProperty)
Retrieves the sprite image with the specified name, taken from the specified context as a base64 enco...
void parseSources(const QVariantMap &sources, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of sources from JSON.
static QColor parseColor(const QVariant &color, QgsMapBoxGlStyleConversionContext &context)
Parses a color in one of these supported formats:
static bool parseSymbolLayerAsRenderer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as a renderer.
static bool parseFillLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context, bool isBackgroundStyle=false)
Parses a fill layer.
static void parseSymbolLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, bool &hasRenderer, QgsVectorTileBasicLabelingStyle &labelingStyle, bool &hasLabeling, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as renderer or labeling.
static bool parseLineLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a line layer.
void parseRasterSource(const QVariantMap &source, const QString &name, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse a raster source from JSON.
static void colorAsHslaComponents(const QColor &color, int &hue, int &saturation, int &lightness, int &alpha)
Takes a QColor object and returns HSLA components in required format for QGIS color_hsla() expression...
static Qt::PenCapStyle parseCapStyle(const QString &style)
Converts a value to Qt::PenCapStyle enum from JSON value.
static QString parseStringStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Parses a list of interpolation stops containing string values.
static QgsProperty parseMatchList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a match function value list.
static QgsProperty parseValueList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a value list (e.g.
static QString parseArrayStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes numerical arrays from stops.
static QString parsePointStops(double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate point/...
Encapsulates a MapBox GL style raster source.
Qgis::MapBoxGlStyleSourceType type() const override
Returns the source type.
QgsMapBoxGlStyleRasterSource(const QString &name)
Constructor for QgsMapBoxGlStyleRasterSource.
QgsRasterLayer * toRasterLayer() const
Returns a new raster layer representing the raster source, or nullptr if the source cannot be represe...
bool setFromJson(const QVariantMap &json, QgsMapBoxGlStyleConversionContext *context) override
Sets the source's state from a json map.
QStringList tiles() const
Returns the list of tile sources.
Encapsulates a MapBox GL style raster sub layer.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the layer's data defined properties.
QgsMapBoxGlStyleRasterSubLayer(const QString &id, const QString &source)
Constructor for QgsMapBoxGlStyleRasterSubLayer, with the given id and source.
Line symbol layer type which draws repeating marker symbols along a line feature.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
virtual void setSize(double size)
Sets the symbol size.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
void setAngle(double angle)
Sets the rotation angle for the marker.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
const QgsLabelObstacleSettings & obstacleSettings() const
Returns the label obstacle settings.
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
Qgis::LabelQuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
int priority
Label priority.
@ FontStyle
Font style name.
@ FontLetterSpacing
Letter spacing.
@ LinePlacementOptions
Line placement flags.
Qgis::RenderUnit offsetUnits
Units for offsets of label.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label's property collection, used for data defined overrides.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
double dist
Distance from feature to the label.
Qgis::RenderUnit distUnits
Units the distance from feature to the label.
QString fieldName
Name of field (or an expression) to use for label text.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
QString expressionString() const
Returns the expression used for the property value.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
A class for filling symbols with a repeated raster image.
void setWidthUnit(const Qgis::RenderUnit unit)
Sets the units for the image's width.
void setWidth(const double width)
Sets the width for scaling the image used in the fill.
void setOpacity(double opacity)
Sets the opacity for the raster image used in the fill.
void setImageFilePath(const QString &imagePath)
Sets the path to the raster image used for the fill.
void setCoordinateMode(Qgis::SymbolCoordinateReference mode)
Set the coordinate mode for fill.
Represents a raster layer.
Line symbol layer type which draws line sections using a raster image file.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Raster marker symbol layer class.
void setOpacity(double opacity)
Set the marker opacity.
void setPath(const QString &path)
Set the marker raster image path.
void setBrushStyle(Qt::BrushStyle style)
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setStrokeStyle(Qt::PenStyle strokeStyle)
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the fill's offset.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setOffset(QPointF offset)
Sets an offset by which polygons will be translated during rendering.
void setStrokeColor(const QColor &strokeColor) override
Sets the stroke color for the symbol layer.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setStrokeWidthUnit(Qgis::RenderUnit u)
Sets the unit for the width of the marker's stroke.
void setStrokeWidth(double w)
Sets the width of the marker's stroke.
void setStrokeColor(const QColor &color) override
Sets the marker's stroke color.
static QColor parseColor(const QString &colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
@ PropertyFile
Filename, eg for svg files.
@ PropertyAngle
Symbol angle.
@ PropertyCustomDash
Custom dash pattern.
@ PropertyOpacity
Opacity.
@ PropertyOffset
Symbol offset.
@ PropertyStrokeWidth
Stroke width.
@ PropertyFillColor
Fill color.
@ PropertyName
Name, eg shape name for simple markers.
@ PropertyInterval
Line marker interval.
@ PropertyStrokeColor
Stroke color.
@ PropertyWidth
Symbol width.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
@ PropertyOpacity
Opacity.
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
Container for settings relating to a text background object.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
@ ShapeMarkerSymbol
Marker symbol.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the shape's size.
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
void setSize(QSizeF size)
Sets the size of the background shape.
void setColor(const QColor &color)
Sets the color for the buffer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QFont font() const
Returns the font used for rendering text.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
Configuration of a single style within QgsVectorTileBasicLabeling.
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit)
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit)
void setStyleName(const QString &name)
Sets human readable name of this style.
void setGeometryType(Qgis::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
void setLabelSettings(const QgsPalLayerSettings &settings)
Sets labeling configuration of this style.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
Basic labeling configuration for vector tile layers.
Definition of map rendering of a subset of vector tile data.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit)
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setSymbol(QgsSymbol *sym)
Sets symbol for rendering. Takes ownership of the symbol.
void setStyleName(const QString &name)
Sets human readable name of this style.
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit)
void setGeometryType(Qgis::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
The default vector tile renderer implementation.
Base class for labeling configuration classes for vector tile layers.
Abstract base class for all vector tile renderer implementations.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsSymbolLayer * > QgsSymbolLayerList