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;
407 const QString sprite =
retrieveSpriteAsBase64( fillPatternJson, context, spriteSize, 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;
499 rasterLineSprite =
retrieveSpriteAsBase64( jsonLinePattern, context, spriteSize, 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;
624 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
626 const QVariant jsonLineOpacity = jsonPaint.value( QStringLiteral(
"line-opacity" ) );
627 switch ( jsonLineOpacity.userType() )
629 case QMetaType::Type::Int:
630 case QMetaType::Type::LongLong:
631 case QMetaType::Type::Double:
632 lineOpacity = jsonLineOpacity.toDouble();
635 case QMetaType::Type::QVariantMap:
638 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
646 case QMetaType::Type::QVariantList:
647 case QMetaType::Type::QStringList:
650 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
659 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineOpacity.userType() ) ) ) );
664 QVector< double > dashVector;
665 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
667 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
668 switch ( jsonLineDashArray.userType() )
670 case QMetaType::Type::QVariantMap:
672 QString arrayExpression;
675 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
676 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
681 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
685 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
686 for (
const QVariant &v : dashSource )
688 dashVector << v.toDouble() * lineWidth;
693 case QMetaType::Type::QVariantList:
694 case QMetaType::Type::QStringList:
696 const QVariantList dashSource = jsonLineDashArray.toList();
698 QVector< double > rawDashVectorSizes;
699 rawDashVectorSizes.reserve( dashSource.size() );
700 for (
const QVariant &v : dashSource )
702 rawDashVectorSizes << v.toDouble();
706 if ( rawDashVectorSizes.size() == 1 )
709 rawDashVectorSizes.clear();
711 else if ( rawDashVectorSizes.size() % 2 == 1 )
715 rawDashVectorSizes[0] = rawDashVectorSizes[0] + rawDashVectorSizes[rawDashVectorSizes.size() - 1];
716 rawDashVectorSizes.resize( rawDashVectorSizes.size() - 1 );
719 if ( !rawDashVectorSizes.isEmpty() && ( !lineWidthProperty.
asExpression().isEmpty() ) )
721 QStringList dashArrayStringParts;
722 dashArrayStringParts.reserve( rawDashVectorSizes.size() );
723 for (
double v : std::as_const( rawDashVectorSizes ) )
728 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
729 .arg( dashArrayStringParts.join(
',' ),
735 for (
double v : std::as_const( rawDashVectorSizes ) )
737 dashVector << v *lineWidth;
744 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-dasharray type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineDashArray.userType() ) ) ) );
749 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
750 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
751 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
753 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
754 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
756 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
758 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
760 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
764 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
765 symbol->setOutputUnit( context.
targetUnit() );
767 if ( !rasterLineSprite.isEmpty() )
777 if ( lineOpacity != -1 )
779 symbol->setOpacity( lineOpacity );
781 if ( lineWidth != -1 )
785 symbol->changeSymbolLayer( 0, lineSymbol );
790 Q_ASSERT( lineSymbol );
800 if ( lineOpacity != -1 )
802 symbol->setOpacity( lineOpacity );
804 if ( lineColor.isValid() )
808 if ( lineWidth != -1 )
812 if ( !dashVector.empty() )
826 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
828 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
832 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
836 QColor circleFillColor;
837 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
839 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
840 switch ( jsonCircleColor.userType() )
842 case QMetaType::Type::QVariantMap:
846 case QMetaType::Type::QVariantList:
847 case QMetaType::Type::QStringList:
851 case QMetaType::Type::QString:
852 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
856 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleColor.userType() ) ) ) );
863 circleFillColor = QColor( 0, 0, 0 );
867 double circleDiameter = 10.0;
868 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
870 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
871 switch ( jsonCircleRadius.userType() )
873 case QMetaType::Type::Int:
874 case QMetaType::Type::LongLong:
875 case QMetaType::Type::Double:
879 case QMetaType::Type::QVariantMap:
884 case QMetaType::Type::QVariantList:
885 case QMetaType::Type::QStringList:
890 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-radius type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleRadius.userType() ) ) ) );
895 double circleOpacity = -1.0;
896 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
898 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
899 switch ( jsonCircleOpacity.userType() )
901 case QMetaType::Type::Int:
902 case QMetaType::Type::LongLong:
903 case QMetaType::Type::Double:
904 circleOpacity = jsonCircleOpacity.toDouble();
907 case QMetaType::Type::QVariantMap:
911 case QMetaType::Type::QVariantList:
912 case QMetaType::Type::QStringList:
917 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleOpacity.userType() ) ) ) );
921 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
923 circleFillColor.setAlphaF( circleOpacity );
927 QColor circleStrokeColor;
928 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
930 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
931 switch ( jsonCircleStrokeColor.userType() )
933 case QMetaType::Type::QVariantMap:
937 case QMetaType::Type::QVariantList:
938 case QMetaType::Type::QStringList:
942 case QMetaType::Type::QString:
943 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
947 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-color type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleStrokeColor.userType() ) ) ) );
953 double circleStrokeWidth = -1.0;
954 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
956 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
957 switch ( circleStrokeWidthJson.userType() )
959 case QMetaType::Type::Int:
960 case QMetaType::Type::LongLong:
961 case QMetaType::Type::Double:
965 case QMetaType::Type::QVariantMap:
966 circleStrokeWidth = -1.0;
970 case QMetaType::Type::QVariantList:
971 case QMetaType::Type::QStringList:
976 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( circleStrokeWidthJson.userType() ) ) ) );
981 double circleStrokeOpacity = -1.0;
982 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
984 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
985 switch ( jsonCircleStrokeOpacity.userType() )
987 case QMetaType::Type::Int:
988 case QMetaType::Type::LongLong:
989 case QMetaType::Type::Double:
990 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
993 case QMetaType::Type::QVariantMap:
997 case QMetaType::Type::QVariantList:
998 case QMetaType::Type::QStringList:
1003 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleStrokeOpacity.userType() ) ) ) );
1007 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
1009 circleStrokeColor.setAlphaF( circleStrokeOpacity );
1013 QPointF circleTranslate;
1014 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
1016 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
1017 switch ( jsonCircleTranslate.userType() )
1020 case QMetaType::Type::QVariantMap:
1024 case QMetaType::Type::QVariantList:
1025 case QMetaType::Type::QStringList:
1031 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleTranslate.userType() ) ) ) );
1036 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
1038 Q_ASSERT( markerSymbolLayer );
1041 symbol->setOutputUnit( context.
targetUnit() );
1042 symbol->setDataDefinedProperties( ddProperties );
1044 if ( !circleTranslate.isNull() )
1046 markerSymbolLayer->
setOffset( circleTranslate );
1050 if ( circleFillColor.isValid() )
1054 if ( circleDiameter != -1 )
1056 markerSymbolLayer->
setSize( circleDiameter );
1059 if ( circleStrokeColor.isValid() )
1063 if ( circleStrokeWidth != -1 )
1076 hasLabeling =
false;
1077 hasRenderer =
false;
1079 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1081 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1084 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1085 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1091 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1097 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
1099 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
1100 switch ( jsonTextSize.userType() )
1102 case QMetaType::Type::Int:
1103 case QMetaType::Type::LongLong:
1104 case QMetaType::Type::Double:
1108 case QMetaType::Type::QVariantMap:
1114 case QMetaType::Type::QVariantList:
1115 case QMetaType::Type::QStringList:
1121 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextSize.userType() ) ) ) );
1125 if ( textSizeProperty )
1132 constexpr double EM_TO_CHARS = 2.0;
1134 double textMaxWidth = -1;
1135 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
1137 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
1138 switch ( jsonTextMaxWidth.userType() )
1140 case QMetaType::Type::Int:
1141 case QMetaType::Type::LongLong:
1142 case QMetaType::Type::Double:
1143 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1146 case QMetaType::Type::QVariantMap:
1150 case QMetaType::Type::QVariantList:
1151 case QMetaType::Type::QStringList:
1156 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-max-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextMaxWidth.userType() ) ) ) );
1163 textMaxWidth = 10 * EM_TO_CHARS;
1166 double textLetterSpacing = -1;
1167 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1169 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1170 switch ( jsonTextLetterSpacing.userType() )
1172 case QMetaType::Type::Int:
1173 case QMetaType::Type::LongLong:
1174 case QMetaType::Type::Double:
1175 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1178 case QMetaType::Type::QVariantMap:
1182 case QMetaType::Type::QVariantList:
1183 case QMetaType::Type::QStringList:
1188 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-letter-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextLetterSpacing.userType() ) ) ) );
1194 bool foundFont =
false;
1196 QString fontStyleName;
1198 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1200 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1202 QString matchedFamily;
1203 const QStringList textFontParts = fontName.split(
' ' );
1204 for (
int i = textFontParts.size() - 1; i >= 1; --i )
1206 const QString candidateFontFamily = textFontParts.mid( 0, i ).join(
' ' );
1207 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1212 family = processedFontFamily;
1213 style = candidateFontStyle;
1218 if ( processedFontFamily == matchedFamily )
1220 family = processedFontFamily;
1221 style = candidateFontStyle;
1225 family = matchedFamily;
1226 style = processedFontFamily;
1227 style.replace( matchedFamily, QString() );
1228 style = style.trimmed();
1229 if ( !style.isEmpty() && !candidateFontStyle.isEmpty() )
1231 style += QStringLiteral(
" %1" ).arg( candidateFontStyle );
1239 if ( QFontDatabase().hasFamily( processedFontFamily ) )
1242 family = processedFontFamily;
1248 family = matchedFamily;
1255 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1256 if ( jsonTextFont.userType() != QMetaType::Type::QVariantList && jsonTextFont.userType() != QMetaType::Type::QStringList && jsonTextFont.userType() != QMetaType::Type::QString
1257 && jsonTextFont.userType() != QMetaType::Type::QVariantMap )
1259 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-font type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextFont.userType() ) ) ) );
1263 switch ( jsonTextFont.userType() )
1265 case QMetaType::Type::QVariantList:
1266 case QMetaType::Type::QStringList:
1267 fontName = jsonTextFont.toList().value( 0 ).toString();
1270 case QMetaType::Type::QString:
1271 fontName = jsonTextFont.toString();
1274 case QMetaType::Type::QVariantMap:
1276 QString familyCaseString = QStringLiteral(
"CASE " );
1277 QString styleCaseString = QStringLiteral(
"CASE " );
1279 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1282 for (
int i = 0; i < stops.length() - 1; ++i )
1285 const QVariant bz = stops.value( i ).toList().value( 0 );
1286 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();
1287 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
1289 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1295 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1296 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
1298 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1303 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1305 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1306 "THEN %3 " ).arg( bz.toString(),
1309 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1310 "THEN %3 " ).arg( bz.toString(),
1316 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1322 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();
1323 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1330 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1337 fontName = fontFamily;
1347 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1350 if ( !fontStyleName.isEmpty() )
1351 textFont.setStyleName( fontStyleName );
1361 fontName = QStringLiteral(
"Open Sans" );
1363 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1364 fontStyleName = QStringLiteral(
"Regular" );
1369 fontName = QStringLiteral(
"Arial Unicode MS" );
1371 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1372 fontStyleName = QStringLiteral(
"Regular" );
1377 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1380 if ( !foundFont && !fontName.isEmpty() )
1382 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1387 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1389 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1390 switch ( jsonTextColor.userType() )
1392 case QMetaType::Type::QVariantMap:
1396 case QMetaType::Type::QVariantList:
1397 case QMetaType::Type::QStringList:
1401 case QMetaType::Type::QString:
1402 textColor =
parseColor( jsonTextColor.toString(), context );
1406 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextColor.userType() ) ) ) );
1413 textColor = QColor( 0, 0, 0 );
1417 QColor bufferColor( 0, 0, 0, 0 );
1418 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1420 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1421 switch ( jsonBufferColor.userType() )
1423 case QMetaType::Type::QVariantMap:
1427 case QMetaType::Type::QVariantList:
1428 case QMetaType::Type::QStringList:
1432 case QMetaType::Type::QString:
1433 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1437 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonBufferColor.userType() ) ) ) );
1442 double bufferSize = 0.0;
1446 constexpr double BUFFER_SIZE_SCALE = 2.0;
1447 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1449 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1450 switch ( jsonHaloWidth.userType() )
1452 case QMetaType::Type::Int:
1453 case QMetaType::Type::LongLong:
1454 case QMetaType::Type::Double:
1458 case QMetaType::Type::QVariantMap:
1463 case QMetaType::Type::QVariantList:
1464 case QMetaType::Type::QStringList:
1470 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonHaloWidth.userType() ) ) ) );
1475 double haloBlurSize = 0;
1476 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1478 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1479 switch ( jsonTextHaloBlur.userType() )
1481 case QMetaType::Type::Int:
1482 case QMetaType::Type::LongLong:
1483 case QMetaType::Type::Double:
1490 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-blur type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextHaloBlur.userType() ) ) ) );
1497 if ( textColor.isValid() )
1499 if ( textSize >= 0 )
1504 if ( !fontStyleName.isEmpty() )
1507 if ( textLetterSpacing > 0 )
1509 QFont f = format.
font();
1510 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1514 if ( bufferSize > 0 )
1517 const double opacity = bufferColor.alphaF();
1518 bufferColor.setAlphaF( 1.0 );
1526 if ( haloBlurSize > 0 )
1542 if ( textMaxWidth > 0 )
1548 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1550 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1551 switch ( jsonTextField.userType() )
1553 case QMetaType::Type::QString:
1555 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1559 case QMetaType::Type::QVariantList:
1560 case QMetaType::Type::QStringList:
1562 const QVariantList textFieldList = jsonTextField.toList();
1570 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1573 for (
int i = 1; i < textFieldList.size(); ++i )
1575 bool isExpression =
false;
1576 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1577 if ( !isExpression )
1584 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1599 case QMetaType::Type::QVariantMap:
1601 const QVariantList stops = jsonTextField.toMap().value( QStringLiteral(
"stops" ) ).toList();
1602 if ( !stops.empty() )
1609 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field dictionary" ).arg( context.
layerId() ) );
1615 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextField.userType() ) ) ) );
1620 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1622 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1623 if ( textTransform == QLatin1String(
"uppercase" ) )
1627 else if ( textTransform == QLatin1String(
"lowercase" ) )
1636 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1638 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1639 if ( symbolPlacement == QLatin1String(
"line" ) )
1645 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1647 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1648 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1658 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1660 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1663 switch ( jsonTextOffset.userType() )
1665 case QMetaType::Type::QVariantMap:
1666 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1667 if ( !textSizeProperty )
1678 case QMetaType::Type::QVariantList:
1679 case QMetaType::Type::QStringList:
1680 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1681 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1685 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextOffset.userType() ) ) ) );
1689 if ( !textOffset.isNull() )
1692 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1694 if ( textSizeProperty && !textOffsetProperty )
1701 if ( textOffset.isNull() )
1709 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1711 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1714 QString textAlign = QStringLiteral(
"center" );
1716 const QVariantMap conversionMap
1718 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1719 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1720 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1721 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1724 switch ( jsonTextJustify.userType() )
1726 case QMetaType::Type::QString:
1727 textAlign = jsonTextJustify.toString();
1730 case QMetaType::Type::QVariantList:
1734 case QMetaType::Type::QVariantMap:
1739 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-justify type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextJustify.userType() ) ) ) );
1743 if ( textAlign == QLatin1String(
"left" ) )
1745 else if ( textAlign == QLatin1String(
"right" ) )
1747 else if ( textAlign == QLatin1String(
"center" ) )
1749 else if ( textAlign == QLatin1String(
"follow" ) )
1759 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1761 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1764 const QVariantMap conversionMap
1766 { QStringLiteral(
"center" ), 4 },
1767 { QStringLiteral(
"left" ), 5 },
1768 { QStringLiteral(
"right" ), 3 },
1769 { QStringLiteral(
"top" ), 7 },
1770 { QStringLiteral(
"bottom" ), 1 },
1771 { QStringLiteral(
"top-left" ), 8 },
1772 { QStringLiteral(
"top-right" ), 6 },
1773 { QStringLiteral(
"bottom-left" ), 2 },
1774 { QStringLiteral(
"bottom-right" ), 0 },
1777 switch ( jsonTextAnchor.userType() )
1779 case QMetaType::Type::QString:
1780 textAnchor = jsonTextAnchor.toString();
1783 case QMetaType::Type::QVariantList:
1787 case QMetaType::Type::QVariantMap:
1792 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-anchor type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextAnchor.userType() ) ) ) );
1796 if ( textAnchor == QLatin1String(
"center" ) )
1798 else if ( textAnchor == QLatin1String(
"left" ) )
1800 else if ( textAnchor == QLatin1String(
"right" ) )
1802 else if ( textAnchor == QLatin1String(
"top" ) )
1804 else if ( textAnchor == QLatin1String(
"bottom" ) )
1806 else if ( textAnchor == QLatin1String(
"top-left" ) )
1808 else if ( textAnchor == QLatin1String(
"top-right" ) )
1810 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1812 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1817 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1819 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1822 switch ( jsonTextOffset.userType() )
1824 case QMetaType::Type::QVariantMap:
1828 case QMetaType::Type::QVariantList:
1829 case QMetaType::Type::QStringList:
1830 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1831 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1835 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextOffset.userType() ) ) ) );
1839 if ( !textOffset.isNull() )
1842 labelSettings.
xOffset = textOffset.x();
1843 labelSettings.
yOffset = textOffset.y();
1848 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1852 QString spriteProperty, spriteSizeProperty;
1853 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1854 if ( !sprite.isEmpty() )
1857 markerLayer->
setPath( sprite );
1858 markerLayer->
setSize( spriteSize.width() );
1861 if ( !spriteProperty.isEmpty() )
1873 backgroundSettings.
setSize( spriteSize );
1881 if ( textSize >= 0 )
1904 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1906 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1909 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1911 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1915 double spacing = -1.0;
1916 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
1918 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
1919 switch ( jsonSpacing.userType() )
1921 case QMetaType::Type::Int:
1922 case QMetaType::Type::LongLong:
1923 case QMetaType::Type::Double:
1927 case QMetaType::Type::QVariantMap:
1931 case QMetaType::Type::QVariantList:
1932 case QMetaType::Type::QStringList:
1937 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported symbol-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonSpacing.userType() ) ) ) );
1947 bool rotateMarkers =
true;
1948 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
1950 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
1951 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
1953 rotateMarkers =
true;
1955 else if ( alignment == QLatin1String(
"viewport" ) )
1957 rotateMarkers =
false;
1962 double rotation = 0.0;
1963 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
1965 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
1966 switch ( jsonIconRotate.userType() )
1968 case QMetaType::Type::Int:
1969 case QMetaType::Type::LongLong:
1970 case QMetaType::Type::Double:
1971 rotation = jsonIconRotate.toDouble();
1974 case QMetaType::Type::QVariantMap:
1978 case QMetaType::Type::QVariantList:
1979 case QMetaType::Type::QStringList:
1984 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconRotate.userType() ) ) ) );
2000 QString spriteProperty, spriteSizeProperty;
2001 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
2002 if ( !sprite.isNull() )
2004 markerLayer->
setPath( sprite );
2005 markerLayer->
setSize( spriteSize.width() );
2008 if ( !spriteProperty.isEmpty() )
2015 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2017 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2020 switch ( jsonIconSize.userType() )
2022 case QMetaType::Type::Int:
2023 case QMetaType::Type::LongLong:
2024 case QMetaType::Type::Double:
2026 size = jsonIconSize.toDouble();
2027 if ( !spriteSizeProperty.isEmpty() )
2030 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2035 case QMetaType::Type::QVariantMap:
2039 case QMetaType::Type::QVariantList:
2040 case QMetaType::Type::QStringList:
2042 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
2045 markerLayer->
setSize( size * spriteSize.width() );
2048 if ( !spriteSizeProperty.isEmpty() )
2065 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
2068 symbol->setOutputUnit( context.
targetUnit() );
2072 rendererStyle.
setSymbol( symbol.release() );
2075 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
2077 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
2080 QString spriteProperty, spriteSizeProperty;
2081 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
2082 if ( !sprite.isEmpty() )
2085 rasterMarker->
setPath( sprite );
2086 rasterMarker->
setSize( spriteSize.width() );
2090 if ( !spriteProperty.isEmpty() )
2096 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2098 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2101 switch ( jsonIconSize.userType() )
2103 case QMetaType::Type::Int:
2104 case QMetaType::Type::LongLong:
2105 case QMetaType::Type::Double:
2107 size = jsonIconSize.toDouble();
2108 if ( !spriteSizeProperty.isEmpty() )
2111 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2116 case QMetaType::Type::QVariantMap:
2120 case QMetaType::Type::QVariantList:
2121 case QMetaType::Type::QStringList:
2123 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
2126 rasterMarker->
setSize( size * spriteSize.width() );
2129 if ( !spriteSizeProperty.isEmpty() )
2142 double rotation = 0.0;
2143 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2145 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
2146 switch ( jsonIconRotate.userType() )
2148 case QMetaType::Type::Int:
2149 case QMetaType::Type::LongLong:
2150 case QMetaType::Type::Double:
2151 rotation = jsonIconRotate.toDouble();
2154 case QMetaType::Type::QVariantMap:
2158 case QMetaType::Type::QVariantList:
2159 case QMetaType::Type::QStringList:
2164 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconRotate.userType() ) ) ) );
2169 double iconOpacity = -1.0;
2170 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2172 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2173 switch ( jsonIconOpacity.userType() )
2175 case QMetaType::Type::Int:
2176 case QMetaType::Type::LongLong:
2177 case QMetaType::Type::Double:
2178 iconOpacity = jsonIconOpacity.toDouble();
2181 case QMetaType::Type::QVariantMap:
2185 case QMetaType::Type::QVariantList:
2186 case QMetaType::Type::QStringList:
2191 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconOpacity.userType() ) ) ) );
2197 rasterMarker->
setAngle( rotation );
2198 if ( iconOpacity >= 0 )
2202 rendererStyle.
setSymbol( markerSymbol );
2213 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2214 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2215 if ( stops.empty() )
2218 QString caseString = QStringLiteral(
"CASE " );
2219 const QString colorComponent(
"color_part(%1,'%2')" );
2221 for (
int i = 0; i < stops.length() - 1; ++i )
2224 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2226 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2228 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2229 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2231 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2232 const QColor topColor =
parseColor( tcVariant.toString(), context );
2234 if ( i == 0 && bottomColor.isValid() )
2241 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2242 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2245 if ( bottomColor.isValid() && topColor.isValid() )
2257 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2258 "%3, %4, %5, %6) " ).arg( bz, tz,
2269 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2270 "%3, %4, %5, %6) " ).arg( bz, tz,
2271 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2272 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2273 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2274 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2279 const QString tz = stops.last().toList().value( 0 ).toString();
2280 const QVariant tcVariant = stops.last().toList().value( 1 );
2281 const QColor topColor =
parseColor( stops.last().toList().value( 1 ), context );
2282 if ( topColor.isValid() )
2289 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2290 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2296 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2297 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2298 .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" ) );
2301 if ( !stops.empty() && defaultColor )
2302 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2309 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2310 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2311 if ( stops.empty() )
2314 QString scaleExpression;
2315 if ( stops.size() <= 2 )
2318 stops.last().toList().value( 0 ).toDouble(),
2319 stops.value( 0 ).toList().value( 1 ),
2320 stops.last().toList().value( 1 ), base, multiplier, &context );
2324 scaleExpression =
parseStops( base, stops, multiplier, context );
2327 if ( !stops.empty() && defaultNumber )
2328 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2338 context = *contextPtr;
2340 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2341 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2342 if ( stops.empty() )
2345 QString scaleExpression;
2346 if ( stops.length() <= 2 )
2348 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2349 const QVariant tv = stops.last().toList().value( 1 );
2350 double bottom = 0.0;
2352 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2353 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2355 stops.last().toList().value( 0 ).toDouble(),
2356 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2357 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2368 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2369 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2370 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2372 for (
int i = 0; i < stops.size() - 1; ++i )
2374 const QVariant bv = stops.value( i ).toList().value( 1 );
2375 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2376 double bottom = 0.0;
2378 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2380 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2381 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2382 .arg( stops.value( i ).toList().value( 0 ).toString(),
2383 stops.value( i + 1 ).toList().value( 0 ).toString(),
2385 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2386 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2387 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2388 base, 1, &context ) );
2391 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2392 "THEN set_color_part(@symbol_color, 'alpha', %2) END" )
2393 .arg( stops.last().toList().value( 0 ).toString() )
2394 .arg( stops.last().toList().value( 1 ).toDouble() * maxOpacity );
2400 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2401 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2402 if ( stops.empty() )
2405 QString scaleExpression;
2406 if ( stops.size() <= 2 )
2408 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2409 stops.last().toList().value( 0 ).toDouble(),
2410 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2411 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2413 stops.last().toList().value( 0 ).toDouble(),
2414 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2415 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2420 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2423 if ( !stops.empty() && defaultPoint )
2424 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2425 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2431 const QVariantMap &conversionMap, QString *defaultString )
2433 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2434 if ( stops.empty() )
2437 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2444 QString caseString = QStringLiteral(
"CASE " );
2446 for (
int i = 0; i < stops.length() - 1; ++i )
2449 const QVariant bz = stops.value( i ).toList().value( 0 );
2450 const QVariant bv = stops.value( i ).toList().value( 1 );
2451 if ( bv.userType() != QMetaType::Type::QVariantList && bv.userType() != QMetaType::Type::QStringList )
2453 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( bz.userType() ) ) ) );
2458 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2459 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2460 if ( tv.userType() != QMetaType::Type::QVariantList && tv.userType() != QMetaType::Type::QStringList )
2462 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( tz.userType() ) ) ) );
2466 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2467 "THEN array(%3,%4)" ).arg( bz.toString(),
2469 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2470 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2472 caseString += QLatin1String(
"END" );
2478 if ( stops.length() < 2 )
2481 QString caseString = QStringLiteral(
"CASE" );
2483 for (
int i = 0; i < stops.length(); ++i )
2485 caseString += QLatin1String(
" WHEN " );
2486 QStringList conditions;
2489 const QVariant bottomZoom = stops.value( i ).toList().value( 0 );
2490 conditions << QStringLiteral(
"@vector_tile_zoom > %1" ).arg( bottomZoom.toString() );
2492 if ( i < stops.length() - 1 )
2494 const QVariant topZoom = stops.value( i + 1 ).toList().value( 0 );
2495 conditions << QStringLiteral(
"@vector_tile_zoom <= %1" ).arg( topZoom.toString() );
2498 const QVariantList values = stops.value( i ).toList().value( 1 ).toList();
2499 QStringList valuesFixed;
2501 for (
const QVariant &value : values )
2503 const double number = value.toDouble( &ok );
2505 valuesFixed << QString::number( number * multiplier );
2509 caseString += QStringLiteral(
"%1 THEN array(%3)" ).arg(
2510 conditions.join( QStringLiteral(
" AND " ) ),
2511 valuesFixed.join(
',' )
2514 caseString += QLatin1String(
" END" );
2520 QString caseString = QStringLiteral(
"CASE " );
2522 for (
int i = 0; i < stops.length() - 1; ++i )
2525 const QVariant bz = stops.value( i ).toList().value( 0 );
2526 const QVariant bv = stops.value( i ).toList().value( 1 );
2527 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2529 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2534 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2535 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2536 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2538 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2542 const QString lowerComparator = i == 0 ? QStringLiteral(
">=" ) : QStringLiteral(
">" );
2544 caseString += QStringLiteral(
"WHEN @vector_tile_zoom %1 %2 AND @vector_tile_zoom <= %3 "
2545 "THEN %4 " ).arg( lowerComparator,
2551 const QVariant z = stops.last().toList().value( 0 );
2552 const QVariant v = stops.last().toList().value( 1 );
2553 QString vStr = v.toString();
2554 if ( ( QMetaType::Type )v.userType() == QMetaType::QVariantList )
2557 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2558 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2562 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2563 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2571 QString caseString = QStringLiteral(
"CASE " );
2573 for (
int i = 0; i < stops.length() - 1; ++i )
2576 const QVariant bz = stops.value( i ).toList().value( 0 );
2577 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2578 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2580 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2585 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2586 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2588 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2592 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2593 "THEN %3 " ).arg( bz.toString(),
2597 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2598 stops.constLast().toList().value( 1 ) ) ) );
2599 if ( defaultString )
2600 *defaultString = stops.constLast().toList().value( 1 ).toString();
2606 QString caseString = QStringLiteral(
"CASE " );
2608 bool isExpression =
false;
2609 for (
int i = 0; i < stops.length() - 1; ++i )
2612 const QVariant bz = stops.value( i ).toList().value( 0 );
2613 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2615 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2620 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2621 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2623 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2627 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2628 if ( fieldPart.isEmpty() )
2629 fieldPart = QStringLiteral(
"''" );
2630 else if ( !isExpression )
2633 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom < %2 "
2634 "THEN %3 " ).arg( bz.toString(),
2640 const QVariant bz = stops.constLast().toList().value( 0 );
2641 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2643 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2647 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2648 if ( fieldPart.isEmpty() )
2649 fieldPart = QStringLiteral(
"''" );
2650 else if ( !isExpression )
2653 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 "
2654 "THEN %3 " ).arg( bz.toString(),
2658 QString defaultPart = processLabelField( stops.constFirst().toList().value( 1 ).toString(), isExpression );
2659 if ( defaultPart.isEmpty() )
2660 defaultPart = QStringLiteral(
"''" );
2661 else if ( !isExpression )
2663 caseString += QStringLiteral(
"ELSE %1 END" ).arg( defaultPart );
2670 const QString method = json.
value( 0 ).toString();
2671 if ( method == QLatin1String(
"interpolate" ) )
2675 else if ( method == QLatin1String(
"match" ) )
2677 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2687 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2688 if ( attribute.isEmpty() )
2690 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2694 QString caseString = QStringLiteral(
"CASE " );
2696 for (
int i = 2; i < json.length() - 1; i += 2 )
2699 QVariant variantKeys = json.value( i );
2700 if ( variantKeys.canConvert< QVariantList >() )
2701 keys = variantKeys.toList();
2703 keys = {variantKeys};
2705 QStringList matchString;
2706 for (
const QVariant &key : keys )
2711 const QVariant value = json.value( i + 1 );
2713 QString valueString;
2718 const QColor color =
parseColor( value, context );
2725 const double v = value.toDouble() * multiplier;
2726 valueString = QString::number( v );
2732 const double v = value.toDouble() * maxOpacity;
2733 valueString = QString::number( v );
2739 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2740 value.toList().value( 0 ).toDouble() * multiplier );
2746 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
2747 matchString.join(
',' ), valueString );
2756 const QColor color =
parseColor( json.constLast(), context );
2758 *defaultColor = color;
2766 const double v = json.constLast().toDouble() * multiplier;
2767 if ( defaultNumber )
2769 elseValue = QString::number( v );
2775 const double v = json.constLast().toDouble() * maxOpacity;
2776 if ( defaultNumber )
2778 elseValue = QString::number( v );
2784 elseValue = QStringLiteral(
"array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
2785 json.constLast().toList().value( 0 ).toDouble() * multiplier );
2791 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
2797 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
2799 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
2804 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
2805 if ( technique == QLatin1String(
"linear" ) )
2807 else if ( technique == QLatin1String(
"exponential" ) )
2808 base = json.value( 1 ).toList(). value( 1 ).toDouble();
2809 else if ( technique == QLatin1String(
"cubic-bezier" ) )
2811 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
2816 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
2820 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
2822 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
2828 for (
int i = 3; i < json.length(); i += 2 )
2830 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
2834 props.insert( QStringLiteral(
"stops" ), stops );
2835 props.insert( QStringLiteral(
"base" ), base );
2855 if ( ( QMetaType::Type )colorExpression.userType() == QMetaType::QVariantList )
2859 return parseValue( colorExpression, context,
true );
2864 if ( color.userType() != QMetaType::Type::QString )
2866 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
2875 hue = std::max( 0, color.hslHue() );
2876 saturation = color.hslSaturation() / 255.0 * 100;
2877 lightness = color.lightness() / 255.0 * 100;
2878 alpha = color.alpha();
2886 context = *contextPtr;
2890 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
2892 bool minDoubleOk =
true;
2893 const double min = valueMin.toDouble( &minDoubleOk );
2894 bool maxDoubleOk =
true;
2895 const double max = valueMax.toDouble( &maxDoubleOk );
2896 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
2898 return QString::number( min * multiplier );
2902 QString minValueExpr = valueMin.toString();
2903 QString maxValueExpr = valueMax.toString();
2904 if ( valueMin.userType() == QMetaType::Type::QVariantList )
2908 if ( valueMax.userType() == QMetaType::Type::QVariantList )
2914 if ( minValueExpr == maxValueExpr )
2916 expression = minValueExpr;
2922 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin )
2924 .arg( minValueExpr )
2925 .arg( maxValueExpr );
2931 QString ratioExpr = QStringLiteral(
"(%1^(@vector_tile_zoom - %2) - 1) / (%1^(%3 - %2) - 1)" ).arg( base ).arg( zoomMin ).arg( zoomMax );
2932 expression = QStringLiteral(
"(%1) + (%2) * ((%3) - (%1))" ).arg( minValueExpr ).arg( ratioExpr ).arg( maxValueExpr );
2942 if ( multiplier != 1 )
2943 return QStringLiteral(
"(%1) * %2" ).arg( expression ).arg( multiplier );
2950 if ( style == QLatin1String(
"round" ) )
2951 return Qt::RoundCap;
2952 else if ( style == QLatin1String(
"square" ) )
2953 return Qt::SquareCap;
2960 if ( style == QLatin1String(
"bevel" ) )
2961 return Qt::BevelJoin;
2962 else if ( style == QLatin1String(
"round" ) )
2963 return Qt::RoundJoin;
2965 return Qt::MiterJoin;
2970 QString op = expression.value( 0 ).toString();
2971 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
2973 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ) ).arg( op ).arg( parseValue( expression.value( 2 ), context ) );
2975 else if ( op == QLatin1String(
"to-number" ) )
2977 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
2979 if ( op == QLatin1String(
"literal" ) )
2981 return expression.value( 1 ).toString();
2983 else if ( op == QLatin1String(
"all" )
2984 || op == QLatin1String(
"any" )
2985 || op == QLatin1String(
"none" ) )
2988 for (
int i = 1; i < expression.size(); ++i )
2990 const QString part = parseValue( expression.at( i ), context );
2991 if ( part.isEmpty() )
2993 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2999 if ( op == QLatin1String(
"none" ) )
3000 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
3002 QString operatorString;
3003 if ( op == QLatin1String(
"all" ) )
3004 operatorString = QStringLiteral(
") AND (" );
3005 else if ( op == QLatin1String(
"any" ) )
3006 operatorString = QStringLiteral(
") OR (" );
3008 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
3010 else if ( op ==
'!' )
3013 QVariantList contraJsonExpr = expression.value( 1 ).toList();
3014 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
3016 return parseKey( contraJsonExpr, context );
3018 else if ( op == QLatin1String(
"==" )
3019 || op == QLatin1String(
"!=" )
3020 || op == QLatin1String(
">=" )
3022 || op == QLatin1String(
"<=" )
3026 if ( op == QLatin1String(
"==" ) )
3027 op = QStringLiteral(
"IS" );
3028 else if ( op == QLatin1String(
"!=" ) )
3029 op = QStringLiteral(
"IS NOT" );
3030 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
3031 op, parseValue( expression.value( 2 ), context ) );
3033 else if ( op == QLatin1String(
"has" ) )
3035 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
3037 else if ( op == QLatin1String(
"!has" ) )
3039 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
3041 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
3043 const QString key = parseKey( expression.value( 1 ), context );
3045 for (
int i = 2; i < expression.size(); ++i )
3047 const QString part = parseValue( expression.at( i ), context );
3048 if ( part.isEmpty() )
3050 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3055 if ( op == QLatin1String(
"in" ) )
3056 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3058 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3060 else if ( op == QLatin1String(
"get" ) )
3062 return parseKey( expression.value( 1 ), context );
3064 else if ( op == QLatin1String(
"match" ) )
3066 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
3068 if ( expression.size() == 5
3069 && expression.at( 3 ).userType() == QMetaType::Type::Bool && expression.at( 3 ).toBool() ==
true
3070 && expression.at( 4 ).userType() == QMetaType::Type::Bool && expression.at( 4 ).toBool() ==
false )
3073 if ( expression.at( 2 ).userType() == QMetaType::Type::QVariantList || expression.at( 2 ).userType() == QMetaType::Type::QStringList )
3076 for (
const QVariant &p : expression.at( 2 ).toList() )
3078 parts << parseValue( p, context );
3081 if ( parts.size() > 1 )
3086 else if ( expression.at( 2 ).userType() == QMetaType::Type::QString || expression.at( 2 ).userType() == QMetaType::Type::Int
3087 || expression.at( 2 ).userType() == QMetaType::Type::Double || expression.at( 2 ).userType() == QMetaType::Type::LongLong )
3093 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3099 QString caseString = QStringLiteral(
"CASE " );
3100 for (
int i = 2; i < expression.size() - 2; i += 2 )
3102 if ( expression.at( i ).userType() == QMetaType::Type::QVariantList || expression.at( i ).userType() == QMetaType::Type::QStringList )
3105 for (
const QVariant &p : expression.at( i ).toList() )
3110 if ( parts.size() > 1 )
3115 else if ( expression.at( i ).userType() == QMetaType::Type::QString || expression.at( i ).userType() == QMetaType::Type::Int
3116 || expression.at( i ).userType() == QMetaType::Type::Double || expression.at( i ).userType() == QMetaType::Type::LongLong )
3121 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
3123 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
3127 else if ( op == QLatin1String(
"to-string" ) )
3129 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3131 else if ( op == QLatin1String(
"case" ) )
3133 QString caseString = QStringLiteral(
"CASE" );
3134 for (
int i = 1; i < expression.size() - 2; i += 2 )
3136 const QString condition =
parseExpression( expression.value( i ).toList(), context );
3137 const QString value = parseValue( expression.value( i + 1 ), context );
3138 caseString += QStringLiteral(
" WHEN (%1) THEN %2" ).arg( condition, value );
3140 const QString value = parseValue( expression.constLast(), context );
3141 caseString += QStringLiteral(
" ELSE %1 END" ).arg( value );
3146 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3155 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3159 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
3160 if ( spriteDefinition.size() == 0 )
3162 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3166 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
3167 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
3168 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
3169 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
3170 if ( sprite.isNull() )
3172 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3176 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
3184 auto prepareBase64 = [](
const QImage & sprite )
3187 if ( !sprite.isNull() )
3190 QBuffer buffer( &blob );
3191 buffer.open( QIODevice::WriteOnly );
3192 sprite.save( &buffer,
"PNG" );
3194 const QByteArray encoded = blob.toBase64();
3195 path = QString( encoded );
3196 path.prepend( QLatin1String(
"base64:" ) );
3201 switch ( value.userType() )
3203 case QMetaType::Type::QString:
3205 QString spriteName = value.toString();
3206 const thread_local QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
3207 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
3208 if ( match.hasMatch() )
3210 const QString fieldName = match.captured( 1 );
3211 spriteProperty = QStringLiteral(
"CASE" );
3212 spriteSizeProperty = QStringLiteral(
"CASE" );
3214 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
3215 spriteName.replace(
")", QLatin1String(
"\\)" ) );
3216 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
3217 const QRegularExpression fieldValueMatch( spriteName );
3219 for (
const QString &name : spriteNames )
3221 match = fieldValueMatch.match( name );
3222 if ( match.hasMatch() )
3226 const QString fieldValue = match.captured( 1 );
3228 path = prepareBase64( sprite );
3229 if ( spritePath.isEmpty() && !path.isEmpty() )
3235 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
3236 .arg( fieldName, fieldValue, path );
3237 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
3238 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
3242 spriteProperty += QLatin1String(
" END" );
3243 spriteSizeProperty += QLatin1String(
" END" );
3247 spriteProperty.clear();
3248 spriteSizeProperty.clear();
3249 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
3250 spritePath = prepareBase64( sprite );
3255 case QMetaType::Type::QVariantMap:
3257 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3258 if ( stops.size() == 0 )
3265 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3266 spritePath = prepareBase64( sprite );
3268 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3269 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3271 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3272 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3273 .arg( spriteSize.width() );
3275 for (
int i = 0; i < stops.size() - 1; ++i )
3278 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3279 path = prepareBase64( sprite );
3281 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3283 .arg( stops.value( i ).toList().value( 0 ).toString(),
3284 stops.value( i + 1 ).toList().value( 0 ).toString(),
3286 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3288 .arg( stops.value( i ).toList().value( 0 ).toString(),
3289 stops.value( i + 1 ).toList().value( 0 ).toString() )
3290 .arg( size.width() );
3292 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3293 path = prepareBase64( sprite );
3295 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3297 .arg( stops.last().toList().value( 0 ).toString() )
3299 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3301 .arg( stops.last().toList().value( 0 ).toString() )
3302 .arg( size.width() );
3306 case QMetaType::Type::QVariantList:
3308 const QVariantList json = value.toList();
3309 const QString method = json.value( 0 ).toString();
3310 if ( method != QLatin1String(
"match" ) )
3312 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3316 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3317 if ( attribute.isEmpty() )
3319 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3323 spriteProperty = QStringLiteral(
"CASE " );
3324 spriteSizeProperty = QStringLiteral(
"CASE " );
3326 for (
int i = 2; i < json.length() - 1; i += 2 )
3328 const QVariantList keys = json.value( i ).toList();
3330 QStringList matchString;
3331 for (
const QVariant &key : keys )
3336 const QVariant value = json.value( i + 1 );
3338 const QImage sprite =
retrieveSprite( value.toString(), context, spriteSize );
3339 spritePath = prepareBase64( sprite );
3341 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3342 "THEN '%3' " ).arg( attribute,
3343 matchString.join(
',' ),
3346 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3347 "THEN %3 " ).arg( attribute,
3348 matchString.join(
',' ) ).arg( spriteSize.width() );
3351 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3352 spritePath = prepareBase64( sprite );
3354 spriteProperty += QStringLiteral(
"ELSE %1 END" ).arg( spritePath );
3355 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3360 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( value.userType() ) ) ) );
3370 switch ( value.userType() )
3372 case QMetaType::Type::QVariantList:
3373 case QMetaType::Type::QStringList:
3376 case QMetaType::Type::Bool:
3377 case QMetaType::Type::QString:
3378 if ( colorExpected )
3383 return parseValue(
c, context );
3388 case QMetaType::Type::Int:
3389 case QMetaType::Type::LongLong:
3390 case QMetaType::Type::Double:
3391 return value.toString();
3393 case QMetaType::Type::QColor:
3394 c = value.value<QColor>();
3395 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3398 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3406 if ( value.toString() == QLatin1String(
"$type" ) )
3408 return QStringLiteral(
"_geom_type" );
3410 if ( value.toString() == QLatin1String(
"level" ) )
3412 return QStringLiteral(
"level" );
3414 else if ( ( value.userType() == QMetaType::Type::QVariantList && value.toList().size() == 1 ) || value.userType() == QMetaType::Type::QStringList )
3416 if ( value.toList().size() > 1 )
3417 return value.toList().at( 1 ).toString();
3420 QString valueString = value.toList().value( 0 ).toString();
3421 if ( valueString == QLatin1String(
"geometry-type" ) )
3423 return QStringLiteral(
"_geom_type" );
3428 else if ( value.userType() == QMetaType::Type::QVariantList && value.toList().size() > 1 )
3435QString QgsMapBoxGlStyleConverter::processLabelField(
const QString &
string,
bool &isExpression )
3439 const thread_local QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
3440 const QRegularExpressionMatch match = singleFieldRx.match(
string );
3441 if ( match.hasMatch() )
3443 isExpression =
false;
3444 return match.captured( 1 );
3447 const thread_local QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
3448 const QStringList parts =
string.split( multiFieldRx );
3449 if ( parts.size() > 1 )
3451 isExpression =
true;
3454 for (
const QString &part : parts )
3456 if ( part.isEmpty() )
3459 if ( !part.contains(
'{' ) )
3466 const QStringList split = part.split(
'}' );
3468 if ( !split.at( 1 ).isEmpty() )
3471 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
3475 isExpression =
false;
3482 return mRenderer ? mRenderer->clone() :
nullptr;
3487 return mLabeling ? mLabeling->clone() :
nullptr;
3497 return mRasterSubLayers;
3502 QList<QgsMapLayer *> subLayers;
3505 const QString sourceName = subLayer.source();
3506 std::unique_ptr< QgsRasterLayer > rl;
3513 rl->pipe()->setDataDefinedProperties( subLayer.dataDefinedProperties() );
3520 subLayers.append( rl.release() );
3529 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3532 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3533 context = tmpContext.get();
3538 if (
string.compare( QLatin1String(
"vector" ), Qt::CaseInsensitive ) == 0 )
3540 else if (
string.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
3542 else if (
string.compare( QLatin1String(
"raster-dem" ), Qt::CaseInsensitive ) == 0 )
3544 else if (
string.compare( QLatin1String(
"geojson" ), Qt::CaseInsensitive ) == 0 )
3546 else if (
string.compare( QLatin1String(
"image" ), Qt::CaseInsensitive ) == 0 )
3548 else if (
string.compare( QLatin1String(
"video" ), Qt::CaseInsensitive ) == 0 )
3550 context->
pushWarning( QObject::tr(
"Invalid source type \"%1\" for source \"%2\"" ).arg(
string, name ) );
3556 const QString name = it.key();
3557 const QVariantMap jsonSource = it.value().toMap();
3558 const QString typeString = jsonSource.value( QStringLiteral(
"type" ) ).toString();
3581 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3584 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3585 context = tmpContext.get();
3588 std::unique_ptr< QgsMapBoxGlStyleRasterSource > raster = std::make_unique< QgsMapBoxGlStyleRasterSource >( name );
3589 if ( raster->setFromJson( source, context ) )
3590 mSources.append( raster.release() );
3593bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
3595 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
3597 bool bDoubleOk, tDoubleOk;
3598 bottom = bottomVariant.toDouble( &bDoubleOk );
3599 top = topVariant.toDouble( &tDoubleOk );
3600 return ( bDoubleOk && tDoubleOk );
3611 mWarnings << warning;
3626 return mSizeConversionFactor;
3631 mSizeConversionFactor = sizeConversionFactor;
3636 return mSpriteImage;
3641 return mSpriteDefinitions;
3646 mSpriteImage = image;
3647 mSpriteDefinitions = definitions;
3697 mAttribution = json.value( QStringLiteral(
"attribution" ) ).toString();
3699 const QString scheme = json.value( QStringLiteral(
"scheme" ), QStringLiteral(
"xyz" ) ).toString();
3700 if ( scheme.compare( QLatin1String(
"xyz" ) ) == 0 )
3706 context->
pushWarning( QObject::tr(
"%1 scheme is not supported for raster source %2" ).arg( scheme,
name() ) );
3710 mMinZoom = json.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"0" ) ).toInt();
3711 mMaxZoom = json.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"22" ) ).toInt();
3712 mTileSize = json.value( QStringLiteral(
"tileSize" ), QStringLiteral(
"512" ) ).toInt();
3714 const QVariantList
tiles = json.value( QStringLiteral(
"tiles" ) ).toList();
3715 for (
const QVariant &tile :
tiles )
3717 mTiles.append( tile.toString() );
3726 parts.insert( QStringLiteral(
"type" ), QStringLiteral(
"xyz" ) );
3727 parts.insert( QStringLiteral(
"url" ), mTiles.value( 0 ) );
3729 if ( mTileSize == 256 )
3730 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"1" ) );
3731 else if ( mTileSize == 512 )
3732 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"2" ) );
3734 parts.insert( QStringLiteral(
"zmax" ), QString::number( mMaxZoom ) );
3735 parts.insert( QStringLiteral(
"zmin" ), QString::number( mMinZoom ) );
3737 std::unique_ptr< QgsRasterLayer > rl = std::make_unique< QgsRasterLayer >(
QgsProviderRegistry::instance()->encodeUri( QStringLiteral(
"wms" ), parts ),
name(), QStringLiteral(
"wms" ) );
3738 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.
QList< QgsMapBoxGlStyleAbstractSource * > sources()
Returns the list of converted sources.
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
QList< QgsMapBoxGlStyleRasterSubLayer > rasterSubLayers() const
Returns a list of raster sub layers contained in the style.
static QgsProperty parseInterpolateByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, double *defaultNumber=nullptr)
Parses a numeric value which is interpolated by zoom range.
static Qt::PenJoinStyle parseJoinStyle(const QString &style)
Converts a value to Qt::PenJoinStyle enum from JSON value.
static QgsProperty parseInterpolateStringByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Interpolates a string by zoom.
static QString interpolateExpression(double zoomMin, double zoomMax, QVariant valueMin, QVariant valueMax, double base, double multiplier=1, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Generates an interpolation for values between valueMin and valueMax, scaled between the ranges zoomMi...
static QgsProperty parseInterpolatePointByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, QPointF *defaultPoint=nullptr)
Interpolates a point/offset with either scale_linear() or scale_exp() (depending on base value).
static bool parseCircleLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a circle layer.
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
static QgsProperty parseInterpolateListByZoom(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Interpolates a list which starts with the interpolate function.
~QgsMapBoxGlStyleConverter()
QList< QgsMapLayer * > createSubLayers() const
Returns a list of new map layers corresponding to sublayers of the style, e.g.
Result
Result of conversion.
@ Success
Conversion was successful.
@ NoLayerList
No layer list was found in JSON input.
QgsMapBoxGlStyleConverter()
Constructor for QgsMapBoxGlStyleConverter.
static QImage retrieveSprite(const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize)
Retrieves the sprite image with the specified name, taken from the specified context.
static QString parseLabelStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops containing label values.
void parseLayers(const QVariantList &layers, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of layers from JSON.
static QgsProperty parseInterpolateColorByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, QColor *defaultColor=nullptr)
Parses a color value which is interpolated by zoom range.
static QgsProperty parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
static QString retrieveSpriteAsBase64(const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize, QString &spriteProperty, QString &spriteSizeProperty)
Retrieves the sprite image with the specified name, taken from the specified context as a base64 enco...
void parseSources(const QVariantMap &sources, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of sources from JSON.
static QColor parseColor(const QVariant &color, QgsMapBoxGlStyleConversionContext &context)
Parses a color in one of these supported formats:
static bool parseSymbolLayerAsRenderer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as a renderer.
static bool parseFillLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context, bool isBackgroundStyle=false)
Parses a fill layer.
static void parseSymbolLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, bool &hasRenderer, QgsVectorTileBasicLabelingStyle &labelingStyle, bool &hasLabeling, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as renderer or labeling.
static bool parseLineLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a line layer.
void parseRasterSource(const QVariantMap &source, const QString &name, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse a raster source from JSON.
static void colorAsHslaComponents(const QColor &color, int &hue, int &saturation, int &lightness, int &alpha)
Takes a QColor object and returns HSLA components in required format for QGIS color_hsla() expression...
static Qt::PenCapStyle parseCapStyle(const QString &style)
Converts a value to Qt::PenCapStyle enum from JSON value.
static QString parseStringStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Parses a list of interpolation stops containing string values.
static QgsProperty parseMatchList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a match function value list.
static QgsProperty parseValueList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a value list (e.g.
static QString parseArrayStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes numerical arrays from stops.
static QString parsePointStops(double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate point/...
Encapsulates a MapBox GL style raster source.
Qgis::MapBoxGlStyleSourceType type() const override
Returns the source type.
QgsMapBoxGlStyleRasterSource(const QString &name)
Constructor for QgsMapBoxGlStyleRasterSource.
QgsRasterLayer * toRasterLayer() const
Returns a new raster layer representing the raster source, or nullptr if the source cannot be represe...
bool setFromJson(const QVariantMap &json, QgsMapBoxGlStyleConversionContext *context) override
Sets the source's state from a json map.
QStringList tiles() const
Returns the list of tile sources.
Encapsulates a MapBox GL style raster sub layer.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the layer's data defined properties.
QgsMapBoxGlStyleRasterSubLayer(const QString &id, const QString &source)
Constructor for QgsMapBoxGlStyleRasterSubLayer, with the given id and source.
Line symbol layer type which draws repeating marker symbols along a line feature.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
virtual void setSize(double size)
Sets the symbol size.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
void setAngle(double angle)
Sets the rotation angle for the marker.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
const QgsLabelObstacleSettings & obstacleSettings() const
Returns the label obstacle settings.
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
int priority
Label priority.
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.
@ 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.
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