Skip to content

Commit

Permalink
Allow bulk load of QgsSpatialIndex to be canceled via QgsFeedback
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 15, 2017
1 parent b441a4f commit 7baa623
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 21 deletions.
13 changes: 11 additions & 2 deletions python/core/qgsspatialindex.sip
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/Difference.py
Expand Up @@ -83,7 +83,7 @@ def processAlgorithm(self, parameters, context, feedback):
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
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/Intersection.py
Expand Up @@ -95,7 +95,7 @@ def processAlgorithm(self, parameters, context, feedback):
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
Expand Down
Expand Up @@ -94,7 +94,7 @@ def processAlgorithm(self, parameters, context, feedback):
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())
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/PointsInPolygon.py
Expand Up @@ -111,7 +111,7 @@ def processAlgorithm(self, parameters, context, feedback):
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:
Expand Down
Expand Up @@ -83,7 +83,7 @@ def processAlgorithm(self, parameters, context, feedback):
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:
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/qgis/SumLines.py
Expand Up @@ -101,7 +101,7 @@ def processAlgorithm(self, parameters, context, feedback):
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())
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/SymmetricalDifference.py
Expand Up @@ -87,8 +87,8 @@ def processAlgorithm(self, parameters, context, feedback):
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
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/Union.py
Expand Up @@ -97,8 +97,8 @@ def processAlgorithm(self, parameters, context, feedback):
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
Expand Down
20 changes: 13 additions & 7 deletions src/core/qgsspatialindex.cpp
Expand Up @@ -21,6 +21,7 @@
#include "qgsrectangle.h"
#include "qgslogger.h"
#include "qgsfeaturesource.h"
#include "qgsfeedback.h"

#include "SpatialIndex.h"

Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
Expand Down Expand Up @@ -141,6 +146,7 @@ class QgsFeatureIteratorDataStream : public IDataStream
private:
QgsFeatureIterator mFi;
RTree::Data *mNextData = nullptr;
QgsFeedback *mFeedback = nullptr;
};


Expand All @@ -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 );
}

Expand Down Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions src/core/qgsspatialindex.h
Expand Up @@ -33,6 +33,7 @@ namespace SpatialIndex SIP_SKIP
}
}

class QgsFeedback;
class QgsFeature;
class QgsRectangle;
class QgsPointXY;
Expand Down Expand Up @@ -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 );
Expand Down

0 comments on commit 7baa623

Please sign in to comment.