QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsalgorithmnearestneighbouranalysis.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmnearestneighbouranalysis.cpp
3  ---------------------
4  begin : December 2019
5  copyright : (C) 2019 by Alexander Bruy
6  email : alexander dot bruy at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgsapplication.h"
20 
22 
23 QString QgsNearestNeighbourAnalysisAlgorithm::name() const
24 {
25  return QStringLiteral( "nearestneighbouranalysis" );
26 }
27 
28 QString QgsNearestNeighbourAnalysisAlgorithm::displayName() const
29 {
30  return QObject::tr( "Nearest neighbour analysis" );
31 }
32 
33 QStringList QgsNearestNeighbourAnalysisAlgorithm::tags() const
34 {
35  return QObject::tr( "point,node,vertex,nearest,neighbour,distance" ).split( ',' );
36 }
37 
38 QString QgsNearestNeighbourAnalysisAlgorithm::group() const
39 {
40  return QObject::tr( "Vector analysis" );
41 }
42 
43 QString QgsNearestNeighbourAnalysisAlgorithm::groupId() const
44 {
45  return QStringLiteral( "vectoranalysis" );
46 }
47 
48 QString QgsNearestNeighbourAnalysisAlgorithm::shortHelpString() const
49 {
50  return QObject::tr( "This algorithm performs nearest neighbor analysis for a point layer.\n\n"
51  "Output is generated as an HTML file with the computed statistical values." );
52 }
53 
54 QString QgsNearestNeighbourAnalysisAlgorithm::svgIconPath() const
55 {
56  return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmNearestNeighbour.svg" ) );
57 }
58 
59 QIcon QgsNearestNeighbourAnalysisAlgorithm::icon() const
60 {
61  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmNearestNeighbour.svg" ) );
62 }
63 
64 QgsNearestNeighbourAnalysisAlgorithm *QgsNearestNeighbourAnalysisAlgorithm::createInstance() const
65 {
66  return new QgsNearestNeighbourAnalysisAlgorithm();
67 }
68 
69 void QgsNearestNeighbourAnalysisAlgorithm::initAlgorithm( const QVariantMap & )
70 {
71  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorPoint ) );
72  addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT_HTML_FILE" ), QObject::tr( "Nearest neighbour" ),
73  QObject::tr( "HTML files (*.html *.HTML)" ), QVariant(), true ) );
74  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "OBSERVED_MD" ), QObject::tr( "Observed mean distance" ) ) );
75  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "EXPECTED_MD" ), QObject::tr( "Expected mean distance" ) ) );
76  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "NN_INDEX" ), QObject::tr( "Nearest neighbour index" ) ) );
77  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "POINT_COUNT" ), QObject::tr( "Number of points" ) ) );
78  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "Z_SCORE" ), QObject::tr( "Z-score" ) ) );
79 }
80 
81 QVariantMap QgsNearestNeighbourAnalysisAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
82 {
83  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
84  if ( !source )
85  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
86 
87  QString outputFile = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT_HTML_FILE" ), context );
88 
89  QgsSpatialIndex spatialIndex( *source, feedback, QgsSpatialIndex::FlagStoreFeatureGeometries );
90  QgsDistanceArea da;
91  da.setSourceCrs( source->sourceCrs(), context.transformContext() );
92  da.setEllipsoid( context.project()->ellipsoid() );
93 
94  double step = source->featureCount() ? 100.0 / source->featureCount() : 1;
95  QgsFeatureIterator it = source->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ) );
96 
97  QgsFeatureRequest request;
98  QgsFeature neighbour;
99  double sumDist = 0.0;
100  double area = source->sourceExtent().width() * source->sourceExtent().height();
101 
102  int i = 0;
103  QgsFeature f;
104  while ( it.nextFeature( f ) )
105  {
106  if ( feedback->isCanceled() )
107  {
108  break;
109  }
110 
111  QgsFeatureId neighbourId = spatialIndex.nearestNeighbor( f.geometry().asPoint(), 2 ).at( 1 );
112  sumDist += da.measureLine( spatialIndex.geometry( neighbourId ).asPoint(), f.geometry().asPoint() );
113 
114  i++;
115  feedback->setProgress( i * step );
116  }
117 
118  int count = source->featureCount() > 0 ? source->featureCount() : 1;
119  double observedDistance = sumDist / count;
120  double expectedDistance = 0.5 / std::sqrt( count / area );
121  double nnIndex = observedDistance / expectedDistance;
122  double se = 0.26136 / std::sqrt( std::pow( count, 2 ) / area );
123  double zScore = ( observedDistance - expectedDistance ) / se;
124 
125  QVariantMap outputs;
126  outputs.insert( QStringLiteral( "OBSERVED_MD" ), observedDistance );
127  outputs.insert( QStringLiteral( "EXPECTED_MD" ), expectedDistance );
128  outputs.insert( QStringLiteral( "NN_INDEX" ), nnIndex );
129  outputs.insert( QStringLiteral( "POINT_COUNT" ), count );
130  outputs.insert( QStringLiteral( "Z_SCORE" ), zScore );
131 
132  if ( !outputFile.isEmpty() )
133  {
134  QFile file( outputFile );
135  if ( file.open( QIODevice::WriteOnly | QIODevice::Text ) )
136  {
137  QTextStream out( &file );
138  out << QStringLiteral( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/></head><body>\n" );
139  out << QObject::tr( "<p>Observed mean distance: %1</p>\n" ).arg( observedDistance, 0, 'f', 11 );
140  out << QObject::tr( "<p>Expected mean distance: %1</p>\n" ).arg( expectedDistance, 0, 'f', 11 );
141  out << QObject::tr( "<p>Nearest neighbour index: %1</p>\n" ).arg( nnIndex, 0, 'f', 11 );
142  out << QObject::tr( "<p>Number of points: %1</p>\n" ).arg( count );
143  out << QObject::tr( "<p>Z-Score: %1</p>\n" ).arg( zScore, 0, 'f', 11 );
144  out << QStringLiteral( "</body></html>" );
145 
146  outputs.insert( QStringLiteral( "OUTPUT_HTML_FILE" ), outputFile );
147  }
148  }
149 
150  return outputs;
151 }
152 
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:75
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsProcessingContext::project
QgsProject * project() const
Returns the project in which the algorithm is being executed.
Definition: qgsprocessingcontext.h:99
QgsProcessingFeedback
Definition: qgsprocessingfeedback.h:37
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsProcessingParameterFeatureSource
Definition: qgsprocessingparameters.h:2612
QgsApplication::iconPath
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Definition: qgsapplication.cpp:594
QgsProcessing::TypeVectorPoint
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:48
QgsProcessingOutputNumber
Definition: qgsprocessingoutputs.h:294
qgsapplication.h
QgsDistanceArea::setEllipsoid
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Definition: qgsdistancearea.cpp:66
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
QgsProcessingContext
Definition: qgsprocessingcontext.h:43
QgsProcessingParameterFileDestination
Definition: qgsprocessingparameters.h:3005
QgsDistanceArea::measureLine
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
Definition: qgsdistancearea.cpp:273
QgsSpatialIndex
Definition: qgsspatialindex.h:67
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:135
QgsDistanceArea::setSourceCrs
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Definition: qgsdistancearea.cpp:60
QgsSpatialIndex::FlagStoreFeatureGeometries
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
Definition: qgsspatialindex.h:77
QgsFeedback::isCanceled
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:66
QgsGeometry::asPoint
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Definition: qgsgeometry.cpp:1559
qgsalgorithmnearestneighbouranalysis.h
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:373
QgsDistanceArea
Definition: qgsdistancearea.h:49
QgsFeature
Definition: qgsfeature.h:55
QgsFeatureIterator
Definition: qgsfeatureiterator.h:263
QgsProject::ellipsoid
QString ellipsoid
Definition: qgsproject.h:100
QgsProcessingException
Definition: qgsexception.h:82
QgsFeatureId
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25