33
33
34
34
from qgis .PyQt .QtGui import QIcon
35
35
36
- from qgis .core import QgsFeatureRequest , QgsFeature , QgsDistanceArea , QgsProcessingUtils
36
+ from qgis .core import (QgsFeatureRequest ,
37
+ QgsDistanceArea ,
38
+ QgsProject ,
39
+ QgsProcessing ,
40
+ QgsProcessingParameterFeatureSource ,
41
+ QgsProcessingParameterFileDestination ,
42
+ QgsProcessingOutputHtml ,
43
+ QgsProcessingOutputNumber ,
44
+ QgsSpatialIndex )
37
45
38
46
from processing .algs .qgis .QgisAlgorithm import QgisAlgorithm
39
- from processing .core .parameters import ParameterVector
40
- from processing .core .outputs import OutputHTML
41
- from processing .core .outputs import OutputNumber
42
- from processing .tools import dataobjects
43
47
44
48
pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
45
49
46
50
47
51
class NearestNeighbourAnalysis (QgisAlgorithm ):
48
52
49
- POINTS = 'POINTS '
50
- OUTPUT = 'OUTPUT '
53
+ INPUT = 'INPUT '
54
+ OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE '
51
55
OBSERVED_MD = 'OBSERVED_MD'
52
56
EXPECTED_MD = 'EXPECTED_MD'
53
57
NN_INDEX = 'NN_INDEX'
@@ -64,20 +68,21 @@ def __init__(self):
64
68
super ().__init__ ()
65
69
66
70
def initAlgorithm (self , config = None ):
67
- self .addParameter (ParameterVector (self .POINTS ,
68
- self .tr ('Points' ), [dataobjects .TYPE_VECTOR_POINT ]))
69
-
70
- self .addOutput (OutputHTML (self .OUTPUT , self .tr ('Nearest neighbour' )))
71
-
72
- self .addOutput (OutputNumber (self .OBSERVED_MD ,
73
- self .tr ('Observed mean distance' )))
74
- self .addOutput (OutputNumber (self .EXPECTED_MD ,
75
- self .tr ('Expected mean distance' )))
76
- self .addOutput (OutputNumber (self .NN_INDEX ,
77
- self .tr ('Nearest neighbour index' )))
78
- self .addOutput (OutputNumber (self .POINT_COUNT ,
79
- self .tr ('Number of points' )))
80
- self .addOutput (OutputNumber (self .Z_SCORE , self .tr ('Z-Score' )))
71
+ self .addParameter (QgsProcessingParameterFeatureSource (self .INPUT ,
72
+ self .tr ('Input layer' ), [QgsProcessing .TypeVectorPoint ]))
73
+
74
+ self .addParameter (QgsProcessingParameterFileDestination (self .OUTPUT_HTML_FILE , self .tr ('Nearest neighbour' ), self .tr ('HTML files (*.html)' ), None , True ))
75
+ self .addOutput (QgsProcessingOutputHtml (self .OUTPUT_HTML_FILE , self .tr ('Nearest neighbour' )))
76
+
77
+ self .addOutput (QgsProcessingOutputNumber (self .OBSERVED_MD ,
78
+ self .tr ('Observed mean distance' )))
79
+ self .addOutput (QgsProcessingOutputNumber (self .EXPECTED_MD ,
80
+ self .tr ('Expected mean distance' )))
81
+ self .addOutput (QgsProcessingOutputNumber (self .NN_INDEX ,
82
+ self .tr ('Nearest neighbour index' )))
83
+ self .addOutput (QgsProcessingOutputNumber (self .POINT_COUNT ,
84
+ self .tr ('Number of points' )))
85
+ self .addOutput (QgsProcessingOutputNumber (self .Z_SCORE , self .tr ('Z-Score' )))
81
86
82
87
def name (self ):
83
88
return 'nearestneighbouranalysis'
@@ -86,26 +91,30 @@ def displayName(self):
86
91
return self .tr ('Nearest neighbour analysis' )
87
92
88
93
def processAlgorithm (self , parameters , context , feedback ):
89
- layer = QgsProcessingUtils . mapLayerFromString ( self .getParameterValue ( self .POINTS ) , context )
90
- output = self .getOutputValue ( self .OUTPUT )
94
+ source = self .parameterAsSource ( parameters , self .INPUT , context )
95
+ output_file = self .parameterAsFileOutput ( parameters , self .OUTPUT_HTML_FILE , context )
91
96
92
- spatialIndex = QgsProcessingUtils . createSpatialIndex ( layer , context )
97
+ spatialIndex = QgsSpatialIndex ( source )
93
98
94
- neighbour = QgsFeature ()
95
99
distance = QgsDistanceArea ()
100
+ distance .setSourceCrs (source .sourceCrs ())
101
+ distance .setEllipsoid (QgsProject .instance ().ellipsoid ())
96
102
97
103
sumDist = 0.00
98
- A = layer . extent ()
104
+ A = source . sourceExtent ()
99
105
A = float (A .width () * A .height ())
100
106
101
- features = QgsProcessingUtils .getFeatures (layer , context )
102
- count = QgsProcessingUtils .featureCount (layer , context )
107
+ features = source .getFeatures ()
108
+ count = source .featureCount ()
103
109
total = 100.0 / count if count else 1
104
110
for current , feat in enumerate (features ):
111
+ if feedback .isCanceled ():
112
+ break
113
+
105
114
neighbourID = spatialIndex .nearestNeighbor (
106
115
feat .geometry ().asPoint (), 2 )[1 ]
107
116
request = QgsFeatureRequest ().setFilterFid (neighbourID ).setSubsetOfAttributes ([])
108
- neighbour = next (layer .getFeatures (request ))
117
+ neighbour = next (source .getFeatures (request ))
109
118
sumDist += distance .measureLine (neighbour .geometry ().asPoint (),
110
119
feat .geometry ().asPoint ())
111
120
@@ -117,20 +126,24 @@ def processAlgorithm(self, parameters, context, feedback):
117
126
SE = float (0.26136 / math .sqrt (count ** 2 / A ))
118
127
zscore = float ((do - de ) / SE )
119
128
120
- data = []
121
- data .append ('Observed mean distance: ' + str (do ))
122
- data .append ('Expected mean distance: ' + str (de ))
123
- data .append ('Nearest neighbour index: ' + str (d ))
124
- data .append ('Number of points: ' + str (count ))
125
- data .append ('Z-Score: ' + str (zscore ))
126
-
127
- self .createHTML (output , data )
128
-
129
- self .setOutputValue (self .OBSERVED_MD , float (data [0 ].split (': ' )[1 ]))
130
- self .setOutputValue (self .EXPECTED_MD , float (data [1 ].split (': ' )[1 ]))
131
- self .setOutputValue (self .NN_INDEX , float (data [2 ].split (': ' )[1 ]))
132
- self .setOutputValue (self .POINT_COUNT , float (data [3 ].split (': ' )[1 ]))
133
- self .setOutputValue (self .Z_SCORE , float (data [4 ].split (': ' )[1 ]))
129
+ results = {}
130
+ results [self .OBSERVED_MD ] = do
131
+ results [self .EXPECTED_MD ] = de
132
+ results [self .NN_INDEX ] = d
133
+ results [self .POINT_COUNT ] = count
134
+ results [self .Z_SCORE ] = zscore
135
+
136
+ if output_file :
137
+ data = []
138
+ data .append ('Observed mean distance: ' + str (do ))
139
+ data .append ('Expected mean distance: ' + str (de ))
140
+ data .append ('Nearest neighbour index: ' + str (d ))
141
+ data .append ('Number of points: ' + str (count ))
142
+ data .append ('Z-Score: ' + str (zscore ))
143
+ self .createHTML (output_file , data )
144
+ results [self .OUTPUT_HTML_FILE ] = output_file
145
+
146
+ return results
134
147
135
148
def createHTML (self , outputFile , algData ):
136
149
with codecs .open (outputFile , 'w' , encoding = 'utf-8' ) as f :
0 commit comments