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;
 
   82   for ( 
const QVariant &layer : layers )
 
   84     const QVariantMap jsonLayer = layer.toMap();
 
   86     const QString layerType = jsonLayer.value( QStringLiteral( 
"type" ) ).toString();
 
   87     if ( layerType == QLatin1String( 
"background" ) )
 
   90     const QString styleId = jsonLayer.value( QStringLiteral( 
"id" ) ).toString();
 
   92     const QString layerName = jsonLayer.value( QStringLiteral( 
"source-layer" ) ).toString();
 
   94     const int minZoom = jsonLayer.value( QStringLiteral( 
"minzoom" ), QStringLiteral( 
"-1" ) ).toInt();
 
   95     const int maxZoom = jsonLayer.value( QStringLiteral( 
"maxzoom" ), QStringLiteral( 
"-1" ) ).toInt();
 
   97     const bool enabled = jsonLayer.value( QStringLiteral( 
"visibility" ) ).toString() != QLatin1String( 
"none" );
 
   99     QString filterExpression;
 
  100     if ( jsonLayer.contains( QStringLiteral( 
"filter" ) ) )
 
  102       filterExpression = 
parseExpression( jsonLayer.value( QStringLiteral( 
"filter" ) ).toList(), *context );
 
  108     bool hasRendererStyle = 
false;
 
  109     bool hasLabelingStyle = 
false;
 
  110     if ( layerType == QLatin1String( 
"fill" ) )
 
  112       hasRendererStyle = 
parseFillLayer( jsonLayer, rendererStyle, *context );
 
  114     else if ( layerType == QLatin1String( 
"line" ) )
 
  116       hasRendererStyle = 
parseLineLayer( jsonLayer, rendererStyle, *context );
 
  118     else if ( layerType == QLatin1String( 
"circle" ) )
 
  122     else if ( layerType == QLatin1String( 
"symbol" ) )
 
  124       parseSymbolLayer( jsonLayer, rendererStyle, hasRendererStyle, labelingStyle, hasLabelingStyle, *context );
 
  128       mWarnings << QObject::tr( 
"%1: Skipping unknown layer type %2" ).arg( context->
layerId(), layerType );
 
  133     if ( hasRendererStyle )
 
  141       rendererStyles.append( rendererStyle );
 
  144     if ( hasLabelingStyle )
 
  152       labelingStyles.append( labelingStyle );
 
  155     mWarnings.append( context->
warnings() );
 
  159   mRenderer = std::make_unique< QgsVectorTileBasicRenderer >();
 
  161   renderer->setStyles( rendererStyles );
 
  163   mLabeling = std::make_unique< QgsVectorTileBasicLabeling >();
 
  165   labeling->setStyles( labelingStyles );
 
  170   if ( !jsonLayer.contains( QStringLiteral( 
"paint" ) ) )
 
  172     context.
pushWarning( QObject::tr( 
"%1: Layer has no paint property, skipping" ).arg( jsonLayer.value( QStringLiteral( 
"id" ) ).toString() ) );
 
  176   const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( 
"paint" ) ).toMap();
 
  183   if ( jsonPaint.contains( QStringLiteral( 
"fill-color" ) ) )
 
  185     const QVariant jsonFillColor = jsonPaint.
value( QStringLiteral( 
"fill-color" ) );
 
  186     switch ( jsonFillColor.type() )
 
  193       case QVariant::StringList:
 
  197       case QVariant::String:
 
  198         fillColor = 
parseColor( jsonFillColor.toString(), context );
 
  211     fillColor = QColor( 0, 0, 0 );
 
  214   QColor fillOutlineColor;
 
  215   if ( !jsonPaint.contains( QStringLiteral( 
"fill-outline-color" ) ) )
 
  218     if ( fillColor.isValid() )
 
  219       fillOutlineColor = fillColor;
 
  229     const QVariant jsonFillOutlineColor = jsonPaint.value( QStringLiteral( 
"fill-outline-color" ) );
 
  230     switch ( jsonFillOutlineColor.type() )
 
  237       case QVariant::StringList:
 
  241       case QVariant::String:
 
  242         fillOutlineColor = 
parseColor( jsonFillOutlineColor.toString(), context );
 
  251   double fillOpacity = -1.0;
 
  252   double rasterOpacity = -1.0;
 
  253   if ( jsonPaint.contains( QStringLiteral( 
"fill-opacity" ) ) )
 
  255     const QVariant jsonFillOpacity = jsonPaint.value( QStringLiteral( 
"fill-opacity" ) );
 
  256     switch ( jsonFillOpacity.type() )
 
  259       case QVariant::Double:
 
  260         fillOpacity = jsonFillOpacity.toDouble();
 
  261         rasterOpacity = fillOpacity;
 
  267           context.
pushWarning( QObject::tr( 
"%1: Could not set opacity of layer, opacity already defined in fill color" ).arg( context.
layerId() ) );
 
  278       case QVariant::StringList:
 
  281           context.
pushWarning( QObject::tr( 
"%1: Could not set opacity of layer, opacity already defined in fill color" ).arg( context.
layerId() ) );
 
  298   QPointF fillTranslate;
 
  299   if ( jsonPaint.contains( QStringLiteral( 
"fill-translate" ) ) )
 
  301     const QVariant jsonFillTranslate = jsonPaint.value( QStringLiteral( 
"fill-translate" ) );
 
  302     switch ( jsonFillTranslate.type() )
 
  310       case QVariant::StringList:
 
  321   std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsFillSymbol >() );
 
  323   Q_ASSERT( fillSymbol ); 
 
  326   symbol->setOutputUnit( context.
targetUnit() );
 
  329   if ( !fillTranslate.isNull() )
 
  335   if ( jsonPaint.contains( QStringLiteral( 
"fill-pattern" ) ) )
 
  339     const QVariant fillPatternJson = jsonPaint.value( QStringLiteral( 
"fill-pattern" ) );
 
  342     fillColor = QColor();
 
  343     fillOutlineColor = QColor();
 
  350     QString spriteProperty, spriteSizeProperty;
 
  351     const QString sprite = 
retrieveSpriteAsBase64( fillPatternJson, context, spriteSize, spriteProperty, spriteSizeProperty );
 
  352     if ( !sprite.isEmpty() )
 
  357       rasterFill->
setWidth( spriteSize.width() );
 
  361       if ( rasterOpacity >= 0 )
 
  366       if ( !spriteProperty.isEmpty() )
 
  373       symbol->appendSymbolLayer( rasterFill );
 
  379   if ( fillOpacity != -1 )
 
  381     symbol->setOpacity( fillOpacity );
 
  384   if ( fillOutlineColor.isValid() )
 
  393   if ( fillColor.isValid() )
 
  409   if ( !jsonLayer.contains( QStringLiteral( 
"paint" ) ) )
 
  411     context.
