2929import random
3030
3131from qgis .PyQt .QtCore import QVariant
32- from qgis .core import (QgsApplication ,
32+ from qgis .core import (QgsField ,
3333 QgsFeatureSink ,
34+ QgsFeature ,
3435 QgsFields ,
35- QgsField ,
3636 QgsGeometry ,
37- QgsSpatialIndex ,
37+ QgsPoint ,
38+ QgsPointXY ,
3839 QgsWkbTypes ,
39- QgsDistanceArea ,
40+ QgsSpatialIndex ,
4041 QgsFeatureRequest ,
41- QgsFeature ,
42- QgsPointXY ,
43- QgsMessageLog ,
42+ QgsDistanceArea ,
4443 QgsProject ,
45- QgsProcessingUtils )
44+ QgsProcessing ,
45+ QgsProcessingException ,
46+ QgsProcessingParameterNumber ,
47+ QgsProcessingParameterBoolean ,
48+ QgsProcessingParameterFeatureSource ,
49+ QgsProcessingParameterFeatureSink ,
50+ QgsProcessingParameterDefinition )
4651
4752from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
48- from processing .core .parameters import ParameterVector
49- from processing .core .parameters import ParameterNumber
50- from processing .core .outputs import OutputVector
51- from processing .tools import dataobjects , vector
53+ from processing .tools import vector
5254
5355
5456class RandomPointsAlongLines (QgisAlgorithm ):
5557
56- VECTOR = 'VECTOR '
57- POINT_NUMBER = 'POINT_NUMBER '
58+ INPUT = 'INPUT '
59+ POINTS_NUMBER = 'POINTS_NUMBER '
5860 MIN_DISTANCE = 'MIN_DISTANCE'
61+ ADD_Z = 'ADD_Z'
62+ ADD_M = 'ADD_M'
5963 OUTPUT = 'OUTPUT'
6064
6165 def group (self ):
@@ -65,13 +69,31 @@ def __init__(self):
6569 super ().__init__ ()
6670
6771 def initAlgorithm (self , config = None ):
68- self .addParameter (ParameterVector (self .VECTOR ,
69- self .tr ('Input layer' ), [dataobjects .TYPE_VECTOR_LINE ]))
70- self .addParameter (ParameterNumber (self .POINT_NUMBER ,
71- self .tr ('Number of points' ), 1 , None , 1 ))
72- self .addParameter (ParameterNumber (self .MIN_DISTANCE ,
73- self .tr ('Minimum distance' ), 0.0 , None , 0.0 ))
74- self .addOutput (OutputVector (self .OUTPUT , self .tr ('Random points' ), datatype = [dataobjects .TYPE_VECTOR_POINT ]))
72+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT ,
73+ self .tr ('Input layer' ),
74+ [QgsProcessing .TypeVectorLine ]))
75+ self .addParameter (QgsProcessingParameterNumber (self .POINTS_NUMBER ,
76+ self .tr ('Number of points' ),
77+ QgsProcessingParameterNumber .Integer ,
78+ 1 , False , 1 , 1000000000 ))
79+ self .addParameter (QgsProcessingParameterNumber (self .MIN_DISTANCE ,
80+ self .tr ('Minimum distance between points' ),
81+ QgsProcessingParameterNumber .Double ,
82+ 0 , False , 0 , 1000000000 ))
83+ params = []
84+ params .append (QgsProcessingParameterBoolean (self .ADD_Z ,
85+ self .tr ('Add Z coordinate' ),
86+ False ))
87+ params .append (QgsProcessingParameterBoolean (self .ADD_M ,
88+ self .tr ('Add M coordinate' ),
89+ False ))
90+ for p in params :
91+ p .setFlags (p .flags () | QgsProcessingParameterDefinition .FlagAdvanced )
92+ self .addParameter (p )
93+
94+ self .addParameter (QgsProcessingParameterFeatureSink (self .OUTPUT ,
95+ self .tr ('Random points' ),
96+ type = QgsProcessing .TypeVectorPoint ))
7597
7698 def name (self ):
7799 return 'randompointsalongline'
@@ -80,35 +102,48 @@ def displayName(self):
80102 return self .tr ('Random points along line' )
81103
82104 def processAlgorithm (self , parameters , context , feedback ):
83- layer = QgsProcessingUtils .mapLayerFromString (self .getParameterValue (self .VECTOR ), context )
84- pointCount = float (self .getParameterValue (self .POINT_NUMBER ))
85- minDistance = float (self .getParameterValue (self .MIN_DISTANCE ))
105+ source = self .parameterAsSource (parameters , self .INPUT , context )
106+ pointCount = self .parameterAsDouble (parameters , self .POINTS_NUMBER , context )
107+ minDistance = self .parameterAsDouble (parameters , self .MIN_DISTANCE , context )
108+ addZ = self .parameterAsBool (parameters , self .ADD_Z , context )
109+ addM = self .parameterAsBool (parameters , self .ADD_M , context )
86110
87111 fields = QgsFields ()
88112 fields .append (QgsField ('id' , QVariant .Int , '' , 10 , 0 ))
89- writer = self .getOutputFromName (self .OUTPUT ).getVectorWriter (fields , QgsWkbTypes .Point , layer .crs (), context )
113+
114+ wkbType = QgsWkbTypes .Point
115+ if addZ :
116+ wkbType = QgsWkbTypes .addZ (wkbType )
117+ if addM :
118+ wkbType = QgsWkbTypes .addM (wkbType )
119+
120+ (sink , dest_id ) = self .parameterAsSink (parameters , self .OUTPUT , context ,
121+ fields , wkbType , source .sourceCrs ())
90122
91123 nPoints = 0
92124 nIterations = 0
93125 maxIterations = pointCount * 200
94- featureCount = layer .featureCount ()
126+ featureCount = source .featureCount ()
95127 total = 100.0 / pointCount if pointCount else 1
96128
97129 index = QgsSpatialIndex ()
98130 points = dict ()
99131
100132 da = QgsDistanceArea ()
101- da .setSourceCrs (layer .sourceCrs ())
133+ da .setSourceCrs (source .sourceCrs ())
102134 da .setEllipsoid (QgsProject .instance ().ellipsoid ())
103135
104136 request = QgsFeatureRequest ()
105137
106138 random .seed ()
107139
108140 while nIterations < maxIterations and nPoints < pointCount :
141+ if feedback .isCanceled ():
142+ break
143+
109144 # pick random feature
110145 fid = random .randint (0 , featureCount - 1 )
111- f = next (layer .getFeatures (request .setFilterFid (fid ).setSubsetOfAttributes ([])))
146+ f = next (source .getFeatures (request .setFilterFid (fid ).setSubsetOfAttributes ([])))
112147 fGeom = f .geometry ()
113148
114149 if fGeom .isMultipart ():
@@ -135,23 +170,28 @@ def processAlgorithm(self, parameters, context, feedback):
135170 ry = (startPoint .y () + d * endPoint .y ()) / (1 + d )
136171
137172 # generate random point
138- pnt = QgsPointXY (rx , ry )
139- geom = QgsGeometry .fromPoint (pnt )
140- if vector .checkMinDistance (pnt , index , minDistance , points ):
173+ pnt = QgsPoint (rx , ry )
174+ p = QgsPointXY (rx , ry )
175+ if addZ :
176+ pnt .addZValue (0.0 )
177+ if addM :
178+ pnt .addMValue (0.0 )
179+ geom = QgsGeometry (pnt )
180+ if vector .checkMinDistance (p , index , minDistance , points ):
141181 f = QgsFeature (nPoints )
142182 f .initAttributes (1 )
143183 f .setFields (fields )
144184 f .setAttribute ('id' , nPoints )
145185 f .setGeometry (geom )
146- writer .addFeature (f , QgsFeatureSink .FastInsert )
186+ sink .addFeature (f , QgsFeatureSink .FastInsert )
147187 index .insertFeature (f )
148- points [nPoints ] = pnt
188+ points [nPoints ] = p
149189 nPoints += 1
150190 feedback .setProgress (int (nPoints * total ))
151191 nIterations += 1
152192
153193 if nPoints < pointCount :
154- QgsMessageLog . logMessage (self .tr ('Can not generate requested number of random points. '
155- 'Maximum number of attempts exceeded.' ), self . tr ( 'Processing' ), QgsMessageLog . INFO )
194+ feedback . pushInfo (self .tr ('Could not generate requested number of random points. '
195+ 'Maximum number of attempts exceeded.' ))
156196
157- del writer
197+ return { self . OUTPUT : dest_id }
0 commit comments