3232 QgsFeatureSink ,
3333 QgsWkbTypes ,
3434 QgsApplication ,
35- QgsProcessingUtils )
35+ QgsProcessingUtils ,
36+ QgsProcessingParameterFeatureSource ,
37+ QgsProcessingParameterVectorLayer ,
38+ QgsProcessingParameterDefinition ,
39+ QgsProcessingParameterNumber ,
40+ QgsProcessingParameterBoolean ,
41+ QgsProcessingParameterFeatureSink ,
42+ QgsProcessingOutputVectorLayer )
3643from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
3744from processing .core .GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
38- from processing .core .parameters import ParameterVector
39- from processing .core .parameters import ParameterNumber
40- from processing .core .parameters import ParameterBoolean
41- from processing .core .outputs import OutputVector
42- from processing .tools import dataobjects
4345import processing
4446from math import sqrt
4547
@@ -57,17 +59,19 @@ def group(self):
5759
5860 def __init__ (self ):
5961 super ().__init__ ()
60- self .addParameter (ParameterVector (ConcaveHull .INPUT ,
61- self .tr ('Input point layer' ), [dataobjects .TYPE_VECTOR_POINT ]))
62- self .addParameter (ParameterNumber (self .ALPHA ,
63- self .tr ('Threshold (0-1, where 1 is equivalent with Convex Hull)' ),
64- 0 , 1 , 0.3 ))
65- self .addParameter (ParameterBoolean (self .HOLES ,
66- self .tr ('Allow holes' ), True ))
67- self .addParameter (ParameterBoolean (self .NO_MULTIGEOMETRY ,
68- self .tr ('Split multipart geometry into singleparts geometries' ), False ))
69- self .addOutput (
70- OutputVector (ConcaveHull .OUTPUT , self .tr ('Concave hull' ), datatype = [dataobjects .TYPE_VECTOR_POLYGON ]))
62+
63+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT , self .tr ('Input point layer' ), [QgsProcessingParameterDefinition .TypeVectorPoint ]))
64+ self .addParameter (QgsProcessingParameterNumber (self .ALPHA ,
65+ self .tr ('Threshold (0-1, where 1 is equivalent with Convex Hull)' ),
66+ minValue = 0 , maxValue = 1 , defaultValue = 0.3 , type = QgsProcessingParameterNumber .Double ))
67+
68+ self .addParameter (QgsProcessingParameterBoolean (self .HOLES ,
69+ self .tr ('Allow holes' ), defaultValue = True ))
70+ self .addParameter (QgsProcessingParameterBoolean (self .NO_MULTIGEOMETRY ,
71+ self .tr ('Split multipart geometry into singleparts geometries' ), defaultValue = False ))
72+
73+ self .addParameter (QgsProcessingParameterFeatureSink (self .OUTPUT , self .tr ('Concave hull' ), type = QgsProcessingParameterDefinition .TypeVectorPolygon ))
74+ self .addOutput (QgsProcessingOutputVectorLayer (self .OUTPUT , self .tr ("Concave hull" ), type = QgsProcessingParameterDefinition .TypeVectorPolygon ))
7175
7276 def name (self ):
7377 return 'concavehull'
@@ -76,28 +80,31 @@ def displayName(self):
7680 return self .tr ('Concave hull' )
7781
7882 def processAlgorithm (self , parameters , context , feedback ):
79- layer = QgsProcessingUtils . mapLayerFromString ( self .getParameterValue ( ConcaveHull .INPUT ) , context )
80- alpha = self .getParameterValue ( self .ALPHA )
81- holes = self .getParameterValue ( self .HOLES )
82- no_multigeom = self .getParameterValue ( self .NO_MULTIGEOMETRY )
83+ layer = self .parameterAsSource ( parameters , ConcaveHull .INPUT , context )
84+ alpha = self .parameterAsDouble ( parameters , self .ALPHA , context )
85+ holes = self .parameterAsBool ( parameters , self .HOLES , context )
86+ no_multigeom = self .parameterAsBool ( parameters , self .NO_MULTIGEOMETRY , context )
8387
8488 # Delaunay triangulation from input point layer
8589 feedback .setProgressText (self .tr ('Creating Delaunay triangles...' ))
86- delone_triangles = processing .run ("qgis:delaunaytriangulation" , layer , None , context = context )['OUTPUT' ]
90+ delone_triangles = processing .run ("qgis:delaunaytriangulation" , { 'INPUT' : parameters [ ConcaveHull . INPUT ], 'OUTPUT' : 'memory:' }, feedback = feedback , context = context )['OUTPUT' ]
8791 delaunay_layer = QgsProcessingUtils .mapLayerFromString (delone_triangles , context )
8892
8993 # Get max edge length from Delaunay triangles
9094 feedback .setProgressText (self .tr ('Computing edges max length...' ))
9195
92- features = QgsProcessingUtils .getFeatures (delaunay_layer , context )
93- count = QgsProcessingUtils .featureCount (delaunay_layer , context )
96+ features = delaunay_layer .getFeatures ()
97+ count = delaunay_layer .featureCount ()
9498 if count == 0 :
9599 raise GeoAlgorithmExecutionException (self .tr ('No Delaunay triangles created.' ))
96100
97101 counter = 50. / count
98102 lengths = []
99103 edges = {}
100104 for feat in features :
105+ if feedback .isCanceled ():
106+ break
107+
101108 line = feat .geometry ().asPolygon ()[0 ]
102109 for i in range (len (line ) - 1 ):
103110 lengths .append (sqrt (line [i ].sqrDist (line [i + 1 ])))
@@ -111,6 +118,9 @@ def processAlgorithm(self, parameters, context, feedback):
111118 i = 0
112119 ids = []
113120 for id , max_len in list (edges .items ()):
121+ if feedback .isCanceled ():
122+ break
123+
114124 if max_len > alpha * max_length :
115125 ids .append (id )
116126 feedback .setProgress (50 + i * counter )
@@ -124,21 +134,25 @@ def processAlgorithm(self, parameters, context, feedback):
124134
125135 # Dissolve all Delaunay triangles
126136 feedback .setProgressText (self .tr ('Dissolving Delaunay triangles...' ))
127- dissolved = processing .run ("qgis:dissolve" , delaunay_layer .id (),
128- True , None , None , context = context )['OUTPUT' ]
137+ dissolved = processing .run ("native:dissolve" , {'INPUT' : delaunay_layer .id (), 'OUTPUT' : 'memory:' }, feedback = feedback , context = context )['OUTPUT' ]
129138 dissolved_layer = QgsProcessingUtils .mapLayerFromString (dissolved , context )
130139
131140 # Save result
132141 feedback .setProgressText (self .tr ('Saving data...' ))
133142 feat = QgsFeature ()
134- QgsProcessingUtils .getFeatures (dissolved_layer , context ).nextFeature (feat )
135- writer = self .getOutputFromName (self .OUTPUT ).getVectorWriter (layer .fields (), QgsWkbTypes .Polygon ,
136- layer .crs (), context )
143+ dissolved_layer .getFeatures ().nextFeature (feat )
144+
145+ (sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
146+ layer .fields (), QgsWkbTypes .Polygon , layer .sourceCrs ())
147+
137148 geom = feat .geometry ()
138149 if no_multigeom and geom .isMultipart ():
139150 # Only singlepart geometries are allowed
140151 geom_list = geom .asMultiPolygon ()
141152 for single_geom_list in geom_list :
153+ if feedback .isCanceled ():
154+ break
155+
142156 single_feature = QgsFeature ()
143157 single_geom = QgsGeometry .fromPolygon (single_geom_list )
144158 if not holes :
@@ -147,13 +161,14 @@ def processAlgorithm(self, parameters, context, feedback):
147161 while deleted :
148162 deleted = single_geom .deleteRing (1 )
149163 single_feature .setGeometry (single_geom )
150- writer .addFeature (single_feature , QgsFeatureSink .FastInsert )
164+ sink .addFeature (single_feature , QgsFeatureSink .FastInsert )
151165 else :
152166 # Multipart geometries are allowed
153167 if not holes :
154168 # Delete holes
155169 deleted = True
156170 while deleted :
157171 deleted = geom .deleteRing (1 )
158- writer .addFeature (feat , QgsFeatureSink .FastInsert )
159- del writer
172+ sink .addFeature (feat , QgsFeatureSink .FastInsert )
173+
174+ return {self .OUTPUT : dest_id }
0 commit comments