@@ -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 ¶meters,
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 ¶meters, 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
0 commit comments