Skip to content

Commit d89b160

Browse files
committed
Native c++ dissolve alg
1 parent 9f018e6 commit d89b160

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

src/core/processing/qgsnativealgorithms.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
5959
{
6060
addAlgorithm( new QgsCentroidAlgorithm() );
6161
addAlgorithm( new QgsBufferAlgorithm() );
62+
addAlgorithm( new QgsDissolveAlgorithm() );
6263
}
6364

6465

@@ -214,4 +215,149 @@ QVariantMap QgsBufferAlgorithm::processAlgorithm( const QVariantMap &parameters,
214215
return outputs;
215216
}
216217

218+
219+
QgsDissolveAlgorithm::QgsDissolveAlgorithm()
220+
{
221+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
222+
addParameter( new QgsProcessingParameterTableField( QStringLiteral( "FIELD" ), QObject::tr( "Unique ID fields" ), QVariant(),
223+
QStringLiteral( "INPUT" ), QgsProcessingParameterTableField::Any, true, true ) );
224+
225+
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) );
226+
addOutput( new QgsProcessingOutputVectorLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Dissolved" ) ) );
227+
}
228+
229+
QString QgsDissolveAlgorithm::shortHelpString() const
230+
{
231+
return QObject::tr( "This algorithm takes a polygon or line vector layer and combines their geometries into new geometries. One or more attributes can "
232+
"be specified to dissolve only geometries belonging to the same class (having the same value for the specified attributes), alternatively "
233+
"all geometries can be dissolved.\n\n"
234+
"If the geometries to be dissolved are spatially separated from each other the output will be multi geometries. "
235+
"In case the input is a polygon layer, common boundaries of adjacent polygons being dissolved will get erased." );
236+
}
237+
238+
QVariantMap QgsDissolveAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const
239+
{
240+
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
241+
if ( !source )
242+
return QVariantMap();
243+
244+
QString dest;
245+
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, source->fields(), QgsWkbTypes::multiType( source->wkbType() ), source->sourceCrs(), dest ) );
246+
247+
if ( !sink )
248+
return QVariantMap();
249+
250+
QStringList fields = parameterAsFields( parameters, QStringLiteral( "FIELD" ), context );
251+
252+
long count = source->featureCount();
253+
if ( count <= 0 )
254+
return QVariantMap();
255+
256+
QgsFeature f;
257+
QgsFeatureIterator it = source->getFeatures();
258+
259+
double step = 100.0 / count;
260+
int current = 0;
261+
262+
if ( fields.isEmpty() )
263+
{
264+
// dissolve all - not using fields
265+
bool firstFeature = true;
266+
// we dissolve geometries in blocks using unaryUnion
267+
QList< QgsGeometry > geomQueue;
268+
QgsFeature outputFeature;
269+
270+
while ( it.nextFeature( f ) )
271+
{
272+
if ( feedback->isCanceled() )
273+
{
274+
break;
275+
}
276+
277+
if ( firstFeature )
278+
{
279+
outputFeature = f;
280+
firstFeature = false;
281+
}
282+
283+
if ( f.hasGeometry() && f.geometry() )
284+
{
285+
geomQueue.append( f.geometry() );
286+
if ( geomQueue.length() > 10000 )
287+
{
288+
// queue too long, combine it
289+
QgsGeometry tempOutputGeometry = QgsGeometry::unaryUnion( geomQueue );
290+
geomQueue.clear();
291+
geomQueue << tempOutputGeometry;
292+
}
293+
}
294+
295+
feedback->setProgress( current * step );
296+
current++;
297+
}
298+
299+
outputFeature.setGeometry( QgsGeometry::unaryUnion( geomQueue ) );
300+
sink->addFeature( outputFeature );
301+
}
302+
else
303+
{
304+
QList< int > fieldIndexes;
305+
Q_FOREACH ( const QString &field, fields )
306+
{
307+
int index = source->fields().lookupField( field );
308+
if ( index >= 0 )
309+
fieldIndexes << index;
310+
}
311+
312+
QHash< QVariant, QgsAttributes > attributeHash;
313+
QHash< QVariant, QList< QgsGeometry > > geometryHash;
314+
315+
while ( it.nextFeature( f ) )
316+
{
317+
if ( feedback->isCanceled() )
318+
{
319+
break;
320+
}
321+
322+
if ( f.hasGeometry() && f.geometry() )
323+
{
324+
QVariantList indexAttributes;
325+
Q_FOREACH ( int index, fieldIndexes )
326+
{
327+
indexAttributes << f.attribute( index );
328+
}
329+
330+
if ( !attributeHash.contains( indexAttributes ) )
331+
{
332+
// keep attributes of first feature
333+
attributeHash.insert( indexAttributes, f.attributes() );
334+
}
335+
geometryHash[ indexAttributes ].append( f.geometry() );
336+
}
337+
}
338+
339+
int numberFeatures = attributeHash.count();
340+
QHash< QVariant, QList< QgsGeometry > >::const_iterator geomIt = geometryHash.constBegin();
341+
for ( ; geomIt != geometryHash.constEnd(); ++geomIt )
342+
{
343+
if ( feedback->isCanceled() )
344+
{
345+
break;
346+
}
347+
348+
QgsFeature outputFeature;
349+
outputFeature.setGeometry( QgsGeometry::unaryUnion( geomIt.value() ) );
350+
outputFeature.setAttributes( attributeHash.value( geomIt.key() ) );
351+
sink->addFeature( outputFeature );
352+
353+
feedback->setProgress( current * 100.0 / numberFeatures );
354+
current++;
355+
}
356+
}
357+
358+
QVariantMap outputs;
359+
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
360+
return outputs;
361+
}
362+
217363
///@endcond

src/core/processing/qgsnativealgorithms.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,29 @@ class QgsBufferAlgorithm : public QgsProcessingAlgorithm
8989

9090
};
9191

92+
/**
93+
* Native dissolve algorithm.
94+
*/
95+
class QgsDissolveAlgorithm : public QgsProcessingAlgorithm
96+
{
97+
98+
public:
99+
100+
QgsDissolveAlgorithm();
101+
102+
QString name() const override { return QStringLiteral( "dissolve" ); }
103+
QString displayName() const override { return QObject::tr( "Dissolve" ); }
104+
virtual QStringList tags() const override { return QObject::tr( "dissolve,union,combine,collect" ).split( ',' ); }
105+
QString group() const override { return QObject::tr( "Vector geometry tools" ); }
106+
QString shortHelpString() const override;
107+
108+
protected:
109+
110+
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
111+
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const override;
112+
113+
};
114+
92115
///@endcond PRIVATE
93116

94117
#endif // QGSNATIVEALGORITHMS_H

0 commit comments

Comments
 (0)