Skip to content
Permalink
Browse files
[vectortile] Implement mapbox gl converter's line-pattern support
  • Loading branch information
nirvn committed Nov 20, 2021
1 parent 8e46f2c commit 3ef76e19dbeef99e3aab60d3f00b1946a883abaa
Showing with 104 additions and 27 deletions.
  1. +75 −27 src/core/vectortile/qgsmapboxglstyleconverter.cpp
  2. +29 −0 tests/src/python/test_qgsmapboxglconverter.py
@@ -428,14 +428,38 @@ bool QgsMapBoxGlStyleConverter::parseLineLayer( const QVariantMap &jsonLayer, Qg
return false;
}

QgsPropertyCollection ddProperties;
QString rasterLineSprite;

const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( "paint" ) ).toMap();
if ( jsonPaint.contains( QStringLiteral( "line-pattern" ) ) )
{
context.pushWarning( QObject::tr( "%1: Skipping unsupported line-pattern property" ).arg( context.layerId() ) );
return false;
}
const QVariant jsonLinePattern = jsonPaint.value( QStringLiteral( "line-pattern" ) );
switch ( jsonLinePattern.type() )
{
case QVariant::Map:
case QVariant::String:
{
QSize spriteSize;
QString spriteProperty, spriteSizeProperty;
rasterLineSprite = retrieveSpriteAsBase64( jsonLinePattern, context, spriteSize, spriteProperty, spriteSizeProperty );
ddProperties.setProperty( QgsSymbolLayer::PropertyFile, QgsProperty::fromExpression( spriteProperty ) );
break;
}

QgsPropertyCollection ddProperties;
case QVariant::List:
case QVariant::StringList:
default:
break;
}

if ( rasterLineSprite.isEmpty() )
{
// unsupported line-pattern definition, moving on
context.pushWarning( QObject::tr( "%1: Skipping unsupported line-pattern property" ).arg( context.layerId() ) );
return false;
}
}

// line color
QColor lineColor;
@@ -637,34 +661,58 @@ bool QgsMapBoxGlStyleConverter::parseLineLayer( const QVariantMap &jsonLayer, Qg
}

std::unique_ptr< QgsSymbol > symbol( std::make_unique< QgsLineSymbol >() );
QgsSimpleLineSymbolLayer *lineSymbol = dynamic_cast< QgsSimpleLineSymbolLayer * >( symbol->symbolLayer( 0 ) );
Q_ASSERT( lineSymbol ); // should not fail since QgsLineSymbol() constructor instantiates a QgsSimpleLineSymbolLayer

// set render units
symbol->setOutputUnit( context.targetUnit() );
lineSymbol->setOutputUnit( context.targetUnit() );
lineSymbol->setPenCapStyle( penCapStyle );
lineSymbol->setPenJoinStyle( penJoinStyle );
lineSymbol->setDataDefinedProperties( ddProperties );
lineSymbol->setOffset( lineOffset );
lineSymbol->setOffsetUnit( context.targetUnit() );

if ( lineOpacity != -1 )
{
symbol->setOpacity( lineOpacity );
}
if ( lineColor.isValid() )
{
lineSymbol->setColor( lineColor );
}
if ( lineWidth != -1 )
if ( !rasterLineSprite.isEmpty() )
{
lineSymbol->setWidth( lineWidth );
QgsRasterLineSymbolLayer *lineSymbol = new QgsRasterLineSymbolLayer( rasterLineSprite );
lineSymbol->setOutputUnit( context.targetUnit() );
lineSymbol->setPenCapStyle( penCapStyle );
lineSymbol->setPenJoinStyle( penJoinStyle );
lineSymbol->setDataDefinedProperties( ddProperties );
lineSymbol->setOffset( lineOffset );
lineSymbol->setOffsetUnit( context.targetUnit() );

if ( lineOpacity != -1 )
{
symbol->setOpacity( lineOpacity );
}
if ( lineWidth != -1 )
{
lineSymbol->setWidth( lineWidth );
}
symbol->changeSymbolLayer( 0, lineSymbol );
}
if ( !dashVector.empty() )
else
{
lineSymbol->setUseCustomDashPattern( true );
lineSymbol->setCustomDashVector( dashVector );
QgsSimpleLineSymbolLayer *lineSymbol = dynamic_cast< QgsSimpleLineSymbolLayer * >( symbol->symbolLayer( 0 ) );
Q_ASSERT( lineSymbol ); // should not fail since QgsLineSymbol() constructor instantiates a QgsSimpleLineSymbolLayer

// set render units
lineSymbol->setOutputUnit( context.targetUnit() );
lineSymbol->setPenCapStyle( penCapStyle );
lineSymbol->setPenJoinStyle( penJoinStyle );
lineSymbol->setDataDefinedProperties( ddProperties );
lineSymbol->setOffset( lineOffset );
lineSymbol->setOffsetUnit( context.targetUnit() );

if ( lineOpacity != -1 )
{
symbol->setOpacity( lineOpacity );
}
if ( lineColor.isValid() )
{
lineSymbol->setColor( lineColor );
}
if ( lineWidth != -1 )
{
lineSymbol->setWidth( lineWidth );
}
if ( !dashVector.empty() )
{
lineSymbol->setUseCustomDashPattern( true );
lineSymbol->setCustomDashVector( dashVector );
}
}

