1
/***************************************************************************
2
osmhandler.cpp - handler for parsing OSM data
5
copyright : (C) 2008 by Lukas Berka
6
***************************************************************************
8
* This program is free software; you can redistribute it and/or modify *
9
* it under the terms of the GNU General Public License as published by *
10
* the Free Software Foundation; either version 2 of the License, or *
11
* (at your option) any later version. *
13
***************************************************************************/
15
#include "osmhandler.h"
20
#include "qgslogger.h"
21
#include "qgsapplication.h"
22
#include "qgsgeometry.h"
24
#include <QtXml/QXmlSimpleReader>
25
#include <QtXml/QXmlInputSource>
26
#include <QtGui/QApplication>
27
#include <QtGui/QLabel>
28
#include <QtXml/QXmlAttributes>
29
#include <QtCore/QFile>
31
#define MAX_FEATURE_ID 99999999
32
#define COMMIT_AFTER_TAGS 300000
35
// object construction
36
OsmHandler::OsmHandler( QFile *f, sqlite3 *database )
40
mPointCnt = mLineCnt = mPolygonCnt = 0;
42
xMin = yMin = MAX_FEATURE_ID;
43
xMax = yMax = -MAX_FEATURE_ID;
44
firstWayMemberId = "";
45
mFirstMemberAppeared = 0;
47
char sqlInsertNode[] = "INSERT INTO node ( id, lat, lon, timestamp, user, usage ) VALUES (?,?,?,?,?,'0');";
48
if ( sqlite3_prepare_v2( mDatabase, sqlInsertNode, sizeof( sqlInsertNode ), &mStmtInsertNode, 0 ) != SQLITE_OK )
50
QgsDebugMsg( "failed to prepare sqlInsertNode!!!" );
53
char sqlInsertWay[] = "INSERT INTO way ( id, timestamp, user, closed ) VALUES (?,?,?,?);";
54
if ( sqlite3_prepare_v2( mDatabase, sqlInsertWay, sizeof( sqlInsertWay ), &mStmtInsertWay, 0 ) != SQLITE_OK )
56
QgsDebugMsg( "failed to prepare sqlInsertWay!!!" );
59
char sqlInsertTag[] = "INSERT INTO tag ( key, val, object_id, object_type ) VALUES (?,?,?,?);";
60
if ( sqlite3_prepare_v2( mDatabase, sqlInsertTag, sizeof( sqlInsertTag ), &mStmtInsertTag, 0 ) != SQLITE_OK )
62
QgsDebugMsg( "failed to prepare sqlInsertTag!!!" );
65
char sqlInsertWayMember[] = "INSERT INTO way_member ( way_id, pos_id, node_id ) VALUES (?,?,?);";
66
if ( sqlite3_prepare_v2( mDatabase, sqlInsertWayMember, sizeof( sqlInsertWayMember ), &mStmtInsertWayMember, 0 ) != SQLITE_OK )
68
QgsDebugMsg( "failed to prepare sqlInsertWayMember!!!" );
71
char sqlInsertRelation[] = "INSERT INTO relation ( id, timestamp, user, type ) VALUES (?,?,?,?);";
72
if ( sqlite3_prepare_v2( mDatabase, sqlInsertRelation, sizeof( sqlInsertRelation ), &mStmtInsertRelation, 0 ) != SQLITE_OK )
74
QgsDebugMsg( "failed to prepare sqlInsertRelation!!!" );
77
char sqlInsertRelationMember[] = "INSERT INTO relation_member ( relation_id, pos_id, member_id, member_type, role ) VALUES (?,?,?,?,?);";
78
if ( sqlite3_prepare_v2( mDatabase, sqlInsertRelationMember, sizeof( sqlInsertRelationMember ), &mStmtInsertRelationMember, 0 ) != SQLITE_OK )
80
QgsDebugMsg( "failed to prepare sqlInsertRelationMember!!!" );
83
char sqlInsertVersion[] = "INSERT INTO version (object_id,object_type,version_id) VALUES (?,?,?);";
84
if ( sqlite3_prepare_v2( mDatabase, sqlInsertVersion, sizeof( sqlInsertVersion ), &mStmtInsertVersion, 0 ) != SQLITE_OK )
86
QgsDebugMsg( "failed to prepare sqlInsertVersion!!!" );
90
OsmHandler::~OsmHandler()
92
sqlite3_finalize( mStmtInsertTag );
93
sqlite3_finalize( mStmtInsertNode );
94
sqlite3_finalize( mStmtInsertWay );
95
sqlite3_finalize( mStmtInsertWayMember );
96
sqlite3_finalize( mStmtInsertRelation );
97
sqlite3_finalize( mStmtInsertRelationMember );
98
sqlite3_finalize( mStmtInsertVersion );
102
bool OsmHandler::startDocument()
104
sqlite3_exec( mDatabase, "BEGIN;", 0, 0, 0 );
109
QString OsmHandler::errorString()
115
bool OsmHandler::startElement( const QString & pUri, const QString & pLocalName, const QString & pName, const QXmlAttributes & pAttrs )
117
QString name = pLocalName;
121
if ( pAttrs.value( "version" ) != "0.6" )
123
mError = "Invalid OSM version. Only files of v0.6 are supported.";
127
else if ( name == "node" )
129
//todo: test if pAttrs.value("visible").toUtf8() is "true" -> if not, node has to be ignored!
131
mObjectId = pAttrs.value( "id" );
132
mObjectType = "node";
134
double id = pAttrs.value( "id" ).toInt();
135
double lat = pAttrs.value( "lat" ).toDouble();
136
double lon = pAttrs.value( "lon" ).toDouble();
137
QString timestamp = pAttrs.value( "timestamp" );
138
QString user = pAttrs.value( "user" );
140
if ( lat < yMin ) yMin = lat;
141
if ( lat > yMax ) yMax = lat;
142
if ( lon < xMin ) xMin = lon;
143
if ( lon > xMax ) xMax = lon;
145
sqlite3_bind_int( mStmtInsertNode, 1, id );
146
sqlite3_bind_double( mStmtInsertNode, 2, lat );
147
sqlite3_bind_double( mStmtInsertNode, 3, lon );
148
sqlite3_bind_text( mStmtInsertNode, 4, timestamp.toUtf8(), -1, SQLITE_TRANSIENT ); // TODO: maybe static?
149
sqlite3_bind_text( mStmtInsertNode, 5, user.toUtf8(), -1, SQLITE_TRANSIENT ); // TODO: maybe static?
151
if ( sqlite3_step( mStmtInsertNode ) != SQLITE_DONE )
153
QgsDebugMsg( "Storing node information into database failed." );
157
sqlite3_reset( mStmtInsertNode ); // make ready for next insert
159
// store version number of this object
160
sqlite3_bind_text( mStmtInsertVersion, 1, pAttrs.value( "id" ).toUtf8(), -1, SQLITE_TRANSIENT );
161
sqlite3_bind_text( mStmtInsertVersion, 2, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT );
162
sqlite3_bind_text( mStmtInsertVersion, 3, pAttrs.value( "version" ).toUtf8(), -1, SQLITE_TRANSIENT );
164
if ( sqlite3_step( mStmtInsertVersion ) != SQLITE_DONE )
166
QgsDebugMsg( "Storing version information into database failed." );
169
sqlite3_reset( mStmtInsertVersion ); // make ready for next insert
171
// increase node counter
174
else if ( name == "way" )
176
mObjectId = pAttrs.value( "id" );
179
mFirstMemberAppeared = 0;
181
//todo: test if pAttrs.value("visible").toUtf8() is "true" -> if not, way has to be ignored!
183
sqlite3_bind_text( mStmtInsertWay, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT );
184
sqlite3_bind_text( mStmtInsertWay, 2, pAttrs.value( "timestamp" ).toUtf8(), -1, SQLITE_TRANSIENT );
185
sqlite3_bind_text( mStmtInsertWay, 3, pAttrs.value( "user" ).toUtf8(), -1, SQLITE_TRANSIENT );
187
// store version number of this object
188
sqlite3_bind_text( mStmtInsertVersion, 1, pAttrs.value( "id" ).toUtf8(), -1, SQLITE_TRANSIENT );
189
sqlite3_bind_text( mStmtInsertVersion, 2, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT );
190
sqlite3_bind_text( mStmtInsertVersion, 3, pAttrs.value( "version" ).toUtf8(), -1, SQLITE_TRANSIENT );
192
if ( sqlite3_step( mStmtInsertVersion ) != SQLITE_DONE )
194
QgsDebugMsg( "Storing version information into database failed." );
197
sqlite3_reset( mStmtInsertVersion ); // make ready for next insert
199
else if ( name == "nd" )
201
// store id of the first and last way member to be able to decide if the way is closed (polygon) or not
202
if ( firstWayMemberId == "" )
204
firstWayMemberId = pAttrs.value( "ref" );
206
lastWayMemberId = pAttrs.value( "ref" );
208
if ( firstWayMemberId == lastWayMemberId )
209
mFirstMemberAppeared++;
211
if (( firstWayMemberId != lastWayMemberId ) || ( mFirstMemberAppeared < 2 ) )
213
sqlite3_bind_text( mStmtInsertWayMember, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT ); // TODO: maybe static?
214
sqlite3_bind_int( mStmtInsertWayMember, 2, mPosId );
215
sqlite3_bind_text( mStmtInsertWayMember, 3, pAttrs.value( "ref" ).toUtf8(), -1, SQLITE_TRANSIENT );
217
if ( sqlite3_step( mStmtInsertWayMember ) != SQLITE_DONE )
219
QgsDebugMsg( "Storing way-node relationship into database failed." );
222
sqlite3_reset( mStmtInsertWayMember );
226
else if ( name == "relation" )
228
mObjectId = pAttrs.value( "id" );
230
mObjectType = "relation";
233
//todo: test if pAttrs.value("visible").toUtf8() is "true" -> if not, relation has to be ignored!
235
sqlite3_bind_text( mStmtInsertRelation, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT );
236
sqlite3_bind_text( mStmtInsertRelation, 2, pAttrs.value( "timestamp" ).toUtf8(), -1, SQLITE_TRANSIENT );
237
sqlite3_bind_text( mStmtInsertRelation, 3, pAttrs.value( "user" ).toUtf8(), -1, SQLITE_TRANSIENT );
239
// store version number of this object
240
sqlite3_bind_text( mStmtInsertVersion, 1, pAttrs.value( "id" ).toUtf8(), -1, SQLITE_TRANSIENT );
241
sqlite3_bind_text( mStmtInsertVersion, 2, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT );
242
sqlite3_bind_text( mStmtInsertVersion, 3, pAttrs.value( "version" ).toUtf8(), -1, SQLITE_TRANSIENT );
244
if ( sqlite3_step( mStmtInsertVersion ) != SQLITE_DONE )
246
QgsDebugMsg( "Storing version information into database failed." );
249
sqlite3_reset( mStmtInsertVersion ); // make ready for next insert
251
else if ( name == "member" )
253
sqlite3_bind_text( mStmtInsertRelationMember, 1, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT );
254
sqlite3_bind_int( mStmtInsertRelationMember, 2, mPosId );
255
sqlite3_bind_text( mStmtInsertRelationMember, 3, pAttrs.value( "ref" ).toUtf8(), -1, SQLITE_TRANSIENT );
256
sqlite3_bind_text( mStmtInsertRelationMember, 4, pAttrs.value( "type" ).toUtf8(), -1, SQLITE_TRANSIENT );
257
sqlite3_bind_text( mStmtInsertRelationMember, 5, pAttrs.value( "role" ).toUtf8(), -1, SQLITE_TRANSIENT );
259
if ( sqlite3_step( mStmtInsertRelationMember ) != SQLITE_DONE )
261
QgsDebugMsg( "Storing relation-feature relationship into database failed." );
265
sqlite3_reset( mStmtInsertRelationMember );
268
else if ( name == "tag" )
270
if ( mCnt == COMMIT_AFTER_TAGS )
272
sqlite3_exec( mDatabase, "COMMIT;", 0, 0, 0 );
273
sqlite3_exec( mDatabase, "BEGIN;", 0, 0, 0 );
278
sqlite3_bind_text( mStmtInsertTag, 1, pAttrs.value( "k" ).toUtf8(), -1, SQLITE_TRANSIENT );
279
sqlite3_bind_text( mStmtInsertTag, 2, pAttrs.value( "v" ).toUtf8(), -1, SQLITE_TRANSIENT );
280
sqlite3_bind_text( mStmtInsertTag, 3, mObjectId.toUtf8(), -1, SQLITE_TRANSIENT );
281
sqlite3_bind_text( mStmtInsertTag, 4, mObjectType.toUtf8(), -1, SQLITE_TRANSIENT );
283
// we've got node parameters -> let's create new database record
284
if ( sqlite3_step( mStmtInsertTag ) != SQLITE_DONE )
286
QgsDebugMsg( QString( "Storing tag into database failed. K:%1, V:%2." ).arg( pAttrs.value( "k" ) ).arg( pAttrs.value( "v" ) ) );
289
sqlite3_reset( mStmtInsertTag );
291
// if we are under xml tag <relation> and we reach xml tag <tag k="type" v="...">, lets insert prepared relation into DB
292
if (( mObjectType == "relation" ) && ( pAttrs.value( "k" ) == "type" ) )
294
mRelationType = pAttrs.value( "v" );
297
else if ( name == "bounds" )
299
// e.g. <bounds minlat="41.388625" minlon="2.15426" maxlat="41.391732" maxlon="2.158192"/>
301
// xMin = pAttrs.value("minlon").toDouble();
302
// xMax = pAttrs.value("maxlon").toDouble();
303
// yMin = pAttrs.value("minlat").toDouble();
304
// yMax = pAttrs.value("maxlat").toDouble();
310
bool OsmHandler::endElement( const QString & pURI, const QString & pLocalName, const QString & pName )
312
QString name = pLocalName;
315
int isPolygon = false;
316
int cntMembers = mPosId - 1;
318
if ( firstWayMemberId == lastWayMemberId )
321
// test if polygon is correct; it should have >2 member points
322
if (( isPolygon ) && ( cntMembers < 4 ) )
324
sqlite3_reset( mStmtInsertWay );
328
// test if way is correct; it should have more then 1 member point
329
if ( cntMembers < 2 )
331
sqlite3_reset( mStmtInsertWay );
335
// we should bind the last information needed for way insertion -> if the way is closed (polygon) or not
336
sqlite3_bind_int( mStmtInsertWay, 4, ( isPolygon ? 1 : 0 ) );
338
// well, insert new way
339
if ( sqlite3_step( mStmtInsertWay ) != SQLITE_DONE )
341
QgsDebugMsg( "Storing way information into database failed." );
345
// make statement ready for next insert
346
sqlite3_reset( mStmtInsertWay );
353
// make variables ready for next way parsing
354
firstWayMemberId = "";
356
else if ( name == "relation" )
358
sqlite3_bind_text( mStmtInsertRelation, 4, mRelationType.toUtf8(), -1, SQLITE_TRANSIENT );
360
if ( sqlite3_step( mStmtInsertRelation ) != SQLITE_DONE )
362
QgsDebugMsg( QString( "Storing relation into database failed." ) );
365
sqlite3_reset( mStmtInsertRelation );
371
bool OsmHandler::endDocument()
373
// first commit all database actions connected to xml parsing
374
sqlite3_exec( mDatabase, "COMMIT;", 0, 0, 0 );