Skip to content

Commit c7645a3

Browse files
committed
[processing] port Random points along lines
1 parent f8b0c06 commit c7645a3

File tree

2 files changed

+78
-37
lines changed

2 files changed

+78
-37
lines changed

python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
from .PostGISExecuteSQL import PostGISExecuteSQL
8585
from .RandomExtract import RandomExtract
8686
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
87+
from .RandomPointsAlongLines import RandomPointsAlongLines
8788
from .RandomPointsExtent import RandomPointsExtent
8889
from .RandomPointsLayer import RandomPointsLayer
8990
from .RandomPointsPolygons import RandomPointsPolygons
@@ -144,7 +145,6 @@
144145
# from .PointsDisplacement import PointsDisplacement
145146
# from .PointsFromPolygons import PointsFromPolygons
146147
# from .PointsFromLines import PointsFromLines
147-
# from .RandomPointsAlongLines import RandomPointsAlongLines
148148
# from .PointsToPaths import PointsToPaths
149149
# from .SetVectorStyle import SetVectorStyle
150150
# from .SetRasterStyle import SetRasterStyle
@@ -271,6 +271,7 @@ def getAlgs(self):
271271
PostGISExecuteSQL(),
272272
RandomExtract(),
273273
RandomExtractWithinSubsets(),
274+
RandomPointsAlongLines(),
274275
RandomPointsExtent(),
275276
RandomPointsLayer(),
276277
RandomPointsPolygons(),

python/plugins/processing/algs/qgis/RandomPointsAlongLines.py

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,33 +29,37 @@
2929
import random
3030

3131
from 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

4752
from 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

5456
class 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

Comments
 (0)