Skip to content

Commit

Permalink
Merge pull request #4901 from alexbruy/processing-random
Browse files Browse the repository at this point in the history
[processing] restore "random" algorithms
  • Loading branch information
alexbruy committed Jul 24, 2017
2 parents 2723f4f + c440ade commit b842043
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 420 deletions.
13 changes: 8 additions & 5 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -84,6 +84,10 @@
from .PostGISExecuteSQL import PostGISExecuteSQL
from .RandomExtract import RandomExtract
from .RandomExtractWithinSubsets import RandomExtractWithinSubsets
from .RandomPointsAlongLines import RandomPointsAlongLines
from .RandomPointsExtent import RandomPointsExtent
from .RandomPointsLayer import RandomPointsLayer
from .RandomPointsPolygons import RandomPointsPolygons
from .RegularPoints import RegularPoints
from .ReverseLineDirection import ReverseLineDirection
from .Ruggedness import Ruggedness
Expand Down Expand Up @@ -141,11 +145,6 @@
# 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
# from .RandomPointsAlongLines import RandomPointsAlongLines
# from .PointsToPaths import PointsToPaths
# from .SetVectorStyle import SetVectorStyle
# from .SetRasterStyle import SetRasterStyle
Expand Down Expand Up @@ -272,6 +271,10 @@ def getAlgs(self):
PostGISExecuteSQL(),
RandomExtract(),
RandomExtractWithinSubsets(),
RandomPointsAlongLines(),
RandomPointsExtent(),
RandomPointsLayer(),
RandomPointsPolygons(),
RegularPoints(),
ReverseLineDirection(),
Ruggedness(),
Expand Down
84 changes: 48 additions & 36 deletions python/plugins/processing/algs/qgis/RandomPointsAlongLines.py
Expand Up @@ -29,32 +29,32 @@
import random

from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsApplication,
from qgis.core import (QgsField,
QgsFeatureSink,
QgsFeature,
QgsFields,
QgsField,
QgsGeometry,
QgsSpatialIndex,
QgsPointXY,
QgsWkbTypes,
QgsDistanceArea,
QgsSpatialIndex,
QgsFeatureRequest,
QgsFeature,
QgsPointXY,
QgsMessageLog,
QgsDistanceArea,
QgsProject,
QgsProcessingUtils)
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterNumber,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterDefinition)

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterNumber
from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector
from processing.tools import vector


class RandomPointsAlongLines(QgisAlgorithm):

VECTOR = 'VECTOR'
POINT_NUMBER = 'POINT_NUMBER'
INPUT = 'INPUT'
POINTS_NUMBER = 'POINTS_NUMBER'
MIN_DISTANCE = 'MIN_DISTANCE'
OUTPUT = 'OUTPUT'

Expand All @@ -65,13 +65,20 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.VECTOR,
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(ParameterNumber(self.POINT_NUMBER,
self.tr('Number of points'), 1, None, 1))
self.addParameter(ParameterNumber(self.MIN_DISTANCE,
self.tr('Minimum distance'), 0.0, None, 0.0))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Random points'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorLine]))
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(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Random points'),
type=QgsProcessing.TypeVectorPoint))

def name(self):
return 'randompointsalongline'
Expand All @@ -80,35 +87,40 @@ def displayName(self):
return self.tr('Random points along line')

def processAlgorithm(self, parameters, context, feedback):
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.VECTOR), context)
pointCount = float(self.getParameterValue(self.POINT_NUMBER))
minDistance = float(self.getParameterValue(self.MIN_DISTANCE))
source = self.parameterAsSource(parameters, self.INPUT, context)
pointCount = self.parameterAsDouble(parameters, self.POINTS_NUMBER, context)
minDistance = self.parameterAsDouble(parameters, self.MIN_DISTANCE, context)

fields = QgsFields()
fields.append(QgsField('id', QVariant.Int, '', 10, 0))
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context)

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Point, source.sourceCrs())

nPoints = 0
nIterations = 0
maxIterations = pointCount * 200
featureCount = layer.featureCount()
featureCount = source.featureCount()
total = 100.0 / pointCount if pointCount else 1

index = QgsSpatialIndex()
points = dict()

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

request = QgsFeatureRequest()

random.seed()

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

# pick random feature
fid = random.randint(0, featureCount - 1)
f = next(layer.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
f = next(source.getFeatures(request.setFilterFid(fid).setSubsetOfAttributes([])))
fGeom = f.geometry()

if fGeom.isMultipart():
Expand All @@ -135,23 +147,23 @@ def processAlgorithm(self, parameters, context, feedback):
ry = (startPoint.y() + d * endPoint.y()) / (1 + d)

# generate random point
pnt = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPoint(pnt)
if vector.checkMinDistance(pnt, index, minDistance, points):
p = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPoint(p)
if 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}
99 changes: 54 additions & 45 deletions python/plugins/processing/algs/qgis/RandomPointsExtent.py
Expand Up @@ -31,29 +31,35 @@

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,
QgsPointXY,
QgsWkbTypes,
QgsSpatialIndex,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterExtent,
QgsProcessingParameterNumber,
QgsProcessingParameterCrs,
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]


class RandomPointsExtent(QgisAlgorithm):

EXTENT = 'EXTENT'
POINT_NUMBER = 'POINT_NUMBER'
POINTS_NUMBER = 'POINTS_NUMBER'
MIN_DISTANCE = 'MIN_DISTANCE'
TARGET_CRS = 'TARGET_CRS'
OUTPUT = 'OUTPUT'
CRS = 'CRS'

def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'random_points.png'))
Expand All @@ -65,15 +71,21 @@ def __init__(self):
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'))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Random points'),
type=QgsProcessing.TypeVectorPoint))

def name(self):
return 'randompointsinextent'
Expand All @@ -82,24 +94,18 @@ def displayName(self):
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)

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)

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.Point, crs)

nPoints = 0
nIterations = 0
Expand All @@ -112,27 +118,30 @@ def processAlgorithm(self, parameters, context, feedback):
random.seed()

while nIterations < maxIterations and nPoints < pointCount:
rx = xMin + (xMax - xMin) * random.random()
ry = yMin + (yMax - yMin) * random.random()
if feedback.isCanceled():
break

rx = bbox.xMinimum() + bbox.width() * random.random()
ry = bbox.yMinimum() + bbox.height() * random.random()

pnt = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPoint(pnt)
p = QgsPointXY(rx, ry)
geom = QgsGeometry.fromPoint(p)
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}

0 comments on commit b842043

Please sign in to comment.