Skip to content

Commit

Permalink
Fix conversion of multiplied pixel sizes for some interpolated values…
Browse files Browse the repository at this point in the history
…, improve interpolation expression results
  • Loading branch information
nyalldawson committed Sep 7, 2020
1 parent 4ba21e0 commit 93d25d6
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 21 deletions.
Expand Up @@ -337,7 +337,7 @@ Takes a QColor object and returns HSLA components in required format for QGIS :p
This is private API only, and may change in future QGIS versions
%End

static QString interpolateExpression( int zoomMin, int zoomMax, double valueMin, double valueMax, double base );
static QString interpolateExpression( int zoomMin, int zoomMax, double valueMin, double valueMax, double base, double multiplier = 1 );
%Docstring
Generates an interpolation for values between ``valueMin`` and ``valueMax``, scaled between the
ranges ``zoomMin`` to ``zoomMax``.
Expand Down
38 changes: 24 additions & 14 deletions src/core/vectortile/qgsmapboxglstyleconverter.cpp
Expand Up @@ -1017,17 +1017,19 @@ QgsProperty QgsMapBoxGlStyleConverter::parseInterpolateByZoom( const QVariantMap
{
if ( base == 1 )
{
scaleExpression = QStringLiteral( "scale_linear(@zoom_level, %1, %2, %3, %4) * %5" ).arg( stops.value( 0 ).toList().value( 0 ).toString(),
scaleExpression = QStringLiteral( "scale_linear(@zoom_level, %1, %2, %3, %4)" ).arg( stops.value( 0 ).toList().value( 0 ).toString(),
stops.last().toList().value( 0 ).toString(),
stops.value( 0 ).toList().value( 1 ).toString(),
stops.last().toList().value( 1 ).toString() ).arg( multiplier );
stops.last().toList().value( 1 ).toString() );
if ( multiplier != 1.0 )
scaleExpression = QStringLiteral( "%1 * %2" ).arg( scaleExpression ).arg( multiplier );
}
else
{
scaleExpression = interpolateExpression( stops.value( 0 ).toList().value( 0 ).toInt(),
stops.last().toList().value( 0 ).toInt(),
stops.value( 0 ).toList().value( 1 ).toInt(),
stops.last().toList().value( 1 ).toInt(), base ) + QStringLiteral( "* %1" ).arg( multiplier );
stops.last().toList().value( 1 ).toInt(), base, multiplier );
}
}
else
Expand Down Expand Up @@ -1147,19 +1149,22 @@ QString QgsMapBoxGlStyleConverter::parseStops( double base, const QVariantList &
{
// base = 1 -> scale_linear
caseString += QStringLiteral( "WHEN @zoom_level > %1 AND @zoom_level <= %2 "
"THEN scale_linear(@zoom_level, %1, %2, %3, %4) "
"* %5 " ).arg( bz.toString(),
"THEN scale_linear(@zoom_level, %1, %2, %3, %4) " ).arg( bz.toString(),
tz.toString(),
bv.toString(),
tv.toString() ).arg( multiplier );
tv.toString() );
if ( multiplier != 1.0 )
{
caseString += QStringLiteral( "* %1 " ).arg( multiplier );
}
}
else
{
// base != 1 -> scale_exp
caseString += QStringLiteral( "WHEN @zoom_level > %1 AND @zoom_level <= %2 "
"THEN %3 * %4 " ).arg( bz.toString(),
"THEN %3 " ).arg( bz.toString(),
tz.toString(),
interpolateExpression( bz.toInt(), tz.toInt(), bv.toDouble(), tv.toDouble(), base ) ).arg( multiplier );
interpolateExpression( bz.toInt(), tz.toInt(), bv.toDouble(), tv.toDouble(), base, multiplier ) );
}
}
caseString += QStringLiteral( "END" );
Expand Down Expand Up @@ -1240,13 +1245,18 @@ void QgsMapBoxGlStyleConverter::colorAsHslaComponents( const QColor &color, int
alpha = color.alpha();
}

QString QgsMapBoxGlStyleConverter::interpolateExpression( int zoomMin, int zoomMax, double valueMin, double valueMax, double base )
QString QgsMapBoxGlStyleConverter::interpolateExpression( int zoomMin, int zoomMax, double valueMin, double valueMax, double base, double multiplier )
{
return QStringLiteral( "%1 + %2 * (%3^(@zoom_level-%4)-1)/(%3^(%5-%4)-1)" ).arg( valueMin )
.arg( valueMax - valueMin )
.arg( base )
.arg( zoomMin )
.arg( zoomMax );
const QString expression = QStringLiteral( "%1 + %2 * (%3^(@zoom_level-%4)-1)/(%3^(%5-%4)-1)" ).arg( valueMin )
.arg( valueMax - valueMin )
.arg( base )
.arg( zoomMin )
.arg( zoomMax );

if ( multiplier != 1 )
return QStringLiteral( "(%1) * %2" ).arg( expression ).arg( multiplier );
else
return expression;
}

Qt::PenCapStyle QgsMapBoxGlStyleConverter::parseCapStyle( const QString &style )
Expand Down
2 changes: 1 addition & 1 deletion src/core/vectortile/qgsmapboxglstyleconverter.h
Expand Up @@ -346,7 +346,7 @@ class CORE_EXPORT QgsMapBoxGlStyleConverter
*
* \warning This is private API only, and may change in future QGIS versions
*/
static QString interpolateExpression( int zoomMin, int zoomMax, double valueMin, double valueMax, double base );
static QString interpolateExpression( int zoomMin, int zoomMax, double valueMin, double valueMax, double base, double multiplier = 1 );

