[processing] restore Random points in layer bounds

This commit is contained in:
Alexander Bruy 2017-07-21 11:15:31 +03:00
parent eb9f45cbb0
commit ae2e32b36e
2 changed files with 86 additions and 34 deletions

View File

@ -85,6 +85,7 @@ from .PostGISExecuteSQL import PostGISExecuteSQL
from .RandomExtract import RandomExtract from .RandomExtract import RandomExtract
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
from .RandomPointsExtent import RandomPointsExtent from .RandomPointsExtent import RandomPointsExtent
from .RandomPointsLayer import RandomPointsLayer
from .RegularPoints import RegularPoints from .RegularPoints import RegularPoints
from .ReverseLineDirection import ReverseLineDirection from .ReverseLineDirection import ReverseLineDirection
from .Ruggedness import Ruggedness from .Ruggedness import Ruggedness
@ -142,7 +143,6 @@ from .ZonalStatistics import ZonalStatistics
# from .PointsDisplacement import PointsDisplacement # from .PointsDisplacement import PointsDisplacement
# from .PointsFromPolygons import PointsFromPolygons # from .PointsFromPolygons import PointsFromPolygons
# from .PointsFromLines import PointsFromLines # from .PointsFromLines import PointsFromLines
# from .RandomPointsLayer import RandomPointsLayer
# from .RandomPointsPolygonsFixed import RandomPointsPolygonsFixed # from .RandomPointsPolygonsFixed import RandomPointsPolygonsFixed
# from .RandomPointsPolygonsVariable import RandomPointsPolygonsVariable # from .RandomPointsPolygonsVariable import RandomPointsPolygonsVariable
# from .RandomPointsAlongLines import RandomPointsAlongLines # from .RandomPointsAlongLines import RandomPointsAlongLines
@ -273,6 +273,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
RandomExtract(), RandomExtract(),
RandomExtractWithinSubsets(), RandomExtractWithinSubsets(),
RandomPointsExtent(), RandomPointsExtent(),
RandomPointsLayer(),
RegularPoints(), RegularPoints(),
ReverseLineDirection(), ReverseLineDirection(),
Ruggedness(), Ruggedness(),

View File

