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();
147 int maxZoom = jsonLayer.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"-1" ) ).toInt();
151 const bool enabled = jsonLayer.value( QStringLiteral(
"visibility" ) ).toString() != QLatin1String(
"none" );
153 QString filterExpression;
154 if ( jsonLayer.contains( QStringLiteral(
"filter" ) ) )
156 filterExpression =
parseExpression( jsonLayer.value( QStringLiteral(
"filter" ) ).toList(), *context );
162 bool hasRendererStyle =
false;
163 bool hasLabelingStyle =
false;
164 if ( layerType == QLatin1String(
"fill" ) )
166 hasRendererStyle =
parseFillLayer( jsonLayer, rendererStyle, *context );
168 else if ( layerType == QLatin1String(
"line" ) )
170 hasRendererStyle =
parseLineLayer( jsonLayer, rendererStyle, *context );
172 else if ( layerType == QLatin1String(
"circle" ) )
176 else if ( layerType == QLatin1String(
"symbol" ) )
178 parseSymbolLayer( jsonLayer, rendererStyle, hasRendererStyle, labelingStyle, hasLabelingStyle, *context );
182 mWarnings << QObject::tr(
"%1: Skipping unknown layer type %2" ).arg( context->
layerId(), layerType );
187 if ( hasRendererStyle )
195 rendererStyles.append( rendererStyle );
198 if ( hasLabelingStyle )
206 labelingStyles.append( labelingStyle );
209 mWarnings.append( context->
warnings() );
213 if ( hasRendererBackgroundStyle )
214 rendererStyles.prepend( rendererBackgroundStyle );
216 mRenderer = std::make_unique< QgsVectorTileBasicRenderer >();
218 renderer->setStyles( rendererStyles );
220 mLabeling = std::make_unique< QgsVectorTileBasicLabeling >();
222 labeling->setStyles( labelingStyles );
227 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
232 bool colorIsDataDefined =
false;
234 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsFillSymbol >() );
238 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) ) )
240 const QVariant jsonFillColor = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) );
241 switch ( jsonFillColor.userType() )
243 case QMetaType::Type::QVariantMap:
247 case QMetaType::Type::QVariantList:
248 case QMetaType::Type::QStringList:
249 colorIsDataDefined =
true;
253 case QMetaType::Type::QString:
254 fillColor =
parseColor( jsonFillColor.toString(), context );
259 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillColor.userType() ) ) ) );
267 fillColor = QColor( 0, 0, 0 );
270 QColor fillOutlineColor;
271 if ( !isBackgroundStyle )
273 if ( !jsonPaint.contains( QStringLiteral(
"fill-outline-color" ) ) )
275 if ( fillColor.isValid() )
276 fillOutlineColor = fillColor;
284 const QVariant jsonFillOutlineColor = jsonPaint.value( QStringLiteral(
"fill-outline-color" ) );
285 switch ( jsonFillOutlineColor.userType() )
287 case QMetaType::Type::QVariantMap:
291 case QMetaType::Type::QVariantList:
292 case QMetaType::Type::QStringList:
296 case QMetaType::Type::QString:
297 fillOutlineColor =
parseColor( jsonFillOutlineColor.toString(), context );
301 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-outline-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillOutlineColor.userType() ) ) ) );
307 double fillOpacity = -1.0;
308 double rasterOpacity = -1.0;
309 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) ) )
311 const QVariant jsonFillOpacity = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) );
312 switch ( jsonFillOpacity.userType() )
314 case QMetaType::Type::Int:
315 case QMetaType::Type::LongLong:
316 case QMetaType::Type::Double:
317 fillOpacity = jsonFillOpacity.toDouble();
318 rasterOpacity = fillOpacity;
321 case QMetaType::Type::QVariantMap:
334 case QMetaType::Type::QVariantList:
335 case QMetaType::Type::QStringList:
349 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillOpacity.userType() ) ) ) );
355 QPointF fillTranslate;
356 if ( jsonPaint.contains( QStringLiteral(
"fill-translate" ) ) )
358 const QVariant jsonFillTranslate = jsonPaint.value( QStringLiteral(
"fill-translate" ) );
359 switch ( jsonFillTranslate.userType() )
362 case QMetaType::Type::QVariantMap:
366 case QMetaType::Type::QVariantList:
367 case QMetaType::Type::QStringList:
373 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillTranslate.userType() ) ) ) );
379 Q_ASSERT( fillSymbol );
382 symbol->setOutputUnit( context.
targetUnit() );
385 if ( !fillTranslate.isNull() )
391 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) ) )
395 const QVariant fillPatternJson = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) );
398 fillColor = QColor();
399 fillOutlineColor = QColor();
406 QString spriteProperty, spriteSizeProperty;
408 if ( !sprite.isEmpty() )
413 rasterFill->
setWidth( spriteSize.width() );
417 if ( rasterOpacity >= 0 )
422 if ( !spriteProperty.isEmpty() )
429 symbol->appendSymbolLayer( rasterFill );
435 if ( fillOpacity != -1 )
437 symbol->setOpacity( fillOpacity );
448 if ( fillOutlineColor.isValid() && ( fillOutlineColor.alpha() == 255 || fillOutlineColor != fillColor ) )
459 if ( fillColor.isValid() )
463 else if ( colorIsDataDefined )
479 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
481 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
486 QString rasterLineSprite;
488 const QVariantMap jsonPaint = jsonLayer.
value( QStringLiteral(
"paint" ) ).toMap();
489 if ( jsonPaint.contains( QStringLiteral(
"line-pattern" ) ) )
491 const QVariant jsonLinePattern = jsonPaint.value( QStringLiteral(
"line-pattern" ) );
492 switch ( jsonLinePattern.userType() )
494 case QMetaType::Type::QVariantMap:
495 case QMetaType::Type::QString:
498 QString spriteProperty, spriteSizeProperty;
504 case QMetaType::Type::QVariantList:
505 case QMetaType::Type::QStringList:
510 if ( rasterLineSprite.isEmpty() )
513 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
520 if ( jsonPaint.contains( QStringLiteral(
"line-color" ) ) )
522 const QVariant jsonLineColor = jsonPaint.value( QStringLiteral(
"line-color" ) );
523 switch ( jsonLineColor.userType() )
525 case QMetaType::Type::QVariantMap:
530 case QMetaType::Type::QVariantList:
531 case QMetaType::Type::QStringList:
536 case QMetaType::Type::QString:
537 lineColor =
parseColor( jsonLineColor.toString(), context );
541 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineColor.userType() ) ) ) );
548 lineColor = QColor( 0, 0, 0 );
554 if ( jsonPaint.contains( QStringLiteral(
"line-width" ) ) )
556 const QVariant jsonLineWidth = jsonPaint.
value( QStringLiteral(
"line-width" ) );
557 switch ( jsonLineWidth.userType() )
559 case QMetaType::Type::Int:
560 case QMetaType::Type::LongLong:
561 case QMetaType::Type::Double:
565 case QMetaType::Type::QVariantMap:
577 case QMetaType::Type::QVariantList:
578 case QMetaType::Type::QStringList:
590 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineWidth.userType() ) ) ) );
595 double lineOffset = 0.0;
596 if ( jsonPaint.contains( QStringLiteral(
"line-offset" ) ) )
598 const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral(
"line-offset" ) );
599 switch ( jsonLineOffset.userType() )
601 case QMetaType::Type::Int:
602 case QMetaType::Type::LongLong:
603 case QMetaType::Type::Double:
607 case QMetaType::Type::QVariantMap:
612 case QMetaType::Type::QVariantList:
613 case QMetaType::Type::QStringList:
618 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineOffset.userType() ) ) ) );
623 double lineOpacity = -1.0;
625 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
627 const QVariant jsonLineOpacity = jsonPaint.
value( QStringLiteral(
"line-opacity" ) );
628 switch ( jsonLineOpacity.userType() )
630 case QMetaType::Type::Int:
631 case QMetaType::Type::LongLong:
632 case QMetaType::Type::Double:
633 lineOpacity = jsonLineOpacity.toDouble();
636 case QMetaType::Type::QVariantMap:
639 double defaultValue = 1.0;
648 case QMetaType::Type::QVariantList:
649 case QMetaType::Type::QStringList:
652 double defaultValue = 1.0;
663 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineOpacity.userType() ) ) ) );
668 QVector< double > dashVector;
669 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
671 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
672 switch ( jsonLineDashArray.userType() )
674 case QMetaType::Type::QVariantMap:
676 QString arrayExpression;
679 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
680 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
685 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
689 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
690 for (
const QVariant &v : dashSource )
692 dashVector << v.toDouble() * lineWidth;
697 case QMetaType::Type::QVariantList:
698 case QMetaType::Type::QStringList:
700 const QVariantList dashSource = jsonLineDashArray.toList();
702 if ( dashSource.at( 0 ).userType() == QMetaType::Type::QString )
708 .arg( property.asExpression(), lineWidthProperty.
asExpression() ) );
718 QVector< double > rawDashVectorSizes;
719 rawDashVectorSizes.reserve( dashSource.size() );
720 for (
const QVariant &v : dashSource )
722 rawDashVectorSizes << v.toDouble();
726 if ( rawDashVectorSizes.size() == 1 )
729 rawDashVectorSizes.clear();
731 else if ( rawDashVectorSizes.size() % 2 == 1 )
735 rawDashVectorSizes[0] = rawDashVectorSizes[0] + rawDashVectorSizes[rawDashVectorSizes.size() - 1];
736 rawDashVectorSizes.resize( rawDashVectorSizes.size() - 1 );
739 if ( !rawDashVectorSizes.isEmpty() && ( !lineWidthProperty.
asExpression().isEmpty() ) )
741 QStringList dashArrayStringParts;
742 dashArrayStringParts.reserve( rawDashVectorSizes.size() );
743 for (
double v : std::as_const( rawDashVectorSizes ) )
748 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
749 .arg( dashArrayStringParts.join(
',' ),
755 for (
double v : std::as_const( rawDashVectorSizes ) )
757 dashVector << v *lineWidth;
764 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-dasharray type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineDashArray.userType() ) ) ) );
769 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
770 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
771 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
773 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
774 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
776 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
778 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
780 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
784 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
785 symbol->setOutputUnit( context.
targetUnit() );
787 if ( !rasterLineSprite.isEmpty() )
797 if ( lineOpacity != -1 )
799 symbol->setOpacity( lineOpacity );
805 symbol->setDataDefinedProperties( ddProperties );
807 if ( lineWidth != -1 )
811 symbol->changeSymbolLayer( 0, lineSymbol );
816 Q_ASSERT( lineSymbol );
826 if ( lineOpacity != -1 )
828 symbol->setOpacity( lineOpacity );
834 symbol->setDataDefinedProperties( ddProperties );
836 if ( lineColor.isValid() )
840 if ( lineWidth != -1 )
844 if ( !dashVector.empty() )
858 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
860 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
864 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
868 QColor circleFillColor;
869 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
871 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
872 switch ( jsonCircleColor.userType() )
874 case QMetaType::Type::QVariantMap:
878 case QMetaType::Type::QVariantList:
879 case QMetaType::Type::QStringList:
883 case QMetaType::Type::QString:
884 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
888 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleColor.userType() ) ) ) );
895 circleFillColor = QColor( 0, 0, 0 );
899 double circleDiameter = 10.0;
900 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
902 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
903 switch ( jsonCircleRadius.userType() )
905 case QMetaType::Type::Int:
906 case QMetaType::Type::LongLong:
907 case QMetaType::Type::Double:
911 case QMetaType::Type::QVariantMap:
916 case QMetaType::Type::QVariantList:
917 case QMetaType::Type::QStringList:
922 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-radius type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleRadius.userType() ) ) ) );
927 double circleOpacity = -1.0;
928 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
930 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
931 switch ( jsonCircleOpacity.userType() )
933 case QMetaType::Type::Int:
934 case QMetaType::Type::LongLong:
935 case QMetaType::Type::Double:
936 circleOpacity = jsonCircleOpacity.toDouble();
939 case QMetaType::Type::QVariantMap:
943 case QMetaType::Type::QVariantList:
944 case QMetaType::Type::QStringList:
949 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleOpacity.userType() ) ) ) );
953 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
955 circleFillColor.setAlphaF( circleOpacity );
959 QColor circleStrokeColor;
960 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
962 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
963 switch ( jsonCircleStrokeColor.userType() )
965 case QMetaType::Type::QVariantMap:
969 case QMetaType::Type::QVariantList:
970 case QMetaType::Type::QStringList:
974 case QMetaType::Type::QString:
975 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
979 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-color type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleStrokeColor.userType() ) ) ) );
985 double circleStrokeWidth = -1.0;
986 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
988 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
989 switch ( circleStrokeWidthJson.userType() )
991 case QMetaType::Type::Int:
992 case QMetaType::Type::LongLong:
993 case QMetaType::Type::Double:
997 case QMetaType::Type::QVariantMap:
998 circleStrokeWidth = -1.0;
1002 case QMetaType::Type::QVariantList:
1003 case QMetaType::Type::QStringList:
1008 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( circleStrokeWidthJson.userType() ) ) ) );
1013 double circleStrokeOpacity = -1.0;
1014 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
1016 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
1017 switch ( jsonCircleStrokeOpacity.userType() )
1019 case QMetaType::Type::Int:
1020 case QMetaType::Type::LongLong:
1021 case QMetaType::Type::Double:
1022 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
1025 case QMetaType::Type::QVariantMap:
1029 case QMetaType::Type::QVariantList:
1030 case QMetaType::Type::QStringList:
1035 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleStrokeOpacity.userType() ) ) ) );
1039 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
1041 circleStrokeColor.setAlphaF( circleStrokeOpacity );
1045 QPointF circleTranslate;
1046 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
1048 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
1049 switch ( jsonCircleTranslate.userType() )
1052 case QMetaType::Type::QVariantMap:
1056 case QMetaType::Type::QVariantList:
1057 case QMetaType::Type::QStringList:
1063 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleTranslate.userType() ) ) ) );
1068 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
1070 Q_ASSERT( markerSymbolLayer );
1073 symbol->setOutputUnit( context.
targetUnit() );
1074 symbol->setDataDefinedProperties( ddProperties );
1076 if ( !circleTranslate.isNull() )
1078 markerSymbolLayer->
setOffset( circleTranslate );
1082 if ( circleFillColor.isValid() )
1086 if ( circleDiameter != -1 )
1088 markerSymbolLayer->
setSize( circleDiameter );
1091 if ( circleStrokeColor.isValid() )
1095 if ( circleStrokeWidth != -1 )
1108 hasLabeling =
false;
1109 hasRenderer =
false;
1111 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1113 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1116 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1117 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1123 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1129 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
1131 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
1132 switch ( jsonTextSize.userType() )
1134 case QMetaType::Type::Int:
1135 case QMetaType::Type::LongLong:
1136 case QMetaType::Type::Double:
1140 case QMetaType::Type::QVariantMap:
1146 case QMetaType::Type::QVariantList:
1147 case QMetaType::Type::QStringList:
1153 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextSize.userType() ) ) ) );
1157 if ( textSizeProperty )
1164 constexpr double EM_TO_CHARS = 2.0;
1166 double textMaxWidth = -1;
1167 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
1169 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
1170 switch ( jsonTextMaxWidth.userType() )
1172 case QMetaType::Type::Int:
1173 case QMetaType::Type::LongLong:
1174 case QMetaType::Type::Double:
1175 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1178 case QMetaType::Type::QVariantMap:
1182 case QMetaType::Type::QVariantList:
1183 case QMetaType::Type::QStringList:
1188 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-max-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextMaxWidth.userType() ) ) ) );
1195 textMaxWidth = 10 * EM_TO_CHARS;
1198 double textLetterSpacing = -1;
1199 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1201 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1202 switch ( jsonTextLetterSpacing.userType() )
1204 case QMetaType::Type::Int:
1205 case QMetaType::Type::LongLong:
1206 case QMetaType::Type::Double:
1207 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1210 case QMetaType::Type::QVariantMap:
1214 case QMetaType::Type::QVariantList:
1215 case QMetaType::Type::QStringList:
1220 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-letter-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextLetterSpacing.userType() ) ) ) );
1226 bool foundFont =
false;
1228 QString fontStyleName;
1230 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1232 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1234 QString matchedFamily;
1235 const QStringList textFontParts = fontName.split(
' ' );
1236 for (
int i = textFontParts.size() - 1; i >= 1; --i )
1238 const QString candidateFontFamily = textFontParts.mid( 0, i ).join(
' ' );
1239 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1244 family = processedFontFamily;
1245 style = candidateFontStyle;
1250 if ( processedFontFamily == matchedFamily )
1252 family = processedFontFamily;
1253 style = candidateFontStyle;
1257 family = matchedFamily;
1258 style = processedFontFamily;
1259 style.replace( matchedFamily, QString() );
1260 style = style.trimmed();
1261 if ( !style.isEmpty() && !candidateFontStyle.isEmpty() )
1263 style += QStringLiteral(
" %1" ).arg( candidateFontStyle );
1271 if ( QFontDatabase().hasFamily( processedFontFamily ) )
1274 family = processedFontFamily;
1280 family = matchedFamily;
1287 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1288 if ( jsonTextFont.userType() != QMetaType::Type::QVariantList && jsonTextFont.userType() != QMetaType::Type::QStringList && jsonTextFont.userType() != QMetaType::Type::QString
1289 && jsonTextFont.userType() != QMetaType::Type::QVariantMap )
1291 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-font type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextFont.userType() ) ) ) );
1295 switch ( jsonTextFont.userType() )
1297 case QMetaType::Type::QVariantList:
1298 case QMetaType::Type::QStringList:
1299 fontName = jsonTextFont.toList().value( 0 ).toString();
1302 case QMetaType::Type::QString:
1303 fontName = jsonTextFont.toString();
1306 case QMetaType::Type::QVariantMap:
1308 QString familyCaseString = QStringLiteral(
"CASE " );
1309 QString styleCaseString = QStringLiteral(
"CASE " );
1311 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1314 for (
int i = 0; i < stops.length() - 1; ++i )
1317 const QVariant bz = stops.value( i ).toList().value( 0 );
1318 const QString bv = stops.value( i ).toList().value( 1 ).userType() == QMetaType::Type::QString ? stops.value( i ).toList().value( 1 ).toString() : stops.value( i ).toList().value( 1 ).toList().value( 0 ).toString();
1319 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
1321 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1327 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1328 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
1330 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1335 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1337 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1338 "THEN %3 " ).arg( bz.toString(),
1341 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1342 "THEN %3 " ).arg( bz.toString(),
1348 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1354 const QString bv = stops.constLast().toList().value( 1 ).userType() == QMetaType::Type::QString ? stops.constLast().toList().value( 1 ).toString() : stops.constLast().toList().value( 1 ).toList().value( 0 ).toString();
1355 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1362 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1369 fontName = fontFamily;
1379 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1382 if ( !fontStyleName.isEmpty() )
1383 textFont.setStyleName( fontStyleName );
1393 fontName = QStringLiteral(
"Open Sans" );
1395 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1396 fontStyleName = QStringLiteral(
"Regular" );
1401 fontName = QStringLiteral(
"Arial Unicode MS" );
1403 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1404 fontStyleName = QStringLiteral(
"Regular" );
1409 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1412 if ( !foundFont && !fontName.isEmpty() )
1414 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1419 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1421 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1422 switch ( jsonTextColor.userType() )
1424 case QMetaType::Type::QVariantMap:
1428 case QMetaType::Type::QVariantList:
1429 case QMetaType::Type::QStringList:
1433 case QMetaType::Type::QString:
1434 textColor =
parseColor( jsonTextColor.toString(), context );
1438 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextColor.userType() ) ) ) );
1445 textColor = QColor( 0, 0, 0 );
1449 QColor bufferColor( 0, 0, 0, 0 );
1450 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1452 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1453 switch ( jsonBufferColor.userType() )
1455 case QMetaType::Type::QVariantMap:
1459 case QMetaType::Type::QVariantList:
1460 case QMetaType::Type::QStringList:
1464 case QMetaType::Type::QString:
1465 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1469 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonBufferColor.userType() ) ) ) );
1474 double bufferSize = 0.0;
1478 constexpr double BUFFER_SIZE_SCALE = 2.0;
1479 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1481 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1482 QString bufferSizeDataDefined;
1483 switch ( jsonHaloWidth.userType() )
1485 case QMetaType::Type::Int:
1486 case QMetaType::Type::LongLong:
1487 case QMetaType::Type::Double:
1491 case QMetaType::Type::QVariantMap:
1496 case QMetaType::Type::QVariantList:
1497 case QMetaType::Type::QStringList:
1503 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonHaloWidth.userType() ) ) ) );
1509 if ( bufferSize > 0 )
1511 if ( textSize > 0 && bufferSizeDataDefined.isEmpty() )
1513 bufferSize = std::min( bufferSize, textSize * BUFFER_SIZE_SCALE / 4 );
1515 else if ( textSize > 0 && !bufferSizeDataDefined.isEmpty() )
1517 bufferSizeDataDefined = QStringLiteral(
"min(%1/4, %2)" ).arg( textSize * BUFFER_SIZE_SCALE ).arg( bufferSizeDataDefined );
1520 else if ( !bufferSizeDataDefined.isEmpty() )
1522 bufferSizeDataDefined = QStringLiteral(
"min(%1*%2/4, %3)" )
1524 .arg( BUFFER_SIZE_SCALE )
1525 .arg( bufferSizeDataDefined );
1528 else if ( bufferSizeDataDefined.isEmpty() )
1530 bufferSizeDataDefined = QStringLiteral(
"min(%1*%2/4, %3)" )
1532 .arg( BUFFER_SIZE_SCALE )
1539 double haloBlurSize = 0;
1540 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1542 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1543 switch ( jsonTextHaloBlur.userType() )
1545 case QMetaType::Type::Int:
1546 case QMetaType::Type::LongLong:
1547 case QMetaType::Type::Double:
1554 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-blur type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextHaloBlur.userType() ) ) ) );
1561 if ( textColor.isValid() )
1563 if ( textSize >= 0 )
1568 if ( !fontStyleName.isEmpty() )
1571 if ( textLetterSpacing > 0 )
1573 QFont f = format.
font();
1574 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1578 if ( bufferSize > 0 )
1581 const double opacity = bufferColor.alphaF();
1582 bufferColor.setAlphaF( 1.0 );
1590 if ( haloBlurSize > 0 )
1606 if ( textMaxWidth > 0 )
1612 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1614 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1615 switch ( jsonTextField.userType() )
1617 case QMetaType::Type::QString:
1619 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1623 case QMetaType::Type::QVariantList:
1624 case QMetaType::Type::QStringList:
1626 const QVariantList textFieldList = jsonTextField.toList();
1634 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1637 for (
int i = 1; i < textFieldList.size(); ++i )
1639 bool isExpression =
false;
1640 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1641 if ( !isExpression )
1648 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1663 case QMetaType::Type::QVariantMap:
1665 const QVariantList stops = jsonTextField.toMap().value( QStringLiteral(
"stops" ) ).toList();
1666 if ( !stops.empty() )
1673 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field dictionary" ).arg( context.
layerId() ) );
1679 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextField.userType() ) ) ) );
1684 if ( jsonLayout.contains( QStringLiteral(
"text-rotate" ) ) )
1686 const QVariant jsonTextRotate = jsonLayout.value( QStringLiteral(
"text-rotate" ) );
1687 switch ( jsonTextRotate.userType() )
1689 case QMetaType::Type::Double:
1690 case QMetaType::Type::Int:
1692 labelSettings.
angleOffset = jsonTextRotate.toDouble();
1696 case QMetaType::Type::QVariantList:
1697 case QMetaType::Type::QStringList:
1705 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextRotate.userType() ) ) ) );
1710 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1712 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1713 if ( textTransform == QLatin1String(
"uppercase" ) )
1717 else if ( textTransform == QLatin1String(
"lowercase" ) )
1726 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1728 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1729 if ( symbolPlacement == QLatin1String(
"line" ) )
1735 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1737 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1738 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1748 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1750 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1753 switch ( jsonTextOffset.userType() )
1755 case QMetaType::Type::QVariantMap:
1756 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1757 if ( !textSizeProperty )
1768 case QMetaType::Type::QVariantList:
1769 case QMetaType::Type::QStringList:
1770 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1771 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1775 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextOffset.userType() ) ) ) );
1779 if ( !textOffset.isNull() )
1782 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1784 if ( textSizeProperty && !textOffsetProperty )
1791 if ( textOffset.isNull() )
1799 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1801 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1804 QString textAlign = QStringLiteral(
"center" );
1806 const QVariantMap conversionMap
1808 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1809 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1810 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1811 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1814 switch ( jsonTextJustify.userType() )
1816 case QMetaType::Type::QString:
1817 textAlign = jsonTextJustify.toString();
1820 case QMetaType::Type::QVariantList:
1824 case QMetaType::Type::QVariantMap:
1829 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-justify type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextJustify.userType() ) ) ) );
1833 if ( textAlign == QLatin1String(
"left" ) )
1835 else if ( textAlign == QLatin1String(
"right" ) )
1837 else if ( textAlign == QLatin1String(
"center" ) )
1839 else if ( textAlign == QLatin1String(
"follow" ) )
1849 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1851 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1854 const QVariantMap conversionMap
1856 { QStringLiteral(
"center" ), 4 },
1857 { QStringLiteral(
"left" ), 5 },
1858 { QStringLiteral(
"right" ), 3 },
1859 { QStringLiteral(
"top" ), 7 },
1860 { QStringLiteral(
"bottom" ), 1 },
1861 { QStringLiteral(
"top-left" ), 8 },
1862 { QStringLiteral(
"top-right" ), 6 },
1863 { QStringLiteral(
"bottom-left" ), 2 },
1864 { QStringLiteral(
"bottom-right" ), 0 },
1867 switch ( jsonTextAnchor.userType() )
1869 case QMetaType::Type::QString:
1870 textAnchor = jsonTextAnchor.toString();
1873 case QMetaType::Type::QVariantList:
1877 case QMetaType::Type::QVariantMap:
1882 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-anchor type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextAnchor.userType() ) ) ) );
1886 if ( textAnchor == QLatin1String(
"center" ) )
1888 else if ( textAnchor == QLatin1String(
"left" ) )
1890 else if ( textAnchor == QLatin1String(
"right" ) )
1892 else if ( textAnchor == QLatin1String(
"top" ) )
1894 else if ( textAnchor == QLatin1String(
"bottom" ) )
1896 else if ( textAnchor == QLatin1String(
"top-left" ) )
1898 else if ( textAnchor == QLatin1String(
"top-right" ) )
1900 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1902 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1907 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1909 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1912 switch ( jsonTextOffset.userType() )
1914 case QMetaType::Type::QVariantMap:
1918 case QMetaType::Type::QVariantList:
1919 case QMetaType::Type::QStringList:
1920 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1921 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1925 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextOffset.userType() ) ) ) );
1929 if ( !textOffset.isNull() )
1932 labelSettings.
xOffset = textOffset.x();
1933 labelSettings.
yOffset = textOffset.y();
1938 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1942 QString spriteProperty, spriteSizeProperty;
1944 if ( !sprite.isEmpty() )
1947 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1950 const QVariant jsonIconSize = jsonLayout.
value( QStringLiteral(
"icon-size" ) );
1951 switch ( jsonIconSize.userType() )
1953 case QMetaType::Type::Int:
1954 case QMetaType::Type::LongLong:
1955 case QMetaType::Type::Double:
1957 size = jsonIconSize.toDouble();
1958 if ( !spriteSizeProperty.isEmpty() )
1961 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
1966 case QMetaType::Type::QVariantMap:
1970 case QMetaType::Type::QVariantList:
1971 case QMetaType::Type::QStringList:
1975 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
1981 if ( !spriteSizeProperty.isEmpty() )
1995 markerLayer->
setPath( sprite );
1996 markerLayer->
setSize( spriteSize.width() );
1999 if ( !spriteProperty.isEmpty() )
2009 backgroundSettings.
setSize( spriteSize * size );
2017 if ( textSize >= 0 )
2040 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
2042 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
2045 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
2047 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
2051 double spacing = -1.0;
2052 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
2054 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
2055 switch ( jsonSpacing.userType() )
2057 case QMetaType::Type::Int:
2058 case QMetaType::Type::LongLong:
2059 case QMetaType::Type::Double:
2063 case QMetaType::Type::QVariantMap:
2067 case QMetaType::Type::QVariantList:
2068 case QMetaType::Type::QStringList:
2073 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported symbol-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonSpacing.userType() ) ) ) );
2083 bool rotateMarkers =
true;
2084 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
2086 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
2087 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
2089 rotateMarkers =
true;
2091 else if ( alignment == QLatin1String(
"viewport" ) )
2093 rotateMarkers =
false;
2098 double rotation = 0.0;
2099 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2101 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
2102 switch ( jsonIconRotate.userType() )
2104 case QMetaType::Type::Int:
2105 case QMetaType::Type::LongLong:
2106 case QMetaType::Type::Double:
2107 rotation = jsonIconRotate.toDouble();
2110 case QMetaType::Type::QVariantMap:
2114 case QMetaType::Type::QVariantList:
2115 case QMetaType::Type::QStringList:
2120 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconRotate.userType() ) ) ) );
2136 QString spriteProperty, spriteSizeProperty;
2138 if ( !sprite.isNull() )
2140 markerLayer->
setPath( sprite );
2141 markerLayer->
setSize( spriteSize.width() );
2144 if ( !spriteProperty.isEmpty() )
2151 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2153 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2156 switch ( jsonIconSize.userType() )
2158 case QMetaType::Type::Int:
2159 case QMetaType::Type::LongLong:
2160 case QMetaType::Type::Double:
2162 size = jsonIconSize.toDouble();
2163 if ( !spriteSizeProperty.isEmpty() )
2166 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2171 case QMetaType::Type::QVariantMap:
2175 case QMetaType::Type::QVariantList:
2176 case QMetaType::Type::QStringList:
2180 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
2183 markerLayer->
setSize( size * spriteSize.width() );
2186 if ( !spriteSizeProperty.isEmpty() )
2203 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
2206 symbol->setOutputUnit( context.
targetUnit() );
2210 rendererStyle.
setSymbol( symbol.release() );
2213 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
2215 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
2218 QString spriteProperty, spriteSizeProperty;
2220 if ( !sprite.isEmpty() || !spriteProperty.isEmpty() )
2223 rasterMarker->
setPath( sprite );
2224 rasterMarker->
setSize( spriteSize.width() );
2228 if ( !spriteProperty.isEmpty() )
2234 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2236 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2239 switch ( jsonIconSize.userType() )
2241 case QMetaType::Type::Int:
2242 case QMetaType::Type::LongLong:
2243 case QMetaType::Type::Double:
2245 size = jsonIconSize.toDouble();
2246 if ( !spriteSizeProperty.isEmpty() )
2249 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2254 case QMetaType::Type::QVariantMap:
2258 case QMetaType::Type::QVariantList:
2259 case QMetaType::Type::QStringList:
2263 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
2266 rasterMarker->
setSize( size * spriteSize.width() );
2269 if ( !spriteSizeProperty.isEmpty() )
2282 double rotation = 0.0;
2283 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2285 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
2286 switch ( jsonIconRotate.userType() )
2288 case QMetaType::Type::Int:
2289 case QMetaType::Type::LongLong:
2290 case QMetaType::Type::Double:
2291 rotation = jsonIconRotate.toDouble();
2294 case QMetaType::Type::QVariantMap:
2298 case QMetaType::Type::QVariantList:
2299 case QMetaType::Type::QStringList:
2304 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconRotate.userType() ) ) ) );
2309 double iconOpacity = -1.0;
2310 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2312 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2313 switch ( jsonIconOpacity.userType() )
2315 case QMetaType::Type::Int:
2316 case QMetaType::Type::LongLong:
2317 case QMetaType::Type::Double:
2318 iconOpacity = jsonIconOpacity.toDouble();
2321 case QMetaType::Type::QVariantMap:
2325 case QMetaType::Type::QVariantList:
2326 case QMetaType::Type::QStringList:
2331 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconOpacity.userType() ) ) ) );
2337 rasterMarker->
setAngle( rotation );
2338 if ( iconOpacity >= 0 )
2342 rendererStyle.
setSymbol( markerSymbol );
2353 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2354 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2355 if ( stops.empty() )
2358 QString caseString = QStringLiteral(
"CASE " );
2359 const QString colorComponent(
"color_part(%1,'%2')" );
2361 for (
int i = 0; i < stops.length() - 1; ++i )
2364 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2366 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2368 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2369 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2371 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2372 const QColor topColor =
parseColor( tcVariant.toString(), context );
2374 if ( i == 0 && bottomColor.isValid() )
2381 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2382 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2385 if ( bottomColor.isValid() && topColor.isValid() )
2397 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2398 "%3, %4, %5, %6) " ).arg( bz, tz,
2409 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2410 "%3, %4, %5, %6) " ).arg( bz, tz,
2411 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2412 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2413 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2414 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2419 const QString tz = stops.last().toList().value( 0 ).toString();
2420 const QVariant tcVariant = stops.last().toList().value( 1 );
2422 if ( tcVariant.userType() == QMetaType::Type::QString )
2425 if ( topColor.isValid() )
2432 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2433 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2436 else if ( tcVariant.userType() == QMetaType::QVariantList )
2440 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2441 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2442 .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" ) );
2445 if ( !stops.empty() && defaultColor )
2446 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2453 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2454 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2455 if ( stops.empty() )
2458 QString scaleExpression;
2459 if ( stops.size() <= 2 )
2462 stops.value( 0 ).toList().value( 0 ).toDouble(),
2463 stops.last().toList().value( 0 ).toDouble(),
2464 stops.value( 0 ).toList().value( 1 ),
2465 stops.last().toList().value( 1 ),
2466 base, multiplier, &context );
2470 scaleExpression =
parseStops( base, stops, multiplier, context );
2473 if ( !stops.empty() && defaultNumber )
2474 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2484 context = *contextPtr;
2486 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2487 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2488 if ( stops.empty() )
2491 QString scaleExpression;
2492 if ( stops.length() <= 2 )
2494 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2495 const QVariant tv = stops.last().toList().value( 1 );
2496 double bottom = 0.0;
2498 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2499 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2501 stops.value( 0 ).toList().value( 0 ).toDouble(),
2502 stops.last().toList().value( 0 ).toDouble(),
2503 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2504 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2515 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2516 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2517 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2519 for (
int i = 0; i < stops.size() - 1; ++i )
2521 const QVariant bv = stops.value( i ).toList().value( 1 );
2522 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2523 double bottom = 0.0;
2525 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2527 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2528 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2529 .arg( stops.value( i ).toList().value( 0 ).toString(),
2530 stops.value( i + 1 ).toList().value( 0 ).toString(),
2532 stops.value( i ).toList().value( 0 ).toDouble(),
2533 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2534 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2535 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2536 base, 1, &context ) );
2540 bool numeric =
false;
2541 const QVariant vv = stops.last().toList().value( 1 );
2542 double dv = vv.toDouble( &numeric );
2544 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2545 "THEN set_color_part(@symbol_color, 'alpha', %2) END" ).arg(
2546 stops.last().toList().value( 0 ).toString(),
2547 numeric ? QString::number( dv * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( vv, context ) ).arg( maxOpacity )
2554 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2555 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2556 if ( stops.empty() )
2559 QString scaleExpression;
2560 if ( stops.size() <= 2 )
2562 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2563 stops.last().toList().value( 0 ).toDouble(),
2564 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2565 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2567 stops.last().toList().value( 0 ).toDouble(),
2568 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2569 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2574 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2577 if ( !stops.empty() && defaultPoint )
2578 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2579 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2585 const QVariantMap &conversionMap, QString *defaultString )
2587 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2588 if ( stops.empty() )
2591 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2598 QString caseString = QStringLiteral(
"CASE " );
2600 for (
int i = 0; i < stops.length() - 1; ++i )
2603 const QVariant bz = stops.value( i ).toList().value( 0 );
2604 const QVariant bv = stops.value( i ).toList().value( 1 );
2605 if ( bv.userType() != QMetaType::Type::QVariantList && bv.userType() != QMetaType::Type::QStringList )
2607 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( bz.userType() ) ) ) );
2612 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2613 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2614 if ( tv.userType() != QMetaType::Type::QVariantList && tv.userType() != QMetaType::Type::QStringList )
2616 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( tz.userType() ) ) ) );
2620 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2621 "THEN array(%3,%4)" ).arg( bz.toString(),
2623 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2624 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2626 caseString += QLatin1String(
"END" );
2632 if ( stops.length() < 2 )
2635 QString caseString = QStringLiteral(
"CASE" );
2637 for (
int i = 0; i < stops.length(); ++i )
2639 caseString += QLatin1String(
" WHEN " );
2640 QStringList conditions;
2643 const QVariant bottomZoom = stops.value( i ).toList().value( 0 );
2644 conditions << QStringLiteral(
"@vector_tile_zoom > %1" ).arg( bottomZoom.toString() );
2646 if ( i < stops.length() - 1 )
2648 const QVariant topZoom = stops.value( i + 1 ).toList().value( 0 );
2649 conditions << QStringLiteral(
"@vector_tile_zoom <= %1" ).arg( topZoom.toString() );
2652 const QVariantList values = stops.value( i ).toList().value( 1 ).toList();
2653 QStringList valuesFixed;
2655 for (
const QVariant &value : values )
2657 const double number = value.toDouble( &ok );
2659 valuesFixed << QString::number( number * multiplier );
2663 caseString += QStringLiteral(
"%1 THEN array(%3)" ).arg(
2664 conditions.join( QLatin1String(
" AND " ) ),
2665 valuesFixed.join(
',' )
2668 caseString += QLatin1String(
" END" );
2674 QString caseString = QStringLiteral(
"CASE " );
2676 for (
int i = 0; i < stops.length() - 1; ++i )
2679 const QVariant bz = stops.value( i ).toList().value( 0 );
2680 const QVariant bv = stops.value( i ).toList().value( 1 );
2681 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2683 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2688 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2689 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2690 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2692 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2696 const QString lowerComparator = i == 0 ? QStringLiteral(
">=" ) : QStringLiteral(
">" );
2698 caseString += QStringLiteral(
"WHEN @vector_tile_zoom %1 %2 AND @vector_tile_zoom <= %3 "
2699 "THEN %4 " ).arg( lowerComparator,
2705 const QVariant z = stops.last().toList().value( 0 );
2706 const QVariant v = stops.last().toList().value( 1 );
2707 QString vStr = v.toString();
2708 if ( ( QMetaType::Type )v.userType() == QMetaType::QVariantList )
2711 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2712 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2716 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2717 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2725 QString caseString = QStringLiteral(
"CASE " );
2727 for (
int i = 0; i < stops.length() - 1; ++i )
2730 const QVariant bz = stops.value( i ).toList().value( 0 );
2731 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2732 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2734 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2739 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2740 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2742 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2746 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2747 "THEN %3 " ).arg( bz.toString(),
2751 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2752 stops.constLast().toList().value( 1 ) ) ) );
2753 if ( defaultString )
2754 *defaultString = stops.constLast().toList().value( 1 ).toString();
2760 QString caseString = QStringLiteral(
"CASE " );
2762 bool isExpression =
false;
2763 for (
int i = 0; i < stops.length() - 1; ++i )
2766 const QVariant bz = stops.value( i ).toList().value( 0 );
2767 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2769 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2774 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2775 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2777 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2781 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2782 if ( fieldPart.isEmpty() )
2783 fieldPart = QStringLiteral(
"''" );
2784 else if ( !isExpression )
2787 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom < %2 "
2788 "THEN %3 " ).arg( bz.toString(),
2794 const QVariant bz = stops.constLast().toList().value( 0 );
2795 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2797 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2801 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2802 if ( fieldPart.isEmpty() )
2803 fieldPart = QStringLiteral(
"''" );
2804 else if ( !isExpression )
2807 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 "
2808 "THEN %3 " ).arg( bz.toString(),
2812 QString defaultPart = processLabelField( stops.constFirst().toList().value( 1 ).toString(), isExpression );
2813 if ( defaultPart.isEmpty() )
2814 defaultPart = QStringLiteral(
"''" );
2815 else if ( !isExpression )
2817 caseString += QStringLiteral(
"ELSE %1 END" ).arg( defaultPart );
2824 const QString method = json.
value( 0 ).toString();
2825 if ( method == QLatin1String(
"interpolate" ) )
2829 else if ( method == QLatin1String(
"match" ) )
2831 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2833 else if ( method == QLatin1String(
"step" ) )
2835 return parseStepList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2845 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2846 if ( attribute.isEmpty() )
2848 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2852 QString caseString = QStringLiteral(
"CASE " );
2854 for (
int i = 2; i < json.length() - 1; i += 2 )
2857 QVariant variantKeys = json.value( i );
2858 if ( variantKeys.userType() == QMetaType::Type::QVariantList || variantKeys.userType() == QMetaType::Type::QStringList )
2859 keys = variantKeys.toList();
2861 keys = {variantKeys};
2863 QStringList matchString;
2864 for (
const QVariant &key : keys )
2869 const QVariant value = json.value( i + 1 );
2871 QString valueString;
2876 if ( value.userType() == QMetaType::Type::QVariantList || value.userType() == QMetaType::Type::QStringList )
2882 const QColor color =
parseColor( value, context );
2890 const double v = value.toDouble() * multiplier;
2891 valueString = QString::number( v );
2897 const double v = value.toDouble() * maxOpacity;
2898 valueString = QString::number( v );
2904 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2905 value.toList().value( 0 ).toDouble() * multiplier );
2911 if ( value.toList().count() == 2 && value.toList().first().toString() == QLatin1String(
"literal" ) )
2913 valueString = QStringLiteral(
"array(%1)" ).arg( value.toList().at( 1 ).toStringList().join(
',' ) );
2917 valueString = QStringLiteral(
"array(%1)" ).arg( value.toStringList().join(
',' ) );
2923 if ( matchString.count() == 1 )
2925 caseString += QStringLiteral(
"WHEN %1 IS %2 THEN %3 " ).arg( attribute, matchString.at( 0 ), valueString );
2929 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute, matchString.join(
',' ), valueString );
2933 QVariant lastValue = json.constLast();
2936 switch ( lastValue.userType() )
2938 case QMetaType::Type::QVariantList:
2939 case QMetaType::Type::QStringList:
2940 elseValue =
parseValueList( lastValue.toList(), type, context, multiplier, maxOpacity, defaultColor, defaultNumber ).
asExpression();
2949 const QColor color =
parseColor( lastValue, context );
2951 *defaultColor = color;
2959 const double v = json.constLast().toDouble() * multiplier;
2960 if ( defaultNumber )
2962 elseValue = QString::number( v );
2968 const double v = json.constLast().toDouble() * maxOpacity;
2969 if ( defaultNumber )
2971 elseValue = QString::number( v );
2977 elseValue = QStringLiteral(
"array(%1,%2)" )
2978 .arg( json.constLast().toList().value( 0 ).toDouble() * multiplier )
2979 .arg( json.constLast().toList().value( 0 ).toDouble() * multiplier );
2985 if ( json.constLast().toList().count() == 2 && json.constLast().toList().first().toString() == QLatin1String(
"literal" ) )
2987 elseValue = QStringLiteral(
"array(%1)" ).arg( json.constLast().toList().at( 1 ).toStringList().join(
',' ) );
2991 elseValue = QStringLiteral(
"array(%1)" ).arg( json.constLast().toStringList().join(
',' ) );
3001 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
3007 const QString expression =
parseExpression( json.value( 1 ).toList(), context );
3008 if ( expression.isEmpty() )
3010 context.
pushWarning( QObject::tr(
"%1: Could not interpret step list" ).arg( context.
layerId() ) );
3014 QString caseString = QStringLiteral(
"CASE " );
3017 for (
int i = json.length() - 2; i > 0; i -= 2 )
3019 const QVariant stepValue = json.value( i + 1 );
3021 QString valueString;
3022 if ( stepValue.canConvert<QVariantList>()
3034 const QColor color =
parseColor( stepValue, context );
3041 const double v = stepValue.toDouble() * multiplier;
3042 valueString = QString::number( v );
3048 const double v = stepValue.toDouble() * maxOpacity;
3049 valueString = QString::number( v );
3055 valueString = QStringLiteral(
"array(%1,%2)" ).arg(
3056 stepValue.toList().value( 0 ).toDouble() * multiplier ).arg(
3057 stepValue.toList().value( 0 ).toDouble() * multiplier
3064 if ( stepValue.toList().count() == 2 && stepValue.toList().first().toString() == QLatin1String(
"literal" ) )
3066 valueString = QStringLiteral(
"array(%1)" ).arg( stepValue.toList().at( 1 ).toStringList().join(
',' ) );
3070 valueString = QStringLiteral(
"array(%1)" ).arg( stepValue.toStringList().join(
',' ) );
3080 caseString += QStringLiteral(
" WHEN %1 >= %2 THEN (%3) " ).arg( expression, stepKey, valueString );
3084 caseString += QStringLiteral(
"ELSE (%1) END" ).arg( valueString );
3092 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
3094 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
3099 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
3100 if ( technique == QLatin1String(
"linear" ) )
3102 else if ( technique == QLatin1String(
"exponential" ) )
3103 base = json.value( 1 ).toList(). value( 1 ).toDouble();
3104 else if ( technique == QLatin1String(
"cubic-bezier" ) )
3106 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
3111 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
3115 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
3117 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
3123 for (
int i = 3; i < json.length(); i += 2 )
3125 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
3129 props.insert( QStringLiteral(
"stops" ), stops );
3130 props.insert( QStringLiteral(
"base" ), base );
3146 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported numeric array in interpolate" ).arg( context.
layerId() ) );
3155 if ( ( QMetaType::Type )colorExpression.userType() == QMetaType::QVariantList )
3159 return parseValue( colorExpression, context,
true );
3164 if ( color.userType() != QMetaType::Type::QString )
3166 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
3175 hue = std::max( 0, color.hslHue() );
3176 saturation = color.hslSaturation() / 255.0 * 100;
3177 lightness = color.lightness() / 255.0 * 100;
3178 alpha = color.alpha();
3186 context = *contextPtr;
3190 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
3192 bool minDoubleOk =
true;
3193 const double min = valueMin.toDouble( &minDoubleOk );
3194 bool maxDoubleOk =
true;
3195 const double max = valueMax.toDouble( &maxDoubleOk );
3196 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
3198 return QString::number( min * multiplier );
3202 QString minValueExpr = valueMin.toString();
3203 QString maxValueExpr = valueMax.toString();
3204 if ( valueMin.userType() == QMetaType::Type::QVariantList )
3208 if ( valueMax.userType() == QMetaType::Type::QVariantList )
3214 if ( minValueExpr == maxValueExpr )
3216 expression = minValueExpr;
3222 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin ).arg( zoomMax ).arg( minValueExpr ).arg( maxValueExpr );
3226 expression = QStringLiteral(
"scale_exponential(@vector_tile_zoom,%1,%2,%3,%4,%5)" ).arg( zoomMin ).arg( zoomMax ).arg( minValueExpr ).arg( maxValueExpr ).arg( base );
3230 if ( multiplier != 1 )
3231 return QStringLiteral(
"(%1) * %2" ).arg( expression ).arg( multiplier );
3238 if ( style == QLatin1String(
"round" ) )
3239 return Qt::RoundCap;
3240 else if ( style == QLatin1String(
"square" ) )
3241 return Qt::SquareCap;
3248 if ( style == QLatin1String(
"bevel" ) )
3249 return Qt::BevelJoin;
3250 else if ( style == QLatin1String(
"round" ) )
3251 return Qt::RoundJoin;
3253 return Qt::MiterJoin;
3258 QString op = expression.value( 0 ).toString();
3259 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
3261 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ),
3263 parseValue( expression.value( 2 ), context ) );
3265 else if ( op == QLatin1String(
"to-number" ) )
3267 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
3269 if ( op == QLatin1String(
"literal" ) )
3271 return expression.value( 1 ).toString();
3273 else if ( op == QLatin1String(
"all" )
3274 || op == QLatin1String(
"any" )
3275 || op == QLatin1String(
"none" ) )
3278 for (
int i = 1; i < expression.size(); ++i )
3280 const QString part = parseValue( expression.at( i ), context );
3281 if ( part.isEmpty() )
3283 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3289 if ( op == QLatin1String(
"none" ) )
3290 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
3292 QString operatorString;
3293 if ( op == QLatin1String(
"all" ) )
3294 operatorString = QStringLiteral(
") AND (" );
3295 else if ( op == QLatin1String(
"any" ) )
3296 operatorString = QStringLiteral(
") OR (" );
3298 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
3300 else if ( op ==
'!' )
3303 QVariantList contraJsonExpr = expression.value( 1 ).toList();
3304 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
3306 return parseKey( contraJsonExpr, context );
3308 else if ( op == QLatin1String(
"==" )
3309 || op == QLatin1String(
"!=" )
3310 || op == QLatin1String(
">=" )
3312 || op == QLatin1String(
"<=" )
3316 if ( op == QLatin1String(
"==" ) )
3317 op = QStringLiteral(
"IS" );
3318 else if ( op == QLatin1String(
"!=" ) )
3319 op = QStringLiteral(
"IS NOT" );
3320 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
3321 op, parseValue( expression.value( 2 ), context ) );
3323 else if ( op == QLatin1String(
"has" ) )
3325 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
3327 else if ( op == QLatin1String(
"!has" ) )
3329 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
3331 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
3333 const QString key = parseKey( expression.value( 1 ), context );
3336 QVariantList values = expression.mid( 2 );
3337 if ( expression.size() == 3
3338 && expression.at( 2 ).userType() == QMetaType::Type::QVariantList && expression.at( 2 ).toList().count() > 1
3339 && expression.at( 2 ).toList().at( 0 ).toString() == QStringLiteral(
"literal" ) )
3341 values = expression.at( 2 ).toList().at( 1 ).toList();
3344 for (
const QVariant &value : std::as_const( values ) )
3346 const QString part = parseValue( value, context );
3347 if ( part.isEmpty() )
3349 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3354 if ( op == QLatin1String(
"in" ) )
3355 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3357 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3359 else if ( op == QLatin1String(
"get" ) )
3361 return parseKey( expression.value( 1 ), context );
3363 else if ( op == QLatin1String(
"match" ) )
3365 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
3367 if ( expression.size() == 5
3368 && expression.at( 3 ).userType() == QMetaType::Type::Bool && expression.at( 3 ).toBool() ==
true
3369 && expression.at( 4 ).userType() == QMetaType::Type::Bool && expression.at( 4 ).toBool() ==
false )
3372 if ( expression.at( 2 ).userType() == QMetaType::Type::QVariantList || expression.at( 2 ).userType() == QMetaType::Type::QStringList )
3375 for (
const QVariant &p : expression.at( 2 ).toList() )
3377 parts << parseValue( p, context );
3380 if ( parts.size() > 1 )
3385 else if ( expression.at( 2 ).userType() == QMetaType::Type::QString || expression.at( 2 ).userType() == QMetaType::Type::Int
3386 || expression.at( 2 ).userType() == QMetaType::Type::Double || expression.at( 2 ).userType() == QMetaType::Type::LongLong )
3392 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3398 QString caseString = QStringLiteral(
"CASE " );
3399 for (
int i = 2; i < expression.size() - 2; i += 2 )
3401 if ( expression.at( i ).userType() == QMetaType::Type::QVariantList || expression.at( i ).userType() == QMetaType::Type::QStringList )
3404 for (
const QVariant &p : expression.at( i ).toList() )
3409 if ( parts.size() > 1 )
3414 else if ( expression.at( i ).userType() == QMetaType::Type::QString || expression.at( i ).userType() == QMetaType::Type::Int
3415 || expression.at( i ).userType() == QMetaType::Type::Double || expression.at( i ).userType() == QMetaType::Type::LongLong )
3420 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
3422 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
3426 else if ( op == QLatin1String(
"to-string" ) )
3428 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3430 else if ( op == QLatin1String(
"case" ) )
3432 QString caseString = QStringLiteral(
"CASE" );
3433 for (
int i = 1; i < expression.size() - 2; i += 2 )
3435 const QString condition =
parseExpression( expression.value( i ).toList(), context );
3436 const QString value = parseValue( expression.value( i + 1 ), context );
3437 caseString += QStringLiteral(
" WHEN (%1) THEN %2" ).arg( condition, value );
3439 const QString value = parseValue( expression.constLast(), context );
3440 caseString += QStringLiteral(
" ELSE %1 END" ).arg( value );
3443 else if ( op == QLatin1String(
"zoom" ) && expression.count() == 1 )
3445 return QStringLiteral(
"@vector_tile_zoom" );
3447 else if ( op == QLatin1String(
"concat" ) )
3449 QString concatString = QStringLiteral(
"concat(" );
3450 for (
int i = 1; i < expression.size(); i++ )
3453 concatString += QLatin1String(
", " );
3454 concatString += parseValue( expression.value( i ), context );
3456 concatString += QLatin1Char(
')' );
3457 return concatString;
3459 else if ( op == QLatin1String(
"length" ) )
3461 return QStringLiteral(
"length(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3463 else if ( op == QLatin1String(
"step" ) )
3465 const QString stepExpression =
parseExpression( expression.value( 1 ).toList(), context );
3466 if ( stepExpression.isEmpty() )
3468 context.
pushWarning( QObject::tr(
"%1: Could not interpret step list" ).arg( context.
layerId() ) );
3472 QString caseString = QStringLiteral(
"CASE " );
3474 for (
int i = expression.length() - 2; i > 0; i -= 2 )
3476 const QString stepValue = parseValue( expression.value( i + 1 ), context, colorExpected );
3480 caseString += QStringLiteral(
" WHEN %1 >= %2 THEN (%3) " ).arg( stepExpression, stepKey, stepValue );
3484 caseString += QStringLiteral(
"ELSE (%1) END" ).arg( stepValue );
3491 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression \"%2\"" ).arg( context.
layerId(), op ) );
3500 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3504 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
3505 if ( spriteDefinition.size() == 0 )
3507 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3511 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
3512 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
3513 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
3514 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
3515 if ( sprite.isNull() )
3517 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3521 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
3529 auto prepareBase64 = [](
const QImage & sprite )
3532 if ( !sprite.isNull() )
3535 QBuffer buffer( &blob );
3536 buffer.open( QIODevice::WriteOnly );
3537 sprite.save( &buffer,
"PNG" );
3539 const QByteArray encoded = blob.toBase64();
3540 path = QString( encoded );
3541 path.prepend( QLatin1String(
"base64:" ) );
3546 switch ( value.userType() )
3548 case QMetaType::Type::QString:
3550 QString spriteName = value.toString();
3551 const thread_local QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
3552 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
3553 if ( match.hasMatch() )
3555 const QString fieldName = match.captured( 1 );
3556 spriteProperty = QStringLiteral(
"CASE" );
3557 spriteSizeProperty = QStringLiteral(
"CASE" );
3559 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
3560 spriteName.replace(
")", QLatin1String(
"\\)" ) );
3561 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
3562 const QRegularExpression fieldValueMatch( spriteName );
3564 for (
const QString &name : spriteNames )
3566 match = fieldValueMatch.match( name );
3567 if ( match.hasMatch() )
3571 const QString fieldValue = match.captured( 1 );
3573 path = prepareBase64( sprite );
3574 if ( spritePath.isEmpty() && !path.isEmpty() )
3580 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
3581 .arg( fieldName, fieldValue, path );
3582 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
3583 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
3587 spriteProperty += QLatin1String(
" END" );
3588 spriteSizeProperty += QLatin1String(
" END" );
3592 spriteProperty.clear();
3593 spriteSizeProperty.clear();
3594 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
3595 spritePath = prepareBase64( sprite );
3600 case QMetaType::Type::QVariantMap:
3602 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3603 if ( stops.size() == 0 )
3610 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3611 spritePath = prepareBase64( sprite );
3613 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3614 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3616 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3617 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3618 .arg( spriteSize.width() );
3620 for (
int i = 0; i < stops.size() - 1; ++i )
3623 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3624 path = prepareBase64( sprite );
3626 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3628 .arg( stops.value( i ).toList().value( 0 ).toString(),
3629 stops.value( i + 1 ).toList().value( 0 ).toString(),
3631 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3633 .arg( stops.value( i ).toList().value( 0 ).toString(),
3634 stops.value( i + 1 ).toList().value( 0 ).toString() )
3635 .arg( size.width() );
3637 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3638 path = prepareBase64( sprite );
3640 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3642 .arg( stops.last().toList().value( 0 ).toString() )
3644 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3646 .arg( stops.last().toList().value( 0 ).toString() )
3647 .arg( size.width() );
3651 case QMetaType::Type::QVariantList:
3653 const QVariantList json = value.toList();
3654 const QString method = json.value( 0 ).toString();
3656 if ( method == QLatin1String(
"match" ) )
3658 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3659 if ( attribute.isEmpty() )
3661 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3665 spriteProperty = QStringLiteral(
"CASE" );
3666 spriteSizeProperty = QStringLiteral(
"CASE" );
3668 for (
int i = 2; i < json.length() - 1; i += 2 )
3670 const QVariant matchKey = json.value( i );
3671 const QVariant matchValue = json.value( i + 1 );
3672 QString matchString;
3673 switch ( matchKey.userType() )
3675 case QMetaType::Type::QVariantList:
3676 case QMetaType::Type::QStringList:
3678 const QVariantList keys = matchKey.toList();
3679 QStringList matchStringList;
3680 for (
const QVariant &key : keys )
3684 matchString = matchStringList.join(
',' );
3688 case QMetaType::Type::Bool:
3689 case QMetaType::Type::QString:
3690 case QMetaType::Type::Int:
3691 case QMetaType::Type::LongLong:
3692 case QMetaType::Type::Double:
3699 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( value.userType() ) ) ) );
3704 const QImage sprite =
retrieveSprite( matchValue.toString(), context, spriteSize );
3705 spritePath = prepareBase64( sprite );
3707 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3708 "THEN '%3'" ).arg( attribute,
3712 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3713 "THEN %3" ).arg( attribute,
3714 matchString ).arg( spriteSize.width() );
3717 if ( !json.constLast().toString().isEmpty() )
3719 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3720 spritePath = prepareBase64( sprite );
3724 spritePath = QString();
3727 spriteProperty += QStringLiteral(
" ELSE '%1' END" ).arg( spritePath );
3728 spriteSizeProperty += QStringLiteral(
" ELSE %3 END" ).arg( spriteSize.width() );
3731 else if ( method == QLatin1String(
"step" ) )
3733 const QString expression =
parseExpression( json.value( 1 ).toList(), context );
3734 if ( expression.isEmpty() )
3736 context.
pushWarning( QObject::tr(
"%1: Could not interpret step list" ).arg( context.
layerId() ) );
3740 spriteProperty = QStringLiteral(
"CASE" );
3741 spriteSizeProperty = QStringLiteral(
"CASE" );
3742 for (
int i = json.length() - 2; i > 2; i -= 2 )
3745 const QString stepValue = json.value( i + 1 ).toString();
3747 const QImage sprite =
retrieveSprite( stepValue, context, spriteSize );
3748 spritePath = prepareBase64( sprite );
3750 spriteProperty += QStringLiteral(
" WHEN %1 >= %2 THEN '%3' " ).arg( expression, stepKey, spritePath );
3751 spriteSizeProperty += QStringLiteral(
" WHEN %1 >= %2 THEN %3 " ).arg( expression ).arg( stepKey ).arg( spriteSize.width() );
3754 const QImage sprite =
retrieveSprite( json.at( 2 ).toString(), context, spriteSize );
3755 spritePath = prepareBase64( sprite );
3757 spriteProperty += QStringLiteral(
"ELSE '%1' END" ).arg( spritePath );
3758 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3761 else if ( method == QLatin1String(
"case" ) )
3763 spriteProperty = QStringLiteral(
"CASE" );
3764 spriteSizeProperty = QStringLiteral(
"CASE" );
3765 for (
int i = 1; i < json.length() - 2; i += 2 )
3767 const QString caseExpression =
parseExpression( json.value( i ).toList(), context );
3768 const QString caseValue = json.value( i + 1 ).toString();
3770 const QImage sprite =
retrieveSprite( caseValue, context, spriteSize );
3771 spritePath = prepareBase64( sprite );
3773 spriteProperty += QStringLiteral(
" WHEN %1 THEN '%2' " ).arg( caseExpression, spritePath );
3774 spriteSizeProperty += QStringLiteral(
" WHEN %1 THEN %2 " ).arg( caseExpression ).arg( spriteSize.width() );
3776 const QImage sprite =
retrieveSprite( json.last().toString(), context, spriteSize );
3777 spritePath = prepareBase64( sprite );
3779 spriteProperty += QStringLiteral(
"ELSE '%1' END" ).arg( spritePath );
3780 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3785 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3791 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( value.userType() ) ) ) );
3801 switch ( value.userType() )
3803 case QMetaType::Type::QVariantList:
3804 case QMetaType::Type::QStringList:
3807 case QMetaType::Type::Bool:
3808 case QMetaType::Type::QString:
3809 if ( colorExpected )
3814 return parseValue(
c, context );
3819 case QMetaType::Type::Int:
3820 case QMetaType::Type::LongLong:
3821 case QMetaType::Type::Double:
3822 return value.toString();
3824 case QMetaType::Type::QColor:
3825 c = value.value<QColor>();
3826 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3829 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3837 if ( value.toString() == QLatin1String(
"$type" ) )
3839 return QStringLiteral(
"_geom_type" );
3841 if ( value.toString() == QLatin1String(
"level" ) )
3843 return QStringLiteral(
"level" );
3845 else if ( ( value.userType() == QMetaType::Type::QVariantList && value.toList().size() == 1 ) || value.userType() == QMetaType::Type::QStringList )
3847 if ( value.toList().size() > 1 )
3848 return value.toList().at( 1 ).toString();
3851 QString valueString = value.toList().value( 0 ).toString();
3852 if ( valueString == QLatin1String(
"geometry-type" ) )
3854 return QStringLiteral(
"_geom_type" );
3859 else if ( value.userType() == QMetaType::Type::QVariantList && value.toList().size() > 1 )
3866QString QgsMapBoxGlStyleConverter::processLabelField(
const QString &
string,
bool &isExpression )
3870 const thread_local QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
3871 const QRegularExpressionMatch match = singleFieldRx.match(
string );
3872 if ( match.hasMatch() )
3874 isExpression =
false;
3875 return match.captured( 1 );
3878 const thread_local QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
3879 const QStringList parts =
string.split( multiFieldRx );
3880 if ( parts.size() > 1 )
3882 isExpression =
true;
3885 for (
const QString &part : parts )
3887 if ( part.isEmpty() )
3890 if ( !part.contains(
'{' ) )
3897 const QStringList split = part.split(
'}' );
3899 if ( !split.at( 1 ).isEmpty() )
3902 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
3906 isExpression =
false;
3913 return mRenderer ? mRenderer->clone() :
nullptr;
3918 return mLabeling ? mLabeling->clone() :
nullptr;
3928 return mRasterSubLayers;
3933 QList<QgsMapLayer *> subLayers;
3936 const QString sourceName = subLayer.source();
3937 std::unique_ptr< QgsRasterLayer > rl;
3944 rl->pipe()->setDataDefinedProperties( subLayer.dataDefinedProperties() );
3951 subLayers.append( rl.release() );
3960 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3963 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3964 context = tmpContext.get();
3969 if (
string.compare( QLatin1String(
"vector" ), Qt::CaseInsensitive ) == 0 )
3971 else if (
string.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
3973 else if (
string.compare( QLatin1String(
"raster-dem" ), Qt::CaseInsensitive ) == 0 )
3975 else if (
string.compare( QLatin1String(
"geojson" ), Qt::CaseInsensitive ) == 0 )
3977 else if (
string.compare( QLatin1String(
"image" ), Qt::CaseInsensitive ) == 0 )
3979 else if (
string.compare( QLatin1String(
"video" ), Qt::CaseInsensitive ) == 0 )
3981 context->
pushWarning( QObject::tr(
"Invalid source type \"%1\" for source \"%2\"" ).arg(
string, name ) );
3987 const QString name = it.key();
3988 const QVariantMap jsonSource = it.value().toMap();
3989 const QString typeString = jsonSource.value( QStringLiteral(
"type" ) ).toString();
4012 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
4015 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
4016 context = tmpContext.get();
4019 std::unique_ptr< QgsMapBoxGlStyleRasterSource > raster = std::make_unique< QgsMapBoxGlStyleRasterSource >( name );
4020 if ( raster->setFromJson( source, context ) )
4021 mSources.append( raster.release() );
4024bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
4026 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
4028 bool bDoubleOk, tDoubleOk;
4029 bottom = bottomVariant.toDouble( &bDoubleOk );
4030 top = topVariant.toDouble( &tDoubleOk );
4031 return ( bDoubleOk && tDoubleOk );
4042 mWarnings << warning;
4057 return mSizeConversionFactor;
4062 mSizeConversionFactor = sizeConversionFactor;
4067 return mSpriteImage;
4072 return mSpriteDefinitions;
4077 mSpriteImage = image;
4078 mSpriteDefinitions = definitions;
4128 mAttribution = json.value( QStringLiteral(
"attribution" ) ).toString();
4130 const QString scheme = json.value( QStringLiteral(
"scheme" ), QStringLiteral(
"xyz" ) ).toString();
4131 if ( scheme.compare( QLatin1String(
"xyz" ) ) == 0 )
4137 context->
pushWarning( QObject::tr(
"%1 scheme is not supported for raster source %2" ).arg( scheme,
name() ) );
4141 mMinZoom = json.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"0" ) ).toInt();
4142 mMaxZoom = json.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"22" ) ).toInt();
4143 mTileSize = json.value( QStringLiteral(
"tileSize" ), QStringLiteral(
"512" ) ).toInt();
4145 const QVariantList
tiles = json.value( QStringLiteral(
"tiles" ) ).toList();
4146 for (
const QVariant &tile :
tiles )
4148 mTiles.append( tile.toString() );
4157 parts.insert( QStringLiteral(
"type" ), QStringLiteral(
"xyz" ) );
4158 parts.insert( QStringLiteral(
"url" ), mTiles.value( 0 ) );
4160 if ( mTileSize == 256 )
4161 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"1" ) );
4162 else if ( mTileSize == 512 )
4163 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"2" ) );
4165 parts.insert( QStringLiteral(
"zmax" ), QString::number( mMaxZoom ) );
4166 parts.insert( QStringLiteral(
"zmin" ), QString::number( mMinZoom ) );
4168 std::unique_ptr< QgsRasterLayer > rl = std::make_unique< QgsRasterLayer >(
QgsProviderRegistry::instance()->encodeUri( QStringLiteral(
"wms" ), parts ),
name(), QStringLiteral(
"wms" ) );
4169 return rl.release();
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
@ OnLine
Labels can be placed directly over a line feature.
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ 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.
@ FollowPlacement
Alignment follows placement of label, e.g., labels to the left of a feature will be drawn with right ...
RenderUnit
Rendering size units.
MapBoxGlStyleSourceType
Available MapBox GL style source types.
@ 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, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
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 QFont createFont(const QString &family, int pointSize=-1, int weight=-1, bool italic=false)
Creates a font with the specified family.
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(Qgis::LabelLinePlacementFlags 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,...
void setQuadrant(Qgis::LabelQuadrantPosition quadrant)
Sets the quadrant in which to offset labels from the point.
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.
@ NumericArray
Numeric array for dash arrays or such.
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 parseStepList(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 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 QString retrieveSpriteAsBase64WithProperties(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...
static QgsProperty parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
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::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
int priority
Label priority.
double angleOffset
Label rotation, in degrees clockwise.
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.
@ LinePlacementOptions
Line placement flags.
@ LabelRotation
Label rotation.
@ FontStyle
Font style name.
@ FontLetterSpacing
Letter spacing.
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...
const QgsLabelPointSettings & pointSettings() const
Returns the label point settings, which contain settings related to how the label engine places and f...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const final
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 final
Returns true if the collection contains an active property with the specified key.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
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.
void setExpressionString(const QString &expression)
Sets the expression to use for the property value.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
A class for filling symbols with a repeated raster image.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the unit for the image's width and height.
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 setWidth(double width)
Sets the width for scaling the image used in 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.
@ RendererOpacity
Raster renderer global opacity.
Renders polygons using a single fill and stroke color.
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 setStrokeWidth(double strokeWidth)
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,...
@ File
Filename, eg for svg files.
@ CustomDash
Custom dash pattern.
@ Name
Name, eg shape name for simple markers.
@ StrokeColor
Stroke color.
@ Interval
Line marker interval.
@ StrokeWidth
Stroke width.
@ LayerEnabled
Whether symbol layer is enabled.
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.
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 setOpacity(double opacity)
Sets the buffer opacity.
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)
#define QgsDebugError(str)
QList< QgsSymbolLayer * > QgsSymbolLayerList