style.setGeometryType( QgsWkbTypes::LineGeometry );
@@ -694,6 +694,35 @@ def testParseLineDashArray(self):
self.assertEqual(dd_properties.property(QgsSymbolLayer.PropertyStrokeWidth).asExpression(), 'CASE WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 11 THEN scale_exp(@vector_tile_zoom,10,11,1.5,2,1.2) WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exp(@vector_tile_zoom,11,12,2,3,1.2) WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exp(@vector_tile_zoom,12,13,3,5,1.2) WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exp(@vector_tile_zoom,13,14,5,6,1.2) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exp(@vector_tile_zoom,14,16,6,10,1.2) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exp(@vector_tile_zoom,16,17,10,12,1.2) WHEN @vector_tile_zoom > 17 THEN 12 END')
self.assertEqual(dd_properties.property(QgsSymbolLayer.PropertyCustomDash).asExpression(), 'array_to_string(array_foreach(CASE WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 17 THEN array(1,1) WHEN @vector_tile_zoom > 17 THEN array(0.3,0.2) END,@element * (CASE WHEN @vector_tile_zoom > 10 AND @vector_tile_zoom <= 11 THEN scale_exp(@vector_tile_zoom,10,11,1.5,2,1.2) WHEN @vector_tile_zoom > 11 AND @vector_tile_zoom <= 12 THEN scale_exp(@vector_tile_zoom,11,12,2,3,1.2) WHEN @vector_tile_zoom > 12 AND @vector_tile_zoom <= 13 THEN scale_exp(@vector_tile_zoom,12,13,3,5,1.2) WHEN @vector_tile_zoom > 13 AND @vector_tile_zoom <= 14 THEN scale_exp(@vector_tile_zoom,13,14,5,6,1.2) WHEN @vector_tile_zoom > 14 AND @vector_tile_zoom <= 16 THEN scale_exp(@vector_tile_zoom,14,16,6,10,1.2) WHEN @vector_tile_zoom > 16 AND @vector_tile_zoom <= 17 THEN scale_exp(@vector_tile_zoom,16,17,10,12,1.2) WHEN @vector_tile_zoom > 17 THEN 12 END)), \';\')')

def testLinePattern(self):
""" Test line-pattern property """
context = QgsMapBoxGlStyleConversionContext()

image = QImage(QSize(1, 1), QImage.Format_ARGB32)
context.setSprites(image, {"foo": {"x": 0, "y": 0, "width": 1, "height": 1, "pixelRatio": 1}})
style = {
"id": "mountain range/ridge",
"type": "line",
"source": "esri",
"source-layer": "mountain range",
"filter": ["==", "_symbol", 1],
"minzoom": 13,
"layout": {
"line-join": "round"
},
"paint": {
"line-pattern": {"stops": [[13, "foo"], [15, "foo"]]},
"line-width": {"stops": [[14, 20], [15, 40]]}
}
}
has_renderer, rendererStyle = QgsMapBoxGlStyleConverter.parseLineLayer(style, context)
self.assertTrue(has_renderer)
self.assertEqual(rendererStyle.geometryType(), QgsWkbTypes.LineGeometry)
self.assertEqual(rendererStyle.symbol().symbolLayers()[0].layerType(), 'RasterLine')
dd_props = rendererStyle.symbol().symbolLayers()[0].dataDefinedProperties()
prop = dd_props.property(QgsSymbolLayer.PropertyFile)
self.assertTrue(prop.isActive())


if __name__ == '__main__':
unittest.main()

0 comments on commit 3ef76e1

Please sign in to comment.