3030
3131from qgis .PyQt .QtGui import QIcon
3232from 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 )
3750
3851from 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
4353
4454pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
4555
4656
4757class RandomPointsLayer (QgisAlgorithm ):
4858
49- VECTOR = 'VECTOR '
50- POINT_NUMBER = 'POINT_NUMBER '
59+ INPUT = 'INPUT '
60+ POINTS_NUMBER = 'POINTS_NUMBER '
5161 MIN_DISTANCE = 'MIN_DISTANCE'
62+ ADD_Z = 'ADD_Z'
63+ ADD_M = 'ADD_M'
5264 OUTPUT = 'OUTPUT'
5365
5466 def icon (self ):
@@ -61,13 +73,31 @@ def __init__(self):
6173 super ().__init__ ()
6274
6375 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 ))
71101
72102 def name (self ):
73103 return 'randompointsinlayerbounds'
@@ -76,16 +106,26 @@ def displayName(self):
76106 return self .tr ('Random points in layer bounds' )
77107
78108 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 )
82114
83- bbox = layer . extent ()
84- idxLayer = QgsProcessingUtils . createSpatialIndex ( layer , context )
115+ bbox = source . sourceExtent ()
116+ sourceIndex = QgsSpatialIndex ( source , feedback )
85117
86118 fields = QgsFields ()
87119 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 ())
89129
90130 nPoints = 0
91131 nIterations = 0
@@ -98,32 +138,43 @@ def processAlgorithm(self, parameters, context, feedback):
98138 random .seed ()
99139
100140 while nIterations < maxIterations and nPoints < pointCount :
141+ if feedback .isCanceled ():
142+ break
143+
101144 rx = bbox .xMinimum () + bbox .width () * random .random ()
102145 ry = bbox .yMinimum () + bbox .height () * random .random ()
103146
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 ())
107155 if len (ids ) > 0 and \
108- vector .checkMinDistance (pnt , index , minDistance , points ):
156+ vector .checkMinDistance (p , index , minDistance , points ):
109157 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+
111162 tmpGeom = f .geometry ()
112163 if geom .within (tmpGeom ):
113164 f = QgsFeature (nPoints )
114165 f .initAttributes (1 )
115166 f .setFields (fields )
116167 f .setAttribute ('id' , nPoints )
117168 f .setGeometry (geom )
118- writer .addFeature (f , QgsFeatureSink .FastInsert )
169+ sink .addFeature (f , QgsFeatureSink .FastInsert )
119170 index .insertFeature (f )
120- points [nPoints ] = pnt
171+ points [nPoints ] = p
121172 nPoints += 1
122173 feedback .setProgress (int (nPoints * total ))
123174 nIterations += 1
124175
125176 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.' ))
128179
129- del writer
180+ return { self . OUTPUT : dest_id }
0 commit comments