Allow bulk load of QgsSpatialIndex to be canceled via QgsFeedback

This commit is contained in:
Nyall Dawson 2017-07-15 16:43:44 +10:00
parent b441a4f2c9
commit 7baa623f6f
11 changed files with 46 additions and 21 deletions

View File

@ -28,19 +28,28 @@ class QgsSpatialIndex
Constructor - creates R-tree
%End
explicit QgsSpatialIndex( const QgsFeatureIterator &fi );
explicit QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback = 0 );
%Docstring
Constructor - creates R-tree and bulk loads it with features from the iterator.
This is much faster approach than creating an empty index and then inserting features one by one.
The optional ``feedback`` object can be used to allow cancelation of bulk feature loading. Ownership
of ``feedback`` is not transferred, and callers must take care that the lifetime of feedback exceeds
that of the spatial index construction.
.. versionadded:: 2.8
%End
explicit QgsSpatialIndex( const QgsFeatureSource &source );
explicit QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback = 0 );
%Docstring
Constructor - creates R-tree and bulk loads it with features from the source.
This is much faster approach than creating an empty index and then inserting features one by one.
The optional ``feedback`` object can be used to allow cancelation of bulk feature loading. Ownership
of ``feedback`` is not transferred, and callers must take care that the lifetime of feedback exceeds
that of the spatial index construction.
.. versionadded:: 3.0
%End

View File

@ -83,7 +83,7 @@ class Difference(QgisAlgorithm):
featB = QgsFeature()
outFeat = QgsFeature()
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
count = 0

View File

@ -95,7 +95,7 @@ class Intersection(QgisAlgorithm):
fields, geomType, sourceA.sourceCrs())
outFeat = QgsFeature()
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1
count = 0

View File

@ -94,7 +94,7 @@ class NearestNeighbourAnalysis(QgisAlgorithm):
source = self.parameterAsSource(parameters, self.INPUT, context)
output_file = self.parameterAsFileOutput(parameters, self.OUTPUT_HTML_FILE, context)
spatialIndex = QgsSpatialIndex(source)
spatialIndex = QgsSpatialIndex(source, feedback)
distance = QgsDistanceArea()
distance.setSourceCrs(source.sourceCrs())

View File

@ -111,7 +111,7 @@ class PointsInPolygon(QgisAlgorithm):
fields, poly_source.wkbType(), poly_source.sourceCrs())
spatialIndex = QgsSpatialIndex(point_source.getFeatures(
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())))
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())), feedback)
point_attribute_indices = []
if weight_field_index >= 0:

View File

@ -83,7 +83,7 @@ class SelectByAttributeSum(QgisAlgorithm):
geom = ft.geometry()
attrSum = ft[fieldName]
idx = QgsSpatialIndex(layer.getFeatures(QgsFeatureRequest.setSubsetOfAttributes([])))
idx = QgsSpatialIndex(layer.getFeatures(QgsFeatureRequest.setSubsetOfAttributes([])), feedback)
req = QgsFeatureRequest()
completed = False
while not completed:

View File

@ -101,7 +101,7 @@ class SumLines(QgisAlgorithm):
fields, poly_source.wkbType(), poly_source.sourceCrs())
spatialIndex = QgsSpatialIndex(line_source.getFeatures(
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())))
QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(poly_source.sourceCrs())), feedback)
distArea = QgsDistanceArea()
distArea.setSourceCrs(poly_source.sourceCrs())

View File

@ -87,8 +87,8 @@ class SymmetricalDifference(QgisAlgorithm):
featB = QgsFeature()
outFeat = QgsFeature()
indexA = QgsSpatialIndex(sourceA)
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
indexA = QgsSpatialIndex(sourceA, feedback)
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
count = 0

View File

@ -97,8 +97,8 @@ class Union(QgisAlgorithm):
featB = QgsFeature()
outFeat = QgsFeature()
indexA = QgsSpatialIndex(sourceA)
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))
indexA = QgsSpatialIndex(sourceA, feedback)
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
total = 100.0 / (sourceA.featureCount() * sourceB.featureCount()) if sourceA.featureCount() and sourceB.featureCount() else 1
count = 0