pushWarning( QObject::tr( 
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
 
  415   const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( 
"paint" ) ).toMap();
 
  416   if ( jsonPaint.contains( QStringLiteral( 
"line-pattern" ) ) )
 
  418     context.
pushWarning( QObject::tr( 
"%1: Skipping unsupported line-pattern property" ).arg( context.
layerId() ) );
 
  426   if ( jsonPaint.contains( QStringLiteral( 
"line-color" ) ) )
 
  428     const QVariant jsonLineColor = jsonPaint.
value( QStringLiteral( 
"line-color" ) );
 
  429     switch ( jsonLineColor.type() )
 
  437       case QVariant::StringList:
 
  442       case QVariant::String:
 
  443         lineColor = 
parseColor( jsonLineColor.toString(), context );
 
  454     lineColor = QColor( 0, 0, 0 );
 
  458   double lineWidth = 1.0;
 
  459   if ( jsonPaint.contains( QStringLiteral( 
"line-width" ) ) )
 
  461     const QVariant jsonLineWidth = jsonPaint.value( QStringLiteral( 
"line-width" ) );
 
  462     switch ( jsonLineWidth.type() )
 
  465       case QVariant::Double:
 
  475       case QVariant::StringList:
 
  485   double lineOffset = 0.0;
 
  486   if ( jsonPaint.contains( QStringLiteral( 
"line-offset" ) ) )
 
  488     const QVariant jsonLineOffset = jsonPaint.value( QStringLiteral( 
"line-offset" ) );
 
  489     switch ( jsonLineOffset.type() )
 
  492       case QVariant::Double:
 
  502       case QVariant::StringList:
 
  512   double lineOpacity = -1.0;
 
  513   if ( jsonPaint.contains( QStringLiteral( 
"line-opacity" ) ) )
 
  515     const QVariant jsonLineOpacity = jsonPaint.value( QStringLiteral( 
"line-opacity" ) );
 
  516     switch ( jsonLineOpacity.type() )
 
  519       case QVariant::Double:
 
  520         lineOpacity = jsonLineOpacity.toDouble();
 
  526           context.
pushWarning( QObject::tr( 
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
 
  535       case QVariant::StringList:
 
  538           context.
pushWarning( QObject::tr( 
"%1: Could not set opacity of layer, opacity already defined in stroke color" ).arg( context.
layerId() ) );
 
  552   QVector< double > dashVector;
 
  553   if ( jsonPaint.contains( QStringLiteral( 
"line-dasharray" ) ) )
 
  555     const QVariant jsonLineDashArray = jsonPaint.value( QStringLiteral( 
"line-dasharray" ) );
 
  556     switch ( jsonLineDashArray.type() )
 
  561         const QVariantList dashSource = jsonLineDashArray.toMap().value( QStringLiteral( 
"stops" ) ).toList().last().toList().value( 1 ).toList();
 
  562         for ( 
const QVariant &v : dashSource )
 
  570       case QVariant::StringList:
 
  572         const QVariantList dashSource = jsonLineDashArray.toList();
 
  573         for ( 
const QVariant &v : dashSource )
 
  586   Qt::PenCapStyle penCapStyle = Qt::FlatCap;
 
  587   Qt::PenJoinStyle penJoinStyle = Qt::MiterJoin;
 
  588   if ( jsonLayer.contains( QStringLiteral( 
"layout" ) ) )
 
  590     const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral( 
"layout" ) ).toMap();
 
  591     if ( jsonLayout.contains( QStringLiteral( 
"line-cap" ) ) )
 
  593       penCapStyle = 
parseCapStyle( jsonLayout.value( QStringLiteral( 
"line-cap" ) ).toString() );
 
  595     if ( jsonLayout.contains( QStringLiteral( 
"line-join" ) ) )
 
  597       penJoinStyle = 
parseJoinStyle( jsonLayout.value( QStringLiteral( 
"line-join" ) ).toString() );
 
  601   std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
 
  603   Q_ASSERT( lineSymbol ); 
 
  606   symbol->setOutputUnit( context.
targetUnit() );
 
  614   if ( lineOpacity != -1 )
 
  616     symbol->setOpacity( lineOpacity );
 
  618   if ( lineColor.isValid() )
 
  622   if ( lineWidth != -1 )
 
  626   if ( !dashVector.empty() )
 
  639   if ( !jsonLayer.contains( QStringLiteral( 
"paint" ) ) )
 
  641     context.
pushWarning( QObject::tr( 
"%1: Style has no paint property, skipping" ).arg( context.
layerId() ) );
 
  645   const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( 
"paint" ) ).toMap();
 
  649   QColor circleFillColor;
 
  650   if ( jsonPaint.contains( QStringLiteral( 
"circle-color" ) ) )
 
  652     const QVariant jsonCircleColor = jsonPaint.
value( QStringLiteral( 
"circle-color" ) );
 
  653     switch ( jsonCircleColor.type() )
 
  660       case QVariant::StringList:
 
  664       case QVariant::String:
 
  665         circleFillColor = 
parseColor( jsonCircleColor.toString(), context );
 
  676     circleFillColor = QColor( 0, 0, 0 );
 
  680   double circleDiameter = 10.0;
 
  681   if ( jsonPaint.contains( QStringLiteral( 
"circle-radius" ) ) )
 
  683     const QVariant jsonCircleRadius = jsonPaint.value( QStringLiteral( 
"circle-radius" ) );
 
  684     switch ( jsonCircleRadius.type() )
 
  687       case QVariant::Double:
 
  697       case QVariant::StringList:
 
  707   double circleOpacity = -1.0;
 
  708   if ( jsonPaint.contains( QStringLiteral( 
"circle-opacity" ) ) )
 
  710     const QVariant jsonCircleOpacity = jsonPaint.value( QStringLiteral( 
"circle-opacity" ) );
 
  711     switch ( jsonCircleOpacity.type() )
 
  714       case QVariant::Double:
 
  715         circleOpacity = jsonCircleOpacity.toDouble();
 
  723       case QVariant::StringList:
 
  732   if ( ( circleOpacity != -1 ) && circleFillColor.isValid() )
 
  734     circleFillColor.setAlphaF( circleOpacity );
 
  738   QColor circleStrokeColor;
 
  739   if ( jsonPaint.contains( QStringLiteral( 
"circle-stroke-color" ) ) )
 
  741     const QVariant jsonCircleStrokeColor = jsonPaint.value( QStringLiteral( 
"circle-stroke-color" ) );
 
  742     switch ( jsonCircleStrokeColor.type() )
 
  749       case QVariant::StringList:
 
  753       case QVariant::String:
 
  754         circleStrokeColor = 
parseColor( jsonCircleStrokeColor.toString(), context );
 
  764   double circleStrokeWidth = -1.0;
 
  765   if ( jsonPaint.contains( QStringLiteral( 
"circle-stroke-width" ) ) )
 
  767     const QVariant circleStrokeWidthJson = jsonPaint.value( QStringLiteral( 
"circle-stroke-width" ) );
 
  768     switch ( circleStrokeWidthJson.type() )
 
  771       case QVariant::Double:
 
  776         circleStrokeWidth = -1.0;
 
  781       case QVariant::StringList:
 
  791   double circleStrokeOpacity = -1.0;
 
  792   if ( jsonPaint.contains( QStringLiteral( 
"circle-stroke-opacity" ) ) )
 
  794     const QVariant jsonCircleStrokeOpacity = jsonPaint.value( QStringLiteral( 
"circle-stroke-opacity" ) );
 
  795     switch ( jsonCircleStrokeOpacity.type() )
 
  798       case QVariant::Double:
 
  799         circleStrokeOpacity = jsonCircleStrokeOpacity.toDouble();
 
  807       case QVariant::StringList:
 
  816   if ( ( circleStrokeOpacity != -1 ) && circleStrokeColor.isValid() )
 
  818     circleStrokeColor.setAlphaF( circleStrokeOpacity );
 
  822   QPointF circleTranslate;
 
  823   if ( jsonPaint.contains( QStringLiteral( 
"circle-translate" ) ) )
 
  825     const QVariant jsonCircleTranslate = jsonPaint.value( QStringLiteral( 
"circle-translate" ) );
 
  826     switch ( jsonCircleTranslate.type() )
 
  834       case QVariant::StringList:
 
  845   std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsMarkerSymbol >() );
 
  847   Q_ASSERT( markerSymbolLayer );
 
  850   symbol->setOutputUnit( context.
targetUnit() );
 
  851   symbol->setDataDefinedProperties( ddProperties );
 
  853   if ( !circleTranslate.isNull() )
 
  855     markerSymbolLayer->
setOffset( circleTranslate );
 
  859   if ( circleFillColor.isValid() )
 
  863   if ( circleDiameter != -1 )
 
  865     markerSymbolLayer->
setSize( circleDiameter );
 
  868   if ( circleStrokeColor.isValid() )
 
  872   if ( circleStrokeWidth != -1 )
 
  888   if ( !jsonLayer.contains( QStringLiteral( 
"layout" ) ) )
 
  890     context.
pushWarning( QObject::tr( 
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
 
  893   const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral( 
"layout" ) ).toMap();
 
  894   if ( !jsonLayout.contains( QStringLiteral( 
"text-field" ) ) )
 
  900   if ( !jsonLayer.contains( QStringLiteral( 
"paint" ) ) )
 
  902     context.
pushWarning( QObject::tr( 
"%1: Style layer has no paint property, skipping" ).arg( context.
layerId() ) );
 
  905   const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( 
"paint" ) ).toMap();
 
  911   if ( jsonLayout.contains( QStringLiteral( 
"text-size" ) ) )
 
  913     const QVariant jsonTextSize = jsonLayout.
value( QStringLiteral( 
"text-size" ) );
 
  914     switch ( jsonTextSize.type() )
 
  917       case QVariant::Double:
 
  928       case QVariant::StringList:
 
  938     if ( textSizeProperty )
 
  945   constexpr 
double EM_TO_CHARS = 2.0;
 
  947   double textMaxWidth = -1;
 
  948   if ( jsonLayout.contains( QStringLiteral( 
"text-max-width" ) ) )
 
  950     const QVariant jsonTextMaxWidth = jsonLayout.value( QStringLiteral( 
"text-max-width" ) );
 
  951     switch ( jsonTextMaxWidth.type() )
 
  954       case QVariant::Double:
 
  955         textMaxWidth = jsonTextMaxWidth.toDouble() * EM_TO_CHARS;
 
  963       case QVariant::StringList:
 
  975     textMaxWidth = 10 * EM_TO_CHARS;
 
  978   double textLetterSpacing = -1;
 
  979   if ( jsonLayout.contains( QStringLiteral( 
"text-letter-spacing" ) ) )
 
  981     const QVariant jsonTextLetterSpacing = jsonLayout.value( QStringLiteral( 
"text-letter-spacing" ) );
 
  982     switch ( jsonTextLetterSpacing.type() )
 
  985       case QVariant::Double:
 
  986         textLetterSpacing = jsonTextLetterSpacing.toDouble();
 
  994       case QVariant::StringList:
 
 1005   bool foundFont = 
