47#include <QRegularExpression>
58 if ( style.contains( QStringLiteral(
"sources" ) ) )
60 parseSources( style.value( QStringLiteral(
"sources" ) ).toMap(), context );
63 if ( style.contains( QStringLiteral(
"layers" ) ) )
65 parseLayers( style.value( QStringLiteral(
"layers" ) ).toList(), context );
69 mError = QObject::tr(
"Could not find layers list in JSON" );
82 qDeleteAll( mSources );
87 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
90 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
91 context = tmpContext.get();
94 QList<QgsVectorTileBasicRendererStyle> rendererStyles;
95 QList<QgsVectorTileBasicLabelingStyle> labelingStyles;
98 bool hasRendererBackgroundStyle =
false;
100 for (
const QVariant &layer : layers )
102 const QVariantMap jsonLayer = layer.toMap();
104 const QString layerType = jsonLayer.value( QStringLiteral(
"type" ) ).toString();
105 if ( layerType == QLatin1String(
"background" ) )
107 hasRendererBackgroundStyle =
parseFillLayer( jsonLayer, rendererBackgroundStyle, *context,
true );
108 if ( hasRendererBackgroundStyle )
118 const QString styleId = jsonLayer.value( QStringLiteral(
"id" ) ).toString();
121 if ( layerType.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
124 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
125 if ( jsonPaint.contains( QStringLiteral(
"raster-opacity" ) ) )
127 const QVariant jsonRasterOpacity = jsonPaint.value( QStringLiteral(
"raster-opacity" ) );
128 double defaultOpacity = 1;
132 mRasterSubLayers.append( raster );
136 const QString layerName = jsonLayer.value( QStringLiteral(
"source-layer" ) ).toString();
138 const int minZoom = jsonLayer.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"-1" ) ).toInt();
147 int maxZoom = jsonLayer.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"-1" ) ).toInt();
151 const bool enabled = jsonLayer.value( QStringLiteral(
"visibility" ) ).toString() != QLatin1String(
"none" );
153 QString filterExpression;
154 if ( jsonLayer.contains( QStringLiteral(
"filter" ) ) )
156 filterExpression =
parseExpression( jsonLayer.value( QStringLiteral(
"filter" ) ).toList(), *context );
162 bool hasRendererStyle =
false;
163 bool hasLabelingStyle =
false;
164 if ( layerType == QLatin1String(
"fill" ) )
166 hasRendererStyle =
parseFillLayer( jsonLayer, rendererStyle, *context );
168 else if ( layerType == QLatin1String(
"line" ) )
170 hasRendererStyle =
parseLineLayer( jsonLayer, rendererStyle, *context );
172 else if ( layerType == QLatin1String(
"circle" ) )
176 else if ( layerType == QLatin1String(
"symbol" ) )
178 parseSymbolLayer( jsonLayer, rendererStyle, hasRendererStyle, labelingStyle, hasLabelingStyle, *context );
182 mWarnings << QObject::tr(
"%1: Skipping unknown layer type %2" ).arg( context->
layerId(), layerType );
187 if ( hasRendererStyle )
195 rendererStyles.append( rendererStyle );
198 if ( hasLabelingStyle )
206 labelingStyles.append( labelingStyle );
209 mWarnings.append( context->
warnings() );
213 if ( hasRendererBackgroundStyle )
214 rendererStyles.prepend( rendererBackgroundStyle );
216 mRenderer = std::make_unique< QgsVectorTileBasicRenderer >();
218 renderer->setStyles( rendererStyles );
220 mLabeling = std::make_unique< QgsVectorTileBasicLabeling >();
222 labeling->setStyles( labelingStyles );
227 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
232 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsFillSymbol >() );
236 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) ) )
238 const QVariant jsonFillColor = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) );
239 switch ( jsonFillColor.type() )
246 case QVariant::StringList:
250 case QVariant::String:
251 fillColor =
parseColor( jsonFillColor.toString(), context );
256 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonFillColor.type() ) ) );
264 fillColor = QColor( 0, 0, 0 );
267 QColor fillOutlineColor;
268 if ( !isBackgroundStyle )
270 if ( !jsonPaint.contains( QStringLiteral(
"fill-outline-color" ) ) )
272 if ( fillColor.isValid() )
273 fillOutlineColor = fillColor;
281 const QVariant jsonFillOutlineColor = jsonPaint.value( QStringLiteral(
"fill-outline-color" ) );
282 switch ( jsonFillOutlineColor.type() )
289 case QVariant::StringList:
293 case QVariant::String:
294 fillOutlineColor =
parseColor( jsonFillOutlineColor.toString(), context );
298 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-outline-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonFillOutlineColor.type() ) ) );
304 double fillOpacity = -1.0;
305 double rasterOpacity = -1.0;
306 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) ) )
308 const QVariant jsonFillOpacity = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) );
309 switch ( jsonFillOpacity.type() )
312 case QVariant::LongLong:
313 case QVariant::Double:
314 fillOpacity = jsonFillOpacity.toDouble();
315 rasterOpacity = fillOpacity;
332 case QVariant::StringList:
346 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonFillOpacity.type() ) ) );
352 QPointF fillTranslate;
353 if ( jsonPaint.contains( QStringLiteral(
"fill-translate" ) ) )
355 const QVariant jsonFillTranslate = jsonPaint.value( QStringLiteral(
"fill-translate" ) );
356 switch ( jsonFillTranslate.type() )
364 case QVariant::StringList:
370 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonFillTranslate.type() ) ) );
376 Q_ASSERT( fillSymbol );
379 symbol->setOutputUnit( context.
targetUnit() );
382 if ( !fillTranslate.isNull() )
388 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) ) )
392 const QVariant fillPatternJson = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) );
395 fillColor = QColor();
396 fillOutlineColor = QColor();
403 QString spriteProperty, spriteSizeProperty;
404 const QString sprite =
retrieveSpriteAsBase64( fillPatternJson, context, spriteSize, spriteProperty, spriteSizeProperty );
405 if ( !sprite.isEmpty() )
410 rasterFill->
setWidth( spriteSize.width() );
414 if ( rasterOpacity >= 0 )
419 if ( !spriteProperty.isEmpty() )
426 symbol->appendSymbolLayer( rasterFill );
432 if ( fillOpacity != -1 )
434 symbol->setOpacity( fillOpacity );
437 if ( fillOutlineColor.isValid() )
446 if ( fillColor.isValid() )
462 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
464 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
469 QString rasterLineSprite;
471 const QVariantMap jsonPaint = jsonLayer.
value( QStringLiteral(
"paint" ) ).toMap();
472 if ( jsonPaint.contains( QStringLiteral(
"line-pattern" ) ) )
474 const QVariant jsonLinePattern = jsonPaint.value( QStringLiteral(
"line-pattern" ) );
475 switch ( jsonLinePattern.type() )
478 case QVariant::String:
481 QString spriteProperty, spriteSizeProperty;
482 rasterLineSprite =
retrieveSpriteAsBase64( jsonLinePattern, context, spriteSize, spriteProperty, spriteSizeProperty );
488 case QVariant::StringList:
493 if ( rasterLineSprite.isEmpty() )
496 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
503 if ( jsonPaint.contains( QStringLiteral(
"line-color" ) ) )
505 const QVariant jsonLineColor = jsonPaint.value( QStringLiteral(
"line-color" ) );
506 switch ( jsonLineColor.type() )
514 case QVariant::StringList:
519 case QVariant::String:
520 lineColor =
parseColor( jsonLineColor.toString(), context );
524 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineColor.type() ) ) );
531 lineColor = QColor( 0, 0, 0 );
537 if ( jsonPaint.contains( QStringLiteral(
"line-width" ) ) )
539 const QVariant jsonLineWidth = jsonPaint.
value( QStringLiteral(
"line-width" ) );
540 switch ( jsonLineWidth.type() )
543 case QVariant::LongLong:
544 case QVariant::Double:
555 case QVariant::StringList:
561 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineWidth.type() ) ) );
566 double lineOffset = 0.0;
567 if ( jsonPaint.contains( QStringLiteral(
"line-offset" ) ) )
569 const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral(
"line-offset" ) );
570 switch ( jsonLineOffset.type() )
573 case QVariant::LongLong:
574 case QVariant::Double:
584 case QVariant::StringList:
589 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineOffset.type() ) ) );
594 double lineOpacity = -1.0;
595 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
597 const QVariant jsonLineOpacity = jsonPaint.value( QStringLiteral(
"line-opacity" ) );
598 switch ( jsonLineOpacity.type() )
601 case QVariant::LongLong:
602 case QVariant::Double:
603 lineOpacity = jsonLineOpacity.toDouble();
609 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
618 case QVariant::StringList:
621 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
630 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineOpacity.type() ) ) );
635 QVector< double > dashVector;
636 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
638 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
639 switch ( jsonLineDashArray.type() )
643 QString arrayExpression;
646 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
647 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
652 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
656 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
657 for (
const QVariant &v : dashSource )
659 dashVector << v.toDouble() * lineWidth;
665 case QVariant::StringList:
667 const QVariantList dashSource = jsonLineDashArray.toList();
669 QVector< double > rawDashVectorSizes;
670 rawDashVectorSizes.reserve( dashSource.size() );
671 for (
const QVariant &v : dashSource )
673 rawDashVectorSizes << v.toDouble();
677 if ( rawDashVectorSizes.size() == 1 )
680 rawDashVectorSizes.clear();
682 else if ( rawDashVectorSizes.size() % 2 == 1 )
686 rawDashVectorSizes[0] = rawDashVectorSizes[0] + rawDashVectorSizes[rawDashVectorSizes.size() - 1];
687 rawDashVectorSizes.resize( rawDashVectorSizes.size() - 1 );
690 if ( !rawDashVectorSizes.isEmpty() && ( !lineWidthProperty.
asExpression().isEmpty() ) )
692 QStringList dashArrayStringParts;
693 dashArrayStringParts.reserve( rawDashVectorSizes.size() );
694 for (
double v : std::as_const( rawDashVectorSizes ) )
699 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
700 .arg( dashArrayStringParts.join(
',' ),
706 for (
double v : std::as_const( rawDashVectorSizes ) )
708 dashVector << v *lineWidth;
715 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-dasharray type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineDashArray.type() ) ) );
720 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
721 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
722 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
724 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
725 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
727 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
729 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
731 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
735 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
736 symbol->setOutputUnit( context.
targetUnit() );
738 if ( !rasterLineSprite.isEmpty() )
748 if ( lineOpacity != -1 )
750 symbol->setOpacity( lineOpacity );
752 if ( lineWidth != -1 )
756 symbol->changeSymbolLayer( 0, lineSymbol );
761 Q_ASSERT( lineSymbol );
771 if ( lineOpacity != -1 )
773 symbol->setOpacity( lineOpacity );
775 if ( lineColor.isValid() )
779 if ( lineWidth != -1 )
783 if ( !dashVector.empty() )
797 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
799 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
803 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
807 QColor circleFillColor;
808 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
810 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
811 switch ( jsonCircleColor.type() )
818 case QVariant::StringList:
822 case QVariant::String:
823 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
827 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonCircleColor.type() ) ) );
834 circleFillColor = QColor( 0, 0, 0 );
838 double circleDiameter = 10.0;
839 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
841 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
842 switch ( jsonCircleRadius.type() )
845 case QVariant::LongLong:
846 case QVariant::Double:
856 case QVariant::StringList:
861 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-radius type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonCircleRadius.type() ) ) );
866 double circleOpacity = -1.0;
867 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
869 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
870 switch ( jsonCircleOpacity.type() )
873 case QVariant::LongLong:
874 case QVariant::Double:
875 circleOpacity = jsonCircleOpacity.toDouble();
883 case QVariant::StringList:
888 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName( jsonCircleOpacity.type() ) ) );
892 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
894 circleFillColor.setAlphaF( circleOpacity );
898 QColor circleStrokeColor;
899 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
901 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
902 switch ( jsonCircleStrokeColor.type() )
909 case QVariant::StringList:
913 case QVariant::String:
914 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
918 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-color type (%2)" ).arg( context.layerId(), QMetaType::typeName( jsonCircleStrokeColor.type() ) ) );
924 double circleStrokeWidth = -1.0;
925 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
927 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
928 switch ( circleStrokeWidthJson.type() )
931 case QVariant::LongLong:
932 case QVariant::Double:
937 circleStrokeWidth = -1.0;
942 case QVariant::StringList:
947 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( circleStrokeWidthJson.type() ) ) );
952 double circleStrokeOpacity = -1.0;
953 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
955 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
956 switch ( jsonCircleStrokeOpacity.type() )
959 case QVariant::LongLong:
960 case QVariant::Double:
961 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
969 case QVariant::StringList:
974 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName( jsonCircleStrokeOpacity.type() ) ) );
978 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
980 circleStrokeColor.setAlphaF( circleStrokeOpacity );
984 QPointF circleTranslate;
985 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
987 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
988 switch ( jsonCircleTranslate.type() )
996 case QVariant::StringList:
1002 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonCircleTranslate.type() ) ) );
1007 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
1009 Q_ASSERT( markerSymbolLayer );
1012 symbol->setOutputUnit( context.
targetUnit() );
1013 symbol->setDataDefinedProperties( ddProperties );
1015 if ( !circleTranslate.isNull() )
1017 markerSymbolLayer->
setOffset( circleTranslate );
1021 if ( circleFillColor.isValid() )
1025 if ( circleDiameter != -1 )
1027 markerSymbolLayer->
setSize( circleDiameter );
1030 if ( circleStrokeColor.isValid() )
1034 if ( circleStrokeWidth != -1 )
1047 hasLabeling =
false;
1048 hasRenderer =
false;
1050 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1052 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1055 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1056 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1062 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1068 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
1070 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
1071 switch ( jsonTextSize.type() )
1074 case QVariant::LongLong:
1075 case QVariant::Double:
1085 case QVariant::List:
1086 case QVariant::StringList:
1092 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextSize.type() ) ) );
1096 if ( textSizeProperty )
1103 constexpr double EM_TO_CHARS = 2.0;
1105 double textMaxWidth = -1;
1106 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
1108 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
1109 switch ( jsonTextMaxWidth.type() )
1112 case QVariant::LongLong:
1113 case QVariant::Double:
1114 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1121 case QVariant::List:
1122 case QVariant::StringList:
1127 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-max-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextMaxWidth.type() ) ) );
1134 textMaxWidth = 10 * EM_TO_CHARS;
1137 double textLetterSpacing = -1;
1138 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1140 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1141 switch ( jsonTextLetterSpacing.type() )
1144 case QVariant::LongLong:
1145 case QVariant::Double:
1146 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1153 case QVariant::List:
1154 case QVariant::StringList:
1159 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-letter-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextLetterSpacing.type() ) ) );
1165 bool foundFont =
false;
1167 QString fontStyleName;
1169 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1171 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1173 QString matchedFamily;
1174 const QStringList textFontParts = fontName.split(
' ' );
1175 for (
int i = textFontParts.size() - 1; i >= 1; --i )
1177 const QString candidateFontFamily = textFontParts.mid( 0, i ).join(
' ' );
1178 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1183 family = processedFontFamily;
1184 style = candidateFontStyle;
1189 if ( processedFontFamily == matchedFamily )
1191 family = processedFontFamily;
1192 style = candidateFontStyle;
1196 family = matchedFamily;
1197 style = processedFontFamily;
1198 style.replace( matchedFamily, QString() );
1199 style = style.trimmed();
1200 if ( !style.isEmpty() && !candidateFontStyle.isEmpty() )
1202 style += QStringLiteral(
" %1" ).arg( candidateFontStyle );
1210 if ( QFontDatabase().hasFamily( processedFontFamily ) )
1213 family = processedFontFamily;
1219 family = matchedFamily;
1226 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1227 if ( jsonTextFont.type() != QVariant::List && jsonTextFont.type() != QVariant::StringList && jsonTextFont.type() != QVariant::String
1228 && jsonTextFont.type() != QVariant::Map )
1230 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-font type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextFont.type() ) ) );
1234 switch ( jsonTextFont.type() )
1236 case QVariant::List:
1237 case QVariant::StringList:
1238 fontName = jsonTextFont.toList().value( 0 ).toString();
1241 case QVariant::String:
1242 fontName = jsonTextFont.toString();
1247 QString familyCaseString = QStringLiteral(
"CASE " );
1248 QString styleCaseString = QStringLiteral(
"CASE " );
1250 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1253 for (
int i = 0; i < stops.length() - 1; ++i )
1256 const QVariant bz = stops.value( i ).toList().value( 0 );
1257 const QString bv = stops.value( i ).toList().value( 1 ).type() == QVariant::String ? stops.value( i ).toList().value( 1 ).toString() : stops.value( i ).toList().value( 1 ).toList().value( 0 ).toString();
1258 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
1260 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1266 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1267 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
1269 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1274 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1276 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1277 "THEN %3 " ).arg( bz.toString(),
1280 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1281 "THEN %3 " ).arg( bz.toString(),
1287 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1293 const QString bv = stops.constLast().toList().value( 1 ).type() == QVariant::String ? stops.constLast().toList().value( 1 ).toString() : stops.constLast().toList().value( 1 ).toList().value( 0 ).toString();
1294 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1301 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1308 fontName = fontFamily;
1318 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1320 textFont = QFont( fontFamily );
1321 if ( !fontStyleName.isEmpty() )
1322 textFont.setStyleName( fontStyleName );
1332 fontName = QStringLiteral(
"Open Sans" );
1333 textFont = QFont( fontName );
1334 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1335 fontStyleName = QStringLiteral(
"Regular" );
1340 fontName = QStringLiteral(
"Arial Unicode MS" );
1341 textFont = QFont( fontName );
1342 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1343 fontStyleName = QStringLiteral(
"Regular" );
1348 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1351 if ( !foundFont && !fontName.isEmpty() )
1353 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1358 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1360 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1361 switch ( jsonTextColor.type() )
1367 case QVariant::List:
1368 case QVariant::StringList:
1372 case QVariant::String:
1373 textColor =
parseColor( jsonTextColor.toString(), context );
1377 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextColor.type() ) ) );
1384 textColor = QColor( 0, 0, 0 );
1388 QColor bufferColor( 0, 0, 0, 0 );
1389 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1391 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1392 switch ( jsonBufferColor.type() )
1398 case QVariant::List:
1399 case QVariant::StringList:
1403 case QVariant::String:
1404 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1408 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonBufferColor.type() ) ) );
1413 double bufferSize = 0.0;
1417 constexpr double BUFFER_SIZE_SCALE = 2.0;
1418 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1420 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1421 switch ( jsonHaloWidth.type() )
1424 case QVariant::LongLong:
1425 case QVariant::Double:
1434 case QVariant::List:
1435 case QVariant::StringList:
1441 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonHaloWidth.type() ) ) );
1446 double haloBlurSize = 0;
1447 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1449 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1450 switch ( jsonTextHaloBlur.type() )
1453 case QVariant::LongLong:
1454 case QVariant::Double:
1461 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-blur type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextHaloBlur.type() ) ) );
1468 if ( textColor.isValid() )
1470 if ( textSize >= 0 )
1475 if ( !fontStyleName.isEmpty() )
1478 if ( textLetterSpacing > 0 )
1480 QFont f = format.
font();
1481 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1485 if ( bufferSize > 0 )
1488 const double opacity = bufferColor.alphaF();
1489 bufferColor.setAlphaF( 1.0 );
1497 if ( haloBlurSize > 0 )
1513 if ( textMaxWidth > 0 )
1519 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1521 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1522 switch ( jsonTextField.type() )
1524 case QVariant::String:
1526 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1530 case QVariant::List:
1531 case QVariant::StringList:
1533 const QVariantList textFieldList = jsonTextField.toList();
1541 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1544 for (
int i = 1; i < textFieldList.size(); ++i )
1546 bool isExpression =
false;
1547 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1548 if ( !isExpression )
1555 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1572 const QVariantList stops = jsonTextField.toMap().value( QStringLiteral(
"stops" ) ).toList();
1573 if ( !stops.empty() )
1580 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field dictionary" ).arg( context.
layerId() ) );
1586 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextField.type() ) ) );
1591 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1593 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1594 if ( textTransform == QLatin1String(
"uppercase" ) )
1598 else if ( textTransform == QLatin1String(
"lowercase" ) )
1607 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1609 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1610 if ( symbolPlacement == QLatin1String(
"line" ) )
1616 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1618 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1619 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1629 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1631 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1634 switch ( jsonTextOffset.type() )
1637 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1638 if ( !textSizeProperty )
1649 case QVariant::List:
1650 case QVariant::StringList:
1651 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1652 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1656 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextOffset.type() ) ) );
1660 if ( !textOffset.isNull() )
1663 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1665 if ( textSizeProperty && !textOffsetProperty )
1672 if ( textOffset.isNull() )
1680 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1682 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1685 QString textAlign = QStringLiteral(
"center" );
1687 const QVariantMap conversionMap
1689 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1690 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1691 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1692 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1695 switch ( jsonTextJustify.type() )
1697 case QVariant::String:
1698 textAlign = jsonTextJustify.toString();
1701 case QVariant::List:
1710 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-justify type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextJustify.type() ) ) );
1714 if ( textAlign == QLatin1String(
"left" ) )
1716 else if ( textAlign == QLatin1String(
"right" ) )
1718 else if ( textAlign == QLatin1String(
"center" ) )
1720 else if ( textAlign == QLatin1String(
"follow" ) )
1730 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1732 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1735 const QVariantMap conversionMap
1737 { QStringLiteral(
"center" ), 4 },
1738 { QStringLiteral(
"left" ), 5 },
1739 { QStringLiteral(
"right" ), 3 },
1740 { QStringLiteral(
"top" ), 7 },
1741 { QStringLiteral(
"bottom" ), 1 },
1742 { QStringLiteral(
"top-left" ), 8 },
1743 { QStringLiteral(
"top-right" ), 6 },
1744 { QStringLiteral(
"bottom-left" ), 2 },
1745 { QStringLiteral(
"bottom-right" ), 0 },
1748 switch ( jsonTextAnchor.type() )
1750 case QVariant::String:
1751 textAnchor = jsonTextAnchor.toString();
1754 case QVariant::List:
1763 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-anchor type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextAnchor.type() ) ) );
1767 if ( textAnchor == QLatin1String(
"center" ) )
1769 else if ( textAnchor == QLatin1String(
"left" ) )
1771 else if ( textAnchor == QLatin1String(
"right" ) )
1773 else if ( textAnchor == QLatin1String(
"top" ) )
1775 else if ( textAnchor == QLatin1String(
"bottom" ) )
1777 else if ( textAnchor == QLatin1String(
"top-left" ) )
1779 else if ( textAnchor == QLatin1String(
"top-right" ) )
1781 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1783 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1788 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1790 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1793 switch ( jsonTextOffset.type() )
1799 case QVariant::List:
1800 case QVariant::StringList:
1801 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1802 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1806 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextOffset.type() ) ) );
1810 if ( !textOffset.isNull() )
1813 labelSettings.
xOffset = textOffset.x();
1814 labelSettings.
yOffset = textOffset.y();
1819 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1823 QString spriteProperty, spriteSizeProperty;
1824 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1825 if ( !sprite.isEmpty() )
1828 markerLayer->
setPath( sprite );
1829 markerLayer->
setSize( spriteSize.width() );
1832 if ( !spriteProperty.isEmpty() )
1844 backgroundSettings.
setSize( spriteSize );
1852 if ( textSize >= 0 )
1875 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1877 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1880 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1882 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1886 double spacing = -1.0;
1887 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
1889 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
1890 switch ( jsonSpacing.type() )
1893 case QVariant::LongLong:
1894 case QVariant::Double:
1902 case QVariant::List:
1903 case QVariant::StringList:
1908 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported symbol-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonSpacing.type() ) ) );
1918 bool rotateMarkers =
true;
1919 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
1921 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
1922 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
1924 rotateMarkers =
true;
1926 else if ( alignment == QLatin1String(
"viewport" ) )
1928 rotateMarkers =
false;
1933 double rotation = 0.0;
1934 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
1936 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
1937 switch ( jsonIconRotate.type() )
1940 case QVariant::LongLong:
1941 case QVariant::Double:
1942 rotation = jsonIconRotate.toDouble();
1949 case QVariant::List:
1950 case QVariant::StringList:
1955 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconRotate.type() ) ) );
1971 QString spriteProperty, spriteSizeProperty;
1972 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1973 if ( !sprite.isNull() )
1975 markerLayer->
setPath( sprite );
1976 markerLayer->
setSize( spriteSize.width() );
1979 if ( !spriteProperty.isEmpty() )
1986 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1988 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
1991 switch ( jsonIconSize.type() )
1994 case QVariant::LongLong:
1995 case QVariant::Double:
1997 size = jsonIconSize.toDouble();
1998 if ( !spriteSizeProperty.isEmpty() )
2001 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2010 case QVariant::List:
2011 case QVariant::StringList:
2013 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconSize.type() ) ) );
2016 markerLayer->
setSize( size * spriteSize.width() );
2019 if ( !spriteSizeProperty.isEmpty() )
2036 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
2039 symbol->setOutputUnit( context.
targetUnit() );
2043 rendererStyle.
setSymbol( symbol.release() );
2046 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
2048 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
2051 QString spriteProperty, spriteSizeProperty;
2052 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
2053 if ( !sprite.isEmpty() )
2056 rasterMarker->
setPath( sprite );
2057 rasterMarker->
setSize( spriteSize.width() );
2061 if ( !spriteProperty.isEmpty() )
2067 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2069 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2072 switch ( jsonIconSize.type() )
2075 case QVariant::LongLong:
2076 case QVariant::Double:
2078 size = jsonIconSize.toDouble();
2079 if ( !spriteSizeProperty.isEmpty() )
2082 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2091 case QVariant::List:
2092 case QVariant::StringList:
2094 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconSize.type() ) ) );
2097 rasterMarker->
setSize( size * spriteSize.width() );
2100 if ( !spriteSizeProperty.isEmpty() )
2113 double rotation = 0.0;
2114 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2116 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
2117 switch ( jsonIconRotate.type() )
2120 case QVariant::LongLong:
2121 case QVariant::Double:
2122 rotation = jsonIconRotate.toDouble();
2129 case QVariant::List:
2130 case QVariant::StringList:
2135 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconRotate.type() ) ) );
2140 double iconOpacity = -1.0;
2141 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2143 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2144 switch ( jsonIconOpacity.type() )
2147 case QVariant::LongLong:
2148 case QVariant::Double:
2149 iconOpacity = jsonIconOpacity.toDouble();
2156 case QVariant::List:
2157 case QVariant::StringList:
2162 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconOpacity.type() ) ) );
2168 rasterMarker->
setAngle( rotation );
2169 if ( iconOpacity >= 0 )
2173 rendererStyle.
setSymbol( markerSymbol );
2184 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2185 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2186 if ( stops.empty() )
2189 QString caseString = QStringLiteral(
"CASE " );
2190 const QString colorComponent(
"color_part(%1,'%2')" );
2192 for (
int i = 0; i < stops.length() - 1; ++i )
2195 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2197 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2199 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2200 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2202 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2203 const QColor topColor =
parseColor( tcVariant.toString(), context );
2205 if ( i == 0 && bottomColor.isValid() )
2212 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2213 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2216 if ( bottomColor.isValid() && topColor.isValid() )
2228 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2229 "%3, %4, %5, %6) " ).arg( bz, tz,
2240 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2241 "%3, %4, %5, %6) " ).arg( bz, tz,
2242 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2243 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2244 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2245 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2250 const QString tz = stops.last().toList().value( 0 ).toString();
2251 const QVariant tcVariant = stops.last().toList().value( 1 );
2252 const QColor topColor =
parseColor( stops.last().toList().value( 1 ), context );
2253 if ( topColor.isValid() )
2260 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2261 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2267 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2268 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2269 .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" ) );
2272 if ( !stops.empty() && defaultColor )
2273 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2280 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2281 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2282 if ( stops.empty() )
2285 QString scaleExpression;
2286 if ( stops.size() <= 2 )
2289 stops.last().toList().value( 0 ).toDouble(),
2290 stops.value( 0 ).toList().value( 1 ),
2291 stops.last().toList().value( 1 ), base, multiplier, &context );
2295 scaleExpression =
parseStops( base, stops, multiplier, context );
2298 if ( !stops.empty() && defaultNumber )
2299 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2309 context = *contextPtr;
2311 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2312 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2313 if ( stops.empty() )
2316 QString scaleExpression;
2317 if ( stops.length() <= 2 )
2319 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2320 const QVariant tv = stops.last().toList().value( 1 );
2321 double bottom = 0.0;
2323 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2324 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2326 stops.last().toList().value( 0 ).toDouble(),
2327 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2328 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2339 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2340 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2341 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2343 for (
int i = 0; i < stops.size() - 1; ++i )
2345 const QVariant bv = stops.value( i ).toList().value( 1 );
2346 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2347 double bottom = 0.0;
2349 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2351 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2352 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2353 .arg( stops.value( i ).toList().value( 0 ).toString(),
2354 stops.value( i + 1 ).toList().value( 0 ).toString(),
2356 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2357 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2358 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2359 base, 1, &context ) );
2362 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2363 "THEN set_color_part(@symbol_color, 'alpha', %2) END" )
2364 .arg( stops.last().toList().value( 0 ).toString() )
2365 .arg( stops.last().toList().value( 1 ).toDouble() * maxOpacity );
2371 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2372 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2373 if ( stops.empty() )
2376 QString scaleExpression;
2377 if ( stops.size() <= 2 )
2379 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2380 stops.last().toList().value( 0 ).toDouble(),
2381 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2382 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2384 stops.last().toList().value( 0 ).toDouble(),
2385 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2386 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2391 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2394 if ( !stops.empty() && defaultPoint )
2395 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2396 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2402 const QVariantMap &conversionMap, QString *defaultString )
2404 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2405 if ( stops.empty() )
2408 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2415 QString caseString = QStringLiteral(
"CASE " );
2417 for (
int i = 0; i < stops.length() - 1; ++i )
2420 const QVariant bz = stops.value( i ).toList().value( 0 );
2421 const QVariant bv = stops.value( i ).toList().value( 1 );
2422 if ( bv.type() != QVariant::List && bv.type() != QVariant::StringList )
2424 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName( bz.type() ) ) );
2429 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2430 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2431 if ( tv.type() != QVariant::List && tv.type() != QVariant::StringList )
2433 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName( tz.type() ) ) );
2437 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2438 "THEN array(%3,%4)" ).arg( bz.toString(),
2440 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2441 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2443 caseString += QLatin1String(
"END" );
2449 if ( stops.length() < 2 )
2452 QString caseString = QStringLiteral(
"CASE " );
2454 for (
int i = 0; i < stops.length() - 1; ++i )
2457 const QVariant bz = stops.value( i ).toList().value( 0 );
2458 const QList<QVariant> bv = stops.value( i ).toList().value( 1 ).toList();
2461 for (
const QVariant &value : bv )
2463 const double number = value.toDouble( &ok );
2465 bl << QString::number( number * multiplier );
2469 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2470 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2471 "THEN array(%3) " ).arg( bz.toString(),
2475 const QVariant lz = stops.value( stops.length() - 1 ).toList().value( 0 );
2476 const QList<QVariant> lv = stops.value( stops.length() - 1 ).toList().value( 1 ).toList();
2479 for (
const QVariant &value : lv )
2481 const double number = value.toDouble( &ok );
2483 ll << QString::number( number * multiplier );
2485 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2486 "THEN array(%2) " ).arg( lz.toString(),
2488 caseString += QLatin1String(
"END" );
2494 QString caseString = QStringLiteral(
"CASE " );
2496 for (
int i = 0; i < stops.length() - 1; ++i )
2499 const QVariant bz = stops.value( i ).toList().value( 0 );
2500 const QVariant bv = stops.value( i ).toList().value( 1 );
2501 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2503 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2508 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2509 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2510 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2512 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2516 const QString lowerComparator = i == 0 ? QStringLiteral(
">=" ) : QStringLiteral(
">" );
2518 caseString += QStringLiteral(
"WHEN @vector_tile_zoom %1 %2 AND @vector_tile_zoom <= %3 "
2519 "THEN %4 " ).arg( lowerComparator,
2525 const QVariant z = stops.last().toList().value( 0 );
2526 const QVariant v = stops.last().toList().value( 1 );
2527 QString vStr = v.toString();
2528 if ( ( QMetaType::Type )v.type() == QMetaType::QVariantList )
2531 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2532 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2536 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2537 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2545 QString caseString = QStringLiteral(
"CASE " );
2547 for (
int i = 0; i < stops.length() - 1; ++i )
2550 const QVariant bz = stops.value( i ).toList().value( 0 );
2551 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2552 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2554 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2559 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2560 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2562 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2566 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2567 "THEN %3 " ).arg( bz.toString(),
2571 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2572 stops.constLast().toList().value( 1 ) ) ) );
2573 if ( defaultString )
2574 *defaultString = stops.constLast().toList().value( 1 ).toString();
2580 QString caseString = QStringLiteral(
"CASE " );
2582 bool isExpression =
false;
2583 for (
int i = 0; i < stops.length() - 1; ++i )
2586 const QVariant bz = stops.value( i ).toList().value( 0 );
2587 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2589 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2594 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2595 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2597 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2601 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2602 if ( fieldPart.isEmpty() )
2603 fieldPart = QStringLiteral(
"''" );
2604 else if ( !isExpression )
2607 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom < %2 "
2608 "THEN %3 " ).arg( bz.toString(),
2614 const QVariant bz = stops.constLast().toList().value( 0 );
2615 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2617 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2621 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2622 if ( fieldPart.isEmpty() )
2623 fieldPart = QStringLiteral(
"''" );
2624 else if ( !isExpression )
2627 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 "
2628 "THEN %3 " ).arg( bz.toString(),
2632 QString defaultPart = processLabelField( stops.constFirst().toList().value( 1 ).toString(), isExpression );
2633 if ( defaultPart.isEmpty() )
2634 defaultPart = QStringLiteral(
"''" );
2635 else if ( !isExpression )
2637 caseString += QStringLiteral(
"ELSE %1 END" ).arg( defaultPart );
2644 const QString method = json.
value( 0 ).toString();
2645 if ( method == QLatin1String(
"interpolate" ) )
2649 else if ( method == QLatin1String(
"match" ) )
2651 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2661 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2662 if ( attribute.isEmpty() )
2664 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2668 QString caseString = QStringLiteral(
"CASE " );
2670 for (
int i = 2; i < json.length() - 1; i += 2 )
2672 const QVariantList keys = json.value( i ).toList();
2674 QStringList matchString;
2675 for (
const QVariant &key : keys )
2680 const QVariant value = json.value( i + 1 );
2682 QString valueString;
2687 const QColor color =
parseColor( value, context );
2694 const double v = value.toDouble() * multiplier;
2695 valueString = QString::number( v );
2701 const double v = value.toDouble() * maxOpacity;
2702 valueString = QString::number( v );
2708 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2709 value.toList().value( 0 ).toDouble() * multiplier );
2715 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
2716 matchString.join(
',' ), valueString );
2725 const QColor color =
parseColor( json.constLast(), context );
2727 *defaultColor = color;
2735 const double v = json.constLast().toDouble() * multiplier;
2736 if ( defaultNumber )
2738 elseValue = QString::number( v );
2744 const double v = json.constLast().toDouble() * maxOpacity;
2745 if ( defaultNumber )
2747 elseValue = QString::number( v );
2753 elseValue = QStringLiteral(
"array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
2754 json.constLast().toList().value( 0 ).toDouble() * multiplier );
2760 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
2766 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
2768 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
2773 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
2774 if ( technique == QLatin1String(
"linear" ) )
2776 else if ( technique == QLatin1String(
"exponential" ) )
2777 base = json.value( 1 ).toList(). value( 1 ).toDouble();
2778 else if ( technique == QLatin1String(
"cubic-bezier" ) )
2780 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
2785 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
2789 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
2791 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
2797 for (
int i = 3; i < json.length(); i += 2 )
2799 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
2803 props.insert( QStringLiteral(
"stops" ), stops );
2804 props.insert( QStringLiteral(
"base" ), base );
2824 if ( ( QMetaType::Type )colorExpression.type() == QMetaType::QVariantList )
2828 return parseValue( colorExpression, context,
true );
2833 if ( color.type() != QVariant::String )
2835 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
2844 hue = std::max( 0, color.hslHue() );
2845 saturation = color.hslSaturation() / 255.0 * 100;
2846 lightness = color.lightness() / 255.0 * 100;
2847 alpha = color.alpha();
2855 context = *contextPtr;
2859 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
2861 bool minDoubleOk =
true;
2862 const double min = valueMin.toDouble( &minDoubleOk );
2863 bool maxDoubleOk =
true;
2864 const double max = valueMax.toDouble( &maxDoubleOk );
2865 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
2867 return QString::number( min * multiplier );
2871 QString minValueExpr = valueMin.toString();
2872 QString maxValueExpr = valueMax.toString();
2873 if ( ( QMetaType::Type )valueMin.type() == QMetaType::QVariantList )
2877 if ( ( QMetaType::Type )valueMax.type() == QMetaType::QVariantList )
2882 if ( minValueExpr == maxValueExpr )
2884 return minValueExpr;
2890 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin )
2892 .arg( minValueExpr )
2893 .arg( maxValueExpr );
2897 expression = QStringLiteral(
"scale_exp(@vector_tile_zoom,%1,%2,%3,%4,%5)" ).arg( zoomMin )
2899 .arg( minValueExpr )
2900 .arg( maxValueExpr )
2904 if ( multiplier != 1 )
2905 return QStringLiteral(
"%1 * %2" ).arg( expression ).arg( multiplier );
2912 if ( style == QLatin1String(
"round" ) )
2913 return Qt::RoundCap;
2914 else if ( style == QLatin1String(
"square" ) )
2915 return Qt::SquareCap;
2922 if ( style == QLatin1String(
"bevel" ) )
2923 return Qt::BevelJoin;
2924 else if ( style == QLatin1String(
"round" ) )
2925 return Qt::RoundJoin;
2927 return Qt::MiterJoin;
2932 QString op = expression.value( 0 ).toString();
2933 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
2935 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ) ).arg( op ).arg( parseValue( expression.value( 2 ), context ) );
2937 else if ( op == QLatin1String(
"to-number" ) )
2939 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
2941 if ( op == QLatin1String(
"literal" ) )
2943 return expression.value( 1 ).toString();
2945 else if ( op == QLatin1String(
"all" )
2946 || op == QLatin1String(
"any" )
2947 || op == QLatin1String(
"none" ) )
2950 for (
int i = 1; i < expression.size(); ++i )
2952 const QString part = parseValue( expression.at( i ), context );
2953 if ( part.isEmpty() )
2955 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2961 if ( op == QLatin1String(
"none" ) )
2962 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
2964 QString operatorString;
2965 if ( op == QLatin1String(
"all" ) )
2966 operatorString = QStringLiteral(
") AND (" );
2967 else if ( op == QLatin1String(
"any" ) )
2968 operatorString = QStringLiteral(
") OR (" );
2970 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
2972 else if ( op ==
'!' )
2975 QVariantList contraJsonExpr = expression.value( 1 ).toList();
2976 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
2978 return parseKey( contraJsonExpr, context );
2980 else if ( op == QLatin1String(
"==" )
2981 || op == QLatin1String(
"!=" )
2982 || op == QLatin1String(
">=" )
2984 || op == QLatin1String(
"<=" )
2988 if ( op == QLatin1String(
"==" ) )
2989 op = QStringLiteral(
"IS" );
2990 else if ( op == QLatin1String(
"!=" ) )
2991 op = QStringLiteral(
"IS NOT" );
2992 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
2993 op, parseValue( expression.value( 2 ), context ) );
2995 else if ( op == QLatin1String(
"has" ) )
2997 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
2999 else if ( op == QLatin1String(
"!has" ) )
3001 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
3003 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
3005 const QString key = parseKey( expression.value( 1 ), context );
3007 for (
int i = 2; i < expression.size(); ++i )
3009 const QString part = parseValue( expression.at( i ), context );
3010 if ( part.isEmpty() )
3012 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3017 if ( op == QLatin1String(
"in" ) )
3018 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3020 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3022 else if ( op == QLatin1String(
"get" ) )
3024 return parseKey( expression.value( 1 ), context );
3026 else if ( op == QLatin1String(
"match" ) )
3028 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
3030 if ( expression.size() == 5
3031 && expression.at( 3 ).type() == QVariant::Bool && expression.at( 3 ).toBool() ==
true
3032 && expression.at( 4 ).type() == QVariant::Bool && expression.at( 4 ).toBool() ==
false )
3035 if ( expression.at( 2 ).type() == QVariant::List || expression.at( 2 ).type() == QVariant::StringList )
3038 for (
const QVariant &p : expression.at( 2 ).toList() )
3040 parts << parseValue( p, context );
3043 if ( parts.size() > 1 )
3048 else if ( expression.at( 2 ).type() == QVariant::String || expression.at( 2 ).type() == QVariant::Int
3049 || expression.at( 2 ).type() == QVariant::Double || expression.at( 2 ).type() == QVariant::LongLong )
3055 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3061 QString caseString = QStringLiteral(
"CASE " );
3062 for (
int i = 2; i < expression.size() - 2; i += 2 )
3064 if ( expression.at( i ).type() == QVariant::List || expression.at( i ).type() == QVariant::StringList )
3067 for (
const QVariant &p : expression.at( i ).toList() )
3072 if ( parts.size() > 1 )
3077 else if ( expression.at( i ).type() == QVariant::String || expression.at( i ).type() == QVariant::Int
3078 || expression.at( i ).type() == QVariant::Double || expression.at( i ).type() == QVariant::LongLong )
3083 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
3085 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
3089 else if ( op == QLatin1String(
"to-string" ) )
3091 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3095 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3104 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3108 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
3109 if ( spriteDefinition.size() == 0 )
3111 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3115 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
3116 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
3117 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
3118 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
3119 if ( sprite.isNull() )
3121 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3125 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
3133 auto prepareBase64 = [](
const QImage & sprite )
3136 if ( !sprite.isNull() )
3139 QBuffer buffer( &blob );
3140 buffer.open( QIODevice::WriteOnly );
3141 sprite.save( &buffer,
"PNG" );
3143 const QByteArray encoded = blob.toBase64();
3144 path = QString( encoded );
3145 path.prepend( QLatin1String(
"base64:" ) );
3150 switch ( value.type() )
3152 case QVariant::String:
3154 QString spriteName = value.toString();
3155 const QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
3156 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
3157 if ( match.hasMatch() )
3159 const QString fieldName = match.captured( 1 );
3160 spriteProperty = QStringLiteral(
"CASE" );
3161 spriteSizeProperty = QStringLiteral(
"CASE" );
3163 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
3164 spriteName.replace(
")", QLatin1String(
"\\)" ) );
3165 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
3166 const QRegularExpression fieldValueMatch( spriteName );
3168 for (
const QString &name : spriteNames )
3170 match = fieldValueMatch.match( name );
3171 if ( match.hasMatch() )
3175 const QString fieldValue = match.captured( 1 );
3177 path = prepareBase64( sprite );
3178 if ( spritePath.isEmpty() && !path.isEmpty() )
3184 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
3185 .arg( fieldName, fieldValue, path );
3186 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
3187 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
3191 spriteProperty += QLatin1String(
" END" );
3192 spriteSizeProperty += QLatin1String(
" END" );
3196 spriteProperty.clear();
3197 spriteSizeProperty.clear();
3198 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
3199 spritePath = prepareBase64( sprite );
3206 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3207 if ( stops.size() == 0 )
3214 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3215 spritePath = prepareBase64( sprite );
3217 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3218 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3220 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3221 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3222 .arg( spriteSize.width() );
3224 for (
int i = 0; i < stops.size() - 1; ++i )
3227 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3228 path = prepareBase64( sprite );
3230 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3232 .arg( stops.value( i ).toList().value( 0 ).toString(),
3233 stops.value( i + 1 ).toList().value( 0 ).toString(),
3235 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3237 .arg( stops.value( i ).toList().value( 0 ).toString(),
3238 stops.value( i + 1 ).toList().value( 0 ).toString() )
3239 .arg( size.width() );
3241 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3242 path = prepareBase64( sprite );
3244 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3246 .arg( stops.last().toList().value( 0 ).toString() )
3248 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3250 .arg( stops.last().toList().value( 0 ).toString() )
3251 .arg( size.width() );
3255 case QVariant::List:
3257 const QVariantList json = value.toList();
3258 const QString method = json.value( 0 ).toString();
3259 if ( method != QLatin1String(
"match" ) )
3261 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3265 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3266 if ( attribute.isEmpty() )
3268 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3272 spriteProperty = QStringLiteral(
"CASE " );
3273 spriteSizeProperty = QStringLiteral(
"CASE " );
3275 for (
int i = 2; i < json.length() - 1; i += 2 )
3277 const QVariantList keys = json.value( i ).toList();
3279 QStringList matchString;
3280 for (
const QVariant &key : keys )
3285 const QVariant value = json.value( i + 1 );
3287 const QImage sprite =
retrieveSprite( value.toString(), context, spriteSize );
3288 spritePath = prepareBase64( sprite );
3290 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3291 "THEN '%3' " ).arg( attribute,
3292 matchString.join(
',' ),
3295 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3296 "THEN %3 " ).arg( attribute,
3297 matchString.join(
',' ) ).arg( spriteSize.width() );
3300 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3301 spritePath = prepareBase64( sprite );
3303 spriteProperty += QStringLiteral(
"ELSE %1 END" ).arg( spritePath );
3304 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3309 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName( value.type() ) ) );
3319 switch ( value.type() )
3321 case QVariant::List:
3322 case QVariant::StringList:
3325 case QVariant::Bool:
3326 case QVariant::String:
3327 if ( colorExpected )
3332 return parseValue(
c, context );
3338 case QVariant::LongLong:
3339 case QVariant::Double:
3340 return value.toString();
3342 case QVariant::Color:
3343 c = value.value<QColor>();
3344 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3347 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3355 if ( value.toString() == QLatin1String(
"$type" ) )
3357 return QStringLiteral(
"_geom_type" );
3359 if ( value.toString() == QLatin1String(
"level" ) )
3361 return QStringLiteral(
"level" );
3363 else if ( ( value.type() == QVariant::List && value.toList().size() == 1 ) || value.type() == QVariant::StringList )
3365 if ( value.toList().size() > 1 )
3366 return value.toList().at( 1 ).toString();
3369 QString valueString = value.toList().value( 0 ).toString();
3370 if ( valueString == QLatin1String(
"geometry-type" ) )
3372 return QStringLiteral(
"_geom_type" );
3377 else if ( value.type() == QVariant::List && value.toList().size() > 1 )
3384QString QgsMapBoxGlStyleConverter::processLabelField(
const QString &
string,
bool &isExpression )
3388 const QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
3389 const QRegularExpressionMatch match = singleFieldRx.match(
string );
3390 if ( match.hasMatch() )
3392 isExpression =
false;
3393 return match.captured( 1 );
3396 const QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
3397 const QStringList parts =
string.split( multiFieldRx );
3398 if ( parts.size() > 1 )
3400 isExpression =
true;
3403 for (
const QString &part : parts )
3405 if ( part.isEmpty() )
3408 if ( !part.contains(
'{' ) )
3415 const QStringList split = part.split(
'}' );
3417 if ( !split.at( 1 ).isEmpty() )
3420 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
3424 isExpression =
false;
3431 return mRenderer ? mRenderer->clone() :
nullptr;
3436 return mLabeling ? mLabeling->clone() :
nullptr;
3446 return mRasterSubLayers;
3451 QList<QgsMapLayer *> subLayers;
3454 const QString sourceName = subLayer.source();
3455 std::unique_ptr< QgsRasterLayer > rl;
3462 rl->pipe()->setDataDefinedProperties( subLayer.dataDefinedProperties() );
3469 subLayers.append( rl.release() );
3478 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3481 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3482 context = tmpContext.get();
3487 if (
string.compare( QLatin1String(
"vector" ), Qt::CaseInsensitive ) == 0 )
3489 else if (
string.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
3491 else if (
string.compare( QLatin1String(
"raster-dem" ), Qt::CaseInsensitive ) == 0 )
3493 else if (
string.compare( QLatin1String(
"geojson" ), Qt::CaseInsensitive ) == 0 )
3495 else if (
string.compare( QLatin1String(
"image" ), Qt::CaseInsensitive ) == 0 )
3497 else if (
string.compare( QLatin1String(
"video" ), Qt::CaseInsensitive ) == 0 )
3499 context->
pushWarning( QObject::tr(
"Invalid source type \"%1\" for source \"%2\"" ).arg(
string, name ) );
3505 const QString name = it.key();
3506 const QVariantMap jsonSource = it.value().toMap();
3507 const QString typeString = jsonSource.value( QStringLiteral(
"type" ) ).toString();
3530 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3533 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3534 context = tmpContext.get();
3537 std::unique_ptr< QgsMapBoxGlStyleRasterSource > raster = std::make_unique< QgsMapBoxGlStyleRasterSource >( name );
3538 if ( raster->setFromJson( source, context ) )
3539 mSources.append( raster.release() );
3542bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
3544 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
3546 bool bDoubleOk, tDoubleOk;
3547 bottom = bottomVariant.toDouble( &bDoubleOk );
3548 top = topVariant.toDouble( &tDoubleOk );
3549 return ( bDoubleOk && tDoubleOk );
3560 mWarnings << warning;
3575 return mSizeConversionFactor;
3580 mSizeConversionFactor = sizeConversionFactor;
3585 return mSpriteImage;
3590 return mSpriteDefinitions;
3595 mSpriteImage = image;
3596 mSpriteDefinitions = definitions;
3646 mAttribution = json.value( QStringLiteral(
"attribution" ) ).toString();
3648 const QString scheme = json.value( QStringLiteral(
"scheme" ), QStringLiteral(
"xyz" ) ).toString();
3649 if ( scheme.compare( QLatin1String(
"xyz" ) ) == 0 )
3655 context->
pushWarning( QObject::tr(
"%1 scheme is not supported for raster source %2" ).arg( scheme,
name() ) );
3659 mMinZoom = json.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"0" ) ).toInt();
3660 mMaxZoom = json.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"22" ) ).toInt();
3661 mTileSize = json.value( QStringLiteral(
"tileSize" ), QStringLiteral(
"512" ) ).toInt();
3663 const QVariantList
tiles = json.value( QStringLiteral(
"tiles" ) ).toList();
3664 for (
const QVariant &tile :
tiles )
3666 mTiles.append( tile.toString() );
3675 parts.insert( QStringLiteral(
"type" ), QStringLiteral(
"xyz" ) );
3676 parts.insert( QStringLiteral(
"url" ), mTiles.value( 0 ) );
3678 if ( mTileSize == 256 )
3679 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"1" ) );
3680 else if ( mTileSize == 512 )
3681 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"2" ) );
3683 parts.insert( QStringLiteral(
"zmax" ), QString::number( mMaxZoom ) );
3684 parts.insert( QStringLiteral(
"zmin" ), QString::number( mMinZoom ) );
3686 std::unique_ptr< QgsRasterLayer > rl = std::make_unique< QgsRasterLayer >(
QgsProviderRegistry::instance()->encodeUri( QStringLiteral(
"wms" ), parts ),
name(), QStringLiteral(
"wms" ) );
3687 return rl.release();
@ CentralPoint
Place symbols at the mid point of the line.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ FollowPlacement
Alignment follows placement of label, e.g., labels to the left of a feature will be drawn with right ...
MapBoxGlStyleSourceType
Flags which control project capabilities.
@ RasterDem
Raster DEM source.
@ Unknown
Other/unknown source type.
@ Viewport
Relative to the whole viewport/output device.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
A paint effect which blurs a source picture, using a number of different blur methods.
@ StackBlur
Stack blur, a fast but low quality blur. Valid blur level values are between 0 - 16.
void setBlurUnit(const QgsUnitTypes::RenderUnit unit)
Sets the units used for the blur level (radius).
void setBlurMethod(const BlurMethod method)
Sets the blur method (algorithm) to use for performing the blur.
void setBlurLevel(const double level)
Sets blur level (radius)
A paint effect which consists of a stack of other chained paint effects.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
Create an expression allowing to evaluate if a field is equal to a value.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QString processFontFamilyName(const QString &name) const
Processes a font family name, applying any matching fontFamilyReplacements() to the name.
static bool fontFamilyHasStyle(const QString &family, const QString &style)
Check whether font family on system has specific style.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
void setPlacementFlags(QgsLabeling::LinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setFactor(double factor)
Sets the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ OnLine
Labels can be placed directly over a line feature.
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
void setOffset(double offset)
Sets 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...
QgsUnitTypes::RenderUnit targetUnit() const
Returns the target unit type.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
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.
void setTargetUnit(QgsUnitTypes::RenderUnit targetUnit)
Sets the target unit type.
QImage spriteImage() const
Returns the sprite image to use during conversion, or an invalid image if this is not set.
void clearWarnings()
Clears the list of warning messages.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
static QString parseOpacityStops(double base, const QVariantList &stops, int maxOpacity, QgsMapBoxGlStyleConversionContext &context)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate alpha ...
static QString parseColorExpression(const QVariant &colorExpression, QgsMapBoxGlStyleConversionContext &context)
Converts an expression representing a color to a string (can be color string or an expression where a...
static QString parseStops(double base, const QVariantList &stops, double multiplier, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
static QString parseExpression(const QVariantList &expression, QgsMapBoxGlStyleConversionContext &context, bool colorExpected=false)
Converts a MapBox GL expression to a QGIS expression.
PropertyType
Property types, for interpolated value conversion.
@ Point
Point/offset property.
@ Numeric
Numeric property (e.g. line width, text size)
@ Opacity
Opacity property.
QList< QgsMapBoxGlStyleAbstractSource * > sources()
Returns the list of converted sources.
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
QList< QgsMapBoxGlStyleRasterSubLayer > rasterSubLayers() const
Returns a list of raster sub layers contained in the style.
static QgsProperty parseInterpolateByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, double *defaultNumber=nullptr)
Parses a numeric value which is interpolated by zoom range.
static Qt::PenJoinStyle parseJoinStyle(const QString &style)
Converts a value to Qt::PenJoinStyle enum from JSON value.
static QgsProperty parseInterpolateStringByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Interpolates a string by zoom.
static QString interpolateExpression(double zoomMin, double zoomMax, QVariant valueMin, QVariant valueMax, double base, double multiplier=1, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Generates an interpolation for values between valueMin and valueMax, scaled between the ranges zoomMi...
static QgsProperty parseInterpolatePointByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, QPointF *defaultPoint=nullptr)
Interpolates a point/offset with either scale_linear() or scale_exp() (depending on base value).
static bool parseCircleLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a circle layer.
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
static QgsProperty parseInterpolateListByZoom(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Interpolates a list which starts with the interpolate function.
~QgsMapBoxGlStyleConverter()
QList< QgsMapLayer * > createSubLayers() const
Returns a list of new map layers corresponding to sublayers of the style, e.g.
Result
Result of conversion.
@ Success
Conversion was successful.
@ NoLayerList
No layer list was found in JSON input.
QgsMapBoxGlStyleConverter()
Constructor for QgsMapBoxGlStyleConverter.
static QImage retrieveSprite(const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize)
Retrieves the sprite image with the specified name, taken from the specified context.
static QString parseLabelStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops containing label values.
void parseLayers(const QVariantList &layers, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of layers from JSON.
static QgsProperty parseInterpolateColorByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, QColor *defaultColor=nullptr)
Parses a color value which is interpolated by zoom range.
static QgsProperty parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
static QString retrieveSpriteAsBase64(const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize, QString &spriteProperty, QString &spriteSizeProperty)
Retrieves the sprite image with the specified name, taken from the specified context as a base64 enco...
void parseSources(const QVariantMap &sources, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of sources from JSON.
static QColor parseColor(const QVariant &color, QgsMapBoxGlStyleConversionContext &context)
Parses a color in one of these supported formats:
static bool parseSymbolLayerAsRenderer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as a renderer.
static bool parseFillLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context, bool isBackgroundStyle=false)
Parses a fill layer.
static void parseSymbolLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, bool &hasRenderer, QgsVectorTileBasicLabelingStyle &labelingStyle, bool &hasLabeling, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as renderer or labeling.
static bool parseLineLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a line layer.
void parseRasterSource(const QVariantMap &source, const QString &name, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse a raster source from JSON.
static void colorAsHslaComponents(const QColor &color, int &hue, int &saturation, int &lightness, int &alpha)
Takes a QColor object and returns HSLA components in required format for QGIS color_hsla() expression...
static Qt::PenCapStyle parseCapStyle(const QString &style)
Converts a value to Qt::PenCapStyle enum from JSON value.
static QString parseStringStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Parses a list of interpolation stops containing string values.
static QgsProperty parseMatchList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a match function value list.
static QgsProperty parseValueList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a value list (e.g.
static QString parseArrayStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes numerical arrays from stops.
static QString parsePointStops(double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate point/...
Encapsulates a MapBox GL style raster source.
Qgis::MapBoxGlStyleSourceType type() const override
Returns the source type.
QgsMapBoxGlStyleRasterSource(const QString &name)
Constructor for QgsMapBoxGlStyleRasterSource.
QgsRasterLayer * toRasterLayer() const
Returns a new raster layer representing the raster source, or nullptr if the source cannot be represe...
bool setFromJson(const QVariantMap &json, QgsMapBoxGlStyleConversionContext *context) override
Sets the source's state from a json map.
QStringList tiles() const
Returns the list of tile sources.
Encapsulates a MapBox GL style raster sub layer.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the layer's data defined properties.
QgsMapBoxGlStyleRasterSubLayer(const QString &id, const QString &source)
Constructor for QgsMapBoxGlStyleRasterSubLayer, with the given id and source.
Line symbol layer type which draws repeating marker symbols along a line feature.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
virtual void setSize(double size)
Sets the symbol size.
void setAngle(double angle)
Sets the rotation angle for the marker.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's size.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's offset.
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.
QgsUnitTypes::RenderUnit offsetUnits
Units for offsets of label.
Qgis::LabelQuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
int priority
Label priority.
QgsUnitTypes::RenderUnit distUnits
Units the distance from feature to the label.
@ FontStyle
Font style name.
@ FontLetterSpacing
Letter spacing.
@ LinePlacementOptions
Line placement flags.
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.
QString fieldName
Name of field (or an expression) to use for label text.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
QString expressionString() const
Returns the expression used for the property value.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
A class for filling symbols with a repeated raster image.
void setWidthUnit(const QgsUnitTypes::RenderUnit unit)
Sets the units for the image's width.
void setWidth(const double width)
Sets the width for scaling the image used in the fill.
void setOpacity(double opacity)
Sets the opacity for the raster image used in the fill.
void setImageFilePath(const QString &imagePath)
Sets the path to the raster image used for the fill.
void setCoordinateMode(Qgis::SymbolCoordinateReference mode)
Set the coordinate mode for fill.
Represents a raster layer.
Line symbol layer type which draws line sections using a raster image file.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Raster marker symbol layer class.
void setOpacity(double opacity)
Set the marker opacity.
void setPath(const QString &path)
Set the marker raster image path.
@ RendererOpacity
Raster renderer global opacity.
void setBrushStyle(Qt::BrushStyle style)
void setStrokeStyle(Qt::PenStyle strokeStyle)
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.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the fill's offset.
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 setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit u)
Sets the unit for the width of the marker's stroke.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setStrokeWidth(double w)
Sets the width of the marker's stroke.
void setStrokeColor(const QColor &color) override
Sets the marker's stroke color.
static QColor parseColor(const QString &colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
@ PropertyFile
Filename, eg for svg files.
@ PropertyAngle
Symbol angle.
@ PropertyCustomDash
Custom dash pattern.
@ PropertyOpacity
Opacity.
@ PropertyOffset
Symbol offset.
@ PropertyStrokeWidth
Stroke width.
@ PropertyFillColor
Fill color.
@ PropertyName
Name, eg shape name for simple markers.
@ PropertyInterval
Line marker interval.
@ PropertyStrokeColor
Stroke color.
@ PropertyWidth
Symbol width.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
@ PropertyOpacity
Opacity.
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
Container for settings relating to a text background object.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
@ ShapeMarkerSymbol
Marker symbol.
void 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 setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the shape's size.
void setColor(const QColor &color)
Sets the color for the buffer.
void setOpacity(double opacity)
Sets the buffer opacity.
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 setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
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(QgsUnitTypes::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.
RenderUnit
Rendering size units.
Configuration of a single style within QgsVectorTileBasicLabeling.
void setGeometryType(QgsWkbTypes::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
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 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 setGeometryType(QgsWkbTypes::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
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).
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.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsSymbolLayer * > QgsSymbolLayerList