30
30
31
31
from qgis .PyQt .QtGui import QIcon
32
32
from qgis .PyQt .QtCore import QVariant
33
- from qgis .core import (QgsGeometry , QgsFeatureSink , QgsFields , QgsField , QgsSpatialIndex , QgsWkbTypes ,
34
- QgsPointXY , QgsFeature , QgsFeatureRequest ,
35
- QgsMessageLog ,
36
- QgsProcessingUtils )
33
+ from qgis .core import (QgsField ,
34
+ QgsFeatureSink ,
35
+ QgsFeature ,
36
+ QgsFields ,
37
+ QgsGeometry ,
38
+ QgsPoint ,
39
+ QgsPointXY ,
40
+ QgsWkbTypes ,
41
+ QgsSpatialIndex ,
42
+ QgsFeatureRequest ,
43
+ QgsProcessing ,
44
+ QgsProcessingException ,
45
+ QgsProcessingParameterNumber ,
46
+ QgsProcessingParameterBoolean ,
47
+ QgsProcessingParameterFeatureSource ,
48
+ QgsProcessingParameterFeatureSink ,
49
+ QgsProcessingParameterDefinition )
37
50
38
51
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
39
- from processing .core .parameters import ParameterVector
40
- from processing .core .parameters import ParameterNumber
41
- from processing .core .outputs import OutputVector
42
- from processing .tools import dataobjects , vector
52
+ from processing .tools import vector
43
53
44
54
pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
45
55
46
56
47
57
class RandomPointsLayer (QgisAlgorithm ):
48
58
49
- VECTOR = 'VECTOR '
50
- POINT_NUMBER = 'POINT_NUMBER '
59
+ INPUT = 'INPUT '
60
+ POINTS_NUMBER = 'POINTS_NUMBER '
51
61
MIN_DISTANCE = 'MIN_DISTANCE'
62
+ ADD_Z = 'ADD_Z'
63
+ ADD_M = 'ADD_M'
52
64
OUTPUT = 'OUTPUT'
53
65
54
66
def icon (self ):
@@ -61,13 +73,31 @@ def __init__(self):
61
73
super ().__init__ ()
62
74
63
75
def initAlgorithm (self , config = None ):
64
- self .addParameter (ParameterVector (self .VECTOR ,
65
- self .tr ('Input layer' ), [dataobjects .TYPE_VECTOR_POLYGON ]))
66
- self .addParameter (ParameterNumber (self .POINT_NUMBER ,
67
- self .tr ('Points number' ), 1 , None , 1 ))
68
- self .addParameter (ParameterNumber (self .MIN_DISTANCE ,
69
- self .tr ('Minimum distance' ), 0.0 , None , 0.0 ))
70
- self .addOutput (OutputVector (self .OUTPUT , self .tr ('Random points' ), datatype = [dataobjects .TYPE_VECTOR_POINT ]))
76
+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT ,
77
+ self .tr ('Input layer' ),
78
+ [QgsProcessing .TypeVectorPolygon ]))
79
+ self .addParameter (QgsProcessingParameterNumber (self .POINTS_NUMBER ,
80
+ self .tr ('Number of points' ),
81
+ QgsProcessingParameterNumber .Integer ,
82
+ 1 , False , 1 , 1000000000 ))
83
+ self .addParameter (QgsProcessingParameterNumber (self .MIN_DISTANCE ,
84
+ self .tr ('Minimum distance between points' ),
85
+ QgsProcessingParameterNumber .Double ,
86
+ 0 , False , 0 , 1000000000 ))
87
+ params = []
88
+ params .append (QgsProcessingParameterBoolean (self .ADD_Z ,
89
+ self .tr ('Add Z coordinate' ),
90
+ False ))
91
+ params .append (QgsProcessingParameterBoolean (self .ADD_M ,
92
+ self .tr ('Add M coordinate' ),
93
+ False ))
94
+ for p in params :
95
+ p .setFlags (p .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
96
+ self .addParameter (p )
97
+
98
+ self .addParameter (QgsProcessingParameterFeatureSink (self .OUTPUT ,
99
+ self .tr ('Random points' ),
100
+ type = QgsProcessing .TypeVectorPoint ))
71
101
72
102
def name (self ):
73
103
return 'randompointsinlayerbounds'
@@ -76,16 +106,26 @@ def displayName(self):
76
106
return self .tr ('Random points in layer bounds' )
77
107
78
108
def processAlgorithm (self , parameters , context , feedback ):
79
- layer = QgsProcessingUtils .mapLayerFromString (self .getParameterValue (self .VECTOR ), context )
80
- pointCount = int (self .getParameterValue (self .POINT_NUMBER ))
81
- minDistance = float (self .getParameterValue (self .MIN_DISTANCE ))
109
+ source = self .parameterAsSource (parameters , self .INPUT , context )
110
+ pointCount = self .parameterAsDouble (parameters , self .POINTS_NUMBER , context )
111
+ minDistance = self .parameterAsDouble (parameters , self .MIN_DISTANCE , context )
112
+ addZ = self .parameterAsBool (parameters , self .ADD_Z , context )
113
+ addM = self .parameterAsBool (parameters , self .ADD_M , context )
82
114
83
- bbox = layer . extent ()
84
- idxLayer = QgsProcessingUtils . createSpatialIndex ( layer , context )
115
+ bbox = source . sourceExtent ()
116
+ sourceIndex = QgsSpatialIndex ( source , feedback )
85
117
86
118
fields = QgsFields ()
87
119
fields .append (QgsField ('id' , QVariant .Int , '' , 10 , 0 ))
88
- writer = self .getOutputFromName (self .OUTPUT ).getVectorWriter (fields , QgsWkbTypes .Point , layer .crs (), context )
120
+
121
+ wkbType = QgsWkbTypes .Point
122
+ if addZ :
123
+ wkbType = QgsWkbTypes .addZ (wkbType )
124
+ if addM :
125
+ wkbType = QgsWkbTypes .addM (wkbType )
126
+
127
+ (sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
128
+ fields , wkbType , source .sourceCrs ())
89
129
90
130
nPoints = 0
91
131
nIterations = 0
@@ -98,32 +138,43 @@ def processAlgorithm(self, parameters, context, feedback):
98
138
random .seed ()
99
139
100
140
while nIterations < maxIterations and nPoints < pointCount :
141
+ if feedback .isCanceled ():
142
+ break
143
+
101
144
rx = bbox .xMinimum () + bbox .width () * random .random ()
102
145
ry = bbox .yMinimum () + bbox .height () * random .random ()
103
146
104
- pnt = QgsPointXY (rx , ry )
105
- geom = QgsGeometry .fromPoint (pnt )
106
- ids = idxLayer .intersects (geom .buffer (5 , 5 ).boundingBox ())
147
+ pnt = QgsPoint (rx , ry )
148
+ p = QgsPointXY (rx , ry )
149
+ if addZ :
150
+ pnt .addZValue (0.0 )
151
+ if addM :
152
+ pnt .addMValue (0.0 )
153
+ geom = QgsGeometry (pnt )
154
+ ids = sourceIndex .intersects (geom .buffer (5 , 5 ).boundingBox ())
107
155
if len (ids ) > 0 and \
108
- vector .checkMinDistance (pnt , index , minDistance , points ):
156
+ vector .checkMinDistance (p , index , minDistance , points ):
109
157
request = QgsFeatureRequest ().setFilterFids (ids ).setSubsetOfAttributes ([])
110
- for f in layer .getFeatures (request ):
158
+ for f in source .getFeatures (request ):
159
+ if feedback .isCanceled ():
160
+ break
161
+
111
162
tmpGeom = f .geometry ()
112
163
if geom .within (tmpGeom ):
113
164
f = QgsFeature (nPoints )
114
165
f .initAttributes (1 )
115
166
f .setFields (fields )
116
167
f .setAttribute ('id' , nPoints )
117
168
f .setGeometry (geom )
118
- writer .addFeature (f , QgsFeatureSink .FastInsert )
169
+ sink .addFeature (f , QgsFeatureSink .FastInsert )
119
170
index .insertFeature (f )
120
- points [nPoints ] = pnt
171
+ points [nPoints ] = p
121
172
nPoints += 1
122
173
feedback .setProgress (int (nPoints * total ))
123
174
nIterations += 1
124
175
125
176
if nPoints < pointCount :
126
- QgsMessageLog . logMessage (self .tr ('Can not generate requested number of random points. '
127
- 'Maximum number of attempts exceeded.' ), self . tr ( 'Processing' ), QgsMessageLog . INFO )
177
+ feedback . pushInfo (self .tr ('Could not generate requested number of random points. '
178
+ 'Maximum number of attempts exceeded.' ))
128
179
129
- del writer
180
+ return { self . OUTPUT : dest_id }
0 commit comments