3333
3434from qgis .PyQt .QtGui import QIcon
3535
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 )
3745
3846from 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
4347
4448pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
4549
4650
4751class NearestNeighbourAnalysis (QgisAlgorithm ):
4852
49- POINTS = 'POINTS '
50- OUTPUT = 'OUTPUT '
53+ INPUT = 'INPUT '
54+ OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE '
5155 OBSERVED_MD = 'OBSERVED_MD'
5256 EXPECTED_MD = 'EXPECTED_MD'
5357 NN_INDEX = 'NN_INDEX'
@@ -64,20 +68,21 @@ def __init__(self):
6468 super ().__init__ ()
6569
6670 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' )))
8186
8287 def name (self ):
8388 return 'nearestneighbouranalysis'
@@ -86,26 +91,30 @@ def displayName(self):
8691 return self .tr ('Nearest neighbour analysis' )
8792
8893 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 )
9196
92- spatialIndex = QgsProcessingUtils . createSpatialIndex ( layer , context )
97+ spatialIndex = QgsSpatialIndex ( source )
9398
94- neighbour = QgsFeature ()
9599 distance = QgsDistanceArea ()
100+ distance .setSourceCrs (source .sourceCrs ())
101+ distance .setEllipsoid (QgsProject .instance ().ellipsoid ())
96102
97103 sumDist = 0.00
98- A = layer . extent ()
104+ A = source . sourceExtent ()
99105 A = float (A .width () * A .height ())
100106
101- features = QgsProcessingUtils .getFeatures (layer , context )
102- count = QgsProcessingUtils .featureCount (layer , context )
107+ features = source .getFeatures ()
108+ count = source .featureCount ()
103109 total = 100.0 / count if count else 1
104110 for current , feat in enumerate (features ):
111+ if feedback .isCanceled ():
112+ break
113+
105114 neighbourID = spatialIndex .nearestNeighbor (
106115 feat .geometry ().asPoint (), 2 )[1 ]
107116 request = QgsFeatureRequest ().setFilterFid (neighbourID ).setSubsetOfAttributes ([])
108- neighbour = next (layer .getFeatures (request ))
117+ neighbour = next (source .getFeatures (request ))
109118 sumDist += distance .measureLine (neighbour .geometry ().asPoint (),
110119 feat .geometry ().asPoint ())
111120
@@ -117,20 +126,24 @@ def processAlgorithm(self, parameters, context, feedback):
117126 SE = float (0.26136 / math .sqrt (count ** 2 / A ))
118127 zscore = float ((do - de ) / SE )
119128
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
134147
135148 def createHTML (self , outputFile , algData ):
136149 with codecs .open (outputFile , 'w' , encoding = 'utf-8' ) as f :
0 commit comments