Skip to content

Commit eaad18c

Browse files
authoredJul 15, 2017
Merge pull request #4861 from nyalldawson/nn
Port nearest neighbour alg to new API
2 parents 1cb2728 + 353d4fc commit eaad18c

17 files changed

+134
-67
lines changed
 

‎python/core/qgsspatialindex.sip

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,28 @@ class QgsSpatialIndex
2828
Constructor - creates R-tree
2929
%End
3030

31-
explicit QgsSpatialIndex( const QgsFeatureIterator &fi );
31+
explicit QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback = 0 );
3232
%Docstring
3333
Constructor - creates R-tree and bulk loads it with features from the iterator.
3434
This is much faster approach than creating an empty index and then inserting features one by one.
3535

36+
The optional ``feedback`` object can be used to allow cancelation of bulk feature loading. Ownership
37+
of ``feedback`` is not transferred, and callers must take care that the lifetime of feedback exceeds
38+
that of the spatial index construction.
39+
3640
.. versionadded:: 2.8
3741
%End
3842

39-
explicit QgsSpatialIndex( const QgsFeatureSource &source );
43+
explicit QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback = 0 );
4044
%Docstring
4145
Constructor - creates R-tree and bulk loads it with features from the source.
4246
This is much faster approach than creating an empty index and then inserting features one by one.
4347

48+
The optional ``feedback`` object can be used to allow cancelation of bulk feature loading. Ownership
49+
of ``feedback`` is not transferred, and callers must take care that the lifetime of feedback exceeds
50+
that of the spatial index construction.
51+
52+
4453
.. versionadded:: 3.0
4554
%End
4655

‎python/plugins/processing/algs/qgis/Difference.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def processAlgorithm(self, parameters, context, feedback):
8383
featB = QgsFeature()
8484
outFeat = QgsFeature()
8585

86-
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
86+
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
8787

8888
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
8989
count = 0

‎python/plugins/processing/algs/qgis/Intersection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def processAlgorithm(self, parameters, context, feedback):
9595
fields, geomType, sourceA.sourceCrs())
9696

9797
outFeat = QgsFeature()
98-
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
98+
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
9999

100100
total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1
101101
count = 0

‎python/plugins/processing/algs/qgis/NearestNeighbourAnalysis.py

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,25 @@
3333

3434
from 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

3846
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
4347

4448
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4549

4650

4751
class 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, feedback)
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:

‎python/plugins/processing/algs/qgis/PointDistance.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
from qgis.PyQt.QtGui import QIcon
3535

36-
from qgis.core import QgsFeatureRequest, QgsDistanceArea, QgsFeatureSink, QgsProcessingUtils
36+
from qgis.core import QgsFeatureRequest, QgsProject, QgsDistanceArea, QgsFeatureSink, QgsProcessingUtils
3737

3838
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
3939
from processing.core.parameters import ParameterNumber
@@ -134,6 +134,8 @@ def linearMatrix(self, context, inLayer, inField, targetLayer, targetField,
134134
outIdx = targetLayer.fields().lookupField(targetField)
135135

136136
distArea = QgsDistanceArea()
137+
distArea.setSourceCrs(inLayer.crs())
138+
distArea.setEllipsoid(QgsProject.instance().ellipsoid())
137139

138140
features = QgsProcessingUtils.getFeatures(inLayer, context)
139141
total = 100.0 / inLayer.featureCount() if inLayer.featureCount() else 0
@@ -172,6 +174,8 @@ def regularMatrix(self, context, inLayer, inField, targetLayer, targetField,
172174
inIdx = inLayer.fields().lookupField(inField)
173175

174176
distArea = QgsDistanceArea()
177+
distArea.setSourceCrs(inLayer.sourceCrs())
178+
distArea.setEllipsoid(QgsProject.instance().ellipsoid())
175179

176180
first = True
177181
features = QgsProcessingUtils.getFeatures(inLayer, context)

‎python/plugins/processing/algs/qgis/PointsInPolygon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def processAlgorithm(self, parameters, context, feedback):
111111
fields, poly_source.wkbType(), poly_source.sourceCrs())
112112

113113
spatialIndex = QgsSpatialIndex(point_source.getFeatures(
114-
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())))
114+
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())), feedback)
115115

