[QGIS Commit] r13900 - branches/threading-branch/src/providers/osm
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Thu Jul 8 08:37:11 EDT 2010
Author: wonder
Date: 2010-07-08 12:37:11 +0000 (Thu, 08 Jul 2010)
New Revision: 13900
Added:
branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.cpp
branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.h
Modified:
branches/threading-branch/src/providers/osm/CMakeLists.txt
branches/threading-branch/src/providers/osm/osmprovider.cpp
branches/threading-branch/src/providers/osm/osmprovider.h
Log:
Adapted OSM provider to use new read API.
Modified: branches/threading-branch/src/providers/osm/CMakeLists.txt
===================================================================
--- branches/threading-branch/src/providers/osm/CMakeLists.txt 2010-07-08 11:09:39 UTC (rev 13899)
+++ branches/threading-branch/src/providers/osm/CMakeLists.txt 2010-07-08 12:37:11 UTC (rev 13900)
@@ -7,6 +7,7 @@
osmprovider.cpp
osmrenderer.cpp
osmstyle.cpp
+qgsosmfeatureiterator.cpp
)
SET(OSM_MOC_HDRS osmprovider.h)
Modified: branches/threading-branch/src/providers/osm/osmprovider.cpp
===================================================================
--- branches/threading-branch/src/providers/osm/osmprovider.cpp 2010-07-08 11:09:39 UTC (rev 13899)
+++ branches/threading-branch/src/providers/osm/osmprovider.cpp 2010-07-08 12:37:11 UTC (rev 13900)
@@ -15,6 +15,7 @@
#include "osmprovider.h"
#include "osmhandler.h"
#include "osmrenderer.h"
+#include "qgsosmfeatureiterator.h"
#include "qgsfeature.h"
#include "qgsfield.h"
@@ -43,12 +44,8 @@
{
QgsDebugMsg( "Initializing provider: " + uri );
- mDatabaseStmt = NULL;
mValid = false;
- // set the selection rectangle to null
- mSelectionRectangle = 0;
- mSelectionRectangleGeom = NULL;
mDatabase = NULL;
mInitObserver = NULL;
mFeatureType = PointType; // default feature type ~ point
@@ -330,9 +327,6 @@
QgsOSMDataProvider::~QgsOSMDataProvider()
{
- // destruct selected geometry
- delete mSelectionRectangleGeom;
-
// finalize all created sqlite3 statements
sqlite3_finalize( mTagsStmt );
sqlite3_finalize( mCustomTagsStmt );
@@ -414,83 +408,6 @@
}
-void QgsOSMDataProvider::select( QgsAttributeList fetchAttributes,
- QgsRectangle rect,
- bool fetchGeometry,
- bool useIntersect )
-{
- // re-initialization
- delete mSelectionRectangleGeom;
- if ( mDatabaseStmt )
- // we must reset sqlite3 statement after recent selection - make it ready for next features selection
- sqlite3_reset( mDatabaseStmt );
-
- // store list of attributes to fetch, rectangle of area, geometry, etc.
- mSelectionRectangle = rect;
- mSelectionRectangleGeom = QgsGeometry::fromRect( rect );
- mAttributesToFetch = fetchAttributes;
-
- // set flags
- mFetchGeom = fetchGeometry;
- mSelectUseIntersect = useIntersect;
-
- if ( mSelectionRectangle.isEmpty() )
- {
- // we want to select all features from OSM data; we will use mSelectFeatsStmt
- // sqlite3 statement that is well prepared for this purpose
- mDatabaseStmt = mSelectFeatsStmt;
- return;
- }
-
- // we want to select features from specified boundary; we will use mSelectFeatsInStmt
- // sqlite3 statement that is well prepared for this purpose
- mDatabaseStmt = mSelectFeatsInStmt;
-
- if ( mFeatureType == PointType )
- {
- // binding variables (boundary) for points selection!
- sqlite3_bind_double( mDatabaseStmt, 1, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 2, mSelectionRectangle.yMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 3, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 4, mSelectionRectangle.xMaximum() );
- }
- else if ( mFeatureType == LineType )
- {
- // binding variables (boundary) for lines selection!
- sqlite3_bind_double( mDatabaseStmt, 1, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 2, mSelectionRectangle.yMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 3, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 4, mSelectionRectangle.yMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 5, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 6, mSelectionRectangle.yMaximum() );
-
- sqlite3_bind_double( mDatabaseStmt, 7, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 8, mSelectionRectangle.xMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 9, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 10, mSelectionRectangle.xMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 11, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 12, mSelectionRectangle.xMaximum() );
- }
- else // mFeatureType == PolygonType
- {
- // binding variables (boundary) for polygons selection!
- sqlite3_bind_double( mDatabaseStmt, 1, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 2, mSelectionRectangle.yMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 3, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 4, mSelectionRectangle.yMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 5, mSelectionRectangle.yMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 6, mSelectionRectangle.yMaximum() );
-
- sqlite3_bind_double( mDatabaseStmt, 7, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 8, mSelectionRectangle.xMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 9, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 10, mSelectionRectangle.xMaximum() );
- sqlite3_bind_double( mDatabaseStmt, 11, mSelectionRectangle.xMinimum() );
- sqlite3_bind_double( mDatabaseStmt, 12, mSelectionRectangle.xMaximum() );
- }
-}
-
-
int QgsOSMDataProvider::wayMemberCount( int wayId )
{
// prepare select: get count of all the WAY members
@@ -522,41 +439,54 @@
}
-bool QgsOSMDataProvider::nextFeature( QgsFeature& feature )
+QgsFeatureIterator QgsOSMDataProvider::getFeatures( QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
{
- // load next requested feature from sqlite3 database
- switch ( sqlite3_step( mDatabaseStmt ) )
+ if ( !mValid )
{
- case SQLITE_DONE: // no more features to return
- feature.setValid( false );
- return false;
+ QgsDebugMsg( "Read attempt on an invalid OSM layer" );
+ return QgsFeatureIterator();
+ }
- case SQLITE_ROW: // another feature to return
- if ( mFeatureType == PointType )
- return fetchNode( feature, mDatabaseStmt, mFetchGeom, mAttributesToFetch );
- else if ( mFeatureType == LineType )
- return fetchWay( feature, mDatabaseStmt, mFetchGeom, mAttributesToFetch );
- else if ( mFeatureType == PolygonType )
- return fetchWay( feature, mDatabaseStmt, mFetchGeom, mAttributesToFetch );
+ return QgsFeatureIterator( new QgsOSMFeatureIterator(this, fetchAttributes, rect, fetchGeometry, useIntersect) );
+}
- default:
- if ( mFeatureType == PointType )
- QgsDebugMsg( "Getting next feature of type <point> failed." );
- else if ( mFeatureType == LineType )
- QgsDebugMsg( "Getting next feature of type <line> failed." );
- else if ( mFeatureType == PolygonType )
- QgsDebugMsg( "Getting next feature of type <polygon> failed." );
- feature.setValid( false );
- return false;
+
+void QgsOSMDataProvider::select( QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+{
+ mOldApiIter = getFeatures( fetchAttributes, rect, fetchGeometry, useIntersect );
+}
+
+
+bool QgsOSMDataProvider::nextFeature( QgsFeature& feature )
+{
+ if (mOldApiIter.nextFeature(feature))
+ return true;
+ else
+ {
+ mOldApiIter.close(); // make sure to unlock the layer
+ return false;
}
}
+void QgsOSMDataProvider::rewind()
+{
+ mOldApiIter.rewind();
+}
+
bool QgsOSMDataProvider::featureAtId( int featureId,
QgsFeature& feature,
bool fetchGeometry,
QgsAttributeList fetchAttributes )
{
+ QMutexLocker locker(&mDatabaseMutex);
+
// load exact feature from sqlite3 database
if ( mFeatureType == PointType )
{
@@ -585,7 +515,7 @@
return false;
}
- fetchWay( feature, mWayStmt, fetchGeometry, fetchAttributes );
+ fetchWay( feature, mWayStmt, fetchGeometry, fetchAttributes, NULL );
// prepare statement for next call
sqlite3_reset( mWayStmt );
@@ -641,7 +571,7 @@
}
-bool QgsOSMDataProvider::fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs )
+bool QgsOSMDataProvider::fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs, QgsGeometry* intersectGeom )
{
int selId;
const char* selTimestamp;
@@ -658,7 +588,7 @@
unsigned char *pzBlob = 0;
int pnBlob = 0;
- if ( fetchGeometry || mSelectUseIntersect || !mSelectionRectangle.isEmpty() )
+ if ( fetchGeometry || intersectGeom )
{
pnBlob = sqlite3_column_bytes( stmt, 1 );
pzBlob = new unsigned char[pnBlob];
@@ -678,21 +608,22 @@
theGeometry->fromWkb(( unsigned char * ) geo, ( size_t ) geolen );
}
- if ( mSelectUseIntersect )
+ if ( intersectGeom )
{
// when using intersect, some features might be ignored if they don't intersect the selection rect
// intersect is a costly operation, use rectangle converted to geos for less conversions
// (this is usually used during identification of an object)
- if ( theGeometry->intersects( mSelectionRectangleGeom ) )
+ if ( theGeometry->intersects( intersectGeom ) )
fetchMoreRows = false;
}
- else if ( !mSelectionRectangle.isEmpty() )
+ /* this is should not be necessary, selection rectangle is used in the query
+ else if ( !selectionRectangle.isEmpty() )
{
// when using selection rectangle but without exact intersection, check only overlap of bounding box
// (usually used when drawing)
- if ( mSelectionRectangle.intersects( theGeometry->boundingBox() ) )
+ if ( selectionRectangle.intersects( theGeometry->boundingBox() ) )
fetchMoreRows = false;
- }
+ }*/
else
{
// no filter => always accept the new feature
@@ -848,6 +779,8 @@
long QgsOSMDataProvider::featureCount() const
{
+ QMutexLocker locker(&mDatabaseMutex);
+
sqlite3_stmt* countStmt;
long cnt = 0;
@@ -869,7 +802,7 @@
uint QgsOSMDataProvider::fieldCount() const
{
- return mAttributeFields.size();;
+ return mAttributeFields.size();
}
@@ -942,15 +875,7 @@
}
-void QgsOSMDataProvider::rewind()
-{
- // we have to reset precompiled database statement; thanx to this action the first feature
- // (returned by the query) will be selected again with the next calling of sqlite3_step(mDatabaseStmt)
- if ( mDatabaseStmt )
- sqlite3_reset( mDatabaseStmt );
-}
-
int QgsOSMDataProvider::freeFeatureId()
{
// todo: optimalization - wouldn't be better to keep minimum id in meta table?
Modified: branches/threading-branch/src/providers/osm/osmprovider.h
===================================================================
--- branches/threading-branch/src/providers/osm/osmprovider.h 2010-07-08 11:09:39 UTC (rev 13899)
+++ branches/threading-branch/src/providers/osm/osmprovider.h 2010-07-08 12:37:11 UTC (rev 13900)
@@ -16,8 +16,8 @@
#include <sqlite3.h>
#include <QFile>
+#include <QMutex>
-
/**
* Quantum GIS provider for OpenStreetMap data.
*/
@@ -72,9 +72,6 @@
sqlite3 *mDatabase;
//! pointer to main sqlite3 database statement object; this statement serves to select OSM data
- sqlite3_stmt *mDatabaseStmt;
-
- //! pointer to main sqlite3 database statement object; this statement serves to select OSM data
sqlite3_stmt *mSelectFeatsStmt;
//! pointer to main sqlite3 db stmt object; this stmt serves to select OSM data from some boundary
@@ -92,25 +89,15 @@
//! sqlite3 database statement for exact node selection
sqlite3_stmt *mNodeStmt;
- // variables used to select OSM data; used mainly in select(), nextFeature() functions:
//! list of supported attribute fields
QgsFieldMap mAttributeFields;
- //! which attributes should be fetched after calling of select() function
- QgsAttributeList mAttributesToFetch;
+ friend class QgsOSMFeatureIterator;
+ QgsFeatureIterator mOldApiIter;
- //! features from which area should be fetched after calling of select() function?
- QgsRectangle mSelectionRectangle;
+ mutable QMutex mDatabaseMutex;
- //! geometry object of area from which features should be fetched after calling of select() function
- QgsGeometry* mSelectionRectangleGeom;
-
- //! determines if intersect should be used while selecting OSM data
- bool mSelectUseIntersect;
-
-
-
public:
/**
@@ -151,6 +138,11 @@
*/
virtual bool nextFeature( QgsFeature& feature );
+ virtual QgsFeatureIterator getFeatures( QgsAttributeList fetchAttributes = QgsAttributeList(),
+ QgsRectangle rect = QgsRectangle(),
+ bool fetchGeometry = true,
+ bool useIntersect = false );
+
/**
* Gets the feature at the given feature ID.
* @param featureId id of the feature
@@ -356,9 +348,10 @@
* @param stmt database statement to fetch way from
* @param fetchGeometry determines if way geometry should be fetched also
* @param fetchAttrs list of attributes to be fetched with way
+ * @param intersectGeom if using exact intersection, pointer to selection rect geometry, otherwise NULL
* @return success of failure flag (true/false)
*/
- bool fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs );
+ bool fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs, QgsGeometry* intersectGeom );
/**
* Function returns string of concatenated tags of specified feature.
Added: branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.cpp
===================================================================
--- branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.cpp (rev 0)
+++ branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.cpp 2010-07-08 12:37:11 UTC (rev 13900)
@@ -0,0 +1,151 @@
+#include "qgsosmfeatureiterator.h"
+#include "osmprovider.h"
+
+#include "qgsgeometry.h"
+#include "qgslogger.h"
+
+// from provider:
+// - mFeatureType
+// - mSelectFeatsStmt, mSelectFeatsInStmt
+// - fetchNode(), fetchWay()
+
+QgsOSMFeatureIterator::QgsOSMFeatureIterator( QgsOSMDataProvider* p,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect )
+ : QgsVectorDataProviderIterator(fetchAttributes, rect, fetchGeometry, useIntersect),
+ P(p),
+ mSelectionRectangleGeom( NULL )
+{
+
+ P->mDatabaseMutex.lock();
+
+ mSelectionRectangleGeom = QgsGeometry::fromRect( rect );
+
+ if ( rect.isEmpty() )
+ {
+ // we want to select all features from OSM data; we will use mSelectFeatsStmt
+ // sqlite3 statement that is well prepared for this purpose
+ mDatabaseStmt = P->mSelectFeatsStmt;
+ return;
+ }
+
+ // we want to select features from specified boundary; we will use mSelectFeatsInStmt
+ // sqlite3 statement that is well prepared for this purpose
+ mDatabaseStmt = P->mSelectFeatsInStmt;
+
+ if ( P->mFeatureType == QgsOSMDataProvider::PointType )
+ {
+ // binding variables (boundary) for points selection!
+ sqlite3_bind_double( mDatabaseStmt, 1, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 2, rect.yMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 3, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 4, rect.xMaximum() );
+ }
+ else if ( P->mFeatureType == QgsOSMDataProvider::LineType )
+ {
+ // binding variables (boundary) for lines selection!
+ sqlite3_bind_double( mDatabaseStmt, 1, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 2, rect.yMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 3, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 4, rect.yMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 5, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 6, rect.yMaximum() );
+
+ sqlite3_bind_double( mDatabaseStmt, 7, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 8, rect.xMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 9, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 10, rect.xMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 11, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 12, rect.xMaximum() );
+ }
+ else // P->mFeatureType == QgsOSMDataProvider::PolygonType
+ {
+ // binding variables (boundary) for polygons selection!
+ sqlite3_bind_double( mDatabaseStmt, 1, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 2, rect.yMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 3, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 4, rect.yMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 5, rect.yMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 6, rect.yMaximum() );
+
+ sqlite3_bind_double( mDatabaseStmt, 7, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 8, rect.xMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 9, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 10, rect.xMaximum() );
+ sqlite3_bind_double( mDatabaseStmt, 11, rect.xMinimum() );
+ sqlite3_bind_double( mDatabaseStmt, 12, rect.xMaximum() );
+ }
+
+}
+
+QgsOSMFeatureIterator::~QgsOSMFeatureIterator()
+{
+ close();
+}
+
+bool QgsOSMFeatureIterator::nextFeature(QgsFeature& feature)
+{
+ if (mClosed)
+ return false;
+
+ // load next requested feature from sqlite3 database
+ switch ( sqlite3_step( mDatabaseStmt ) )
+ {
+ case SQLITE_DONE: // no more features to return
+ feature.setValid( false );
+ return false;
+
+ case SQLITE_ROW: // another feature to return
+ if ( P->mFeatureType == QgsOSMDataProvider::PointType )
+ return P->fetchNode( feature, mDatabaseStmt, mFetchGeometry, mFetchAttributes );
+ else if ( P->mFeatureType == QgsOSMDataProvider::LineType )
+ return P->fetchWay( feature, mDatabaseStmt, mFetchGeometry, mFetchAttributes, mSelectionRectangleGeom );
+ else if ( P->mFeatureType == QgsOSMDataProvider::PolygonType )
+ return P->fetchWay( feature, mDatabaseStmt, mFetchGeometry, mFetchAttributes, mSelectionRectangleGeom );
+
+ default:
+ if ( P->mFeatureType == QgsOSMDataProvider::PointType )
+ QgsDebugMsg( "Getting next feature of type <point> failed." );
+ else if ( P->mFeatureType == QgsOSMDataProvider::LineType )
+ QgsDebugMsg( "Getting next feature of type <line> failed." );
+ else if ( P->mFeatureType == QgsOSMDataProvider::PolygonType )
+ QgsDebugMsg( "Getting next feature of type <polygon> failed." );
+ feature.setValid( false );
+ return false;
+ }
+
+}
+
+bool QgsOSMFeatureIterator::rewind()
+{
+ if (mClosed)
+ return false;
+
+ // we have to reset precompiled database statement; thanx to this action the first feature
+ // (returned by the query) will be selected again with the next calling of sqlite3_step(mDatabaseStmt)
+ if ( mDatabaseStmt )
+ sqlite3_reset( mDatabaseStmt );
+
+ return true;
+}
+
+bool QgsOSMFeatureIterator::close()
+{
+ if (mClosed)
+ return false;
+
+ // we must reset sqlite3 statement after recent selection - make it ready for next features selection
+ if ( mDatabaseStmt )
+ sqlite3_reset( mDatabaseStmt );
+
+ // destruct selected geometry
+ delete mSelectionRectangleGeom;
+ mSelectionRectangleGeom = NULL;
+
+ P->mDatabaseMutex.unlock();
+
+ mClosed = true;
+ return true;
+}
Added: branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.h
===================================================================
--- branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.h (rev 0)
+++ branches/threading-branch/src/providers/osm/qgsosmfeatureiterator.h 2010-07-08 12:37:11 UTC (rev 13900)
@@ -0,0 +1,41 @@
+#ifndef QGSOSMFEATUREITERATOR_H
+#define QGSOSMFEATUREITERATOR_H
+
+#include "qgsvectordataprovider.h"
+
+#include <sqlite3.h>
+
+class QgsOSMDataProvider;
+
+class QgsOSMFeatureIterator : public QgsVectorDataProviderIterator
+{
+public:
+ QgsOSMFeatureIterator( QgsOSMDataProvider* p,
+ QgsAttributeList fetchAttributes,
+ QgsRectangle rect,
+ bool fetchGeometry,
+ bool useIntersect );
+
+ ~QgsOSMFeatureIterator();
+
+ //! fetch next feature, return true on success
+ virtual bool nextFeature(QgsFeature& f);
+
+ //! reset the iterator to the starting position
+ virtual bool rewind();
+
+ //! end of iterating: free the resources / lock
+ virtual bool close();
+
+protected:
+ QgsOSMDataProvider* P;
+
+ //! geometry object of area from which features should be fetched after calling of select() function
+ QgsGeometry* mSelectionRectangleGeom;
+
+ //! pointer to main sqlite3 database statement object; this statement serves to select OSM data
+ sqlite3_stmt *mDatabaseStmt;
+
+};
+
+#endif // QGSOSMFEATUREITERATOR_H
More information about the QGIS-commit
mailing list