41 #include <QRegularExpression>
51 if ( style.contains( QStringLiteral(
"layers" ) ) )
53 parseLayers( style.value( QStringLiteral(
"layers" ) ).toList(), context );
57 mError = QObject::tr(
"Could not find layers list in JSON" );
72 std::unique_ptr< QgsMapBoxGlStyleConversionContext > tmpContext;
75 tmpContext = std::make_unique< QgsMapBoxGlStyleConversionContext >();
76 context = tmpContext.get();
79 QList<QgsVectorTileBasicRendererStyle> rendererStyles;
80 QList<QgsVectorTileBasicLabelingStyle> labelingStyles;
83 bool hasRendererBackgroundStyle =
false;
85 for (
const QVariant &layer : layers )
87 const QVariantMap jsonLayer = layer.toMap();
89 const QString layerType = jsonLayer.value( QStringLiteral(
"type" ) ).toString();
90 if ( layerType == QLatin1String(
"background" ) )
92 hasRendererBackgroundStyle =
parseFillLayer( jsonLayer, rendererBackgroundStyle, *context,
true );
93 if ( hasRendererBackgroundStyle )
103 const QString styleId = jsonLayer.value( QStringLiteral(
"id" ) ).toString();
105 const QString layerName = jsonLayer.value( QStringLiteral(
"source-layer" ) ).toString();
107 const int minZoom = jsonLayer.value( QStringLiteral(
"minzoom" ), QStringLiteral(
"-1" ) ).toInt();
108 const int maxZoom = jsonLayer.value( QStringLiteral(
"maxzoom" ), QStringLiteral(
"-1" ) ).toInt();
110 const bool enabled = jsonLayer.value( QStringLiteral(
"visibility" ) ).toString() != QLatin1String(
"none" );
112 QString filterExpression;
113 if ( jsonLayer.contains( QStringLiteral(
"filter" ) ) )
115 filterExpression =
parseExpression( jsonLayer.value( QStringLiteral(
"filter" ) ).toList(), *context );
121 bool hasRendererStyle =
false;
122 bool hasLabelingStyle =
false;
123 if ( layerType == QLatin1String(
"fill" ) )
125 hasRendererStyle =
parseFillLayer( jsonLayer, rendererStyle, *context );
127 else if ( layerType == QLatin1String(
"line" ) )
129 hasRendererStyle =
parseLineLayer( jsonLayer, rendererStyle, *context );
131 else if ( layerType == QLatin1String(
"circle" ) )
135 else if ( layerType == QLatin1String(
"symbol" ) )
137 parseSymbolLayer( jsonLayer, rendererStyle, hasRendererStyle, labelingStyle, hasLabelingStyle, *context );
141 mWarnings << QObject::tr(
"%1: Skipping unknown layer type %2" ).arg( context->
layerId(), layerType );
146 if ( hasRendererStyle )
154 rendererStyles.append( rendererStyle );
157 if ( hasLabelingStyle )
165 labelingStyles.append( labelingStyle );
168 mWarnings.append( context->
warnings() );
172 if ( hasRendererBackgroundStyle )
173 rendererStyles.prepend( rendererBackgroundStyle );
175 mRenderer = std::make_unique< QgsVectorTileBasicRenderer >();
177 renderer->setStyles( rendererStyles );
179 mLabeling = std::make_unique< QgsVectorTileBasicLabeling >();
181 labeling->setStyles( labelingStyles );
186 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
188 context.
pushWarning( QObject::tr(
"%1: Layer has no paint property, skipping" ).arg( jsonLayer.value( QStringLiteral(
"id" ) ).toString() ) );
192 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
197 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsFillSymbol >() );
201 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) ) )
203 const QVariant jsonFillColor = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-color" ) : QStringLiteral(
"fill-color" ) );
204 switch ( jsonFillColor.type() )
211 case QVariant::StringList:
215 case QVariant::String:
216 fillColor =
parseColor( jsonFillColor.toString(), context );
229 fillColor = QColor( 0, 0, 0 );
232 QColor fillOutlineColor;
233 if ( !isBackgroundStyle )
235 if ( !jsonPaint.contains( QStringLiteral(
"fill-outline-color" ) ) )
237 if ( fillColor.isValid() )
238 fillOutlineColor = fillColor;
246 const QVariant jsonFillOutlineColor = jsonPaint.value( QStringLiteral(
"fill-outline-color" ) );
247 switch ( jsonFillOutlineColor.type() )
254 case QVariant::StringList:
258 case QVariant::String:
259 fillOutlineColor =
parseColor( jsonFillOutlineColor.toString(), context );
269 double fillOpacity = -1.0;
270 double rasterOpacity = -1.0;
271 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) ) )
273 const QVariant jsonFillOpacity = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-opacity" ) : QStringLiteral(
"fill-opacity" ) );
274 switch ( jsonFillOpacity.type() )
277 case QVariant::Double:
278 fillOpacity = jsonFillOpacity.toDouble();
279 rasterOpacity = fillOpacity;
296 case QVariant::StringList:
316 QPointF fillTranslate;
317 if ( jsonPaint.contains( QStringLiteral(
"fill-translate" ) ) )
319 const QVariant jsonFillTranslate = jsonPaint.value( QStringLiteral(
"fill-translate" ) );
320 switch ( jsonFillTranslate.type() )
328 case QVariant::StringList:
340 Q_ASSERT( fillSymbol );
343 symbol->setOutputUnit( context.
targetUnit() );
346 if ( !fillTranslate.isNull() )
352 if ( jsonPaint.contains( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) ) )
356 const QVariant fillPatternJson = jsonPaint.value( isBackgroundStyle ? QStringLiteral(
"background-pattern" ) : QStringLiteral(
"fill-pattern" ) );
359 fillColor = QColor();
360 fillOutlineColor = QColor();
367 QString spriteProperty, spriteSizeProperty;
368 const QString sprite =
retrieveSpriteAsBase64( fillPatternJson, context, spriteSize, spriteProperty, spriteSizeProperty );
369 if ( !sprite.isEmpty() )
374 rasterFill->
setWidth( spriteSize.width() );
378 if ( rasterOpacity >= 0 )
383 if ( !spriteProperty.isEmpty() )
390 symbol->appendSymbolLayer( rasterFill );
396 if ( fillOpacity != -1 )
398 symbol->setOpacity( fillOpacity );
401 if ( fillOutlineColor.isValid() )
410 if ( fillColor.isValid() )
426 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
428 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
432 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
433 if ( jsonPaint.contains( QStringLiteral(
"line-pattern" ) ) )
435 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
443 if ( jsonPaint.contains( QStringLiteral(
"line-color" ) ) )
445 const QVariant jsonLineColor = jsonPaint.
value( QStringLiteral(
"line-color" ) );
446 switch ( jsonLineColor.type() )
454 case QVariant::StringList:
459 case QVariant::String:
460 lineColor =
parseColor( jsonLineColor.toString(), context );
471 lineColor = QColor( 0, 0, 0 );
475 double lineWidth = 1.0;
477 if ( jsonPaint.contains( QStringLiteral(
"line-width" ) ) )
479 const QVariant jsonLineWidth = jsonPaint.
value( QStringLiteral(
"line-width" ) );
480 switch ( jsonLineWidth.type() )
483 case QVariant::Double:
494 case QVariant::StringList:
505 double lineOffset = 0.0;
506 if ( jsonPaint.contains( QStringLiteral(
"line-offset" ) ) )
508 const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral(
"line-offset" ) );
509 switch ( jsonLineOffset.type() )
512 case QVariant::Double:
522 case QVariant::StringList:
532 double lineOpacity = -1.0;
533 if ( jsonPaint.contains( QStringLiteral(
"line-opacity" ) ) )
535 const QVariant jsonLineOpacity = jsonPaint.value( QStringLiteral(
"line-opacity" ) );
536 switch ( jsonLineOpacity.type() )
539 case QVariant::Double:
540 lineOpacity = jsonLineOpacity.toDouble();
546 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
555 case QVariant::StringList:
558 context.
pushWarning( QObject::tr(
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
572 QVector< double > dashVector;
573 if ( jsonPaint.contains( QStringLiteral(
"line-dasharray" ) ) )
575 const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral(
"line-dasharray" ) );
576 switch ( jsonLineDashArray.type() )
580 QString arrayExpression;
583 arrayExpression = QStringLiteral(
"array_to_string(array_foreach(%1,@element * (%2)), ';')" )
584 .arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, 1 ),
589 arrayExpression = QStringLiteral(
"array_to_string(%1, ';')" ).arg(
parseArrayStops( jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList(), context, lineWidth ) );
593 const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral(
"stops" ) ).toList().first().toList().value( 1 ).toList();
594 for (
const QVariant &v : dashSource )
596 dashVector << v.toDouble() * lineWidth;
602 case QVariant::StringList:
606 QString arrayExpression = QStringLiteral(
"array_to_string(array_foreach(array(%1),@element * (%2)), ';')" )
607 .arg( jsonLineDashArray.toStringList().join(
',' ),
611 const QVariantList dashSource = jsonLineDashArray.toList();
612 for (
const QVariant &v : dashSource )
614 dashVector << v.toDouble() * lineWidth;
625 Qt::PenCapStyle penCapStyle = Qt::FlatCap;
626 Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
627 if ( jsonLayer.contains( QStringLiteral(
"layout" ) ) )
629 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
630 if ( jsonLayout.contains( QStringLiteral(
"line-cap" ) ) )
632 penCapStyle =
parseCapStyle( jsonLayout.value( QStringLiteral(
"line-cap" ) ).toString() );
634 if ( jsonLayout.contains( QStringLiteral(
"line-join" ) ) )
636 penJoinStyle =
parseJoinStyle( jsonLayout.value( QStringLiteral(
"line-join" ) ).toString() );
640 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
642 Q_ASSERT( lineSymbol );
645 symbol->setOutputUnit( context.
targetUnit() );
653 if ( lineOpacity != -1 )
655 symbol->setOpacity( lineOpacity );
657 if ( lineColor.isValid() )
661 if ( lineWidth != -1 )
665 if ( !dashVector.empty() )
678 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
680 context.
pushWarning( QObject::tr(
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
684 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
688 QColor circleFillColor;
689 if ( jsonPaint.contains( QStringLiteral(
"circle-color" ) ) )
691 const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral(
"circle-color" ) );
692 switch ( jsonCircleColor.type() )
699 case QVariant::StringList:
703 case QVariant::String:
704 circleFillColor =
parseColor( jsonCircleColor.toString(), context );
715 circleFillColor = QColor( 0, 0, 0 );
719 double circleDiameter = 10.0;
720 if ( jsonPaint.contains( QStringLiteral(
"circle-radius" ) ) )
722 const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral(
"circle-radius" ) );
723 switch ( jsonCircleRadius.type() )
726 case QVariant::Double:
736 case QVariant::StringList:
746 double circleOpacity = -1.0;
747 if ( jsonPaint.contains( QStringLiteral(
"circle-opacity" ) ) )
749 const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral(
"circle-opacity" ) );
750 switch ( jsonCircleOpacity.type() )
753 case QVariant::Double:
754 circleOpacity = jsonCircleOpacity.toDouble();
762 case QVariant::StringList:
771 if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
773 circleFillColor.setAlphaF( circleOpacity );
777 QColor circleStrokeColor;
778 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-color" ) ) )
780 const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral(
"circle-stroke-color" ) );
781 switch ( jsonCircleStrokeColor.type() )
788 case QVariant::StringList:
792 case QVariant::String:
793 circleStrokeColor =
parseColor( jsonCircleStrokeColor.toString(), context );
803 double circleStrokeWidth = -1.0;
804 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-width" ) ) )
806 const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral(
"circle-stroke-width" ) );
807 switch ( circleStrokeWidthJson.type() )
810 case QVariant::Double:
815 circleStrokeWidth = -1.0;
820 case QVariant::StringList:
830 double circleStrokeOpacity = -1.0;
831 if ( jsonPaint.contains( QStringLiteral(
"circle-stroke-opacity" ) ) )
833 const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral(
"circle-stroke-opacity" ) );
834 switch ( jsonCircleStrokeOpacity.type() )
837 case QVariant::Double:
838 circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
846 case QVariant::StringList:
855 if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
857 circleStrokeColor.setAlphaF( circleStrokeOpacity );
861 QPointF circleTranslate;
862 if ( jsonPaint.contains( QStringLiteral(
"circle-translate" ) ) )
864 const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral(
"circle-translate" ) );
865 switch ( jsonCircleTranslate.type() )
873 case QVariant::StringList:
884 std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
886 Q_ASSERT( markerSymbolLayer );
889 symbol->setOutputUnit( context.
targetUnit() );
890 symbol->setDataDefinedProperties( ddProperties );
892 if ( !circleTranslate.isNull() )
894 markerSymbolLayer->
setOffset( circleTranslate );
898 if ( circleFillColor.isValid() )
902 if ( circleDiameter != -1 )
904 markerSymbolLayer->
setSize( circleDiameter );
907 if ( circleStrokeColor.isValid() )
911 if ( circleStrokeWidth != -1 )
927 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
929 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
932 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
933 if ( !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
939 if ( !jsonLayer.contains( QStringLiteral(
"paint" ) ) )
941 context.
pushWarning( QObject::tr(
"%1: Style layer has no paint property, skipping" ).arg( context.
layerId() ) );
944 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
950 if ( jsonLayout.contains( QStringLiteral(
"text-size" ) ) )
952 const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral(
"text-size" ) );
953 switch ( jsonTextSize.type() )
956 case QVariant::Double:
967 case QVariant::StringList:
977 if ( textSizeProperty )
984 constexpr
double EM_TO_CHARS = 2.0;
986 double textMaxWidth = -1;
987 if ( jsonLayout.contains( QStringLiteral(
"text-max-width" ) ) )
989 const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral(
"text-max-width" ) );
990 switch ( jsonTextMaxWidth.type() )
993 case QVariant::Double:
994 textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
1001 case QVariant::List:
1002 case QVariant::StringList:
1014 textMaxWidth = 10 * EM_TO_CHARS;
1017 double textLetterSpacing = -1;
1018 if ( jsonLayout.contains( QStringLiteral(
"text-letter-spacing" ) ) )
1020 const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral(
"text-letter-spacing" ) );
1021 switch ( jsonTextLetterSpacing.type() )
1024 case QVariant::Double:
1025 textLetterSpacing = jsonTextLetterSpacing.toDouble();
1032 case QVariant::List:
1033 case QVariant::StringList:
1044 bool foundFont =
false;
1046 QString fontStyleName;
1048 if ( jsonLayout.contains( QStringLiteral(
"text-font" ) ) )
1050 auto splitFontFamily = [](
const QString & fontName, QString & family, QString & style ) ->
bool
1052 const QStringList textFontParts = fontName.split(
' ' );
1053 for (
int i = 1; i < textFontParts.size(); ++i )
1055 const QString candidateFontName = textFontParts.mid( 0, i ).join(
' ' );
1056 const QString candidateFontStyle = textFontParts.mid( i ).join(
' ' );
1059 family = candidateFontName;
1060 style = candidateFontStyle;
1065 if ( QFontDatabase().hasFamily( fontName ) )
1075 const QVariant jsonTextFont = jsonLayout.value( QStringLiteral(
"text-font" ) );
1076 if ( jsonTextFont.type() != QVariant::List && jsonTextFont.type() != QVariant::StringList && jsonTextFont.type() != QVariant::String
1077 && jsonTextFont.type() != QVariant::Map )
1083 switch ( jsonTextFont.type() )
1085 case QVariant::List:
1086 case QVariant::StringList:
1087 fontName = jsonTextFont.toList().value( 0 ).toString();
1090 case QVariant::String:
1091 fontName = jsonTextFont.toString();
1096 QString familyCaseString = QStringLiteral(
"CASE " );
1097 QString styleCaseString = QStringLiteral(
"CASE " );
1099 const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral(
"stops" ) ).toList();
1102 for (
int i = 0; i < stops.length() - 1; ++i )
1105 const QVariant bz = stops.value( i ).toList().value( 0 );
1106 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();
1107 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
1109 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1115 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
1116 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
1118 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
1123 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1125 familyCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1126 "THEN %3 " ).arg( bz.toString(),
1129 styleCaseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
1130 "THEN %3 " ).arg( bz.toString(),
1136 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1142 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();
1143 if ( splitFontFamily( bv, fontFamily, fontStyleName ) )
1150 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
1157 fontName = fontFamily;
1167 if ( splitFontFamily( fontName, fontFamily, fontStyleName ) )
1169 textFont = QFont( fontFamily );
1170 if ( !fontStyleName.isEmpty() )
1171 textFont.setStyleName( fontStyleName );
1181 fontName = QStringLiteral(
"Open Sans" );
1182 textFont = QFont( fontName );
1183 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1184 fontStyleName = QStringLiteral(
"Regular" );
1189 fontName = QStringLiteral(
"Arial Unicode MS" );
1190 textFont = QFont( fontName );
1191 textFont.setStyleName( QStringLiteral(
"Regular" ) );
1192 fontStyleName = QStringLiteral(
"Regular" );
1197 fontName = QStringLiteral(
"Open Sans, Arial Unicode MS" );
1200 if ( !foundFont && !fontName.isEmpty() )
1202 context.
pushWarning( QObject::tr(
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
1207 if ( jsonPaint.contains( QStringLiteral(
"text-color" ) ) )
1209 const QVariant jsonTextColor = jsonPaint.value( QStringLiteral(
"text-color" ) );
1210 switch ( jsonTextColor.type() )
1216 case QVariant::List:
1217 case QVariant::StringList:
1221 case QVariant::String:
1222 textColor =
parseColor( jsonTextColor.toString(), context );
1233 textColor = QColor( 0, 0, 0 );
1238 if ( jsonPaint.contains( QStringLiteral(
"text-halo-color" ) ) )
1240 const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral(
"text-halo-color" ) );
1241 switch ( jsonBufferColor.type() )
1247 case QVariant::List:
1248 case QVariant::StringList:
1252 case QVariant::String:
1253 bufferColor =
parseColor( jsonBufferColor.toString(), context );
1262 double bufferSize = 0.0;
1266 constexpr
double BUFFER_SIZE_SCALE = 2.0;
1267 if ( jsonPaint.contains( QStringLiteral(
"text-halo-width" ) ) )
1269 const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral(
"text-halo-width" ) );
1270 switch ( jsonHaloWidth.type() )
1273 case QVariant::Double:
1282 case QVariant::List:
1283 case QVariant::StringList:
1294 double haloBlurSize = 0;
1295 if ( jsonPaint.contains( QStringLiteral(
"text-halo-blur" ) ) )
1297 const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral(
"text-halo-blur" ) );
1298 switch ( jsonTextHaloBlur.type() )
1301 case QVariant::Double:
1315 if ( textColor.isValid() )
1317 if ( textSize >= 0 )
1322 if ( !fontStyleName.isEmpty() )
1325 if ( textLetterSpacing > 0 )
1327 QFont f = format.
font();
1328 f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
1332 if ( bufferSize > 0 )
1339 if ( haloBlurSize > 0 )
1355 if ( textMaxWidth > 0 )
1362 auto processLabelField = [](
const QString & string,
bool & isExpression )->QString
1366 const QRegularExpression singleFieldRx( QStringLiteral(
"^{([^}]+)}$" ) );
1367 const QRegularExpressionMatch match = singleFieldRx.match(
string );
1368 if ( match.hasMatch() )
1370 isExpression =
false;
1371 return match.captured( 1 );
1374 const QRegularExpression multiFieldRx( QStringLiteral(
"(?={[^}]+})" ) );
1375 const QStringList parts =
string.split( multiFieldRx );
1376 if ( parts.size() > 1 )
1378 isExpression =
true;
1381 for (
const QString &part : parts )
1383 if ( part.isEmpty() )
1386 if ( !part.contains(
'{' ) )
1393 const QStringList split = part.split(
'}' );
1395 if ( !split.at( 1 ).isEmpty() )
1398 return QStringLiteral(
"concat(%1)" ).arg( res.join(
',' ) );
1402 isExpression =
false;
1407 if ( jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1409 const QVariant jsonTextField = jsonLayout.value( QStringLiteral(
"text-field" ) );
1410 switch ( jsonTextField.type() )
1412 case QVariant::String:
1414 labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
1418 case QVariant::List:
1419 case QVariant::StringList:
1421 const QVariantList textFieldList = jsonTextField.toList();
1429 if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String(
"format" ) )
1432 for (
int i = 1; i < textFieldList.size(); ++i )
1434 bool isExpression =
false;
1435 const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
1436 if ( !isExpression )
1443 labelSettings.
fieldName = QStringLiteral(
"concat(%1)" ).arg( parts.join(
',' ) );
1464 if ( jsonLayout.contains( QStringLiteral(
"text-transform" ) ) )
1466 const QString textTransform = jsonLayout.value( QStringLiteral(
"text-transform" ) ).toString();
1467 if ( textTransform == QLatin1String(
"uppercase" ) )
1471 else if ( textTransform == QLatin1String(
"lowercase" ) )
1480 if ( jsonLayout.contains( QStringLiteral(
"symbol-placement" ) ) )
1482 const QString symbolPlacement = jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString();
1483 if ( symbolPlacement == QLatin1String(
"line" ) )
1489 if ( jsonLayout.contains( QStringLiteral(
"text-rotation-alignment" ) ) )
1491 const QString textRotationAlignment = jsonLayout.value( QStringLiteral(
"text-rotation-alignment" ) ).toString();
1492 if ( textRotationAlignment == QLatin1String(
"viewport" ) )
1502 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1504 const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral(
"text-offset" ) );
1507 switch ( jsonTextOffset.type() )
1510 textOffsetProperty =
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
1511 if ( !textSizeProperty )
1522 case QVariant::List:
1523 case QVariant::StringList:
1524 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1525 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1533 if ( !textOffset.isNull() )
1536 labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
1538 if ( textSizeProperty && !textOffsetProperty )
1545 if ( textOffset.isNull() )
1553 if ( jsonLayout.contains( QStringLiteral(
"text-justify" ) ) )
1555 const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral(
"text-justify" ) );
1558 QString textAlign = QStringLiteral(
"center" );
1560 const QVariantMap conversionMap
1562 { QStringLiteral(
"left" ), QStringLiteral(
"left" ) },
1563 { QStringLiteral(
"center" ), QStringLiteral(
"center" ) },
1564 { QStringLiteral(
"right" ), QStringLiteral(
"right" ) },
1565 { QStringLiteral(
"auto" ), QStringLiteral(
"follow" ) }
1568 switch ( jsonTextJustify.type() )
1570 case QVariant::String:
1571 textAlign = jsonTextJustify.toString();
1574 case QVariant::List:
1587 if ( textAlign == QLatin1String(
"left" ) )
1589 else if ( textAlign == QLatin1String(
"right" ) )
1591 else if ( textAlign == QLatin1String(
"center" ) )
1593 else if ( textAlign == QLatin1String(
"follow" ) )
1603 if ( jsonLayout.contains( QStringLiteral(
"text-anchor" ) ) )
1605 const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral(
"text-anchor" ) );
1608 const QVariantMap conversionMap
1610 { QStringLiteral(
"center" ), 4 },
1611 { QStringLiteral(
"left" ), 5 },
1612 { QStringLiteral(
"right" ), 3 },
1613 { QStringLiteral(
"top" ), 7 },
1614 { QStringLiteral(
"bottom" ), 1 },
1615 { QStringLiteral(
"top-left" ), 8 },
1616 { QStringLiteral(
"top-right" ), 6 },
1617 { QStringLiteral(
"bottom-left" ), 2 },
1618 { QStringLiteral(
"bottom-right" ), 0 },
1621 switch ( jsonTextAnchor.type() )
1623 case QVariant::String:
1624 textAnchor = jsonTextAnchor.toString();
1627 case QVariant::List:
1640 if ( textAnchor == QLatin1String(
"center" ) )
1642 else if ( textAnchor == QLatin1String(
"left" ) )
1644 else if ( textAnchor == QLatin1String(
"right" ) )
1646 else if ( textAnchor == QLatin1String(
"top" ) )
1648 else if ( textAnchor == QLatin1String(
"bottom" ) )
1650 else if ( textAnchor == QLatin1String(
"top-left" ) )
1652 else if ( textAnchor == QLatin1String(
"top-right" ) )
1654 else if ( textAnchor == QLatin1String(
"bottom-left" ) )
1656 else if ( textAnchor == QLatin1String(
"bottom-right" ) )
1661 if ( jsonLayout.contains( QStringLiteral(
"text-offset" ) ) )
1663 const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral(
"text-offset" ) );
1666 switch ( jsonTextOffset.type() )
1672 case QVariant::List:
1673 case QVariant::StringList:
1674 textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
1675 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
1683 if ( !textOffset.isNull() )
1686 labelSettings.
xOffset = textOffset.x();
1687 labelSettings.
yOffset = textOffset.y();
1692 if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) &&
1696 QString spriteProperty, spriteSizeProperty;
1697 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1698 if ( !sprite.isEmpty() )
1701 markerLayer->
setPath( sprite );
1702 markerLayer->
setSize( spriteSize.width() );
1705 if ( !spriteProperty.isEmpty() )
1717 backgroundSettings.
setSize( spriteSize );
1725 if ( textSize >= 0 )
1748 if ( !jsonLayer.contains( QStringLiteral(
"layout" ) ) )
1750 context.
pushWarning( QObject::tr(
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
1753 const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral(
"layout" ) ).toMap();
1755 if ( jsonLayout.value( QStringLiteral(
"symbol-placement" ) ).toString() == QLatin1String(
"line" ) && !jsonLayout.contains( QStringLiteral(
"text-field" ) ) )
1759 double spacing = -1.0;
1760 if ( jsonLayout.contains( QStringLiteral(
"symbol-spacing" ) ) )
1762 const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral(
"symbol-spacing" ) );
1763 switch ( jsonSpacing.type() )
1766 case QVariant::Double:
1774 case QVariant::List:
1775 case QVariant::StringList:
1790 bool rotateMarkers =
true;
1791 if ( jsonLayout.contains( QStringLiteral(
"icon-rotation-alignment" ) ) )
1793 const QString alignment = jsonLayout.value( QStringLiteral(
"icon-rotation-alignment" ) ).toString();
1794 if ( alignment == QLatin1String(
"map" ) || alignment == QLatin1String(
"auto" ) )
1796 rotateMarkers =
true;
1798 else if ( alignment == QLatin1String(
"viewport" ) )
1800 rotateMarkers =
false;
1805 double rotation = 0.0;
1806 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
1808 const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral(
"icon-rotate" ) );
1809 switch ( jsonIconRotate.type() )
1812 case QVariant::Double:
1813 rotation = jsonIconRotate.toDouble();
1820 case QVariant::List:
1821 case QVariant::StringList:
1842 QString spriteProperty, spriteSizeProperty;
1843 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1844 if ( !sprite.isNull() )
1846 markerLayer->
setPath( sprite );
1847 markerLayer->
setSize( spriteSize.width() );
1850 if ( !spriteProperty.isEmpty() )
1857 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1859 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
1862 switch ( jsonIconSize.type() )
1865 case QVariant::Double:
1867 size = jsonIconSize.toDouble();
1868 if ( !spriteSizeProperty.isEmpty() )
1871 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
1880 case QVariant::List:
1881 case QVariant::StringList:
1886 markerLayer->
setSize( size * spriteSize.width() );
1889 if ( !spriteSizeProperty.isEmpty() )
1906 std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >(
QgsSymbolLayerList() << lineSymbol );
1909 symbol->setOutputUnit( context.
targetUnit() );
1913 rendererStyle.
setSymbol( symbol.release() );
1916 else if ( jsonLayout.contains( QStringLiteral(
"icon-image" ) ) )
1918 const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral(
"paint" ) ).toMap();
1921 QString spriteProperty, spriteSizeProperty;
1922 const QString sprite =
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral(
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
1923 if ( !sprite.isEmpty() )
1926 rasterMarker->
setPath( sprite );
1927 rasterMarker->
setSize( spriteSize.width() );
1931 if ( !spriteProperty.isEmpty() )
1937 if ( jsonLayout.contains( QStringLiteral(
"icon-size" ) ) )
1939 const QVariant jsonIconSize = jsonLayout.value( QStringLiteral(
"icon-size" ) );
1942 switch ( jsonIconSize.type() )
1945 case QVariant::Double:
1947 size = jsonIconSize.toDouble();
1948 if ( !spriteSizeProperty.isEmpty() )
1951 QgsProperty::fromExpression( QStringLiteral(
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
1960 case QVariant::List:
1961 case QVariant::StringList:
1966 rasterMarker->
setSize( size * spriteSize.width() );
1969 if ( !spriteSizeProperty.isEmpty() )
1982 double rotation = 0.0;
1983 if ( jsonLayout.contains( QStringLiteral(
"icon-rotate" ) ) )
1985 const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral(
"icon-rotate" ) );
1986 switch ( jsonIconRotate.type() )
1989 case QVariant::Double:
1990 rotation = jsonIconRotate.toDouble();
1997 case QVariant::List:
1998 case QVariant::StringList:
2008 double iconOpacity = -1.0;
2009 if ( jsonPaint.contains( QStringLiteral(
"icon-opacity" ) ) )
2011 const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral(
"icon-opacity" ) );
2012 switch ( jsonIconOpacity.type() )
2015 case QVariant::Double:
2016 iconOpacity = jsonIconOpacity.toDouble();
2023 case QVariant::List:
2024 case QVariant::StringList:
2035 rasterMarker->
setAngle( rotation );
2036 if ( iconOpacity >= 0 )
2040 rendererStyle.
setSymbol( markerSymbol );
2051 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2052 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2053 if ( stops.empty() )
2056 QString caseString = QStringLiteral(
"CASE " );
2057 const QString colorComponent(
"color_part(%1,'%2')" );
2059 for (
int i = 0; i < stops.length() - 1; ++i )
2062 const QString bz = stops.at( i ).toList().value( 0 ).toString();
2064 const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
2066 const QVariant bcVariant = stops.at( i ).toList().value( 1 );
2067 const QVariant tcVariant = stops.at( i + 1 ).toList().value( 1 );
2069 const QColor bottomColor =
parseColor( bcVariant.toString(), context );
2070 const QColor topColor =
parseColor( tcVariant.toString(), context );
2072 if ( i == 0 && bottomColor.isValid() )
2079 caseString += QStringLiteral(
"WHEN @vector_tile_zoom < %1 THEN color_hsla(%2, %3, %4, %5) " )
2080 .arg( bz ).arg( bcHue ).arg( bcSat ).arg( bcLight ).arg( bcAlpha );
2083 if ( bottomColor.isValid() && topColor.isValid() )
2095 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2096 "%3, %4, %5, %6) " ).arg( bz, tz,
2107 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla("
2108 "%3, %4, %5, %6) " ).arg( bz, tz,
2109 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_hue" ), colorComponent.arg( topColorExpr ).arg(
"hsl_hue" ), base, 1, &context ),
2110 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"hsl_saturation" ), colorComponent.arg( topColorExpr ).arg(
"hsl_saturation" ), base, 1, &context ),
2111 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"lightness" ), colorComponent.arg( topColorExpr ).arg(
"lightness" ), base, 1, &context ),
2112 interpolateExpression( bz.toDouble(), tz.toDouble(), colorComponent.arg( bottomColorExpr ).arg(
"alpha" ), colorComponent.arg( topColorExpr ).arg(
"alpha" ), base, 1, &context ) );
2117 const QString tz = stops.last().toList().value( 0 ).toString();
2118 const QVariant tcVariant = stops.last().toList().value( 1 );
2119 const QColor topColor =
parseColor( stops.last().toList().value( 1 ), context );
2120 if ( topColor.isValid() )
2127 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2128 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz ).arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
2134 caseString += QStringLiteral(
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) "
2135 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
2136 .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" ) );
2139 if ( !stops.empty() && defaultColor )
2140 *defaultColor =
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
2147 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2148 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2149 if ( stops.empty() )
2152 QString scaleExpression;
2153 if ( stops.size() <= 2 )
2156 stops.last().toList().value( 0 ).toDouble(),
2157 stops.value( 0 ).toList().value( 1 ),
2158 stops.last().toList().value( 1 ), base, multiplier, &context );
2162 scaleExpression =
parseStops( base, stops, multiplier, context );
2165 if ( !stops.empty() && defaultNumber )
2166 *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
2176 context = *contextPtr;
2178 const double base = json.value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2179 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2180 if ( stops.empty() )
2183 QString scaleExpression;
2184 if ( stops.length() <= 2 )
2186 const QVariant bv = stops.value( 0 ).toList().value( 1 );
2187 const QVariant tv = stops.last().toList().value( 1 );
2188 double bottom = 0.0;
2190 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2191 scaleExpression = QStringLiteral(
"set_color_part(@symbol_color, 'alpha', %1)" )
2193 stops.last().toList().value( 0 ).toDouble(),
2194 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2195 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ), base, 1, &context ) );
2206 QString caseString = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
2207 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
2208 .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
2210 for (
int i = 0; i < stops.size() - 1; ++i )
2212 const QVariant bv = stops.value( i ).toList().value( 1 );
2213 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2214 double bottom = 0.0;
2216 const bool numeric = numericArgumentsOnly( bv, tv, bottom, top );
2218 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
2219 "THEN set_color_part(@symbol_color, 'alpha', %3)" )
2220 .arg( stops.value( i ).toList().value( 0 ).toString(),
2221 stops.value( i + 1 ).toList().value( 0 ).toString(),
2223 stops.value( i + 1 ).toList().value( 0 ).toDouble(),
2224 numeric ? QString::number( bottom * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( bv, context ) ).arg( maxOpacity ),
2225 numeric ? QString::number( top * maxOpacity ) : QString(
"(%1) * %2" ).arg( parseValue( tv, context ) ).arg( maxOpacity ),
2226 base, 1, &context ) );
2229 caseString += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
2230 "THEN set_color_part(@symbol_color, 'alpha', %2) END" )
2231 .arg( stops.last().toList().value( 0 ).toString() )
2232 .arg( stops.last().toList().value( 1 ).toDouble() * maxOpacity );
2238 const double base = json.
value( QStringLiteral(
"base" ), QStringLiteral(
"1" ) ).toDouble();
2239 const QVariantList stops = json.value( QStringLiteral(
"stops" ) ).toList();
2240 if ( stops.empty() )
2243 QString scaleExpression;
2244 if ( stops.size() <= 2 )
2246 scaleExpression = QStringLiteral(
"array(%1,%2)" ).arg(
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
2247 stops.last().toList().value( 0 ).toDouble(),
2248 stops.value( 0 ).toList().value( 1 ).toList().value( 0 ),
2249 stops.last().toList().value( 1 ).toList().value( 0 ), base, multiplier, &context ),
2251 stops.last().toList().value( 0 ).toDouble(),
2252 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ),
2253 stops.last().toList().value( 1 ).toList().value( 1 ), base, multiplier, &context )
2258 scaleExpression =
parsePointStops( base, stops, context, multiplier );
2261 if ( !stops.empty() && defaultPoint )
2262 *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
2263 stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
2269 const QVariantMap &conversionMap, QString *defaultString )
2271 const QVariantList stops = json.
value( QStringLiteral(
"stops" ) ).toList();
2272 if ( stops.empty() )
2275 const QString scaleExpression =
parseStringStops( stops, context, conversionMap, defaultString );
2282 QString caseString = QStringLiteral(
"CASE " );
2284 for (
int i = 0; i < stops.length() - 1; ++i )
2287 const QVariant bz = stops.value( i ).toList().value( 0 );
2288 const QVariant bv = stops.value( i ).toList().value( 1 );
2289 if ( bv.type() != QVariant::List && bv.type() != QVariant::StringList )
2296 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2297 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2298 if ( tv.type() != QVariant::List && tv.type() != QVariant::StringList )
2304 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2305 "THEN array(%3,%4)" ).arg( bz.toString(),
2307 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ), tv.toList().value( 0 ), base, multiplier, &context ),
2308 interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ), tv.toList().value( 1 ), base, multiplier, &context ) );
2310 caseString += QLatin1String(
"END" );
2316 if ( stops.length() < 2 )
2319 QString caseString = QStringLiteral(
"CASE " );
2321 for (
int i = 0; i < stops.length() - 1; ++i )
2324 const QVariant bz = stops.value( i ).toList().value( 0 );
2325 const QList<QVariant> bv = stops.value( i ).toList().value( 1 ).toList();
2328 for (
const QVariant &value : bv )
2330 const double number = value.toDouble( &ok );
2332 bl << QString::number( number * multiplier );
2336 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2337 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2338 "THEN array(%3) " ).arg( bz.toString(),
2342 const QVariant lz = stops.value( stops.length() - 1 ).toList().value( 0 );
2343 const QList<QVariant> lv = stops.value( stops.length() - 1 ).toList().value( 1 ).toList();
2346 for (
const QVariant &value : lv )
2348 const double number = value.toDouble( &ok );
2350 ll << QString::number( number * multiplier );
2352 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2353 "THEN array(%2) " ).arg( lz.toString(),
2355 caseString += QLatin1String(
"END" );
2361 QString caseString = QStringLiteral(
"CASE " );
2363 for (
int i = 0; i < stops.length() - 1; ++i )
2366 const QVariant bz = stops.value( i ).toList().value( 0 );
2367 const QVariant bv = stops.value( i ).toList().value( 1 );
2368 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2370 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2375 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2376 const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
2377 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2379 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2383 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2384 "THEN %3 " ).arg( bz.toString(),
2389 const QVariant z = stops.last().toList().value( 0 );
2390 const QVariant v = stops.last().toList().value( 1 );
2391 QString vStr = v.toString();
2392 if ( ( QMetaType::Type )v.type() == QMetaType::QVariantList )
2395 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2396 "THEN ( ( %2 ) * %3 ) END" ).arg( z.toString() ).arg( vStr ).arg( multiplier );
2400 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 "
2401 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
2409 QString caseString = QStringLiteral(
"CASE " );
2411 for (
int i = 0; i < stops.length() - 1; ++i )
2414 const QVariant bz = stops.value( i ).toList().value( 0 );
2415 const QString bv = stops.value( i ).toList().value( 1 ).toString();
2416 if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
2418 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2423 const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
2424 if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
2426 context.
pushWarning( QObject::tr(
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
2430 caseString += QStringLiteral(
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 "
2431 "THEN %3 " ).arg( bz.toString(),
2435 caseString += QStringLiteral(
"ELSE %1 END" ).arg(
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
2436 stops.constLast().toList().value( 1 ) ) ) );
2437 if ( defaultString )
2438 *defaultString = stops.constLast().toList().value( 1 ).toString();
2444 const QString method = json.
value( 0 ).toString();
2445 if ( method == QLatin1String(
"interpolate" ) )
2449 else if ( method == QLatin1String(
"match" ) )
2451 return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
2461 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
2462 if ( attribute.isEmpty() )
2464 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
2468 QString caseString = QStringLiteral(
"CASE " );
2470 for (
int i = 2; i < json.length() - 1; i += 2 )
2472 const QVariantList keys = json.value( i ).toList();
2474 QStringList matchString;
2475 for (
const QVariant &key : keys )
2480 const QVariant value = json.value( i + 1 );
2482 QString valueString;
2487 const QColor color =
parseColor( value, context );
2494 const double v = value.toDouble() * multiplier;
2495 valueString = QString::number( v );
2501 const double v = value.toDouble() * maxOpacity;
2502 valueString = QString::number( v );
2508 valueString = QStringLiteral(
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
2509 value.toList().value( 0 ).toDouble() * multiplier );
2515 caseString += QStringLiteral(
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
2516 matchString.join(
',' ), valueString );
2525 const QColor color =
parseColor( json.constLast(), context );
2527 *defaultColor = color;
2535 const double v = json.constLast().toDouble() * multiplier;
2536 if ( defaultNumber )
2538 elseValue = QString::number( v );
2544 const double v = json.constLast().toDouble() * maxOpacity;
2545 if ( defaultNumber )
2547 elseValue = QString::number( v );
2553 elseValue = QStringLiteral(
"array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
2554 json.constLast().toList().value( 0 ).toDouble() * multiplier );
2560 caseString += QStringLiteral(
"ELSE %1 END" ).arg( elseValue );
2566 if ( json.value( 0 ).toString() != QLatin1String(
"interpolate" ) )
2568 context.
pushWarning( QObject::tr(
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
2573 const QString technique = json.value( 1 ).toList().value( 0 ).toString();
2574 if ( technique == QLatin1String(
"linear" ) )
2576 else if ( technique == QLatin1String(
"exponential" ) )
2577 base = json.value( 1 ).toList(). value( 1 ).toDouble();
2578 else if ( technique == QLatin1String(
"cubic-bezier" ) )
2580 context.
pushWarning( QObject::tr(
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
2585 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
2589 if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String(
"zoom" ) )
2591 context.
pushWarning( QObject::tr(
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
2597 for (
int i = 3; i < json.length(); i += 2 )
2599 stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ) );
2603 props.insert( QStringLiteral(
"stops" ), stops );
2604 props.insert( QStringLiteral(
"base" ), base );
2607 case PropertyType::Color:
2610 case PropertyType::Numeric:
2613 case PropertyType::Opacity:
2616 case PropertyType::Point:
2624 if ( ( QMetaType::Type )colorExpression.type() == QMetaType::QVariantList )
2628 return parseValue( colorExpression, context,
true );
2633 if ( color.type() != QVariant::String )
2635 context.
pushWarning( QObject::tr(
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
2644 hue = std::max( 0, color.hslHue() );
2645 saturation = color.hslSaturation() / 255.0 * 100;
2646 lightness = color.lightness() / 255.0 * 100;
2647 alpha = color.alpha();
2655 context = *contextPtr;
2659 if ( valueMin.canConvert( QMetaType::Double ) && valueMax.canConvert( QMetaType::Double ) )
2661 bool minDoubleOk =
true;
2662 const double min = valueMin.toDouble( &minDoubleOk );
2663 bool maxDoubleOk =
true;
2664 const double max = valueMax.toDouble( &maxDoubleOk );
2665 if ( minDoubleOk && maxDoubleOk &&
qgsDoubleNear( min, max ) )
2667 return QString::number( min * multiplier );
2671 QString minValueExpr = valueMin.toString();
2672 QString maxValueExpr = valueMax.toString();
2673 if ( ( QMetaType::Type )valueMin.type() == QMetaType::QVariantList )
2677 if ( ( QMetaType::Type )valueMax.type() == QMetaType::QVariantList )
2682 if ( minValueExpr == maxValueExpr )
2684 return minValueExpr;
2690 expression = QStringLiteral(
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin )
2692 .arg( minValueExpr )
2693 .arg( maxValueExpr );
2697 expression = QStringLiteral(
"scale_exp(@vector_tile_zoom,%1,%2,%3,%4,%5)" ).arg( zoomMin )
2699 .arg( minValueExpr )
2700 .arg( maxValueExpr )
2704 if ( multiplier != 1 )
2705 return QStringLiteral(
"%1 * %2" ).arg( expression ).arg( multiplier );
2712 if ( style == QLatin1String(
"round" ) )
2713 return Qt::RoundCap;
2714 else if ( style == QLatin1String(
"square" ) )
2715 return Qt::SquareCap;
2722 if ( style == QLatin1String(
"bevel" ) )
2723 return Qt::BevelJoin;
2724 else if ( style == QLatin1String(
"round" ) )
2725 return Qt::RoundJoin;
2727 return Qt::MiterJoin;
2732 QString op = expression.value( 0 ).toString();
2733 if ( op == QLatin1String(
"%" ) && expression.size() >= 3 )
2735 return QStringLiteral(
"%1 %2 %3" ).arg( parseValue( expression.value( 1 ), context ) ).arg( op ).arg( parseValue( expression.value( 2 ), context ) );
2737 else if ( op == QLatin1String(
"to-number" ) )
2739 return QStringLiteral(
"to_real(%1)" ).arg( parseValue( expression.value( 1 ), context ) );
2741 if ( op == QLatin1String(
"literal" ) )
2743 return expression.value( 1 ).toString();
2745 else if ( op == QLatin1String(
"all" )
2746 || op == QLatin1String(
"any" )
2747 || op == QLatin1String(
"none" ) )
2750 for (
int i = 1; i < expression.size(); ++i )
2752 const QString part = parseValue( expression.at( i ), context );
2753 if ( part.isEmpty() )
2755 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2761 if ( op == QLatin1String(
"none" ) )
2762 return QStringLiteral(
"NOT (%1)" ).arg( parts.join( QLatin1String(
") AND NOT (" ) ) );
2764 QString operatorString;
2765 if ( op == QLatin1String(
"all" ) )
2766 operatorString = QStringLiteral(
") AND (" );
2767 else if ( op == QLatin1String(
"any" ) )
2768 operatorString = QStringLiteral(
") OR (" );
2770 return QStringLiteral(
"(%1)" ).arg( parts.join( operatorString ) );
2772 else if ( op ==
'!' )
2775 QVariantList contraJsonExpr = expression.value( 1 ).toList();
2776 contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
2778 return parseKey( contraJsonExpr, context );
2780 else if ( op == QLatin1String(
"==" )
2781 || op == QLatin1String(
"!=" )
2782 || op == QLatin1String(
">=" )
2784 || op == QLatin1String(
"<=" )
2788 if ( op == QLatin1String(
"==" ) )
2789 op = QStringLiteral(
"IS" );
2790 else if ( op == QLatin1String(
"!=" ) )
2791 op = QStringLiteral(
"IS NOT" );
2792 return QStringLiteral(
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ), context ),
2793 op, parseValue( expression.value( 2 ), context ) );
2795 else if ( op == QLatin1String(
"has" ) )
2797 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NOT NULL" );
2799 else if ( op == QLatin1String(
"!has" ) )
2801 return parseKey( expression.value( 1 ), context ) + QStringLiteral(
" IS NULL" );
2803 else if ( op == QLatin1String(
"in" ) || op == QLatin1String(
"!in" ) )
2805 const QString key = parseKey( expression.value( 1 ), context );
2807 for (
int i = 2; i < expression.size(); ++i )
2809 const QString part = parseValue( expression.at( i ), context );
2810 if ( part.isEmpty() )
2812 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2817 if ( op == QLatin1String(
"in" ) )
2818 return QStringLiteral(
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String(
", " ) ) );
2820 return QStringLiteral(
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String(
", " ) ) );
2822 else if ( op == QLatin1String(
"get" ) )
2824 return parseKey( expression.value( 1 ), context );
2826 else if ( op == QLatin1String(
"match" ) )
2828 const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
2830 if ( expression.size() == 5
2831 && expression.at( 3 ).type() == QVariant::Bool && expression.at( 3 ).toBool() ==
true
2832 && expression.at( 4 ).type() == QVariant::Bool && expression.at( 4 ).toBool() ==
false )
2835 if ( expression.at( 2 ).type() == QVariant::List || expression.at( 2 ).type() == QVariant::StringList )
2838 for (
const QVariant &p : expression.at( 2 ).toList() )
2840 parts << parseValue( p, context );
2843 if ( parts.size() > 1 )
2848 else if ( expression.at( 2 ).type() == QVariant::String || expression.at( 2 ).type() == QVariant::Int
2849 || expression.at( 2 ).type() == QVariant::Double )
2855 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2861 QString caseString = QStringLiteral(
"CASE " );
2862 for (
int i = 2; i < expression.size() - 2; i += 2 )
2864 if ( expression.at( i ).type() == QVariant::List || expression.at( i ).type() == QVariant::StringList )
2867 for (
const QVariant &p : expression.at( i ).toList() )
2872 if ( parts.size() > 1 )
2877 else if ( expression.at( i ).type() == QVariant::String || expression.at( i ).type() == QVariant::Int
2878 || expression.at( i ).type() == QVariant::Double )
2883 caseString += QStringLiteral(
"THEN %1 " ).arg( parseValue( expression.at( i + 1 ), context, colorExpected ) );
2885 caseString += QStringLiteral(
"ELSE %1 END" ).arg( parseValue( expression.last(), context, colorExpected ) );
2889 else if ( op == QLatin1String(
"to-string" ) )
2891 return QStringLiteral(
"to_string(%1)" ).arg(
parseExpression( expression.value( 1 ).toList(), context ) );
2895 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
2904 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
2908 const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
2909 if ( spriteDefinition.size() == 0 )
2911 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
2915 const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral(
"x" ) ).toInt(),
2916 spriteDefinition.value( QStringLiteral(
"y" ) ).toInt(),
2917 spriteDefinition.value( QStringLiteral(
"width" ) ).toInt(),
2918 spriteDefinition.value( QStringLiteral(
"height" ) ).toInt() );
2919 if ( sprite.isNull() )
2921 context.
pushWarning( QObject::tr(
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
2925 spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral(
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
2933 auto prepareBase64 = [](
const QImage & sprite )
2936 if ( !sprite.isNull() )
2939 QBuffer buffer( &blob );
2940 buffer.open( QIODevice::WriteOnly );
2941 sprite.save( &buffer,
"PNG" );
2943 const QByteArray encoded = blob.toBase64();
2944 path = QString( encoded );
2945 path.prepend( QLatin1String(
"base64:" ) );
2950 switch ( value.type() )
2952 case QVariant::String:
2954 QString spriteName = value.toString();
2955 const QRegularExpression fieldNameMatch( QStringLiteral(
"{([^}]+)}" ) );
2956 QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
2957 if ( match.hasMatch() )
2959 const QString fieldName = match.captured( 1 );
2960 spriteProperty = QStringLiteral(
"CASE" );
2961 spriteSizeProperty = QStringLiteral(
"CASE" );
2963 spriteName.replace(
"(", QLatin1String(
"\\(" ) );
2964 spriteName.replace(
")", QLatin1String(
"\\)" ) );
2965 spriteName.replace( fieldNameMatch, QStringLiteral(
"([^\\/\\\\]+)" ) );
2966 const QRegularExpression fieldValueMatch( spriteName );
2968 for (
const QString &name : spriteNames )
2970 match = fieldValueMatch.match( name );
2971 if ( match.hasMatch() )
2975 const QString fieldValue = match.captured( 1 );
2977 path = prepareBase64( sprite );
2978 if ( spritePath.isEmpty() && !path.isEmpty() )
2984 spriteProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN '%3'" )
2985 .arg( fieldName, fieldValue, path );
2986 spriteSizeProperty += QStringLiteral(
" WHEN \"%1\" = '%2' THEN %3" )
2987 .arg( fieldName ).arg( fieldValue ).arg( size.width() );
2991 spriteProperty += QLatin1String(
" END" );
2992 spriteSizeProperty += QLatin1String(
" END" );
2996 spriteProperty.clear();
2997 spriteSizeProperty.clear();
2998 const QImage sprite =
retrieveSprite( spriteName, context, spriteSize );
2999 spritePath = prepareBase64( sprite );
3006 const QVariantList stops = value.toMap().value( QStringLiteral(
"stops" ) ).toList();
3007 if ( stops.size() == 0 )
3014 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
3015 spritePath = prepareBase64( sprite );
3017 spriteProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
3018 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3020 spriteSizeProperty = QStringLiteral(
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
3021 .arg( stops.value( 0 ).toList().value( 0 ).toString() )
3022 .arg( spriteSize.width() );
3024 for (
int i = 0; i < stops.size() - 1; ++i )
3027 sprite =
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
3028 path = prepareBase64( sprite );
3030 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3032 .arg( stops.value( i ).toList().value( 0 ).toString(),
3033 stops.value( i + 1 ).toList().value( 0 ).toString(),
3035 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 "
3037 .arg( stops.value( i ).toList().value( 0 ).toString(),
3038 stops.value( i + 1 ).toList().value( 0 ).toString() )
3039 .arg( size.width() );
3041 sprite =
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
3042 path = prepareBase64( sprite );
3044 spriteProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3046 .arg( stops.last().toList().value( 0 ).toString() )
3048 spriteSizeProperty += QStringLiteral(
" WHEN @vector_tile_zoom >= %1 "
3050 .arg( stops.last().toList().value( 0 ).toString() )
3051 .arg( size.width() );
3055 case QVariant::List:
3057 const QVariantList json = value.toList();
3058 const QString method = json.value( 0 ).toString();
3059 if ( method != QLatin1String(
"match" ) )
3061 context.
pushWarning( QObject::tr(
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
3065 const QString attribute =
parseExpression( json.value( 1 ).toList(), context );
3066 if ( attribute.isEmpty() )
3068 context.
pushWarning( QObject::tr(
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
3072 spriteProperty = QStringLiteral(
"CASE " );
3073 spriteSizeProperty = QStringLiteral(
"CASE " );
3075 for (
int i = 2; i < json.length() - 1; i += 2 )
3077 const QVariantList keys = json.value( i ).toList();
3079 QStringList matchString;
3080 for (
const QVariant &key : keys )
3085 const QVariant value = json.value( i + 1 );
3087 const QImage sprite =
retrieveSprite( value.toString(), context, spriteSize );
3088 spritePath = prepareBase64( sprite );
3090 spriteProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3091 "THEN '%3' " ).arg( attribute,
3092 matchString.join(
',' ),
3095 spriteSizeProperty += QStringLiteral(
" WHEN %1 IN (%2) "
3096 "THEN %3 " ).arg( attribute,
3097 matchString.join(
',' ) ).arg( spriteSize.width() );
3100 const QImage sprite =
retrieveSprite( json.constLast().toString(), context, spriteSize );
3101 spritePath = prepareBase64( sprite );
3103 spriteProperty += QStringLiteral(
"ELSE %1 END" ).arg( spritePath );
3104 spriteSizeProperty += QStringLiteral(
"ELSE %3 END" ).arg( spriteSize.width() );
3119 switch ( value.type() )
3121 case QVariant::List:
3122 case QVariant::StringList:
3125 case QVariant::Bool:
3126 case QVariant::String:
3127 if ( colorExpected )
3132 return parseValue(
c, context );
3138 case QVariant::Double:
3139 return value.toString();
3141 case QVariant::Color:
3142 c = value.value<QColor>();
3143 return QString(
"color_rgba(%1,%2,%3,%4)" ).arg(
c.red() ).arg(
c.green() ).arg(
c.blue() ).arg(
c.alpha() );
3146 context.
pushWarning( QObject::tr(
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
3154 if ( value.toString() == QLatin1String(
"$type" ) )
3156 return QStringLiteral(
"_geom_type" );
3158 if ( value.toString() == QLatin1String(
"level" ) )
3160 return QStringLiteral(
"level" );
3162 else if ( ( value.type() == QVariant::List && value.toList().size() == 1 ) || value.type() == QVariant::StringList )
3164 if ( value.toList().size() > 1 )
3165 return value.toList().at( 1 ).toString();
3168 QString valueString = value.toList().value( 0 ).toString();
3169 if ( valueString == QLatin1String(
"geometry-type" ) )
3171 return QStringLiteral(
"_geom_type" );
3176 else if ( value.type() == QVariant::List && value.toList().size() > 1 )
3185 return mRenderer ? mRenderer->clone() :
nullptr;
3190 return mLabeling ? mLabeling->clone() :
nullptr;
3193 bool QgsMapBoxGlStyleConverter::numericArgumentsOnly(
const QVariant &bottomVariant,
const QVariant &topVariant,
double &bottom,
double &top )
3195 if ( bottomVariant.canConvert( QMetaType::Double ) && topVariant.canConvert( QMetaType::Double ) )
3197 bool bDoubleOk, tDoubleOk;
3198 bottom = bottomVariant.toDouble( &bDoubleOk );
3199 top = topVariant.toDouble( &tDoubleOk );
3200 return ( bDoubleOk && tDoubleOk );
3211 mWarnings << warning;
3226 return mSizeConversionFactor;
3231 mSizeConversionFactor = sizeConversionFactor;
3236 return mSpriteImage;
3241 return mSpriteDefinitions;
3246 mSpriteImage = image;
3247 mSpriteDefinitions = definitions;
A paint effect which blurs a source picture, using a number of different blur methods.
@ StackBlur
Stack blur, a fast but low quality blur. Valid blur level values are between 0 - 16.
void setBlurUnit(const QgsUnitTypes::RenderUnit unit)
Sets the units used for the blur level (radius).
void setBlurMethod(const BlurMethod method)
Sets the blur method (algorithm) to use for performing the blur.
void setBlurLevel(const double level)
Sets blur level (radius)
A paint effect which consists of a stack of other chained paint effects.
void appendEffect(QgsPaintEffect *effect)
Appends an effect to the end of the stack.
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quotedString(QString text)
Returns a quoted version of a string (in single quotes)
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
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)
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.
void setPlacementFlags(QgsLabeling::LinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setFactor(double factor)
Sets the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,...
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ OnLine
Labels can be placed directly over a line feature.
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
virtual void setWidth(double width)
Sets the width of the line symbol layer.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
void setOffset(double offset)
Sets the line's offset.
Context for a MapBox GL style conversion operation.
void setLayerId(const QString &value)
Sets the layer ID of the layer currently being converted.
QStringList warnings() const
Returns a list of warning messages generated during the conversion.
void pushWarning(const QString &warning)
Pushes a warning message generated during the conversion.
double pixelSizeConversionFactor() const
Returns the pixel size conversion factor, used to scale the original pixel sizes when converting styl...
QgsUnitTypes::RenderUnit targetUnit() const
Returns the target unit type.
void setPixelSizeConversionFactor(double sizeConversionFactor)
Sets the pixel size conversion factor, used to scale the original pixel sizes when converting styles.
void setSprites(const QImage &image, const QVariantMap &definitions)
Sets the sprite image and definitions JSON to use during conversion.
QString layerId() const
Returns the layer ID of the layer currently being converted.
void setTargetUnit(QgsUnitTypes::RenderUnit targetUnit)
Sets the target unit type.
QImage spriteImage() const
Returns the sprite image to use during conversion, or an invalid image if this is not set.
void clearWarnings()
Clears the list of warning messages.
QVariantMap spriteDefinitions() const
Returns the sprite definitions to use during conversion.
static QString parseOpacityStops(double base, const QVariantList &stops, int maxOpacity, QgsMapBoxGlStyleConversionContext &context)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate alpha ...
static QString parseColorExpression(const QVariant &colorExpression, QgsMapBoxGlStyleConversionContext &context)
Converts an expression representing a color to a string (can be color string or an expression where a...
static QString parseStops(double base, const QVariantList &stops, double multiplier, QgsMapBoxGlStyleConversionContext &context)
Parses a list of interpolation stops.
QgsVectorTileRenderer * renderer() const
Returns a new instance of a vector tile renderer representing the converted style,...
static QString parseExpression(const QVariantList &expression, QgsMapBoxGlStyleConversionContext &context, bool colorExpected=false)
Converts a MapBox GL expression to a QGIS expression.
PropertyType
Property types, for interpolated value conversion.
@ Numeric
Numeric property (e.g. line width, text size)
@ Opacity
Opacity property.
@ Point
Point/offset property.
QgsVectorTileLabeling * labeling() const
Returns a new instance of a vector tile labeling representing the converted 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()
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.
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...
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.
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/...
Line symbol layer type which draws repeating marker symbols along a line feature.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
virtual void setSize(double size)
Sets the symbol size.
void setAngle(double angle)
Sets the rotation angle for the marker.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's size.
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the symbol's offset.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Contains settings for how a map layer will be labeled.
double yOffset
Vertical offset of label.
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
double xOffset
Horizontal offset of label.
QuadrantPosition quadOffset
Sets the quadrant in which to offset labels from feature.
QgsUnitTypes::RenderUnit offsetUnits
Units for offsets of label.
@ 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...
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
int priority
Label priority.
QgsUnitTypes::RenderUnit distUnits
Units the distance from feature to the label.
MultiLineAlign multilineAlign
Horizontal alignment of multi-line labels.
@ FontStyle
Font style name.
@ FontLetterSpacing
Letter spacing.
@ LinePlacementOptions
Line placement flags.
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
const QgsLabelObstacleSettings & obstacleSettings() const
Returns the label obstacle settings.
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'
double dist
Distance from feature to the label.
QString fieldName
Name of field (or an expression) to use for label text.
int autoWrapLength
If non-zero, indicates that label text should be automatically wrapped to (ideally) the specified num...
A grouped map of multiple QgsProperty objects, each referenced by a integer key value.
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
QString expressionString() const
Returns the expression used for the property value.
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
A class for filling symbols with a repeated raster image.
void setWidthUnit(const QgsUnitTypes::RenderUnit unit)
Sets the units for the image's width.
@ Viewport
Tiling is based on complete map viewport.
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(FillCoordinateMode mode)
Set the coordinate mode for fill.
Raster marker symbol layer class.
void setOpacity(double opacity)
Set the marker opacity.
void setPath(const QString &path)
Set the marker raster image path.
void setBrushStyle(Qt::BrushStyle style)
void setStrokeStyle(Qt::PenStyle strokeStyle)
void setFillColor(const QColor &color) override
Set fill color.
void setOffset(QPointF offset)
Sets an offset by which polygons will be translated during rendering.
void setStrokeColor(const QColor &strokeColor) override
Set stroke color.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the fill's offset.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke.
void setStrokeWidthUnit(QgsUnitTypes::RenderUnit u)
Sets the unit for the width of the marker's stroke.
void setFillColor(const QColor &color) override
Set fill color.
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)
The fill color.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the symbol layer's property collection, used for data defined overrides.
@ PropertyOpacity
Opacity.
@ CentralPoint
Place symbols at the mid point of the line.
void setPlacement(Placement placement)
Sets the placement of the symbols.
Container for settings relating to a text background object.
void setMarkerSymbol(QgsMarkerSymbol *symbol)
Sets the current marker symbol for the background shape.
void setSizeType(SizeType type)
Sets the method used to determine the size of the background shape (e.g., fixed size or buffer around...
@ ShapeMarkerSymbol
Marker symbol.
void setType(ShapeType type)
Sets the type of background shape to draw (e.g., square, ellipse, SVG).
void setEnabled(bool enabled)
Sets whether the text background will be drawn.
void setSize(QSizeF size)
Sets the size of the background shape.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the shape's size.
void setColor(const QColor &color)
Sets the color for the buffer.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the buffer.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units used for the buffer size.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the size of rendered text.
void setBackground(const QgsTextBackgroundSettings &backgroundSettings)
Sets the text's background settings.q.
void setNamedStyle(const QString &style)
Sets the named style for the font used for rendering text.
QFont font() const
Returns the font used for rendering text.
QgsTextBufferSettings & buffer()
Returns a reference to the text buffer settings.
RenderUnit
Rendering size units.
Configuration of a single style within QgsVectorTileBasicLabeling.
void setGeometryType(QgsWkbTypes::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit)
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit)
void setStyleName(const QString &name)
Sets human readable name of this style.
void setLabelSettings(const QgsPalLayerSettings &settings)
Sets labeling configuration of this style.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
Basic labeling configuration for vector tile layers.
Definition of map rendering of a subset of vector tile data.
void setEnabled(bool enabled)
Sets whether this style is enabled (used for rendering)
void setMinZoomLevel(int minZoom)
Sets minimum zoom level index (negative number means no limit)
void setLayerName(const QString &name)
Sets name of the sub-layer to render (empty layer means that all layers match)
void setGeometryType(QgsWkbTypes::GeometryType geomType)
Sets type of the geometry that will be used (point / line / polygon)
void setFilterExpression(const QString &expr)
Sets filter expression (empty filter means that all features match)
void setSymbol(QgsSymbol *sym)
Sets symbol for rendering. Takes ownership of the symbol.
void setStyleName(const QString &name)
Sets human readable name of this style.
void setMaxZoomLevel(int maxZoom)
Sets maximum zoom level index (negative number means no limit)
The default vector tile renderer implementation.
Base class for labeling configuration classes for vector tile layers.
Abstract base class for all vector tile renderer implementations.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsSymbolLayer * > QgsSymbolLayerList