false;
 
 1007   if ( jsonLayout.contains( QStringLiteral( 
"text-font" ) ) )
 
 1009     auto splitFontFamily = []( 
const QString & fontName, QString & family, QString & style ) -> 
bool 
 1011       const QStringList textFontParts = fontName.split( 
' ' );
 
 1012       for ( 
int i = 1; i < textFontParts.size(); ++i )
 
 1014         const QString candidateFontName = textFontParts.mid( 0, i ).join( 
' ' );
 
 1015         const QString candidateFontStyle = textFontParts.mid( i ).join( 
' ' );
 
 1018           family = candidateFontName;
 
 1019           style = candidateFontStyle;
 
 1024       if ( QFontDatabase().hasFamily( fontName ) )
 
 1034     const QVariant jsonTextFont = jsonLayout.value( QStringLiteral( 
"text-font" ) );
 
 1035     if ( jsonTextFont.type() != QVariant::List && jsonTextFont.type() != QVariant::StringList && jsonTextFont.type() != QVariant::String
 
 1036          && jsonTextFont.type() != QVariant::Map )
 
 1042       switch ( jsonTextFont.type() )
 
 1044         case QVariant::List:
 
 1045         case QVariant::StringList:
 
 1046           fontName = jsonTextFont.toList().value( 0 ).toString();
 
 1049         case QVariant::String:
 
 1050           fontName = jsonTextFont.toString();
 
 1055           QString familyCaseString = QStringLiteral( 
"CASE " );
 
 1056           QString styleCaseString = QStringLiteral( 
"CASE " );
 
 1059           const QVariantList stops = jsonTextFont.toMap().value( QStringLiteral( 
"stops" ) ).toList();
 
 1062           for ( 
int i = 0; i < stops.length() - 1; ++i )
 
 1065             const QVariant bz = stops.value( i ).toList().value( 0 );
 
 1066             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();
 
 1067             if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
 
 1069               context.
