Skip to content
Permalink
Browse files

Polishing and optimizations in memory provider:

- possibility to use spatial index
- more effective getNextFeature (wheter using spatial index or not)


git-svn-id: http://svn.osgeo.org/qgis/trunk@8652 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
wonder
wonder committed Jun 17, 2008
1 parent b7b9f62 commit 42e0ae50aaa62e18c5b5445c0462249a6a2d1ecd
Showing with 127 additions and 11 deletions.
  1. +1 −1 src/providers/memory/CMakeLists.txt
  2. +111 −10 src/providers/memory/memoryprovider.cpp
  3. +15 −0 src/providers/memory/memoryprovider.h
@@ -3,7 +3,7 @@ SET (MEMORY_SRCS memoryprovider.cpp)

INCLUDE_DIRECTORIES(
.
../../core
../../core ../../core/spatialindex
${GEOS_INCLUDE_DIR}
)

@@ -19,14 +19,17 @@
#include "qgsfield.h"
#include "qgsgeometry.h"
#include "qgslogger.h"
#include "qgsspatialindex.h"
#include "qgsspatialrefsys.h"


static const QString TEXT_PROVIDER_KEY = "memory";
static const QString TEXT_PROVIDER_DESCRIPTION = "Memory provider";

QgsMemoryProvider::QgsMemoryProvider(QString uri)
: QgsVectorDataProvider(uri)
: QgsVectorDataProvider(uri),
mSpatialIndex(NULL),
mSelectRectGeom(NULL)
{
if (uri == "Point")
mWkbType = QGis::WKBPoint;
@@ -48,6 +51,8 @@ QgsMemoryProvider::QgsMemoryProvider(QString uri)

QgsMemoryProvider::~QgsMemoryProvider()
{
delete mSpatialIndex;
delete mSelectRectGeom;
}

QString QgsMemoryProvider::storageType() const
@@ -58,23 +63,63 @@ QString QgsMemoryProvider::storageType() const
bool QgsMemoryProvider::getNextFeature(QgsFeature& feature)
{
bool hasFeature = FALSE;

// option 1: using spatial index
if (mSelectUsingSpatialIndex)
{
while (mSelectSI_Iterator != mSelectSI_Features.end())
{
// do exact check in case we're doing intersection
if (mSelectUseIntersect)
{
if (mFeatures[*mSelectSI_Iterator].geometry()->intersects(mSelectRectGeom))
hasFeature = TRUE;
}
else
hasFeature = TRUE;

if (hasFeature)
break;

mSelectSI_Iterator++;
}

// copy feature
if (hasFeature)
{
feature = mFeatures[*mSelectSI_Iterator];
mSelectSI_Iterator++;
}
return hasFeature;
}

// option 2: not using spatial index
while (mSelectIterator != mFeatures.end())
{
if (mSelectRect.isEmpty())
{
// selection rect empty => using all features
hasFeature = TRUE;
break;
}
else
{
// TODO: could use some less accurate test when not using mSelectUseIntersect (e.g. spatial index)
if (mSelectIterator->geometry()->intersects(mSelectRect))
if (mSelectUseIntersect)
{
hasFeature = TRUE;
break;
// using exact test when checking for intersection
if (mSelectIterator->geometry()->intersects(mSelectRectGeom))
hasFeature = TRUE;
}
else
{
// check just bounding box against rect when not using intersection
if (mSelectIterator->geometry()->boundingBox().intersects(mSelectRect))
hasFeature = TRUE;
}
}

if (hasFeature)
break;

mSelectIterator++;
}

@@ -88,6 +133,7 @@ bool QgsMemoryProvider::getNextFeature(QgsFeature& feature)
return hasFeature;
}


bool QgsMemoryProvider::getFeatureAtId(int featureId,
QgsFeature& feature,
bool fetchGeometry,
@@ -110,15 +156,34 @@ void QgsMemoryProvider::select(QgsAttributeList fetchAttributes,
{
mSelectAttrs = fetchAttributes;
mSelectRect = rect;
delete mSelectRectGeom;
mSelectRectGeom = QgsGeometry::fromRect(rect);
mSelectGeometry = fetchGeometry;
mSelectUseIntersect = useIntersect;

// if there's spatial index, use it!
// (but don't use it when selection rect is not specified)
if (mSpatialIndex && !mSelectRect.isEmpty())
{
mSelectUsingSpatialIndex = TRUE;
mSelectSI_Features = mSpatialIndex->intersects(rect);
QgsDebugMsg("Features returned by spatial index: "+QString::number(mSelectSI_Features.count()));
}
else
{
mSelectUsingSpatialIndex = FALSE;
mSelectSI_Features.clear();
}

reset();
}

void QgsMemoryProvider::reset()
{
mSelectIterator = mFeatures.begin();
if (mSelectUsingSpatialIndex)
mSelectSI_Iterator = mSelectSI_Features.begin();
else
mSelectIterator = mFeatures.begin();
}


@@ -166,10 +231,17 @@ bool QgsMemoryProvider::addFeatures(QgsFeatureList & flist)
for (QgsFeatureList::iterator it = flist.begin(); it != flist.end(); ++it)
{
mFeatures[mNextFeatureId] = *it;
mFeatures[mNextFeatureId].setFeatureId(mNextFeatureId);
QgsFeature& newfeat = mFeatures[mNextFeatureId];
newfeat.setFeatureId(mNextFeatureId);

// update spatial index
if (mSpatialIndex)
mSpatialIndex->insertFeature(newfeat);

mNextFeatureId++;
}


updateExtent();

return TRUE;
@@ -178,7 +250,19 @@ bool QgsMemoryProvider::addFeatures(QgsFeatureList & flist)
bool QgsMemoryProvider::deleteFeatures(const QgsFeatureIds & id)
{
for (QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it)
mFeatures.remove(*it);
{
QgsFeatureMap::iterator fit = mFeatures.find(*it);

// check whether such feature exists
if (fit == mFeatures.end())
continue;

// update spatial index
if (mSpatialIndex)
mSpatialIndex->deleteFeature(*fit);

mFeatures.erase(fit);
}

updateExtent();

@@ -230,15 +314,32 @@ bool QgsMemoryProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
{
// TODO: change geometries

// TODO: update spatial index

updateExtent();

return FALSE;
}

bool QgsMemoryProvider::createSpatialIndex()
{
if (!mSpatialIndex)
{
mSpatialIndex = new QgsSpatialIndex();

// add existing features to index
for (QgsFeatureMap::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it)
{
mSpatialIndex->insertFeature(*it);
}
}
return TRUE;
}

int QgsMemoryProvider::capabilities() const
{
return AddFeatures | DeleteFeatures | ChangeGeometries |
ChangeAttributeValues | AddAttributes | DeleteAttributes |
ChangeAttributeValues | AddAttributes | DeleteAttributes | CreateSpatialIndex |
SelectAtId | SelectGeometryAtId | RandomSelectGeometryAtId | SequentialSelectGeometryAtId;
}

@@ -18,6 +18,7 @@

typedef QMap<int, QgsFeature> QgsFeatureMap;

class QgsSpatialIndex;

class QgsMemoryProvider : public QgsVectorDataProvider
{
@@ -138,6 +139,12 @@ class QgsMemoryProvider : public QgsVectorDataProvider
*/
virtual bool changeGeometryValues(QgsGeometryMap & geometry_map);

/**
* Creates a spatial index
* @return true in case of success
*/
virtual bool createSpatialIndex();

/** Returns a bitmask containing the supported capabilities
Note, some capabilities may change depending on whether
a spatial filter is active on this provider, so it may
@@ -188,6 +195,14 @@ class QgsMemoryProvider : public QgsVectorDataProvider
// selection
QgsAttributeList mSelectAttrs;
QgsRect mSelectRect;
QgsGeometry* mSelectRectGeom;
bool mSelectGeometry, mSelectUseIntersect;
QgsFeatureMap::iterator mSelectIterator;
bool mSelectUsingSpatialIndex;
QList<int> mSelectSI_Features;
QList<int>::iterator mSelectSI_Iterator;

// indexing
QgsSpatialIndex* mSpatialIndex;

};

0 comments on commit 42e0ae5

Please sign in to comment.
You can’t perform that action at this time.