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