View File

@ -21,6 +21,7 @@
#include "qgsrectangle.h"
#include "qgslogger.h"
#include "qgsfeaturesource.h"
#include "qgsfeedback.h"
#include "SpatialIndex.h"
@ -92,9 +93,10 @@ class QgsFeatureIteratorDataStream : public IDataStream
{
public:
//! constructor - needs to load all data to a vector for later access when bulk loading
explicit QgsFeatureIteratorDataStream( const QgsFeatureIterator &fi )
explicit QgsFeatureIteratorDataStream( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr )
: mFi( fi )
, mNextData( nullptr )
, mFeedback( feedback )
{
readNextEntry();
}
@ -107,6 +109,9 @@ class QgsFeatureIteratorDataStream : public IDataStream
//! returns a pointer to the next entry in the stream or 0 at the end of the stream.
IData *getNext() override
{
if ( mFeedback && mFeedback->isCanceled() )
return nullptr;
RTree::Data *ret = mNextData;
mNextData = nullptr;
readNextEntry();
@ -141,6 +146,7 @@ class QgsFeatureIteratorDataStream : public IDataStream
private:
QgsFeatureIterator mFi;
RTree::Data *mNextData = nullptr;
QgsFeedback *mFeedback = nullptr;
};
@ -157,9 +163,9 @@ class QgsSpatialIndexData : public QSharedData
initTree();
}
explicit QgsSpatialIndexData( const QgsFeatureIterator &fi )
explicit QgsSpatialIndexData( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr )
{
QgsFeatureIteratorDataStream fids( fi );
QgsFeatureIteratorDataStream fids( fi, feedback );
initTree( &fids );
}
@ -224,14 +230,14 @@ QgsSpatialIndex::QgsSpatialIndex()
d = new QgsSpatialIndexData;
}
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureIterator &fi )
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback )
{
d = new QgsSpatialIndexData( fi );
d = new QgsSpatialIndexData( fi, feedback );
}
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureSource &source )
QgsSpatialIndex::QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback )
{
d = new QgsSpatialIndexData( source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ) );
d = new QgsSpatialIndexData( source.getFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) ), feedback );
}
QgsSpatialIndex::QgsSpatialIndex( const QgsSpatialIndex &other ) //NOLINT

View File

@ -33,6 +33,7 @@ namespace SpatialIndex SIP_SKIP
}
}
class QgsFeedback;
class QgsFeature;
class QgsRectangle;
class QgsPointXY;
@ -64,17 +65,26 @@ class CORE_EXPORT QgsSpatialIndex
/** Constructor - creates R-tree and bulk loads it with features from the iterator.
* This is much faster approach than creating an empty index and then inserting features one by one.
*
* The optional \a feedback object can be used to allow cancelation of bulk feature loading. Ownership
* of \a feedback is not transferred, and callers must take care that the lifetime of feedback exceeds
* that of the spatial index construction.
*
* \since QGIS 2.8
*/
explicit QgsSpatialIndex( const QgsFeatureIterator &fi );
explicit QgsSpatialIndex( const QgsFeatureIterator &fi, QgsFeedback *feedback = nullptr );
/**
* Constructor - creates R-tree and bulk loads it with features from the source.
* This is much faster approach than creating an empty index and then inserting features one by one.
*
* The optional \a feedback object can be used to allow cancelation of bulk feature loading. Ownership
* of \a feedback is not transferred, and callers must take care that the lifetime of feedback exceeds
* that of the spatial index construction.
*
* \since QGIS 3.0
*/
explicit QgsSpatialIndex( const QgsFeatureSource &source );
explicit QgsSpatialIndex( const QgsFeatureSource &source, QgsFeedback *feedback = nullptr );
//! Copy constructor
QgsSpatialIndex( const QgsSpatialIndex &other );