116116
point_attribute_indices = []
117117
if weight_field_index >= 0:

‎python/plugins/processing/algs/qgis/PointsToPaths.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
QgsField,
3838
QgsGeometry,
3939
QgsDistanceArea,
40+
QgsProject,
4041
QgsWkbTypes,
4142
QgsProcessingUtils)
4243

@@ -120,6 +121,8 @@ def processAlgorithm(self, parameters, context, feedback):
120121
feedback.setProgress(0)
121122

122123
da = QgsDistanceArea()
124+
da.setSourceCrs(layer.sourceCrs())
125+
da.setEllipsoid(QgsProject.instance().ellipsoid())
123126

124127
current = 0
125128
total = 100.0 / len(points) if points else 1

‎python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
from .Intersection import Intersection
6767
from .LinesToPolygons import LinesToPolygons
6868
from .Merge import Merge
69+
from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
6970
from .PointsInPolygon import PointsInPolygon
7071
from .PointsLayerFromTable import PointsLayerFromTable
7172
from .PolygonsToLines import PolygonsToLines
@@ -90,7 +91,6 @@
9091
from .ZonalStatistics import ZonalStatistics
9192

9293
# from .ExtractByLocation import ExtractByLocation
93-
# from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
9494
# from .LinesIntersection import LinesIntersection
9595
# from .MeanCoords import MeanCoords
9696
# from .PointDistance import PointDistance
@@ -183,7 +183,7 @@ def __init__(self):
183183
self.externalAlgs = []
184184

185185
def getAlgs(self):
186-
# algs = [NearestNeighbourAnalysis(), MeanCoords(),
186+
# algs = [MeanCoords(),
187187
# LinesIntersection(), UniqueValues(), PointDistance(),
188188
# ExportGeometryInfo(),
189189
# SinglePartsToMultiparts(),
@@ -260,6 +260,7 @@ def getAlgs(self):
260260
Intersection(),
261261
LinesToPolygons(),
262262
Merge(),
263+
NearestNeighbourAnalysis(),
263264
PointsInPolygon(),
264265
PointsLayerFromTable(),
265266
PolygonsToLines(),

‎python/plugins/processing/algs/qgis/RandomPointsAlongLines.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
QgsFeature,
4242
QgsPointXY,
4343
QgsMessageLog,
44+
QgsProject,
4445
QgsProcessingUtils)
4546

4647
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -97,6 +98,9 @@ def processAlgorithm(self, parameters, context, feedback):
9798
points = dict()
9899

99100
da = QgsDistanceArea()
101+
da.setSourceCrs(layer.sourceCrs())
102+
da.setEllipsoid(QgsProject.instance().ellipsoid())
103+
100104
request = QgsFeatureRequest()
101105

102106
random.seed()

‎python/plugins/processing/algs/qgis/RandomPointsPolygonsFixed.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
from qgis.core import (QgsFields, QgsFeatureSink, QgsField, QgsDistanceArea, QgsGeometry, QgsWkbTypes,
3434
QgsSpatialIndex, QgsPointXY, QgsFeature,
3535
QgsMessageLog,
36-
QgsProcessingUtils)
36+
QgsProcessingUtils,
37+
QgsProject)
3738

3839
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
3940
from processing.core.parameters import ParameterVector
@@ -94,6 +95,8 @@ def processAlgorithm(self, parameters, context, feedback):
9495
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context)
9596

9697
da = QgsDistanceArea()
98+
da.setSourceCrs(layer.sourceCrs())
99+
da.setEllipsoid(QgsProject.instance().ellipsoid())
97100

98101
features = QgsProcessingUtils.getFeatures(layer, context)
99102
for current, f in enumerate(features):

