Skip to content

Commit

Permalink
Correctly parse 'match' interpolation list values during conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 14, 2020
1 parent 91598c7 commit 229c240
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 19 deletions.
Expand Up @@ -397,6 +397,27 @@ Parses a list of interpolation stops containing string values.
%End


static QgsProperty parseValueList( const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1,
int maxOpacity = 255, QColor *defaultColor /Out/ = 0, double *defaultNumber /Out/ = 0 );
%Docstring
Parses and converts a value list (e.g. an interpolate list).

.. warning::

This is private API only, and may change in future QGIS versions
%End


static QgsProperty parseMatchList( const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1,
int maxOpacity = 255, QColor *defaultColor /Out/ = 0, double *defaultNumber /Out/ = 0 );
%Docstring
Parses and converts a match function value list.

.. warning::

This is private API only, and may change in future QGIS versions
%End

static QgsProperty parseInterpolateListByZoom( const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1,
int maxOpacity = 255, QColor *defaultColor /Out/ = 0, double *defaultNumber /Out/ = 0 );
%Docstring
Expand Down
161 changes: 142 additions & 19 deletions src/core/vectortile/qgsmapboxglstyleconverter.cpp
Expand Up @@ -181,7 +181,7 @@ bool QgsMapBoxGlStyleConverter::parseFillLayer( const QVariantMap &jsonLayer, Qg

case QVariant::List:
case QVariant::StringList:
ddProperties.setProperty( QgsSymbolLayer::PropertyFillColor, parseInterpolateListByZoom( jsonFillColor.toList(), PropertyType::Color, context, 1, 255, &fillColor ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyFillColor, parseValueList( jsonFillColor.toList(), PropertyType::Color, context, 1, 255, &fillColor ) );
break;

case QVariant::String:
Expand Down Expand Up @@ -220,7 +220,7 @@ bool QgsMapBoxGlStyleConverter::parseFillLayer( const QVariantMap &jsonLayer, Qg

case QVariant::List:
case QVariant::StringList:
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, parseInterpolateListByZoom( jsonFillOutlineColor.toList(), PropertyType::Color, context, 1, 255, &fillOutlineColor ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, parseValueList( jsonFillOutlineColor.toList(), PropertyType::Color, context, 1, 255, &fillOutlineColor ) );
break;

case QVariant::String:
Expand Down Expand Up @@ -267,9 +267,9 @@ bool QgsMapBoxGlStyleConverter::parseFillLayer( const QVariantMap &jsonLayer, Qg
}
else
{
ddProperties.setProperty( QgsSymbolLayer::PropertyFillColor, parseInterpolateListByZoom( jsonFillOpacity.toList(), PropertyType::Opacity, context, 1, fillColor.isValid() ? fillColor.alpha() : 255 ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, parseInterpolateListByZoom( jsonFillOpacity.toList(), PropertyType::Opacity, context, 1, fillOutlineColor.isValid() ? fillOutlineColor.alpha() : 255 ) );
ddRasterProperties.setProperty( QgsSymbolLayer::PropertyOpacity, parseInterpolateListByZoom( jsonFillOpacity.toList(), PropertyType::Numeric, context, 100, 255, nullptr, &rasterOpacity ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyFillColor, parseValueList( jsonFillOpacity.toList(), PropertyType::Opacity, context, 1, fillColor.isValid() ? fillColor.alpha() : 255 ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, parseValueList( jsonFillOpacity.toList(), PropertyType::Opacity, context, 1, fillOutlineColor.isValid() ? fillOutlineColor.alpha() : 255 ) );
ddRasterProperties.setProperty( QgsSymbolLayer::PropertyOpacity, parseValueList( jsonFillOpacity.toList(), PropertyType::Numeric, context, 100, 255, nullptr, &rasterOpacity ) );
}
break;

Expand Down Expand Up @@ -407,7 +407,7 @@ bool QgsMapBoxGlStyleConverter::parseLineLayer( const QVariantMap &jsonLayer, Qg

case QVariant::List:
case QVariant::StringList:
ddProperties.setProperty( QgsSymbolLayer::PropertyFillColor, parseInterpolateListByZoom( jsonLineColor.toList(), PropertyType::Color, context, 1, 255, &lineColor ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyFillColor, parseValueList( jsonLineColor.toList(), PropertyType::Color, context, 1, 255, &lineColor ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, ddProperties.property( QgsSymbolLayer::PropertyFillColor ) );
break;

Expand Down Expand Up @@ -440,7 +440,7 @@ bool QgsMapBoxGlStyleConverter::parseLineLayer( const QVariantMap &jsonLayer, Qg

case QVariant::List:
case QVariant::StringList:
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeWidth, parseInterpolateListByZoom( jsonLineWidth.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &lineWidth ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeWidth, parseValueList( jsonLineWidth.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &lineWidth ) );
break;

default:
Expand All @@ -467,7 +467,7 @@ bool QgsMapBoxGlStyleConverter::parseLineLayer( const QVariantMap &jsonLayer, Qg

case QVariant::List:
case QVariant::StringList:
ddProperties.setProperty( QgsSymbolLayer::PropertyOffset, parseInterpolateListByZoom( jsonLineOffset.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor() * -1, 255, nullptr, &lineOffset ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyOffset, parseValueList( jsonLineOffset.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor() * -1, 255, nullptr, &lineOffset ) );
break;

default:
Expand Down Expand Up @@ -506,7 +506,7 @@ bool QgsMapBoxGlStyleConverter::parseLineLayer( const QVariantMap &jsonLayer, Qg
}
else
{
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, parseInterpolateListByZoom( jsonLineOpacity.toList(), PropertyType::Opacity, context, 1, lineColor.isValid() ? lineColor.alpha() : 255 ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyStrokeColor, parseValueList( jsonLineOpacity.toList(), PropertyType::Opacity, context, 1, lineColor.isValid() ? lineColor.alpha() : 255 ) );
}
break;

Expand Down Expand Up @@ -647,7 +647,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
case QVariant::List:
case QVariant::StringList:
textSize = -1;
textSizeProperty = parseInterpolateListByZoom( jsonTextSize.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &textSize );
textSizeProperty = parseValueList( jsonTextSize.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &textSize );
break;

default:
Expand Down Expand Up @@ -681,7 +681,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,

case QVariant::List:
case QVariant::StringList:
ddLabelProperties.setProperty( QgsPalLayerSettings::AutoWrapLength, parseInterpolateListByZoom( jsonTextMaxWidth.toList(), PropertyType::Numeric, context, EM_TO_CHARS, 255, nullptr, &textMaxWidth ) );
ddLabelProperties.setProperty( QgsPalLayerSettings::AutoWrapLength, parseValueList( jsonTextMaxWidth.toList(), PropertyType::Numeric, context, EM_TO_CHARS, 255, nullptr, &textMaxWidth ) );
break;

default:
Expand All @@ -707,7 +707,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,

case QVariant::List:
case QVariant::StringList:
ddLabelProperties.setProperty( QgsPalLayerSettings::FontLetterSpacing, parseInterpolateListByZoom( jsonTextLetterSpacing.toList(), PropertyType::Numeric, context, 1, 255, nullptr, &textLetterSpacing ) );
ddLabelProperties.setProperty( QgsPalLayerSettings::FontLetterSpacing, parseValueList( jsonTextLetterSpacing.toList(), PropertyType::Numeric, context, 1, 255, nullptr, &textLetterSpacing ) );
break;

default:
Expand Down Expand Up @@ -779,7 +779,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,

case QVariant::List:
case QVariant::StringList:
ddLabelProperties.setProperty( QgsPalLayerSettings::Color, parseInterpolateListByZoom( jsonTextColor.toList(), PropertyType::Color, context, 1, 255, &textColor ) );
ddLabelProperties.setProperty( QgsPalLayerSettings::Color, parseValueList( jsonTextColor.toList(), PropertyType::Color, context, 1, 255, &textColor ) );
break;

case QVariant::String:
Expand All @@ -805,7 +805,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,

case QVariant::List:
case QVariant::StringList:
ddLabelProperties.setProperty( QgsPalLayerSettings::BufferColor, parseInterpolateListByZoom( jsonBufferColor.toList(), PropertyType::Color, context, 1, 255, &bufferColor ) );
ddLabelProperties.setProperty( QgsPalLayerSettings::BufferColor, parseValueList( jsonBufferColor.toList(), PropertyType::Color, context, 1, 255, &bufferColor ) );
break;

case QVariant::String:
Expand Down Expand Up @@ -837,7 +837,7 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
case QVariant::List:
case QVariant::StringList:
bufferSize = 1;
ddLabelProperties.setProperty( QgsPalLayerSettings::BufferSize, parseInterpolateListByZoom( jsonHaloWidth.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &bufferSize ) );
ddLabelProperties.setProperty( QgsPalLayerSettings::BufferSize, parseValueList( jsonHaloWidth.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &bufferSize ) );
break;

default:
Expand Down Expand Up @@ -1270,7 +1270,7 @@ bool QgsMapBoxGlStyleConverter::parseSymbolLayerAsRenderer( const QVariantMap &j

case QVariant::List:
case QVariant::StringList:
ddProperties.setProperty( QgsSymbolLayer::PropertyInterval, parseInterpolateListByZoom( jsonSpacing.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &spacing ) );
ddProperties.setProperty( QgsSymbolLayer::PropertyInterval, parseValueList( jsonSpacing.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &spacing ) );
break;

default:
Expand Down Expand Up @@ -1311,7 +1311,7 @@ bool QgsMapBoxGlStyleConverter::parseSymbolLayerAsRenderer( const QVariantMap &j

case QVariant::List:
case QVariant::StringList:
markerDdProperties.setProperty( QgsSymbolLayer::PropertyAngle, parseInterpolateListByZoom( jsonIconRotate.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &rotation ) );
markerDdProperties.setProperty( QgsSymbolLayer::PropertyAngle, parseValueList( jsonIconRotate.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &rotation ) );
break;

default:
Expand Down Expand Up @@ -1398,7 +1398,7 @@ bool QgsMapBoxGlStyleConverter::parseSymbolLayerAsRenderer( const QVariantMap &j

case QVariant::List:
case QVariant::StringList:
markerDdProperties.setProperty( QgsSymbolLayer::PropertyAngle, parseInterpolateListByZoom( jsonIconRotate.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &rotation ) );
markerDdProperties.setProperty( QgsSymbolLayer::PropertyAngle, parseValueList( jsonIconRotate.toList(), PropertyType::Numeric, context, context.pixelSizeConversionFactor(), 255, nullptr, &rotation ) );
break;

default:
Expand All @@ -1424,7 +1424,7 @@ bool QgsMapBoxGlStyleConverter::parseSymbolLayerAsRenderer( const QVariantMap &j

case QVariant::List:
case QVariant::StringList:
markerDdProperties.setProperty( QgsSymbolLayer::PropertyOpacity, parseInterpolateListByZoom( jsonIconOpacity.toList(), PropertyType::Numeric, context, 100, 255, nullptr, &iconOpacity ) );
markerDdProperties.setProperty( QgsSymbolLayer::PropertyOpacity, parseValueList( jsonIconOpacity.toList(), PropertyType::Numeric, context, 100, 255, nullptr, &iconOpacity ) );
break;

default:
Expand Down Expand Up @@ -1730,6 +1730,129 @@ QString QgsMapBoxGlStyleConverter::parseStringStops( const QVariantList &stops,
return caseString;
}

QgsProperty QgsMapBoxGlStyleConverter::parseValueList( const QVariantList &json, QgsMapBoxGlStyleConverter::PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier, int maxOpacity, QColor *defaultColor, double *defaultNumber )
{
const QString method = json.value( 0 ).toString();
if ( method == QLatin1String( "interpolate" ) )
{
return parseInterpolateListByZoom( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
}
else if ( method == QLatin1String( "match" ) )
{
return parseMatchList( json, type, context, multiplier, maxOpacity, defaultColor, defaultNumber );
}
else
{
context.pushWarning( QObject::tr( "Could not interpret value list with method %1" ).arg( method ) );
return QgsProperty();
}
}

QgsProperty QgsMapBoxGlStyleConverter::parseMatchList( const QVariantList &json, QgsMapBoxGlStyleConverter::PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier, int maxOpacity, QColor *defaultColor, double *defaultNumber )
{
const QString attribute = parseExpression( json.value( 1 ).toList(), context );
if ( attribute.isEmpty() )
{
context.pushWarning( QObject::tr( "Could not interpret match list" ) );
return QgsProperty();
}

QString caseString = QStringLiteral( "CASE " );

for ( int i = 2; i < json.length() - 1; i += 2 )
{
const QVariantList keys = json.value( i ).toList();

QStringList matchString;
for ( const QVariant &key : keys )
{
matchString << QgsExpression::quotedValue( key );
}

const QVariant value = json.value( i + 1 );

QString valueString;
switch ( type )
{
case Color:
{
const QColor color = parseColor( value, context );
valueString = QgsExpression::quotedString( color.name() );
break;
}

case Numeric:
{
const double v = value.toDouble() * multiplier;
valueString = QString::number( v );
break;
}

case Opacity:
{
const double v = value.toDouble() * maxOpacity;
valueString = QString::number( v );
break;
}

case Point:
{
valueString = QStringLiteral( "array(%1,%2)" ).arg( value.toList().value( 0 ).toDouble() * multiplier,
value.toList().value( 0 ).toDouble() * multiplier );
break;
}

}

caseString += QStringLiteral( "WHEN %1 IN (%2) THEN %3 " ).arg( attribute,
matchString.join( ',' ), valueString );
}


QString elseValue;
switch ( type )
{
case Color:
{
const QColor color = parseColor( json.constLast(), context );
if ( defaultColor )
*defaultColor = color;

elseValue = QgsExpression::quotedString( color.name() );
break;
}

case Numeric:
{
const double v = json.constLast().toDouble() * multiplier;
if ( defaultNumber )
*defaultNumber = v;
elseValue = QString::number( v );
break;
}

case Opacity:
{
const double v = json.constLast().toDouble() * maxOpacity;
if ( defaultNumber )
*defaultNumber = v;
elseValue = QString::number( v );
break;
}

case Point:
{
elseValue = QStringLiteral( "array(%1,%2)" ).arg( json.constLast().toList().value( 0 ).toDouble() * multiplier,
json.constLast().toList().value( 0 ).toDouble() * multiplier );
break;
}

}

caseString += QStringLiteral( "ELSE %1 END" ).arg( elseValue );
return QgsProperty::fromExpression( caseString );
}

QgsProperty QgsMapBoxGlStyleConverter::parseInterpolateListByZoom( const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier, int maxOpacity, QColor *defaultColor, double *defaultNumber )
{
if ( json.value( 0 ).toString() != QLatin1String( "interpolate" ) )
Expand Down
17 changes: 17 additions & 0 deletions src/core/vectortile/qgsmapboxglstyleconverter.h
Expand Up @@ -397,6 +397,23 @@ class CORE_EXPORT QgsMapBoxGlStyleConverter
QString *defaultString SIP_OUT = nullptr );


/**
* Parses and converts a value list (e.g. an interpolate list).
*
* \warning This is private API only, and may change in future QGIS versions
*/
static QgsProperty parseValueList( const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1,
int maxOpacity = 255, QColor *defaultColor SIP_OUT = nullptr, double *defaultNumber SIP_OUT = nullptr );


/**
* Parses and converts a match function value list.
*
* \warning This is private API only, and may change in future QGIS versions
*/
static QgsProperty parseMatchList( const QVariantList &json, PropertyType type, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1,
int maxOpacity = 255, QColor *defaultColor SIP_OUT = nullptr, double *defaultNumber SIP_OUT = nullptr );

/**
* Interpolates a list which starts with the interpolate function.
*
Expand Down

0 comments on commit 229c240

Please sign in to comment.