Skip to content

Commit 1b423ca

Browse files
committedMay 16, 2014
[processing] new tool: random points in layer bounds
Work done for Faunalia funded by Prof. António Mira (University of Évora, Portugal, Unidade de Biologia da Conservação) and Dr. Rosana Peixoto
1 parent bfc33ba commit 1b423ca

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed
 

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
from PointsFromPolygons import PointsFromPolygons
9292
from PointsFromLines import PointsFromLines
9393
from RandomPointsExtent import RandomPointsExtent
94+
from RandomPointsLayer import RandomPointsLayer
9495

9596
# from VectorLayerHistogram import VectorLayerHistogram
9697
# from VectorLayerScatterplot import VectorLayerScatterplot
@@ -144,6 +145,7 @@ def __init__(self):
144145
RasterLayerStatistics(), PointsDisplacement(),
145146
ZonalStatistics(), PointsFromPolygons(),
146147
PointsFromLines(), RandomPointsExtent(),
148+
RandomPointsLayer(),
147149
# ------ raster ------
148150
# CreateConstantRaster(),
149151
# ------ graphics ------
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
RandomPointsLayer.py
6+
---------------------
7+
Date : April 2014
8+
Copyright : (C) 2014 by Alexander Bruy
9+
Email : alexander dot bruy at gmail dot com
10+
***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************
18+
"""
19+
20+
__author__ = 'Alexander Bruy'
21+
__date__ = 'April 2014'
22+
__copyright__ = '(C) 2014, Alexander Bruy'
23+
24+
# This will get replaced with a git SHA1 when you do a git archive
25+
26+
__revision__ = '$Format:%H$'
27+
28+
import math
29+
import random
30+
31+
from PyQt4.QtCore import *
32+
33+
from qgis.core import *
34+
35+
from processing import interface
36+
from processing.core.GeoAlgorithm import GeoAlgorithm
37+
from processing.core.ProcessingLog import ProcessingLog
38+
from processing.parameters.ParameterVector import ParameterVector
39+
from processing.parameters.ParameterNumber import ParameterNumber
40+
from processing.outputs.OutputVector import OutputVector
41+
from processing.tools import dataobjects, vector
42+
43+
44+
class RandomPointsLayer(GeoAlgorithm):
45+
46+
VECTOR = 'VECTOR'
47+
POINT_NUMBER = 'POINT_NUMBER'
48+
MIN_DISTANCE = 'MIN_DISTANCE'
49+
OUTPUT = 'OUTPUT'
50+
51+
def defineCharacteristics(self):
52+
self.name = 'Random points in layer bounds'
53+
self.group = 'Vector creation tools'
54+
self.addParameter(ParameterVector(self.VECTOR,
55+
'Input layer',[ParameterVector.VECTOR_TYPE_POLYGON]))
56+
self.addParameter(
57+
ParameterNumber(self.POINT_NUMBER, 'Points number', 1, 9999999, 1))
58+
self.addParameter(ParameterNumber(
59+
self.MIN_DISTANCE, 'Minimum distance', 0.0, 9999999, 0.0))
60+
self.addOutput(OutputVector(self.OUTPUT, 'Random points'))
61+
62+
def processAlgorithm(self, progress):
63+
layer = dataobjects.getObjectFromUri(
64+
self.getParameterValue(self.VECTOR))
65+
pointCount = int(self.getParameterValue(self.POINT_NUMBER))
66+
minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
67+
68+
bbox = layer.extent()
69+
extent = QgsGeometry().fromRect(bbox)
70+
idxLayer = vector.spatialindex(layer)
71+
72+
fields = QgsFields()
73+
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
74+
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
75+
fields, QGis.WKBPoint, layer.dataProvider().crs())
76+
77+
nPoints = 0
78+
nIterations = 0
79+
maxIterations = pointCount * 200
80+
total = 100.0 / pointCount
81+
82+
index = QgsSpatialIndex()
83+
points = dict()
84+
85+
request = QgsFeatureRequest()
86+
87+
while nIterations < maxIterations and nPoints < pointCount:
88+
rx = bbox.xMinimum() + bbox.width() * random.random()
89+
ry = bbox.yMinimum() + bbox.height() * random.random()
90+
91+
pnt = QgsPoint(rx, ry)
92+
geom = QgsGeometry.fromPoint(pnt)
93+
ids = idxLayer.intersects(geom.buffer(5, 5).boundingBox())
94+
if len(ids) > 0 and \
95+
self.checkMinDistance(pnt, index, minDistance, points):
96+
for i in ids:
97+
f = layer.getFeatures(request.setFilterFid(i)).next()
98+
tmpGeom = QgsGeometry(f.geometry())
99+
if geom.within(tmpGeom):
100+
f = QgsFeature(nPoints)
101+
f.initAttributes(1)
102+
f.setFields(fields)
103+
f.setAttribute('id', nPoints)
104+
f.setGeometry(geom)
105+
writer.addFeature(f)
106+
index.insertFeature(f)
107+
points[nPoints] = pnt
108+
nPoints += 1
109+
progress.setPercentage(int(nPoints * total))
110+
nIterations += 1
111+
112+
if nPoints < pointCount:
113+
ProcessingLog.addToLog(
114+
ProcessingLog.LOG_INFO,
115+
'Can not generate requested number of random points. Maximum '
116+
'number of attempts exceeded.')
117+
118+
del writer
119+
120+
def checkMinDistance(self, point, index, distance, points):
121+
if distance == 0:
122+
return True
123+
124+
neighbors = index.nearestNeighbor(point, 1)
125+
if len(neighbors) == 0:
126+
return True
127+
128+
if neighbors[0] in points:
129+
np = points[neighbors[0]]
130+
if np.sqrDist(point) < (distance * distance):
131+
return False
132+
133+
return True

0 commit comments

Comments
 (0)
Please sign in to comment.