Skip to content

Commit a8eee62

Browse files
committed
[FEATURE][processing] Package layers algorithm
Allows multiple vector layers to be collected together into a geopackage database output Previously all existing methods avilable in QGIS rely on adding layers one-at-a-time, which is tedious for large numbers of layers. Sponsored by SMEC
1 parent e6d86bb commit a8eee62

File tree

4 files changed

+234
-0
lines changed

4 files changed

+234
-0
lines changed

src/analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ SET(QGIS_ANALYSIS_SRCS
4646
processing/qgsalgorithmminimumenclosingcircle.cpp
4747
processing/qgsalgorithmmultiparttosinglepart.cpp
4848
processing/qgsalgorithmorientedminimumboundingbox.cpp
49+
processing/qgsalgorithmpackage.cpp
4950
processing/qgsalgorithmpromotetomultipart.cpp
5051
processing/qgsalgorithmrasterlayeruniquevalues.cpp
5152
processing/qgsalgorithmremovenullgeometry.cpp
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/***************************************************************************
2+
qgsalgorithmpackage.cpp
3+
---------------------
4+
begin : November 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsalgorithmpackage.h"
19+
#include "qgsgeometryengine.h"
20+
#include "qgsogrutils.h"
21+
#include "qgsvectorfilewriter.h"
22+
23+
///@cond PRIVATE
24+
25+
QString QgsPackageAlgorithm::name() const
26+
{
27+
return QStringLiteral( "package" );
28+
}
29+
30+
QString QgsPackageAlgorithm::displayName() const
31+
{
32+
return QObject::tr( "Package layers" );
33+
}
34+
35+
QStringList QgsPackageAlgorithm::tags() const
36+
{
37+
return QObject::tr( "geopackage,collect,merge,combine" ).split( ',' );
38+
}
39+
40+
QString QgsPackageAlgorithm::group() const
41+
{
42+
return QObject::tr( "Database" );
43+
}
44+
45+
void QgsPackageAlgorithm::initAlgorithm( const QVariantMap & )
46+
{
47+
addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), QgsProcessing::TypeVector ) );
48+
addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination GeoPackage" ), QStringLiteral( "*.gpkg" ) ) );
49+
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "OVERWRITE" ), QObject::tr( "Overwrite existing GeoPackage" ), false ) );
50+
}
51+
52+
QString QgsPackageAlgorithm::shortHelpString() const
53+
{
54+
return QObject::tr( "This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
55+
}
56+
57+
QgsPackageAlgorithm *QgsPackageAlgorithm::createInstance() const
58+
{
59+
return new QgsPackageAlgorithm();
60+
}
61+
62+
QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
63+
{
64+
bool overwrite = parameterAsBool( parameters, QStringLiteral( "OVERWRITE" ), context );
65+
QString packagePath = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
66+
if ( packagePath.isEmpty() )
67+
throw QgsProcessingException( QObject::tr( "No output file specified." ) );
68+
69+
// delete existing geopackage if it exists
70+
if ( overwrite && QFile::exists( packagePath ) )
71+
{
72+
feedback->pushInfo( QObject::tr( "Removing existing file '%1'" ).arg( packagePath ) );
73+
if ( !QFile( packagePath ).remove() )
74+
{
75+
throw QgsProcessingException( QObject::tr( "Could not remove existing file '%1'" ) );
76+
}
77+
}
78+
79+
OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
80+
if ( !hGpkgDriver )
81+
{
82+
throw QgsProcessingException( QObject::tr( "GeoPackage driver not found." ) );
83+
}
84+
85+
gdal::ogr_datasource_unique_ptr hDS( OGR_Dr_CreateDataSource( hGpkgDriver, packagePath.toUtf8().constData(), nullptr ) );
86+
if ( !hDS )
87+
throw QgsProcessingException( QObject::tr( "Creation of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );
88+
89+
bool errored = false;
90+
const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );
91+
92+
QgsProcessingMultiStepFeedback multiStepFeedback( layers.count(), feedback );
93+
94+
int i = 0;
95+
for ( QgsMapLayer *layer : layers )
96+
{
97+
if ( feedback->isCanceled() )
98+
break;
99+
100+
multiStepFeedback.setCurrentStep( i );
101+
i++;
102+
103+
feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( layers.count() ).arg( layer->name() ) );
104+
105+
if ( !layer )
106+
{
107+
// don't throw immediately - instead do what we can and error out later
108+
feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
109+
errored = true;
110+
continue;
111+
}
112+
113+
switch ( layer->type() )
114+
{
115+
case QgsMapLayer::VectorLayer:
116+
{
117+
if ( !packageVectorLayer( qobject_cast< QgsVectorLayer * >( layer ), packagePath,
118+
context, &multiStepFeedback ) )
119+
errored = true;
120+
break;
121+
}
122+
123+
case QgsMapLayer::RasterLayer:
124+
{
125+
//not supported
126+
feedback->pushDebugInfo( QObject::tr( "Raster layers are not currently supported." ) );
127+
errored = true;
128+
break;
129+
}
130+
131+
case QgsMapLayer::PluginLayer:
132+
//not supported
133+
feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
134+
errored = true;
135+
break;
136+
}
137+
}
138+
139+
if ( errored )
140+
throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );
141+
142+
QVariantMap outputs;
143+
outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
144+
return outputs;
145+
}
146+
147+
bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context,
148+
QgsProcessingFeedback *feedback )
149+
{
150+
QgsVectorFileWriter::SaveVectorOptions options;
151+
options.driverName = QStringLiteral( "GPKG" );
152+
options.layerName = layer->name();
153+
options.actionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
154+
options.fileEncoding = context.defaultEncoding();
155+
options.feedback = feedback;
156+
157+
QString error;
158+
if ( QgsVectorFileWriter::writeAsVectorFormat( layer, path, options, &error ) != QgsVectorFileWriter::NoError )
159+
{
160+
feedback->pushDebugInfo( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
161+
return false;
162+
}
163+
else
164+
{
165+
return true;
166+
}
167+
}
168+
169+
///@endcond
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/***************************************************************************
2+
qgsalgorithmpackage.h
3+
------------------
4+
begin : November 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSALGORITHMPACKAGE_H
19+
#define QGSALGORITHMPACKAGE_H
20+
21+
#define SIP_NO_FILE
22+
23+
#include "qgis.h"
24+
#include "qgsprocessingalgorithm.h"
25+
26+
///@cond PRIVATE
27+
28+
class QgsVectorLayer;
29+
30+
/**
31+
* Native package layers algorithm.
32+
*/
33+
class QgsPackageAlgorithm : public QgsProcessingAlgorithm
34+
{
35+
36+
public:
37+
38+
QgsPackageAlgorithm() = default;
39+
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
40+
QString name() const override;
41+
QString displayName() const override;
42+
virtual QStringList tags() const override;
43+
QString group() const override;
44+
QString shortHelpString() const override;
45+
QgsPackageAlgorithm *createInstance() const override SIP_FACTORY;
46+
47+
protected:
48+
49+
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
50+
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
51+
52+
private:
53+
54+
bool packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context, QgsProcessingFeedback *feedback );
55+
56+
};
57+
58+
///@endcond PRIVATE
59+
60+
#endif // QGSALGORITHMPACKAGE_H
61+
62+

src/analysis/processing/qgsnativealgorithms.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "qgsalgorithmminimumenclosingcircle.h"
4444
#include "qgsalgorithmmultiparttosinglepart.h"
4545
#include "qgsalgorithmorientedminimumboundingbox.h"
46+
#include "qgsalgorithmpackage.h"
4647
#include "qgsalgorithmpromotetomultipart.h"
4748
#include "qgsalgorithmrasterlayeruniquevalues.h"
4849
#include "qgsalgorithmremovenullgeometry.h"
@@ -118,6 +119,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
118119
addAlgorithm( new QgsMinimumEnclosingCircleAlgorithm() );
119120
addAlgorithm( new QgsMultipartToSinglepartAlgorithm() );
120121
addAlgorithm( new QgsOrientedMinimumBoundingBoxAlgorithm() );
122+
addAlgorithm( new QgsPackageAlgorithm() );
121123
addAlgorithm( new QgsPromoteToMultipartAlgorithm() );
122124
addAlgorithm( new QgsRasterLayerUniqueValuesReportAlgorithm() );
123125
addAlgorithm( new QgsRemoveNullGeometryAlgorithm() );

0 commit comments

Comments
 (0)