Skip to content

Commit

Permalink
Added widget wrapper, added two separate algorithms (xyz + mbtiles)
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed May 8, 2020
1 parent 04941ab commit 49f832a
Show file tree
Hide file tree
Showing 16 changed files with 1,024 additions and 345 deletions.
Expand Up @@ -96,6 +96,11 @@ Emitted when the selection changes in the widget.
void addOption( const QVariant &value, const QString &title, bool selected, bool updateExistingTitle = false );
%Docstring
Adds a new option to the widget.
%End

QListView *listView() const;
%Docstring
Returns pointer to the list view
%End

};
Expand Down
249 changes: 127 additions & 122 deletions src/analysis/processing/qgsalgorithmwritevectortiles.cpp
Expand Up @@ -15,181 +15,186 @@

#include "qgsalgorithmwritevectortiles.h"

#include "qgsprocessingparametervectortilewriterlayers.h"
#include "qgsvectorlayer.h"
#include "qgsvectortilewriter.h"

///@cond PRIVATE


class QgsProcessingParameterVectorTileWriterLayers : public QgsProcessingParameterDefinition
QString QgsWriteVectorTilesBaseAlgorithm::group() const
{
public:
QgsProcessingParameterVectorTileWriterLayers( const QString &name, const QString &description = QString() )
: QgsProcessingParameterDefinition( name, description, QVariant(), false ) {}

static QString typeName() { return QStringLiteral( "vectortilewriterlayers" ); }
QgsProcessingParameterDefinition *clone() const override
{
return new QgsProcessingParameterVectorTileWriterLayers( *this );
}
QString type() const override { return typeName(); }
return QObject::tr( "Vector tiles" );
}

bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context ) const override
{
if ( !input.isValid() )
return mFlags & FlagOptional;
QString QgsWriteVectorTilesBaseAlgorithm::groupId() const
{
return QStringLiteral( "vectortiles" );
}

if ( input.type() != QVariant::List )
return false;
QString QgsWriteVectorTilesBaseAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm exports one or more vector layers to vector tiles - a data format optimized for fast map rendering and small data size." );
}

const QVariantList inputList = input.toList();
for ( const QVariant &inputItem : inputList )
{
if ( inputItem.type() != QVariant::Map )
return false;
QVariantMap inputItemMap = inputItem.toMap();
void QgsWriteVectorTilesBaseAlgorithm::addBaseParameters()
{
addParameter( new QgsProcessingParameterVectorTileWriterLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ) ) );

// "layer" is required - pointing to a vector layer
if ( !inputItemMap.contains( "layer" ) )
return false;
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MIN_ZOOM" ), QObject::tr( "Minimum zoom level" ), QgsProcessingParameterNumber::Integer, 0, false, 0, 24 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MAX_ZOOM" ), QObject::tr( "Maximum zoom level" ), QgsProcessingParameterNumber::Integer, 3, false, 0, 24 ) );

QVariant inputItemLayer = inputItemMap["layer"];
// optional extent
addParameter( new QgsProcessingParameterExtent( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ), QVariant(), true ) );
}

if ( qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( inputItemLayer ) ) )
continue;
QVariantMap QgsWriteVectorTilesBaseAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
int minZoom = parameterAsInt( parameters, QStringLiteral( "MIN_ZOOM" ), context );
int maxZoom = parameterAsInt( parameters, QStringLiteral( "MAX_ZOOM" ), context );

if ( !QgsProcessingUtils::mapLayerFromString( inputItemLayer.toString(), *context ) )
return false;
}
QVariant layersVariant = parameters.value( parameterDefinition( QStringLiteral( "LAYERS" ) )->name() );
const QList<QgsVectorTileWriter::Layer> layers = QgsProcessingParameterVectorTileWriterLayers::parameterAsLayers( layersVariant, context );

return true;
for ( const QgsVectorTileWriter::Layer &layer : layers )
{
if ( !layer.layer() )
throw QgsProcessingException( QObject::tr( "Unknown input layer" ) );
}

// TODO: anything else?
// - valueAsPythonString()
// - asScriptCode()
// - asPythonString()
QgsVectorTileWriter writer;
QVariantMap outputs;
prepareWriter( writer, parameters, context, outputs );

