Skip to content
Permalink
Browse files

Fix conversion of multiplied pixel sizes for some interpolated values…

…, improve interpolation expression results
  • Loading branch information
nyalldawson committed Sep 7, 2020
1 parent 4ba21e0 commit 93d25d61e7bfe7c95eaf28acf8a3484c894fe2b9
@@ -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``.
@@ -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
@@ -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" );
@@ -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 )
@@ -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.
@@ -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()
@@ -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],

0 comments on commit 93d25d6

Please sign in to comment.
You can’t perform that action at this time.