@ -30,25 +30,37 @@ import random
from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QVariant from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsGeometry, QgsFeatureSink, QgsFields, QgsField, QgsSpatialIndex, QgsWkbTypes, from qgis.core import (QgsField,
QgsPointXY, QgsFeature, QgsFeatureRequest, QgsFeatureSink,
QgsMessageLog, QgsFeature,
QgsProcessingUtils) QgsFields,
QgsGeometry,
QgsPoint,
QgsPointXY,
QgsWkbTypes,
QgsSpatialIndex,
QgsFeatureRequest,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterNumber,
QgsProcessingParameterBoolean,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDefinition)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector from processing.tools import vector
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class RandomPointsLayer(QgisAlgorithm): class RandomPointsLayer(QgisAlgorithm):
VECTOR = 'VECTOR' INPUT = 'INPUT'
POINT_NUMBER = 'POINT_NUMBER' POINTS_NUMBER = 'POINTS_NUMBER'
MIN_DISTANCE = 'MIN_DISTANCE' MIN_DISTANCE = 'MIN_DISTANCE'
ADD_Z = 'ADD_Z'
ADD_M = 'ADD_M'
OUTPUT = 'OUTPUT' OUTPUT = 'OUTPUT'
def icon(self): def icon(self):
@ -61,13 +73,31 @@ class RandomPointsLayer(QgisAlgorithm):
super().__init__() super().__init__()
def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.VECTOR, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_POLYGON])) self.tr('Input layer'),
self.addParameter(ParameterNumber(self.POINT_NUMBER, [QgsProcessing.TypeVectorPolygon]))
self.tr('Points number'), 1, None, 1)) self.addParameter(QgsProcessingParameterNumber(self.POINTS_NUMBER,
self.addParameter(ParameterNumber(self.MIN_DISTANCE, self.tr('Number of points'),
self.tr('Minimum distance'), 0.0, None, 0.0)) QgsProcessingParameterNumber.Integer,
self.addOutput(OutputVector(self.OUTPUT, self.tr('Random points'), datatype=[dataobjects.TYPE_VECTOR_POINT])) 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): def name(self):
return 'randompointsinlayerbounds' return 'randompointsinlayerbounds'
@ -76,16 +106,26 @@ class RandomPointsLayer(QgisAlgorithm):
return self.tr('Random points in layer bounds') return self.tr('Random points in layer bounds')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.VECTOR), context) source = self.parameterAsSource(parameters, self.INPUT, context)
pointCount = int(self.getParameterValue(self.POINT_NUMBER)) pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)
addZ = self.parameterAsBool(parameters, self.ADD_Z, context)
addM = self.parameterAsBool(parameters, self.ADD_M, context)
bbox = layer.extent() bbox = source.sourceExtent()
idxLayer = QgsProcessingUtils.createSpatialIndex(layer, context) sourceIndex = QgsSpatialIndex(source, feedback)
fields = QgsFields() fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0)) 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 nPoints = 0
nIterations = 0 nIterations = 0
@ -98,16 +138,27 @@ class RandomPointsLayer(QgisAlgorithm):
random.seed() random.seed()
while nIterations < maxIterations and nPoints < pointCount: while nIterations < maxIterations and nPoints < pointCount:
if feedback.isCanceled():
break
rx = bbox.xMinimum() + bbox.width() * random.random() rx = bbox.xMinimum() + bbox.width() * random.random()
ry = bbox.yMinimum() + bbox.height() * random.random() ry = bbox.yMinimum() + bbox.height() * random.random()
pnt = QgsPointXY(rx, ry) pnt = QgsPoint(rx, ry)
geom = QgsGeometry.fromPoint(pnt) p = QgsPointXY(rx, ry)
ids = idxLayer.intersects(geom.buffer(5, 5).boundingBox()) if addZ:
pnt.addZValue(0.0)
if addM:
pnt.addMValue(0.0)
geom = QgsGeometry(pnt)
ids = sourceIndex.intersects(geom.buffer(5, 5).boundingBox())
if len(ids) > 0 and \ if len(ids) > 0 and \
vector.checkMinDistance(pnt, index, minDistance, points): vector.checkMinDistance(p, index, minDistance, points):
request = QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([]) request = QgsFeatureRequest().setFilterFids(ids).setSubsetOfAttributes([])
for f in layer.getFeatures(request): for f in source.getFeatures(request):
if feedback.isCanceled():
break
tmpGeom = f.geometry() tmpGeom = f.geometry()
if geom.within(tmpGeom): if geom.within(tmpGeom):
f = QgsFeature(nPoints) f = QgsFeature(nPoints)
@ -115,15 +166,15 @@ class RandomPointsLayer(QgisAlgorithm):
f.setFields(fields) f.setFields(fields)
f.setAttribute('id', nPoints) f.setAttribute('id', nPoints)
f.setGeometry(geom) f.setGeometry(geom)
writer.addFeature(f, QgsFeatureSink.FastInsert) sink.addFeature(f, QgsFeatureSink.FastInsert)
index.insertFeature(f) index.insertFeature(f)
points[nPoints] = pnt points[nPoints] = p
nPoints += 1 nPoints += 1
feedback.setProgress(int(nPoints * total)) feedback.setProgress(int(nPoints * total))
nIterations += 1 nIterations += 1
if nPoints < pointCount: if nPoints < pointCount:
QgsMessageLog.logMessage(self.tr('Can not generate requested number of random points. ' feedback.pushInfo(self.tr('Could not generate requested number of random points. '
'Maximum number of attempts exceeded.'), self.tr('Processing'), QgsMessageLog.INFO) 'Maximum number of attempts exceeded.'))
del writer return {self.OUTPUT: dest_id}