pushWarning( QObject::tr( 
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
 
 1075             const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
 
 1076             if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
 
 1078               context.
pushWarning( QObject::tr( 
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
 
 1083             if ( splitFontFamily( bv, fontFamily, fontStyle ) )
 
 1085               familyCaseString += QStringLiteral( 
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 " 
 1086                                                   "THEN %3 " ).arg( bz.toString(),
 
 1089               styleCaseString += QStringLiteral( 
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 " 
 1090                                                  "THEN %3 " ).arg( bz.toString(),
 
 1096               context.
pushWarning( QObject::tr( 
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
 
 1102           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();
 
 1103           if ( splitFontFamily( bv, fontFamily, fontStyle ) )
 
 1110             context.
pushWarning( QObject::tr( 
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), bv ) );
 
 1117           fontName = fontFamily;
 
 1128       if ( splitFontFamily( fontName, fontFamily, fontStyle ) )
 
 1130         textFont = QFont( fontFamily );
 
 1131         if ( !fontStyle.isEmpty() )
 
 1132           textFont.setStyleName( fontStyle );
 
 1142       fontName = QStringLiteral( 
"Open Sans" );
 
 1143       textFont = QFont( fontName );
 
 1144       textFont.setStyleName( QStringLiteral( 
"Regular" ) );
 
 1149       fontName = QStringLiteral( 
"Arial Unicode MS" );
 
 1150       textFont = QFont( fontName );
 
 1151       textFont.setStyleName( QStringLiteral( 
"Regular" ) );
 
 1156       fontName = QStringLiteral( 
"Open Sans, Arial Unicode MS" );
 
 1159   if ( !foundFont && !fontName.isEmpty() )
 
 1161     context.
pushWarning( QObject::tr( 
"%1: Referenced font %2 is not available on system" ).arg( context.
layerId(), fontName ) );
 
 1166   if ( jsonPaint.contains( QStringLiteral( 
"text-color" ) ) )
 
 1168     const QVariant jsonTextColor = jsonPaint.value( QStringLiteral( 
"text-color" ) );
 
 1169     switch ( jsonTextColor.type() )
 
 1175       case QVariant::List:
 
 1176       case QVariant::StringList:
 
 1180       case QVariant::String:
 
 1181         textColor = 
parseColor( jsonTextColor.toString(), context );
 
 1192     textColor = QColor( 0, 0, 0 );
 
 1197   if ( jsonPaint.contains( QStringLiteral( 
"text-halo-color" ) ) )
 
 1199     const QVariant jsonBufferColor = jsonPaint.value( QStringLiteral( 
"text-halo-color" ) );
 
 1200     switch ( jsonBufferColor.type() )
 
 1206       case QVariant::List:
 
 1207       case QVariant::StringList:
 
 1211       case QVariant::String:
 
 1212         bufferColor = 
parseColor( jsonBufferColor.toString(), context );
 
 1221   double bufferSize = 0.0;
 
 1225   constexpr 
double BUFFER_SIZE_SCALE = 2.0;
 
 1226   if ( jsonPaint.contains( QStringLiteral( 
"text-halo-width" ) ) )
 
 1228     const QVariant jsonHaloWidth = jsonPaint.value( QStringLiteral( 
"text-halo-width" ) );
 
 1229     switch ( jsonHaloWidth.type() )
 
 1232       case QVariant::Double:
 
 1241       case QVariant::List:
 
 1242       case QVariant::StringList:
 
 1253   double haloBlurSize = 0;
 
 1254   if ( jsonPaint.contains( QStringLiteral( 
"text-halo-blur" ) ) )
 
 1256     const QVariant jsonTextHaloBlur = jsonPaint.value( QStringLiteral( 
"text-halo-blur" ) );
 
 1257     switch ( jsonTextHaloBlur.type() )
 
 1260       case QVariant::Double:
 
 1274   if ( textColor.isValid() )
 
 1276   if ( textSize >= 0 )
 
 1280   if ( textLetterSpacing > 0 )
 
 1282     QFont f = format.
font();
 
 1283     f.setLetterSpacing( QFont::AbsoluteSpacing, textLetterSpacing );
 
 1287   if ( bufferSize > 0 )
 
 1294     if ( haloBlurSize > 0 )
 
 1310   if ( textMaxWidth > 0 )
 
 1317   auto processLabelField = []( 
const QString & string, 
bool & isExpression )->QString
 
 1321     const QRegularExpression singleFieldRx( QStringLiteral( 
"^{([^}]+)}$" ) );
 
 1322     QRegularExpressionMatch match = singleFieldRx.match( 
string );
 
 1323     if ( match.hasMatch() )
 
 1325       isExpression = 
false;
 
 1326       return match.captured( 1 );
 
 1329     const QRegularExpression multiFieldRx( QStringLiteral( 
"(?={[^}]+})" ) );
 
 1330     const QStringList parts = 
string.split( multiFieldRx );
 
 1331     if ( parts.size() > 1 )
 
 1333       isExpression = 
true;
 
 1336       for ( 
const QString &part : parts )
 
 1338         if ( part.isEmpty() )
 
 1342         const QStringList split = part.split( 
'}' );
 
 1344         if ( !split.at( 1 ).isEmpty() )
 
 1347       return QStringLiteral( 
"concat(%1)" ).arg( res.join( 
',' ) );
 
 1351       isExpression = 
false;
 
 1356   if ( jsonLayout.contains( QStringLiteral( 
"text-field" ) ) )
 
 1358     const QVariant jsonTextField = jsonLayout.value( QStringLiteral( 
"text-field" ) );
 
 1359     switch ( jsonTextField.type() )
 
 1361       case QVariant::String:
 
 1363         labelSettings.
fieldName = processLabelField( jsonTextField.toString(), labelSettings.
isExpression );
 
 1367       case QVariant::List:
 
 1368       case QVariant::StringList:
 
 1370         const QVariantList textFieldList = jsonTextField.toList();
 
 1378         if ( textFieldList.size() > 2 && textFieldList.at( 0 ).toString() == QLatin1String( 
"format" ) )
 
 1381           for ( 
int i = 1; i < textFieldList.size(); ++i )
 
 1383             bool isExpression = 
false;
 
 1384             const QString part = processLabelField( textFieldList.at( i ).toString(), isExpression );
 
 1385             if ( !isExpression )
 
 1392           labelSettings.
fieldName = QStringLiteral( 
"concat(%1)" ).arg( parts.join( 
',' ) );
 
 1413   if ( jsonLayout.contains( QStringLiteral( 
"text-transform" ) ) )
 
 1415     const QString textTransform = jsonLayout.value( QStringLiteral( 
"text-transform" ) ).toString();
 
 1416     if ( textTransform == QLatin1String( 
"uppercase" ) )
 
 1420     else if ( textTransform == QLatin1String( 
"lowercase" ) )
 
 1429   if ( jsonLayout.contains( QStringLiteral( 
"symbol-placement" ) ) )
 
 1431     const QString symbolPlacement = jsonLayout.value( QStringLiteral( 
"symbol-placement" ) ).toString();
 
 1432     if ( symbolPlacement == QLatin1String( 
"line" ) )
 
 1438       if ( jsonLayout.contains( QStringLiteral( 
"text-rotation-alignment" ) ) )
 
 1440         const QString textRotationAlignment = jsonLayout.value( QStringLiteral( 
"text-rotation-alignment" ) ).toString();
 
 1441         if ( textRotationAlignment == QLatin1String( 
"viewport" ) )
 
 1451         if ( jsonLayout.contains( QStringLiteral( 
"text-offset" ) ) )
 
 1453           const QVariant jsonTextOffset = jsonLayout.
value( QStringLiteral( 
"text-offset" ) );
 
 1456           switch ( jsonTextOffset.type() )
 
 1459               textOffsetProperty = 
parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, !textSizeProperty ? textSize : 1.0, &textOffset );
 
 1460               if ( !textSizeProperty )
 
 1471             case QVariant::List:
 
 1472             case QVariant::StringList:
 
 1473               textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
 
 1474                                     jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
 
 1482           if ( !textOffset.isNull() )
 
 1485             labelSettings.
dist = std::abs( textOffset.y() ) - textSize;
 
 1487             if ( textSizeProperty && !textOffsetProperty )
 
 1494         if ( textOffset.isNull() )
 
 1502   if ( jsonLayout.contains( QStringLiteral( 
"text-justify" ) ) )
 
 1504     const QVariant jsonTextJustify = jsonLayout.value( QStringLiteral( 
"text-justify" ) );
 
 1507     QString textAlign = QStringLiteral( 
"center" );
 
 1509     const QVariantMap conversionMap
 
 1511       { QStringLiteral( 
"left" ), QStringLiteral( 
"left" ) },
 
 1512       { QStringLiteral( 
"center" ), QStringLiteral( 
"center" ) },
 
 1513       { QStringLiteral( 
"right" ), QStringLiteral( 
"right" ) },
 
 1514       { QStringLiteral( 
"auto" ), QStringLiteral( 
"follow" ) }
 
 1517     switch ( jsonTextJustify.type() )
 
 1519       case QVariant::String:
 
 1520         textAlign = jsonTextJustify.toString();
 
 1523       case QVariant::List:
 
 1536     if ( textAlign == QLatin1String( 
"left" ) )
 
 1538     else if ( textAlign == QLatin1String( 
"right" ) )
 
 1540     else if ( textAlign == QLatin1String( 
"center" ) )
 
 1542     else if ( textAlign == QLatin1String( 
"follow" ) )
 
 1552     if ( jsonLayout.contains( QStringLiteral( 
"text-anchor" ) ) )
 
 1554       const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral( 
"text-anchor" ) );
 
 1557       const QVariantMap conversionMap
 
 1559         { QStringLiteral( 
"center" ), 4 },
 
 1560         { QStringLiteral( 
"left" ), 5 },
 
 1561         { QStringLiteral( 
"right" ), 3 },
 
 1562         { QStringLiteral( 
"top" ), 7 },
 
 1563         { QStringLiteral( 
"bottom" ), 1 },
 
 1564         { QStringLiteral( 
"top-left" ), 8 },
 
 1565         { QStringLiteral( 
"top-right" ), 6 },
 
 1566         { QStringLiteral( 
"bottom-left" ), 2 },
 
 1567         { QStringLiteral( 
"bottom-right" ), 0 },
 
 1570       switch ( jsonTextAnchor.type() )
 
 1572         case QVariant::String:
 
 1573           textAnchor = jsonTextAnchor.toString();
 
 1576         case QVariant::List:
 
 1589       if ( textAnchor == QLatin1String( 
"center" ) )
 
 1591       else if ( textAnchor == QLatin1String( 
"left" ) )
 
 1593       else if ( textAnchor == QLatin1String( 
"right" ) )
 
 1595       else if ( textAnchor == QLatin1String( 
"top" ) )
 
 1597       else if ( textAnchor == QLatin1String( 
"bottom" ) )
 
 1599       else if ( textAnchor == QLatin1String( 
"top-left" ) )
 
 1601       else if ( textAnchor == QLatin1String( 
"top-right" ) )
 
 1603       else if ( textAnchor == QLatin1String( 
"bottom-left" ) )
 
 1605       else if ( textAnchor == QLatin1String( 
"bottom-right" ) )
 
 1610     if ( jsonLayout.contains( QStringLiteral( 
"text-offset" ) ) )
 
 1612       const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral( 
"text-offset" ) );
 
 1615       switch ( jsonTextOffset.type() )
 
 1621         case QVariant::List:
 
 1622         case QVariant::StringList:
 
 1623           textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
 
 1624                                 jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
 
 1632       if ( !textOffset.isNull() )
 
 1635         labelSettings.
xOffset = textOffset.x();
 
 1636         labelSettings.
yOffset = textOffset.y();
 
 1641   if ( jsonLayout.contains( QStringLiteral( 
"icon-image" ) ) &&
 
 1645     QString spriteProperty, spriteSizeProperty;
 
 1646     const QString sprite = 
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( 
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
 
 1647     if ( !sprite.isEmpty() )
 
 1650       markerLayer->
setPath( sprite );
 
 1651       markerLayer->
setSize( spriteSize.width() );
 
 1654       if ( !spriteProperty.isEmpty() )
 
 1666       backgroundSettings.
setSize( spriteSize );
 
 1674   if ( textSize >= 0 )
 
 1697   if ( !jsonLayer.contains( QStringLiteral( 
"layout" ) ) )
 
 1699     context.
pushWarning( QObject::tr( 
"%1: Style layer has no layout property, skipping" ).arg( context.
layerId() ) );
 
 1702   const QVariantMap jsonLayout = jsonLayer.value( QStringLiteral( 
"layout" ) ).toMap();
 
 1704   if ( jsonLayout.value( QStringLiteral( 
"symbol-placement" ) ).toString() == QLatin1String( 
"line" ) && !jsonLayout.contains( QStringLiteral( 
"text-field" ) ) )
 
 1708     double spacing = -1.0;
 
 1709     if ( jsonLayout.contains( QStringLiteral( 
"symbol-spacing" ) ) )
 
 1711       const QVariant jsonSpacing = jsonLayout.
value( QStringLiteral( 
"symbol-spacing" ) );
 
 1712       switch ( jsonSpacing.type() )
 
 1715         case QVariant::Double:
 
 1723         case QVariant::List:
 
 1724         case QVariant::StringList:
 
 1739     bool rotateMarkers = 
true;
 
 1740     if ( jsonLayout.contains( QStringLiteral( 
"icon-rotation-alignment" ) ) )
 
 1742       const QString alignment = jsonLayout.value( QStringLiteral( 
"icon-rotation-alignment" ) ).toString();
 
 1743       if ( alignment == QLatin1String( 
"map" ) || alignment == QLatin1String( 
"auto" ) )
 
 1745         rotateMarkers = 
true;
 
 1747       else if ( alignment == QLatin1String( 
"viewport" ) )
 
 1749         rotateMarkers = 
false;
 
 1754     double rotation = 0.0;
 
 1755     if ( jsonLayout.contains( QStringLiteral( 
"icon-rotate" ) ) )
 
 1757       const QVariant jsonIconRotate = jsonLayout.
value( QStringLiteral( 
"icon-rotate" ) );
 
 1758       switch ( jsonIconRotate.type() )
 
 1761         case QVariant::Double:
 
 1762           rotation = jsonIconRotate.toDouble();
 
 1769         case QVariant::List:
 
 1770         case QVariant::StringList:
 
 1791     QString spriteProperty, spriteSizeProperty;
 
 1792     const QString sprite = 
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( 
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
 
 1793     if ( !sprite.isNull() )
 
 1795       markerLayer->
setPath( sprite );
 
 1796       markerLayer->
setSize( spriteSize.width() );
 
 1799       if ( !spriteProperty.isEmpty() )
 
 1806     if ( jsonLayout.contains( QStringLiteral( 
"icon-size" ) ) )
 
 1808       const QVariant jsonIconSize = jsonLayout.value( QStringLiteral( 
"icon-size" ) );
 
 1811       switch ( jsonIconSize.type() )
 
 1814         case QVariant::Double:
 
 1816           size = jsonIconSize.toDouble();
 
 1817           if ( !spriteSizeProperty.isEmpty() )
 
 1820                                             QgsProperty::fromExpression( QStringLiteral( 
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
 
 1829         case QVariant::List:
 
 1830         case QVariant::StringList:
 
 1835       markerLayer->
setSize( size * spriteSize.width() );
 
 1838         if ( !spriteSizeProperty.isEmpty() )
 
 1855     std::unique_ptr< QgsSymbol > symbol = std::make_unique< QgsLineSymbol >( 
QgsSymbolLayerList() << lineSymbol );
 
 1858     symbol->setOutputUnit( context.
targetUnit() );
 
 1862     rendererStyle.
setSymbol( symbol.release() );
 
 1865   else if ( jsonLayout.contains( QStringLiteral( 
"icon-image" ) ) )
 
 1867     const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( 
"paint" ) ).toMap();
 
 1870     QString spriteProperty, spriteSizeProperty;
 
 1871     const QString sprite = 
retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( 
"icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
 
 1872     if ( !sprite.isEmpty() )
 
 1875       rasterMarker->
setPath( sprite );
 
 1876       rasterMarker->
setSize( spriteSize.width() );
 
 1880       if ( !spriteProperty.isEmpty() )
 
 1886       if ( jsonLayout.contains( QStringLiteral( 
"icon-size" ) ) )
 
 1888         const QVariant jsonIconSize = jsonLayout.value( QStringLiteral( 
"icon-size" ) );
 
 1891         switch ( jsonIconSize.type() )
 
 1894           case QVariant::Double:
 
 1896             size = jsonIconSize.toDouble();
 
 1897             if ( !spriteSizeProperty.isEmpty() )
 
 1900                                               QgsProperty::fromExpression( QStringLiteral( 
"with_variable('marker_size',%1,%2*@marker_size)" ).arg( spriteSizeProperty ).arg( size ) ) );
 
 1909           case QVariant::List:
 
 1910           case QVariant::StringList:
 
 1915         rasterMarker->
setSize( size * spriteSize.width() );
 
 1918           if ( !spriteSizeProperty.isEmpty() )
 
 1931       double rotation = 0.0;
 
 1932       if ( jsonLayout.contains( QStringLiteral( 
"icon-rotate" ) ) )
 
 1934         const QVariant jsonIconRotate = jsonLayout.value( QStringLiteral( 
"icon-rotate" ) );
 
 1935         switch ( jsonIconRotate.type() )
 
 1938           case QVariant::Double:
 
 1939             rotation = jsonIconRotate.toDouble();
 
 1946           case QVariant::List:
 
 1947           case QVariant::StringList:
 
 1957       double iconOpacity = -1.0;
 
 1958       if ( jsonPaint.contains( QStringLiteral( 
"icon-opacity" ) ) )
 
 1960         const QVariant jsonIconOpacity = jsonPaint.value( QStringLiteral( 
"icon-opacity" ) );
 
 1961         switch ( jsonIconOpacity.type() )
 
 1964           case QVariant::Double:
 
 1965             iconOpacity = jsonIconOpacity.toDouble();
 
 1972           case QVariant::List:
 
 1973           case QVariant::StringList:
 
 1984       rasterMarker->
setAngle( rotation );
 
 1985       if ( iconOpacity >= 0 )
 
 1989       rendererStyle.
setSymbol( markerSymbol );
 
 2000   const double base = json.
value( QStringLiteral( 
"base" ), QStringLiteral( 
"1" ) ).toDouble();
 
 2001   const QVariantList stops = json.value( QStringLiteral( 
"stops" ) ).toList();
 
 2002   if ( stops.empty() )
 
 2005   QString caseString = QStringLiteral( 
"CASE " );
 
 2007   for ( 
int i = 0; i < stops.length() - 1; ++i )
 
 2010     const QString bz = stops.at( i ).toList().value( 0 ).toString();
 
 2012     const QString tz = stops.at( i + 1 ).toList().value( 0 ).toString();
 
 2014     const QColor bottomColor = 
parseColor( stops.at( i ).toList().value( 1 ), context );
 
 2015     const QColor topColor = 
parseColor( stops.at( i + 1 ).toList().value( 1 ), context );
 
 2028     caseString += QStringLiteral( 
"WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 THEN color_hsla(" 
 2029                                   "%3, %4, %5, %6) " ).arg( bz, tz,
 
 2037   const QString tz = stops.last().toList().value( 0 ).toString();
 
 2038   const QColor topColor = 
parseColor( stops.last().toList().value( 1 ), context );
 
 2045   caseString += QStringLiteral( 
"WHEN @vector_tile_zoom >= %1 THEN color_hsla(%2, %3, %4, %5) " 
 2046                                 "ELSE color_hsla(%2, %3, %4, %5) END" ).arg( tz )
 
 2047                 .arg( tcHue ).arg( tcSat ).arg( tcLight ).arg( tcAlpha );
 
 2050   if ( !stops.empty() && defaultColor )
 
 2051     *defaultColor = 
parseColor( stops.value( 0 ).toList().value( 1 ).toString(), context );
 
 2058   const double base = json.
value( QStringLiteral( 
"base" ), QStringLiteral( 
"1" ) ).toDouble();
 
 2059   const QVariantList stops = json.value( QStringLiteral( 
"stops" ) ).toList();
 
 2060   if ( stops.empty() )
 
 2063   QString scaleExpression;
 
 2064   if ( stops.size() <= 2 )
 
 2067                       stops.last().toList().value( 0 ).toDouble(),
 
 2068                       stops.value( 0 ).toList().value( 1 ).toDouble(),
 
 2069                       stops.last().toList().value( 1 ).toDouble(), base, multiplier );
 
 2073     scaleExpression = 
parseStops( base, stops, multiplier, context );
 
 2076   if ( !stops.empty() && defaultNumber )
 
 2077     *defaultNumber = stops.value( 0 ).toList().value( 1 ).toDouble() * multiplier;
 
 2084   const double base = json.
value( QStringLiteral( 
"base" ), QStringLiteral( 
"1" ) ).toDouble();
 
 2085   const QVariantList stops = json.value( QStringLiteral( 
"stops" ) ).toList();
 
 2086   if ( stops.empty() )
 
 2089   QString scaleExpression;
 
 2090   if ( stops.length() <= 2 )
 
 2092     scaleExpression = QStringLiteral( 
"set_color_part(@symbol_color, 'alpha', %1)" )
 
 2094                             stops.last().toList().value( 0 ).toDouble(),
 
 2095                             stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity,
 
 2096                             stops.last().toList().value( 1 ).toDouble() * maxOpacity, base ) );
 
 2107   QString caseString = QStringLiteral( 
"CASE WHEN @vector_tile_zoom < %1 THEN set_color_part(@symbol_color, 'alpha', %2)" )
 
 2108                        .arg( stops.value( 0 ).toList().value( 0 ).toString() )
 
 2109                        .arg( stops.value( 0 ).toList().value( 1 ).toDouble() * maxOpacity );
 
 2111   for ( 
int i = 0; i < stops.size() - 1; ++i )
 
 2113     caseString += QStringLiteral( 
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 " 
 2114                                   "THEN set_color_part(@symbol_color, 'alpha', %3)" )
 
 2115                   .arg( stops.value( i ).toList().value( 0 ).toString(),
 
 2116                         stops.value( i + 1 ).toList().value( 0 ).toString(),
 
 2118                             stops.value( i + 1 ).toList().value( 0 ).toDouble(),
 
 2119                             stops.value( i ).toList().value( 1 ).toDouble() * maxOpacity,
 
 2120                             stops.value( i + 1 ).toList().value( 1 ).toDouble() * maxOpacity, base ) );
 
 2123   caseString += QStringLiteral( 
" WHEN @vector_tile_zoom >= %1 " 
 2124                                 "THEN set_color_part(@symbol_color, 'alpha', %2) END" )
 
 2125                 .arg( stops.last().toList().value( 0 ).toString() )
 
 2126                 .arg( stops.last().toList().value( 1 ).toDouble() * maxOpacity );
 
 2132   const double base = json.
value( QStringLiteral( 
"base" ), QStringLiteral( 
"1" ) ).toDouble();
 
 2133   const QVariantList stops = json.value( QStringLiteral( 
"stops" ) ).toList();
 
 2134   if ( stops.empty() )
 
 2137   QString scaleExpression;
 
 2138   if ( stops.size() <= 2 )
 
 2140     scaleExpression = QStringLiteral( 
"array(%1,%2)" ).arg( 
interpolateExpression( stops.value( 0 ).toList().value( 0 ).toDouble(),
 
 2141                       stops.last().toList().value( 0 ).toDouble(),
 
 2142                       stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble(),
 
 2143                       stops.last().toList().value( 1 ).toList().value( 0 ).toDouble(), base, multiplier ),
 
 2145                           stops.last().toList().value( 0 ).toDouble(),
 
 2146                           stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble(),
 
 2147                           stops.last().toList().value( 1 ).toList().value( 1 ).toDouble(), base, multiplier )
 
 2152     scaleExpression = 
parsePointStops( base, stops, context, multiplier );
 
 2155   if ( !stops.empty() && defaultPoint )
 
 2156     *defaultPoint = QPointF( stops.value( 0 ).toList().value( 1 ).toList().value( 0 ).toDouble() * multiplier,
 
 2157                              stops.value( 0 ).toList().value( 1 ).toList().value( 1 ).toDouble() * multiplier );
 
 2163     const QVariantMap &conversionMap, QString *defaultString )
 
 2165   const QVariantList stops = json.
value( QStringLiteral( 
"stops" ) ).toList();
 
 2166   if ( stops.empty() )
 
 2169   QString scaleExpression = 
parseStringStops( stops, context, conversionMap, defaultString );
 
 2176   QString caseString = QStringLiteral( 
"CASE " );
 
 2178   for ( 
int i = 0; i < stops.length() - 1; ++i )
 
 2181     const QVariant bz = stops.value( i ).toList().value( 0 );
 
 2182     const QVariant bv = stops.value( i ).toList().value( 1 );
 
 2183     if ( bv.type() != QVariant::List && bv.type() != QVariant::StringList )
 
 2190     const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
 
 2191     const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
 
 2192     if ( tv.type() != QVariant::List && tv.type() != QVariant::StringList )
 
 2198     caseString += QStringLiteral( 
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 " 
 2199                                   "THEN array(%3,%4)" ).arg( bz.toString(),
 
 2201                                       interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 0 ).toDouble(), tv.toList().value( 0 ).toDouble(), base, multiplier ),
 
 2202                                       interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toList().value( 1 ).toDouble(), tv.toList().value( 1 ).toDouble(), base, multiplier ) );
 
 2204   caseString += QLatin1String( 
"END" );
 
 2210   QString caseString = QStringLiteral( 
"CASE " );
 
 2212   for ( 
int i = 0; i < stops.length() - 1; ++i )
 
 2215     const QVariant bz = stops.value( i ).toList().value( 0 );
 
 2216     const QVariant bv = stops.value( i ).toList().value( 1 );
 
 2217     if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
 
 2219       context.
pushWarning( QObject::tr( 
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
 
 2224     const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
 
 2225     const QVariant tv = stops.value( i + 1 ).toList().value( 1 );
 
 2226     if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
 
 2228       context.
pushWarning( QObject::tr( 
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
 
 2232     caseString += QStringLiteral( 
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 " 
 2233                                   "THEN %3 " ).arg( bz.toString(),
 
 2235                                       interpolateExpression( bz.toDouble(), tz.toDouble(), bv.toDouble(), tv.toDouble(), base, multiplier ) );
 
 2238   const QVariant z = stops.last().toList().value( 0 );
 
 2239   const QVariant v = stops.last().toList().value( 1 );
 
 2240   caseString += QStringLiteral( 
"WHEN @vector_tile_zoom > %1 " 
 2241                                 "THEN %2 END" ).arg( z.toString() ).arg( v.toDouble() * multiplier );
 
 2247   QString caseString = QStringLiteral( 
"CASE " );
 
 2249   for ( 
int i = 0; i < stops.length() - 1; ++i )
 
 2252     const QVariant bz = stops.value( i ).toList().value( 0 );
 
 2253     const QString bv = stops.value( i ).toList().value( 1 ).toString();
 
 2254     if ( bz.type() == QVariant::List || bz.type() == QVariant::StringList )
 
 2256       context.
pushWarning( QObject::tr( 
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
 
 2261     const QVariant tz = stops.value( i + 1 ).toList().value( 0 );
 
 2262     if ( tz.type() == QVariant::List || tz.type() == QVariant::StringList )
 
 2264       context.
pushWarning( QObject::tr( 
"%1: Expressions in interpolation function are not supported, skipping." ).arg( context.
layerId() ) );
 
 2268     caseString += QStringLiteral( 
"WHEN @vector_tile_zoom > %1 AND @vector_tile_zoom <= %2 " 
 2269                                   "THEN %3 " ).arg( bz.toString(),
 
 2273   caseString += QStringLiteral( 
"ELSE %1 END" ).arg( 
QgsExpression::quotedValue( conversionMap.value( stops.constLast().toList().value( 1 ).toString(),
 
 2274                 stops.constLast().toList().value( 1 ) ) ) );
 
 2275   if ( defaultString )
 
 2276     *defaultString = stops.constLast().toList().value( 1 ).toString();
 
 2282   const QString method = json.
value( 0 ).toString();
 
 2283   if ( method == QLatin1String( 
"interpolate" ) )
 
 2287   else if ( method == QLatin1String( 
"match" ) )
 
 2289     return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
 
 2293     context.
pushWarning( QObject::tr( 
"%1: Could not interpret value list with method %2" ).arg( context.
layerId(), method ) );
 
 2300   const QString attribute = 
parseExpression( json.value( 1 ).toList(), context );
 
 2301   if ( attribute.isEmpty() )
 
 2303     context.
pushWarning( QObject::tr( 
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
 
 2307   QString caseString = QStringLiteral( 
"CASE " );
 
 2309   for ( 
int i = 2; i < json.length() - 1; i += 2 )
 
 2311     const QVariantList keys = json.value( i ).toList();
 
 2313     QStringList matchString;
 
 2314     for ( 
const QVariant &key : keys )
 
 2319     const QVariant value = json.value( i + 1 );
 
 2321     QString valueString;
 
 2326         const QColor color = 
parseColor( value, context );
 
 2333         const double v = value.toDouble() * multiplier;
 
 2334         valueString = QString::number( v );
 
 2340         const double v = value.toDouble() * maxOpacity;
 
 2341         valueString = QString::number( v );
 
 2347         valueString = QStringLiteral( 
"array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
 
 2348                       value.toList().value( 0 ).toDouble() * multiplier );
 
 2354     caseString += QStringLiteral( 
"WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
 
 2355                   matchString.join( 
',' ), valueString );
 
 2364       const QColor color = 
parseColor( json.constLast(), context );
 
 2366         *defaultColor = color;
 
 2374       const double v = json.constLast().toDouble() * multiplier;
 
 2375       if ( defaultNumber )
 
 2377       elseValue = QString::number( v );
 
 2383       const double v = json.constLast().toDouble() * maxOpacity;
 
 2384       if ( defaultNumber )
 
 2386       elseValue = QString::number( v );
 
 2392       elseValue = QStringLiteral( 
"array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
 
 2393                   json.constLast().toList().value( 0 ).toDouble() * multiplier );
 
 2399   caseString += QStringLiteral( 
"ELSE %1 END" ).arg( elseValue );
 
 2405   if ( json.value( 0 ).toString() != QLatin1String( 
"interpolate" ) )
 
 2407     context.
pushWarning( QObject::tr( 
"%1: Could not interpret value list" ).arg( context.
layerId() ) );
 
 2412   const QString technique = json.value( 1 ).toList().value( 0 ).toString();
 
 2413   if ( technique == QLatin1String( 
"linear" ) )
 
 2415   else if ( technique == QLatin1String( 
"exponential" ) )
 
 2416     base = json.value( 1 ).toList(). value( 1 ).toDouble();
 
 2417   else if ( technique == QLatin1String( 
"cubic-bezier" ) )
 
 2419     context.
pushWarning( QObject::tr( 
"%1: Cubic-bezier interpolation is not supported, linear used instead." ).arg( context.
layerId() ) );
 
 2424     context.
pushWarning( QObject::tr( 
"%1: Skipping not implemented interpolation method %2" ).arg( context.
layerId(), technique ) );
 
 2428   if ( json.value( 2 ).toList().value( 0 ).toString() != QLatin1String( 
"zoom" ) )
 
 2430     context.
pushWarning( QObject::tr( 
"%1: Skipping not implemented interpolation input %2" ).arg( context.
layerId(), json.value( 2 ).toString() ) );
 
 2436   for ( 
int i = 3; i < json.length(); i += 2 )
 
 2438     stops.push_back( QVariantList() << json.value( i ).toString() << json.value( i + 1 ).toString() );
 
 2442   props.insert( QStringLiteral( 
"stops" ), stops );
 
 2443   props.insert( QStringLiteral( 
"base" ), base );
 
 2446     case PropertyType::Color:
 
 2449     case PropertyType::Numeric:
 
 2452     case PropertyType::Opacity:
 
 2455     case PropertyType::Point:
 
 2463   if ( color.type() != QVariant::String )
 
 2465     context.
pushWarning( QObject::tr( 
"%1: Could not parse non-string color %2, skipping" ).arg( context.
layerId(), color.toString() ) );
 
 2474   hue = std::max( 0, color.hslHue() );
 
 2475   saturation = color.hslSaturation() / 255.0 * 100;
 
 2476   lightness = color.lightness() / 255.0 * 100;
 
 2477   alpha = color.alpha();
 
 2484     return QString::number( valueMin * multiplier );
 
 2489     expression = QStringLiteral( 
"scale_linear(@vector_tile_zoom,%1,%2,%3,%4)" ).arg( zoomMin )
 
 2496     expression = QStringLiteral( 
"scale_exp(@vector_tile_zoom,%1,%2,%3,%4,%5)" ).arg( zoomMin )
 
 2503   if ( multiplier != 1 )
 
 2504     return QStringLiteral( 
"%1 * %2" ).arg( expression ).arg( multiplier );
 
 2511   if ( style == QLatin1String( 
"round" ) )
 
 2512     return Qt::RoundCap;
 
 2513   else if ( style == QLatin1String( 
"square" ) )
 
 2514     return Qt::SquareCap;
 
 2521   if ( style == QLatin1String( 
"bevel" ) )
 
 2522     return Qt::BevelJoin;
 
 2523   else if ( style == QLatin1String( 
"round" ) )
 
 2524     return Qt::RoundJoin;
 
 2526     return Qt::MiterJoin; 
 
 2531   QString op = expression.value( 0 ).toString();
 
 2532   if ( op == QLatin1String( 
"all" )
 
 2533        || op == QLatin1String( 
"any" )
 
 2534        || op == QLatin1String( 
"none" ) )
 
 2537     for ( 
int i = 1; i < expression.size(); ++i )
 
 2539       QString part = parseValue( expression.at( i ), context );
 
 2540       if ( part.isEmpty() )
 
 2542         context.
pushWarning( QObject::tr( 
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
 
 2548     if ( op == QLatin1String( 
"none" ) )
 
 2549       return QStringLiteral( 
"NOT (%1)" ).arg( parts.join( QLatin1String( 
") AND NOT (" ) ) );
 
 2551     QString operatorString;
 
 2552     if ( op == QLatin1String( 
"all" ) )
 
 2553       operatorString = QStringLiteral( 
") AND (" );
 
 2554     else if ( op == QLatin1String( 
"any" ) )
 
 2555       operatorString = QStringLiteral( 
") OR (" );
 
 2557     return QStringLiteral( 
"(%1)" ).arg( parts.join( operatorString ) );
 
 2559   else if ( op == 
'!' )
 
 2562     QVariantList contraJsonExpr = expression.value( 1 ).toList();
 
 2563     contraJsonExpr[0] = QString( op + contraJsonExpr[0].toString() );
 
 2565     return parseKey( contraJsonExpr );
 
 2567   else if ( op == QLatin1String( 
"==" )
 
 2568             || op == QLatin1String( 
"!=" )
 
 2569             || op == QLatin1String( 
">=" )
 
 2571             || op == QLatin1String( 
"<=" )
 
 2575     if ( op == QLatin1String( 
"==" ) )
 
 2576       op = QStringLiteral( 
"IS" );
 
 2577     else if ( op == QLatin1String( 
"!=" ) )
 
 2578       op = QStringLiteral( 
"IS NOT" );
 
 2579     return QStringLiteral( 
"%1 %2 %3" ).arg( parseKey( expression.value( 1 ) ),
 
 2580            op, parseValue( expression.value( 2 ), context ) );
 
 2582   else if ( op == QLatin1String( 
"has" ) )
 
 2584     return parseKey( expression.value( 1 ) ) + QStringLiteral( 
" IS NOT NULL" );
 
 2586   else if ( op == QLatin1String( 
"!has" ) )
 
 2588     return parseKey( expression.value( 1 ) ) + QStringLiteral( 
" IS NULL" );
 
 2590   else if ( op == QLatin1String( 
"in" ) || op == QLatin1String( 
"!in" ) )
 
 2592     const QString key = parseKey( expression.value( 1 ) );
 
 2594     for ( 
int i = 2; i < expression.size(); ++i )
 
 2596       QString part = parseValue( expression.at( i ), context );
 
 2597       if ( part.isEmpty() )
 
 2599         context.
pushWarning( QObject::tr( 
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
 
 2604     if ( op == QLatin1String( 
"in" ) )
 
 2605       return QStringLiteral( 
"%1 IN (%2)" ).arg( key, parts.join( QLatin1String( 
", " ) ) );
 
 2607       return QStringLiteral( 
"(%1 IS NULL OR %1 NOT IN (%2))" ).arg( key, parts.join( QLatin1String( 
", " ) ) );
 
 2609   else if ( op == QLatin1String( 
"get" ) )
 
 2611     return parseKey( expression.value( 1 ) );
 
 2613   else if ( op == QLatin1String( 
"match" ) )
 
 2615     const QString attribute = expression.value( 1 ).toList().value( 1 ).toString();
 
 2617     if ( expression.size() == 5
 
 2618          && expression.at( 3 ).type() == QVariant::Bool && expression.at( 3 ).toBool() == 
true 
 2619          && expression.at( 4 ).type() == QVariant::Bool && expression.at( 4 ).toBool() == 
false )
 
 2622       if ( expression.at( 2 ).type() == QVariant::List || expression.at( 2 ).type() == QVariant::StringList )
 
 2625         for ( 
const QVariant &p : expression.at( 2 ).toList() )
 
 2630         if ( parts.size() > 1 )
 
 2635       else if ( expression.at( 2 ).type() == QVariant::String || expression.at( 2 ).type() == QVariant::Int
 
 2636                 || expression.at( 2 ).type() == QVariant::Double )
 
 2642         context.
pushWarning( QObject::tr( 
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
 
 2648       QString caseString = QStringLiteral( 
"CASE " );
 
 2649       for ( 
int i = 2; i < expression.size() - 2; i += 2 )
 
 2651         if ( expression.at( i ).type() == QVariant::List || expression.at( i ).type() == QVariant::StringList )
 
 2654           for ( 
const QVariant &p : expression.at( i ).toList() )
 
 2659           if ( parts.size() > 1 )
 
 2664         else if ( expression.at( i ).type() == QVariant::String || expression.at( i ).type() == QVariant::Int
 
 2665                   || expression.at( i ).type() == QVariant::Double )
 
 2676   else if ( op == QLatin1String( 
"to-string" ) )
 
 2678     return QStringLiteral( 
"to_string(%1)" ).arg( 
parseExpression( expression.value( 1 ).toList(), context ) );
 
 2682     context.
pushWarning( QObject::tr( 
"%1: Skipping unsupported expression" ).arg( context.
layerId() ) );
 
 2691     context.
pushWarning( QObject::tr( 
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
 
 2695   const QVariantMap spriteDefinition = context.
spriteDefinitions().value( name ).toMap();
 
 2696   if ( spriteDefinition.size() == 0 )
 
 2698     context.
pushWarning( QObject::tr( 
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
 
 2702   const QImage sprite = context.
spriteImage().copy( spriteDefinition.value( QStringLiteral( 
"x" ) ).toInt(),
 
 2703                         spriteDefinition.value( QStringLiteral( 
"y" ) ).toInt(),
 
 2704                         spriteDefinition.value( QStringLiteral( 
"width" ) ).toInt(),
 
 2705                         spriteDefinition.value( QStringLiteral( 
"height" ) ).toInt() );
 
 2706   if ( sprite.isNull() )
 
 2708     context.
pushWarning( QObject::tr( 
"%1: Could not retrieve sprite '%2'" ).arg( context.
layerId(), name ) );
 
 2712   spriteSize = sprite.size() / spriteDefinition.value( QStringLiteral( 
"pixelRatio" ) ).toDouble() * context.
pixelSizeConversionFactor();
 
 2720   auto prepareBase64 = []( 
const QImage & sprite )
 
 2723     if ( !sprite.isNull() )
 
 2726       QBuffer buffer( &blob );
 
 2727       buffer.open( QIODevice::WriteOnly );
 
 2728       sprite.save( &buffer, 
"PNG" );
 
 2730       QByteArray encoded = blob.toBase64();
 
 2731       path = QString( encoded );
 
 2732       path.prepend( QLatin1String( 
"base64:" ) );
 
 2737   switch ( value.type() )
 
 2739     case QVariant::String:
 
 2741       QString spriteName = value.toString();
 
 2742       QRegularExpression fieldNameMatch( QStringLiteral( 
"{([^}]+)}" ) );
 
 2743       QRegularExpressionMatch match = fieldNameMatch.match( spriteName );
 
 2744       if ( match.hasMatch() )
 
 2746         const QString fieldName = match.captured( 1 );
 
 2747         spriteProperty = QStringLiteral( 
"CASE" );
 
 2748         spriteSizeProperty = QStringLiteral( 
"CASE" );
 
 2750         spriteName.replace( 
"(", QLatin1String( 
"\\(" ) );
 
 2751         spriteName.replace( 
")", QLatin1String( 
"\\)" ) );
 
 2752         spriteName.replace( fieldNameMatch, QStringLiteral( 
"([^\\/\\\\]+)" ) );
 
 2753         QRegularExpression fieldValueMatch( spriteName );
 
 2755         for ( 
const QString &name : spriteNames )
 
 2757           match = fieldValueMatch.match( name );
 
 2758           if ( match.hasMatch() )
 
 2762             const QString fieldValue = match.captured( 1 );
 
 2764             path = prepareBase64( sprite );
 
 2765             if ( spritePath.isEmpty() && !path.isEmpty() )
 
 2771             spriteProperty += QStringLiteral( 
" WHEN \"%1\" = '%2' THEN '%3'" )
 
 2772                               .arg( fieldName, fieldValue, path );
 
 2773             spriteSizeProperty += QStringLiteral( 
" WHEN \"%1\" = '%2' THEN %3" )
 
 2774                                   .arg( fieldName ).arg( fieldValue ).arg( size.width() );
 
 2778         spriteProperty += QLatin1String( 
" END" );
 
 2779         spriteSizeProperty += QLatin1String( 
" END" );
 
 2783         spriteProperty.clear();
 
 2784         spriteSizeProperty.clear();
 
 2785         const QImage sprite = 
retrieveSprite( spriteName, context, spriteSize );
 
 2786         spritePath = prepareBase64( sprite );
 
 2793       const QVariantList stops = value.toMap().value( QStringLiteral( 
"stops" ) ).toList();
 
 2794       if ( stops.size() == 0 )
 
 2801       sprite = 
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, spriteSize );
 
 2802       spritePath = prepareBase64( sprite );
 
 2804       spriteProperty = QStringLiteral( 
"CASE WHEN @vector_tile_zoom < %1 THEN '%2'" )
 
 2805                        .arg( stops.value( 0 ).toList().value( 0 ).toString() )
 
 2807       spriteSizeProperty = QStringLiteral( 
"CASE WHEN @vector_tile_zoom < %1 THEN %2" )
 
 2808                            .arg( stops.value( 0 ).toList().value( 0 ).toString() )
 
 2809                            .arg( spriteSize.width() );
 
 2811       for ( 
int i = 0; i < stops.size() - 1; ++i )
 
 2814         sprite = 
retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context, size );
 
 2815         path = prepareBase64( sprite );
 
 2817         spriteProperty += QStringLiteral( 
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 " 
 2819                           .arg( stops.value( i ).toList().value( 0 ).toString(),
 
 2820                                 stops.value( i + 1 ).toList().value( 0 ).toString(),
 
 2822         spriteSizeProperty += QStringLiteral( 
" WHEN @vector_tile_zoom >= %1 AND @vector_tile_zoom < %2 " 
 2824                               .arg( stops.value( i ).toList().value( 0 ).toString(),
 
 2825                                     stops.value( i + 1 ).toList().value( 0 ).toString() )
 
 2826                               .arg( size.width() );
 
 2828       sprite = 
retrieveSprite( stops.last().toList().value( 1 ).toString(), context, size );
 
 2829       path = prepareBase64( sprite );
 
 2831       spriteProperty += QStringLiteral( 
" WHEN @vector_tile_zoom >= %1 " 
 2833                         .arg( stops.last().toList().value( 0 ).toString() )
 
 2835       spriteSizeProperty += QStringLiteral( 
" WHEN @vector_tile_zoom >= %1 " 
 2837                             .arg( stops.last().toList().value( 0 ).toString() )
 
 2838                             .arg( size.width() );
 
 2842     case QVariant::List:
 
 2844       const QVariantList json = value.toList();
 
 2845       const QString method = json.value( 0 ).toString();
 
 2846       if ( method != QLatin1String( 
"match" ) )
 
 2848         context.
pushWarning( QObject::tr( 
"%1: Could not interpret sprite value list with method %2" ).arg( context.
layerId(), method ) );
 
 2852       const QString attribute = 
parseExpression( json.value( 1 ).toList(), context );
 
 2853       if ( attribute.isEmpty() )
 
 2855         context.
pushWarning( QObject::tr( 
"%1: Could not interpret match list" ).arg( context.
layerId() ) );
 
 2859       spriteProperty = QStringLiteral( 
"CASE " );
 
 2860       spriteSizeProperty = QStringLiteral( 
"CASE " );
 
 2862       for ( 
int i = 2; i < json.length() - 1; i += 2 )
 
 2864         const QVariantList keys = json.value( i ).toList();
 
 2866         QStringList matchString;
 
 2867         for ( 
const QVariant &key : keys )
 
 2872         const QVariant value = json.value( i + 1 );
 
 2874         const QImage sprite = 
retrieveSprite( value.toString(), context, spriteSize );
 
 2875         spritePath = prepareBase64( sprite );
 
 2877         spriteProperty += QStringLiteral( 
" WHEN %1 IN (%2) " 
 2878                                           "THEN '%3' " ).arg( attribute,
 
 2879                                               matchString.join( 
',' ),
 
 2882         spriteSizeProperty += QStringLiteral( 
" WHEN %1 IN (%2) " 
 2883                                               "THEN %3 " ).arg( attribute,
 
 2884                                                   matchString.join( 
',' ) ).arg( spriteSize.width() );
 
 2887       const QImage sprite = 
retrieveSprite( json.constLast().toString(), context, spriteSize );
 
 2888       spritePath = prepareBase64( sprite );
 
 2890       spriteProperty += QStringLiteral( 
"ELSE %1 END" ).arg( spritePath );
 
 2891       spriteSizeProperty += QStringLiteral( 
"ELSE %3 END" ).arg( spriteSize.width() );
 
 2905   switch ( value.type() )
 
 2907     case QVariant::List:
 
 2908     case QVariant::StringList:
 
 2911     case QVariant::String:
 
 2915     case QVariant::Double:
 
 2916       return value.toString();
 
 2919       context.
pushWarning( QObject::tr( 
"%1: Skipping unsupported expression part" ).arg( context.
layerId() ) );
 
 2925 QString QgsMapBoxGlStyleConverter::parseKey( 
const QVariant &value )
 
 2927   if ( value.toString() == QLatin1String( 
"$type" ) )
 
 2928     return QStringLiteral( 
"_geom_type" );
 
 2929   else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
 
 2931     if ( value.toList().size() > 1 )
 
 2932       return value.toList().at( 1 ).toString();
 
 2934       return value.toList().value( 0 ).toString();
 
 2941   return mRenderer ? mRenderer->clone() : 
nullptr;
 
 2946   return mLabeling ? mLabeling->clone() : 
nullptr;
 
 2955   mWarnings << warning;
 
 2970   return mSizeConversionFactor;
 
 2975   mSizeConversionFactor = sizeConversionFactor;
 
 2980   return mSpriteImage;
 
 2985   return mSpriteDefinitions;
 
 2990   mSpriteImage = image;
 
 2991   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 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 bool parseFillLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &style, QgsMapBoxGlStyleConversionContext &context)
Parses a fill layer.
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 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 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 QString parseExpression(const QVariantList &expression, QgsMapBoxGlStyleConversionContext &context)
Converts a MapBox GL expression to a QGIS expression.
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 void parseSymbolLayer(const QVariantMap &jsonLayer, QgsVectorTileBasicRendererStyle &rendererStyle, bool &hasRenderer, QgsVectorTileBasicLabelingStyle &labelingStyle, bool &hasLabeling, QgsMapBoxGlStyleConversionContext &context)
Parses a symbol layer as renderer or labeling.
static QString interpolateExpression(double zoomMin, double zoomMax, double valueMin, double valueMax, double base, double multiplier=1)
Generates an interpolation for values between valueMin and valueMax, scaled between the ranges zoomMi...
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 parseOpacityStops(double base, const QVariantList &stops, int maxOpacity)
Takes values from stops and uses either scale_linear() or scale_exp() functions to interpolate alpha ...
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 parseInterpolateOpacityByZoom(const QVariantMap &json, int maxOpacity)
Interpolates opacity with either scale_linear() or scale_exp() (depending on base value).
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 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.
@ 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.
@ 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.
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.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QList< QgsSymbolLayer * > QgsSymbolLayerList