writer.setMinZoom( minZoom );
writer.setMaxZoom( maxZoom );
writer.setLayers( layers );
writer.setTransformContext( context.transformContext() );

static QList<QgsVectorTileWriter::Layer> parameterAsLayers( const QVariant &layersVariant, QgsProcessingContext &context )
if ( parameters.contains( QStringLiteral( "EXTENT" ) ) )
{
QList<QgsVectorTileWriter::Layer> layers;
const QVariantList layersVariantList = layersVariant.toList();
for ( const QVariant &layerItem : layersVariantList )
{
QVariantMap layerVariantMap = layerItem.toMap();
QVariant layerVariant = layerVariantMap["layer"];

QgsVectorLayer *inputLayer = nullptr;
if ( ( inputLayer = qobject_cast< QgsVectorLayer * >( qvariant_cast<QObject *>( layerVariant ) ) ) )
{
// good
}
else if ( ( inputLayer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerVariant.toString(), context ) ) ) )
{
// good
}
else
{
// bad
throw QgsProcessingException( "unknown input layer" );
}

QgsVectorTileWriter::Layer writerLayer( inputLayer );
if ( layerVariantMap.contains( "filterExpression" ) )
writerLayer.setFilterExpression( layerVariantMap["filterExpression"].toString() );
if ( layerVariantMap.contains( "minZoom" ) )
writerLayer.setMinZoom( layerVariantMap["minZoom"].toInt() );
if ( layerVariantMap.contains( "maxZoom" ) )
writerLayer.setMaxZoom( layerVariantMap["maxZoom"].toInt() );
if ( layerVariantMap.contains( "layerName" ) )
writerLayer.setLayerName( layerVariantMap["layerName"].toString() );
layers << writerLayer;
}
return layers;
QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context, QgsCoordinateReferenceSystem( "EPSG:3857" ) );
writer.setExtent( extent );
}

};
bool res = writer.writeTiles( feedback );

if ( !res )
throw QgsProcessingException( QObject::tr( "Failed to write vector tiles: " ) + writer.errorMessage() );

return outputs;
}

QString QgsWriteVectorTilesAlgorithm::name() const
//
// QgsWriteVectorTilesXyzAlgorithm
//

QString QgsWriteVectorTilesXyzAlgorithm::name() const
{
return QStringLiteral( "writevectortiles" );
return QStringLiteral( "writevectortiles_xyz" );
}

QString QgsWriteVectorTilesAlgorithm::displayName() const
QString QgsWriteVectorTilesXyzAlgorithm::displayName() const
{
return QObject::tr( "Write Vector Tiles" );
return QObject::tr( "Write Vector Tiles (XYZ)" );
}

QString QgsWriteVectorTilesAlgorithm::group() const
QgsProcessingAlgorithm *QgsWriteVectorTilesXyzAlgorithm::createInstance() const
{
return QObject::tr( "Vector tiles" );
return new QgsWriteVectorTilesXyzAlgorithm();
}

QString QgsWriteVectorTilesAlgorithm::groupId() const
void QgsWriteVectorTilesXyzAlgorithm::initAlgorithm( const QVariantMap & )
{
return QStringLiteral( "vectortiles" );
addParameter( new QgsProcessingParameterFolderDestination( QStringLiteral( "OUTPUT_DIR" ), QObject::tr( "Output directry" ) ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "XYZ_TEMPLATE" ), QObject::tr( "File template" ), QStringLiteral( "{z}/{x}/{y}.pbf" ) ) );

addBaseParameters();
}

QString QgsWriteVectorTilesAlgorithm::shortHelpString() const
void QgsWriteVectorTilesXyzAlgorithm::prepareWriter( QgsVectorTileWriter &writer, const QVariantMap &parameters, QgsProcessingContext &context, QVariantMap &outputs )
{
return QObject::tr( "blah blah" ); // TODO
QString outputDir = parameterAsString( parameters, QStringLiteral( "OUTPUT_DIR" ), context );
QString xyzTemplate = parameterAsString( parameters, QStringLiteral( "XYZ_TEMPLATE" ), context );
QgsDataSourceUri dsUri;
dsUri.setParam( QStringLiteral( "type" ), QStringLiteral( "xyz" ) );
dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( outputDir + "/" + xyzTemplate ).toString() );
QString uri = dsUri.encodedUri();

