From eb9f45cbb09ce77b03fe210eaf505fc9121ff628 Mon Sep 17 00:00:00 2001 From: Alexander Bruy Date: Fri, 21 Jul 2017 10:29:01 +0300 Subject: [PATCH] [processing] port Random points within extent --- .../algs/qgis/QGISAlgorithmProvider.py | 3 +- .../algs/qgis/RandomPointsExtent.py | 128 ++++++++++++------ 2 files changed, 85 insertions(+), 46 deletions(-) diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index ab06ea33ab2..c3477ec6e39 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -84,6 +84,7 @@ from .PolygonsToLines import PolygonsToLines from .PostGISExecuteSQL import PostGISExecuteSQL from .RandomExtract import RandomExtract from .RandomExtractWithinSubsets import RandomExtractWithinSubsets +from .RandomPointsExtent import RandomPointsExtent from .RegularPoints import RegularPoints from .ReverseLineDirection import ReverseLineDirection from .Ruggedness import Ruggedness @@ -141,7 +142,6 @@ from .ZonalStatistics import ZonalStatistics # from .PointsDisplacement import PointsDisplacement # from .PointsFromPolygons import PointsFromPolygons # from .PointsFromLines import PointsFromLines -# from .RandomPointsExtent import RandomPointsExtent # from .RandomPointsLayer import RandomPointsLayer # from .RandomPointsPolygonsFixed import RandomPointsPolygonsFixed # from .RandomPointsPolygonsVariable import RandomPointsPolygonsVariable @@ -272,6 +272,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider): PostGISExecuteSQL(), RandomExtract(), RandomExtractWithinSubsets(), + RandomPointsExtent(), RegularPoints(), ReverseLineDirection(), Ruggedness(), diff --git a/python/plugins/processing/algs/qgis/RandomPointsExtent.py b/python/plugins/processing/algs/qgis/RandomPointsExtent.py index ead6c09b5b4..d3e6fab03cc 100644 --- a/python/plugins/processing/algs/qgis/RandomPointsExtent.py +++ b/python/plugins/processing/algs/qgis/RandomPointsExtent.py @@ -31,18 +31,26 @@ import random from qgis.PyQt.QtGui import QIcon from qgis.PyQt.QtCore import QVariant -from qgis.core import (QgsGeometry, QgsFeatureSink, QgsRectangle, QgsFeature, QgsFields, QgsWkbTypes, - QgsField, QgsSpatialIndex, QgsPointXY, - QgsCoordinateReferenceSystem, - QgsMessageLog, - QgsProcessingUtils) +from qgis.core import (QgsField, + QgsFeatureSink, + QgsFeature, + QgsFields, + QgsGeometry, + QgsPoint, + QgsPointXY, + QgsWkbTypes, + QgsSpatialIndex, + QgsProcessing, + QgsProcessingException, + QgsProcessingParameterExtent, + QgsProcessingParameterNumber, + QgsProcessingParameterCrs, + QgsProcessingParameterBoolean, + QgsProcessingParameterFeatureSink, + QgsProcessingParameterDefinition) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.core.parameters import ParameterExtent -from processing.core.parameters import ParameterNumber -from processing.core.parameters import ParameterCrs -from processing.core.outputs import OutputVector -from processing.tools import vector, dataobjects +from processing.tools import vector pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] @@ -50,10 +58,12 @@ pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] class RandomPointsExtent(QgisAlgorithm): EXTENT = 'EXTENT' - POINT_NUMBER = 'POINT_NUMBER' + POINTS_NUMBER = 'POINTS_NUMBER' MIN_DISTANCE = 'MIN_DISTANCE' + TARGET_CRS = 'TARGET_CRS' + ADD_Z = 'ADD_Z' + ADD_M = 'ADD_M' OUTPUT = 'OUTPUT' - CRS = 'CRS' def icon(self): return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'random_points.png')) @@ -65,15 +75,33 @@ class RandomPointsExtent(QgisAlgorithm): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(ParameterExtent(self.EXTENT, - self.tr('Input extent'), optional=False)) - self.addParameter(ParameterNumber(self.POINT_NUMBER, - self.tr('Points number'), 1, None, 1)) - self.addParameter(ParameterNumber(self.MIN_DISTANCE, - self.tr('Minimum distance'), 0.0, None, 0.0)) - self.addParameter(ParameterCrs(self.CRS, - self.tr('Output layer CRS'), 'ProjectCrs')) - self.addOutput(OutputVector(self.OUTPUT, self.tr('Random points'), datatype=[dataobjects.TYPE_VECTOR_POINT])) + self.addParameter(QgsProcessingParameterExtent(self.EXTENT, self.tr('Input extent'))) + 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)) + self.addParameter(QgsProcessingParameterCrs(self.TARGET_CRS, + self.tr('Target CRS'), + 'ProjectCrs')) + + 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 'randompointsinextent' @@ -82,24 +110,26 @@ class RandomPointsExtent(QgisAlgorithm): return self.tr('Random points in extent') def processAlgorithm(self, parameters, context, feedback): - pointCount = int(self.getParameterValue(self.POINT_NUMBER)) - minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) - extent = str(self.getParameterValue(self.EXTENT)).split(',') + bbox = self.parameterAsExtent(parameters, self.EXTENT, context) + pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context) + minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context) + crs = self.parameterAsCrs(parameters, self.TARGET_CRS, context) + addZ = self.parameterAsBool(parameters, self.ADD_Z, context) + addM = self.parameterAsBool(parameters, self.ADD_M, context) - crsId = self.getParameterValue(self.CRS) - crs = QgsCoordinateReferenceSystem() - crs.createFromUserInput(crsId) - - xMin = float(extent[0]) - xMax = float(extent[1]) - yMin = float(extent[2]) - yMax = float(extent[3]) - extent = QgsGeometry().fromRect( - QgsRectangle(xMin, yMin, xMax, yMax)) + extent = QgsGeometry().fromRect(bbox) fields = QgsFields() fields.append(QgsField('id', QVariant.Int, '', 10, 0)) - writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, 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, crs) nPoints = 0 nIterations = 0 @@ -112,27 +142,35 @@ class RandomPointsExtent(QgisAlgorithm): random.seed() while nIterations < maxIterations and nPoints < pointCount: - rx = xMin + (xMax - xMin) * random.random() - ry = yMin + (yMax - yMin) * random.random() + if feedback.isCanceled(): + break - pnt = QgsPointXY(rx, ry) - geom = QgsGeometry.fromPoint(pnt) + rx = bbox.xMinimum() + bbox.width() * random.random() + ry = bbox.yMinimum() + bbox.height() * random.random() + + pnt = QgsPoint(rx, ry) + p = QgsPointXY(rx, ry) + if addZ: + pnt.addZValue(0.0) + if addM: + pnt.addMValue(0.0) + geom = QgsGeometry(pnt) if geom.within(extent) and \ - vector.checkMinDistance(pnt, index, minDistance, points): + 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}