diff --git a/python/plugins/processing/algs/qgis/HubDistancePoints.py b/python/plugins/processing/algs/qgis/HubDistancePoints.py
index ea670b39b4d..32effadfc14 100644
--- a/python/plugins/processing/algs/qgis/HubDistancePoints.py
+++ b/python/plugins/processing/algs/qgis/HubDistancePoints.py
@@ -33,34 +33,32 @@ from qgis.core import (QgsField,
QgsDistanceArea,
QgsFeature,
QgsFeatureRequest,
+ QgsSpatialIndex,
QgsWkbTypes,
- QgsApplication,
- QgsProject,
- QgsProcessingUtils)
+ QgsUnitTypes,
+ QgsProcessing,
+ QgsProcessingUtils,
+ QgsProcessingParameterFeatureSource,
+ QgsProcessingParameterField,
+ QgsProcessingParameterEnum,
+ QgsProcessingParameterFeatureSink,
+ QgsProcessingException)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
-from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
-from processing.core.parameters import ParameterVector
-from processing.core.parameters import ParameterTableField
-from processing.core.parameters import ParameterSelection
-from processing.core.outputs import OutputVector
-
-from processing.tools import dataobjects
-
-from math import sqrt
class HubDistancePoints(QgisAlgorithm):
- POINTS = 'POINTS'
+ INPUT = 'INPUT'
HUBS = 'HUBS'
FIELD = 'FIELD'
UNIT = 'UNIT'
OUTPUT = 'OUTPUT'
+ LAYER_UNITS = 'LAYER_UNITS'
- UNITS = ['Meters',
- 'Feet',
- 'Miles',
- 'Kilometers',
- 'Layer units'
+ UNITS = [QgsUnitTypes.DistanceMeters,
+ QgsUnitTypes.DistanceFeet,
+ QgsUnitTypes.DistanceMiles,
+ QgsUnitTypes.DistanceKilometers,
+ LAYER_UNITS
]
def group(self):
@@ -76,16 +74,16 @@ class HubDistancePoints(QgisAlgorithm):
self.tr('Kilometers'),
self.tr('Layer units')]
- self.addParameter(ParameterVector(self.POINTS,
- self.tr('Source points layer')))
- self.addParameter(ParameterVector(self.HUBS,
- self.tr('Destination hubs layer')))
- self.addParameter(ParameterTableField(self.FIELD,
- self.tr('Hub layer name attribute'), self.HUBS))
- self.addParameter(ParameterSelection(self.UNIT,
- self.tr('Measurement unit'), self.units))
+ self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
+ self.tr('Source points layer')))
+ self.addParameter(QgsProcessingParameterFeatureSource(self.HUBS,
+ self.tr('Destination hubs layer')))
+ self.addParameter(QgsProcessingParameterField(self.FIELD,
+ self.tr('Hub layer name attribute'), parentLayerParameterName=self.HUBS))
+ self.addParameter(QgsProcessingParameterEnum(self.UNIT,
+ self.tr('Measurement unit'), self.units))
- self.addOutput(OutputVector(self.OUTPUT, self.tr('Hub distance'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
+ self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Hub distance'), QgsProcessing.TypeVectorPoint))
def name(self):
return 'distancetonearesthubpoints'
@@ -94,61 +92,62 @@ class HubDistancePoints(QgisAlgorithm):
return self.tr('Distance to nearest hub (points)')
def processAlgorithm(self, parameters, context, feedback):
- layerPoints = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.POINTS), context)
- layerHubs = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.HUBS), context)
- fieldName = self.getParameterValue(self.FIELD)
-
- units = self.UNITS[self.getParameterValue(self.UNIT)]
-
- if layerPoints.source() == layerHubs.source():
- raise GeoAlgorithmExecutionException(
+ if parameters[self.INPUT] == parameters[self.HUBS]:
+ raise QgsProcessingException(
self.tr('Same layer given for both hubs and spokes'))
- fields = layerPoints.fields()
+ point_source = self.parameterAsSource(parameters, self.INPUT, context)
+ hub_source = self.parameterAsSource(parameters, self.HUBS, context)
+ fieldName = self.parameterAsString(parameters, self.FIELD, context)
+
+ units = self.UNITS[self.parameterAsEnum(parameters, self.UNIT, context)]
+
+ fields = point_source.fields()
fields.append(QgsField('HubName', QVariant.String))
fields.append(QgsField('HubDist', QVariant.Double))
- writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layerPoints.crs(),
- context)
+ (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
+ fields, QgsWkbTypes.Point, point_source.sourceCrs())
- index = QgsProcessingUtils.createSpatialIndex(layerHubs, context)
+ index = QgsSpatialIndex(hub_source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(point_source.sourceCrs())))
distance = QgsDistanceArea()
- distance.setSourceCrs(layerPoints.crs())
+ distance.setSourceCrs(point_source.sourceCrs())
distance.setEllipsoid(context.project().ellipsoid())
# Scan source points, find nearest hub, and write to output file
- features = QgsProcessingUtils.getFeatures(layerPoints, context)
- total = 100.0 / layerPoints.featureCount() if layerPoints.featureCount() else 0
+ features = point_source.getFeatures()
+ total = 100.0 / point_source.featureCount() if point_source.featureCount() else 0
for current, f in enumerate(features):
+ if feedback.isCanceled():
+ break
+
+ if not f.hasGeometry():
+ sink.addFeature(f, QgsFeatureSink.FastInsert)
+ continue
+
src = f.geometry().boundingBox().center()
neighbors = index.nearestNeighbor(src, 1)
- ft = next(layerHubs.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], layerHubs.fields())))
+ ft = next(hub_source.getFeatures(QgsFeatureRequest().setFilterFid(neighbors[0]).setSubsetOfAttributes([fieldName], hub_source.fields()).setDestinationCrs(point_source.sourceCrs())))
closest = ft.geometry().boundingBox().center()
hubDist = distance.measureLine(src, closest)
+ if units != self.LAYER_UNITS:
+ hub_dist_in_desired_units = distance.convertLengthMeasurement(hubDist, units)
+ else:
+ hub_dist_in_desired_units = hubDist
+
attributes = f.attributes()
attributes.append(ft[fieldName])
- if units == 'Feet':
- attributes.append(hubDist * 3.2808399)
- elif units == 'Miles':
- attributes.append(hubDist * 0.000621371192)
- elif units == 'Kilometers':
- attributes.append(hubDist / 1000.0)
- elif units != 'Meters':
- attributes.append(sqrt(
- pow(src.x() - closest.x(), 2.0) +
- pow(src.y() - closest.y(), 2.0)))
- else:
- attributes.append(hubDist)
+ attributes.append(hub_dist_in_desired_units)
feat = QgsFeature()
feat.setAttributes(attributes)
feat.setGeometry(QgsGeometry.fromPoint(src))
- writer.addFeature(feat, QgsFeatureSink.FastInsert)
+ sink.addFeature(feat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total))
- del writer
+ return {self.OUTPUT: dest_id}
diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
index 97d113597dc..d58960a5770 100644
--- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
+++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
@@ -75,6 +75,7 @@ from .GridLine import GridLine
from .GridPolygon import GridPolygon
from .Heatmap import Heatmap
from .Hillshade import Hillshade
+from .HubDistancePoints import HubDistancePoints
from .ImportIntoPostGIS import ImportIntoPostGIS
from .ImportIntoSpatialite import ImportIntoSpatialite
from .Intersection import Intersection
@@ -141,7 +142,7 @@ from .ZonalStatistics import ZonalStatistics
# from .ExtractByLocation import ExtractByLocation
# from .SelectByLocation import SelectByLocation
# from .SpatialJoin import SpatialJoin
-# from .HubDistancePoints import HubDistancePoints
+
# from .HubDistanceLines import HubDistanceLines
# from .HubLines import HubLines
# from .GeometryConvert import GeometryConvert
@@ -188,7 +189,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# SelectByLocation(),
# ExtractByLocation(),
# SpatialJoin(),
- # HubDistancePoints(),
# HubDistanceLines(), HubLines(),
# GeometryConvert(), FieldsCalculator(),
# JoinAttributes(),
@@ -245,6 +245,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
GridPolygon(),
Heatmap(),
Hillshade(),
+ HubDistancePoints(),
ImportIntoPostGIS(),
ImportIntoSpatialite(),
Intersection(),
diff --git a/python/plugins/processing/tests/testdata/custom/hub_points.gfs b/python/plugins/processing/tests/testdata/custom/hub_points.gfs
new file mode 100644
index 00000000000..35cbfd91664
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/custom/hub_points.gfs
@@ -0,0 +1,22 @@
+
+
+ hub_points
+ hub_points
+
+ 1
+ EPSG:4326
+
+ 3
+ 1.34481
+ 6.29897
+ -1.25947
+ 2.27221
+
+
+ name
+ name
+ String
+ 6
+
+
+
diff --git a/python/plugins/processing/tests/testdata/custom/hub_points.gml b/python/plugins/processing/tests/testdata/custom/hub_points.gml
new file mode 100644
index 00000000000..99d14c1d02a
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/custom/hub_points.gml
@@ -0,0 +1,32 @@
+
+
+
+
+ 1.344807662693645-1.259467184083282
+ 6.2989682466352512.272211648033507
+
+
+
+
+
+ 1.34480766269365,-1.25946718408328
+ point1
+
+
+
+
+ 6.29896824663525,0.138489020296281
+ point2
+
+
+
+
+ 3.12290985247467,2.27221164803351
+ point3
+
+
+
diff --git a/python/plugins/processing/tests/testdata/expected/hub_distance_points.gfs b/python/plugins/processing/tests/testdata/expected/hub_distance_points.gfs
new file mode 100644
index 00000000000..43674410adb
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/expected/hub_distance_points.gfs
@@ -0,0 +1,37 @@
+
+
+ hub_distance_points
+ hub_distance_points
+
+ 1
+ EPSG:4326
+
+ 9
+ 0.00000
+ 8.00000
+ -5.00000
+ 3.00000
+
+
+ id
+ id
+ Integer
+
+
+ id2
+ id2
+ Integer
+
+
+ HubName
+ HubName
+ String
+ 6
+
+
+ HubDist
+ HubDist
+ Real
+
+
+
diff --git a/python/plugins/processing/tests/testdata/expected/hub_distance_points.gml b/python/plugins/processing/tests/testdata/expected/hub_distance_points.gml
new file mode 100644
index 00000000000..4e767e8b117
--- /dev/null
+++ b/python/plugins/processing/tests/testdata/expected/hub_distance_points.gml
@@ -0,0 +1,95 @@
+
+
+
+
+ 0-5
+ 83
+
+
+
+
+
+ 1,1
+ 1
+ 2
+ point1
+ 254434.675423572
+
+
+
+
+ 3,3
+ 2
+ 1
+ point3
+ 82164.2455422206
+
+
+
+
+ 2,2
+ 3
+ 0
+ point3
+ 128622.227687308
+
+
+
+
+ 5,2
+ 4
+ 2
+ point3
+ 211142.486929284
+
+
+
+
+ 4,1
+ 5
+ 1
+ point3
+ 172016.876891364
+
+
+
+
+ 0,-5
+ 6
+ 0
+ point1
+ 442487.532089586
+
+
+
+
+ 8,-1
+ 7
+ 0
+ point2
+ 227856.24000978
+
+
+
+
+ 7,-1
+ 8
+ 0
+ point2
+ 148835.564980152
+
+
+
+
+ 0,-1
+ 9
+ 0
+ point1
+ 152464.26003518
+
+
+
diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
index ac3d7d2929a..e79b77c2cd3 100644
--- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
+++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
@@ -2184,6 +2184,22 @@ tests:
name: expected/gridify_lines.gml
type: vector
+ - algorithm: qgis:distancetonearesthubpoints
+ name: Hub distance points
+ params:
+ INPUT:
+ name: points.gml
+ type: vector
+ HUBS:
+ name: custom/hub_points.gml
+ type: vector
+ FIELD: name
+ UNIT: 0
+ results:
+ OUTPUT:
+ name: expected/hub_distance_points.gml
+ type: vector
+
# - algorithm: qgis:joinattributestable
# name: join the attribute table by common field
# params: