Skip to content
Permalink
Browse files

[processing] port Random points in polygons

  • Loading branch information
alexbruy committed Jul 21, 2017
1 parent ae2e32b commit f8b0c06942f6d7a39e61d6041c79233b56a13839
@@ -86,6 +86,7 @@
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
from .RandomPointsExtent import RandomPointsExtent
from .RandomPointsLayer import RandomPointsLayer
from .RandomPointsPolygons import RandomPointsPolygons
from .RegularPoints import RegularPoints
from .ReverseLineDirection import ReverseLineDirection
from .Ruggedness import Ruggedness
@@ -143,8 +144,6 @@
# from .PointsDisplacement import PointsDisplacement
# from .PointsFromPolygons import PointsFromPolygons
# from .PointsFromLines import PointsFromLines
# from .RandomPointsPolygonsFixed import RandomPointsPolygonsFixed
# from .RandomPointsPolygonsVariable import RandomPointsPolygonsVariable
# from .RandomPointsAlongLines import RandomPointsAlongLines
# from .PointsToPaths import PointsToPaths
# from .SetVectorStyle import SetVectorStyle
@@ -274,6 +273,7 @@ def getAlgs(self):
RandomExtractWithinSubsets(),
RandomPointsExtent(),
RandomPointsLayer(),
RandomPointsPolygons(),
RegularPoints(),
ReverseLineDirection(),
Ruggedness(),
@@ -0,0 +1,220 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
RandomPointsPolygons.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 os
import random

from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsField,
QgsFeatureSink,
QgsFeature,
QgsFields,
QgsGeometry,
QgsPoint,
QgsPointXY,
QgsWkbTypes,
QgsSpatialIndex,
QgsFeatureRequest,
QgsExpression,
QgsDistanceArea,
QgsProject,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterNumber,
QgsProcessingParameterBoolean,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterExpression,
QgsProcessingParameterEnum,
QgsProcessingParameterDefinition)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]


class RandomPointsPolygons(QgisAlgorithm):

INPUT = 'INPUT'
EXPRESSION = 'EXPRESSION'
MIN_DISTANCE = 'MIN_DISTANCE'
STRATEGY = 'STRATEGY'
ADD_Z = 'ADD_Z'
ADD_M = 'ADD_M'
OUTPUT = 'OUTPUT'

def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'random_points.png'))

def group(self):
return self.tr('Vector creation tools')

def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.strategies = [self.tr('Points count'),
self.tr('Points density')]

self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterEnum(self.STRATEGY,
self.tr('Sampling strategy'),
self.strategies,
False,
0))
self.addParameter(QgsProcessingParameterExpression(self.EXPRESSION,
self.tr('Expression'),
parentLayerParameterName=self.INPUT))
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 'randompointsinsidepolygons'

def displayName(self):
return self.tr('Random points inside polygons')

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
strategy = self.parameterAsEnum(parameters, self.STRATEGY, 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)

expression = QgsExpression(self.parameterAsString(parameters, self.EXPRESSION, context))
if expression.hasParserError():
raise ProcessingException(expression.parserErrorString())

expressionContext = self.createExpressionContext(parameters, context)
if not expression.prepare(expressionContext):
raise ProcessingException(
self.tr('Evaluation error: {0}').format(expression.evalErrorString()))

fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0))

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())

da = QgsDistanceArea()
da.setSourceCrs(source.sourceCrs())
da.setEllipsoid(QgsProject.instance().ellipsoid())

total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, f in enumerate(source.getFeatures()):
if feedback.isCanceled():
break

expressionContext.setFeature(f)
value = expression.evaluate(expressionContext)
if expression.hasEvalError():
feedback.pushInfo(
self.tr('Evaluation error for feature ID {}: {}').format(f.id(), expression.evalErrorString()))
continue

fGeom = f.geometry()
bbox = fGeom.boundingBox()
if strategy == 0:
pointCount = int(value)
else:
pointCount = int(round(value * da.measureArea(fGeom)))

if pointCount == 0:
feedback.pushInfo("Skip feature {} as number of points for it is 0.")
continue

index = QgsSpatialIndex()
points = dict()

nPoints = 0
nIterations = 0
maxIterations = pointCount * 200
total = 100.0 / pointCount if pointCount else 1

random.seed()

while nIterations < maxIterations and nPoints < pointCount:
if feedback.isCanceled():
break

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(fGeom) and \
vector.checkMinDistance(p, index, minDistance, points):
f = QgsFeature(nPoints)
f.initAttributes(1)
f.setFields(fields)
f.setAttribute('id', nPoints)
f.setGeometry(geom)
sink.addFeature(f, QgsFeatureSink.FastInsert)
index.insertFeature(f)
points[nPoints] = p
nPoints += 1
feedback.setProgress(int(nPoints * total))
nIterations += 1

if nPoints < pointCount:
feedback.pushInfo(self.tr('Could not generate requested number of random '
'points. Maximum number of attempts exceeded.'))

feedback.setProgress(0)

return {self.OUTPUT: dest_id}

This file was deleted.

0 comments on commit f8b0c06

Please sign in to comment.
You can’t perform that action at this time.