From 80084da84cb91dc116473280fd6a34405caf3318 Mon Sep 17 00:00:00 2001 From: mhugent Date: Sat, 30 Sep 2006 09:17:48 +0000 Subject: [PATCH] Use str tree spatial index from geos for the wfsprovider git-svn-id: http://svn.osgeo.org/qgis/trunk@5889 c8812cc2-4d05-0410-92ff-de0c093fc19c --- src/core/qgsgeometry.cpp | 12 ++---- src/providers/wfs/qgswfsprovider.cpp | 62 ++++++++++++++++++---------- src/providers/wfs/qgswfsprovider.h | 16 ++++--- 3 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/core/qgsgeometry.cpp b/src/core/qgsgeometry.cpp index c46d02f0160..5f96e776970 100644 --- a/src/core/qgsgeometry.cpp +++ b/src/core/qgsgeometry.cpp @@ -2489,9 +2489,6 @@ geos::Geometry* QgsGeometry::geosGeometry() const ptr += sizeof(double); y = (double *) ptr; ptr += sizeof(double); -#ifdef QGISDEBUG - qWarning("QgsGeometry::geosGeometry: adding coordinate pair "+QString::number(*x)+"//"+QString::number(*y)); -#endif sequence->add(geos::Coordinate(*x,*y)); } return geosGeometryFactory->createLineString(sequence); @@ -2603,9 +2600,6 @@ geos::Geometry* QgsGeometry::geosGeometry() const ptr += sizeof(double); y = (double *) ptr; ptr += sizeof(double); -#ifdef QGISDEBUG - //qWarning("adding coordinate pair "+QString::number(*x)+"//"+QString::number(*y)); -#endif sequence->add(geos::Coordinate(*x,*y)); } geos::LinearRing* ring=geosGeometryFactory->createLinearRing(sequence); @@ -2723,9 +2717,9 @@ bool QgsGeometry::exportGeosToWkb() const for (int n = 0; n < numPoints; n++) { #ifdef QGISDEBUG - std::cout << "QgsGeometry::exportGeosToWkb: Adding " - << sequence->getAt(n).x << ", " - << sequence->getAt(n).y << "." << std::endl; + //std::cout << "QgsGeometry::exportGeosToWkb: Adding " + // << sequence->getAt(n).x << ", " + // << sequence->getAt(n).y << "." << std::endl; #endif // assign x memcpy(ptr, &(sequence->getAt(n).x), sizeof(double)); diff --git a/src/providers/wfs/qgswfsprovider.cpp b/src/providers/wfs/qgswfsprovider.cpp index 93f72616645..fa10b198e7e 100644 --- a/src/providers/wfs/qgswfsprovider.cpp +++ b/src/providers/wfs/qgswfsprovider.cpp @@ -36,9 +36,8 @@ static const QString TEXT_PROVIDER_DESCRIPTION = "WFS data provider"; static const QString WFS_NAMESPACE = "http://www.opengis.net/wfs"; static const QString GML_NAMESPACE = "http://www.opengis.net/gml"; -QgsWFSProvider::QgsWFSProvider(const QString& uri): QgsVectorDataProvider(uri), mFilter(0), mUseIntersect(false), mSourceSRS(0) +QgsWFSProvider::QgsWFSProvider(const QString& uri): QgsVectorDataProvider(uri), mUseIntersect(false), mSourceSRS(0), mSelectedFeatures(0), mFeatureCount(0) { - mFeatureIterator = mFeatures.begin(); if(getFeature(uri) == 0) { //provider valid @@ -47,16 +46,20 @@ QgsWFSProvider::QgsWFSProvider(const QString& uri): QgsVectorDataProvider(uri), { //provider invalid } + //set spatial filter to the whole extent + select(&mExtent, false); } QgsWFSProvider::~QgsWFSProvider() { - for(std::vector::iterator it = mFeatures.begin(); it != mFeatures.end(); ++it) + delete mSelectedFeatures; + delete mSourceSRS; + for(std::list >::iterator it = mEnvelopesAndFeatures.begin();\ + it != mEnvelopesAndFeatures.end(); ++it) { - delete (*it); + delete it->first; + delete it->second; } - mFeatures.clear(); - delete mFilter; } QgsFeature* QgsWFSProvider::getFirstFeature(bool fetchAttributes) @@ -80,29 +83,29 @@ QgsFeature* QgsWFSProvider::getNextFeature(std::list const & attlist, int f { while(true) //go through the loop until we find a feature in the filter { - if(mFeatureIterator == mFeatures.end()) + if(!mSelectedFeatures || mFeatureIterator == mSelectedFeatures->end()) { return 0; } QgsFeature* f = new QgsFeature(); - unsigned char* geom = (*mFeatureIterator)->getGeometry(); - int geomSize = (*mFeatureIterator)->getGeometrySize(); + unsigned char* geom = ((QgsFeature*)(*mFeatureIterator))->getGeometry(); + int geomSize = ((QgsFeature*)(*mFeatureIterator))->getGeometrySize(); unsigned char* copiedGeom = new unsigned char[geomSize]; memcpy(copiedGeom, geom, geomSize); f->setGeometryAndOwnership(copiedGeom, geomSize); - f->setFeatureId((*mFeatureIterator)->featureId()); + f->setFeatureId(((QgsFeature*)(*mFeatureIterator))->featureId()); - const std::vector attributes = (*mFeatureIterator)->attributeMap(); + const std::vector attributes = ((QgsFeature*)(*mFeatureIterator))->attributeMap(); for(std::list::const_iterator it = attlist.begin(); it != attlist.end(); ++it) { f->addAttribute(attributes[*it].fieldName(), attributes[*it].fieldValue(), attributes[*it].isNumeric()); } ++mFeatureIterator; - if(mFilter && mUseIntersect) + if(mUseIntersect) { - if(f->geometry()->fast_intersects(mFilter)) + if(f->geometry()->fast_intersects(&mSpatialFilter)) { return f; } @@ -130,7 +133,7 @@ int QgsWFSProvider::geometryType() const long QgsWFSProvider::featureCount() const { - return mFeatures.size(); + return mFeatureCount; } int QgsWFSProvider::fieldCount() const @@ -145,9 +148,13 @@ std::vector const & QgsWFSProvider::fields() const void QgsWFSProvider::reset() { - mFeatureIterator = mFeatures.begin(); - delete mFilter; - mFilter = 0; + geos::Envelope e(mExtent.xMin(), mExtent.xMax(), mExtent.yMin(), mExtent.yMax()); + delete mSelectedFeatures; + mSelectedFeatures = mSpatialIndex.query(&e); + if(mSelectedFeatures) + { + mFeatureIterator = mSelectedFeatures->begin(); + } } QString QgsWFSProvider::minValue(int position) @@ -231,9 +238,12 @@ bool QgsWFSProvider::isValid() void QgsWFSProvider::select(QgsRect *mbr, bool useIntersect) { - reset(); - mFilter = new QgsRect(*mbr); mUseIntersect = useIntersect; + delete mSelectedFeatures; + mSpatialFilter = *mbr; + geos::Envelope filter(mbr->xMin(), mbr->xMax(), mbr->yMin(), mbr->yMax()); + mSelectedFeatures = mSpatialIndex.query(&filter); + mFeatureIterator = mSelectedFeatures->begin(); } int QgsWFSProvider::getCapabilities(const QString& uri, QgsWFSProvider::REQUEST_ENCODING e, std::list& typenames, std::list< std::list >& crs) @@ -404,7 +414,7 @@ int QgsWFSProvider::getFeatureGET(const QString& uri, const QString& geometryAtt setSRSFromGML2(featureCollectionElement); - if(getFeaturesFromGML2(featureCollectionElement, geometryAttribute, mFeatures) != 0) + if(getFeaturesFromGML2(featureCollectionElement, geometryAttribute) != 0) { return 4; } @@ -638,7 +648,7 @@ int QgsWFSProvider::setSRSFromGML2(const QDomElement& wfsCollectionElement) return 0; } -int QgsWFSProvider::getFeaturesFromGML2(const QDomElement& wfsCollectionElement, const QString& geometryAttribute, std::vector& features) const +int QgsWFSProvider::getFeaturesFromGML2(const QDomElement& wfsCollectionElement, const QString& geometryAttribute) { QDomNodeList featureTypeNodeList = wfsCollectionElement.elementsByTagNameNS(GML_NAMESPACE, "featureMember"); QDomElement currentFeatureMemberElem; @@ -650,6 +660,9 @@ int QgsWFSProvider::getFeaturesFromGML2(const QDomElement& wfsCollectionElement, unsigned char* wkb = 0; int wkbSize = 0; QGis::WKBTYPE currentType; + QgsRect featureBBox; + geos::Envelope* geosBBox; + mFeatureCount = 0; for(int i = 0; i < featureTypeNodeList.size(); ++i) { @@ -679,7 +692,12 @@ int QgsWFSProvider::getFeaturesFromGML2(const QDomElement& wfsCollectionElement, } if(wkb && wkbSize > 0) { - features.push_back(f); + //insert bbox and pointer to feature into search tree + featureBBox = f->boundingBox(); + geosBBox = new geos::Envelope(featureBBox.xMin(), featureBBox.xMax(), featureBBox.yMin(), featureBBox.yMax()); + mSpatialIndex.insert(geosBBox, (void*)f); + mEnvelopesAndFeatures.push_back(std::make_pair(geosBBox, f)); + ++mFeatureCount; } ++counter; } diff --git a/src/providers/wfs/qgswfsprovider.h b/src/providers/wfs/qgswfsprovider.h index d70a5b29ef7..14ad72003fc 100644 --- a/src/providers/wfs/qgswfsprovider.h +++ b/src/providers/wfs/qgswfsprovider.h @@ -22,6 +22,7 @@ #include "qgis.h" #include "qgsrect.h" #include "qgsvectordataprovider.h" +#include class QgsRect; @@ -86,13 +87,17 @@ class QgsWFSProvider: public QgsVectorDataProvider /**Bounding box for the layer*/ QgsRect mExtent; /**Spatial filter for the layer*/ - QgsRect* mFilter; + QgsRect mSpatialFilter; /**Flag if precise intersection test is needed. Otherwise, every feature is returned (even if a filter is set)*/ bool mUseIntersect; - /**Stores all the features*/ - std::vector mFeatures; + /**A spatial index for fast access to a feature subset*/ + geos::STRtree mSpatialIndex; + /**Stores all the inserted rectangles and features. This is used to clean up the memory in the destructor*/ + std::list< std::pair > mEnvelopesAndFeatures; + /**Vector where the QgsFeature* of a query are inserted*/ + std::vector* mSelectedFeatures; /**Iterator on the feature vector for use in reset(), getNextFeature(), etc...*/ - std::vector::iterator mFeatureIterator; + std::vector::iterator mFeatureIterator; /**Geometry type of the features in this layer*/ mutable QGis::WKBTYPE mWKBType; /**Source SRS*/ @@ -100,6 +105,7 @@ class QgsWFSProvider: public QgsVectorDataProvider /**Stores the minimum/maximum values for each attribute The position in the vector is equal to the position of an attribute in the layers attribute vector*/ std::vector< std::pair > mMinMaxCash; + int mFeatureCount; /**Goes through all the features and their attributes and populates mMinMaxCash with entries*/ void fillMinMaxCash(); @@ -123,7 +129,7 @@ class QgsWFSProvider: public QgsVectorDataProvider //GML2 specific methods int getExtentFromGML2(QgsRect* extent, const QDomElement& wfsCollectionElement) const; - int getFeaturesFromGML2(const QDomElement& wfsCollectionElement, const QString& geometryAttribute, std::vector& features) const; + int getFeaturesFromGML2(const QDomElement& wfsCollectionElement, const QString& geometryAttribute); int getWkbFromGML2(const QDomNode& geometryElement, unsigned char** wkb, int* wkbSize, QGis::WKBTYPE* type) const; /**Creates WKB from a element*/