Skip to content

Commit

Permalink
Convert interpolated icon marker sprites
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn authored and nyalldawson committed Sep 13, 2020
1 parent 499d1a6 commit 73e73c0
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 21 deletions.
Expand Up @@ -482,7 +482,7 @@ The ``context`` must have valid sprite definitions and images set via :py:func:`
prior to conversion.
%End

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

Expand Down
159 changes: 140 additions & 19 deletions src/core/vectortile/qgsmapboxglstyleconverter.cpp
Expand Up @@ -330,7 +330,8 @@ bool QgsMapBoxGlStyleConverter::parseFillLayer( const QVariantMap &jsonLayer, Qg
case QVariant::String:
{
QSize spriteSize;
const QString sprite = retrieveSpriteAsBase64( fillPatternJson.toString(), context, spriteSize );
QString spriteProperty, spriteSizeProperty;
const QString sprite = retrieveSpriteAsBase64( fillPatternJson, context, spriteSize, spriteProperty, spriteSizeProperty );
if ( !sprite.isEmpty() )
{
// when fill-pattern exists, set and insert QgsRasterFillSymbolLayer
Expand Down Expand Up @@ -1302,12 +1303,19 @@ bool QgsMapBoxGlStyleConverter::parseSymbolLayerAsRenderer( const QVariantMap &j

QgsRasterMarkerSymbolLayer *markerLayer = new QgsRasterMarkerSymbolLayer( );
QSize spriteSize;
const QString sprite = retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( "icon-image" ) ).toString(), context, spriteSize );
QString spriteProperty, spriteSizeProperty;
const QString sprite = retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( "icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
if ( !sprite.isNull() )
{
markerLayer->setPath( sprite );
markerLayer->setSize( context.pixelSizeConversionFactor() * spriteSize.width() );
markerLayer->setSize( spriteSize.width() );
markerLayer->setSizeUnit( context.targetUnit() );

if ( !spriteProperty.isEmpty() )
{
markerDdProperties.setProperty( QgsSymbolLayer::PropertyName, QgsProperty::fromExpression( spriteProperty ) );
markerDdProperties.setProperty( QgsSymbolLayer::PropertyWidth, QgsProperty::fromExpression( spriteSizeProperty ) );
}
}

markerLayer->setDataDefinedProperties( markerDdProperties );
Expand All @@ -1329,15 +1337,22 @@ bool QgsMapBoxGlStyleConverter::parseSymbolLayerAsRenderer( const QVariantMap &j
const QVariantMap jsonPaint = jsonLayer.value( QStringLiteral( "paint" ) ).toMap();

QSize spriteSize;
const QString sprite = retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( "icon-image" ) ).toString(), context, spriteSize );
QString spriteProperty, spriteSizeProperty;
const QString sprite = retrieveSpriteAsBase64( jsonLayout.value( QStringLiteral( "icon-image" ) ), context, spriteSize, spriteProperty, spriteSizeProperty );
if ( !sprite.isEmpty() )
{
QgsRasterMarkerSymbolLayer *rasterMarker = new QgsRasterMarkerSymbolLayer( );
rasterMarker->setPath( sprite );
rasterMarker->setSize( context.pixelSizeConversionFactor() * spriteSize.width() );
rasterMarker->setSize( spriteSize.width() );
rasterMarker->setSizeUnit( context.targetUnit() );

QgsPropertyCollection markerDdProperties;
if ( !spriteProperty.isEmpty() )
{
markerDdProperties.setProperty( QgsSymbolLayer::PropertyName, QgsProperty::fromExpression( spriteProperty ) );
markerDdProperties.setProperty( QgsSymbolLayer::PropertyWidth, QgsProperty::fromExpression( spriteSizeProperty ) );
}

double rotation = 0.0;
if ( jsonLayout.contains( QStringLiteral( "icon-rotate" ) ) )
{
Expand Down Expand Up @@ -1999,24 +2014,130 @@ QImage QgsMapBoxGlStyleConverter::retrieveSprite( const QString &name, QgsMapBox
return sprite;
}

QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &size )
QString QgsMapBoxGlStyleConverter::retrieveSpriteAsBase64( const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &size, QString &spriteProperty, QString &spriteSizeProperty )
{
const QImage sprite = retrieveSprite( name, context );
if ( !sprite.isNull() )
QString returnPath;
switch ( value.type() )
{
size = sprite.size();
QByteArray blob;
QBuffer buffer( &blob );
buffer.open( QIODevice::WriteOnly );
sprite.save( &buffer, "PNG" );
buffer.close();
QByteArray encoded = blob.toBase64();
case QVariant::String:
{
spriteProperty.clear();
spriteSizeProperty.clear();
const QImage sprite = retrieveSprite( value.toString(), context );
if ( !sprite.isNull() )
{
size = sprite.size() * context.pixelSizeConversionFactor();
QByteArray blob;
QBuffer buffer( &blob );
buffer.open( QIODevice::WriteOnly );
sprite.save( &buffer, "PNG" );
buffer.close();
QByteArray encoded = blob.toBase64();

QString path( encoded );
path.prepend( QLatin1String( "base64:" ) );
returnPath = path;
}
break;
}

case QVariant::Map:
{
const QVariantList stops = value.toMap().value( QStringLiteral( "stops" ) ).toList();
if ( stops.size() == 0 )
break;

QString path;
QImage sprite;

QString path( encoded );
path.prepend( QLatin1String( "base64:" ) );
return path;
sprite = retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context );
if ( !sprite.isNull() )
{
size = sprite.size() * context.pixelSizeConversionFactor();
QByteArray blob;
QBuffer buffer( &blob );
buffer.open( QIODevice::WriteOnly );
sprite.save( &buffer, "PNG" );
buffer.close();
QByteArray encoded = blob.toBase64();

path = QString( encoded );
path.prepend( QLatin1String( "base64:" ) );
returnPath = path;
}
spriteProperty = QStringLiteral( "CASE WHEN @zoom_level < %1 THEN '%2'" )
.arg( stops.value( 0 ).toList().value( 0 ).toString() )
.arg( path );
spriteSizeProperty = QStringLiteral( "CASE WHEN @zoom_level < %1 THEN %2" )
.arg( stops.value( 0 ).toList().value( 0 ).toString() )
.arg( size.width() );

QSize s;
for ( int i = 0; i < stops.size() - 1; ++i )
{
;
sprite = retrieveSprite( stops.value( 0 ).toList().value( 1 ).toString(), context );
if ( !sprite.isNull() )
{
s = sprite.size() * context.pixelSizeConversionFactor();
QByteArray blob;
QBuffer buffer( &blob );
buffer.open( QIODevice::WriteOnly );
sprite.save( &buffer, "PNG" );
buffer.close();
QByteArray encoded = blob.toBase64();

path = QString( encoded );
path.prepend( QLatin1String( "base64:" ) );
}
else
{
path.clear();
}

spriteProperty += QStringLiteral( " WHEN @zoom_level >= %1 AND @zoom_level < %2 "
"THEN '%3'" )
.arg( stops.value( i ).toList().value( 0 ).toString(),
stops.value( i + 1 ).toList().value( 0 ).toString(),
path );
spriteSizeProperty += QStringLiteral( " WHEN @zoom_level >= %1 AND @zoom_level < %2 "
"THEN %3" )
.arg( stops.value( i ).toList().value( 0 ).toString(),
stops.value( i + 1 ).toList().value( 0 ).toString() )
.arg( s.width() );
}
sprite = retrieveSprite( stops.last().toList().value( 1 ).toString(), context );
if ( !sprite.isNull() )
{
s = sprite.size() * context.pixelSizeConversionFactor();
QByteArray blob;
QBuffer buffer( &blob );
buffer.open( QIODevice::WriteOnly );
sprite.save( &buffer, "PNG" );
buffer.close();
QByteArray encoded = blob.toBase64();

path = QString( encoded );
path.prepend( QLatin1String( "base64:" ) );
}

spriteProperty += QStringLiteral( " WHEN @zoom_level >= %1 "
"THEN '%2' END" )
.arg( stops.last().toList().value( 0 ).toString() )
.arg( path );
spriteSizeProperty += QStringLiteral( " WHEN @zoom_level >= %1 "
"THEN %2 END" )
.arg( stops.last().toList().value( 0 ).toString() )
.arg( s.width() );
break;
}

default:
context.pushWarning( QObject::tr( "Skipping unsupported sprite part" ) );
break;
}
return QString();

return returnPath;
}

QString QgsMapBoxGlStyleConverter::parseValue( const QVariant &value, QgsMapBoxGlStyleConversionContext &context )
Expand Down
2 changes: 1 addition & 1 deletion src/core/vectortile/qgsmapboxglstyleconverter.h
Expand Up @@ -473,7 +473,7 @@ class CORE_EXPORT QgsMapBoxGlStyleConverter
* The \a context must have valid sprite definitions and images set via QgsMapBoxGlStyleConversionContext::setSprites()
* prior to conversion.
*/
static QString retrieveSpriteAsBase64( const QString &name, QgsMapBoxGlStyleConversionContext &context, QSize &size );
static QString retrieveSpriteAsBase64( const QVariant &value, QgsMapBoxGlStyleConversionContext &context, QSize &size, QString &spriteProperty, QString &spriteSizeProperty );

private:

Expand Down

0 comments on commit 73e73c0

Please sign in to comment.