QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 #include "qgsdistancearea.h"
21 #include <QTextStream>
22 
24 
25 QString QgsNearestNeighbourAnalysisAlgorithm::name() const
26 {
27  return QStringLiteral( "nearestneighbouranalysis" );
28 }
29 
30 QString QgsNearestNeighbourAnalysisAlgorithm::displayName() const
31 {
32  return QObject::tr( "Nearest neighbour analysis" );
33 }
34 
35 QStringList QgsNearestNeighbourAnalysisAlgorithm::tags() const
36 {
37  return QObject::tr( "point,node,vertex,nearest,neighbour,distance" ).split( ',' );
38 }
39 
40 QString QgsNearestNeighbourAnalysisAlgorithm::group() const
41 {
42  return QObject::tr( "Vector analysis" );
43 }
44 
45 QString QgsNearestNeighbourAnalysisAlgorithm::groupId() const
46 {
47  return QStringLiteral( "vectoranalysis" );
48 }
49 
50 QString QgsNearestNeighbourAnalysisAlgorithm::shortHelpString() const
51 {
52  return QObject::tr( "This algorithm performs nearest neighbor analysis for a point layer.\n\n"
53  "The output describes how the data are distributed (clustered, randomly or distributed).\n\n"
54  "Output is generated as an HTML file with the computed statistical values." );
55 }
56 
57 QString QgsNearestNeighbourAnalysisAlgorithm::svgIconPath() const
58 {
59  return QgsApplication::iconPath( QStringLiteral( "/algorithms/mAlgorithmNearestNeighbour.svg" ) );
60 }
61 
62 QIcon QgsNearestNeighbourAnalysisAlgorithm::icon() const
63 {
64  return QgsApplication::getThemeIcon( QStringLiteral( "/algorithms/mAlgorithmNearestNeighbour.svg" ) );
65 }
66 
67 QgsNearestNeighbourAnalysisAlgorithm *QgsNearestNeighbourAnalysisAlgorithm::createInstance() const
68 {
69  return new QgsNearestNeighbourAnalysisAlgorithm();
70 }
71 
72 void QgsNearestNeighbourAnalysisAlgorithm::initAlgorithm( const QVariantMap & )
73 {
74  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorPoint ) );
75  addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT_HTML_FILE" ), QObject::tr( "Nearest neighbour" ),
76  QObject::tr( "HTML files (*.html *.HTML)" ), QVariant(), true ) );
77  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "OBSERVED_MD" ), QObject::tr( "Observed mean distance" ) ) );
78  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "EXPECTED_MD" ), QObject::tr( "Expected mean distance" ) ) );
79  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "NN_INDEX" ), QObject::tr( "Nearest neighbour index" ) ) );
80  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "POINT_COUNT" ), QObject::tr( "Number of points" ) ) );
81  addOutput( new QgsProcessingOutputNumber( QStringLiteral( "Z_SCORE" ), QObject::tr( "Z-score" ) ) );
82 }
83 
84 QVariantMap QgsNearestNeighbourAnalysisAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
85 {
86  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
87  if ( !source )
88  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
89 
90  const QString outputFile = parameterAsFileOutput( parameters, QStringLiteral( "OUTPUT_HTML_FILE" ), context );
91 
92  const QgsSpatialIndex spatialIndex( *source, feedback, QgsSpatialIndex::FlagStoreFeatureGeometries );
93  QgsDistanceArea da;
94  da.setSourceCrs( source->sourceCrs(), context.transformContext() );
95  da.setEllipsoid( context.ellipsoid() );
96 
97  const double step = source->featureCount() ? 100.0 / source->featureCount() : 1;
98  QgsFeatureIterator it = source->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QList< int >() ) );
99 
100  const QgsFeatureRequest request;
101  const QgsFeature neighbour;
102  double sumDist = 0.0;
103  const double area = source->sourceExtent().width() * source->sourceExtent().height();
104 
105  int i = 0;
106  QgsFeature f;
107  while ( it.nextFeature( f ) )
108  {
109  if ( feedback->isCanceled() )
110  {
111  break;
112  }
113 
114  const QgsFeatureId neighbourId = spatialIndex.nearestNeighbor( f.geometry().asPoint(), 2 ).at( 1 );
115  sumDist += da.measureLine( spatialIndex.geometry( neighbourId ).asPoint(), f.geometry().asPoint() );
116 
117  i++;
118  feedback->setProgress( i * step );
119  }
120 
121  const long long count = source->featureCount() > 0 ? source->featureCount() : 1;
122  const double observedDistance = sumDist / count;
123  const double expectedDistance = 0.5 / std::sqrt( count / area );
124  const double nnIndex = observedDistance / expectedDistance;
125  const double se = 0.26136 / std::sqrt( std::pow( count, 2 ) / area );
126  const double zScore = ( observedDistance - expectedDistance ) / se;
127 
128  QVariantMap outputs;
129  outputs.insert( QStringLiteral( "OBSERVED_MD" ), observedDistance );
130  outputs.insert( QStringLiteral( "EXPECTED_MD" ), expectedDistance );
131  outputs.insert( QStringLiteral( "NN_INDEX" ), nnIndex );
132  outputs.insert( QStringLiteral( "POINT_COUNT" ), count );
133  outputs.insert( QStringLiteral( "Z_SCORE" ), zScore );
134 
135  if ( !outputFile.isEmpty() )
136  {
137  QFile file( outputFile );
138  if ( file.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
139  {
140  QTextStream out( &file );
141 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
142  out.setCodec( "UTF-8" );
143 #endif
144  out << QStringLiteral( "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/></head><body>\n" );
145  out << QObject::tr( "<p>Observed mean distance: %1</p>\n" ).arg( observedDistance, 0, 'f', 11 );
146  out << QObject::tr( "<p>Expected mean distance: %1</p>\n" ).arg( expectedDistance, 0, 'f', 11 );
147  out << QObject::tr( "<p>Nearest neighbour index: %1</p>\n" ).arg( nnIndex, 0, 'f', 11 );
148  out << QObject::tr( "<p>Number of points: %1</p>\n" ).arg( count );
149  out << QObject::tr( "<p>Z-Score: %1</p>\n" ).arg( zScore, 0, 'f', 11 );
150  out << QStringLiteral( "</body></html>" );
151 
152  outputs.insert( QStringLiteral( "OUTPUT_HTML_FILE" ), outputFile );
153  }
154  }
155 
156  return outputs;
157 }
158 
QgsFeedback::setProgress
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:76
QgsProcessingFeedback
Base class for providing feedback from a processing algorithm.
Definition: qgsprocessingfeedback.h:37
QgsFeature::geometry
QgsGeometry geometry
Definition: qgsfeature.h:71
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsProcessingParameterFeatureSource
An input feature source (such as vector layers) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:3057
QgsApplication::iconPath
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
Definition: qgsapplication.cpp:682
QgsProcessing::TypeVectorPoint
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:49
QgsProcessingOutputNumber
A numeric output for processing algorithms.
Definition: qgsprocessingoutputs.h:312
qgsapplication.h
QgsDistanceArea::setEllipsoid
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
Definition: qgsdistancearea.cpp:89
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:46
QgsProcessingParameterFileDestination
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
Definition: qgsprocessingparameters.h:3451
QgsDistanceArea::measureLine
double measureLine(const QVector< QgsPointXY > &points) const
Measures the length of a line with multiple segments.
Definition: qgsdistancearea.cpp:298
QgsProcessingContext::ellipsoid
QString ellipsoid() const
Returns the ellipsoid to use for distance and area calculations.
Definition: qgsprocessingcontext.cpp:185
QgsSpatialIndex
A spatial index for QgsFeature objects.
Definition: qgsspatialindex.h:67
QgsProcessingContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context.
Definition: qgsprocessingcontext.h:165
QgsDistanceArea::setSourceCrs
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Definition: qgsdistancearea.cpp:83
QgsSpatialIndex::FlagStoreFeatureGeometries
@ FlagStoreFeatureGeometries
Indicates that the spatial index should also store feature geometries. This requires more memory,...
Definition: qgsspatialindex.h:77
QgsGeometry::asPoint
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Definition: qgsgeometry.cpp:1662
qgsalgorithmnearestneighbouranalysis.h
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsDistanceArea
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
Definition: qgsdistancearea.h:52
qgsdistancearea.h
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsProcessingException
Custom exception class for processing related exceptions.
Definition: qgsexception.h:82
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28