‎python/plugins/processing/algs/qgis/RandomPointsPolygonsVariable.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from qgis.core import (QgsFields, QgsFeatureSink, QgsField, QgsFeature, QgsPointXY, QgsWkbTypes,
3434
QgsGeometry, QgsSpatialIndex, QgsDistanceArea,
3535
QgsMessageLog,
36+
QgsProject,
3637
QgsProcessingUtils)
3738

3839
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
@@ -95,6 +96,8 @@ def processAlgorithm(self, parameters, context, feedback):
9596
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, QgsWkbTypes.Point, layer.crs(), context)
9697

9798
da = QgsDistanceArea()
99+
da.setSourceCrs(layer.sourceCrs())
100+
da.setEllipsoid(QgsProject.instance().ellipsoid())
98101

99102
features = QgsProcessingUtils.getFeatures(layer, context)
100103
for current, f in enumerate(features):

‎python/plugins/processing/algs/qgis/SelectByAttributeSum.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def processAlgorithm(self, parameters, context, feedback):
8383
geom = ft.geometry()
8484
attrSum = ft[fieldName]
8585

86-
idx = QgsSpatialIndex(layer.getFeatures(QgsFeatureRequest.setSubsetOfAttributes([])))
86+
idx = QgsSpatialIndex(layer.getFeatures(QgsFeatureRequest.setSubsetOfAttributes([])), feedback)
8787
req = QgsFeatureRequest()
8888
completed = False
8989
while not completed:

‎python/plugins/processing/algs/qgis/SumLines.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
QgsGeometry,
3636
QgsFeatureRequest,
3737
QgsDistanceArea,
38+
QgsProject,
3839
QgsProcessing,
3940
QgsProcessingParameterString,
4041
QgsProcessingParameterFeatureSource,
@@ -100,9 +101,11 @@ def processAlgorithm(self, parameters, context, feedback):
100101
fields, poly_source.wkbType(), poly_source.sourceCrs())
101102

102103
spatialIndex = QgsSpatialIndex(line_source.getFeatures(
103-
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())))
104+
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())), feedback)
104105

105106
distArea = QgsDistanceArea()
107+
distArea.setSourceCrs(poly_source.sourceCrs())
108+
distArea.setEllipsoid(QgsProject.instance().ellipsoid())
106109

107110
features = poly_source.getFeatures()
108111
total = 100.0 / poly_source.featureCount() if poly_source.featureCount() else 0

‎python/plugins/processing/algs/qgis/SymmetricalDifference.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ def processAlgorithm(self, parameters, context, feedback):
8787
featB = QgsFeature()
8888
outFeat = QgsFeature()
8989

90-
indexA = QgsSpatialIndex(sourceA)
91-
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
90+
indexA = QgsSpatialIndex(sourceA, feedback)
91+
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
9292

9393
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
9494
count = 0

‎python/plugins/processing/algs/qgis/Union.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ def processAlgorithm(self, parameters, context, feedback):
9797
featB = QgsFeature()
9898
outFeat = QgsFeature()
9999

100-
indexA = QgsSpatialIndex(sourceA)
101-
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
100+
indexA = QgsSpatialIndex(sourceA, feedback)
101+
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
102102

103103
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
104104
count = 0

‎src/core/qgsspatialindex.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgsrectangle.h"
2222
#include "qgslogger.h"
2323
#include "qgsfeaturesource.h"
24+
#include "qgsfeedback.h"
2425

2526
#include "SpatialIndex.h"
2627

