32
32
QgsFeatureSink ,
33
33
QgsWkbTypes ,
34
34
QgsApplication ,
35
- QgsProcessingUtils )
35
+ QgsProcessingUtils ,
36
+ QgsProcessingParameterFeatureSource ,
37
+ QgsProcessingParameterVectorLayer ,
38
+ QgsProcessingParameterDefinition ,
39
+ QgsProcessingParameterNumber ,
40
+ QgsProcessingParameterBoolean ,
41
+ QgsProcessingParameterFeatureSink ,
42
+ QgsProcessingOutputVectorLayer )
36
43
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
37
44
from 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
43
45
import processing
44
46
from math import sqrt
45
47
@@ -57,17 +59,19 @@ def group(self):
57
59
58
60
def __init__ (self ):
59
61
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 ))
71
75
72
76
def name (self ):
73
77
return 'concavehull'
@@ -76,28 +80,31 @@ def displayName(self):
76
80
return self .tr ('Concave hull' )
77
81
78
82
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 )
83
87
84
88
# Delaunay triangulation from input point layer
85
89
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' ]
87
91
delaunay_layer = QgsProcessingUtils .mapLayerFromString (delone_triangles , context )
88
92
89
93
# Get max edge length from Delaunay triangles
90
94
feedback .setProgressText (self .tr ('Computing edges max length...' ))
91
95
92
- features = QgsProcessingUtils .getFeatures (delaunay_layer , context )
93
- count = QgsProcessingUtils .featureCount (delaunay_layer , context )
96
+ features = delaunay_layer .getFeatures ()
97
+ count = delaunay_layer .featureCount ()
94
98
if count == 0 :
95
99
raise GeoAlgorithmExecutionException (self .tr ('No Delaunay triangles created.' ))
96
100
97
101
counter = 50. / count
98
102
lengths = []
99
103
edges = {}
100
104
for feat in features :
105
+ if feedback .isCanceled ():
106
+ break
107
+
101
108
line = feat .geometry ().asPolygon ()[0 ]
102
109
for i in range (len (line ) - 1 ):
103
110
lengths .append (sqrt (line [i ].sqrDist (line [i + 1 ])))
@@ -111,6 +118,9 @@ def processAlgorithm(self, parameters, context, feedback):
111
118
i = 0
112
119
ids = []
113
120
for id , max_len in list (edges .items ()):
121
+ if feedback .isCanceled ():
122
+ break
123
+
114
124
if max_len > alpha * max_length :
115
125
ids .append (id )
116
126
feedback .setProgress (50 + i * counter )
@@ -124,21 +134,25 @@ def processAlgorithm(self, parameters, context, feedback):
124
134
125
135
# Dissolve all Delaunay triangles
126
136
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' ]
129
138
dissolved_layer = QgsProcessingUtils .mapLayerFromString (dissolved , context )
130
139
131
140
# Save result
132
141
feedback .setProgressText (self .tr ('Saving data...' ))
133
142
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
+
137
148
geom = feat .geometry ()
138
149
if no_multigeom and geom .isMultipart ():
139
150
# Only singlepart geometries are allowed
140
151
geom_list = geom .asMultiPolygon ()
141
152
for single_geom_list in geom_list :
153
+ if feedback .isCanceled ():
154
+ break
155
+
142
156
single_feature = QgsFeature ()
143
157
single_geom = QgsGeometry .fromPolygon (single_geom_list )
144
158
if not holes :
@@ -147,13 +161,14 @@ def processAlgorithm(self, parameters, context, feedback):
147
161
while deleted :
148
162
deleted = single_geom .deleteRing (1 )
149
163
single_feature .setGeometry (single_geom )
150
- writer .addFeature (single_feature , QgsFeatureSink .FastInsert )
164
+ sink .addFeature (single_feature , QgsFeatureSink .FastInsert )
151
165
else :
152
166
# Multipart geometries are allowed
153
167
if not holes :
154
168
# Delete holes
155
169
deleted = True
156
170
while deleted :
157
171
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