33
33
QgsDistanceArea ,
34
34
QgsFeature ,
35
35
QgsFeatureRequest ,
36
+ QgsSpatialIndex ,
36
37
QgsWkbTypes ,
37
- QgsApplication ,
38
- QgsProject ,
39
- QgsProcessingUtils )
38
+ QgsUnitTypes ,
39
+ QgsProcessing ,
40
+ QgsProcessingUtils ,
41
+ QgsProcessingParameterFeatureSource ,
42
+ QgsProcessingParameterField ,
43
+ QgsProcessingParameterEnum ,
44
+ QgsProcessingParameterFeatureSink ,
45
+ QgsProcessingException )
40
46
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
41
- from processing .core .GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
42
- from processing .core .parameters import ParameterVector
43
- from processing .core .parameters import ParameterTableField
44
- from processing .core .parameters import ParameterSelection
45
- from processing .core .outputs import OutputVector
46
-
47
- from processing .tools import dataobjects
48
-
49
- from math import sqrt
50
47
51
48
52
49
class HubDistancePoints (QgisAlgorithm ):
53
- POINTS = 'POINTS '
50
+ INPUT = 'INPUT '
54
51
HUBS = 'HUBS'
55
52
FIELD = 'FIELD'
56
53
UNIT = 'UNIT'
57
54
OUTPUT = 'OUTPUT'
55
+ LAYER_UNITS = 'LAYER_UNITS'
58
56
59
- UNITS = ['Meters' ,
60
- 'Feet' ,
61
- 'Miles' ,
62
- 'Kilometers' ,
63
- 'Layer units'
57
+ UNITS = [QgsUnitTypes . DistanceMeters ,
58
+ QgsUnitTypes . DistanceFeet ,
59
+ QgsUnitTypes . DistanceMiles ,
60
+ QgsUnitTypes . DistanceKilometers ,
61
+ LAYER_UNITS
64
62
]
65
63
66
64
def group (self ):
@@ -76,16 +74,16 @@ def initAlgorithm(self, config=None):
76
74
self .tr ('Kilometers' ),
77
75
self .tr ('Layer units' )]
78
76
79
- self .addParameter (ParameterVector (self .POINTS ,
80
- self .tr ('Source points layer' )))
81
- self .addParameter (ParameterVector (self .HUBS ,
82
- self .tr ('Destination hubs layer' )))
83
- self .addParameter (ParameterTableField (self .FIELD ,
84
- self .tr ('Hub layer name attribute' ), self .HUBS ))
85
- self .addParameter (ParameterSelection (self .UNIT ,
86
- self .tr ('Measurement unit' ), self .units ))
77
+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT ,
78
+ self .tr ('Source points layer' )))
79
+ self .addParameter (QgsProcessingParameterFeatureSource (self .HUBS ,
80
+ self .tr ('Destination hubs layer' )))
81
+ self .addParameter (QgsProcessingParameterField (self .FIELD ,
82
+ self .tr ('Hub layer name attribute' ), parentLayerParameterName = self .HUBS ))
83
+ self .addParameter (QgsProcessingParameterEnum (self .UNIT ,
84
+ self .tr ('Measurement unit' ), self .units ))
87
85
88
- self .addOutput ( OutputVector (self .OUTPUT , self .tr ('Hub distance' ), datatype = [ dataobjects . TYPE_VECTOR_POINT ] ))
86
+ self .addParameter ( QgsProcessingParameterFeatureSink (self .OUTPUT , self .tr ('Hub distance' ), QgsProcessing . TypeVectorPoint ))
89
87
90
88
def name (self ):
91
89
return 'distancetonearesthubpoints'
@@ -94,61 +92,62 @@ def displayName(self):
94
92
return self .tr ('Distance to nearest hub (points)' )
95
93
96
94
def processAlgorithm (self , parameters , context , feedback ):
97
- layerPoints = QgsProcessingUtils . mapLayerFromString ( self .getParameterValue ( self . POINTS ), context )
98
- layerHubs = QgsProcessingUtils . mapLayerFromString ( self . getParameterValue ( self . HUBS ), context )
99
- fieldName = self .getParameterValue ( self . FIELD )
95
+ if parameters [ self . INPUT ] == parameters [ self .HUBS ]:
96
+ raise QgsProcessingException (
97
+ self .tr ( 'Same layer given for both hubs and spokes' ) )
100
98
101
- units = self .UNITS [self .getParameterValue (self .UNIT )]
99
+ point_source = self .parameterAsSource (parameters , self .INPUT , context )
100
+ hub_source = self .parameterAsSource (parameters , self .HUBS , context )
101
+ fieldName = self .parameterAsString (parameters , self .FIELD , context )
102
102
103
- if layerPoints .source () == layerHubs .source ():
104
- raise GeoAlgorithmExecutionException (
105
- self .tr ('Same layer given for both hubs and spokes' ))
103
+ units = self .UNITS [self .parameterAsEnum (parameters , self .UNIT , context )]
106
104
107
- fields = layerPoints .fields ()
105
+ fields = point_source .fields ()
108
106
fields .append (QgsField ('HubName' , QVariant .String ))
109
107
fields .append (QgsField ('HubDist' , QVariant .Double ))
110
108
111
- writer = self .getOutputFromName ( self .OUTPUT ). getVectorWriter ( fields , QgsWkbTypes . Point , layerPoints . crs () ,
112
- context )
109
+ ( sink , dest_id ) = self .parameterAsSink ( parameters , self .OUTPUT , context ,
110
+ fields , QgsWkbTypes . Point , point_source . sourceCrs () )
113
111
114
- index = QgsProcessingUtils . createSpatialIndex ( layerHubs , context )
112
+ index = QgsSpatialIndex ( hub_source . getFeatures ( QgsFeatureRequest (). setSubsetOfAttributes ([]). setDestinationCrs ( point_source . sourceCrs ())) )
115
113
116
114
distance = QgsDistanceArea ()
117
- distance .setSourceCrs (layerPoints . crs ())
115
+ distance .setSourceCrs (point_source . sourceCrs ())
118
116
distance .setEllipsoid (context .project ().ellipsoid ())
119
117
120
118
# Scan source points, find nearest hub, and write to output file
121
- features = QgsProcessingUtils .getFeatures (layerPoints , context )
122
- total = 100.0 / layerPoints .featureCount () if layerPoints .featureCount () else 0
119
+ features = point_source .getFeatures ()
120
+ total = 100.0 / point_source .featureCount () if point_source .featureCount () else 0
123
121
for current , f in enumerate (features ):
122
+ if feedback .isCanceled ():
123
+ break
124
+
125
+ if not f .hasGeometry ():
126
+ sink .addFeature (f , QgsFeatureSink .FastInsert )
127
+ continue
128
+
124
129
src = f .geometry ().boundingBox ().center ()
125
130
126
131
neighbors = index .nearestNeighbor (src , 1 )
127
- ft = next (layerHubs .getFeatures (QgsFeatureRequest ().setFilterFid (neighbors [0 ]).setSubsetOfAttributes ([fieldName ], layerHubs .fields ())))
132
+ ft = next (hub_source .getFeatures (QgsFeatureRequest ().setFilterFid (neighbors [0 ]).setSubsetOfAttributes ([fieldName ], hub_source .fields ()). setDestinationCrs ( point_source . sourceCrs ())))
128
133
closest = ft .geometry ().boundingBox ().center ()
129
134
hubDist = distance .measureLine (src , closest )
130
135
136
+ if units != self .LAYER_UNITS :
137
+ hub_dist_in_desired_units = distance .convertLengthMeasurement (hubDist , units )
138
+ else :
139
+ hub_dist_in_desired_units = hubDist
140
+
131
141
attributes = f .attributes ()
132
142
attributes .append (ft [fieldName ])
133
- if units == 'Feet' :
134
- attributes .append (hubDist * 3.2808399 )
135
- elif units == 'Miles' :
136
- attributes .append (hubDist * 0.000621371192 )
137
- elif units == 'Kilometers' :
138
- attributes .append (hubDist / 1000.0 )
139
- elif units != 'Meters' :
140
- attributes .append (sqrt (
141
- pow (src .x () - closest .x (), 2.0 ) +
142
- pow (src .y () - closest .y (), 2.0 )))
143
- else :
144
- attributes .append (hubDist )
143
+ attributes .append (hub_dist_in_desired_units )
145
144
146
145
feat = QgsFeature ()
147
146
feat .setAttributes (attributes )
148
147
149
148
feat .setGeometry (QgsGeometry .fromPoint (src ))
150
149
151
- writer .addFeature (feat , QgsFeatureSink .FastInsert )
150
+ sink .addFeature (feat , QgsFeatureSink .FastInsert )
152
151
feedback .setProgress (int (current * total ))
153
152
154
- del writer
153
+ return { self . OUTPUT : dest_id }
0 commit comments