[processing] port Random points along lines

This commit is contained in:
Alexander Bruy 2017-07-21 15:22:37 +03:00
parent f8b0c06942
commit c7645a3884
2 changed files with 80 additions and 39 deletions

View File

@ -84,6 +84,7 @@ from .PolygonsToLines import PolygonsToLines
from .PostGISExecuteSQL import PostGISExecuteSQL
from .RandomExtract import RandomExtract
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
from .RandomPointsAlongLines import RandomPointsAlongLines
from .RandomPointsExtent import RandomPointsExtent
from .RandomPointsLayer import RandomPointsLayer
from .RandomPointsPolygons import RandomPointsPolygons
@ -144,7 +145,6 @@ from .ZonalStatistics import ZonalStatistics
# from .PointsDisplacement import PointsDisplacement
# from .PointsFromPolygons import PointsFromPolygons
# from .PointsFromLines import PointsFromLines
# from .RandomPointsAlongLines import RandomPointsAlongLines
# from .PointsToPaths import PointsToPaths
# from .SetVectorStyle import SetVectorStyle
# from .SetRasterStyle import SetRasterStyle
@ -271,6 +271,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
PostGISExecuteSQL(),
RandomExtract(),
RandomExtractWithinSubsets(),
RandomPointsAlongLines(),
RandomPointsExtent(),
RandomPointsLayer(),
RandomPointsPolygons(),

View File

@ -29,33 +29,37 @@ __revision__ = '$Format:%H$'
import random
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsApplication,
from qgis.core import (QgsField,
QgsFeatureSink,
QgsFields,
QgsField,
QgsGeometry,
QgsSpatialIndex,
QgsWkbTypes,
QgsDistanceArea,
QgsFeatureRequest,
QgsFeature,
QgsFields,
QgsGeometry,
QgsPoint,
QgsPointXY,
QgsMessageLog,
QgsWkbTypes,
QgsSpatialIndex,
QgsFeatureRequest,
QgsDistanceArea,
QgsProject,
QgsProcessingUtils)
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterNumber,
QgsProcessingParameterBoolean,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector
from processing.tools import vector
class RandomPointsAlongLines(QgisAlgorithm):
VECTOR = 'VECTOR'
POINT_NUMBER = 'POINT_NUMBER'
INPUT = 'INPUT'
POINTS_NUMBER = 'POINTS_NUMBER'
MIN_DISTANCE = 'MIN_DISTANCE'
ADD_Z = 'ADD_Z'
ADD_M = 'ADD_M'
OUTPUT = 'OUTPUT'
def group(self):
@ -65,13 +69,31 @@ class RandomPointsAlongLines(QgisAlgorithm):
super().__init__()
def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.VECTOR,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterNumber(self.POINT_NUMBER,
self.tr('Number of points'), 1, None, 1))
self.addParameter(ParameterNumber(self.MIN_DISTANCE,
self.tr('Minimum distance'), 0.0, None, 0.0))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Random points'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterNumber(self.POINTS_NUMBER,
self.tr('Number of points'),
QgsProcessingParameterNumber.Integer,
1, False, 1, 1000000000))
self.addParameter(QgsProcessingParameterNumber(self.MIN_DISTANCE,
self.tr('Minimum distance between points'),
QgsProcessingParameterNumber.Double,
0, False, 0, 1000000000))
params = []
params.append(QgsProcessingParameterBoolean(self.ADD_Z,
self.tr('Add Z coordinate'),
False))
params.append(QgsProcessingParameterBoolean(self.ADD_M,
self.tr('Add M coordinate'),
False))
for p in params:
p.setFlags(p.flags() | QgsProcessingParameterDefinition.FlagAdvanced)
self.addParameter(p)
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Random points'),
type=QgsProcessing.TypeVectorPoint))
def name(self):
return 'randompointsalongline'
@ -80,25 +102,35 @@ class RandomPointsAlongLines(QgisAlgorithm):
return self.tr('Random points along line')
def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.VECTOR), context)
pointCount = float(self.getParameterValue(self.POINT_NUMBER))
minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
source = self.parameterAsSource(parameters, self.INPUT, context)
pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
addZ = self.parameterAsBool(parameters, self.ADD_Z, context)
addM = self.parameterAsBool(parameters, self.ADD_M, context)
fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context)
wkbType = QgsWkbTypes.Point
if addZ:
wkbType = QgsWkbTypes.addZ(wkbType)
if addM:
wkbType = QgsWkbTypes.addM(wkbType)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, wkbType, source.sourceCrs())
nPoints = 0
nIterations = 0
maxIterations = pointCount * 200
featureCount = layer.featureCount()
featureCount = source.featureCount()
total = 100.0 / pointCount if pointCount else 1
index = QgsSpatialIndex()
points = dict()
da = QgsDistanceArea()
da.setSourceCrs(layer.sourceCrs())
da.setSourceCrs(source.sourceCrs())
da.setEllipsoid(QgsProject.instance().ellipsoid())
request = QgsFeatureRequest()
@ -106,9 +138,12 @@ class RandomPointsAlongLines(QgisAlgorithm):
random.seed()
while nIterations < maxIterations and nPoints < pointCount:
if feedback.isCanceled():
break
# pick random feature
fid = random.randint(0, featureCount - 1)
f = next(layer.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
f = next(source.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
fGeom = f.geometry()
if fGeom.isMultipart():
@ -135,23 +170,28 @@ class RandomPointsAlongLines(QgisAlgorithm):
ry = (startPoint.y() + d * endPoint.y()) / (1 + d)
# generate random point
pnt = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPoint(pnt)
if vector.checkMinDistance(pnt, index, minDistance, points):
pnt = QgsPoint(rx, ry)
p = QgsPointXY(rx, ry)
if addZ:
pnt.addZValue(0.0)
if addM:
pnt.addMValue(0.0)
geom = QgsGeometry(pnt)
if vector.checkMinDistance(p, index, minDistance, points):
f = QgsFeature(nPoints)
f.initAttributes(1)
f.setFields(fields)
f.setAttribute('id', nPoints)
f.setGeometry(geom)
writer.addFeature(f, QgsFeatureSink.FastInsert)
sink.addFeature(f, QgsFeatureSink.FastInsert)
index.insertFeature(f)
points[nPoints] = pnt
points[nPoints] = p
nPoints += 1
feedback.setProgress(int(nPoints * total))
nIterations += 1
if nPoints < pointCount:
QgsMessageLog.logMessage(self.tr('Can not generate requested number of random points. '
'Maximum number of attempts exceeded.'), self.tr('Processing'), QgsMessageLog.INFO)
feedback.pushInfo(self.tr('Could not generate requested number of random points. '
'Maximum number of attempts exceeded.'))
del writer
return {self.OUTPUT: dest_id}