31
31
32
32
from qgis .PyQt .QtGui import QIcon
33
33
from qgis .PyQt .QtCore import QVariant
34
- from qgis .core import (QgsGeometry , QgsFeatureSink , QgsRectangle , QgsFeature , QgsFields , QgsWkbTypes ,
35
- QgsField , QgsSpatialIndex , QgsPointXY ,
36
- QgsCoordinateReferenceSystem ,
37
- QgsMessageLog ,
38
- QgsProcessingUtils )
34
+ from qgis .core import (QgsField ,
35
+ QgsFeatureSink ,
36
+ QgsFeature ,
37
+ QgsFields ,
38
+ QgsGeometry ,
39
+ QgsPoint ,
40
+ QgsPointXY ,
41
+ QgsWkbTypes ,
42
+ QgsSpatialIndex ,
43
+ QgsProcessing ,
44
+ QgsProcessingException ,
45
+ QgsProcessingParameterExtent ,
46
+ QgsProcessingParameterNumber ,
47
+ QgsProcessingParameterCrs ,
48
+ QgsProcessingParameterBoolean ,
49
+ QgsProcessingParameterFeatureSink ,
50
+ QgsProcessingParameterDefinition )
39
51
40
52
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
41
- from processing .core .parameters import ParameterExtent
42
- from processing .core .parameters import ParameterNumber
43
- from processing .core .parameters import ParameterCrs
44
- from processing .core .outputs import OutputVector
45
- from processing .tools import vector , dataobjects
53
+ from processing .tools import vector
46
54
47
55
pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
48
56
49
57
50
58
class RandomPointsExtent (QgisAlgorithm ):
51
59
52
60
EXTENT = 'EXTENT'
53
- POINT_NUMBER = 'POINT_NUMBER '
61
+ POINTS_NUMBER = 'POINTS_NUMBER '
54
62
MIN_DISTANCE = 'MIN_DISTANCE'
63
+ TARGET_CRS = 'TARGET_CRS'
64
+ ADD_Z = 'ADD_Z'
65
+ ADD_M = 'ADD_M'
55
66
OUTPUT = 'OUTPUT'
56
- CRS = 'CRS'
57
67
58
68
def icon (self ):
59
69
return QIcon (os .path .join (pluginPath , 'images' , 'ftools' , 'random_points.png' ))
@@ -65,15 +75,33 @@ def __init__(self):
65
75
super ().__init__ ()
66
76
67
77
def initAlgorithm (self , config = None ):
68
- self .addParameter (ParameterExtent (self .EXTENT ,
69
- self .tr ('Input extent' ), optional = False ))
70
- self .addParameter (ParameterNumber (self .POINT_NUMBER ,
71
- self .tr ('Points number' ), 1 , None , 1 ))
72
- self .addParameter (ParameterNumber (self .MIN_DISTANCE ,
73
- self .tr ('Minimum distance' ), 0.0 , None , 0.0 ))
74
- self .addParameter (ParameterCrs (self .CRS ,
75
- self .tr ('Output layer CRS' ), 'ProjectCrs' ))
76
- self .addOutput (OutputVector (self .OUTPUT , self .tr ('Random points' ), datatype = [dataobjects .TYPE_VECTOR_POINT ]))
78
+ self .addParameter (QgsProcessingParameterExtent (self .EXTENT , self .tr ('Input extent' )))
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
+ self .addParameter (QgsProcessingParameterCrs (self .TARGET_CRS ,
88
+ self .tr ('Target CRS' ),
89
+ 'ProjectCrs' ))
90
+
91
+ params = []
92
+ params .append (QgsProcessingParameterBoolean (self .ADD_Z ,
93
+ self .tr ('Add Z coordinate' ),
94
+ False ))
95
+ params .append (QgsProcessingParameterBoolean (self .ADD_M ,
96
+ self .tr ('Add M coordinate' ),
97
+ False ))
98
+ for p in params :
99
+ p .setFlags (p .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
100
+ self .addParameter (p )
101
+
102
+ self .addParameter (QgsProcessingParameterFeatureSink (self .OUTPUT ,
103
+ self .tr ('Random points' ),
104
+ type = QgsProcessing .TypeVectorPoint ))
77
105
78
106
def name (self ):
79
107
return 'randompointsinextent'
@@ -82,24 +110,26 @@ def displayName(self):
82
110
return self .tr ('Random points in extent' )
83
111
84
112
def processAlgorithm (self , parameters , context , feedback ):
85
- pointCount = int (self .getParameterValue (self .POINT_NUMBER ))
86
- minDistance = float (self .getParameterValue (self .MIN_DISTANCE ))
87
- extent = str (self .getParameterValue (self .EXTENT )).split (',' )
113
+ bbox = self .parameterAsExtent (parameters , self .EXTENT , context )
114
+ pointCount = self .parameterAsDouble (parameters , self .POINTS_NUMBER , context )
115
+ minDistance = self .parameterAsDouble (parameters , self .MIN_DISTANCE , context )
116
+ crs = self .parameterAsCrs (parameters , self .TARGET_CRS , context )
117
+ addZ = self .parameterAsBool (parameters , self .ADD_Z , context )
118
+ addM = self .parameterAsBool (parameters , self .ADD_M , context )
88
119
89
- crsId = self .getParameterValue (self .CRS )
90
- crs = QgsCoordinateReferenceSystem ()
91
- crs .createFromUserInput (crsId )
92
-
93
- xMin = float (extent [0 ])
94
- xMax = float (extent [1 ])
95
- yMin = float (extent [2 ])
96
- yMax = float (extent [3 ])
97
- extent = QgsGeometry ().fromRect (
98
- QgsRectangle (xMin , yMin , xMax , yMax ))
120
+ extent = QgsGeometry ().fromRect (bbox )
99
121
100
122
fields = QgsFields ()
101
123
fields .append (QgsField ('id' , QVariant .Int , '' , 10 , 0 ))
102
- writer = self .getOutputFromName (self .OUTPUT ).getVectorWriter (fields , QgsWkbTypes .Point , crs , context )
124
+
125
+ wkbType = QgsWkbTypes .Point
126
+ if addZ :
127
+ wkbType = QgsWkbTypes .addZ (wkbType )
128
+ if addM :
129
+ wkbType = QgsWkbTypes .addM (wkbType )
130
+
131
+ (sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
132
+ fields , wkbType , crs )
103
133
104
134
nPoints = 0
105
135
nIterations = 0
@@ -112,27 +142,35 @@ def processAlgorithm(self, parameters, context, feedback):
112
142
random .seed ()
113
143
114
144
while nIterations < maxIterations and nPoints < pointCount :
115
- rx = xMin + (xMax - xMin ) * random .random ()
116
- ry = yMin + (yMax - yMin ) * random .random ()
117
-
118
- pnt = QgsPointXY (rx , ry )
119
- geom = QgsGeometry .fromPoint (pnt )
145
+ if feedback .isCanceled ():
146
+ break
147
+
148
+ rx = bbox .xMinimum () + bbox .width () * random .random ()
149
+ ry = bbox .yMinimum () + bbox .height () * random .random ()
150
+
151
+ pnt = QgsPoint (rx , ry )
152
+ p = QgsPointXY (rx , ry )
153
+ if addZ :
154
+ pnt .addZValue (0.0 )
155
+ if addM :
156
+ pnt .addMValue (0.0 )
157
+ geom = QgsGeometry (pnt )
120
158
if geom .within (extent ) and \
121
- vector .checkMinDistance (pnt , index , minDistance , points ):
159
+ vector .checkMinDistance (p , index , minDistance , points ):
122
160
f = QgsFeature (nPoints )
123
161
f .initAttributes (1 )
124
162
f .setFields (fields )
125
163
f .setAttribute ('id' , nPoints )
126
164
f .setGeometry (geom )
127
- writer .addFeature (f , QgsFeatureSink .FastInsert )
165
+ sink .addFeature (f , QgsFeatureSink .FastInsert )
128
166
index .insertFeature (f )
129
- points [nPoints ] = pnt
167
+ points [nPoints ] = p
130
168
nPoints += 1
131
169
feedback .setProgress (int (nPoints * total ))
132
170
nIterations += 1
133
171
134
172
if nPoints < pointCount :
135
- QgsMessageLog . logMessage (self .tr ('Can not generate requested number of random points. '
136
- 'Maximum number of attempts exceeded.' ), self . tr ( 'Processing' ), QgsMessageLog . INFO )
173
+ feedback . pushInfo (self .tr ('Could not generate requested number of random points. '
174
+ 'Maximum number of attempts exceeded.' ))
137
175
138
- del writer
176
+ return { self . OUTPUT : dest_id }
0 commit comments