writer.setDestinationUri( uri );

outputs.insert( QStringLiteral( "OUTPUT_DIR" ), outputDir );
}

QgsProcessingAlgorithm *QgsWriteVectorTilesAlgorithm::createInstance() const
//
// QgsWriteVectorTilesMbtilesAlgorithm
//

QString QgsWriteVectorTilesMbtilesAlgorithm::name() const
{
return new QgsWriteVectorTilesAlgorithm();
return QStringLiteral( "writevectortiles_mbtiles" );
}

void QgsWriteVectorTilesAlgorithm::initAlgorithm( const QVariantMap & )
QString QgsWriteVectorTilesMbtilesAlgorithm::displayName() const
{
addParameter( new QgsProcessingParameterVectorTileWriterLayers( "LAYERS", QObject::tr("Input layers") ) );
return QObject::tr( "Write Vector Tiles (MBTiles)" );
}

addParameter( new QgsProcessingParameterString( "XYZ_TEMPLATE", QObject::tr("File template"), "/home/qgis/{z}/{x}/{y}.pbf" ) );
// TODO maybe use this:
// addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination GeoPackage" ), QObject::tr( "GeoPackage files (*.gpkg)" ) ) );
QgsProcessingAlgorithm *QgsWriteVectorTilesMbtilesAlgorithm::createInstance() const
{
return new QgsWriteVectorTilesMbtilesAlgorithm();
}

addParameter( new QgsProcessingParameterNumber( "MIN_ZOOM", QObject::tr("Minimum zoom level"), QgsProcessingParameterNumber::Integer, 0, false, 0, 24 ) );
addParameter( new QgsProcessingParameterNumber( "MAX_ZOOM", QObject::tr("Maximum zoom level"), QgsProcessingParameterNumber::Integer, 3, false, 0, 24 ) );
void QgsWriteVectorTilesMbtilesAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination MBTiles" ), QObject::tr( "MBTiles files (*.mbtiles)" ) ) );

// optional extent
addParameter( new QgsProcessingParameterExtent( "EXTENT", QObject::tr("Extent"), QVariant(), true ) );
addBaseParameters();

// TODO: optional metadata (only for MBTiles? and with concrete values rather than single QVariantMap?)
// optional metadata for MBTiles
addParameter( new QgsProcessingParameterString( QStringLiteral( "META_NAME" ), QObject::tr( "Metadata: Name" ), QVariant(), false, true ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "META_DESCRIPTION" ), QObject::tr( "Metadata: Description" ), QVariant(), false, true ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "META_ATTRIBUTION" ), QObject::tr( "Metadata: Attribution" ), QVariant(), false, true ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "META_VERSION" ), QObject::tr( "Metadata: Version" ), QVariant(), false, true ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "META_TYPE" ), QObject::tr( "Metadata: Type" ), QVariant(), false, true ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "META_CENTER" ), QObject::tr( "Metadata: Center" ), QVariant(), false, true ) );
}

