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 );
445 if ( fillOutlineColor.isValid() && ( fillOutlineColor.alpha() == 255 || fillOutlineColor != fillColor ) )
456 if ( fillColor.isValid() )
472 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
474 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
479 QString rasterLineSprite;
481 const QVariantMap jsonPaint = jsonLayer.
value( QStringLiteral(
"paint" ) ).toMap();
482 if ( jsonPaint.contains( QStringLiteral(
"line-pattern" ) ) )
484 const QVariant jsonLinePattern = jsonPaint.value( QStringLiteral(
"line-pattern" ) );
485 switch ( jsonLinePattern.type() )
488 case QVariant::String:
491 QString spriteProperty, spriteSizeProperty;
492 rasterLineSprite =
retrieveSpriteAsBase64( jsonLinePattern, context, spriteSize, spriteProperty, spriteSizeProperty );
498 case QVariant::StringList:
503 if ( rasterLineSprite.isEmpty() )
506 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
513 if ( jsonPaint.contains( QStringLiteral(
"line-color" ) ) )
515 const QVariant jsonLineColor = jsonPaint.value( QStringLiteral(
"line-color" ) );
516 switch ( jsonLineColor.type() )
524 case QVariant::StringList:
529 case QVariant::String:
530 lineColor =
parseColor( jsonLineColor.toString(), context );
534 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineColor.type() ) ) );
541 lineColor = QColor( 0, 0, 0 );
547 if ( jsonPaint.contains( QStringLiteral(
"line-width" ) ) )
549 const QVariant jsonLineWidth = jsonPaint.
value( QStringLiteral(
"line-width" ) );
550 switch ( jsonLineWidth.type() )
553 case QVariant::LongLong:
554 case QVariant::Double:
565 case QVariant::StringList:
571 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported fill-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineWidth.type() ) ) );
576 double lineOffset = 0.0;
577 if ( jsonPaint.contains( QStringLiteral(
"line-offset" ) ) )
579 const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral(
"line-offset" ) );
580 switch ( jsonLineOffset.type() )
583 case QVariant::LongLong:
584 case QVariant::Double:
594 case QVariant::StringList:
599 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineOffset.type() ) ) );
604 double lineOpacity = -1.0;
605 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
607 const QVariant jsonLineOpacity = jsonPaint.value( QStringLiteral(
"line-opacity" ) );
608 switch ( jsonLineOpacity.type() )
611 case QVariant::LongLong:
612 case QVariant::Double:
613 lineOpacity = jsonLineOpacity.toDouble();
619 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
628 case QVariant::StringList:
631 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
640 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineOpacity.type() ) ) );
645 QVector< double > dashVector;
646 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
648 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
649 switch ( jsonLineDashArray.type() )
653 QString arrayExpression;
656 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
657 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
662 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
666 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
667 for (
const QVariant &v : dashSource )
669 dashVector << v.toDouble() * lineWidth;
675 case QVariant::StringList:
677 const QVariantList dashSource = jsonLineDashArray.toList();
679 QVector< double > rawDashVectorSizes;
680 rawDashVectorSizes.reserve( dashSource.size() );
681 for (
const QVariant &v : dashSource )
683 rawDashVectorSizes << v.toDouble();
687 if ( rawDashVectorSizes.size() == 1 )
690 rawDashVectorSizes.clear();
692 else if ( rawDashVectorSizes.size() % 2 == 1 )
696 rawDashVectorSizes[0] = rawDashVectorSizes[0] + rawDashVectorSizes[rawDashVectorSizes.size() - 1];
697 rawDashVectorSizes.resize( rawDashVectorSizes.size() - 1 );
700 if ( !rawDashVectorSizes.isEmpty() && ( !lineWidthProperty.
asExpression().isEmpty() ) )
702 QStringList dashArrayStringParts;
703 dashArrayStringParts.reserve( rawDashVectorSizes.size() );
704 for (
double v : std::as_const( rawDashVectorSizes ) )
709 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
710 .arg( dashArrayStringParts.join(
',' ),
716 for (
double v : std::as_const( rawDashVectorSizes ) )
718 dashVector << v *lineWidth;
725 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-dasharray type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonLineDashArray.type() ) ) );
730 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
731 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
732 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
734 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
735 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
737 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
739 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
741 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
745 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
746 symbol->setOutputUnit( context.
targetUnit() );
748 if ( !rasterLineSprite.isEmpty() )
758 if ( lineOpacity != -1 )
760 symbol->setOpacity( lineOpacity );
762 if ( lineWidth != -1 )
766 symbol->changeSymbolLayer( 0, lineSymbol );
771 Q_ASSERT( lineSymbol );
781 if ( lineOpacity != -1 )
783 symbol->setOpacity( lineOpacity );
785 if ( lineColor.isValid() )
789 if ( lineWidth != -1 )
793 if ( !dashVector.empty() )
807 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
809 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
813 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
817 QColor circleFillColor;
818 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
820 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
821 switch ( jsonCircleColor.type() )
828 case QVariant::StringList:
832 case QVariant::String:
833 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
837 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonCircleColor.type() ) ) );
844 circleFillColor = QColor( 0, 0, 0 );
848 double circleDiameter = 10.0;
849 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
851 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
852 switch ( jsonCircleRadius.type() )
855 case QVariant::LongLong:
856 case QVariant::Double:
866 case QVariant::StringList:
871 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-radius type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonCircleRadius.type() ) ) );
876 double circleOpacity = -1.0;
877 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
879 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
880 switch ( jsonCircleOpacity.type() )
883 case QVariant::LongLong:
884 case QVariant::Double:
885 circleOpacity = jsonCircleOpacity.toDouble();
893 case QVariant::StringList:
898 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName( jsonCircleOpacity.type() ) ) );
902 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
904 circleFillColor.setAlphaF( circleOpacity );
908 QColor circleStrokeColor;
909 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
911 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
912 switch ( jsonCircleStrokeColor.type() )
919 case QVariant::StringList:
923 case QVariant::String:
924 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
928 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-color type (%2)" ).arg( context.layerId(), QMetaType::typeName( jsonCircleStrokeColor.type() ) ) );
934 double circleStrokeWidth = -1.0;
935 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
937 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
938 switch ( circleStrokeWidthJson.type() )
941 case QVariant::LongLong:
942 case QVariant::Double:
947 circleStrokeWidth = -1.0;
952 case QVariant::StringList:
957 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( circleStrokeWidthJson.type() ) ) );
962 double circleStrokeOpacity = -1.0;
963 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
965 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
966 switch ( jsonCircleStrokeOpacity.type() )
969 case QVariant::LongLong:
970 case QVariant::Double:
971 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
979 case QVariant::StringList:
984 context.pushWarning( QObject::tr(
"%1: Skipping unsupported circle-stroke-opacity type (%2)" ).arg( context.layerId(), QMetaType::typeName( jsonCircleStrokeOpacity.type() ) ) );
988 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
990 circleStrokeColor.setAlphaF( circleStrokeOpacity );
994 QPointF circleTranslate;
995 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
997 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
998 switch ( jsonCircleTranslate.type() )
1005 case QVariant::List:
1006 case QVariant::StringList:
1012 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported circle-translate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonCircleTranslate.type() ) ) );
1017 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
1019 Q_ASSERT( markerSymbolLayer );
1022 symbol->setOutputUnit( context.
targetUnit() );
1023 symbol->setDataDefinedProperties( ddProperties );
1025 if ( !circleTranslate.isNull() )
1027 markerSymbolLayer->
setOffset( circleTranslate );
1031 if ( circleFillColor.isValid() )
1035 if ( circleDiameter != -1 )
1037 markerSymbolLayer->
setSize( circleDiameter );
1040 if ( circleStrokeColor.isValid() )
1044 if ( circleStrokeWidth != -1 )
1057 hasLabeling =
false;
1058 hasRenderer =
false;
1060 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1062 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1065 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1066 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1072 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1078 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
1080 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
1081 switch ( jsonTextSize.type() )
1084 case QVariant::LongLong:
1085 case QVariant::Double:
1095 case QVariant::List:
1096 case QVariant::StringList:
1102 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextSize.type() ) ) );
1106 if ( textSizeProperty )
1113 constexpr double EM_TO_CHARS = 2.0;
1115 double textMaxWidth = -1;
1116 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
1118 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
1119 switch ( jsonTextMaxWidth.type() )
1122 case QVariant::LongLong:
1123 case QVariant::Double:
1124 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1131 case QVariant::List:
1132 case QVariant::StringList:
1137 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-max-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextMaxWidth.type() ) ) );
1144 textMaxWidth = 10 * EM_TO_CHARS;
1147 double textLetterSpacing = -1;
1148 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1150 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1151 switch ( jsonTextLetterSpacing.type() )
1154 case QVariant::LongLong:
1155 case QVariant::Double:
1156 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1163 case QVariant::List:
1164 case QVariant::StringList:
1169 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-letter-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextLetterSpacing.type() ) ) );
1175 bool foundFont =
false;
1177 QString fontStyleName;
1179 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1181 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1183 QString matchedFamily;
1184 const QStringList textFontParts = fontName.split(
' ' );
1185 for (
int i = textFontParts.size() - 1; i >= 1; --i )
1187 const QString candidateFontFamily = textFontParts.mid( 0, i ).join(
' ' );
1188 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1193 family = processedFontFamily;
1194 style = candidateFontStyle;
1199 if ( processedFontFamily == matchedFamily )
1201 family = processedFontFamily;
1202 style = candidateFontStyle;
1206 family = matchedFamily;
1207 style = processedFontFamily;
1208 style.replace( matchedFamily, QString() );
1209 style = style.trimmed();
1210 if ( !style.isEmpty() && !candidateFontStyle.isEmpty() )
1212 style += QStringLiteral(
" %1" ).arg( candidateFontStyle );
1220 if ( QFontDatabase().hasFamily( processedFontFamily ) )
1223 family = processedFontFamily;
1229 family = matchedFamily;
1236 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1237 if ( jsonTextFont.type() != QVariant::List && jsonTextFont.type() != QVariant::StringList && jsonTextFont.type() != QVariant::String
1238 && jsonTextFont.type() != QVariant::Map )
1240 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-font type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextFont.type() ) ) );
1244 switch ( jsonTextFont.type() )
1246 case QVariant::List:
1247 case QVariant::StringList:
1248 fontName = jsonTextFont.toList().value( 0 ).toString();
1251 case QVariant::String:
1252 fontName = jsonTextFont.toString();
1257 QString familyCaseString = QStringLiteral(
"CASE " );
1258 QString styleCaseString = QStringLiteral(
"CASE " );
1260 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1263 for (
int i = 0; i < stops.length() - 1; ++i )
1266 const QVariant bz = stops.value( i ).toList().value( 0 );
1267 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();
1268 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
1270 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1276 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1277 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
1279 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1284 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1286 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1287 "THEN %3 " ).arg( bz.toString(),
1290 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1291 "THEN %3 " ).arg( bz.toString(),
1297 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1303 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();
1304 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1311 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1318 fontName = fontFamily;
1328 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1331 if ( !fontStyleName.isEmpty() )
1332 textFont.setStyleName( fontStyleName );
1342 fontName = QStringLiteral(
"Open Sans" );
1344 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1345 fontStyleName = QStringLiteral(
"Regular" );
1350 fontName = QStringLiteral(
"Arial Unicode MS" );
1352 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1353 fontStyleName = QStringLiteral(
"Regular" );
1358 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1361 if ( !foundFont && !fontName.isEmpty() )
1363 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1368 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1370 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1371 switch ( jsonTextColor.type() )
1377 case QVariant::List:
1378 case QVariant::StringList:
1382 case QVariant::String:
1383 textColor =
parseColor( jsonTextColor.toString(), context );
1387 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextColor.type() ) ) );
1394 textColor = QColor( 0, 0, 0 );
1398 QColor bufferColor( 0, 0, 0, 0 );
1399 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1401 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1402 switch ( jsonBufferColor.type() )
1408 case QVariant::List:
1409 case QVariant::StringList:
1413 case QVariant::String:
1414 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1418 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-color type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonBufferColor.type() ) ) );
1423 double bufferSize = 0.0;
1427 constexpr double BUFFER_SIZE_SCALE = 2.0;
1428 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1430 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1431 switch ( jsonHaloWidth.type() )
1434 case QVariant::LongLong:
1435 case QVariant::Double:
1444 case QVariant::List:
1445 case QVariant::StringList:
1451 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-width type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonHaloWidth.type() ) ) );
1456 double haloBlurSize = 0;
1457 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1459 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1460 switch ( jsonTextHaloBlur.type() )
1463 case QVariant::LongLong:
1464 case QVariant::Double:
1471 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-halo-blur type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextHaloBlur.type() ) ) );
1478 if ( textColor.isValid() )
1480 if ( textSize >= 0 )
1485 if ( !fontStyleName.isEmpty() )
1488 if ( textLetterSpacing > 0 )
1490 QFont f = format.
font();
1491 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1495 if ( bufferSize > 0 )
1498 const double opacity = bufferColor.alphaF();
1499 bufferColor.setAlphaF( 1.0 );
1507 if ( haloBlurSize > 0 )
1523 if ( textMaxWidth > 0 )
1529 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1531 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1532 switch ( jsonTextField.type() )
1534 case QVariant::String:
1536 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1540 case QVariant::List:
1541 case QVariant::StringList:
1543 const QVariantList textFieldList = jsonTextField.toList();
1551 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1554 for (
int i = 1; i < textFieldList.size(); ++i )
1556 bool isExpression =
false;
1557 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1558 if ( !isExpression )
1565 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1582 const QVariantList stops = jsonTextField.toMap().value( QStringLiteral(
"stops" ) ).toList();
1583 if ( !stops.empty() )
1590 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field dictionary" ).arg( context.
layerId() ) );
1596 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-field type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextField.type() ) ) );
1601 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1603 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1604 if ( textTransform == QLatin1String(
"uppercase" ) )
1608 else if ( textTransform == QLatin1String(
"lowercase" ) )
1617 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1619 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1620 if ( symbolPlacement == QLatin1String(
"line" ) )
1626 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1628 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1629 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1639 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1641 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1644 switch ( jsonTextOffset.type() )
1647 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1648 if ( !textSizeProperty )
1659 case QVariant::List:
1660 case QVariant::StringList:
1661 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1662 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1666 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextOffset.type() ) ) );
1670 if ( !textOffset.isNull() )
1673 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1675 if ( textSizeProperty && !textOffsetProperty )
1682 if ( textOffset.isNull() )
1690 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1692 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1695 QString textAlign = QStringLiteral(
"center" );
1697 const QVariantMap conversionMap
1699 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1700 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1701 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1702 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1705 switch ( jsonTextJustify.type() )
1707 case QVariant::String:
1708 textAlign = jsonTextJustify.toString();
1711 case QVariant::List:
1720 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-justify type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextJustify.type() ) ) );
1724 if ( textAlign == QLatin1String(
"left" ) )
1726 else if ( textAlign == QLatin1String(
"right" ) )
1728 else if ( textAlign == QLatin1String(
"center" ) )
1730 else if ( textAlign == QLatin1String(
"follow" ) )
1740 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1742 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1745 const QVariantMap conversionMap
1747 { QStringLiteral(
"center" ), 4 },
1748 { QStringLiteral(
"left" ), 5 },
1749 { QStringLiteral(
"right" ), 3 },
1750 { QStringLiteral(
"top" ), 7 },
1751 { QStringLiteral(
"bottom" ), 1 },
1752 { QStringLiteral(
"top-left" ), 8 },
1753 { QStringLiteral(
"top-right" ), 6 },
1754 { QStringLiteral(
"bottom-left" ), 2 },
1755 { QStringLiteral(
"bottom-right" ), 0 },
1758 switch ( jsonTextAnchor.type() )
1760 case QVariant::String:
1761 textAnchor = jsonTextAnchor.toString();
1764 case QVariant::List:
1773 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-anchor type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextAnchor.type() ) ) );
1777 if ( textAnchor == QLatin1String(
"center" ) )
1779 else if ( textAnchor == QLatin1String(
"left" ) )
1781 else if ( textAnchor == QLatin1String(
"right" ) )
1783 else if ( textAnchor == QLatin1String(
"top" ) )
1785 else if ( textAnchor == QLatin1String(
"bottom" ) )
1787 else if ( textAnchor == QLatin1String(
"top-left" ) )
1789 else if ( textAnchor == QLatin1String(
"top-right" ) )
1791 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1793 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1798 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1800 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1803 switch ( jsonTextOffset.type() )
1809 case QVariant::List:
1810 case QVariant::StringList:
1811 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1812 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1816 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported text-offset type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonTextOffset.type() ) ) );
1820 if ( !textOffset.isNull() )
1823 labelSettings.
xOffset = textOffset.x();
1824 labelSettings.
yOffset = textOffset.y();
1829 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1833 QString spriteProperty, spriteSizeProperty;
1834 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1835 if ( !sprite.isEmpty() )
1838 markerLayer->
setPath( sprite );
1839 markerLayer->
setSize( spriteSize.width() );
1842 if ( !spriteProperty.isEmpty() )
1854 backgroundSettings.
setSize( spriteSize );
1862 if ( textSize >= 0 )
1885 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1887 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1890 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1892 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1896 double spacing = -1.0;
1897 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
1899 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
1900 switch ( jsonSpacing.type() )
1903 case QVariant::LongLong:
1904 case QVariant::Double:
1912 case QVariant::List:
1913 case QVariant::StringList:
1918 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported symbol-spacing type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonSpacing.type() ) ) );
1928 bool rotateMarkers =
true;
1929 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
1931 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
1932 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
1934 rotateMarkers =
true;
1936 else if ( alignment == QLatin1String(
"viewport" ) )
1938 rotateMarkers =
false;
1943 double rotation = 0.0;
1944 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
1946 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
1947 switch ( jsonIconRotate.type() )
1950 case QVariant::LongLong:
1951 case QVariant::Double:
1952 rotation = jsonIconRotate.toDouble();
1959 case QVariant::List:
1960 case QVariant::StringList:
1965 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconRotate.type() ) ) );
1981 QString spriteProperty, spriteSizeProperty;
1982 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1983 if ( !sprite.isNull() )
1985 markerLayer->
setPath( sprite );
1986 markerLayer->
setSize( spriteSize.width() );
1989 if ( !spriteProperty.isEmpty() )
1996 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1998 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2001 switch ( jsonIconSize.type() )
2004 case QVariant::LongLong:
2005 case QVariant::Double:
2007 size = jsonIconSize.toDouble();
2008 if ( !spriteSizeProperty.isEmpty() )
2011 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2020 case QVariant::List:
2021 case QVariant::StringList:
2023 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconSize.type() ) ) );
2026 markerLayer->
setSize( size * spriteSize.width() );
2029 if ( !spriteSizeProperty.isEmpty() )
2046 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
2049 symbol->setOutputUnit( context.
targetUnit() );
2053 rendererStyle.
setSymbol( symbol.release() );
2056 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
2058 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
2061 QString spriteProperty, spriteSizeProperty;
2062 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
2063 if ( !sprite.isEmpty() )
2066 rasterMarker->
setPath( sprite );
2067 rasterMarker->
setSize( spriteSize.width() );
2071 if ( !spriteProperty.isEmpty() )
2077 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
2079 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
2082 switch ( jsonIconSize.type() )
2085 case QVariant::LongLong:
2086 case QVariant::Double:
2088 size = jsonIconSize.toDouble();
2089 if ( !spriteSizeProperty.isEmpty() )
2092 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
2101 case QVariant::List:
2102 case QVariant::StringList:
2104 context.
pushWarning( QObject::tr(
"%1: Skipping non-implemented icon-size type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconSize.type() ) ) );
2107 rasterMarker->
setSize( size * spriteSize.width() );
2110 if ( !spriteSizeProperty.isEmpty() )
2123 double rotation = 0.0;
2124 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
2126 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
2127 switch ( jsonIconRotate.type() )
2130 case QVariant::LongLong:
2131 case QVariant::Double:
2132 rotation = jsonIconRotate.toDouble();
2139 case QVariant::List:
2140 case QVariant::StringList:
2145 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-rotate type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconRotate.type() ) ) );
2150 double iconOpacity = -1.0;
2151 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2153 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2154 switch ( jsonIconOpacity.type() )
2157 case QVariant::LongLong:
2158 case QVariant::Double:
2159 iconOpacity = jsonIconOpacity.toDouble();
2166 case QVariant::List:
2167 case QVariant::StringList:
2172 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported icon-opacity type (%2)" ).arg( context.
layerId(), QMetaType::typeName( jsonIconOpacity.type() ) ) );
2178 rasterMarker->
setAngle( rotation );
2179 if ( iconOpacity >= 0 )
2183 rendererStyle.
setSymbol( markerSymbol );
2194 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2195 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2196 if ( stops.empty() )
2199 QString caseString = QStringLiteral(
"CASE " );
2200 const QString colorComponent(
"color_part(%1,'%2')" );
2202 for (
int i = 0; i < stops.length() - 1; ++i )
2205 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2207 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2209 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2210 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2212 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2213 const QColor topColor =
parseColor( tcVariant.toString(), context );
2215 if ( i == 0 && bottomColor.isValid() )
2222 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2223 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2226 if ( bottomColor.isValid() && topColor.isValid() )
2238 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2239 "%3, %4, %5, %6) " ).arg( bz, tz,
2250 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2251 "%3, %4, %5, %6) " ).arg( bz, tz,
2252 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2253 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2254 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2255 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2260 const QString tz = stops.last().toList().value( 0 ).toString();
2261 const QVariant tcVariant = stops.last().toList().value( 1 );
2262 const QColor topColor =
parseColor( stops.last().toList().value( 1 ), context );
2263 if ( topColor.isValid() )
2270 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2271 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2277 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2278 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2279 .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" ) );
2282 if ( !stops.empty() && defaultColor )
2283 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2290 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2291 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2292 if ( stops.empty() )
2295 QString scaleExpression;
2296 if ( stops.size() <= 2 )
2299 stops.last().toList().value( 0 ).toDouble(),
2300 stops.value( 0 ).toList().value( 1 ),
2301 stops.last().toList().value( 1 ), base, multiplier, &context );
2305 scaleExpression =
parseStops( base, stops, multiplier, context );
2308 if ( !stops.empty() && defaultNumber )
2309 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2319 context = *contextPtr;
2321 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2322 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2323 if ( stops.empty() )
2326 QString scaleExpression;
2327 if ( stops.length() <= 2 )
2329 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2330 const QVariant tv = stops.last().toList().value( 1 );
2331 double bottom = 0.0;
2333 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2334 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2336 stops.last().toList().value( 0 ).toDouble(),
2337 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2338 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2349 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2350 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2351 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2353 for (
int i = 0; i < stops.size() - 1; ++i )
2355 const QVariant bv = stops.value( i ).toList().value( 1 );
2356 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2357 double bottom = 0.0;
2359 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2361 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2362 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2363 .arg( stops.value( i ).toList().value( 0 ).toString(),
2364 stops.value( i + 1 ).toList().value( 0 ).toString(),
2366 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2367 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2368 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2369 base, 1, &context ) );
2372 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2373 "THEN set_color_part(@symbol_color, 'alpha', %2) END" )
2374 .arg( stops.last().toList().value( 0 ).toString() )
2375 .arg( stops.last().toList().value( 1 ).toDouble() * maxOpacity );
2381 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2382 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2383 if ( stops.empty() )
2386 QString scaleExpression;
2387 if ( stops.size() <= 2 )
2389 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2390 stops.last().toList().value( 0 ).toDouble(),
2391 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2392 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2394 stops.last().toList().value( 0 ).toDouble(),
2395 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2396 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2401 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2404 if ( !stops.empty() && defaultPoint )
2405 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2406 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2412 const QVariantMap &conversionMap, QString *defaultString )
2414 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2415 if ( stops.empty() )
2418 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2425 QString caseString = QStringLiteral(
"CASE " );
2427 for (
int i = 0; i < stops.length() - 1; ++i )
2430 const QVariant bz = stops.value( i ).toList().value( 0 );
2431 const QVariant bv = stops.value( i ).toList().value( 1 );
2432 if ( bv.type() != QVariant::List && bv.type() != QVariant::StringList )
2434 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName( bz.type() ) ) );
2439 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2440 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2441 if ( tv.type() != QVariant::List && tv.type() != QVariant::StringList )
2443 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported offset interpolation type (%2)." ).arg( context.
layerId(), QMetaType::typeName( tz.type() ) ) );
2447 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2448 "THEN array(%3,%4)" ).arg( bz.toString(),
2450 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2451 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2453 caseString += QLatin1String(
"END" );
2459 if ( stops.length() < 2 )
2462 QString caseString = QStringLiteral(
"CASE " );
2464 for (
int i = 0; i < stops.length() - 1; ++i )
2467 const QVariant bz = stops.value( i ).toList().value( 0 );
2468 const QList<QVariant> bv = stops.value( i ).toList().value( 1 ).toList();
2471 for (
const QVariant &value : bv )
2473 const double number = value.toDouble( &ok );
2475 bl << QString::number( number * multiplier );
2479 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2480 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2481 "THEN array(%3) " ).arg( bz.toString(),
2485 const QVariant lz = stops.value( stops.length() - 1 ).toList().value( 0 );
2486 const QList<QVariant> lv = stops.value( stops.length() - 1 ).toList().value( 1 ).toList();
2489 for (
const QVariant &value : lv )
2491 const double number = value.toDouble( &ok );
2493 ll << QString::number( number * multiplier );
2495 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2496 "THEN array(%2) " ).arg( lz.toString(),
2498 caseString += QLatin1String(
"END" );
2504 QString caseString = QStringLiteral(
"CASE " );
2506 for (
int i = 0; i < stops.length() - 1; ++i )
2509 const QVariant bz = stops.value( i ).toList().value( 0 );
2510 const QVariant bv = stops.value( i ).toList().value( 1 );
2511 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2513 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2518 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2519 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2520 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2522 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2526 const QString lowerComparator = i == 0 ? QStringLiteral(
">=" ) : QStringLiteral(
">" );
2528 caseString += QStringLiteral(
"WHEN @vector_tile_zoom %1 %2 AND @vector_tile_zoom <= %3 "
2529 "THEN %4 " ).arg( lowerComparator,
2535 const QVariant z = stops.last().toList().value( 0 );
2536 const QVariant v = stops.last().toList().value( 1 );
2537 QString vStr = v.toString();
2538 if ( ( QMetaType::Type )v.type() == QMetaType::QVariantList )
2541 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2542 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2546 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2547 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2555 QString caseString = QStringLiteral(
"CASE " );
2557 for (
int i = 0; i < stops.length() - 1; ++i )
2560 const QVariant bz = stops.value( i ).toList().value( 0 );
2561 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2562 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2564 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2569 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2570 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2572 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2576 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2577 "THEN %3 " ).arg( bz.toString(),
2581 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2582 stops.constLast().toList().value( 1 ) ) ) );
2583 if ( defaultString )
2584 *defaultString = stops.constLast().toList().value( 1 ).toString();
2590 QString caseString = QStringLiteral(
"CASE " );
2592 bool isExpression =
false;
2593 for (
int i = 0; i < stops.length() - 1; ++i )
2596 const QVariant bz = stops.value( i ).toList().value( 0 );
2597 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2599 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2604 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2605 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2607 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2611 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2612 if ( fieldPart.isEmpty() )
2613 fieldPart = QStringLiteral(
"''" );
2614 else if ( !isExpression )
2617 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom < %2 "
2618 "THEN %3 " ).arg( bz.toString(),
2624 const QVariant bz = stops.constLast().toList().value( 0 );
2625 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2627 context.
pushWarning( QObject::tr(
"%1: Lists in label interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2631 QString fieldPart = processLabelField( stops.constLast().toList().value( 1 ).toString(), isExpression );
2632 if ( fieldPart.isEmpty() )
2633 fieldPart = QStringLiteral(
"''" );
2634 else if ( !isExpression )
2637 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 "
2638 "THEN %3 " ).arg( bz.toString(),
2642 QString defaultPart = processLabelField( stops.constFirst().toList().value( 1 ).toString(), isExpression );
2643 if ( defaultPart.isEmpty() )
2644 defaultPart = QStringLiteral(
"''" );
2645 else if ( !isExpression )
2647 caseString += QStringLiteral(
"ELSE %1 END" ).arg( defaultPart );
2654 const QString method = json.
value( 0 ).toString();
2655 if ( method == QLatin1String(
"interpolate" ) )
2659 else if ( method == QLatin1String(
"match" ) )
2661 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2671 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2672 if ( attribute.isEmpty() )
2674 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2678 QString caseString = QStringLiteral(
"CASE " );
2680 for (
int i = 2; i < json.length() - 1; i += 2 )
2682 const QVariantList keys = json.value( i ).toList();
2684 QStringList matchString;
2685 for (
const QVariant &key : keys )
2690 const QVariant value = json.value( i + 1 );
2692 QString valueString;
2697 const QColor color =
parseColor( value, context );
2704 const double v = value.toDouble() * multiplier;
2705 valueString = QString::number( v );
2711 const double v = value.toDouble() * maxOpacity;
2712 valueString = QString::number( v );
2718 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2719 value.toList().value( 0 ).toDouble() * multiplier );
2725 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
2726 matchString.join(
',' ), valueString );
2735 const QColor color =
parseColor( json.constLast(), context );
2737 *defaultColor = color;
2745 const double v = json.constLast().toDouble() * multiplier;
2746 if ( defaultNumber )
2748 elseValue = QString::number( v );
2754 const double v = json.constLast().toDouble() * maxOpacity;
2755 if ( defaultNumber )
2757 elseValue = QString::number( v );
2763 elseValue = QStringLiteral(
"array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
2764 json.constLast().toList().value( 0 ).toDouble() * multiplier );
2770 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
2776 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
2778 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
2783 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
2784 if ( technique == QLatin1String(
"linear" ) )
2786 else if ( technique == QLatin1String(
"exponential" ) )
2787 base = json.value( 1 ).toList(). value( 1 ).toDouble();
2788 else if ( technique == QLatin1String(
"cubic-bezier" ) )
2790 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
2795 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
2799 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
2801 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
2807 for (
int i = 3; i < json.length(); i += 2 )
2809 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
2813 props.insert( QStringLiteral(
"stops" ), stops );
2814 props.insert( QStringLiteral(
"base" ), base );
2834 if ( ( QMetaType::Type )colorExpression.type() == QMetaType::QVariantList )
2838 return parseValue( colorExpression, context,
true );
2843 if ( color.type() != QVariant::String )
2845 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
2854 hue = std::max( 0, color.hslHue() );
2855 saturation = color.hslSaturation() / 255.0 * 100;
2856 lightness = color.lightness() / 255.0 * 100;
2857 alpha = color.alpha();
2865 context = *contextPtr;
2869 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
2871 bool minDoubleOk =
true;
2872 const double min = valueMin.toDouble( &minDoubleOk );
2873 bool maxDoubleOk =
true;
2874 const double max = valueMax.toDouble( &maxDoubleOk );
2875 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
2877 return QString::number( min * multiplier );
2881 QString minValueExpr = valueMin.toString();
2882 QString maxValueExpr = valueMax.toString();
2883 if ( ( QMetaType::Type )valueMin.type() == QMetaType::QVariantList )
2887 if ( ( QMetaType::Type )valueMax.type() == QMetaType::QVariantList )
2892 if ( minValueExpr == maxValueExpr )
2894 return minValueExpr;
2900 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin )
2902 .arg( minValueExpr )
2903 .arg( maxValueExpr );
2909 QString ratioExpr = QStringLiteral(
"(%1^(@vector_tile_zoom - %2) - 1) / (%1^(%3 - %2) - 1)" ).arg( base ).arg( zoomMin ).arg( zoomMax );
2910 expression = QStringLiteral(
"(%1) + (%2) * ((%3) - (%1))" ).arg( minValueExpr ).arg( ratioExpr ).arg( maxValueExpr );
2919 if ( multiplier != 1 )
2920 return QStringLiteral(
"(%1) * %2" ).arg( expression ).arg( multiplier );
2927 if ( style == QLatin1String(
"round" ) )
2928 return Qt::RoundCap;
2929 else if ( style == QLatin1String(
"square" ) )
2930 return Qt::SquareCap;
2937 if ( style == QLatin1String(
"bevel" ) )
2938 return Qt::BevelJoin;
2939 else if ( style == QLatin1String(
"round" ) )
2940 return Qt::RoundJoin;
2942 return Qt::MiterJoin;
2947 QString op = expression.value( 0 ).toString();
2948 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
2950 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ) ).arg( op ).arg( parseValue( expression.value( 2 ), context ) );
2952 else if ( op == QLatin1String(
"to-number" ) )
2954 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
2956 if ( op == QLatin1String(
"literal" ) )
2958 return expression.value( 1 ).toString();
2960 else if ( op == QLatin1String(
"all" )
2961 || op == QLatin1String(
"any" )
2962 || op == QLatin1String(
"none" ) )
2965 for (
int i = 1; i < expression.size(); ++i )
2967 const QString part = parseValue( expression.at( i ), context );
2968 if ( part.isEmpty() )
2970 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2976 if ( op == QLatin1String(
"none" ) )
2977 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
2979 QString operatorString;
2980 if ( op == QLatin1String(
"all" ) )
2981 operatorString = QStringLiteral(
") AND (" );
2982 else if ( op == QLatin1String(
"any" ) )
2983 operatorString = QStringLiteral(
") OR (" );
2985 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
2987 else if ( op ==
'!' )
2990 QVariantList contraJsonExpr = expression.value( 1 ).toList();
2991 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
2993 return parseKey( contraJsonExpr, context );
2995 else if ( op == QLatin1String(
"==" )
2996 || op == QLatin1String(
"!=" )
2997 || op == QLatin1String(
">=" )
2999 || op == QLatin1String(
"<=" )
3003 if ( op == QLatin1String(
"==" ) )
3004 op = QStringLiteral(
"IS" );
3005 else if ( op == QLatin1String(
"!=" ) )
3006 op = QStringLiteral(
"IS NOT" );
3007 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
3008 op, parseValue( expression.value( 2 ), context ) );
3010 else if ( op == QLatin1String(
"has" ) )
3012 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
3014 else if ( op == QLatin1String(
"!has" ) )
3016 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
3018 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
3020 const QString key = parseKey( expression.value( 1 ), context );
3022 for (
int i = 2; i < expression.size(); ++i )
3024 const QString part = parseValue( expression.at( i ), context );
3025 if ( part.isEmpty() )
3027 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3032 if ( op == QLatin1String(
"in" ) )
3033 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3035 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
3037 else if ( op == QLatin1String(
"get" ) )
3039 return parseKey( expression.value( 1 ), context );
3041 else if ( op == QLatin1String(
"match" ) )
3043 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
3045 if ( expression.size() == 5
3046 && expression.at( 3 ).type() == QVariant::Bool && expression.at( 3 ).toBool() ==
true
3047 && expression.at( 4 ).type() == QVariant::Bool && expression.at( 4 ).toBool() ==
false )
3050 if ( expression.at( 2 ).type() == QVariant::List || expression.at( 2 ).type() == QVariant::StringList )
3053 for (
const QVariant &p : expression.at( 2 ).toList() )
3055 parts << parseValue( p, context );
3058 if ( parts.size() > 1 )
3063 else if ( expression.at( 2 ).type() == QVariant::String || expression.at( 2 ).type() == QVariant::Int
3064 || expression.at( 2 ).type() == QVariant::Double || expression.at( 2 ).type() == QVariant::LongLong )
3070 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3076 QString caseString = QStringLiteral(
"CASE " );
3077 for (
int i = 2; i < expression.size() - 2; i += 2 )
3079 if ( expression.at( i ).type() == QVariant::List || expression.at( i ).type() == QVariant::StringList )
3082 for (
const QVariant &p : expression.at( i ).toList() )
3087 if ( parts.size() > 1 )
3092 else if ( expression.at( i ).type() == QVariant::String || expression.at( i ).type() == QVariant::Int
3093 || expression.at( i ).type() == QVariant::Double || expression.at( i ).type() == QVariant::LongLong )
3098 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
3100 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
3104 else if ( op == QLatin1String(
"to-string" ) )
3106 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
3110 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
3119 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3123 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
3124 if ( spriteDefinition.size() == 0 )
3126 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3130 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
3131 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
3132 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
3133 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
3134 if ( sprite.isNull() )
3136 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
3140 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
3148 auto prepareBase64 = [](
const QImage & sprite )
3151 if ( !sprite.isNull() )
3154 QBuffer buffer( &blob );
3155 buffer.open( QIODevice::WriteOnly );
3156 sprite.save( &buffer,
"PNG" );
3158 const QByteArray encoded = blob.toBase64();
3159 path = QString( encoded );
3160 path.prepend( QLatin1String(
"base64:" ) );
3165 switch ( value.type() )
3167 case QVariant::String:
3169 QString spriteName = value.toString();
3170 const thread_local QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
3171 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
3172 if ( match.hasMatch() )
3174 const QString fieldName = match.captured( 1 );
3175 spriteProperty = QStringLiteral(
"CASE" );
3176 spriteSizeProperty = QStringLiteral(
"CASE" );
3178 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
3179 spriteName.replace(
")", QLatin1String(
"\\)" ) );
3180 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
3181 const QRegularExpression fieldValueMatch( spriteName );
3183 for (
const QString &name : spriteNames )
3185 match = fieldValueMatch.match( name );
3186 if ( match.hasMatch() )
3190 const QString fieldValue = match.captured( 1 );
3192 path = prepareBase64( sprite );
3193 if ( spritePath.isEmpty() && !path.isEmpty() )
3199 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
3200 .arg( fieldName, fieldValue, path );
3201 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
3202 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
3206 spriteProperty += QLatin1String(
" END" );
3207 spriteSizeProperty += QLatin1String(
" END" );
3211 spriteProperty.clear();
3212 spriteSizeProperty.clear();
3213 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
3214 spritePath = prepareBase64( sprite );
3221 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3222 if ( stops.size() == 0 )
3229 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3230 spritePath = prepareBase64( sprite );
3232 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3233 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3235 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3236 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3237 .arg( spriteSize.width() );
3239 for (
int i = 0; i < stops.size() - 1; ++i )
3242 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3243 path = prepareBase64( sprite );
3245 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3247 .arg( stops.value( i ).toList().value( 0 ).toString(),
3248 stops.value( i + 1 ).toList().value( 0 ).toString(),
3250 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3252 .arg( stops.value( i ).toList().value( 0 ).toString(),
3253 stops.value( i + 1 ).toList().value( 0 ).toString() )
3254 .arg( size.width() );
3256 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3257 path = prepareBase64( sprite );
3259 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3261 .arg( stops.last().toList().value( 0 ).toString() )
3263 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3265 .arg( stops.last().toList().value( 0 ).toString() )
3266 .arg( size.width() );
3270 case QVariant::List:
3272 const QVariantList json = value.toList();
3273 const QString method = json.value( 0 ).toString();
3274 if ( method != QLatin1String(
"match" ) )
3276 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3280 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3281 if ( attribute.isEmpty() )
3283 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3287 spriteProperty = QStringLiteral(
"CASE " );
3288 spriteSizeProperty = QStringLiteral(
"CASE " );
3290 for (
int i = 2; i < json.length() - 1; i += 2 )
3292 const QVariantList keys = json.value( i ).toList();
3294 QStringList matchString;
3295 for (
const QVariant &key : keys )
3300 const QVariant value = json.value( i + 1 );
3302 const QImage sprite =
retrieveSprite( value.toString(), context, spriteSize );
3303 spritePath = prepareBase64( sprite );
3305 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3306 "THEN '%3' " ).arg( attribute,
3307 matchString.join(
',' ),
3310 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3311 "THEN %3 " ).arg( attribute,
3312 matchString.join(
',' ) ).arg( spriteSize.width() );
3315 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3316 spritePath = prepareBase64( sprite );
3318 spriteProperty += QStringLiteral(
"ELSE %1 END" ).arg( spritePath );
3319 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3324 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported sprite type (%2)." ).arg( context.
layerId(), QMetaType::typeName( value.type() ) ) );
3334 switch ( value.type() )
3336 case QVariant::List:
3337 case QVariant::StringList:
3340 case QVariant::Bool:
3341 case QVariant::String:
3342 if ( colorExpected )
3347 return parseValue(
c, context );
3353 case QVariant::LongLong:
3354 case QVariant::Double:
3355 return value.toString();
3357 case QVariant::Color:
3358 c = value.value<QColor>();
3359 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3362 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3370 if ( value.toString() == QLatin1String(
"$type" ) )
3372 return QStringLiteral(
"_geom_type" );
3374 if ( value.toString() == QLatin1String(
"level" ) )
3376 return QStringLiteral(
"level" );
3378 else if ( ( value.type() == QVariant::List && value.toList().size() == 1 ) || value.type() == QVariant::StringList )
3380 if ( value.toList().size() > 1 )
3381 return value.toList().at( 1 ).toString();
3384 QString valueString = value.toList().value( 0 ).toString();
3385 if ( valueString == QLatin1String(
"geometry-type" ) )
3387 return QStringLiteral(
"_geom_type" );
3392 else if ( value.type() == QVariant::List && value.toList().size() > 1 )
3399QString QgsMapBoxGlStyleConverter::processLabelField(
const QString &
string,
bool &isExpression )
3403 const thread_local QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
3404 const QRegularExpressionMatch match = singleFieldRx.match(
string );
3405 if ( match.hasMatch() )
3407 isExpression =
false;
3408 return match.captured( 1 );
3411 const thread_local QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
3412 const QStringList parts =
string.split( multiFieldRx );
3413 if ( parts.size() > 1 )
3415 isExpression =
true;
3418 for (
const QString &part : parts )
3420 if ( part.isEmpty() )
3423 if ( !part.contains(
'{' ) )
3430 const QStringList split = part.split(
'}' );
3432 if ( !split.at( 1 ).isEmpty() )
3435 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
3439 isExpression =
false;
3446 return mRenderer ? mRenderer->clone() :
nullptr;
3451 return mLabeling ? mLabeling->clone() :
nullptr;
3461 return mRasterSubLayers;
3466 QList<QgsMapLayer *> subLayers;
3469 const QString sourceName = subLayer.source();
3470 std::unique_ptr< QgsRasterLayer > rl;
3477 rl->pipe()->setDataDefinedProperties( subLayer.dataDefinedProperties() );
3484 subLayers.append( rl.release() );
3493 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3496 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3497 context = tmpContext.get();
3502 if (
string.compare( QLatin1String(
"vector" ), Qt::CaseInsensitive ) == 0 )
3504 else if (
string.compare( QLatin1String(
"raster" ), Qt::CaseInsensitive ) == 0 )
3506 else if (
string.compare( QLatin1String(
"raster-dem" ), Qt::CaseInsensitive ) == 0 )
3508 else if (
string.compare( QLatin1String(
"geojson" ), Qt::CaseInsensitive ) == 0 )
3510 else if (
string.compare( QLatin1String(
"image" ), Qt::CaseInsensitive ) == 0 )
3512 else if (
string.compare( QLatin1String(
"video" ), Qt::CaseInsensitive ) == 0 )
3514 context->
pushWarning( QObject::tr(
"Invalid source type \"%1\" for source \"%2\"" ).arg(
string, name ) );
3520 const QString name = it.key();
3521 const QVariantMap jsonSource = it.value().toMap();
3522 const QString typeString = jsonSource.value( QStringLiteral(
"type" ) ).toString();
3545 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
3548 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
3549 context = tmpContext.get();
3552 std::unique_ptr< QgsMapBoxGlStyleRasterSource > raster = std::make_unique< QgsMapBoxGlStyleRasterSource >( name );
3553 if ( raster->setFromJson( source, context ) )
3554 mSources.append( raster.release() );
3557bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
3559 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
3561 bool bDoubleOk, tDoubleOk;
3562 bottom = bottomVariant.toDouble( &bDoubleOk );
3563 top = topVariant.toDouble( &tDoubleOk );
3564 return ( bDoubleOk && tDoubleOk );
3575 mWarnings << warning;
3590 return mSizeConversionFactor;
3595 mSizeConversionFactor = sizeConversionFactor;
3600 return mSpriteImage;
3605 return mSpriteDefinitions;
3610 mSpriteImage = image;
3611 mSpriteDefinitions = definitions;
3661 mAttribution = json.value( QStringLiteral(
"attribution" ) ).toString();
3663 const QString scheme = json.value( QStringLiteral(
"scheme" ), QStringLiteral(
"xyz" ) ).toString();
3664 if ( scheme.compare( QLatin1String(
"xyz" ) ) == 0 )
3670 context->
pushWarning( QObject::tr(
"%1 scheme is not supported for raster source %2" ).arg( scheme,
name() ) );
3674 mMinZoom = json.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"0" ) ).toInt();
3675 mMaxZoom = json.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"22" ) ).toInt();
3676 mTileSize = json.value( QStringLiteral(
"tileSize" ), QStringLiteral(
"512" ) ).toInt();
3678 const QVariantList
tiles = json.value( QStringLiteral(
"tiles" ) ).toList();
3679 for (
const QVariant &tile :
tiles )
3681 mTiles.append( tile.toString() );
3690 parts.insert( QStringLiteral(
"type" ), QStringLiteral(
"xyz" ) );
3691 parts.insert( QStringLiteral(
"url" ), mTiles.value( 0 ) );
3693 if ( mTileSize == 256 )
3694 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"1" ) );
3695 else if ( mTileSize == 512 )
3696 parts.insert( QStringLiteral(
"tilePixelRation" ), QStringLiteral(
"2" ) );
3698 parts.insert( QStringLiteral(
"zmax" ), QString::number( mMaxZoom ) );
3699 parts.insert( QStringLiteral(
"zmin" ), QString::number( mMinZoom ) );
3701 std::unique_ptr< QgsRasterLayer > rl = std::make_unique< QgsRasterLayer >(
QgsProviderRegistry::instance()->encodeUri( QStringLiteral(
"wms" ), parts ),
name(), QStringLiteral(
"wms" ) );
3702 return rl.release();
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
@ OnLine
Labels can be placed directly over a line feature.
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ CentralPoint
Place symbols at the mid point of the line.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Curved
Arranges candidates following the curvature of a line feature. Applies to line layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ FollowPlacement
Alignment follows placement of label, e.g., labels to the left of a feature will be drawn with right ...
RenderUnit
Rendering size units.
MapBoxGlStyleSourceType
Flags which control project capabilities.
@ RasterDem
Raster DEM source.
@ Unknown
Other/unknown source type.
@ Viewport
Relative to the whole viewport/output device.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
static QgsFontManager * fontManager()
Returns the application font manager, which manages available fonts and font installation for the QGI...
A paint effect which blurs a source picture, using a number of different blur methods.
void setBlurUnit(const Qgis::RenderUnit unit)
Sets the units used for the blur level (radius).
@ StackBlur
Stack blur, a fast but low quality blur. Valid blur level values are between 0 - 16.
void setBlurMethod(const BlurMethod method)
Sets the blur method (algorithm) to use for performing the blur.
void setBlurLevel(const double level)
Sets blur level (radius)
A paint effect which consists of a stack of other chained paint effects.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value, QVariant::Type fieldType=QVariant::Type::Invalid)
Create an expression allowing to evaluate if a field is equal to a value.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
QString processFontFamilyName(const QString &name) const
Processes a font family name, applying any matching fontFamilyReplacements() to the name.
static QFont createFont(const QString &family, int pointSize=-1, int weight=-1, bool italic=false)
Creates a font with the specified family.
static bool fontFamilyHasStyle(const QString &family, const QString &style)
Check whether font family on system has specific style.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
void setPlacementFlags(Qgis::LabelLinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setFactor(double factor)
Sets the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setOffset(double offset)
Sets the line's offset.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the line's offset.
Abstract base class for MapBox GL style sources.
QString name() const
Returns the source's name.
virtual ~QgsMapBoxGlStyleAbstractSource()
QgsMapBoxGlStyleAbstractSource(const QString &name)
Constructor for QgsMapBoxGlStyleAbstractSource.
Context for a MapBox GL style conversion operation.
void setLayerId(const QString &value)
Sets the layer ID of the layer currently being converted.
QStringList warnings() const
Returns a list of warning messages generated during the conversion.
void pushWarning(const QString &warning)
Pushes a warning message generated during the conversion.
double pixelSizeConversionFactor() const
Returns the pixel size conversion factor, used to scale the original pixel sizes when converting styl...
void setTargetUnit(Qgis::RenderUnit targetUnit)
Sets the target unit type.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
Qgis::RenderUnit targetUnit() const
Returns the target unit type.
void setSprites(const QImage &image, const QVariantMap &definitions)
Sets the sprite image and definitions JSON to use during conversion.
QString layerId() const
Returns the layer ID of the layer currently being converted.
QImage spriteImage() const
Returns the sprite image to use during conversion, or an invalid image if this is not set.
void clearWarnings()
Clears the list of warning messages.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
static QString parseOpacityStops(double base, const QVariantList &stops, int maxOpacity, QgsMapBoxGlStyleConversionContext &context)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate alpha ...
static QString parseColorExpression(const QVariant &colorExpression, QgsMapBoxGlStyleConversionContext &context)
Converts an expression representing a color to a string (can be color string or an expression where a...
static QString parseStops(double base, const QVariantList &stops, double multiplier, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
static QString parseExpression(const QVariantList &expression, QgsMapBoxGlStyleConversionContext &context, bool colorExpected=false)
Converts a MapBox GL expression to a QGIS expression.
PropertyType
Property types, for interpolated value conversion.
@ Point
Point/offset property.
@ Numeric
Numeric property (e.g. line width, text size)
@ Opacity
Opacity property.
QList< QgsMapBoxGlStyleAbstractSource * > sources()
Returns the list of converted sources.
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted style,...
QList< QgsMapBoxGlStyleRasterSubLayer > rasterSubLayers() const
Returns a list of raster sub layers contained in the style.
static QgsProperty parseInterpolateByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, double *defaultNumber=nullptr)
Parses a numeric value which is interpolated by zoom range.
static Qt::PenJoinStyle parseJoinStyle(const QString &style)
Converts a value to Qt::PenJoinStyle enum from JSON value.
static QgsProperty parseInterpolateStringByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Interpolates a string by zoom.
static QString interpolateExpression(double zoomMin, double zoomMax, QVariant valueMin, QVariant valueMax, double base, double multiplier=1, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Generates an interpolation for values between valueMin and valueMax, scaled between the ranges zoomMi...
static QgsProperty parseInterpolatePointByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, QPointF *defaultPoint=nullptr)
Interpolates a point/offset with either scale_linear() or scale_exp() (depending on base value).
static bool parseCircleLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a circle layer.
Result convert(const QVariantMap &style, QgsMapBoxGlStyleConversionContext *context=nullptr)
Converts a JSON style map, and returns the resultant status of the conversion.
static QgsProperty parseInterpolateListByZoom(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Interpolates a list which starts with the interpolate function.
~QgsMapBoxGlStyleConverter()
QList< QgsMapLayer * > createSubLayers() const
Returns a list of new map layers corresponding to sublayers of the style, e.g.
Result
Result of conversion.
@ Success
Conversion was successful.
@ NoLayerList
No layer list was found in JSON input.
QgsMapBoxGlStyleConverter()
Constructor for QgsMapBoxGlStyleConverter.
static QImage retrieveSprite(const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize)
Retrieves the sprite image with the specified name, taken from the specified context.
static QString parseLabelStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops containing label values.
void parseLayers(const QVariantList &layers, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of layers from JSON.
static QgsProperty parseInterpolateColorByZoom(const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, QColor *defaultColor=nullptr)
Parses a color value which is interpolated by zoom range.
static QgsProperty parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity, QgsMapBoxGlStyleConversionContext *contextPtr=0)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
static QString retrieveSpriteAsBase64(const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &spriteSize, QString &spriteProperty, QString &spriteSizeProperty)
Retrieves the sprite image with the specified name, taken from the specified context as a base64 enco...
void parseSources(const QVariantMap &sources, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse list of sources from JSON.
static QColor parseColor(const QVariant &color, QgsMapBoxGlStyleConversionContext &context)
Parses a color in one of these supported formats:
static bool parseSymbolLayerAsRenderer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as a renderer.
static bool parseFillLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context, bool isBackgroundStyle=false)
Parses a fill layer.
static void parseSymbolLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, bool &hasRenderer, QgsVectorTileBasicLabelingStyle &labelingStyle, bool &hasLabeling, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as renderer or labeling.
static bool parseLineLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a line layer.
void parseRasterSource(const QVariantMap &source, const QString &name, QgsMapBoxGlStyleConversionContext *context=nullptr)
Parse a raster source from JSON.
static void colorAsHslaComponents(const QColor &color, int &hue, int &saturation, int &lightness, int &alpha)
Takes a QColor object and returns HSLA components in required format for QGIS color_hsla() expression...
static Qt::PenCapStyle parseCapStyle(const QString &style)
Converts a value to Qt::PenCapStyle enum from JSON value.
static QString parseStringStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, const QVariantMap &conversionMap, QString *defaultString=nullptr)
Parses a list of interpolation stops containing string values.
static QgsProperty parseMatchList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a match function value list.
static QgsProperty parseValueList(const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier=1, int maxOpacity=255, QColor *defaultColor=nullptr, double *defaultNumber=nullptr)
Parses and converts a value list (e.g.
static QString parseArrayStops(const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes numerical arrays from stops.
static QString parsePointStops(double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier=1)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate point/...
Encapsulates a MapBox GL style raster source.
Qgis::MapBoxGlStyleSourceType type() const override
Returns the source type.
QgsMapBoxGlStyleRasterSource(const QString &name)
Constructor for QgsMapBoxGlStyleRasterSource.
QgsRasterLayer * toRasterLayer() const
Returns a new raster layer representing the raster source, or nullptr if the source cannot be represe...
bool setFromJson(const QVariantMap &json, QgsMapBoxGlStyleConversionContext *context) override
Sets the source's state from a json map.
QStringList tiles() const
Returns the list of tile sources.
Encapsulates a MapBox GL style raster sub layer.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the layer's data defined properties.
QgsMapBoxGlStyleRasterSubLayer(const QString &id, const QString &source)
Constructor for QgsMapBoxGlStyleRasterSubLayer, with the given id and source.
Line symbol layer type which draws repeating marker symbols along a line feature.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
virtual void setSize(double size)
Sets the symbol size.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
void setAngle(double angle)
Sets the rotation angle for the marker.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
const QgsLabelObstacleSettings & obstacleSettings() const
Returns the label obstacle settings.
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
Qgis::LabelPlacement placement
Label placement mode.
Qgis::LabelQuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
Qgis::LabelMultiLineAlignment multilineAlign
Horizontal alignment of multi-line labels.
int priority
Label priority.
@ FontStyle
Font style name.
@ FontLetterSpacing
Letter spacing.
@ LinePlacementOptions
Line placement flags.
Qgis::RenderUnit offsetUnits
Units for offsets of label.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the label's property collection, used for data defined overrides.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
double dist
Distance from feature to the label.
Qgis::RenderUnit distUnits
Units the distance from feature to the label.
QString fieldName
Name of field (or an expression) to use for label text.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
QString expressionString() const
Returns the expression used for the property value.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
A class for filling symbols with a repeated raster image.
void setWidthUnit(const Qgis::RenderUnit unit)
Sets the units for the image's width.
void setWidth(const double width)
Sets the width for scaling the image used in the fill.
void setOpacity(double opacity)
Sets the opacity for the raster image used in the fill.
void setImageFilePath(const QString &imagePath)
Sets the path to the raster image used for the fill.
void setCoordinateMode(Qgis::SymbolCoordinateReference mode)
Set the coordinate mode for fill.
Represents a raster layer.
Line symbol layer type which draws line sections using a raster image file.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Raster marker symbol layer class.
void setOpacity(double opacity)
Set the marker opacity.
void setPath(const QString &path)
Set the marker raster image path.
@ RendererOpacity
Raster renderer global opacity.
void setBrushStyle(Qt::BrushStyle style)
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setStrokeWidth(double strokeWidth)
void setStrokeStyle(Qt::PenStyle strokeStyle)
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the fill's offset.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setOffset(QPointF offset)
Sets an offset by which polygons will be translated during rendering.
void setStrokeColor(const QColor &strokeColor) override
Sets the stroke color for the symbol layer.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
void setFillColor(const QColor &color) override
Sets the fill color for the symbol layer.
void setStrokeWidthUnit(Qgis::RenderUnit u)
Sets the unit for the width of the marker's stroke.
void setStrokeWidth(double w)
Sets the width of the marker's stroke.
void setStrokeColor(const QColor &color) override
Sets the marker's stroke color.
static QColor parseColor(const QString &colorStr, bool strictEval=false)
Attempts to parse a string as a color using a variety of common formats, including hex codes,...
@ PropertyFile
Filename, eg for svg files.
@ PropertyAngle
Symbol angle.
@ PropertyCustomDash
Custom dash pattern.
@ PropertyOpacity
Opacity.
@ PropertyOffset
Symbol offset.
@ PropertyStrokeWidth
Stroke width.
@ PropertyFillColor
Fill color.
@ PropertyName
Name, eg shape name for simple markers.
@ PropertyInterval
Line marker interval.
@ PropertyStrokeColor
Stroke color.
@ PropertyWidth
Symbol width.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
@ PropertyOpacity
Opacity.
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
Container for settings relating to a text background object.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
@ ShapeMarkerSymbol
Marker symbol.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the shape's size.
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
void setSize(QSizeF size)
Sets the size of the background shape.
void setColor(const QColor &color)
Sets the color for the buffer.
void setOpacity(double opacity)
Sets the buffer opacity.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QFont font() const
Returns the font used for rendering text.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
Configuration of a single style within QgsVectorTileBasicLabeling.
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit).
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit).
void setStyleName(const QString &name)
Sets human readable name of this style.
void setGeometryType(Qgis::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
void setLabelSettings(const QgsPalLayerSettings &settings)
Sets labeling configuration of this style.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
Basic labeling configuration for vector tile layers.
Definition of map rendering of a subset of vector tile data.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit).
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setSymbol(QgsSymbol *sym)
Sets symbol for rendering. Takes ownership of the symbol.
void setStyleName(const QString &name)
Sets human readable name of this style.
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit).
void setGeometryType(Qgis::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
The default vector tile renderer implementation.
Base class for labeling configuration classes for vector tile layers.
Abstract base class for all vector tile renderer implementations.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugError(str)
QList< QgsSymbolLayer * > QgsSymbolLayerList