27
27
28
28
from qgis .core import (QgsFeature ,
29
29
QgsGeometry ,
30
+ QgsMultiPointV2 ,
31
+ QgsMultiLineString ,
32
+ QgsLineString ,
33
+ QgsPolygonV2 ,
30
34
QgsFeatureSink ,
31
35
QgsWkbTypes ,
32
36
QgsProcessingException ,
@@ -72,20 +76,32 @@ def processAlgorithm(self, parameters, context, feedback):
72
76
source = self .parameterAsSource (parameters , self .INPUT , context )
73
77
index = self .parameterAsEnum (parameters , self .TYPE , context )
74
78
75
- splitNodes = False
76
79
if index == 0 :
77
80
newType = QgsWkbTypes .Point
78
81
elif index == 1 :
79
82
newType = QgsWkbTypes .Point
80
- splitNodes = True
83
+ if QgsWkbTypes .hasM (source .wkbType ()):
84
+ newType = QgsWkbTypes .addM (newType )
85
+ if QgsWkbTypes .hasZ (source .wkbType ()):
86
+ newType = QgsWkbTypes .addZ (newType )
81
87
elif index == 2 :
82
88
newType = QgsWkbTypes .LineString
89
+ if QgsWkbTypes .hasM (source .wkbType ()):
90
+ newType = QgsWkbTypes .addM (newType )
91
+ if QgsWkbTypes .hasZ (source .wkbType ()):
92
+ newType = QgsWkbTypes .addZ (newType )
83
93
elif index == 3 :
84
94
newType = QgsWkbTypes .MultiLineString
85
- elif index == 4 :
86
- newType = QgsWkbTypes .Polygon
95
+ if QgsWkbTypes .hasM (source .wkbType ()):
96
+ newType = QgsWkbTypes .addM (newType )
97
+ if QgsWkbTypes .hasZ (source .wkbType ()):
98
+ newType = QgsWkbTypes .addZ (newType )
87
99
else :
88
- newType = QgsWkbTypes .Point
100
+ newType = QgsWkbTypes .Polygon
101
+ if QgsWkbTypes .hasM (source .wkbType ()):
102
+ newType = QgsWkbTypes .addM (newType )
103
+ if QgsWkbTypes .hasZ (source .wkbType ()):
104
+ newType = QgsWkbTypes .addZ (newType )
89
105
90
106
(sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
91
107
source .fields (), newType , source .sourceCrs ())
@@ -99,140 +115,120 @@ def processAlgorithm(self, parameters, context, feedback):
99
115
100
116
if not f .hasGeometry ():
101
117
sink .addFeature (f , QgsFeatureSink .FastInsert )
102
-
103
- geom = f .geometry ()
104
- geomType = geom .wkbType ()
105
-
106
- if QgsWkbTypes .geometryType (geomType ) == QgsWkbTypes .PointGeometry and not QgsWkbTypes .isMultiType (geomType ):
107
- if newType == QgsWkbTypes .Point :
108
- sink .addFeature (f , QgsFeatureSink .FastInsert )
109
- else :
110
- raise QgsProcessingException (
111
- self .tr ('Cannot convert from {0} to {1}' ).format (geomType , newType ))
112
- elif QgsWkbTypes .geometryType (geomType ) == QgsWkbTypes .PointGeometry and QgsWkbTypes .isMultiType (geomType ):
113
- if newType == QgsWkbTypes .Point and splitNodes :
114
- points = geom .asMultiPoint ()
115
- for p in points :
116
- feat = QgsFeature ()
117
- feat .setAttributes (f .attributes ())
118
- feat .setGeometry (QgsGeometry .fromPoint (p ))
119
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
120
- elif newType == QgsWkbTypes .Point :
121
- feat = QgsFeature ()
122
- feat .setAttributes (f .attributes ())
123
- feat .setGeometry (geom .centroid ())
124
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
125
- else :
126
- raise QgsProcessingException (
127
- self .tr ('Cannot convert from {0} to {1}' ).format (geomType , newType ))
128
- elif QgsWkbTypes .geometryType (geomType ) == QgsWkbTypes .LineGeometry and not QgsWkbTypes .isMultiType (geomType ):
129
- if newType == QgsWkbTypes .Point and splitNodes :
130
- points = geom .asPolyline ()
131
- for p in points :
132
- feat = QgsFeature ()
133
- feat .setAttributes (f .attributes ())
134
- feat .setGeometry (QgsGeometry .fromPoint (p ))
135
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
136
- elif newType == QgsWkbTypes .Point :
137
- feat = QgsFeature ()
138
- feat .setAttributes (f .attributes ())
139
- feat .setGeometry (geom .centroid ())
140
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
141
- elif newType == QgsWkbTypes .LineString :
142
- sink .addFeature (f , QgsFeatureSink .FastInsert )
143
- else :
144
- raise QgsProcessingException (
145
- self .tr ('Cannot convert from {0} to {1}' ).format (geomType , newType ))
146
- elif QgsWkbTypes .geometryType (geomType ) == QgsWkbTypes .LineGeometry and QgsWkbTypes .isMultiType (
147
- geomType ):
148
- if newType == QgsWkbTypes .Point and splitNodes :
149
- lines = geom .asMultiPolyline ()
150
- for line in lines :
151
- for p in line :
152
- feat = QgsFeature ()
153
- feat .setAttributes (f .attributes ())
154
- feat .setGeometry (QgsGeometry .fromPoint (p ))
155
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
156
- elif newType == QgsWkbTypes .Point :
118
+ else :
119
+ for p in self .convertGeometry (f .geometry (), index ):
157
120
feat = QgsFeature ()
158
121
feat .setAttributes (f .attributes ())
159
- feat .setGeometry (geom . centroid () )
122
+ feat .setGeometry (p )
160
123
sink .addFeature (feat , QgsFeatureSink .FastInsert )
161
- elif newType == QgsWkbTypes .LineString :
162
- lines = geom .asMultiPolyline ()
163
- for line in lines :
164
- feat = QgsFeature ()
165
- feat .setAttributes (f .attributes ())
166
- feat .setGeometry (QgsGeometry .fromPolyline (line ))
167
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
168
- elif newType == QgsWkbTypes .MultiLineString :
169
- sink .addFeature (f , QgsFeatureSink .FastInsert )
170
- else :
171
- raise QgsProcessingException (
172
- self .tr ('Cannot convert from {0} to {1}' ).format (geomType , newType ))
173
- elif QgsWkbTypes .geometryType (geomType ) == QgsWkbTypes .PolygonGeometry and not QgsWkbTypes .isMultiType (
174
- geomType ):
175
- if newType == QgsWkbTypes .Point and splitNodes :
176
- rings = geom .asPolygon ()
177
- for ring in rings :
178
- for p in ring :
179
- feat = QgsFeature ()
180
- feat .setAttributes (f .attributes ())
181
- feat .setGeometry (QgsGeometry .fromPoint (p ))
182
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
183
- elif newType == QgsWkbTypes .Point :
184
- feat = QgsFeature ()
185
- feat .setAttributes (f .attributes ())
186
- feat .setGeometry (geom .centroid ())
187
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
188
- elif newType == QgsWkbTypes .MultiLineString :
189
- rings = geom .asPolygon ()
190
- feat = QgsFeature ()
191
- feat .setAttributes (f .attributes ())
192
- feat .setGeometry (QgsGeometry .fromMultiPolyline (rings ))
193
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
194
- elif newType == QgsWkbTypes .Polygon :
195
- sink .addFeature (f , QgsFeatureSink .FastInsert )
196
- else :
197
- raise QgsProcessingException (
198
- self .tr ('Cannot convert from {0} to {1}' ).format (geomType , newType ))
199
- elif QgsWkbTypes .geometryType (
200
- geomType ) == QgsWkbTypes .PolygonGeometry and QgsWkbTypes .isMultiType (
201
- geomType ):
202
- if newType == QgsWkbTypes .Point and splitNodes :
203
- polygons = geom .asMultiPolygon ()
204
- for polygon in polygons :
205
- for line in polygon :
206
- for p in line :
207
- feat = QgsFeature ()
208
- feat .setAttributes (f .attributes ())
209
- feat .setGeometry (QgsGeometry .fromPoint (p ))
210
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
211
- elif newType == QgsWkbTypes .Point :
212
- feat = QgsFeature ()
213
- feat .setAttributes (f .attributes ())
214
- feat .setGeometry (geom .centroid ())
215
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
216
- elif newType == QgsWkbTypes .LineString :
217
- polygons = geom .asMultiPolygon ()
218
- for polygon in polygons :
219
- feat = QgsFeature ()
220
- feat .setAttributes (f .attributes ())
221
- feat .setGeometry (QgsGeometry .fromPolyline (polygon ))
222
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
223
- elif newType == QgsWkbTypes .Polygon :
224
- polygons = geom .asMultiPolygon ()
225
- for polygon in polygons :
226
- feat = QgsFeature ()
227
- feat .setAttributes (f .attributes ())
228
- feat .setGeometry (QgsGeometry .fromPolygon (polygon ))
229
- sink .addFeature (feat , QgsFeatureSink .FastInsert )
230
- elif newType in [QgsWkbTypes .MultiLineString , QgsWkbTypes .MultiPolygon ]:
231
- sink .addFeature (f , QgsFeatureSink .FastInsert )
232
- else :
233
- raise QgsProcessingException (
234
- self .tr ('Cannot convert from {0} to {1}' ).format (geomType , newType ))
235
124
236
125
feedback .setProgress (int (current * total ))
237
126
238
127
return {self .OUTPUT : dest_id }
128
+
129
+ def convertGeometry (self , geom , target_type ):
130
+ # returns an array of output geometries for the input geometry
131
+ if target_type == 0 :
132
+ #centroid
133
+ return self .convertToCentroid (geom )
134
+ elif target_type == 1 :
135
+ #nodes
136
+ return self .convertToNodes (geom )
137
+ elif target_type == 2 :
138
+ #linestrings
139
+ return self .convertToLineStrings (geom )
140
+ elif target_type == 3 :
141
+ #multilinestrings
142
+ return self .convertToMultiLineStrings (geom )
143
+ elif target_type == 4 :
144
+ #polygon
145
+ return self .convertToPolygon (geom )
146
+
147
+ def convertToCentroid (self , geom ):
148
+ return [geom .centroid ()]
149
+
150
+ def convertToNodes (self , geom ):
151
+ mp = QgsMultiPointV2 ()
152
+ # TODO: mega inefficient - needs rework when geometry iterators land
153
+ # (but at least it doesn't lose Z/M values)
154
+ for g in geom .geometry ().coordinateSequence ():
155
+ for r in g :
156
+ for p in r :
157
+ mp .addGeometry (p )
158
+ return [QgsGeometry (mp )]
159
+
160
+ def convertToLineStrings (self , geom ):
161
+ if QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .PointGeometry :
162
+ raise QgsProcessingException (
163
+ self .tr ('Cannot convert from {0} to LineStrings' ).format (QgsWkbTypes .displayString (geom .wkbType ())))
164
+ elif QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .LineGeometry :
165
+ if QgsWkbTypes .isMultiType (geom .wkbType ()):
166
+ return geom .asGeometryCollection ()
167
+ else :
168
+ #line to line
169
+ return [geom ]
170
+ else :
171
+ # polygons to lines
172
+ # we just use the boundary here - that consists of all rings in the (multi)polygon
173
+ boundary = QgsGeometry (geom .geometry ().boundary ())
174
+ # boundary will be multipart
175
+ return boundary .asGeometryCollection ()
176
+
177
+ def convertToMultiLineStrings (self , geom ):
178
+ if QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .PointGeometry :
179
+ raise QgsProcessingException (
180
+ self .tr ('Cannot convert from {0} to MultiLineStrings' ).format (QgsWkbTypes .displayString (geom .wkbType ())))
181
+ elif QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .LineGeometry :
182
+ if QgsWkbTypes .isMultiType (geom .wkbType ()):
183
+ return [geom ]
184
+ else :
185
+ # line to multiLine
186
+ ml = QgsMultiLineString ()
187
+ ml .addGeometry (geom .geometry ().clone ())
188
+ return [QgsGeometry (ml )]
189
+ else :
190
+ # polygons to multilinestring
191
+ # we just use the boundary here - that consists of all rings in the (multi)polygon
192
+ return [QgsGeometry (geom .geometry ().boundary ())]
193
+
194
+ def convertToPolygon (self , geom ):
195
+ if QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .PointGeometry and geom .geometry ().nCoordinates () < 3 :
196
+ raise QgsProcessingException (
197
+ self .tr ('Cannot convert from Point to Polygon' ).format (QgsWkbTypes .displayString (geom .wkbType ())))
198
+ elif QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .PointGeometry :
199
+ # multipoint with at least 3 points
200
+ # TODO: mega inefficient - needs rework when geometry iterators land
201
+ # (but at least it doesn't lose Z/M values)
202
+ points = []
203
+ for g in geom .geometry ().coordinateSequence ():
204
+ for r in g :
205
+ for p in r :
206
+ points .append (p )
207
+ linestring = QgsLineString (points )
208
+ linestring .close ()
209
+ p = QgsPolygonV2 ()
210
+ p .setExteriorRing (linestring )
211
+ return [QgsGeometry (p )]
212
+ elif QgsWkbTypes .geometryType (geom .wkbType ()) == QgsWkbTypes .LineGeometry :
213
+ if QgsWkbTypes .isMultiType (geom ):
214
+ parts = []
215
+ for i in range (geom .geometry ().numGeometries ()):
216
+ p = QgsPolygonV2 ()
217
+ linestring = geom .geometry ().geometryN (i ).clone ()
218
+ linestring .close ()
219
+ p .setExteriorRing (linestring )
220
+ parts .append (QgsGeometry (p ))
221
+ return QgsGeometry .collectGeometry (parts )
222
+ else :
223
+ # linestring to polygon
224
+ p = QgsPolygonV2 ()
225
+ linestring = geom .geometry ().clone ()
226
+ linestring .close ()
227
+ p .setExteriorRing (linestring )
228
+ return [QgsGeometry (p )]
229
+ else :
230
+ #polygon
231
+ if QgsWkbTypes .isMultiType (geom ):
232
+ return geom .asGeometryCollection ()
233
+ else :
234
+ return [geom ]
0 commit comments