diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index bbb26941600..88784721243 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -90,6 +90,7 @@ from PointsDisplacement import PointsDisplacement from ZonalStatistics import ZonalStatistics from PointsFromPolygons import PointsFromPolygons from PointsFromLines import PointsFromLines +from RandomPointsExtent import RandomPointsExtent # from VectorLayerHistogram import VectorLayerHistogram # from VectorLayerScatterplot import VectorLayerScatterplot @@ -119,8 +120,9 @@ class QGISAlgorithmProvider(AlgorithmProvider): VariableDistanceBuffer(), Dissolve(), Difference(), Intersection(), Union(), Clip(), ExtentFromLayer(), RandomSelection(), RandomSelectionWithinSubsets(), - SelectByLocation(), RandomExtract(), RandomExtractWithinSubsets(), - ExtractByLocation(), SpatialJoin(), + SelectByLocation(), RandomExtract(), + RandomExtractWithinSubsets(), ExtractByLocation(), + SpatialJoin(), # ------ mmqgisx ------ mmqgisx_delete_columns_algorithm(), mmqgisx_delete_duplicate_geometries_algorithm(), @@ -141,7 +143,7 @@ class QGISAlgorithmProvider(AlgorithmProvider): StatisticsByCategories(), ConcaveHull(), Polygonize(), RasterLayerStatistics(), PointsDisplacement(), ZonalStatistics(), PointsFromPolygons(), - PointsFromLines(), + PointsFromLines(), RandomPointsExtent(), # ------ raster ------ # CreateConstantRaster(), # ------ graphics ------ diff --git a/python/plugins/processing/algs/qgis/RandomPointsExtent.py b/python/plugins/processing/algs/qgis/RandomPointsExtent.py new file mode 100644 index 00000000000..7378d5f3258 --- /dev/null +++ b/python/plugins/processing/algs/qgis/RandomPointsExtent.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- + +""" +*************************************************************************** + RandomPointsExtent.py + --------------------- + Date : April 2014 + Copyright : (C) 2014 by Alexander Bruy + Email : alexander dot bruy at gmail dot com +*************************************************************************** +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +*************************************************************************** +""" + +__author__ = 'Alexander Bruy' +__date__ = 'April 2014' +__copyright__ = '(C) 2014, Alexander Bruy' + +# This will get replaced with a git SHA1 when you do a git archive + +__revision__ = '$Format:%H$' + +import math +import random + +from PyQt4.QtCore import * + +from qgis.core import * + +from processing import interface +from processing.core.GeoAlgorithm import GeoAlgorithm +from processing.core.ProcessingLog import ProcessingLog +from processing.parameters.ParameterExtent import ParameterExtent +from processing.parameters.ParameterNumber import ParameterNumber +from processing.outputs.OutputVector import OutputVector + + +class RandomPointsExtent(GeoAlgorithm): + + EXTENT = 'EXTENT' + POINT_NUMBER = 'POINT_NUMBER' + MIN_DISTANCE = 'MIN_DISTANCE' + OUTPUT = 'OUTPUT' + + def defineCharacteristics(self): + self.name = 'Random points in extent' + self.group = 'Vector creation tools' + self.addParameter(ParameterExtent(self.EXTENT, 'Input extent')) + self.addParameter( + ParameterNumber(self.POINT_NUMBER, 'Points number', 1, 9999999, 1)) + self.addParameter(ParameterNumber( + self.MIN_DISTANCE, 'Minimum distance', 0.0, 9999999, 0.0)) + self.addOutput(OutputVector(self.OUTPUT, 'Random points')) + + def processAlgorithm(self, progress): + pointCount = int(self.getParameterValue(self.POINT_NUMBER)) + minDistance = float(self.getParameterValue(self.MIN_DISTANCE)) + extent = str(self.getParameterValue(self.EXTENT)).split(',') + + xMin = float(extent[0]) + xMax = float(extent[1]) + yMin = float(extent[2]) + yMax = float(extent[3]) + extent = QgsGeometry().fromRect( + QgsRectangle(xMin, yMin, xMax, yMax)) + + fields = QgsFields() + fields.append(QgsField('id', QVariant.Int, '', 10, 0)) + mapCRS = interface.iface.mapCanvas().mapSettings().destinationCrs() + writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( + fields, QGis.WKBPoint, mapCRS) + + nPoints = 0 + nIterations = 0 + maxIterations = pointCount * 200 + total = 100.0 / pointCount + + index = QgsSpatialIndex() + points = dict() + + while nIterations < maxIterations and nPoints < pointCount: + rx = xMin + (xMax - xMin) * random.random() + ry = yMin + (yMax - yMin) * random.random() + + pnt = QgsPoint(rx, ry) + geom = QgsGeometry.fromPoint(pnt) + if geom.within(extent) and \ + self.checkMinDistance(pnt, index, minDistance, points): + f = QgsFeature(nPoints) + f.initAttributes(1) + f.setFields(fields) + f.setAttribute('id', nPoints) + f.setGeometry(geom) + writer.addFeature(f) + index.insertFeature(f) + points[nPoints] = pnt + nPoints += 1 + progress.setPercentage(int(nPoints * total)) + nIterations += 1 + + if nPoints < pointCount: + ProcessingLog.addToLog( + ProcessingLog.LOG_INFO, + 'Can not generate requested number of random points. Maximum ' + 'number of attempts exceeded.') + + del writer + + def checkMinDistance(self, point, index, distance, points): + if distance == 0: + return True + + neighbors = index.nearestNeighbor(point, 1) + if len(neighbors) == 0: + return True + + if neighbors[0] in points: + np = points[neighbors[0]] + if np.sqrDist(point) < (distance * distance): + return False + + return True