mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Port a multi-step algorithm to new API (concave hull)
This commit is contained in:
parent
a15d283cd6
commit
db816ec3fe
@ -32,14 +32,16 @@ from qgis.core import (QgsFeatureRequest,
|
||||
QgsFeatureSink,
|
||||
QgsWkbTypes,
|
||||
QgsApplication,
|
||||
QgsProcessingUtils)
|
||||
QgsProcessingUtils,
|
||||
QgsProcessingParameterFeatureSource,
|
||||
QgsProcessingParameterVectorLayer,
|
||||
QgsProcessingParameterDefinition,
|
||||
QgsProcessingParameterNumber,
|
||||
QgsProcessingParameterBoolean,
|
||||
QgsProcessingParameterFeatureSink,
|
||||
QgsProcessingOutputVectorLayer)
|
||||
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
|
||||
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
|
||||
from processing.core.parameters import ParameterVector
|
||||
from processing.core.parameters import ParameterNumber
|
||||
from processing.core.parameters import ParameterBoolean
|
||||
from processing.core.outputs import OutputVector
|
||||
from processing.tools import dataobjects
|
||||
import processing
|
||||
from math import sqrt
|
||||
|
||||
@ -57,17 +59,19 @@ class ConcaveHull(QgisAlgorithm):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.addParameter(ParameterVector(ConcaveHull.INPUT,
|
||||
self.tr('Input point layer'), [dataobjects.TYPE_VECTOR_POINT]))
|
||||
self.addParameter(ParameterNumber(self.ALPHA,
|
||||
self.tr('Threshold (0-1, where 1 is equivalent with Convex Hull)'),
|
||||
0, 1, 0.3))
|
||||
self.addParameter(ParameterBoolean(self.HOLES,
|
||||
self.tr('Allow holes'), True))
|
||||
self.addParameter(ParameterBoolean(self.NO_MULTIGEOMETRY,
|
||||
self.tr('Split multipart geometry into singleparts geometries'), False))
|
||||
self.addOutput(
|
||||
OutputVector(ConcaveHull.OUTPUT, self.tr('Concave hull'), datatype=[dataobjects.TYPE_VECTOR_POLYGON]))
|
||||
|
||||
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, self.tr('Input point layer'), [QgsProcessingParameterDefinition.TypeVectorPoint]))
|
||||
self.addParameter(QgsProcessingParameterNumber(self.ALPHA,
|
||||
self.tr('Threshold (0-1, where 1 is equivalent with Convex Hull)'),
|
||||
minValue=0, maxValue=1, defaultValue=0.3, type=QgsProcessingParameterNumber.Double))
|
||||
|
||||
self.addParameter(QgsProcessingParameterBoolean(self.HOLES,
|
||||
self.tr('Allow holes'), defaultValue=True))
|
||||
self.addParameter(QgsProcessingParameterBoolean(self.NO_MULTIGEOMETRY,
|
||||
self.tr('Split multipart geometry into singleparts geometries'), defaultValue=False))
|
||||
|
||||
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Concave hull'), type=QgsProcessingParameterDefinition.TypeVectorPolygon))
|
||||
self.addOutput(QgsProcessingOutputVectorLayer(self.OUTPUT, self.tr("Concave hull"), type=QgsProcessingParameterDefinition.TypeVectorPolygon))
|
||||
|
||||
def name(self):
|
||||
return 'concavehull'
|
||||
@ -76,21 +80,21 @@ class ConcaveHull(QgisAlgorithm):
|
||||
return self.tr('Concave hull')
|
||||
|
||||
def processAlgorithm(self, parameters, context, feedback):
|
||||
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(ConcaveHull.INPUT), context)
|
||||
alpha = self.getParameterValue(self.ALPHA)
|
||||
holes = self.getParameterValue(self.HOLES)
|
||||
no_multigeom = self.getParameterValue(self.NO_MULTIGEOMETRY)
|
||||
layer = self.parameterAsSource(parameters, ConcaveHull.INPUT, context)
|
||||
alpha = self.parameterAsDouble(parameters, self.ALPHA, context)
|
||||
holes = self.parameterAsBool(parameters, self.HOLES, context)
|
||||
no_multigeom = self.parameterAsBool(parameters, self.NO_MULTIGEOMETRY, context)
|
||||
|
||||
# Delaunay triangulation from input point layer
|
||||
feedback.setProgressText(self.tr('Creating Delaunay triangles...'))
|
||||
delone_triangles = processing.run("qgis:delaunaytriangulation", layer, None, context=context)['OUTPUT']
|
||||
delone_triangles = processing.run("qgis:delaunaytriangulation", {'INPUT': parameters[ConcaveHull.INPUT], 'OUTPUT': 'memory:'}, feedback=feedback, context=context)['OUTPUT']
|
||||
delaunay_layer = QgsProcessingUtils.mapLayerFromString(delone_triangles, context)
|
||||
|
||||
# Get max edge length from Delaunay triangles
|
||||
feedback.setProgressText(self.tr('Computing edges max length...'))
|
||||
|
||||
features = QgsProcessingUtils.getFeatures(delaunay_layer, context)
|
||||
count = QgsProcessingUtils.featureCount(delaunay_layer, context)
|
||||
features = delaunay_layer.getFeatures()
|
||||
count = delaunay_layer.featureCount()
|
||||
if count == 0:
|
||||
raise GeoAlgorithmExecutionException(self.tr('No Delaunay triangles created.'))
|
||||
|
||||
@ -98,6 +102,9 @@ class ConcaveHull(QgisAlgorithm):
|
||||
lengths = []
|
||||
edges = {}
|
||||
for feat in features:
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
line = feat.geometry().asPolygon()[0]
|
||||
for i in range(len(line) - 1):
|
||||
lengths.append(sqrt(line[i].sqrDist(line[i + 1])))
|
||||
@ -111,6 +118,9 @@ class ConcaveHull(QgisAlgorithm):
|
||||
i = 0
|
||||
ids = []
|
||||
for id, max_len in list(edges.items()):
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
if max_len > alpha * max_length:
|
||||
ids.append(id)
|
||||
feedback.setProgress(50 + i * counter)
|
||||
@ -124,21 +134,25 @@ class ConcaveHull(QgisAlgorithm):
|
||||
|
||||
# Dissolve all Delaunay triangles
|
||||
feedback.setProgressText(self.tr('Dissolving Delaunay triangles...'))
|
||||
dissolved = processing.run("qgis:dissolve", delaunay_layer.id(),
|
||||
True, None, None, context=context)['OUTPUT']
|
||||
dissolved = processing.run("native:dissolve", {'INPUT': delaunay_layer.id(), 'OUTPUT': 'memory:'}, feedback=feedback, context=context)['OUTPUT']
|
||||
dissolved_layer = QgsProcessingUtils.mapLayerFromString(dissolved, context)
|
||||
|
||||
# Save result
|
||||
feedback.setProgressText(self.tr('Saving data...'))
|
||||
feat = QgsFeature()
|
||||
QgsProcessingUtils.getFeatures(dissolved_layer, context).nextFeature(feat)
|
||||
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), QgsWkbTypes.Polygon,
|
||||
layer.crs(), context)
|
||||
dissolved_layer.getFeatures().nextFeature(feat)
|
||||
|
||||
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
|
||||
layer.fields(), QgsWkbTypes.Polygon, layer.sourceCrs())
|
||||
|
||||
geom = feat.geometry()
|
||||
if no_multigeom and geom.isMultipart():
|
||||
# Only singlepart geometries are allowed
|
||||
geom_list = geom.asMultiPolygon()
|
||||
for single_geom_list in geom_list:
|
||||
if feedback.isCanceled():
|
||||
break
|
||||
|
||||
single_feature = QgsFeature()
|
||||
single_geom = QgsGeometry.fromPolygon(single_geom_list)
|
||||
if not holes:
|
||||
@ -147,7 +161,7 @@ class ConcaveHull(QgisAlgorithm):
|
||||
while deleted:
|
||||
deleted = single_geom.deleteRing(1)
|
||||
single_feature.setGeometry(single_geom)
|
||||
writer.addFeature(single_feature, QgsFeatureSink.FastInsert)
|
||||
sink.addFeature(single_feature, QgsFeatureSink.FastInsert)
|
||||
else:
|
||||
# Multipart geometries are allowed
|
||||
if not holes:
|
||||
@ -155,5 +169,6 @@ class ConcaveHull(QgisAlgorithm):
|
||||
deleted = True
|
||||
while deleted:
|
||||
deleted = geom.deleteRing(1)
|
||||
writer.addFeature(feat, QgsFeatureSink.FastInsert)
|
||||
del writer
|
||||
sink.addFeature(feat, QgsFeatureSink.FastInsert)
|
||||
|
||||
return {self.OUTPUT: dest_id}
|
||||
|
@ -47,6 +47,7 @@ from .BasicStatistics import BasicStatisticsForField
|
||||
from .Boundary import Boundary
|
||||
from .BoundingBox import BoundingBox
|
||||
from .CheckValidity import CheckValidity
|
||||
from .ConcaveHull import ConcaveHull
|
||||
from .CreateAttributeIndex import CreateAttributeIndex
|
||||
from .Delaunay import Delaunay
|
||||
from .DeleteColumn import DeleteColumn
|
||||
@ -110,7 +111,6 @@ from .ZonalStatistics import ZonalStatistics
|
||||
# from .HubDistanceLines import HubDistanceLines
|
||||
# from .HubLines import HubLines
|
||||
# from .GeometryConvert import GeometryConvert
|
||||
# from .ConcaveHull import ConcaveHull
|
||||
# from .RasterLayerStatistics import RasterLayerStatistics
|
||||
# from .StatisticsByCategories import StatisticsByCategories
|
||||
# from .EquivalentNumField import EquivalentNumField
|
||||
@ -206,7 +206,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
# JoinAttributes(),
|
||||
# Explode(), FieldsPyculator(),
|
||||
# EquivalentNumField(),
|
||||
# StatisticsByCategories(), ConcaveHull(),
|
||||
# StatisticsByCategories(),
|
||||
# RasterLayerStatistics(), PointsDisplacement(),
|
||||
# PointsFromPolygons(),
|
||||
# PointsFromLines(), RandomPointsExtent(),
|
||||
@ -246,6 +246,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
|
||||
Boundary(),
|
||||
BoundingBox(),
|
||||
CheckValidity(),
|
||||
ConcaveHull(),
|
||||
CreateAttributeIndex(),
|
||||
Delaunay(),
|
||||
DeleteColumn(),
|
||||
|
Loading…
x
Reference in New Issue
Block a user