@@ -92,9 +93,10 @@ class QgsFeatureIteratorDataStream : public IDataStream
9293
{
9394
public:
9495
//! constructor - needs to load all data to a vector for later access when bulk loading
95-
explicit QgsFeatureIteratorDataStream( const QgsFeatureIterator &fi )
96+
explicit QgsFeatureIteratorDataStream( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr )
9697
: mFi( fi )
9798
, mNextData( nullptr )
99+
, mFeedback( feedback )
98100
{
99101
readNextEntry();
100102
}
@@ -107,6 +109,9 @@ class QgsFeatureIteratorDataStream : public IDataStream
107109
//! returns a pointer to the next entry in the stream or 0 at the end of the stream.
108110
IData *getNext() override
109111
{
112+
if ( mFeedback && mFeedback->isCanceled() )
113+
return nullptr;
114+
110115
RTree::Data *ret = mNextData;
111116
mNextData = nullptr;
112117
readNextEntry();
@@ -141,6 +146,7 @@ class QgsFeatureIteratorDataStream : public IDataStream
141146
private:
142147
QgsFeatureIterator mFi;
143148
RTree::Data *mNextData = nullptr;
149+
QgsFeedback *mFeedback = nullptr;
144150
};
145151

146152

@@ -157,9 +163,17 @@ class QgsSpatialIndexData : public QSharedData
157163
initTree();
158164
}
159165

160-
explicit QgsSpatialIndexData( const QgsFeatureIterator &fi )
166+
/**
167+
* Constructor for QgsSpatialIndexData which bulk loads features from the specified feature iterator
168+
* \a fi.
169+
*
170+
* The optional \a feedback object can be used to allow cancelation of bulk feature loading. Ownership
171+
* of \a feedback is not transferred, and callers must take care that the lifetime of feedback exceeds
172+
* that of the spatial index construction.
173+
*/
174+
explicit QgsSpatialIndexData( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr )
161175
{
162-
QgsFeatureIteratorDataStream fids( fi );
176+
QgsFeatureIteratorDataStream fids( fi, feedback );
163177
initTree( &fids );
164178
}
165179

@@ -224,14 +238,14 @@ QgsSpatialIndex::QgsSpatialIndex()
224238
d = new QgsSpatialIndexData;
225239
}
226240

227-
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureIterator &fi )
241+
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback )
228242
{
229-
d = new QgsSpatialIndexData( fi );
243+
d = new QgsSpatialIndexData( fi, feedback );
230244
}
231245

232-
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureSource &source )
246+
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback )
233247
{
234-
d = new QgsSpatialIndexData( source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ) );
248+
d = new QgsSpatialIndexData( source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ), feedback );
235249
}
236250

237251
QgsSpatialIndex::QgsSpatialIndex( const QgsSpatialIndex &other ) //NOLINT

‎src/core/qgsspatialindex.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace SpatialIndex SIP_SKIP
3333
}
3434
}
3535

36+
class QgsFeedback;
3637
class QgsFeature;
3738
class QgsRectangle;
3839
class QgsPointXY;
@@ -64,17 +65,26 @@ class CORE_EXPORT QgsSpatialIndex
6465
/** Constructor - creates R-tree and bulk loads it with features from the iterator.
6566
* This is much faster approach than creating an empty index and then inserting features one by one.
6667
*
68+
* The optional \a feedback object can be used to allow cancelation of bulk feature loading. Ownership
69+
* of \a feedback is not transferred, and callers must take care that the lifetime of feedback exceeds
70+
* that of the spatial index construction.
71+
*
6772
* \since QGIS 2.8
6873
*/
69-
explicit QgsSpatialIndex( const QgsFeatureIterator &fi );
74+
explicit QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr );
7075

7176
/**
7277
* Constructor - creates R-tree and bulk loads it with features from the source.
7378
* This is much faster approach than creating an empty index and then inserting features one by one.
79+
*
80+
* The optional \a feedback object can be used to allow cancelation of bulk feature loading. Ownership
81+
* of \a feedback is not transferred, and callers must take care that the lifetime of feedback exceeds
82+
* that of the spatial index construction.
83+
7484
*
7585
* \since QGIS 3.0
7686
*/
77-
explicit QgsSpatialIndex( const QgsFeatureSource &source );
87+
explicit QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback = nullptr );
7888

7989
//! Copy constructor
8090
QgsSpatialIndex( const QgsSpatialIndex &other );

0 commit comments

Comments
 (0)
Please sign in to comment.