Skip to content

Commit

Permalink
Correctly parse interpolated text-anchor
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 10, 2020
1 parent 0694ae2 commit 5ee97c9
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 1 deletion.
Expand Up @@ -349,6 +349,19 @@ For ``json`` with intermediate stops it uses :py:func:`~QgsMapBoxGlStyleConverte
This is private API only, and may change in future QGIS versions
%End

static QgsProperty parseInterpolateStringByZoom( const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context,
const QVariantMap &conversionMap,
QString *defaultString /Out/ = 0 );
%Docstring
Interpolates a string by zoom.
For ``json`` with intermediate stops it uses :py:func:`~QgsMapBoxGlStyleConverter.parseStringStops` function.

.. warning::

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


static QString parsePointStops( double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1 );
%Docstring
Takes values from stops and uses either :py:func:`~QgsMapBoxGlStyleConverter.scale_linear` or :py:func:`~QgsMapBoxGlStyleConverter.scale_exp` functions
Expand All @@ -369,6 +382,21 @@ Parses a list of interpolation stops
:param context: conversion context
%End

static QString parseStringStops( const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context,
const QVariantMap &conversionMap,
QString *defaultString /Out/ = 0 );
%Docstring
Parses a list of interpolation stops containing string values.

:param stops: definition of interpolation stops
:param context: conversion context
:param conversionMap: map of input string to output expression value

:return: - converted expression
- defaultString: reasonable default value taken from stops
%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 Expand Up @@ -450,6 +478,14 @@ Converts a MapBox GL expression to a QGIS expression.
%Docstring
Retrieves the sprite image with the specified ``name``, taken from the specified ``context``.

The ``context`` must have valid sprite definitions and images set via :py:func:`QgsMapBoxGlStyleConversionContext.setSprites()`
prior to conversion.
%End

static QString retrieveSpriteAsBase64( const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &size );
%Docstring
Retrieves the sprite image with the specified ``name``, taken from the specified ``context`` as a base64 encoded value

The ``context`` must have valid sprite definitions and images set via :py:func:`QgsMapBoxGlStyleConversionContext.setSprites()`
prior to conversion.
%End
Expand Down
79 changes: 78 additions & 1 deletion src/core/vectortile/qgsmapboxglstyleconverter.cpp
Expand Up @@ -1046,7 +1046,41 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
{
if ( jsonLayout.contains( QStringLiteral( "text-anchor" ) ) )
{
const QString textAnchor = jsonLayout.value( QStringLiteral( "text-anchor" ) ).toString();
const QVariant jsonTextAnchor = jsonLayout.value( QStringLiteral( "text-anchor" ) );
QString textAnchor;

const QVariantMap conversionMap
{
{ QStringLiteral( "center" ), 4 },
{ QStringLiteral( "left" ), 5 },
{ QStringLiteral( "right" ), 3 },
{ QStringLiteral( "top" ), 7 },
{ QStringLiteral( "bottom" ), 1 },
{ QStringLiteral( "top-left" ), 8 },
{ QStringLiteral( "top-right" ), 6 },
{ QStringLiteral( "bottom-left" ), 2 },
{ QStringLiteral( "bottom-right" ), 0 },
};

switch ( jsonTextAnchor.type() )
{
case QVariant::String:
textAnchor = jsonTextAnchor.toString();
break;

case QVariant::List:
ddLabelProperties.setProperty( QgsPalLayerSettings::OffsetQuad, QgsProperty::fromExpression( parseStringStops( jsonTextAnchor.toList(), context, conversionMap, &textAnchor ) ) );
break;

case QVariant::Map:
ddLabelProperties.setProperty( QgsPalLayerSettings::OffsetQuad, parseInterpolateStringByZoom( jsonTextAnchor.toMap(), context, conversionMap, &textAnchor ) );
break;

default:
context.pushWarning( QObject::tr( "Skipping non-implemented text-anchor expression" ) );
break;
}

if ( textAnchor == QLatin1String( "center" ) )
labelSettings.quadOffset = QgsPalLayerSettings::QuadrantOver;
else if ( textAnchor == QLatin1String( "left" ) )
Expand All @@ -1066,6 +1100,37 @@ void QgsMapBoxGlStyleConverter::parseSymbolLayer( const QVariantMap &jsonLayer,
else if ( textAnchor == QLatin1String( "bottom-right" ) )
labelSettings.quadOffset = QgsPalLayerSettings::QuadrantAboveLeft;
}

QPointF textOffset;
if ( jsonLayout.contains( QStringLiteral( "text-offset" ) ) )
{
const QVariant jsonTextOffset = jsonLayout.value( QStringLiteral( "text-offset" ) );

// units are ems!
switch ( jsonTextOffset.type() )
{
case QVariant::Map:
ddLabelProperties.setProperty( QgsPalLayerSettings::OffsetXY, parseInterpolatePointByZoom( jsonTextOffset.toMap(), context, textSize, &textOffset ) );
break;

case QVariant::List:
case QVariant::StringList:
textOffset = QPointF( jsonTextOffset.toList().value( 0 ).toDouble() * textSize,
jsonTextOffset.toList().value( 1 ).toDouble() * textSize );
break;

default:
context.pushWarning( QObject::tr( "Skipping non-implemented fill-translate expression" ) );
break;
}

if ( !textOffset.isNull() )
{
labelSettings.offsetUnits = context.targetUnit();
labelSettings.xOffset = textOffset.x();
labelSettings.yOffset = textOffset.y();
}
}
}

if ( textSize >= 0 )
Expand Down Expand Up @@ -1368,6 +1433,18 @@ QgsProperty QgsMapBoxGlStyleConverter::parseInterpolatePointByZoom( const QVaria
return QgsProperty::fromExpression( scaleExpression );
}

QgsProperty QgsMapBoxGlStyleConverter::parseInterpolateStringByZoom( const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context,
const QVariantMap &conversionMap, QString *defaultString )
{
const QVariantList stops = json.value( QStringLiteral( "stops" ) ).toList();
if ( stops.empty() )
return QgsProperty();

QString scaleExpression = parseStringStops( stops, context, conversionMap, defaultString );

return QgsProperty::fromExpression( scaleExpression );
}

QString QgsMapBoxGlStyleConverter::parsePointStops( double base, const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context, double multiplier )
{
QString caseString = QStringLiteral( "CASE " );
Expand Down
26 changes: 26 additions & 0 deletions src/core/vectortile/qgsmapboxglstyleconverter.h
Expand Up @@ -353,6 +353,17 @@ class CORE_EXPORT QgsMapBoxGlStyleConverter
*/
static QgsProperty parseInterpolatePointByZoom( const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context, double multiplier = 1, QPointF *defaultPoint SIP_OUT = nullptr );

/**
* Interpolates a string by zoom.
* For \a json with intermediate stops it uses parseStringStops() function.
*
* \warning This is private API only, and may change in future QGIS versions
*/
static QgsProperty parseInterpolateStringByZoom( const QVariantMap &json, QgsMapBoxGlStyleConversionContext &context,
const QVariantMap &conversionMap,
QString *defaultString SIP_OUT = nullptr );


/**
* Takes values from stops and uses either scale_linear() or scale_exp() functions
* to interpolate point/offset values.
Expand All @@ -371,6 +382,21 @@ class CORE_EXPORT QgsMapBoxGlStyleConverter
*/
static QString parseStops( double base, const QVariantList &stops, double multiplier, QgsMapBoxGlStyleConversionContext &context );

/**
* Parses a list of interpolation stops containing string values.
*
* \param stops definition of interpolation stops
* \param context conversion context
* \param conversionMap map of input string to output expression value
* \param defaultString reasonable default value taken from stops
*
* \returns converted expression
*/
static QString parseStringStops( const QVariantList &stops, QgsMapBoxGlStyleConversionContext &context,
const QVariantMap &conversionMap,
QString *defaultString SIP_OUT = nullptr );


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

0 comments on commit 5ee97c9

Please sign in to comment.