22#include "moc_qgsmapboxglstyleconverter.cpp"
48#include <QRegularExpression>
59 if ( style.contains( QStringLiteral(
"sources" ) ) )
61 parseSources( style.value( QStringLiteral(
"sources" ) ).toMap(), context );
64 if ( style.contains( QStringLiteral(
"layers" ) ) )
66 parseLayers( style.value( QStringLiteral(
"layers" ) ).toList(), context );
70 mError = QObject::tr(
"Could not find layers list in JSON" );
83 qDeleteAll( mSources );
88 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
91 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
92 context = tmpContext.get();
95 QList<QgsVectorTileBasicRendererStyle> rendererStyles;
96 QList<QgsVectorTileBasicLabelingStyle> labelingStyles;
99 bool hasRendererBackgroundStyle =
false;
101 for (
const QVariant &layer : layers )
103 const QVariantMap jsonLayer = layer.toMap();
105 const QString layerType = jsonLayer.value( QStringLiteral(
"type" ) ).toString();
106 if ( layerType == QLatin1String(
"background" ) )
108 hasRendererBackgroundStyle =
parseFillLayer( jsonLayer, rendererBackgroundStyle, *context,
true );
109 if ( hasRendererBackgroundStyle )
119 const QString styleId = jsonLayer.value( QStringLiteral(
"id" ) ).toString();
122 if ( layerType.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
125 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
126 if ( jsonPaint.contains( QStringLiteral(
"raster-opacity" ) ) )
128 const QVariant jsonRasterOpacity = jsonPaint.value( QStringLiteral(
"raster-opacity" ) );
129 double defaultOpacity = 1;
133 mRasterSubLayers.append( raster );
137 const QString layerName = jsonLayer.value( QStringLiteral(
"source-layer" ) ).toString();
139 const int minZoom = jsonLayer.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"-1" ) ).toInt();
148 int maxZoom = jsonLayer.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"-1" ) ).toInt();
152 const bool enabled = jsonLayer.value( QStringLiteral(
"visibility" ) ).toString() != QLatin1String(
"none" );
154 QString filterExpression;
155 if ( jsonLayer.contains( QStringLiteral(
"filter" ) ) )
157 filterExpression =
parseExpression( jsonLayer.value( QStringLiteral(
"filter" ) ).toList(), *context );
163 bool hasRendererStyle =
false;
164 bool hasLabelingStyle =
false;
165 if ( layerType == QLatin1String(
"fill" ) )
167 hasRendererStyle =
parseFillLayer( jsonLayer, rendererStyle, *context );
169 else if ( layerType == QLatin1String(
"line" ) )
171 hasRendererStyle =
parseLineLayer( jsonLayer, rendererStyle, *context );
173 else if ( layerType == QLatin1String(
"circle" ) )
177 else if ( layerType == QLatin1String(
"symbol" ) )
179 parseSymbolLayer( jsonLayer, rendererStyle, hasRendererStyle, labelingStyle, hasLabelingStyle, *context );
183 mWarnings << QObject::tr(
"%1: Skipping unknown layer type %2" ).arg( context->
layerId(), layerType );
188 if ( hasRendererStyle )
196 rendererStyles.append( rendererStyle );
199 if ( hasLabelingStyle )
207 labelingStyles.append( labelingStyle );
210 mWarnings.append( context->
warnings() );
214 if ( hasRendererBackgroundStyle )
215 rendererStyles.prepend( rendererBackgroundStyle );
217 mRenderer = std::make_unique< QgsVectorTileBasicRenderer >();
219 renderer->setStyles( rendererStyles );
221 mLabeling = std::make_unique< QgsVectorTileBasicLabeling >();
223 labeling->setStyles( labelingStyles );
228 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
233 bool colorIsDataDefined =
false;
235 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsFillSymbol >() );
239 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) ) )
241 const QVariant jsonFillColor = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) );
242 switch ( jsonFillColor.userType() )
244 case QMetaType::Type::QVariantMap:
248 case QMetaType::Type::QVariantList:
249 case QMetaType::Type::QStringList:
250 colorIsDataDefined =
true;
254 case QMetaType::Type::QString:
255 fillColor =
parseColor( jsonFillColor.toString(), context );
260 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillColor.userType() ) ) ) );
268 fillColor = QColor( 0, 0, 0 );
271 QColor fillOutlineColor;
272 if ( !isBackgroundStyle )
274 if ( !jsonPaint.contains( QStringLiteral(
"fill-outline-color" ) ) )
276 if ( fillColor.isValid() )
277 fillOutlineColor = fillColor;
285 const QVariant jsonFillOutlineColor = jsonPaint.value( QStringLiteral(
"fill-outline-color" ) );
286 switch ( jsonFillOutlineColor.userType() )
288 case QMetaType::Type::QVariantMap:
292 case QMetaType::Type::QVariantList:
293 case QMetaType::Type::QStringList:
297 case QMetaType::Type::QString:
298 fillOutlineColor =
parseColor( jsonFillOutlineColor.toString(), context );
302 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-outline-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillOutlineColor.userType() ) ) ) );
308 double fillOpacity = -1.0;
309 double rasterOpacity = -1.0;
310 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) ) )
312 const QVariant jsonFillOpacity = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) );
313 switch ( jsonFillOpacity.userType() )
315 case QMetaType::Type::Int:
316 case QMetaType::Type::LongLong:
317 case QMetaType::Type::Double:
318 fillOpacity = jsonFillOpacity.toDouble();
319 rasterOpacity = fillOpacity;
322 case QMetaType::Type::QVariantMap:
335 case QMetaType::Type::QVariantList:
336 case QMetaType::Type::QStringList:
350 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillOpacity.userType() ) ) ) );
356 QPointF fillTranslate;
357 if ( jsonPaint.contains( QStringLiteral(
"fill-translate" ) ) )
359 const QVariant jsonFillTranslate = jsonPaint.value( QStringLiteral(
"fill-translate" ) );
360 switch ( jsonFillTranslate.userType() )
363 case QMetaType::Type::QVariantMap:
367 case QMetaType::Type::QVariantList:
368 case QMetaType::Type::QStringList:
374 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonFillTranslate.userType() ) ) ) );
380 Q_ASSERT( fillSymbol );
383 symbol->setOutputUnit( context.
targetUnit() );
386 if ( !fillTranslate.isNull() )
392 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) ) )
396 const QVariant fillPatternJson = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) );
399 fillColor = QColor();
400 fillOutlineColor = QColor();
407 QString spriteProperty, spriteSizeProperty;
409 if ( !sprite.isEmpty() )
414 rasterFill->
setWidth( spriteSize.width() );
418 if ( rasterOpacity >= 0 )
423 if ( !spriteProperty.isEmpty() )
430 symbol->appendSymbolLayer( rasterFill );
436 if ( fillOpacity != -1 )
438 symbol->setOpacity( fillOpacity );
449 if ( fillOutlineColor.isValid() && ( fillOutlineColor.alpha() == 255 || fillOutlineColor != fillColor ) )
460 if ( fillColor.isValid() )
464 else if ( colorIsDataDefined )
480 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
482 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
487 QString rasterLineSprite;
489 const QVariantMap jsonPaint = jsonLayer.
value( QStringLiteral(
"paint" ) ).toMap();
490 if ( jsonPaint.contains( QStringLiteral(
"line-pattern" ) ) )
492 const QVariant jsonLinePattern = jsonPaint.value( QStringLiteral(
"line-pattern" ) );
493 switch ( jsonLinePattern.userType() )
495 case QMetaType::Type::QVariantMap:
496 case QMetaType::Type::QString:
499 QString spriteProperty, spriteSizeProperty;
505 case QMetaType::Type::QVariantList:
506 case QMetaType::Type::QStringList:
511 if ( rasterLineSprite.isEmpty() )
514 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
521 if ( jsonPaint.contains( QStringLiteral(
"line-color" ) ) )
523 const QVariant jsonLineColor = jsonPaint.value( QStringLiteral(
"line-color" ) );
524 switch ( jsonLineColor.userType() )
526 case QMetaType::Type::QVariantMap:
531 case QMetaType::Type::QVariantList:
532 case QMetaType::Type::QStringList:
537 case QMetaType::Type::QString:
538 lineColor =
parseColor( jsonLineColor.toString(), context );
542 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineColor.userType() ) ) ) );
549 lineColor = QColor( 0, 0, 0 );
555 if ( jsonPaint.contains( QStringLiteral(
"line-width" ) ) )
557 const QVariant jsonLineWidth = jsonPaint.
value( QStringLiteral(
"line-width" ) );
558 switch ( jsonLineWidth.userType() )
560 case QMetaType::Type::Int:
561 case QMetaType::Type::LongLong:
562 case QMetaType::Type::Double:
566 case QMetaType::Type::QVariantMap:
578 case QMetaType::Type::QVariantList:
579 case QMetaType::Type::QStringList:
591 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineWidth.userType() ) ) ) );
596 double lineOffset = 0.0;
597 if ( jsonPaint.contains( QStringLiteral(
"line-offset" ) ) )
599 const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral(
"line-offset" ) );
600 switch ( jsonLineOffset.userType() )
602 case QMetaType::Type::Int:
603 case QMetaType::Type::LongLong:
604 case QMetaType::Type::Double:
608 case QMetaType::Type::QVariantMap:
613 case QMetaType::Type::QVariantList:
614 case QMetaType::Type::QStringList:
619 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineOffset.userType() ) ) ) );
624 double lineOpacity = -1.0;
626 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
628 const QVariant jsonLineOpacity = jsonPaint.
value( QStringLiteral(
"line-opacity" ) );
629 switch ( jsonLineOpacity.userType() )
631 case QMetaType::Type::Int:
632 case QMetaType::Type::LongLong:
633 case QMetaType::Type::Double:
634 lineOpacity = jsonLineOpacity.toDouble();
637 case QMetaType::Type::QVariantMap:
640 double defaultValue = 1.0;
649 case QMetaType::Type::QVariantList:
650 case QMetaType::Type::QStringList:
653 double defaultValue = 1.0;
664 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineOpacity.userType() ) ) ) );
669 QVector< double > dashVector;
670 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
672 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
673 switch ( jsonLineDashArray.userType() )
675 case QMetaType::Type::QVariantMap:
677 QString arrayExpression;
680 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
681 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
686 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
690 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
691 for (
const QVariant &v : dashSource )
693 dashVector << v.toDouble() * lineWidth;
698 case QMetaType::Type::QVariantList:
699 case QMetaType::Type::QStringList:
701 const QVariantList dashSource = jsonLineDashArray.toList();
703 if ( dashSource.at( 0 ).userType() == QMetaType::Type::QString )
709 .arg( property.asExpression(), lineWidthProperty.
asExpression() ) );
719 QVector< double > rawDashVectorSizes;
720 rawDashVectorSizes.reserve( dashSource.size() );
721 for (
const QVariant &v : dashSource )
723 rawDashVectorSizes << v.toDouble();
727 if ( rawDashVectorSizes.size() == 1 )
730 rawDashVectorSizes.clear();
732 else if ( rawDashVectorSizes.size() % 2 == 1 )
736 rawDashVectorSizes[0] = rawDashVectorSizes[0] + rawDashVectorSizes[rawDashVectorSizes.size() - 1];
737 rawDashVectorSizes.resize( rawDashVectorSizes.size() - 1 );
740 if ( !rawDashVectorSizes.isEmpty() && ( !lineWidthProperty.
asExpression().isEmpty() ) )
742 QStringList dashArrayStringParts;
743 dashArrayStringParts.reserve( rawDashVectorSizes.size() );
744 for (
double v : std::as_const( rawDashVectorSizes ) )
749 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
750 .arg( dashArrayStringParts.join(
',' ),
756 for (
double v : std::as_const( rawDashVectorSizes ) )
758 dashVector << v *lineWidth;
765 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-dasharray type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonLineDashArray.userType() ) ) ) );
770 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
771 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
772 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
774 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
775 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
777 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
779 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
781 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
785 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
786 symbol->setOutputUnit( context.
targetUnit() );
788 if ( !rasterLineSprite.isEmpty() )
798 if ( lineOpacity != -1 )
800 symbol->setOpacity( lineOpacity );
806 symbol->setDataDefinedProperties( ddProperties );
808 if ( lineWidth != -1 )
812 symbol->changeSymbolLayer( 0, lineSymbol );
817 Q_ASSERT( lineSymbol );
827 if ( lineOpacity != -1 )
829 symbol->setOpacity( lineOpacity );
835 symbol->setDataDefinedProperties( ddProperties );
837 if ( lineColor.isValid() )
841 if ( lineWidth != -1 )
845 if ( !dashVector.empty() )
859 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
861 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
865 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
869 QColor circleFillColor;
870 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
872 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
873 switch ( jsonCircleColor.userType() )
875 case QMetaType::Type::QVariantMap:
879 case QMetaType::Type::QVariantList:
880 case QMetaType::Type::QStringList:
884 case QMetaType::Type::QString:
885 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
889 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleColor.userType() ) ) ) );
896 circleFillColor = QColor( 0, 0, 0 );
900 double circleDiameter = 10.0;
901 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
903 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
904 switch ( jsonCircleRadius.userType() )
906 case QMetaType::Type::Int:
907 case QMetaType::Type::LongLong:
908 case QMetaType::Type::Double:
912 case QMetaType::Type::QVariantMap:
917 case QMetaType::Type::QVariantList:
918 case QMetaType::Type::QStringList:
923 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-radius type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleRadius.userType() ) ) ) );
928 double circleOpacity = -1.0;
929 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
931 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
932 switch ( jsonCircleOpacity.userType() )
934 case QMetaType::Type::Int:
935 case QMetaType::Type::LongLong:
936 case QMetaType::Type::Double:
937 circleOpacity = jsonCircleOpacity.toDouble();
940 case QMetaType::Type::QVariantMap:
944 case QMetaType::Type::QVariantList:
945 case QMetaType::Type::QStringList:
950 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleOpacity.userType() ) ) ) );
954 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
956 circleFillColor.setAlphaF( circleOpacity );
960 QColor circleStrokeColor;
961 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
963 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
964 switch ( jsonCircleStrokeColor.userType() )
966 case QMetaType::Type::QVariantMap:
970 case QMetaType::Type::QVariantList:
971 case QMetaType::Type::QStringList:
975 case QMetaType::Type::QString:
976 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
980 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-color type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleStrokeColor.userType() ) ) ) );
986 double circleStrokeWidth = -1.0;
987 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
989 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
990 switch ( circleStrokeWidthJson.userType() )
992 case QMetaType::Type::Int:
993 case QMetaType::Type::LongLong:
994 case QMetaType::Type::Double:
998 case QMetaType::Type::QVariantMap:
999 circleStrokeWidth = -1.0;
1003 case QMetaType::Type::QVariantList:
1004 case QMetaType::Type::QStringList:
1009 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( circleStrokeWidthJson.userType() ) ) ) );
1014 double circleStrokeOpacity = -1.0;
1015 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
1017 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
1018 switch ( jsonCircleStrokeOpacity.userType() )
1020 case QMetaType::Type::Int:
1021 case QMetaType::Type::LongLong:
1022 case QMetaType::Type::Double:
1023 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
1026 case QMetaType::Type::QVariantMap:
1030 case QMetaType::Type::QVariantList:
1031 case QMetaType::Type::QStringList:
1036 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleStrokeOpacity.userType() ) ) ) );
1040 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
1042 circleStrokeColor.setAlphaF( circleStrokeOpacity );
1046 QPointF circleTranslate;
1047 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
1049 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
1050 switch ( jsonCircleTranslate.userType() )
1053 case QMetaType::Type::QVariantMap:
1057 case QMetaType::Type::QVariantList:
1058 case QMetaType::Type::QStringList:
1064 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonCircleTranslate.userType() ) ) ) );
1069 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
1071 Q_ASSERT( markerSymbolLayer );
1074 symbol->setOutputUnit( context.
targetUnit() );
1075 symbol->setDataDefinedProperties( ddProperties );
1077 if ( !circleTranslate.isNull() )
1079 markerSymbolLayer->
setOffset( circleTranslate );
1083 if ( circleFillColor.isValid() )
1087 if ( circleDiameter != -1 )
1089 markerSymbolLayer->
setSize( circleDiameter );
1092 if ( circleStrokeColor.isValid() )
1096 if ( circleStrokeWidth != -1 )
1109 hasLabeling =
false;
1110 hasRenderer =
false;
1112 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1114 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1117 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1118 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1124 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1130 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
1132 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
1133 switch ( jsonTextSize.userType() )
1135 case QMetaType::Type::Int:
1136 case QMetaType::Type::LongLong:
1137 case QMetaType::Type::Double:
1141 case QMetaType::Type::QVariantMap:
1147 case QMetaType::Type::QVariantList:
1148 case QMetaType::Type::QStringList:
1154 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextSize.userType() ) ) ) );
1158 if ( textSizeProperty )
1165 constexpr double EM_TO_CHARS = 2.0;
1167 double textMaxWidth = -1;
1168 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
1170 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
1171 switch ( jsonTextMaxWidth.userType() )
1173 case QMetaType::Type::Int:
1174 case QMetaType::Type::LongLong:
1175 case QMetaType::Type::Double:
1176 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1179 case QMetaType::Type::QVariantMap:
1183 case QMetaType::Type::QVariantList:
1184 case QMetaType::Type::QStringList:
1189 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-max-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextMaxWidth.userType() ) ) ) );
1196 textMaxWidth = 10 * EM_TO_CHARS;
1199 double textLetterSpacing = -1;
1200 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1202 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1203 switch ( jsonTextLetterSpacing.userType() )
1205 case QMetaType::Type::Int:
1206 case QMetaType::Type::LongLong:
1207 case QMetaType::Type::Double:
1208 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1211 case QMetaType::Type::QVariantMap:
1215 case QMetaType::Type::QVariantList:
1216 case QMetaType::Type::QStringList:
1221 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-letter-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextLetterSpacing.userType() ) ) ) );
1227 bool foundFont =
false;
1229 QString fontStyleName;
1231 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1233 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1235 QString matchedFamily;
1236 const QStringList textFontParts = fontName.split(
' ' );
1237 for (
int i = textFontParts.size() - 1; i >= 1; --i )
1239 const QString candidateFontFamily = textFontParts.mid( 0, i ).join(
' ' );
1240 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1245 family = processedFontFamily;
1246 style = candidateFontStyle;
1251 if ( processedFontFamily == matchedFamily )
1253 family = processedFontFamily;
1254 style = candidateFontStyle;
1258 family = matchedFamily;
1259 style = processedFontFamily;
1260 style.replace( matchedFamily, QString() );
1261 style = style.trimmed();
1262 if ( !style.isEmpty() && !candidateFontStyle.isEmpty() )
1264 style += QStringLiteral(
" %1" ).arg( candidateFontStyle );
1272 if ( QFontDatabase().hasFamily( processedFontFamily ) )
1275 family = processedFontFamily;
1281 family = matchedFamily;
1288 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1289 if ( jsonTextFont.userType() != QMetaType::Type::QVariantList && jsonTextFont.userType() != QMetaType::Type::QStringList && jsonTextFont.userType() != QMetaType::Type::QString
1290 && jsonTextFont.userType() != QMetaType::Type::QVariantMap )
1292 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-font type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextFont.userType() ) ) ) );
1296 switch ( jsonTextFont.userType() )
1298 case QMetaType::Type::QVariantList:
1299 case QMetaType::Type::QStringList:
1300 fontName = jsonTextFont.toList().value( 0 ).toString();
1303 case QMetaType::Type::QString:
1304 fontName = jsonTextFont.toString();
1307 case QMetaType::Type::QVariantMap:
1309 QString familyCaseString = QStringLiteral(
"CASE " );
1310 QString styleCaseString = QStringLiteral(
"CASE " );
1312 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1315 for (
int i = 0; i < stops.length() - 1; ++i )
1318 const QVariant bz = stops.value( i ).toList().value( 0 );
1319 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();
1320 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
1322 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1328 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1329 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
1331 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1336 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1338 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1339 "THEN %3 " ).arg( bz.toString(),
1342 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1343 "THEN %3 " ).arg( bz.toString(),
1349 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1355 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();
1356 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1363 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1370 fontName = fontFamily;
1380 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1383 if ( !fontStyleName.isEmpty() )
1384 textFont.setStyleName( fontStyleName );
1394 fontName = QStringLiteral(
"Open Sans" );
1396 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1397 fontStyleName = QStringLiteral(
"Regular" );
1402 fontName = QStringLiteral(
"Arial Unicode MS" );
1404 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1405 fontStyleName = QStringLiteral(
"Regular" );
1410 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1413 if ( !foundFont && !fontName.isEmpty() )
1415 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1420 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1422 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1423 switch ( jsonTextColor.userType() )
1425 case QMetaType::Type::QVariantMap:
1429 case QMetaType::Type::QVariantList:
1430 case QMetaType::Type::QStringList:
1434 case QMetaType::Type::QString:
1435 textColor =
parseColor( jsonTextColor.toString(), context );
1439 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextColor.userType() ) ) ) );
1446 textColor = QColor( 0, 0, 0 );
1450 QColor bufferColor( 0, 0, 0, 0 );
1451 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1453 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1454 switch ( jsonBufferColor.userType() )
1456 case QMetaType::Type::QVariantMap:
1460 case QMetaType::Type::QVariantList:
1461 case QMetaType::Type::QStringList:
1465 case QMetaType::Type::QString:
1466 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1470 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonBufferColor.userType() ) ) ) );
1475 double bufferSize = 0.0;
1479 constexpr double BUFFER_SIZE_SCALE = 2.0;
1480 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1482 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1483 QString bufferSizeDataDefined;
1484 switch ( jsonHaloWidth.userType() )
1486 case QMetaType::Type::Int:
1487 case QMetaType::Type::LongLong:
1488 case QMetaType::Type::Double:
1492 case QMetaType::Type::QVariantMap:
1497 case QMetaType::Type::QVariantList:
1498 case QMetaType::Type::QStringList:
1504 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonHaloWidth.userType() ) ) ) );
1510 if ( bufferSize > 0 )
1512 if ( textSize > 0 && bufferSizeDataDefined.isEmpty() )
1514 bufferSize = std::min( bufferSize, textSize * BUFFER_SIZE_SCALE / 4 );
1516 else if ( textSize > 0 && !bufferSizeDataDefined.isEmpty() )
1518 bufferSizeDataDefined = QStringLiteral(
"min(%1/4, %2)" ).arg( textSize * BUFFER_SIZE_SCALE ).arg( bufferSizeDataDefined );
1521 else if ( !bufferSizeDataDefined.isEmpty() )
1523 bufferSizeDataDefined = QStringLiteral(
"min(%1*%2/4, %3)" )
1525 .arg( BUFFER_SIZE_SCALE )
1526 .arg( bufferSizeDataDefined );
1529 else if ( bufferSizeDataDefined.isEmpty() )
1531 bufferSizeDataDefined = QStringLiteral(
"min(%1*%2/4, %3)" )
1533 .arg( BUFFER_SIZE_SCALE )
1540 double haloBlurSize = 0;
1541 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1543 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1544 switch ( jsonTextHaloBlur.userType() )
1546 case QMetaType::Type::Int:
1547 case QMetaType::Type::LongLong:
1548 case QMetaType::Type::Double:
1555 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-blur type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextHaloBlur.userType() ) ) ) );
1562 if ( textColor.isValid() )
1564 if ( textSize >= 0 )
1569 if ( !fontStyleName.isEmpty() )
1572 if ( textLetterSpacing > 0 )
1574 QFont f = format.
font();
1575 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1579 if ( bufferSize > 0 )
1582 const double opacity = bufferColor.alphaF();
1583 bufferColor.setAlphaF( 1.0 );
1591 if ( haloBlurSize > 0 )
1607 if ( textMaxWidth > 0 )
1613 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1615 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1616 switch ( jsonTextField.userType() )
1618 case QMetaType::Type::QString:
1620 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1624 case QMetaType::Type::QVariantList:
1625 case QMetaType::Type::QStringList:
1627 const QVariantList textFieldList = jsonTextField.toList();
1635 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1638 for (
int i = 1; i < textFieldList.size(); ++i )
1640 bool isExpression =
false;
1641 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1642 if ( !isExpression )
1649 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1664 case QMetaType::Type::QVariantMap:
1666 const QVariantList stops = jsonTextField.toMap().value( QStringLiteral(
"stops" ) ).toList();
1667 if ( !stops.empty() )
1674 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field dictionary" ).arg( context.
layerId() ) );
1680 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextField.userType() ) ) ) );
1685 if ( jsonLayout.contains( QStringLiteral(
"text-rotate" ) ) )
1687 const QVariant jsonTextRotate = jsonLayout.value( QStringLiteral(
"text-rotate" ) );
1688 switch ( jsonTextRotate.userType() )
1690 case QMetaType::Type::Double:
1691 case QMetaType::Type::Int:
1693 labelSettings.
angleOffset = jsonTextRotate.toDouble();
1697 case QMetaType::Type::QVariantList:
1698 case QMetaType::Type::QStringList:
1706 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextRotate.userType() ) ) ) );
1711 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1713 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1714 if ( textTransform == QLatin1String(
"uppercase" ) )
1718 else if ( textTransform == QLatin1String(
"lowercase" ) )
1727 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1729 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1730 if ( symbolPlacement == QLatin1String(
"line" ) )
1736 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1738 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1739 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1749 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1751 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1754 switch ( jsonTextOffset.userType() )
1756 case QMetaType::Type::QVariantMap:
1757 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1758 if ( !textSizeProperty )
1769 case QMetaType::Type::QVariantList:
1770 case QMetaType::Type::QStringList:
1771 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1772 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1776 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextOffset.userType() ) ) ) );
1780 if ( !textOffset.isNull() )
1783 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1785 if ( textSizeProperty && !textOffsetProperty )
1792 if ( textOffset.isNull() )
1800 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1802 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1805 QString textAlign = QStringLiteral(
"center" );
1807 const QVariantMap conversionMap
1809 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1810 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1811 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1812 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1815 switch ( jsonTextJustify.userType() )
1817 case QMetaType::Type::QString:
1818 textAlign = jsonTextJustify.toString();
1821 case QMetaType::Type::QVariantList:
1825 case QMetaType::Type::QVariantMap:
1830 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-justify type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextJustify.userType() ) ) ) );
1834 if ( textAlign == QLatin1String(
"left" ) )
1836 else if ( textAlign == QLatin1String(
"right" ) )
1838 else if ( textAlign == QLatin1String(
"center" ) )
1840 else if ( textAlign == QLatin1String(
"follow" ) )
1850 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1852 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1855 const QVariantMap conversionMap
1857 { QStringLiteral(
"center" ), 4 },
1858 { QStringLiteral(
"left" ), 5 },
1859 { QStringLiteral(
"right" ), 3 },
1860 { QStringLiteral(
"top" ), 7 },
1861 { QStringLiteral(
"bottom" ), 1 },
1862 { QStringLiteral(
"top-left" ), 8 },
1863 { QStringLiteral(
"top-right" ), 6 },
1864 { QStringLiteral(
"bottom-left" ), 2 },
1865 { QStringLiteral(
"bottom-right" ), 0 },
1868 switch ( jsonTextAnchor.userType() )
1870 case QMetaType::Type::QString:
1871 textAnchor = jsonTextAnchor.toString();
1874 case QMetaType::Type::QVariantList:
1878 case QMetaType::Type::QVariantMap:
1883 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-anchor type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextAnchor.userType() ) ) ) );
1887 if ( textAnchor == QLatin1String(
"center" ) )
1889 else if ( textAnchor == QLatin1String(
"left" ) )
1891 else if ( textAnchor == QLatin1String(
"right" ) )
1893 else if ( textAnchor == QLatin1String(
"top" ) )
1895 else if ( textAnchor == QLatin1String(
"bottom" ) )
1897 else if ( textAnchor == QLatin1String(
"top-left" ) )
1899 else if ( textAnchor == QLatin1String(
"top-right" ) )
1901 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1903 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1908 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1910 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1913 switch ( jsonTextOffset.userType() )
1915 case QMetaType::Type::QVariantMap:
1919 case QMetaType::Type::QVariantList:
1920 case QMetaType::Type::QStringList:
1921 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1922 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1926 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonTextOffset.userType() ) ) ) );
1930 if ( !textOffset.isNull() )
1933 labelSettings.
xOffset = textOffset.x();
1934 labelSettings.
yOffset = textOffset.y();
1939 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1943 QString spriteProperty, spriteSizeProperty;
1945 if ( !sprite.isEmpty() )
1948 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1951 const QVariant jsonIconSize = jsonLayout.
value( QStringLiteral(
"icon-size" ) );
1952 switch ( jsonIconSize.userType() )
1954 case QMetaType::Type::Int:
1955 case QMetaType::Type::LongLong:
1956 case QMetaType::Type::Double:
1958 size = jsonIconSize.toDouble();
1959 if ( !spriteSizeProperty.isEmpty() )
1962 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
1967 case QMetaType::Type::QVariantMap:
1971 case QMetaType::Type::QVariantList:
1972 case QMetaType::Type::QStringList:
1976 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
1982 if ( !spriteSizeProperty.isEmpty() )
1996 markerLayer->
setPath( sprite );
1997 markerLayer->
setSize( spriteSize.width() );
2000 if ( !spriteProperty.isEmpty() )
2010 backgroundSettings.
setSize( spriteSize * size );
2018 if ( textSize >= 0 )
2041 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
2043 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
2046 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
2048 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
2052 double spacing = -1.0;
2053 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
2055 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
2056 switch ( jsonSpacing.userType() )
2058 case QMetaType::Type::Int:
2059 case QMetaType::Type::LongLong:
2060 case QMetaType::Type::Double:
2064 case QMetaType::Type::QVariantMap:
2068 case QMetaType::Type::QVariantList:
2069 case QMetaType::Type::QStringList:
2074 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported symbol-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonSpacing.userType() ) ) ) );
2084 bool rotateMarkers =
true;
2085 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
2087 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
2088 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
2090 rotateMarkers =
true;
2092 else if ( alignment == QLatin1String(
"viewport" ) )
2094 rotateMarkers =
false;
2099 double rotation = 0.0;
2100 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2102 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
2103 switch ( jsonIconRotate.userType() )
2105 case QMetaType::Type::Int:
2106 case QMetaType::Type::LongLong:
2107 case QMetaType::Type::Double:
2108 rotation = jsonIconRotate.toDouble();
2111 case QMetaType::Type::QVariantMap:
2115 case QMetaType::Type::QVariantList:
2116 case QMetaType::Type::QStringList:
2121 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconRotate.userType() ) ) ) );
2137 QString spriteProperty, spriteSizeProperty;
2139 if ( !sprite.isNull() )
2141 markerLayer->
setPath( sprite );
2142 markerLayer->
setSize( spriteSize.width() );
2145 if ( !spriteProperty.isEmpty() )
2152 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2154 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2157 switch ( jsonIconSize.userType() )
2159 case QMetaType::Type::Int:
2160 case QMetaType::Type::LongLong:
2161 case QMetaType::Type::Double:
2163 size = jsonIconSize.toDouble();
2164 if ( !spriteSizeProperty.isEmpty() )
2167 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2172 case QMetaType::Type::QVariantMap:
2176 case QMetaType::Type::QVariantList:
2177 case QMetaType::Type::QStringList:
2181 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
2184 markerLayer->
setSize( size * spriteSize.width() );
2187 if ( !spriteSizeProperty.isEmpty() )
2204 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
2207 symbol->setOutputUnit( context.
targetUnit() );
2211 rendererStyle.
setSymbol( symbol.release() );
2214 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
2216 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
2219 QString spriteProperty, spriteSizeProperty;
2221 if ( !sprite.isEmpty() || !spriteProperty.isEmpty() )
2224 rasterMarker->
setPath( sprite );
2225 rasterMarker->
setSize( spriteSize.width() );
2229 if ( !spriteProperty.isEmpty() )
2235 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2237 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2240 switch ( jsonIconSize.userType() )
2242 case QMetaType::Type::Int:
2243 case QMetaType::Type::LongLong:
2244 case QMetaType::Type::Double:
2246 size = jsonIconSize.toDouble();
2247 if ( !spriteSizeProperty.isEmpty() )
2250 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2255 case QMetaType::Type::QVariantMap:
2259 case QMetaType::Type::QVariantList:
2260 case QMetaType::Type::QStringList:
2264 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconSize.userType() ) ) ) );
2267 rasterMarker->
setSize( size * spriteSize.width() );
2270 if ( !spriteSizeProperty.isEmpty() )
2283 double rotation = 0.0;
2284 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2286 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
2287 switch ( jsonIconRotate.userType() )
2289 case QMetaType::Type::Int:
2290 case QMetaType::Type::LongLong:
2291 case QMetaType::Type::Double:
2292 rotation = jsonIconRotate.toDouble();
2295 case QMetaType::Type::QVariantMap:
2299 case QMetaType::Type::QVariantList:
2300 case QMetaType::Type::QStringList:
2305 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconRotate.userType() ) ) ) );
2310 double iconOpacity = -1.0;
2311 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2313 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2314 switch ( jsonIconOpacity.userType() )
2316 case QMetaType::Type::Int:
2317 case QMetaType::Type::LongLong:
2318 case QMetaType::Type::Double:
2319 iconOpacity = jsonIconOpacity.toDouble();
2322 case QMetaType::Type::QVariantMap:
2326 case QMetaType::Type::QVariantList:
2327 case QMetaType::Type::QStringList:
2332 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( jsonIconOpacity.userType() ) ) ) );
2338 rasterMarker->
setAngle( rotation );
2339 if ( iconOpacity >= 0 )
2343 rendererStyle.
setSymbol( markerSymbol );
2354 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2355 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2356 if ( stops.empty() )
2359 QString caseString = QStringLiteral(
"CASE " );
2360 const QString colorComponent(
"color_part(%1,'%2')" );
2362 for (
int i = 0; i < stops.length() - 1; ++i )
2365 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2367 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2369 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2370 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2372 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2373 const QColor topColor =
parseColor( tcVariant.toString(), context );
2375 if ( i == 0 && bottomColor.isValid() )
2382 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2383 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2386 if ( bottomColor.isValid() && topColor.isValid() )
2398 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2399 "%3, %4, %5, %6) " ).arg( bz, tz,
2410 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2411 "%3, %4, %5, %6) " ).arg( bz, tz,
2412 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2413 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2414 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2415 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2420 const QString tz = stops.last().toList().value( 0 ).toString();
2421 const QVariant tcVariant = stops.last().toList().value( 1 );
2423 if ( tcVariant.userType() == QMetaType::Type::QString )
2426 if ( topColor.isValid() )
2433 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2434 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2437 else if ( tcVariant.userType() == QMetaType::QVariantList )
2441 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2442 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2443 .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" ) );
2446 if ( !stops.empty() && defaultColor )
2447 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2454 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2455 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2456 if ( stops.empty() )
2459 QString scaleExpression;
2460 if ( stops.size() <= 2 )
2463 stops.value( 0 ).toList().value( 0 ).toDouble(),
2464 stops.last().toList().value( 0 ).toDouble(),
2465 stops.value( 0 ).toList().value( 1 ),
2466 stops.last().toList().value( 1 ),
2467 base, multiplier, &context );
2471 scaleExpression =
parseStops( base, stops, multiplier, context );
2474 if ( !stops.empty() && defaultNumber )
2475 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2485 context = *contextPtr;
2487 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2488 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2489 if ( stops.empty() )
2492 QString scaleExpression;
2493 if ( stops.length() <= 2 )
2495 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2496 const QVariant tv = stops.last().toList().value( 1 );
2497 double bottom = 0.0;
2499 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2500 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2502 stops.value( 0 ).toList().value( 0 ).toDouble(),
2503 stops.last().toList().value( 0 ).toDouble(),
2504 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2505 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2516 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2517 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2518 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2520 for (
int i = 0; i < stops.size() - 1; ++i )
2522 const QVariant bv = stops.value( i ).toList().value( 1 );
2523 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2524 double bottom = 0.0;
2526 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2528 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2529 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2530 .arg( stops.value( i ).toList().value( 0 ).toString(),
2531 stops.value( i + 1 ).toList().value( 0 ).toString(),
2533 stops.value( i ).toList().value( 0 ).toDouble(),
2534 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2535 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2536 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2537 base, 1, &context ) );
2541 bool numeric =
false;
2542 const QVariant vv = stops.last().toList().value( 1 );
2543 double dv = vv.toDouble( &numeric );
2545 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2546 "THEN set_color_part(@symbol_color, 'alpha', %2) END" ).arg(
2547 stops.last().toList().value( 0 ).toString(),
2548 numeric ? QString::number( dv * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( vv, context ) ).arg( maxOpacity )
2555 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2556 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2557 if ( stops.empty() )
2560 QString scaleExpression;
2561 if ( stops.size() <= 2 )
2563 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2564 stops.last().toList().value( 0 ).toDouble(),
2565 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2566 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2568 stops.last().toList().value( 0 ).toDouble(),
2569 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2570 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2575 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2578 if ( !stops.empty() && defaultPoint )
2579 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2580 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2586 const QVariantMap &conversionMap, QString *defaultString )
2588 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2589 if ( stops.empty() )
2592 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2599 QString caseString = QStringLiteral(
"CASE " );
2601 for (
int i = 0; i < stops.length() - 1; ++i )
2604 const QVariant bz = stops.value( i ).toList().value( 0 );
2605 const QVariant bv = stops.value( i ).toList().value( 1 );
2606 if ( bv.userType() != QMetaType::Type::QVariantList && bv.userType() != QMetaType::Type::QStringList )
2608 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( bz.userType() ) ) ) );
2613 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2614 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2615 if ( tv.userType() != QMetaType::Type::QVariantList && tv.userType() != QMetaType::Type::QStringList )
2617 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( tz.userType() ) ) ) );
2621 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2622 "THEN array(%3,%4)" ).arg( bz.toString(),
2624 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2625 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2627 caseString += QLatin1String(
"END" );
2633 if ( stops.length() < 2 )
2636 QString caseString = QStringLiteral(
"CASE" );
2638 for (
int i = 0; i < stops.length(); ++i )
2640 caseString += QLatin1String(
" WHEN " );
2641 QStringList conditions;
2644 const QVariant bottomZoom = stops.value( i ).toList().value( 0 );
2645 conditions << QStringLiteral(
"@vector_tile_zoom > %1" ).arg( bottomZoom.toString() );
2647 if ( i < stops.length() - 1 )
2649 const QVariant topZoom = stops.value( i + 1 ).toList().value( 0 );
2650 conditions << QStringLiteral(
"@vector_tile_zoom <= %1" ).arg( topZoom.toString() );
2653 const QVariantList values = stops.value( i ).toList().value( 1 ).toList();
2654 QStringList valuesFixed;
2656 for (
const QVariant &value : values )
2658 const double number = value.toDouble( &ok );
2660 valuesFixed << QString::number( number * multiplier );
2664 caseString += QStringLiteral(
"%1 THEN array(%3)" ).arg(
2665 conditions.join( QLatin1String(
" AND " ) ),
2666 valuesFixed.join(
',' )
2669 caseString += QLatin1String(
" END" );
2675 QString caseString = QStringLiteral(
"CASE " );
2677 for (
int i = 0; i < stops.length() - 1; ++i )
2680 const QVariant bz = stops.value( i ).toList().value( 0 );
2681 const QVariant bv = stops.value( i ).toList().value( 1 );
2682 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2684 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2689 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2690 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2691 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2693 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2697 const QString lowerComparator = i == 0 ? QStringLiteral(
">=" ) : QStringLiteral(
">" );
2699 caseString += QStringLiteral(
"WHEN @vector_tile_zoom %1 %2 AND @vector_tile_zoom <= %3 "
2700 "THEN %4 " ).arg( lowerComparator,
2706 const QVariant z = stops.last().toList().value( 0 );
2707 const QVariant v = stops.last().toList().value( 1 );
2708 QString vStr = v.toString();
2709 if ( ( QMetaType::Type )v.userType() == QMetaType::QVariantList )
2712 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2713 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2717 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2718 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2726 QString caseString = QStringLiteral(
"CASE " );
2728 for (
int i = 0; i < stops.length() - 1; ++i )
2731 const QVariant bz = stops.value( i ).toList().value( 0 );
2732 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2733 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2735 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2740 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2741 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2743 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2747 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2748 "THEN %3 " ).arg( bz.toString(),
2752 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2753 stops.constLast().toList().value( 1 ) ) ) );
2754 if ( defaultString )
2755 *defaultString = stops.constLast().toList().value( 1 ).toString();
2761 QString caseString = QStringLiteral(
"CASE " );
2763 bool isExpression =
false;
2764 for (
int i = 0; i < stops.length() - 1; ++i )
2767 const QVariant bz = stops.value( i ).toList().value( 0 );
2768 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2770 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2775 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2776 if ( tz.userType() == QMetaType::Type::QVariantList || tz.userType() == QMetaType::Type::QStringList )
2778 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2782 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2783 if ( fieldPart.isEmpty() )
2784 fieldPart = QStringLiteral(
"''" );
2785 else if ( !isExpression )
2788 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom < %2 "
2789 "THEN %3 " ).arg( bz.toString(),
2795 const QVariant bz = stops.constLast().toList().value( 0 );
2796 if ( bz.userType() == QMetaType::Type::QVariantList || bz.userType() == QMetaType::Type::QStringList )
2798 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2802 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2803 if ( fieldPart.isEmpty() )
2804 fieldPart = QStringLiteral(
"''" );
2805 else if ( !isExpression )
2808 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 "
2809 "THEN %3 " ).arg( bz.toString(),
2813 QString defaultPart = processLabelField( stops.constFirst().toList().value( 1 ).toString(), isExpression );
2814 if ( defaultPart.isEmpty() )
2815 defaultPart = QStringLiteral(
"''" );
2816 else if ( !isExpression )
2818 caseString += QStringLiteral(
"ELSE %1 END" ).arg( defaultPart );
2825 const QString method = json.
value( 0 ).toString();
2826 if ( method == QLatin1String(
"interpolate" ) )
2830 else if ( method == QLatin1String(
"match" ) )
2832 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2834 else if ( method == QLatin1String(
"step" ) )
2836 return parseStepList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2846 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2847 if ( attribute.isEmpty() )
2849 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2853 QString caseString = QStringLiteral(
"CASE " );
2855 for (
int i = 2; i < json.length() - 1; i += 2 )
2858 QVariant variantKeys = json.value( i );
2859 if ( variantKeys.userType() == QMetaType::Type::QVariantList || variantKeys.userType() == QMetaType::Type::QStringList )
2860 keys = variantKeys.toList();
2862 keys = {variantKeys};
2864 QStringList matchString;
2865 for (
const QVariant &key : keys )
2870 const QVariant value = json.value( i + 1 );
2872 QString valueString;
2877 if ( value.userType() == QMetaType::Type::QVariantList || value.userType() == QMetaType::Type::QStringList )
2883 const QColor color =
parseColor( value, context );
2891 const double v = value.toDouble() * multiplier;
2892 valueString = QString::number( v );
2898 const double v = value.toDouble() * maxOpacity;
2899 valueString = QString::number( v );
2905 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2906 value.toList().value( 0 ).toDouble() * multiplier );
2912 if ( value.toList().count() == 2 && value.toList().first().toString() == QLatin1String(
"literal" ) )
2914 valueString = QStringLiteral(
"array(%1)" ).arg( value.toList().at( 1 ).toStringList().join(
',' ) );
2918 valueString = QStringLiteral(
"array(%1)" ).arg( value.toStringList().join(
',' ) );
2924 if ( matchString.count() == 1 )
2926 caseString += QStringLiteral(
"WHEN %1 IS %2 THEN %3 " ).arg( attribute, matchString.at( 0 ), valueString );
2930 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute, matchString.join(
',' ), valueString );
2934 QVariant lastValue = json.constLast();
2937 switch ( lastValue.userType() )
2939 case QMetaType::Type::QVariantList:
2940 case QMetaType::Type::QStringList:
2941 elseValue =
parseValueList( lastValue.toList(), type, context, multiplier, maxOpacity, defaultColor, defaultNumber ).
asExpression();
2950 const QColor color =
parseColor( lastValue, context );
2952 *defaultColor = color;
2960 const double v = json.constLast().toDouble() * multiplier;
2961 if ( defaultNumber )
2963 elseValue = QString::number( v );
2969 const double v = json.constLast().toDouble() * maxOpacity;
2970 if ( defaultNumber )
2972 elseValue = QString::number( v );
2978 elseValue = QStringLiteral(
"array(%1,%2)" )
2979 .arg( json.constLast().toList().value( 0 ).toDouble() * multiplier )
2980 .arg( json.constLast().toList().value( 0 ).toDouble() * multiplier );
2986 if ( json.constLast().toList().count() == 2 && json.constLast().toList().first().toString() == QLatin1String(
"literal" ) )
2988 elseValue = QStringLiteral(
"array(%1)" ).arg( json.constLast().toList().at( 1 ).toStringList().join(
',' ) );
2992 elseValue = QStringLiteral(
"array(%1)" ).arg( json.constLast().toStringList().join(
',' ) );
3002 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
3008 const QString expression =
parseExpression( json.value( 1 ).toList(), context );
3009 if ( expression.isEmpty() )
3011 context.
pushWarning( QObject::tr(
"%1: Could not interpret step list" ).arg( context.
layerId() ) );
3015 QString caseString = QStringLiteral(
"CASE " );
3018 for (
int i = json.length() - 2; i > 0; i -= 2 )
3020 const QVariant stepValue = json.value( i + 1 );
3022 QString valueString;
3023 if ( stepValue.canConvert<QVariantList>()
3035 const QColor color =
parseColor( stepValue, context );
3042 const double v = stepValue.toDouble() * multiplier;
3043 valueString = QString::number( v );
3049 const double v = stepValue.toDouble() * maxOpacity;
3050 valueString = QString::number( v );
3056 valueString = QStringLiteral(
"array(%1,%2)" ).arg(
3057 stepValue.toList().value( 0 ).toDouble() * multiplier ).arg(
3058 stepValue.toList().value( 0 ).toDouble() * multiplier
3065 if ( stepValue.toList().count() == 2 && stepValue.toList().first().toString() == QLatin1String(
"literal" ) )
3067 valueString = QStringLiteral(
"array(%1)" ).arg( stepValue.toList().at( 1 ).toStringList().join(
',' ) );
3071 valueString = QStringLiteral(
"array(%1)" ).arg( stepValue.toStringList().join(
',' ) );
3081 caseString += QStringLiteral(
" WHEN %1 >= %2 THEN (%3) " ).arg( expression, stepKey, valueString );
3085 caseString += QStringLiteral(
"ELSE (%1) END" ).arg( valueString );
3093 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
3095 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
3100 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
3101 if ( technique == QLatin1String(
"linear" ) )
3103 else if ( technique == QLatin1String(
"exponential" ) )
3104 base = json.value( 1 ).toList(). value( 1 ).toDouble();
3105 else if ( technique == QLatin1String(
"cubic-bezier" ) )
3107 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
3112 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
3116 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
3118 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
3124 for (
int i = 3; i < json.length(); i += 2 )
3126 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
3130 props.insert( QStringLiteral(
"stops" ), stops );
3131 props.insert( QStringLiteral(
"base" ), base );
3147 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported numeric array in interpolate" ).arg( context.
layerId() ) );
3156 if ( ( QMetaType::Type )colorExpression.userType() == QMetaType::QVariantList )
3160 return parseValue( colorExpression, context,
true );
3165 if ( color.userType() != QMetaType::Type::QString )
3167 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
3176 hue = std::max( 0, color.hslHue() );
3177 saturation = color.hslSaturation() / 255.0 * 100;
3178 lightness = color.lightness() / 255.0 * 100;
3179 alpha = color.alpha();
3187 context = *contextPtr;
3191 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
3193 bool minDoubleOk =
true;
3194 const double min = valueMin.toDouble( &minDoubleOk );
3195 bool maxDoubleOk =
true;
3196 const double max = valueMax.toDouble( &maxDoubleOk );
3197 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
3199 return QString::number( min * multiplier );
3203 QString minValueExpr = valueMin.toString();
3204 QString maxValueExpr = valueMax.toString();
3205 if ( valueMin.userType() == QMetaType::Type::QVariantList )
3209 if ( valueMax.userType() == QMetaType::Type::QVariantList )
3215 if ( minValueExpr == maxValueExpr )
3217 expression = minValueExpr;
3223 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin ).arg( zoomMax ).arg( minValueExpr ).arg( maxValueExpr );
3227 expression = QStringLiteral(
"scale_exponential(@vector_tile_zoom,%1,%2,%3,%4,%5)" ).arg( zoomMin ).arg( zoomMax ).arg( minValueExpr ).arg( maxValueExpr ).arg( base );
3231 if ( multiplier != 1 )
3232 return QStringLiteral(
"(%1) * %2" ).arg( expression ).arg( multiplier );
3239 if ( style == QLatin1String(
"round" ) )
3240 return Qt::RoundCap;
3241 else if ( style == QLatin1String(
"square" ) )
3242 return Qt::SquareCap;
3249 if ( style == QLatin1String(
"bevel" ) )
3250 return Qt::BevelJoin;
3251 else if ( style == QLatin1String(
"round" ) )
3252 return Qt::RoundJoin;
3254 return Qt::MiterJoin;
3259 QString op = expression.value( 0 ).toString();
3260 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
3262 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ),
3264 parseValue( expression.value( 2 ), context ) );
3266 else if ( op == QLatin1String(
"to-number" ) )
3268 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
3270 if ( op == QLatin1String(
"literal" ) )
3272 return expression.value( 1 ).toString();
3274 else if ( op == QLatin1String(
"all" )
3275 || op == QLatin1String(
"any" )
3276 || op == QLatin1String(
"none" ) )
3279 for (
int i = 1; i < expression.size(); ++i )
3281 const QString part = parseValue( expression.at( i ), context );
3282 if ( part.isEmpty() )
3284 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3290 if ( op == QLatin1String(
"none" ) )
3291 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
3293 QString operatorString;
3294 if ( op == QLatin1String(
"all" ) )
3295 operatorString = QStringLiteral(
") AND (" );
3296 else if ( op == QLatin1String(
"any" ) )
3297 operatorString = QStringLiteral(
") OR (" );
3299 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
3301 else if ( op ==
'!' )
3304 QVariantList contraJsonExpr = expression.value( 1 ).toList();
3305 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
3307 return parseKey( contraJsonExpr, context );
3309 else if ( op == QLatin1String(
"==" )
3310 || op == QLatin1String(
"!=" )
3311 || op == QLatin1String(
">=" )
3313 || op == QLatin1String(
"<=" )
3317 if ( op == QLatin1String(
"==" ) )
3318 op = QStringLiteral(
"IS" );
3319 else if ( op == QLatin1String(
"!=" ) )
3320 op = QStringLiteral(
"IS NOT" );
3321 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
3322 op, parseValue( expression.value( 2 ), context ) );
3324 else if ( op == QLatin1String(
"has" ) )
3326 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
3328 else if ( op == QLatin1String(
"!has" ) )
3330 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
3332 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
3334 const QString key = parseKey( expression.value( 1 ), context );
3337 QVariantList values = expression.mid( 2 );
3338 if ( expression.size() == 3
3339 && expression.at( 2 ).userType() == QMetaType::Type::QVariantList && expression.at( 2 ).toList().count() > 1
3340 && expression.at( 2 ).toList().at( 0 ).toString() == QLatin1String(
"literal" ) )
3342 values = expression.at( 2 ).toList().at( 1 ).toList();
3345 for (
const QVariant &value : std::as_const( values ) )
3347 const QString part = parseValue( value, context );
3348 if ( part.isEmpty() )
3350 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3355 if ( op == QLatin1String(
"in" ) )
3356 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3358 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3360 else if ( op == QLatin1String(
"get" ) )
3362 return parseKey( expression.value( 1 ), context );
3364 else if ( op == QLatin1String(
"match" ) )
3366 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
3368 if ( expression.size() == 5
3369 && expression.at( 3 ).userType() == QMetaType::Type::Bool && expression.at( 3 ).toBool() ==
true
3370 && expression.at( 4 ).userType() == QMetaType::Type::Bool && expression.at( 4 ).toBool() ==
false )
3373 if ( expression.at( 2 ).userType() == QMetaType::Type::QVariantList || expression.at( 2 ).userType() == QMetaType::Type::QStringList )
3376 for (
const QVariant &p : expression.at( 2 ).toList() )
3378 parts << parseValue( p, context );
3381 if ( parts.size() > 1 )
3386 else if ( expression.at( 2 ).userType() == QMetaType::Type::QString || expression.at( 2 ).userType() == QMetaType::Type::Int
3387 || expression.at( 2 ).userType() == QMetaType::Type::Double || expression.at( 2 ).userType() == QMetaType::Type::LongLong )
3393 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3399 QString caseString = QStringLiteral(
"CASE " );
3400 for (
int i = 2; i < expression.size() - 2; i += 2 )
3402 if ( expression.at( i ).userType() == QMetaType::Type::QVariantList || expression.at( i ).userType() == QMetaType::Type::QStringList )
3405 for (
const QVariant &p : expression.at( i ).toList() )
3410 if ( parts.size() > 1 )
3415 else if ( expression.at( i ).userType() == QMetaType::Type::QString || expression.at( i ).userType() == QMetaType::Type::Int
3416 || expression.at( i ).userType() == QMetaType::Type::Double || expression.at( i ).userType() == QMetaType::Type::LongLong )
3421 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
3423 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
3427 else if ( op == QLatin1String(
"to-string" ) )
3429 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3431 else if ( op == QLatin1String(
"to-boolean" ) )
3433 return QStringLiteral(
"to_bool(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3435 else if ( op == QLatin1String(
"case" ) )
3437 QString caseString = QStringLiteral(
"CASE" );
3438 for (
int i = 1; i < expression.size() - 2; i += 2 )
3440 const QString condition =
parseExpression( expression.value( i ).toList(), context );
3441 const QString value = parseValue( expression.value( i + 1 ), context );
3442 caseString += QStringLiteral(
" WHEN (%1) THEN %2" ).arg( condition, value );
3444 const QString value = parseValue( expression.constLast(), context );
3445 caseString += QStringLiteral(
" ELSE %1 END" ).arg( value );
3448 else if ( op == QLatin1String(
"zoom" ) && expression.count() == 1 )
3450 return QStringLiteral(
"@vector_tile_zoom" );
3452 else if ( op == QLatin1String(
"concat" ) )
3454 QString concatString = QStringLiteral(
"concat(" );
3455 for (
int i = 1; i < expression.size(); i++ )
3458 concatString += QLatin1String(
", " );
3459 concatString += parseValue( expression.value( i ), context );
3461 concatString += QLatin1Char(
')' );
3462 return concatString;
3464 else if ( op == QLatin1String(
"length" ) )
3466 return QStringLiteral(
"length(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3468 else if ( op == QLatin1String(
"step" ) )
3470 const QString stepExpression =
parseExpression( expression.value( 1 ).toList(), context );
3471 if ( stepExpression.isEmpty() )
3473 context.
pushWarning( QObject::tr(
"%1: Could not interpret step list" ).arg( context.
layerId() ) );
3477 QString caseString = QStringLiteral(
"CASE " );
3479 for (
int i = expression.length() - 2; i > 0; i -= 2 )
3481 const QString stepValue = parseValue( expression.value( i + 1 ), context, colorExpected );
3485 caseString += QStringLiteral(
" WHEN %1 >= %2 THEN (%3) " ).arg( stepExpression, stepKey, stepValue );
3489 caseString += QStringLiteral(
"ELSE (%1) END" ).arg( stepValue );
3496 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression \"%2\"" ).arg( context.
layerId(), op ) );
3505 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3509 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
3510 if ( spriteDefinition.size() == 0 )
3512 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3516 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
3517 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
3518 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
3519 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
3520 if ( sprite.isNull() )
3522 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3526 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
3534 auto prepareBase64 = [](
const QImage & sprite )
3537 if ( !sprite.isNull() )
3540 QBuffer buffer( &blob );
3541 buffer.open( QIODevice::WriteOnly );
3542 sprite.save( &buffer,
"PNG" );
3544 const QByteArray encoded = blob.toBase64();
3545 path = QString( encoded );
3546 path.prepend( QLatin1String(
"base64:" ) );
3551 switch ( value.userType() )
3553 case QMetaType::Type::QString:
3555 QString spriteName = value.toString();
3556 const thread_local QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
3557 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
3558 if ( match.hasMatch() )
3560 const QString fieldName = match.captured( 1 );
3561 spriteProperty = QStringLiteral(
"CASE" );
3562 spriteSizeProperty = QStringLiteral(
"CASE" );
3564 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
3565 spriteName.replace(
")", QLatin1String(
"\\)" ) );
3566 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
3567 const QRegularExpression fieldValueMatch( spriteName );
3569 for (
const QString &name : spriteNames )
3571 match = fieldValueMatch.match( name );
3572 if ( match.hasMatch() )
3576 const QString fieldValue = match.captured( 1 );
3578 path = prepareBase64( sprite );
3579 if ( spritePath.isEmpty() && !path.isEmpty() )
3585 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
3586 .arg( fieldName, fieldValue, path );
3587 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
3588 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
3592 spriteProperty += QLatin1String(
" END" );
3593 spriteSizeProperty += QLatin1String(
" END" );
3597 spriteProperty.clear();
3598 spriteSizeProperty.clear();
3599 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
3600 spritePath = prepareBase64( sprite );
3605 case QMetaType::Type::QVariantMap:
3607 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3608 if ( stops.size() == 0 )
3615 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3616 spritePath = prepareBase64( sprite );
3618 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3619 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3621 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3622 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3623 .arg( spriteSize.width() );
3625 for (
int i = 0; i < stops.size() - 1; ++i )
3628 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3629 path = prepareBase64( sprite );
3631 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3633 .arg( stops.value( i ).toList().value( 0 ).toString(),
3634 stops.value( i + 1 ).toList().value( 0 ).toString(),
3636 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3638 .arg( stops.value( i ).toList().value( 0 ).toString(),
3639 stops.value( i + 1 ).toList().value( 0 ).toString() )
3640 .arg( size.width() );
3642 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3643 path = prepareBase64( sprite );
3645 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3647 .arg( stops.last().toList().value( 0 ).toString() )
3649 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3651 .arg( stops.last().toList().value( 0 ).toString() )
3652 .arg( size.width() );
3656 case QMetaType::Type::QVariantList:
3658 const QVariantList json = value.toList();
3659 const QString method = json.value( 0 ).toString();
3661 if ( method == QLatin1String(
"match" ) )
3663 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3664 if ( attribute.isEmpty() )
3666 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3670 spriteProperty = QStringLiteral(
"CASE" );
3671 spriteSizeProperty = QStringLiteral(
"CASE" );
3673 for (
int i = 2; i < json.length() - 1; i += 2 )
3675 const QVariant matchKey = json.value( i );
3676 const QVariant matchValue = json.value( i + 1 );
3677 QString matchString;
3678 switch ( matchKey.userType() )
3680 case QMetaType::Type::QVariantList:
3681 case QMetaType::Type::QStringList:
3683 const QVariantList keys = matchKey.toList();
3684 QStringList matchStringList;
3685 for (
const QVariant &key : keys )
3689 matchString = matchStringList.join(
',' );
3693 case QMetaType::Type::Bool:
3694 case QMetaType::Type::QString:
3695 case QMetaType::Type::Int:
3696 case QMetaType::Type::LongLong:
3697 case QMetaType::Type::Double:
3704 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( value.userType() ) ) ) );
3709 const QImage sprite =
retrieveSprite( matchValue.toString(), context, spriteSize );
3710 spritePath = prepareBase64( sprite );
3712 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3713 "THEN '%3'" ).arg( attribute,
3717 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3718 "THEN %3" ).arg( attribute,
3719 matchString ).arg( spriteSize.width() );
3722 if ( !json.constLast().toString().isEmpty() )
3724 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3725 spritePath = prepareBase64( sprite );
3729 spritePath = QString();
3732 spriteProperty += QStringLiteral(
" ELSE '%1' END" ).arg( spritePath );
3733 spriteSizeProperty += QStringLiteral(
" ELSE %3 END" ).arg( spriteSize.width() );
3736 else if ( method == QLatin1String(
"step" ) )
3738 const QString expression =
parseExpression( json.value( 1 ).toList(), context );
3739 if ( expression.isEmpty() )
3741 context.
pushWarning( QObject::tr(
"%1: Could not interpret step list" ).arg( context.
layerId() ) );
3745 spriteProperty = QStringLiteral(
"CASE" );
3746 spriteSizeProperty = QStringLiteral(
"CASE" );
3747 for (
int i = json.length() - 2; i > 2; i -= 2 )
3750 const QString stepValue = json.value( i + 1 ).toString();
3752 const QImage sprite =
retrieveSprite( stepValue, context, spriteSize );
3753 spritePath = prepareBase64( sprite );
3755 spriteProperty += QStringLiteral(
" WHEN %1 >= %2 THEN '%3' " ).arg( expression, stepKey, spritePath );
3756 spriteSizeProperty += QStringLiteral(
" WHEN %1 >= %2 THEN %3 " ).arg( expression ).arg( stepKey ).arg( spriteSize.width() );
3759 const QImage sprite =
retrieveSprite( json.at( 2 ).toString(), context, spriteSize );
3760 spritePath = prepareBase64( sprite );
3762 spriteProperty += QStringLiteral(
"ELSE '%1' END" ).arg( spritePath );
3763 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3766 else if ( method == QLatin1String(
"case" ) )
3768 spriteProperty = QStringLiteral(
"CASE" );
3769 spriteSizeProperty = QStringLiteral(
"CASE" );
3770 for (
int i = 1; i < json.length() - 2; i += 2 )
3772 const QString caseExpression =
parseExpression( json.value( i ).toList(), context );
3773 const QString caseValue = json.value( i + 1 ).toString();
3775 const QImage sprite =
retrieveSprite( caseValue, context, spriteSize );
3776 spritePath = prepareBase64( sprite );
3778 spriteProperty += QStringLiteral(
" WHEN %1 THEN '%2' " ).arg( caseExpression, spritePath );
3779 spriteSizeProperty += QStringLiteral(
" WHEN %1 THEN %2 " ).arg( caseExpression ).arg( spriteSize.width() );
3781 const QImage sprite =
retrieveSprite( json.last().toString(), context, spriteSize );
3782 spritePath = prepareBase64( sprite );
3784 spriteProperty += QStringLiteral(
"ELSE '%1' END" ).arg( spritePath );
3785 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3790 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3796 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName(
static_cast<QMetaType::Type
>( value.userType() ) ) ) );
3806 switch ( value.userType() )
3808 case QMetaType::Type::QVariantList:
3809 case QMetaType::Type::QStringList:
3812 case QMetaType::Type::Bool:
3813 case QMetaType::Type::QString:
3814 if ( colorExpected )
3819 return parseValue(
c, context );
3824 case QMetaType::Type::Int:
3825 case QMetaType::Type::LongLong:
3826 case QMetaType::Type::Double:
3827 return value.toString();
3829 case QMetaType::Type::QColor:
3830 c = value.value<QColor>();
3831 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3834 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3842 if ( value.toString() == QLatin1String(
"$type" ) )
3844 return QStringLiteral(
"_geom_type" );
3846 if ( value.toString() == QLatin1String(
"level" ) )
3848 return QStringLiteral(
"level" );
3850 else if ( ( value.userType() == QMetaType::Type::QVariantList && value.toList().size() == 1 ) || value.userType() == QMetaType::Type::QStringList )
3852 if ( value.toList().size() > 1 )
3853 return value.toList().at( 1 ).toString();
3856 QString valueString = value.toList().value( 0 ).toString();
3857 if ( valueString == QLatin1String(
"geometry-type" ) )
3859 return QStringLiteral(
"_geom_type" );
3864 else if ( value.userType() == QMetaType::Type::QVariantList && value.toList().size() > 1 )
3871QString QgsMapBoxGlStyleConverter::processLabelField(
const QString &
string,
bool &isExpression )
3875 const thread_local QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
3876 const QRegularExpressionMatch match = singleFieldRx.match(
string );
3877 if ( match.hasMatch() )
3879 isExpression =
false;
3880 return match.captured( 1 );
3883 const thread_local QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
3884 const QStringList parts =
string.split( multiFieldRx );
3885 if ( parts.size() > 1 )
3887 isExpression =
true;
3890 for (
const QString &part : parts )
3892 if ( part.isEmpty() )
3895 if ( !part.contains(
'{' ) )
3902 const QStringList split = part.split(
'}' );
3904 if ( !split.at( 1 ).isEmpty() )
3907 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
3911 isExpression =
false;
3918 return mRenderer ? mRenderer->clone() :
nullptr;
3923 return mLabeling ? mLabeling->clone() :
nullptr;
3933 return mRasterSubLayers;
3938 QList<QgsMapLayer *> subLayers;
3941 const QString sourceName = subLayer.source();
3942 std::unique_ptr< QgsRasterLayer > rl;
3949 rl->pipe()->setDataDefinedProperties( subLayer.dataDefinedProperties() );
3956 subLayers.append( rl.release() );
3965 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3968 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3969 context = tmpContext.get();
3974 if (
string.compare( QLatin1String(
"vector" ), Qt::CaseInsensitive ) == 0 )
3976 else if (
string.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
3978 else if (
string.compare( QLatin1String(
"raster-dem" ), Qt::CaseInsensitive ) == 0 )
3980 else if (
string.compare( QLatin1String(
"geojson" ), Qt::CaseInsensitive ) == 0 )
3982 else if (
string.compare( QLatin1String(
"image" ), Qt::CaseInsensitive ) == 0 )
3984 else if (
string.compare( QLatin1String(
"video" ), Qt::CaseInsensitive ) == 0 )
3986 context->
pushWarning( QObject::tr(
"Invalid source type \"%1\" for source \"%2\"" ).arg(
string, name ) );
3992 const QString name = it.key();
3993 const QVariantMap jsonSource = it.value().toMap();
3994 const QString typeString = jsonSource.value( QStringLiteral(
"type" ) ).toString();
4017 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
4020 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
4021 context = tmpContext.get();
4024 std::unique_ptr< QgsMapBoxGlStyleRasterSource > raster = std::make_unique< QgsMapBoxGlStyleRasterSource >( name );
4025 if ( raster->setFromJson( source, context ) )
4026 mSources.append( raster.release() );
4029bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
4031 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
4033 bool bDoubleOk, tDoubleOk;
4034 bottom = bottomVariant.toDouble( &bDoubleOk );
4035 top = topVariant.toDouble( &tDoubleOk );
4036 return ( bDoubleOk && tDoubleOk );
4047 mWarnings << warning;
4062 return mSizeConversionFactor;
4067 mSizeConversionFactor = sizeConversionFactor;
4072 return mSpriteImage;
4077 return mSpriteDefinitions;
4082 mSpriteImage = image;
4083 mSpriteDefinitions = definitions;
4133 mAttribution = json.value( QStringLiteral(
"attribution" ) ).toString();
4135 const QString scheme = json.value( QStringLiteral(
"scheme" ), QStringLiteral(
"xyz" ) ).toString();
4136 if ( scheme.compare( QLatin1String(
"xyz" ) ) == 0 )
4142 context->
pushWarning( QObject::tr(
"%1 scheme is not supported for raster source %2" ).arg( scheme,
name() ) );
4146 mMinZoom = json.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"0" ) ).toInt();
4147 mMaxZoom = json.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"22" ) ).toInt();
4148 mTileSize = json.value( QStringLiteral(
"tileSize" ), QStringLiteral(
"512" ) ).toInt();
4150 const QVariantList
tiles = json.value( QStringLiteral(
"tiles" ) ).toList();
4151 for (
const QVariant &tile :
tiles )
4153 mTiles.append( tile.toString() );
4162 parts.insert( QStringLiteral(
"type" ), QStringLiteral(
"xyz" ) );
4163 parts.insert( QStringLiteral(
"url" ), mTiles.value( 0 ) );
4165 if ( mTileSize == 256 )
4166 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"1" ) );
4167 else if ( mTileSize == 512 )
4168 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"2" ) );
4170 parts.insert( QStringLiteral(
"zmax" ), QString::number( mMaxZoom ) );
4171 parts.insert( QStringLiteral(
"zmin" ), QString::number( mMinZoom ) );
4173 std::unique_ptr< QgsRasterLayer > rl = std::make_unique< QgsRasterLayer >(
QgsProviderRegistry::instance()->encodeUri( QStringLiteral(
"wms" ), parts ),
name(), QStringLiteral(
"wms" ) );
4174 return rl.release();
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
@ OnLine
Labels can be placed directly over a line feature.
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ CentralPoint
Place symbols at the mid point of the line.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ FollowPlacement
Alignment follows placement of label, e.g., labels to the left of a feature will be drawn with right ...
RenderUnit
Rendering size units.
MapBoxGlStyleSourceType
Available MapBox GL style source types.
@ RasterDem
Raster DEM source.
@ Unknown
Other/unknown source type.
@ Viewport
Relative to the whole viewport/output device.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
A paint effect which blurs a source picture, using a number of different blur methods.
void setBlurUnit(const Qgis::RenderUnit unit)
Sets the units used for the blur level (radius).
@ StackBlur
Stack blur, a fast but low quality blur. Valid blur level values are between 0 - 16.
void setBlurMethod(const BlurMethod method)
Sets the blur method (algorithm) to use for performing the blur.
void setBlurLevel(const double level)
Sets blur level (radius)
A paint effect which consists of a stack of other chained paint effects.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QMetaType::Type fieldType=QMetaType::Type::UnknownType)
Create an expression allowing to evaluate if a field is equal to a value.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QString processFontFamilyName(const QString &name) const
Processes a font family name, applying any matching fontFamilyReplacements() to the name.
static QFont createFont(const QString &family, int pointSize=-1, int weight=-1, bool italic=false)
Creates a font with the specified family.
static bool fontFamilyHasStyle(const QString &family, const QString &style)
Check whether font family on system has specific style.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
void setPlacementFlags(Qgis::LabelLinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setFactor(double factor)
Sets the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
void setQuadrant(Qgis::LabelQuadrantPosition quadrant)
Sets the quadrant in which to offset labels from the point.
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setOffset(double offset)
Sets the line's offset.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the line's offset.
Abstract base class for MapBox GL style sources.
QString name() const
Returns the source's name.
virtual ~QgsMapBoxGlStyleAbstractSource()
QgsMapBoxGlStyleAbstractSource(const QString &name)
Constructor for QgsMapBoxGlStyleAbstractSource.
Context for a MapBox GL style conversion operation.
void setLayerId(const QString &value)
Sets the layer ID of the layer currently being converted.
QStringList warnings() const
Returns a list of warning messages generated during the conversion.
void pushWarning(const QString &warning)
Pushes a warning message generated during the conversion.
double pixelSizeConversionFactor() const
Returns the pixel size conversion factor, used to scale the original pixel sizes when converting styl...
void setTargetUnit(Qgis::RenderUnit targetUnit)
Sets the target unit type.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
Qgis::RenderUnit targetUnit() const
Returns the target unit type.
void setSprites(const QImage &image, const QVariantMap &definitions)
Sets the sprite image and definitions JSON to use during conversion.
QString layerId() const
Returns the layer ID of the layer currently being converted.
QImage spriteImage() const
Returns the sprite image to use during conversion, or an invalid image if this is not set.
void clearWarnings()
Clears the list of warning messages.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
static QString parseOpacityStops(double base, const QVariantList &stops, int maxOpacity, QgsMapBoxGlStyleConversionContext &context)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate alpha ...
static QString parseColorExpression(const QVariant &colorExpression, QgsMapBoxGlStyleConversionContext &context)
Converts an expression representing a color to a string (can be color string or an expression where a...
static QString parseStops(double base, const QVariantList &stops, double multiplier, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
static QString parseExpression(const QVariantList &expression, QgsMapBoxGlStyleConversionContext &context, bool colorExpected=false)
Converts a MapBox GL expression to a QGIS expression.
PropertyType
Property types, for interpolated value conversion.
@ Point
Point/offset property.
@ Numeric
Numeric property (e.g. line width, text size)
@ Opacity
Opacity property.
@ NumericArray
Numeric array for dash arrays or such.
QList< QgsMapBoxGlStyleAbstractSource * > sources()
Returns the list of converted sources.
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
QList< QgsMapBoxGlStyleRasterSubLayer > rasterSubLayers() const
Returns a list of raster sub layers contained in the style.
static QgsProperty parseInterpolateByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, double *defaultNumber=nullptr)
Parses a numeric value which is interpolated by zoom range.
static Qt::PenJoinStyle parseJoinStyle(const QString &style)
Converts a value to Qt::PenJoinStyle enum from JSON value.
static QgsProperty parseInterpolateStringByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Interpolates a string by zoom.
static QString interpolateExpression(double zoomMin, double zoomMax, QVariant valueMin, QVariant valueMax, double base, double multiplier=1, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Generates an interpolation for values between valueMin and valueMax, scaled between the ranges zoomMi...
static QgsProperty parseStepList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a match function value list.
static QgsProperty parseInterpolatePointByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, QPointF *defaultPoint=nullptr)
Interpolates a point/offset with either scale_linear() or scale_exp() (depending on base value).
static bool parseCircleLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a circle layer.
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
static QgsProperty parseInterpolateListByZoom(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Interpolates a list which starts with the interpolate function.
~QgsMapBoxGlStyleConverter()
QList< QgsMapLayer * > createSubLayers() const
Returns a list of new map layers corresponding to sublayers of the style, e.g.
Result
Result of conversion.
@ Success
Conversion was successful.
@ NoLayerList
No layer list was found in JSON input.
QgsMapBoxGlStyleConverter()
Constructor for QgsMapBoxGlStyleConverter.
static QImage retrieveSprite(const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize)
Retrieves the sprite image with the specified name, taken from the specified context.
static QString parseLabelStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops containing label values.
void parseLayers(const QVariantList &layers, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of layers from JSON.
static QgsProperty parseInterpolateColorByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, QColor *defaultColor=nullptr)
Parses a color value which is interpolated by zoom range.
static QString retrieveSpriteAsBase64WithProperties(const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize, QString &spriteProperty, QString &spriteSizeProperty)
Retrieves the sprite image with the specified name, taken from the specified context as a base64 enco...
static QgsProperty parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
void parseSources(const QVariantMap &sources, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of sources from JSON.
static QColor parseColor(const QVariant &color, QgsMapBoxGlStyleConversionContext &context)
Parses a color in one of these supported formats:
static bool parseSymbolLayerAsRenderer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as a renderer.
static bool parseFillLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context, bool isBackgroundStyle=false)
Parses a fill layer.
static void parseSymbolLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, bool &hasRenderer, QgsVectorTileBasicLabelingStyle &labelingStyle, bool &hasLabeling, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as renderer or labeling.
static bool parseLineLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a line layer.
void parseRasterSource(const QVariantMap &source, const QString &name, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse a raster source from JSON.
static void colorAsHslaComponents(const QColor &color, int &hue, int &saturation, int &lightness, int &alpha)
Takes a QColor object and returns HSLA components in required format for QGIS color_hsla() expression...
static Qt::PenCapStyle parseCapStyle(const QString &style)
Converts a value to Qt::PenCapStyle enum from JSON value.
static QString parseStringStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Parses a list of interpolation stops containing string values.
static QgsProperty parseMatchList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a match function value list.
static QgsProperty parseValueList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a value list (e.g.
static QString parseArrayStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes numerical arrays from stops.
static QString parsePointStops(double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate point/...
Encapsulates a MapBox GL style raster source.
Qgis::MapBoxGlStyleSourceType type() const override
Returns the source type.
QgsMapBoxGlStyleRasterSource(const QString &name)
Constructor for QgsMapBoxGlStyleRasterSource.
QgsRasterLayer * toRasterLayer() const
Returns a new raster layer representing the raster source, or nullptr if the source cannot be represe...
bool setFromJson(const QVariantMap &json, QgsMapBoxGlStyleConversionContext *context) override
Sets the source's state from a json map.
QStringList tiles() const
Returns the list of tile sources.
Encapsulates a MapBox GL style raster sub layer.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the layer's data defined properties.
QgsMapBoxGlStyleRasterSubLayer(const QString &id, const QString &source)
Constructor for QgsMapBoxGlStyleRasterSubLayer, with the given id and source.
Line symbol layer type which draws repeating marker symbols along a line feature.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
virtual void setSize(double size)
Sets the symbol size.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
void setAngle(double angle)
Sets the rotation angle for the marker.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
const QgsLabelObstacleSettings & obstacleSettings() const
Returns the label obstacle settings.
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
int priority
Label priority.
double angleOffset
Label rotation, in degrees clockwise.
Qgis::RenderUnit offsetUnits
Units for offsets of label.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label's property collection, used for data defined overrides.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
double dist
Distance from feature to the label.
Qgis::RenderUnit distUnits
Units the distance from feature to the label.
@ LinePlacementOptions
Line placement flags.
@ LabelRotation
Label rotation.
@ FontStyle
Font style name.
@ FontLetterSpacing
Letter spacing.
QString fieldName
Name of field (or an expression) to use for label text.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
const QgsLabelPointSettings & pointSettings() const
Returns the label point settings, which contain settings related to how the label engine places and f...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const final
Returns the calculated value of the property with the specified key from within the collection.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
QString expressionString() const
Returns the expression used for the property value.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
void setExpressionString(const QString &expression)
Sets the expression to use for the property value.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
A class for filling symbols with a repeated raster image.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the unit for the image's width and height.
void setOpacity(double opacity)
Sets the opacity for the raster image used in the fill.
void setImageFilePath(const QString &imagePath)
Sets the path to the raster image used for the fill.
void setWidth(double width)
Sets the width for scaling the image used in the fill.
void setCoordinateMode(Qgis::SymbolCoordinateReference mode)
Set the coordinate mode for fill.
Represents a raster layer.
Line symbol layer type which draws line sections using a raster image file.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Raster marker symbol layer class.
void setOpacity(double opacity)
Set the marker opacity.
void setPath(const QString &path)
Set the marker raster image path.
@ RendererOpacity
Raster renderer global opacity.
Renders polygons using a single fill and stroke color.
void setBrushStyle(Qt::BrushStyle style)
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setStrokeWidth(double strokeWidth)
void setStrokeStyle(Qt::PenStyle strokeStyle)
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the fill's offset.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setOffset(QPointF offset)
Sets an offset by which polygons will be translated during rendering.
void setStrokeColor(const QColor &strokeColor) override
Sets the stroke color for the symbol layer.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setStrokeWidthUnit(Qgis::RenderUnit u)
Sets the unit for the width of the marker's stroke.
void setStrokeWidth(double w)
Sets the width of the marker's stroke.
void setStrokeColor(const QColor &color) override
Sets the marker's stroke color.
static QColor parseColor(const QString &colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
@ File
Filename, eg for svg files.
@ CustomDash
Custom dash pattern.
@ Name
Name, eg shape name for simple markers.
@ StrokeColor
Stroke color.
@ Interval
Line marker interval.
@ StrokeWidth
Stroke width.
@ LayerEnabled
Whether symbol layer is enabled.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
Container for settings relating to a text background object.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
@ ShapeMarkerSymbol
Marker symbol.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the shape's size.
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
void setSize(QSizeF size)
Sets the size of the background shape.
void setColor(const QColor &color)
Sets the color for the buffer.
void setOpacity(double opacity)
Sets the buffer opacity.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QFont font() const
Returns the font used for rendering text.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
Configuration of a single style within QgsVectorTileBasicLabeling.
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit).
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit).
void setStyleName(const QString &name)
Sets human readable name of this style.
void setGeometryType(Qgis::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
void setLabelSettings(const QgsPalLayerSettings &settings)
Sets labeling configuration of this style.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
Basic labeling configuration for vector tile layers.
Definition of map rendering of a subset of vector tile data.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit).
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setSymbol(QgsSymbol *sym)
Sets symbol for rendering. Takes ownership of the symbol.
void setStyleName(const QString &name)
Sets human readable name of this style.
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit).
void setGeometryType(Qgis::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
The default vector tile renderer implementation.
Base class for labeling configuration classes for vector tile layers.
Abstract base class for all vector tile renderer implementations.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugError(str)
QList< QgsSymbolLayer * > QgsSymbolLayerList