QVariantMap QgsWriteVectorTilesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
void QgsWriteVectorTilesMbtilesAlgorithm::prepareWriter( QgsVectorTileWriter &writer, const QVariantMap &parameters, QgsProcessingContext &context, QVariantMap &outputs )
{
int minZoom = parameterAsInt( parameters, QStringLiteral( "MIN_ZOOM" ), context );
int maxZoom = parameterAsInt( parameters, QStringLiteral( "MAX_ZOOM" ), context );

// prepare output URI
QString xyzTemplate = parameterAsString( parameters, QStringLiteral( "XYZ_TEMPLATE" ), context );
QString outputFile = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT" ), context );
QgsDataSourceUri dsUri;
dsUri.setParam( "type", "xyz" );
dsUri.setParam( "url", QUrl::fromLocalFile( xyzTemplate ).toString() );
dsUri.setParam( QStringLiteral( "type" ), QStringLiteral( "mbtiles" ) );
dsUri.setParam( QStringLiteral( "url" ), outputFile );
QString uri = dsUri.encodedUri();

QVariant layersVariant = parameters.value( parameterDefinition( QStringLiteral( "LAYERS" ) )->name() );
QList<QgsVectorTileWriter::Layer> layers = QgsProcessingParameterVectorTileWriterLayers::parameterAsLayers( layersVariant, context );

QgsVectorTileWriter writer;
writer.setDestinationUri( uri );
writer.setMinZoom( minZoom );
writer.setMaxZoom( maxZoom );
writer.setLayers( layers );
writer.setTransformContext( context.transformContext() );

if ( parameters.contains( "EXTENT" ) )
{
QgsRectangle extent = parameterAsExtent( parameters, "EXTENT", context, QgsCoordinateReferenceSystem( "EPSG:3857" ) );
writer.setExtent( extent );
}

bool res = writer.writeTiles( feedback );

QVariantMap outputs;
outputs["RESULT"] = res;
return outputs;
QString metaName = parameterAsString( parameters, QStringLiteral( "META_NAME" ), context );
QString metaDesciption = parameterAsString( parameters, QStringLiteral( "META_DESCRIPTION" ), context );
QString metaAttribution = parameterAsString( parameters, QStringLiteral( "META_ATTRIBUTION" ), context );
QString metaVersion = parameterAsString( parameters, QStringLiteral( "META_VERSION" ), context );
QString metaType = parameterAsString( parameters, QStringLiteral( "META_TYPE" ), context );
QString metaCenter = parameterAsString( parameters, QStringLiteral( "META_CENTER" ), context );

QVariantMap meta;
if ( !metaName.isEmpty() )
meta["name"] = metaName;
if ( !metaDesciption.isEmpty() )
meta["description"] = metaDesciption;
if ( !metaAttribution.isEmpty() )
meta["attribution"] = metaAttribution;
if ( !metaVersion.isEmpty() )
meta["version"] = metaVersion;
if ( !metaType.isEmpty() )
meta["type"] = metaType;
if ( !metaCenter.isEmpty() )
meta["center"] = metaCenter;

writer.setMetadata( meta );

outputs.insert( QStringLiteral( "OUTPUT" ), outputFile );
}


///@endcond
48 changes: 39 additions & 9 deletions src/analysis/processing/qgsalgorithmwritevectortiles.h
Expand Up @@ -20,30 +20,60 @@
#define SIP_NO_FILE

#include "qgsprocessingalgorithm.h"
//#include "qgsapplication.h"

///@cond PRIVATE

class QgsWriteVectorTilesAlgorithm : public QgsProcessingAlgorithm
class QgsVectorTileWriter;


class QgsWriteVectorTilesBaseAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsWriteVectorTilesAlgorithm() = default;
// TODO: icon?
//QIcon icon() const override { return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmUnion.svg" ) ); }
//QString svgIconPath() const override { return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmUnion.svg" ) ); }
QString name() const override;
QString displayName() const override;

QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;

protected:
QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

void addBaseParameters();

virtual void prepareWriter( QgsVectorTileWriter &writer, const QVariantMap &parameters, QgsProcessingContext &context, QVariantMap &outputs ) = 0;

};


class QgsWriteVectorTilesXyzAlgorithm : public QgsWriteVectorTilesBaseAlgorithm
{
public:

QString name() const override;
QString displayName() const override;

protected:
QgsProcessingAlgorithm *createInstance() const override;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QVariantMap processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

void prepareWriter( QgsVectorTileWriter &writer, const QVariantMap &parameters, QgsProcessingContext &context, QVariantMap &outputs ) override;
};


class QgsWriteVectorTilesMbtilesAlgorithm : public QgsWriteVectorTilesBaseAlgorithm
{
public:

QString name() const override;
QString displayName() const override;

protected:
QgsProcessingAlgorithm *createInstance() const override;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;

void prepareWriter( QgsVectorTileWriter &writer, const QVariantMap &parameters, QgsProcessingContext &context, QVariantMap &outputs ) override;
};


///@endcond PRIVATE

#endif // QGSWRITEVECTORTILESALGORITHM_H

0 comments on commit 49f832a

Please sign in to comment.