/**
* Converts a value to Qt::PenCapStyle enum from JSON value.
Expand Down
20 changes: 15 additions & 5 deletions tests/src/python/test_qgsmapboxglconverter.py
Expand Up @@ -71,11 +71,13 @@ def testParseInterpolateColorByZoom(self):
def testParseStops(self):
conversion_context = QgsMapBoxGlStyleConversionContext()
self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1, [[1, 10], [2, 20], [5, 100]], 1, conversion_context),
'CASE WHEN @zoom_level > 1 AND @zoom_level <= 2 THEN scale_linear(@zoom_level, 1, 2, 10, 20) * 1 WHEN @zoom_level > 2 AND @zoom_level <= 5 THEN scale_linear(@zoom_level, 2, 5, 20, 100) * 1 END')
'CASE WHEN @zoom_level > 1 AND @zoom_level <= 2 THEN scale_linear(@zoom_level, 1, 2, 10, 20) WHEN @zoom_level > 2 AND @zoom_level <= 5 THEN scale_linear(@zoom_level, 2, 5, 20, 100) END')
self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1.5, [[1, 10], [2, 20], [5, 100]], 1, conversion_context),
'CASE WHEN @zoom_level > 1 AND @zoom_level <= 2 THEN 10 + 10 * (1.5^(@zoom_level-1)-1)/(1.5^(2-1)-1) * 1 WHEN @zoom_level > 2 AND @zoom_level <= 5 THEN 20 + 80 * (1.5^(@zoom_level-2)-1)/(1.5^(5-2)-1) * 1 END')
'CASE WHEN @zoom_level > 1 AND @zoom_level <= 2 THEN 10 + 10 * (1.5^(@zoom_level-1)-1)/(1.5^(2-1)-1) WHEN @zoom_level > 2 AND @zoom_level <= 5 THEN 20 + 80 * (1.5^(@zoom_level-2)-1)/(1.5^(5-2)-1) END')
self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1, [[1, 10], [2, 20], [5, 100]], 8, conversion_context),
'CASE WHEN @zoom_level > 1 AND @zoom_level <= 2 THEN scale_linear(@zoom_level, 1, 2, 10, 20) * 8 WHEN @zoom_level > 2 AND @zoom_level <= 5 THEN scale_linear(@zoom_level, 2, 5, 20, 100) * 8 END')
self.assertEqual(QgsMapBoxGlStyleConverter.parseStops(1.5, [[1, 10], [2, 20], [5, 100]], 8, conversion_context),
'CASE WHEN @zoom_level > 1 AND @zoom_level <= 2 THEN (10 + 10 * (1.5^(@zoom_level-1)-1)/(1.5^(2-1)-1)) * 8 WHEN @zoom_level > 2 AND @zoom_level <= 5 THEN (20 + 80 * (1.5^(@zoom_level-2)-1)/(1.5^(5-2)-1)) * 8 END')

def testInterpolateByZoom(self):
conversion_context = QgsMapBoxGlStyleConversionContext()
Expand All @@ -85,23 +87,31 @@ def testInterpolateByZoom(self):
[250, 22]]
}, conversion_context)
self.assertEqual(prop.expressionString(),
'CASE WHEN @zoom_level > 0 AND @zoom_level <= 150 THEN scale_linear(@zoom_level, 0, 150, 11, 15) * 1 WHEN @zoom_level > 150 AND @zoom_level <= 250 THEN scale_linear(@zoom_level, 150, 250, 15, 22) * 1 END')
'CASE WHEN @zoom_level > 0 AND @zoom_level <= 150 THEN scale_linear(@zoom_level, 0, 150, 11, 15) WHEN @zoom_level > 150 AND @zoom_level <= 250 THEN scale_linear(@zoom_level, 150, 250, 15, 22) END')
self.assertEqual(default_val, 11.0)
prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 1,
'stops': [[0, 11],
[150, 15]]
}, conversion_context)
self.assertEqual(prop.expressionString(),
'scale_linear(@zoom_level, 0, 150, 11, 15) * 1')
'scale_linear(@zoom_level, 0, 150, 11, 15)')
self.assertEqual(default_val, 11.0)
prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 2,
'stops': [[0, 11],
[150, 15]]
}, conversion_context)
self.assertEqual(prop.expressionString(),
'11 + 4 * (2^(@zoom_level-0)-1)/(2^(150-0)-1)* 1')
'11 + 4 * (2^(@zoom_level-0)-1)/(2^(150-0)-1)')
self.assertEqual(default_val, 11.0)

prop, default_val = QgsMapBoxGlStyleConverter.parseInterpolateByZoom({'base': 2,
'stops': [[0, 11],
[150, 15]]
}, conversion_context, multiplier=5)
self.assertEqual(prop.expressionString(),
'(11 + 4 * (2^(@zoom_level-0)-1)/(2^(150-0)-1)) * 5')
self.assertEqual(default_val, 55.0)

def testInterpolateOpacityByZoom(self):
self.assertEqual(QgsMapBoxGlStyleConverter.parseInterpolateOpacityByZoom({'base': 1,
'stops': [[0, 0.1],
Expand Down

0 comments on commit 93d25d6

Please sign in to comment.