mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
OSM provider ported to new API
This commit is contained in:
parent
b16c68ecd8
commit
600baca9a4
@ -323,7 +323,6 @@ class OsmDatabaseManager:
|
||||
lay=self.pointLayers[self.currentKey]
|
||||
lay.select([],area,True,True)
|
||||
result=lay.nextFeature(feat)
|
||||
lay.dataProvider().rewind()
|
||||
|
||||
if result:
|
||||
return (feat,'Point')
|
||||
@ -332,7 +331,6 @@ class OsmDatabaseManager:
|
||||
lay=self.lineLayers[self.currentKey]
|
||||
lay.select([],area,True,True)
|
||||
result=lay.nextFeature(feat)
|
||||
lay.dataProvider().rewind()
|
||||
|
||||
if result:
|
||||
# line vertices
|
||||
@ -341,7 +339,7 @@ class OsmDatabaseManager:
|
||||
,{"minLat":area.yMinimum(),"maxLat":area.yMaximum(),"minLon":area.xMinimum(),"maxLon":area.xMaximum(),"lineId":str(feat.id())})
|
||||
|
||||
for rec in c:
|
||||
feat2=QgsFeature(rec[0],"Point")
|
||||
feat2=QgsFeature(rec[0])
|
||||
feat2.setGeometry(QgsGeometry.fromPoint(QgsPoint(rec[2],rec[1])))
|
||||
# without features' attributes here! we don't need them...
|
||||
c.close()
|
||||
@ -354,7 +352,6 @@ class OsmDatabaseManager:
|
||||
lay=self.polygonLayers[self.currentKey]
|
||||
lay.select([],area,True,True)
|
||||
result=lay.nextFeature(feat)
|
||||
lay.dataProvider().rewind()
|
||||
|
||||
if result:
|
||||
# polygon vertices
|
||||
@ -363,7 +360,7 @@ class OsmDatabaseManager:
|
||||
,{"minLat":area.yMinimum(),"maxLat":area.yMaximum(),"minLon":area.xMinimum(),"maxLon":area.xMaximum(),"polygonId":str(feat.id())})
|
||||
|
||||
for rec in c:
|
||||
feat2=QgsFeature(rec[0],"Point")
|
||||
feat2=QgsFeature(rec[0])
|
||||
feat2.setGeometry(QgsGeometry.fromPoint(QgsPoint(rec[2],rec[1])))
|
||||
# without features' attributes here! we don't need them...
|
||||
c.close()
|
||||
@ -416,7 +413,7 @@ class OsmDatabaseManager:
|
||||
,{"minLat":area.yMinimum(),"maxLat":area.yMaximum(),"minLon":area.xMinimum(),"maxLon":area.xMaximum(),"lineId":str(feat.id())})
|
||||
|
||||
for rec in c:
|
||||
feat2=QgsFeature(rec[0],"Point")
|
||||
feat2=QgsFeature(rec[0])
|
||||
feat2.setGeometry(QgsGeometry.fromPoint(QgsPoint(rec[2],rec[1])))
|
||||
# without features' attributes here! we don't need them...
|
||||
featMap[feat2.id()]=feat2
|
||||
@ -439,7 +436,7 @@ class OsmDatabaseManager:
|
||||
,{"minLat":area.yMinimum(),"maxLat":area.yMaximum(),"minLon":area.xMinimum(),"maxLon":area.xMaximum(),"polygonId":str(feat.id())})
|
||||
|
||||
for rec in c:
|
||||
feat2=QgsFeature(rec[0],"Point")
|
||||
feat2=QgsFeature(rec[0])
|
||||
feat2.setGeometry(QgsGeometry.fromPoint(QgsPoint(rec[2],rec[1])))
|
||||
# without features' attributes here! we don't need them...
|
||||
featMap[feat2.id()]=feat2
|
||||
@ -471,7 +468,7 @@ class OsmDatabaseManager:
|
||||
nodeId=self.__getFreeFeatureId()
|
||||
|
||||
affected=set()
|
||||
feat=QgsFeature(nodeId,"Point")
|
||||
feat=QgsFeature(nodeId)
|
||||
feat.setGeometry(QgsGeometry.fromPoint(QgsPoint(mapPoint.x(),mapPoint.y())))
|
||||
|
||||
# should snapping be done? if not, everything's easy
|
||||
@ -612,7 +609,7 @@ class OsmDatabaseManager:
|
||||
|
||||
# finishing...
|
||||
c.close()
|
||||
feat=QgsFeature(lineId,"Line")
|
||||
feat=QgsFeature(lineId)
|
||||
feat.setGeometry(QgsGeometry.fromPolyline(pline))
|
||||
|
||||
if doCommit:
|
||||
@ -691,7 +688,7 @@ class OsmDatabaseManager:
|
||||
|
||||
# finish
|
||||
c.close()
|
||||
feat=QgsFeature(polygonId,"Polygon")
|
||||
feat=QgsFeature(polygonId)
|
||||
polygon=[]
|
||||
polygon.append(pline)
|
||||
feat.setGeometry(QgsGeometry.fromPolygon(polygon))
|
||||
|
@ -6,7 +6,7 @@ ADD_SUBDIRECTORY(memory)
|
||||
ADD_SUBDIRECTORY(ogr)
|
||||
ADD_SUBDIRECTORY(wms)
|
||||
ADD_SUBDIRECTORY(delimitedtext)
|
||||
#ADD_SUBDIRECTORY(osm) # TODO: enable when migrated to new api
|
||||
ADD_SUBDIRECTORY(osm)
|
||||
#ADD_SUBDIRECTORY(sqlanywhere) # TODO: enable when migrated to new api
|
||||
ADD_SUBDIRECTORY(gdal)
|
||||
#ADD_SUBDIRECTORY(mssql) # TODO: enable when migrated to new api
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Files
|
||||
|
||||
SET(OSM_SRCS
|
||||
osmfeatureiterator.cpp
|
||||
osmhandler.cpp
|
||||
osmprovider.cpp
|
||||
osmrenderer.cpp
|
||||
|
472
src/providers/osm/osmfeatureiterator.cpp
Normal file
472
src/providers/osm/osmfeatureiterator.cpp
Normal file
@ -0,0 +1,472 @@
|
||||
#include "osmfeatureiterator.h"
|
||||
|
||||
#include "osmprovider.h"
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
QgsOSMFeatureIterator::QgsOSMFeatureIterator( QgsOSMDataProvider* p, const QgsFeatureRequest& request )
|
||||
: QgsAbstractFeatureIterator( request ), P( p )
|
||||
, mRectGeom(0)
|
||||
{
|
||||
// make sure that only one iterator is active
|
||||
if ( P->mActiveIterator )
|
||||
P->mActiveIterator->close();
|
||||
P->mActiveIterator = this;
|
||||
|
||||
|
||||
bool hasFilterFid = mRequest.filterType() == QgsFeatureRequest::FilterFid;
|
||||
bool hasFilterRect = mRequest.filterType() == QgsFeatureRequest::FilterRect;
|
||||
QgsRectangle rect = mRequest.filterRect();
|
||||
mRectGeom = QgsGeometry::fromRect( rect );
|
||||
|
||||
|
||||
if ( P->mFeatureType == QgsOSMDataProvider::PointType )
|
||||
{
|
||||
const char* sqlSelectNode = "SELECT id, lat, lon, timestamp, user FROM node WHERE id=? AND usage=0 AND status<>'R' AND u=1";
|
||||
const char* sqlSelectPoints = "SELECT id, lat, lon, timestamp, user FROM node WHERE usage=0 AND status<>'R' AND u=1";
|
||||
const char* sqlSelectPointsIn = "SELECT id, lat, lon, timestamp, user FROM node WHERE usage=0 AND status<>'R' AND u=1 "
|
||||
"AND lat>=? AND lat<=? AND lon>=? AND lon<=?";
|
||||
|
||||
const char* sql = hasFilterFid ? sqlSelectNode : (hasFilterRect ? sqlSelectPointsIn : sqlSelectPoints);
|
||||
|
||||
if ( sqlite3_prepare_v2( P->mDatabase, sql, -1, &mSelectStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for points retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( hasFilterFid )
|
||||
{
|
||||
sqlite3_bind_int64( mSelectStmt, 1, mRequest.filterFid() );
|
||||
}
|
||||
else if ( hasFilterRect )
|
||||
{
|
||||
// binding variables (boundary) for points selection!
|
||||
sqlite3_bind_double( mSelectStmt, 1, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 2, rect.yMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 3, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 4, rect.xMaximum() );
|
||||
}
|
||||
}
|
||||
else if ( P->mFeatureType == QgsOSMDataProvider::LineType )
|
||||
{
|
||||
const char* sqlSelectWay = "SELECT id, wkb, timestamp, user FROM way WHERE id=? AND status<>'R' AND u=1";
|
||||
const char* sqlSelectLines = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=0 AND w.status<>'R' AND w.u=1";
|
||||
const char* sqlSelectLinesIn = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=0 AND w.status<>'R' AND w.u=1 "
|
||||
"AND (((w.max_lat between ? AND ?) OR (w.min_lat between ? AND ?) OR (w.min_lat<? AND w.max_lat>?)) "
|
||||
"AND ((w.max_lon between ? AND ?) OR (w.min_lon between ? AND ?) OR (w.min_lon<? AND w.max_lon>?)))";
|
||||
const char* sql = hasFilterFid ? sqlSelectWay : ( hasFilterRect ? sqlSelectLinesIn : sqlSelectLines );
|
||||
|
||||
if ( sqlite3_prepare_v2( P->mDatabase, sql, -1, &mSelectStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for lines retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( hasFilterFid )
|
||||
{
|
||||
sqlite3_bind_int64( mSelectStmt, 1, mRequest.filterFid() );
|
||||
}
|
||||
else if ( hasFilterRect )
|
||||
{
|
||||
// binding variables (boundary) for lines selection!
|
||||
sqlite3_bind_double( mSelectStmt, 1, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 2, rect.yMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 3, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 4, rect.yMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 5, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 6, rect.yMaximum() );
|
||||
|
||||
sqlite3_bind_double( mSelectStmt, 7, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 8, rect.xMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 9, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 10, rect.xMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 11, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 12, rect.xMaximum() );
|
||||
}
|
||||
}
|
||||
else // mFeatureType == PolygonType
|
||||
{
|
||||
const char* sqlSelectWay = "SELECT id, wkb, timestamp, user FROM way WHERE id=? AND status<>'R' AND u=1";
|
||||
const char* sqlSelectPolys = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=1 AND w.status<>'R' AND w.u=1";
|
||||
const char* sqlSelectPolysIn = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=1 AND w.status<>'R' AND w.u=1 "
|
||||
"AND (((w.max_lat between ? AND ?) OR (w.min_lat between ? AND ?) OR (w.min_lat<? AND w.max_lat>?)) "
|
||||
"AND ((w.max_lon between ? AND ?) OR (w.min_lon between ? AND ?) OR (w.min_lon<? AND w.max_lon>?)))";
|
||||
const char* sql = hasFilterFid ? sqlSelectWay : ( hasFilterRect ? sqlSelectPolysIn : sqlSelectPolys );
|
||||
|
||||
if ( sqlite3_prepare_v2( P->mDatabase, sql, -1, &mSelectStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for polygons retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( hasFilterFid )
|
||||
{
|
||||
sqlite3_bind_int64( mSelectStmt, 1, mRequest.filterFid() );
|
||||
}
|
||||
else if ( hasFilterRect )
|
||||
{
|
||||
// binding variables (boundary) for polygons selection!
|
||||
sqlite3_bind_double( mSelectStmt, 1, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 2, rect.yMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 3, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 4, rect.yMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 5, rect.yMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 6, rect.yMaximum() );
|
||||
|
||||
sqlite3_bind_double( mSelectStmt, 7, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 8, rect.xMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 9, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 10, rect.xMaximum() );
|
||||
sqlite3_bind_double( mSelectStmt, 11, rect.xMinimum() );
|
||||
sqlite3_bind_double( mSelectStmt, 12, rect.xMaximum() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// prepare statement for tag retrieval
|
||||
const char* sqlSelectTags = "SELECT key, val FROM tag WHERE object_id=? AND object_type=?";
|
||||
int rc = sqlite3_prepare_v2( P->mDatabase, sqlSelectTags, -1, &mTagsStmt, 0 );
|
||||
if ( rc != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for feature tags selection - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
const char* sqlSelectTagValue = "SELECT val FROM tag WHERE object_id=? AND object_type=? AND key=?";
|
||||
rc = sqlite3_prepare_v2( P->mDatabase, sqlSelectTagValue, -1, &mCustomTagsStmt, 0 );
|
||||
if ( rc != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for tag value selection - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
QgsOSMFeatureIterator::~QgsOSMFeatureIterator()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool QgsOSMFeatureIterator::nextFeature( QgsFeature& feature )
|
||||
{
|
||||
if ( mClosed )
|
||||
return false;
|
||||
|
||||
// load next requested feature from sqlite3 database
|
||||
switch ( sqlite3_step( mSelectStmt ) )
|
||||
{
|
||||
case SQLITE_DONE: // no more features to return
|
||||
feature.setValid( false );
|
||||
close();
|
||||
return false;
|
||||
|
||||
case SQLITE_ROW: // another feature to return
|
||||
if ( P->mFeatureType == QgsOSMDataProvider::PointType )
|
||||
return fetchNode( feature );
|
||||
else if ( P->mFeatureType == QgsOSMDataProvider::LineType )
|
||||
return fetchWay( feature );
|
||||
else if ( P->mFeatureType == QgsOSMDataProvider::PolygonType )
|
||||
return fetchWay( feature );
|
||||
}
|
||||
|
||||
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 );
|
||||
close();
|
||||
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(mStmt)
|
||||
if ( mSelectStmt )
|
||||
sqlite3_reset( mSelectStmt );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsOSMFeatureIterator::close()
|
||||
{
|
||||
if ( mClosed )
|
||||
return false;
|
||||
|
||||
// destruct selected geometry
|
||||
delete mRectGeom;
|
||||
mRectGeom = 0;
|
||||
|
||||
sqlite3_finalize( mSelectStmt );
|
||||
|
||||
// finalize all created sqlite3 statements
|
||||
sqlite3_finalize( mTagsStmt );
|
||||
sqlite3_finalize( mCustomTagsStmt );
|
||||
|
||||
// tell provider that this iterator is not active anymore
|
||||
P->mActiveIterator = 0;
|
||||
|
||||
mClosed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool QgsOSMFeatureIterator::fetchNode( QgsFeature& feature )
|
||||
{
|
||||
sqlite3_stmt* stmt = mSelectStmt;
|
||||
bool fetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
|
||||
|
||||
int selId = sqlite3_column_int( stmt, 0 );
|
||||
double selLat = sqlite3_column_double( stmt, 1 );
|
||||
double selLon = sqlite3_column_double( stmt, 2 );
|
||||
|
||||
feature.setFeatureId( selId );
|
||||
feature.setValid( true );
|
||||
feature.initAttributes( P->mAttributeFields.count() );
|
||||
feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups
|
||||
|
||||
// fetch feature's geometry
|
||||
if ( fetchGeometry )
|
||||
{
|
||||
char* geo = new char[21];
|
||||
memset( geo, 0, 21 );
|
||||
geo[0] = QgsApplication::endian();
|
||||
geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint;
|
||||
memcpy( geo + 5, &selLon, sizeof( double ) );
|
||||
memcpy( geo + 13, &selLat, sizeof( double ) );
|
||||
feature.setGeometryAndOwnership(( unsigned char * )geo, 24 ); // 24 is size of wkb point structure!
|
||||
}
|
||||
|
||||
// fetch attributes
|
||||
fetchAttributes( feature, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QgsOSMFeatureIterator::fetchWay( QgsFeature& feature )
|
||||
{
|
||||
sqlite3_stmt* stmt = mSelectStmt;
|
||||
bool fetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
|
||||
bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect;
|
||||
|
||||
int selId;
|
||||
QgsGeometry *theGeometry = NULL;
|
||||
bool fetchMoreRows = true;
|
||||
int rc = -1;
|
||||
|
||||
do
|
||||
{
|
||||
selId = sqlite3_column_int( stmt, 0 );
|
||||
unsigned char *pzBlob = 0;
|
||||
int pnBlob = 0;
|
||||
|
||||
if ( fetchGeometry || useIntersect || mRequest.filterType() == QgsFeatureRequest::FilterRect )
|
||||
{
|
||||
pnBlob = sqlite3_column_bytes( stmt, 1 );
|
||||
pzBlob = new unsigned char[pnBlob];
|
||||
memcpy( pzBlob, sqlite3_column_blob( stmt, 1 ), pnBlob );
|
||||
|
||||
// create geometry
|
||||
theGeometry = new QgsGeometry();
|
||||
theGeometry->fromWkb(( unsigned char * ) pzBlob, pnBlob );
|
||||
}
|
||||
|
||||
if ( theGeometry && ( theGeometry->type() == 3 ) && ( selId != 0 ) )
|
||||
{
|
||||
// line/polygon geometry is not cached!
|
||||
char *geo;
|
||||
int geolen;
|
||||
P->updateWayWKB( selId, ( P->mFeatureType == QgsOSMDataProvider::LineType ) ? 0 : 1, &geo, &geolen );
|
||||
theGeometry->fromWkb(( unsigned char * ) geo, ( size_t ) geolen );
|
||||
}
|
||||
|
||||
if ( mRequest.filterType() == QgsFeatureRequest::FilterRect )
|
||||
{
|
||||
if ( useIntersect )
|
||||
{
|
||||
// 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( mRectGeom ) )
|
||||
fetchMoreRows = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// when using selection rectangle but without exact intersection, check only overlap of bounding box
|
||||
// (usually used when drawing)
|
||||
if ( mRequest.filterRect().intersects( theGeometry->boundingBox() ) )
|
||||
fetchMoreRows = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no filter => always accept the new feature
|
||||
// (used in attribute table)
|
||||
fetchMoreRows = false;
|
||||
}
|
||||
|
||||
// delete the geometry (if any) in case we're not going to use it anyway
|
||||
if ( fetchMoreRows )
|
||||
delete theGeometry;
|
||||
}
|
||||
while ( fetchMoreRows && (( rc = sqlite3_step( stmt ) ) == SQLITE_ROW ) );
|
||||
|
||||
// no more features to return
|
||||
if ( rc == SQLITE_DONE )
|
||||
{
|
||||
sqlite3_exec( P->mDatabase, "COMMIT;", 0, 0, 0 );
|
||||
feature.setValid( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
// fetch feature's geometry
|
||||
if ( fetchGeometry )
|
||||
{
|
||||
feature.setGeometry( theGeometry );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete theGeometry; // make sure it's deleted
|
||||
}
|
||||
|
||||
feature.setFeatureId( selId );
|
||||
feature.setValid( true );
|
||||
|
||||
// fetch attributes
|
||||
fetchAttributes( feature, false );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void QgsOSMFeatureIterator::fetchAttributes( QgsFeature& feature, bool isNode )
|
||||
{
|
||||
feature.initAttributes( P->mAttributeFields.count() );
|
||||
feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups
|
||||
|
||||
// node
|
||||
const char* selTimestamp = ( const char* ) sqlite3_column_text( mSelectStmt, isNode ? 3 : 2 );
|
||||
const char* selUser = ( const char* ) sqlite3_column_text( mSelectStmt, isNode ? 4 : 3 );
|
||||
int selId = sqlite3_column_int( mSelectStmt, 0 );
|
||||
|
||||
// TODO[MD]: subset of attributes
|
||||
|
||||
//QgsAttributeList::const_iterator iter;
|
||||
//for ( iter = fetchAttrs.begin(); iter != fetchAttrs.end(); ++iter )
|
||||
for ( int i = 0; i < P->mAttributeFields.count(); ++i )
|
||||
{
|
||||
switch ( i )
|
||||
{
|
||||
case QgsOSMDataProvider::TimestampAttr:
|
||||
feature.setAttribute( QgsOSMDataProvider::TimestampAttr, QString::fromUtf8( selTimestamp ) );
|
||||
break;
|
||||
case QgsOSMDataProvider::UserAttr:
|
||||
feature.setAttribute( QgsOSMDataProvider::UserAttr, QString::fromUtf8( selUser ) );
|
||||
break;
|
||||
case QgsOSMDataProvider::TagAttr:
|
||||
feature.setAttribute( QgsOSMDataProvider::TagAttr, tagsForObject( isNode, selId ) );
|
||||
break;
|
||||
default: // suppose it's a custom tag
|
||||
if ( i >= QgsOSMDataProvider::CustomTagAttr && i < QgsOSMDataProvider::CustomTagAttr + P->mCustomTagsList.count() )
|
||||
{
|
||||
feature.setAttribute( i, tagForObject( isNode, selId, P->mCustomTagsList[i - QgsOSMDataProvider::CustomTagAttr] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString QgsOSMFeatureIterator::tagForObject( bool isNode, int id, QString tagKey )
|
||||
{
|
||||
sqlite3_bind_int( mCustomTagsStmt, 1, id );
|
||||
sqlite3_bind_text( mCustomTagsStmt, 2, isNode ? "node" : "way", -1, 0 );
|
||||
QByteArray tag = tagKey.toUtf8(); // must keep the byte array until the query is run
|
||||
sqlite3_bind_text( mCustomTagsStmt, 3, tag.data(), -1, 0 );
|
||||
|
||||
QString value;
|
||||
int rc;
|
||||
|
||||
if (( rc = sqlite3_step( mCustomTagsStmt ) ) == SQLITE_ROW )
|
||||
{
|
||||
const char* tagVal = ( const char* ) sqlite3_column_text( mCustomTagsStmt, 0 );
|
||||
value = QString::fromUtf8( tagVal );
|
||||
}
|
||||
else
|
||||
{
|
||||
// tag wasn't found
|
||||
sqlite3_reset( mCustomTagsStmt ); // make ready for next retrieval
|
||||
return "";
|
||||
}
|
||||
|
||||
sqlite3_reset( mCustomTagsStmt ); // make ready for next retrieval
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString QgsOSMFeatureIterator::tagsForObject( bool isNode, int id )
|
||||
{
|
||||
sqlite3_bind_int( mTagsStmt, 1, id );
|
||||
sqlite3_bind_text( mTagsStmt, 2, isNode ? "node" : "way", -1, 0 );
|
||||
|
||||
QString tags;
|
||||
int rc;
|
||||
|
||||
while (( rc = sqlite3_step( mTagsStmt ) ) == SQLITE_ROW )
|
||||
{
|
||||
const char* tagKey = ( const char* ) sqlite3_column_text( mTagsStmt, 0 );
|
||||
const char* tagVal = ( const char* ) sqlite3_column_text( mTagsStmt, 1 );
|
||||
QString key = QString::fromUtf8( tagKey );
|
||||
QString val = QString::fromUtf8( tagVal );
|
||||
|
||||
// we concatenate tags this way: "key1"="val1","key2"="val2","key3"="val3"
|
||||
// -all ; in keyX and valX are replaced by ;;
|
||||
// -all , in keyX and valX are replaced by ;
|
||||
// -all - in keyX and valX are replaced by --
|
||||
// -all = in keyX and valX are replaced by -
|
||||
key = key.replace( ';', ";;" );
|
||||
val = val.replace( ';', ";;" );
|
||||
key = key.replace( ',', ";" );
|
||||
val = val.replace( ',', ";" );
|
||||
|
||||
key = key.replace( '-', "--" );
|
||||
val = val.replace( '-', "--" );
|
||||
key = key.replace( '=', "-" );
|
||||
val = val.replace( '=', "-" );
|
||||
|
||||
if ( tags.count() > 0 )
|
||||
tags += ",";
|
||||
|
||||
tags += QString( "\"%1\"=\"%2\"" ).arg( key ).arg( val );
|
||||
}
|
||||
|
||||
if ( rc != SQLITE_DONE )
|
||||
{
|
||||
// no tags for object
|
||||
//QgsDebugMsg(QString("tags for object failed: type %1 id %2").arg(type).arg(id));
|
||||
}
|
||||
|
||||
sqlite3_reset( mTagsStmt ); // make ready for next retrieval
|
||||
return tags;
|
||||
}
|
87
src/providers/osm/osmfeatureiterator.h
Normal file
87
src/providers/osm/osmfeatureiterator.h
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef OSMFEATUREITERATOR_H
|
||||
#define OSMFEATUREITERATOR_H
|
||||
|
||||
#include "qgsfeatureiterator.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
|
||||
class QgsOSMDataProvider;
|
||||
|
||||
class QgsOSMFeatureIterator : public QgsAbstractFeatureIterator
|
||||
{
|
||||
public:
|
||||
QgsOSMFeatureIterator( QgsOSMDataProvider* p, const QgsFeatureRequest& request );
|
||||
|
||||
~QgsOSMFeatureIterator();
|
||||
|
||||
//! fetch next feature, return true on success
|
||||
virtual bool nextFeature( QgsFeature& feature );
|
||||
|
||||
//! reset the iterator to the starting position
|
||||
virtual bool rewind();
|
||||
|
||||
//! end of iterating: free the resources / lock
|
||||
virtual bool close();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Function fetches one node from current sqlite3 statement.
|
||||
* @param feature output; feature representing fetched node
|
||||
* @return success of failure flag (true/false)
|
||||
*/
|
||||
bool fetchNode( QgsFeature& feature );
|
||||
|
||||
/**
|
||||
* Function fetches one way from current sqlite3 statement.
|
||||
* @param feature output; feature representing fetched way
|
||||
* @return success of failure flag (true/false)
|
||||
*/
|
||||
bool fetchWay( QgsFeature& feature );
|
||||
|
||||
|
||||
/**
|
||||
* Function returns string of concatenated tags of specified feature.
|
||||
* @param isNode true for node, false for way
|
||||
* @param id feature identifier
|
||||
* @return string of tags concatenation
|
||||
*/
|
||||
QString tagsForObject( bool isNode, int id );
|
||||
|
||||
/**
|
||||
* Function returns one tag value of specified feature and specified key.
|
||||
* @param isNode true for node, false for way
|
||||
* @param id feature identifier
|
||||
* @param tagKey tag key
|
||||
* @return tag value
|
||||
*/
|
||||
QString tagForObject( bool isNode, int id, QString tagKey );
|
||||
|
||||
/**
|
||||
* Add attributes to the feature from the current row
|
||||
* @param feature
|
||||
* @param isNode true for node, false for way
|
||||
*/
|
||||
void fetchAttributes( QgsFeature& feature, bool isNode );
|
||||
|
||||
protected:
|
||||
QgsOSMDataProvider* P;
|
||||
|
||||
//! sqlite3 database statement for selection
|
||||
sqlite3_stmt *mSelectStmt;
|
||||
|
||||
//! sqlite3 database statement ready to select all feature tags
|
||||
sqlite3_stmt *mTagsStmt;
|
||||
|
||||
//! sqlite3 database statement ready to select concrete feature tag
|
||||
sqlite3_stmt *mCustomTagsStmt;
|
||||
|
||||
//! geometry for exact intersection test
|
||||
QgsGeometry* mRectGeom;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // OSMFEATUREITERATOR_H
|
@ -15,6 +15,7 @@
|
||||
#include "osmprovider.h"
|
||||
#include "osmhandler.h"
|
||||
#include "osmrenderer.h"
|
||||
#include "osmfeatureiterator.h"
|
||||
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfield.h"
|
||||
@ -40,24 +41,19 @@ const char* QgsOSMDataProvider::attr[] = { "timestamp", "user", "tags" };
|
||||
|
||||
QgsOSMDataProvider::QgsOSMDataProvider( QString uri )
|
||||
: QgsVectorDataProvider( uri )
|
||||
, mActiveIterator( 0 )
|
||||
{
|
||||
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
|
||||
|
||||
// set default boundaries
|
||||
xMin = -DEFAULT_EXTENT;
|
||||
xMax = DEFAULT_EXTENT;
|
||||
yMin = -DEFAULT_EXTENT;
|
||||
yMax = DEFAULT_EXTENT;
|
||||
mExtent = QgsRectangle( -DEFAULT_EXTENT, -DEFAULT_EXTENT, DEFAULT_EXTENT, DEFAULT_EXTENT );
|
||||
|
||||
// get the filename and other parameters from the URI
|
||||
int fileNameEnd = uri.indexOf( '?' );
|
||||
@ -137,14 +133,14 @@ QgsOSMDataProvider::QgsOSMDataProvider( QString uri )
|
||||
}
|
||||
|
||||
// set up attributes depending on the feature type - same attributes for both point and way type so far
|
||||
mAttributeFields[TimestampAttr] = QgsField( attr[TimestampAttr], QVariant::String, "string" );
|
||||
mAttributeFields[UserAttr] = QgsField( attr[UserAttr], QVariant::String, "string" );
|
||||
mAttributeFields[TagAttr] = QgsField( attr[TagAttr], QVariant::String, "string" );
|
||||
mAttributeFields.append( QgsField( attr[TimestampAttr], QVariant::String, "string" ) );
|
||||
mAttributeFields.append( QgsField( attr[UserAttr], QVariant::String, "string" ) );
|
||||
mAttributeFields.append( QgsField( attr[TagAttr], QVariant::String, "string" ) );
|
||||
|
||||
// add custom attributes - these were chosen by user through OSM plugin
|
||||
for ( int tagId = 0; tagId < mCustomTagsList.count(); ++tagId )
|
||||
{
|
||||
mAttributeFields[CustomTagAttr+tagId] = QgsField( mCustomTagsList[tagId], QVariant::String, "string" );
|
||||
mAttributeFields.append( QgsField( mCustomTagsList[tagId], QVariant::String, "string" ) );
|
||||
}
|
||||
|
||||
// get source file name and database file name
|
||||
@ -226,10 +222,10 @@ QgsOSMDataProvider::QgsOSMDataProvider( QString uri )
|
||||
QStringList parts = boundaries.split( QChar( ':' ) );
|
||||
if ( parts.count() == 4 )
|
||||
{
|
||||
xMin = parts[0].toDouble();
|
||||
yMin = parts[1].toDouble();
|
||||
xMax = parts[2].toDouble();
|
||||
yMax = parts[3].toDouble();
|
||||
mExtent.setXMinimum( parts[0].toDouble() );
|
||||
mExtent.setYMinimum( parts[1].toDouble() );
|
||||
mExtent.setXMaximum( parts[2].toDouble() );
|
||||
mExtent.setYMaximum( parts[3].toDouble() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -243,94 +239,6 @@ QgsOSMDataProvider::QgsOSMDataProvider( QString uri )
|
||||
}
|
||||
|
||||
|
||||
// prepare statement for tag retrieval
|
||||
char sqlSelectTags[] = "SELECT key, val FROM tag WHERE object_id=? AND object_type=?";
|
||||
int rc = sqlite3_prepare_v2( mDatabase, sqlSelectTags, sizeof( sqlSelectTags ), &mTagsStmt, 0 );
|
||||
if ( rc != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for feature tags selection - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
char sqlSelectTagValue[] = "SELECT val FROM tag WHERE object_id=? AND object_type=? AND key=?";
|
||||
rc = sqlite3_prepare_v2( mDatabase, sqlSelectTagValue, sizeof( sqlSelectTagValue ), &mCustomTagsStmt, 0 );
|
||||
if ( rc != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for tag value selection - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
// prepare statements for feature retrieval
|
||||
char sqlSelectWay[] = "SELECT id, wkb, timestamp, user FROM way WHERE id=? AND status<>'R' AND u=1";
|
||||
rc = sqlite3_prepare_v2( mDatabase, sqlSelectWay, sizeof( sqlSelectWay ), &mWayStmt, 0 );
|
||||
if ( rc != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for way retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
char sqlSelectNode[] = "SELECT id, lat, lon, timestamp, user FROM node WHERE id=? AND usage=0 AND status<>'R' AND u=1";
|
||||
rc = sqlite3_prepare_v2( mDatabase, sqlSelectNode, sizeof( sqlSelectNode ), &mNodeStmt, 0 );
|
||||
if ( rc != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for node retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( mFeatureType == PointType )
|
||||
{
|
||||
char sqlSelectPoints[] = "SELECT id, lat, lon, timestamp, user FROM node WHERE usage=0 AND status<>'R' AND u=1";
|
||||
char sqlSelectPointsIn[] = "SELECT id, lat, lon, timestamp, user FROM node WHERE usage=0 AND status<>'R' AND u=1 \
|
||||
AND lat>=? AND lat<=? AND lon>=? AND lon<=?";
|
||||
|
||||
if ( sqlite3_prepare_v2( mDatabase, sqlSelectPoints, sizeof( sqlSelectPoints ), &mSelectFeatsStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for points retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
if ( sqlite3_prepare_v2( mDatabase, sqlSelectPointsIn, sizeof( sqlSelectPointsIn ), &mSelectFeatsInStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for points in boundary retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( mFeatureType == LineType )
|
||||
{
|
||||
char sqlSelectLines[] = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=0 AND w.status<>'R' AND w.u=1";
|
||||
char sqlSelectLinesIn[] = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=0 AND w.status<>'R' AND w.u=1 \
|
||||
AND (((w.max_lat between ? AND ?) OR (w.min_lat between ? AND ?) OR (w.min_lat<? AND w.max_lat>?)) \
|
||||
AND ((w.max_lon between ? AND ?) OR (w.min_lon between ? AND ?) OR (w.min_lon<? AND w.max_lon>?)))";
|
||||
|
||||
if ( sqlite3_prepare_v2( mDatabase, sqlSelectLines, sizeof( sqlSelectLines ), &mSelectFeatsStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for lines retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
if ( sqlite3_prepare_v2( mDatabase, sqlSelectLinesIn, sizeof( sqlSelectLinesIn ), &mSelectFeatsInStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for lines in boundary retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else // mFeatureType == PolygonType
|
||||
{
|
||||
char sqlSelectPolys[] = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=1 AND w.status<>'R' AND w.u=1";
|
||||
char sqlSelectPolysIn[] = "SELECT w.id, w.wkb, w.timestamp, w.user FROM way w WHERE w.closed=1 AND w.status<>'R' AND w.u=1 \
|
||||
AND (((w.max_lat between ? AND ?) OR (w.min_lat between ? AND ?) OR (w.min_lat<? AND w.max_lat>?)) \
|
||||
AND ((w.max_lon between ? AND ?) OR (w.min_lon between ? AND ?) OR (w.min_lon<? AND w.max_lon>?)))";
|
||||
|
||||
if ( sqlite3_prepare_v2( mDatabase, sqlSelectPolys, sizeof( sqlSelectPolys ), &mSelectFeatsStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for polygons retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
if ( sqlite3_prepare_v2( mDatabase, sqlSelectPolysIn, sizeof( sqlSelectPolysIn ), &mSelectFeatsInStmt, 0 ) != SQLITE_OK )
|
||||
{
|
||||
QgsDebugMsg( "sqlite3 statement for polygons in boundary retrieval - prepare failed." );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// finally OSM provider is initialized and considered to be valid!
|
||||
mValid = true;
|
||||
}
|
||||
@ -338,16 +246,8 @@ QgsOSMDataProvider::QgsOSMDataProvider( QString uri )
|
||||
|
||||
QgsOSMDataProvider::~QgsOSMDataProvider()
|
||||
{
|
||||
// destruct selected geometry
|
||||
delete mSelectionRectangleGeom;
|
||||
|
||||
// finalize all created sqlite3 statements
|
||||
sqlite3_finalize( mTagsStmt );
|
||||
sqlite3_finalize( mCustomTagsStmt );
|
||||
sqlite3_finalize( mWayStmt );
|
||||
sqlite3_finalize( mNodeStmt );
|
||||
sqlite3_finalize( mSelectFeatsStmt );
|
||||
sqlite3_finalize( mSelectFeatsInStmt );
|
||||
if ( mActiveIterator )
|
||||
mActiveIterator->close();
|
||||
|
||||
// close opened sqlite3 database
|
||||
if ( mDatabase )
|
||||
@ -422,82 +322,6 @@ QString QgsOSMDataProvider::storageType() const
|
||||
}
|
||||
|
||||
|
||||
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 )
|
||||
{
|
||||
@ -530,322 +354,9 @@ int QgsOSMDataProvider::wayMemberCount( int wayId )
|
||||
}
|
||||
|
||||
|
||||
bool QgsOSMDataProvider::nextFeature( QgsFeature& feature )
|
||||
{
|
||||
// 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 ( 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 );
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool QgsOSMDataProvider::featureAtId( QgsFeatureId featureId,
|
||||
QgsFeature& feature,
|
||||
bool fetchGeometry,
|
||||
QgsAttributeList fetchAttributes )
|
||||
{
|
||||
// load exact feature from sqlite3 database
|
||||
if ( mFeatureType == PointType )
|
||||
{
|
||||
sqlite3_bind_int64( mNodeStmt, 1, featureId );
|
||||
|
||||
if ( sqlite3_step( mNodeStmt ) != SQLITE_ROW )
|
||||
{
|
||||
QgsDebugMsg( QString( "Getting information about point with id=%1 failed." ).arg( featureId ) );
|
||||
sqlite3_reset( mNodeStmt );
|
||||
return false;
|
||||
}
|
||||
|
||||
fetchNode( feature, mNodeStmt, fetchGeometry, fetchAttributes );
|
||||
|
||||
// prepare statement for next call
|
||||
sqlite3_reset( mNodeStmt );
|
||||
}
|
||||
else if (( mFeatureType == LineType ) || ( mFeatureType == PolygonType ) )
|
||||
{
|
||||
sqlite3_bind_int64( mWayStmt, 1, featureId );
|
||||
|
||||
if ( sqlite3_step( mWayStmt ) != SQLITE_ROW )
|
||||
{
|
||||
QgsDebugMsg( QString( "Getting information about way with id=%1 failed." ).arg( featureId ) );
|
||||
sqlite3_reset( mWayStmt );
|
||||
return false;
|
||||
}
|
||||
|
||||
fetchWay( feature, mWayStmt, fetchGeometry, fetchAttributes );
|
||||
|
||||
// prepare statement for next call
|
||||
sqlite3_reset( mWayStmt );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QgsOSMDataProvider::fetchNode( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs )
|
||||
{
|
||||
int selId = sqlite3_column_int( stmt, 0 );
|
||||
double selLat = sqlite3_column_double( stmt, 1 );
|
||||
double selLon = sqlite3_column_double( stmt, 2 );
|
||||
const char* selTimestamp = ( const char* ) sqlite3_column_text( stmt, 3 );
|
||||
const char* selUser = ( const char* ) sqlite3_column_text( stmt, 4 );
|
||||
|
||||
// fetch feature's geometry
|
||||
if ( fetchGeometry )
|
||||
{
|
||||
char* geo = new char[21];
|
||||
memset( geo, 0, 21 );
|
||||
geo[0] = QgsApplication::endian();
|
||||
geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint;
|
||||
memcpy( geo + 5, &selLon, sizeof( double ) );
|
||||
memcpy( geo + 13, &selLat, sizeof( double ) );
|
||||
feature.setGeometryAndOwnership(( unsigned char * )geo, 24 ); // 24 is size of wkb point structure!
|
||||
}
|
||||
|
||||
// fetch attributes
|
||||
QgsAttributeList::const_iterator iter;
|
||||
for ( iter = fetchAttrs.begin(); iter != fetchAttrs.end(); ++iter )
|
||||
{
|
||||
switch ( *iter )
|
||||
{
|
||||
case TimestampAttr:
|
||||
feature.addAttribute( TimestampAttr, QString::fromUtf8( selTimestamp ) ); break;
|
||||
case UserAttr:
|
||||
feature.addAttribute( UserAttr, QString::fromUtf8( selUser ) ); break;
|
||||
case TagAttr:
|
||||
feature.addAttribute( TagAttr, tagsForObject( "node", selId ) ); break;
|
||||
|
||||
default: // suppose it's a custom tag
|
||||
if ( *iter >= CustomTagAttr && *iter < CustomTagAttr + mCustomTagsList.count() )
|
||||
{
|
||||
feature.addAttribute( *iter, tagForObject( "node", selId, mCustomTagsList[*iter-CustomTagAttr] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
feature.setFeatureId( selId );
|
||||
feature.setValid( true );
|
||||
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool QgsOSMDataProvider::fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs )
|
||||
{
|
||||
int selId;
|
||||
const char* selTimestamp;
|
||||
const char* selUser;
|
||||
QgsGeometry *theGeometry = NULL;
|
||||
bool fetchMoreRows = true;
|
||||
int rc = -1;
|
||||
|
||||
do
|
||||
{
|
||||
selId = sqlite3_column_int( stmt, 0 );
|
||||
selTimestamp = ( const char* ) sqlite3_column_text( stmt, 2 );
|
||||
selUser = ( const char* ) sqlite3_column_text( stmt, 3 );
|
||||
unsigned char *pzBlob = 0;
|
||||
int pnBlob = 0;
|
||||
|
||||
if ( fetchGeometry || mSelectUseIntersect || !mSelectionRectangle.isEmpty() )
|
||||
{
|
||||
pnBlob = sqlite3_column_bytes( stmt, 1 );
|
||||
pzBlob = new unsigned char[pnBlob];
|
||||
memcpy( pzBlob, sqlite3_column_blob( stmt, 1 ), pnBlob );
|
||||
|
||||
// create geometry
|
||||
theGeometry = new QgsGeometry();
|
||||
theGeometry->fromWkb(( unsigned char * ) pzBlob, pnBlob );
|
||||
}
|
||||
|
||||
if ( theGeometry && ( theGeometry->type() == 3 ) && ( selId != 0 ) )
|
||||
{
|
||||
// line/polygon geometry is not cached!
|
||||
char *geo;
|
||||
int geolen;
|
||||
updateWayWKB( selId, ( mFeatureType == LineType ) ? 0 : 1, &geo, &geolen );
|
||||
theGeometry->fromWkb(( unsigned char * ) geo, ( size_t ) geolen );
|
||||
}
|
||||
|
||||
if ( mSelectUseIntersect )
|
||||
{
|
||||
// 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 ) )
|
||||
fetchMoreRows = false;
|
||||
}
|
||||
else if ( !mSelectionRectangle.isEmpty() )
|
||||
{
|
||||
// when using selection rectangle but without exact intersection, check only overlap of bounding box
|
||||
// (usually used when drawing)
|
||||
if ( mSelectionRectangle.intersects( theGeometry->boundingBox() ) )
|
||||
fetchMoreRows = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no filter => always accept the new feature
|
||||
// (used in attribute table)
|
||||
fetchMoreRows = false;
|
||||
}
|
||||
|
||||
// delete the geometry (if any) in case we're not going to use it anyway
|
||||
if ( fetchMoreRows )
|
||||
delete theGeometry;
|
||||
}
|
||||
while ( fetchMoreRows && (( rc = sqlite3_step( stmt ) ) == SQLITE_ROW ) );
|
||||
|
||||
// no more features to return
|
||||
if ( rc == SQLITE_DONE )
|
||||
{
|
||||
sqlite3_exec( mDatabase, "COMMIT;", 0, 0, 0 );
|
||||
feature.setValid( false );
|
||||
return false;
|
||||
}
|
||||
|
||||
// fetch feature's geometry
|
||||
if ( fetchGeometry )
|
||||
{
|
||||
feature.setGeometry( theGeometry );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete theGeometry; // make sure it's deleted
|
||||
}
|
||||
|
||||
// fetch attributes
|
||||
QgsAttributeList::const_iterator iter;
|
||||
for ( iter = fetchAttrs.begin(); iter != fetchAttrs.end(); ++iter )
|
||||
{
|
||||
switch ( *iter )
|
||||
{
|
||||
case TimestampAttr:
|
||||
feature.addAttribute( TimestampAttr, QString::fromUtf8( selTimestamp ) );
|
||||
break;
|
||||
case UserAttr:
|
||||
feature.addAttribute( UserAttr, QString::fromUtf8( selUser ) );
|
||||
break;
|
||||
case TagAttr:
|
||||
feature.addAttribute( TagAttr, tagsForObject( "way", selId ) );
|
||||
break;
|
||||
default: // suppose it's a custom tag
|
||||
if ( *iter >= CustomTagAttr && *iter < CustomTagAttr + mCustomTagsList.count() )
|
||||
{
|
||||
feature.addAttribute( *iter, tagForObject( "way", selId, mCustomTagsList[*iter-CustomTagAttr] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
feature.setFeatureId( selId );
|
||||
feature.setValid( true );
|
||||
feature.setFieldMap( &mAttributeFields ); // allow name-based attribute lookups
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QString QgsOSMDataProvider::tagForObject( const char* type, int id, QString tagKey )
|
||||
{
|
||||
sqlite3_bind_int( mCustomTagsStmt, 1, id );
|
||||
sqlite3_bind_text( mCustomTagsStmt, 2, type, -1, 0 );
|
||||
QByteArray tag = tagKey.toUtf8(); // must keep the byte array until the query is run
|
||||
sqlite3_bind_text( mCustomTagsStmt, 3, tag.data(), -1, 0 );
|
||||
|
||||
QString value;
|
||||
int rc;
|
||||
|
||||
if (( rc = sqlite3_step( mCustomTagsStmt ) ) == SQLITE_ROW )
|
||||
{
|
||||
const char* tagVal = ( const char* ) sqlite3_column_text( mCustomTagsStmt, 0 );
|
||||
value = QString::fromUtf8( tagVal );
|
||||
}
|
||||
else
|
||||
{
|
||||
// tag wasn't found
|
||||
sqlite3_reset( mCustomTagsStmt ); // make ready for next retrieval
|
||||
return "";
|
||||
}
|
||||
|
||||
sqlite3_reset( mCustomTagsStmt ); // make ready for next retrieval
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
QString QgsOSMDataProvider::tagsForObject( const char* type, int id )
|
||||
{
|
||||
sqlite3_bind_int( mTagsStmt, 1, id );
|
||||
sqlite3_bind_text( mTagsStmt, 2, type, -1, 0 );
|
||||
|
||||
QString tags;
|
||||
int rc;
|
||||
|
||||
while (( rc = sqlite3_step( mTagsStmt ) ) == SQLITE_ROW )
|
||||
{
|
||||
const char* tagKey = ( const char* ) sqlite3_column_text( mTagsStmt, 0 );
|
||||
const char* tagVal = ( const char* ) sqlite3_column_text( mTagsStmt, 1 );
|
||||
QString key = QString::fromUtf8( tagKey );
|
||||
QString val = QString::fromUtf8( tagVal );
|
||||
|
||||
// we concatenate tags this way: "key1"="val1","key2"="val2","key3"="val3"
|
||||
// -all ; in keyX and valX are replaced by ;;
|
||||
// -all , in keyX and valX are replaced by ;
|
||||
// -all - in keyX and valX are replaced by --
|
||||
// -all = in keyX and valX are replaced by -
|
||||
key = key.replace( ';', ";;" );
|
||||
val = val.replace( ';', ";;" );
|
||||
key = key.replace( ',', ";" );
|
||||
val = val.replace( ',', ";" );
|
||||
|
||||
key = key.replace( '-', "--" );
|
||||
val = val.replace( '-', "--" );
|
||||
key = key.replace( '=', "-" );
|
||||
val = val.replace( '=', "-" );
|
||||
|
||||
if ( tags.count() > 0 )
|
||||
tags += ",";
|
||||
|
||||
tags += QString( "\"%1\"=\"%2\"" ).arg( key ).arg( val );
|
||||
}
|
||||
|
||||
if ( rc != SQLITE_DONE )
|
||||
{
|
||||
// no tags for object
|
||||
//QgsDebugMsg(QString("tags for object failed: type %1 id %2").arg(type).arg(id));
|
||||
}
|
||||
|
||||
sqlite3_reset( mTagsStmt ); // make ready for next retrieval
|
||||
return tags;
|
||||
}
|
||||
|
||||
|
||||
QgsRectangle QgsOSMDataProvider::extent()
|
||||
{
|
||||
return QgsRectangle( xMin, yMin, xMax, yMax );
|
||||
return mExtent;
|
||||
}
|
||||
|
||||
|
||||
@ -883,6 +394,12 @@ long QgsOSMDataProvider::featureCount() const
|
||||
}
|
||||
|
||||
|
||||
QgsFeatureIterator QgsOSMDataProvider::getFeatures( const QgsFeatureRequest& request )
|
||||
{
|
||||
return QgsFeatureIterator( new QgsOSMFeatureIterator( this, request ) );
|
||||
}
|
||||
|
||||
|
||||
bool QgsOSMDataProvider::isValid()
|
||||
{
|
||||
return mValid;
|
||||
@ -940,7 +457,7 @@ QGISEXTERN bool isProvider()
|
||||
}
|
||||
|
||||
|
||||
const QgsFieldMap & QgsOSMDataProvider::fields() const
|
||||
const QgsFields & QgsOSMDataProvider::fields() const
|
||||
{
|
||||
return mAttributeFields;
|
||||
}
|
||||
@ -952,15 +469,6 @@ QgsCoordinateReferenceSystem QgsOSMDataProvider::crs()
|
||||
}
|
||||
|
||||
|
||||
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?
|
||||
@ -1395,14 +903,13 @@ bool QgsOSMDataProvider::loadOsmFile( QString osm_filename )
|
||||
}
|
||||
|
||||
// store information got with handler into provider member variables
|
||||
xMin = handler->xMin; // boundaries defining the area of all features
|
||||
xMax = handler->xMax;
|
||||
yMin = handler->yMin;
|
||||
yMax = handler->yMax;
|
||||
// boundaries defining the area of all features
|
||||
mExtent = QgsRectangle( handler->xMin, handler->yMin, handler->xMax, handler->yMax );
|
||||
|
||||
// storing boundary information into database
|
||||
QString cmd3 = QString( "INSERT INTO meta ( key, val ) VALUES ('default-area-boundaries','%1:%2:%3:%4');" )
|
||||
.arg( xMin, 0, 'f', 10 ).arg( yMin, 0, 'f', 10 ).arg( xMax, 0, 'f', 10 ).arg( yMax, 0, 'f', 10 );
|
||||
.arg( mExtent.xMinimum(), 0, 'f', 10 ).arg( mExtent.yMinimum(), 0, 'f', 10 )
|
||||
.arg( mExtent.xMaximum(), 0, 'f', 10 ).arg( mExtent.yMaximum(), 0, 'f', 10 );
|
||||
QByteArray cmd_bytes3 = cmd3.toAscii();
|
||||
const char *ptr3 = cmd_bytes3.data();
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
#ifndef OSMPROVIDER_H
|
||||
#define OSMPROVIDER_H
|
||||
|
||||
/***************************************************************************
|
||||
osmprovider.h - provider for OSM; stores OSM data in sqlite3 DB
|
||||
------------------
|
||||
@ -19,6 +22,8 @@
|
||||
|
||||
class QgsVectorLayer;
|
||||
|
||||
class QgsOSMFeatureIterator;
|
||||
|
||||
/**
|
||||
* Quantum GIS provider for OpenStreetMap data.
|
||||
*/
|
||||
@ -29,7 +34,8 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
private:
|
||||
|
||||
//! provider manages features with one of three geometry types; variable determines feature type of this provider
|
||||
enum { PointType, LineType, PolygonType } mFeatureType;
|
||||
enum OSMType { PointType, LineType, PolygonType };
|
||||
OSMType mFeatureType;
|
||||
|
||||
//! supported feature attributes
|
||||
enum Attribute { TimestampAttr = 0, UserAttr = 1, TagAttr, CustomTagAttr };
|
||||
@ -53,7 +59,7 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
QObject* mInitObserver;
|
||||
|
||||
//! boundary of all OSM data that provider manages
|
||||
double xMin, xMax, yMin, yMax;
|
||||
QgsRectangle mExtent;
|
||||
|
||||
//! list of feature tags for which feature attributes are created
|
||||
QStringList mCustomTagsList;
|
||||
@ -72,44 +78,11 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
//! pointer to sqlite3 database that keeps OSM data
|
||||
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
|
||||
sqlite3_stmt *mSelectFeatsInStmt;
|
||||
|
||||
//! sqlite3 database statement ready to select all feature tags
|
||||
sqlite3_stmt *mTagsStmt;
|
||||
|
||||
//! sqlite3 database statement ready to select concrete feature tag
|
||||
sqlite3_stmt *mCustomTagsStmt;
|
||||
|
||||
//! sqlite3 database statement for exact way selection
|
||||
sqlite3_stmt *mWayStmt;
|
||||
|
||||
//! 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;
|
||||
|
||||
//! features from which area should be fetched after calling of select() function?
|
||||
QgsRectangle mSelectionRectangle;
|
||||
|
||||
//! 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;
|
||||
QgsFields mAttributeFields;
|
||||
|
||||
friend class QgsOSMFeatureIterator;
|
||||
QgsOSMFeatureIterator* mActiveIterator; //!< pointer to currently active iterator (0 if none)
|
||||
|
||||
|
||||
public:
|
||||
@ -133,38 +106,6 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
*/
|
||||
virtual QString storageType() const;
|
||||
|
||||
/** Select features based on a bounding rectangle. Features can be retrieved with calls to getNextFeature.
|
||||
* @param fetchAttributes list of attributes which should be fetched
|
||||
* @param rect spatial filter
|
||||
* @param fetchGeometry true if the feature geometry should be fetched
|
||||
* @param useIntersect true if an accurate intersection test should be used,
|
||||
* false if a test based on bounding box is sufficient
|
||||
*/
|
||||
virtual void select( QgsAttributeList fetchAttributes = QgsAttributeList(),
|
||||
QgsRectangle rect = QgsRectangle(),
|
||||
bool fetchGeometry = true,
|
||||
bool useIntersect = false );
|
||||
|
||||
/**
|
||||
* Get the next feature resulting from a select operation.
|
||||
* @param feature feature which will receive data from the provider
|
||||
* @return true when there was a feature to fetch, false when end was hit
|
||||
*/
|
||||
virtual bool nextFeature( QgsFeature& feature );
|
||||
|
||||
/**
|
||||
* Gets the feature at the given feature ID.
|
||||
* @param featureId id of the feature
|
||||
* @param feature feature which will receive the data
|
||||
* @param fetchGeometry if true, geometry will be fetched from the provider
|
||||
* @param fetchAttributes a list containing the indexes of the attribute fields to copy
|
||||
* @return True when feature was found, otherwise false
|
||||
*/
|
||||
virtual bool featureAtId( QgsFeatureId featureId,
|
||||
QgsFeature& feature,
|
||||
bool fetchGeometry = true,
|
||||
QgsAttributeList fetchAttributes = QgsAttributeList() );
|
||||
|
||||
/**
|
||||
* Get feature type.
|
||||
* @return int representing the feature type
|
||||
@ -181,12 +122,7 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
* Return a map of indexes with field names for this layer
|
||||
* @return map of fields
|
||||
*/
|
||||
virtual const QgsFieldMap & fields() const;
|
||||
|
||||
/**
|
||||
* Restart reading features from previous select operation.
|
||||
*/
|
||||
virtual void rewind();
|
||||
virtual const QgsFields & fields() const;
|
||||
|
||||
/**
|
||||
* Returns a bitmask containing the supported capabilities
|
||||
@ -196,6 +132,8 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
*/
|
||||
virtual int capabilities() const;
|
||||
|
||||
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request );
|
||||
|
||||
|
||||
// Implementation of QgsDataProvider functions
|
||||
|
||||
@ -330,42 +268,6 @@ class QgsOSMDataProvider: public QgsVectorDataProvider
|
||||
* @return number of way members
|
||||
*/
|
||||
int wayMemberCount( int wayId );
|
||||
|
||||
/**
|
||||
* Function fetches one node from current sqlite3 statement.
|
||||
* @param feature output; feature representing fetched node
|
||||
* @param stmt database statement to fetch node from
|
||||
* @param fetchGeometry determines if node geometry should be fetched also
|
||||
* @param fetchAttrs list of attributes to be fetched with node
|
||||
* @return success of failure flag (true/false)
|
||||
*/
|
||||
bool fetchNode( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs );
|
||||
|
||||
/**
|
||||
* Function fetches one way from current sqlite3 statement.
|
||||
* @param feature output; feature representing fetched way
|
||||
* @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
|
||||
* @return success of failure flag (true/false)
|
||||
*/
|
||||
bool fetchWay( QgsFeature& feature, sqlite3_stmt* stmt, bool fetchGeometry, QgsAttributeList& fetchAttrs );
|
||||
|
||||
/**
|
||||
* Function returns string of concatenated tags of specified feature.
|
||||
* @param type type of feature (one of "node","way","relation")
|
||||
* @param id feature identifier
|
||||
* @return string of tags concatenation
|
||||
*/
|
||||
QString tagsForObject( const char* type, int id );
|
||||
|
||||
/**
|
||||
* Function returns one tag value of specified feature and specified key.
|
||||
* @param type type of feature (one of "node","way","relation")
|
||||
* @param id feature identifier
|
||||
* @param tagKey tag key
|
||||
* @return tag value
|
||||
*/
|
||||
QString tagForObject( const char* type, int id, QString tagKey );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user