| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| #ifndef OSMDATABASE_H | ||
| #define OSMDATABASE_H | ||
|
|
||
| #include <QString> | ||
| #include <QStringList> | ||
|
|
||
| #include "qgsosmbase.h" | ||
|
|
||
| #include "qgsgeometry.h" | ||
|
|
||
| class QgsOSMNodeIterator; | ||
| class QgsOSMWayIterator; | ||
|
|
||
| typedef QPair<QString, int> QgsOSMTagCountPair; | ||
|
|
||
| /** | ||
| * Class that encapsulates access to OpenStreetMap data stored in a database | ||
| * previously imported from XML file. | ||
| */ | ||
| class ANALYSIS_EXPORT QgsOSMDatabase | ||
| { | ||
| public: | ||
| explicit QgsOSMDatabase( const QString& dbFileName = QString() ); | ||
| ~QgsOSMDatabase(); | ||
|
|
||
| void setFileName( const QString& dbFileName ) { mDbFileName = dbFileName; } | ||
| QString filename() const { return mDbFileName; } | ||
| bool isOpen() const; | ||
|
|
||
| bool open(); | ||
| bool close(); | ||
|
|
||
| QString errorString() const { return mError; } | ||
|
|
||
| // data access | ||
|
|
||
| int countNodes() const; | ||
| int countWays() const; | ||
|
|
||
| QgsOSMNodeIterator listNodes() const; | ||
| QgsOSMWayIterator listWays() const; | ||
|
|
||
| QgsOSMNode node( QgsOSMId id ) const; | ||
| QgsOSMWay way( QgsOSMId id ) const; | ||
| //OSMRelation relation( OSMId id ) const; | ||
|
|
||
| QgsOSMTags tags( bool way, QgsOSMId id ) const; | ||
|
|
||
| QList<QgsOSMTagCountPair> usedTags( bool ways ) const; | ||
|
|
||
| QgsPolyline wayPoints( QgsOSMId id ) const; | ||
|
|
||
| // export to spatialite | ||
|
|
||
| enum ExportType { Point, Polyline, Polygon }; | ||
| bool exportSpatiaLite( ExportType type, const QString& tableName, const QStringList& tagKeys = QStringList() ); | ||
|
|
||
| protected: | ||
| bool prepareStatements(); | ||
| int runCountStatement( const char* sql ) const; | ||
| void deleteStatement( sqlite3_stmt*& stmt ); | ||
|
|
||
| void exportSpatiaLiteNodes( const QString& tableName, const QStringList& tagKeys ); | ||
| void exportSpatiaLiteWays( bool closed, const QString& tableName, const QStringList& tagKeys ); | ||
| bool createSpatialTable( const QString& tableName, const QString& geometryType, const QStringList& tagKeys ); | ||
| bool createSpatialIndex( const QString& tableName ); | ||
|
|
||
| QString quotedIdentifier( QString id ); | ||
| QString quotedValue( QString value ); | ||
|
|
||
| private: | ||
| //! database file name | ||
| QString mDbFileName; | ||
|
|
||
| QString mError; | ||
|
|
||
| //! pointer to sqlite3 database that keeps OSM data | ||
| sqlite3* mDatabase; | ||
|
|
||
| sqlite3_stmt* mStmtNode; | ||
| sqlite3_stmt* mStmtNodeTags; | ||
| sqlite3_stmt* mStmtWay; | ||
| sqlite3_stmt* mStmtWayNode; | ||
| sqlite3_stmt* mStmtWayNodePoints; | ||
| sqlite3_stmt* mStmtWayTags; | ||
| }; | ||
|
|
||
|
|
||
| /** Encapsulate iteration over table of nodes */ | ||
| class ANALYSIS_EXPORT QgsOSMNodeIterator | ||
| { | ||
| public: | ||
| ~QgsOSMNodeIterator(); | ||
|
|
||
| QgsOSMNode next(); | ||
| void close(); | ||
|
|
||
| protected: | ||
| QgsOSMNodeIterator( sqlite3* handle ); | ||
|
|
||
| sqlite3_stmt* mStmt; | ||
|
|
||
| friend class QgsOSMDatabase; | ||
| }; | ||
|
|
||
|
|
||
|
|
||
| /** Encapsulate iteration over table of ways */ | ||
| class ANALYSIS_EXPORT QgsOSMWayIterator | ||
| { | ||
| public: | ||
| ~QgsOSMWayIterator(); | ||
|
|
||
| QgsOSMWay next(); | ||
| void close(); | ||
|
|
||
| protected: | ||
| QgsOSMWayIterator( sqlite3* handle ); | ||
|
|
||
| sqlite3_stmt* mStmt; | ||
|
|
||
| friend class QgsOSMDatabase; | ||
| }; | ||
|
|
||
|
|
||
|
|
||
| #endif // OSMDATABASE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| #include "qgsosmdownload.h" | ||
|
|
||
| #include <QNetworkAccessManager> | ||
| #include <QNetworkRequest> | ||
| #include <QNetworkReply> | ||
|
|
||
| #include "qgsnetworkaccessmanager.h" | ||
| #include "qgsrectangle.h" | ||
|
|
||
|
|
||
| QString QgsOSMDownload::defaultServiceUrl() | ||
| { | ||
| return "http://overpass-api.de/api/interpreter"; | ||
| } | ||
|
|
||
|
|
||
| QString QgsOSMDownload::queryFromRect( const QgsRectangle& rect ) | ||
| { | ||
| return QString( "(node(%1,%2,%3,%4);<;);out;" ).arg( rect.yMinimum() ).arg( rect.xMinimum() ) | ||
| .arg( rect.yMaximum() ).arg( rect.xMaximum() ); | ||
| } | ||
|
|
||
|
|
||
| QgsOSMDownload::QgsOSMDownload() | ||
| : mServiceUrl( defaultServiceUrl() ), mReply( 0 ) | ||
| { | ||
| } | ||
|
|
||
| QgsOSMDownload::~QgsOSMDownload() | ||
| { | ||
| if ( mReply ) | ||
| { | ||
| mReply->abort(); | ||
| mReply->deleteLater(); | ||
| mReply = 0; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| bool QgsOSMDownload::start() | ||
| { | ||
| mError.clear(); | ||
|
|
||
| if ( mQuery.isEmpty() ) | ||
| { | ||
| mError = tr( "No query has been specified." ); | ||
| return false; | ||
| } | ||
|
|
||
| if ( mReply ) | ||
| { | ||
| mError = tr( "There is already a pending request for data." ); | ||
| return false; | ||
| } | ||
|
|
||
| if ( !mFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) | ||
| { | ||
| mError = tr( "Cannot open output file: %1" ).arg( mFile.fileName() ); | ||
| return false; | ||
| } | ||
|
|
||
| QgsNetworkAccessManager* nwam = QgsNetworkAccessManager::instance(); | ||
|
|
||
| QUrl url( mServiceUrl ); | ||
| url.addQueryItem( "data", mQuery ); | ||
|
|
||
| QNetworkRequest request( url ); | ||
| request.setRawHeader( "User-Agent", "QGIS" ); | ||
|
|
||
| mReply = nwam->get( request ); | ||
|
|
||
| connect( mReply, SIGNAL( readyRead() ), this, SLOT( onReadyRead() ) ); | ||
| connect( mReply, SIGNAL( error( QNetworkReply::NetworkError ) ), this, SLOT( onError( QNetworkReply::NetworkError ) ) ); | ||
| connect( mReply, SIGNAL( finished() ), this, SLOT( onFinished() ) ); | ||
| connect( mReply, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SIGNAL( downloadProgress( qint64, qint64 ) ) ); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
||
| bool QgsOSMDownload::abort() | ||
| { | ||
| if ( !mReply ) | ||
| return false; | ||
|
|
||
| mReply->abort(); | ||
| return true; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMDownload::onReadyRead() | ||
| { | ||
| Q_ASSERT( mReply ); | ||
|
|
||
| QByteArray data = mReply->read( 1024 * 1024 ); | ||
| mFile.write( data ); | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMDownload::onFinished() | ||
| { | ||
| qDebug( "finished" ); | ||
| Q_ASSERT( mReply ); | ||
|
|
||
| mReply->deleteLater(); | ||
| mReply = 0; | ||
|
|
||
| mFile.close(); | ||
|
|
||
| emit finished(); | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMDownload::onError( QNetworkReply::NetworkError err ) | ||
| { | ||
| qDebug( "error: %d", err ); | ||
| Q_ASSERT( mReply ); | ||
|
|
||
| mError = mReply->errorString(); | ||
| } | ||
|
|
||
|
|
||
| bool QgsOSMDownload::isFinished() const | ||
| { | ||
| if ( !mReply ) | ||
| return true; | ||
|
|
||
| return mReply->isFinished(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| #ifndef OSMDOWNLOAD_H | ||
| #define OSMDOWNLOAD_H | ||
|
|
||
|
|
||
| #include <QObject> | ||
| #include <QFile> | ||
| #include <QNetworkReply> | ||
|
|
||
| class QgsRectangle; | ||
|
|
||
| /** | ||
| * @brief OSMDownload is a utility class for downloading OpenStreetMap via Overpass API. | ||
| * | ||
| * To use this class, it is necessary to set query, output file name and start the request. | ||
| * The interface is asynchronous, the caller has to wait for finished() signal that is | ||
| * emitted whe the request has finished (successfully or with an error). | ||
| * | ||
| * To check whether the the request has been successful, check hasError() and use errorString() | ||
| * to retreive error message. An error may happen either directly in start() method | ||
| * or during the network communication. | ||
| * | ||
| * By default OSMDownload uses remote service at location returned by defaultServiceUrl() method. | ||
| */ | ||
| class ANALYSIS_EXPORT QgsOSMDownload : public QObject | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
|
|
||
| //! Return URL of the service that is used by default | ||
| static QString defaultServiceUrl(); | ||
|
|
||
| //! Create query (in Overpass Query Language) that fetches everything in given rectangle | ||
| static QString queryFromRect( const QgsRectangle& rect ); | ||
|
|
||
| QgsOSMDownload(); | ||
| ~QgsOSMDownload(); | ||
|
|
||
| void setServiceUrl( const QString& serviceUrl ) { mServiceUrl = serviceUrl; } | ||
| QString serviceUrl() const { return mServiceUrl; } | ||
|
|
||
| void setQuery( const QString& query ) { mQuery = query; } | ||
| QString query() const { return mQuery; } | ||
|
|
||
| void setOutputFileName( const QString& outputFileName ) { mFile.setFileName( outputFileName ); } | ||
| QString outputFileName() const { return mFile.fileName(); } | ||
|
|
||
| bool hasError() const { return !mError.isNull(); } | ||
| QString errorString() const { return mError; } | ||
|
|
||
| /** | ||
| * @brief Starts network request for data. The prerequisite is that the query string and output | ||
| * file name have been set. | ||
| * | ||
| * Only one request may be pending at one point - if you need more requests at once, use several instances. | ||
| * | ||
| * @return true if the network request has been issued, false otherwise (and sets error string) | ||
| */ | ||
| bool start(); | ||
|
|
||
| /** | ||
| * @brief Aborts current pending request | ||
| * @return true if there is a pending request and has been aborted, false otherwise | ||
| */ | ||
| bool abort(); | ||
|
|
||
| //! Returns true if the request has already finished | ||
| bool isFinished() const; | ||
|
|
||
| signals: | ||
| void finished(); //!< emitted when the network reply has finished (with success or with an error) | ||
| void downloadProgress( qint64, qint64 ); //!< normally the total length is not known (until we reach end) | ||
|
|
||
| private slots: | ||
| void onReadyRead(); | ||
| void onFinished(); | ||
| void onError( QNetworkReply::NetworkError err ); | ||
|
|
||
| private: | ||
| QString mServiceUrl; | ||
| QString mQuery; | ||
| QString mError; | ||
|
|
||
| QNetworkReply* mReply; | ||
| QFile mFile; | ||
| }; | ||
|
|
||
| #endif // OSMDOWNLOAD_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,371 @@ | ||
| #include "qgsosmimport.h" | ||
|
|
||
| #include <spatialite.h> | ||
|
|
||
| #include <QXmlStreamReader> | ||
|
|
||
|
|
||
| QgsOSMXmlImport::QgsOSMXmlImport( const QString& xmlFilename, const QString& dbFilename ) | ||
| : mXmlFileName( xmlFilename ) | ||
| , mDbFileName( dbFilename ) | ||
| , mDatabase( 0 ) | ||
| , mStmtInsertNode( 0 ) | ||
| , mStmtInsertNodeTag( 0 ) | ||
| , mStmtInsertWay( 0 ) | ||
| , mStmtInsertWayNode( 0 ) | ||
| , mStmtInsertWayTag( 0 ) | ||
| { | ||
|
|
||
| } | ||
|
|
||
| bool QgsOSMXmlImport::import() | ||
| { | ||
| mError.clear(); | ||
|
|
||
| // open input | ||
| mInputFile.setFileName( mXmlFileName ); | ||
| if ( !mInputFile.open( QIODevice::ReadOnly ) ) | ||
| { | ||
| mError = QString( "Cannot open input file: %1" ).arg( mXmlFileName ); | ||
| return false; | ||
| } | ||
|
|
||
| // open output | ||
|
|
||
| if ( QFile::exists( mDbFileName ) ) | ||
| { | ||
| if ( !QFile( mDbFileName ).remove() ) | ||
| { | ||
| mError = QString( "Database file cannot be overwritten: %1" ).arg( mDbFileName ); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| // load spatialite extension | ||
| spatialite_init( 0 ); | ||
|
|
||
| if ( !createDatabase() ) | ||
| { | ||
| // mError is set in createDatabase() | ||
| return false; | ||
| } | ||
|
|
||
| qDebug( "starting import" ); | ||
|
|
||
| int retX = sqlite3_exec( mDatabase, "BEGIN", NULL, NULL, 0 ); | ||
| Q_ASSERT( retX == SQLITE_OK ); | ||
|
|
||
| // start parsing | ||
|
|
||
| QXmlStreamReader xml( &mInputFile ); | ||
|
|
||
| while ( !xml.atEnd() ) | ||
| { | ||
| xml.readNext(); | ||
|
|
||
| if ( xml.isEndDocument() ) | ||
| break; | ||
|
|
||
| if ( xml.isStartElement() ) | ||
| { | ||
| if ( xml.name() == "osm" ) | ||
| readRoot( xml ); | ||
| else | ||
| xml.raiseError( "Invalid root tag" ); | ||
| } | ||
| } | ||
|
|
||
| int retY = sqlite3_exec( mDatabase, "COMMIT", NULL, NULL, 0 ); | ||
| Q_ASSERT( retY == SQLITE_OK ); | ||
|
|
||
| createIndexes(); | ||
|
|
||
| if ( xml.hasError() ) | ||
| { | ||
| mError = QString( "XML error: %1" ).arg( xml.errorString() ); | ||
| return false; | ||
| } | ||
|
|
||
| closeDatabase(); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| bool QgsOSMXmlImport::createIndexes() | ||
| { | ||
| // index on tags for faster access | ||
| const char* sqlIndexes[] = | ||
| { | ||
| "CREATE INDEX nodes_tags_idx ON nodes_tags(id)", | ||
| "CREATE INDEX ways_tags_idx ON ways_tags(id)", | ||
| "CREATE INDEX ways_nodes_way ON ways_nodes(way_id)" | ||
| }; | ||
| int count = sizeof( sqlIndexes ) / sizeof( const char* ); | ||
| for ( int i = 0; i < count; ++i ) | ||
| { | ||
| int ret = sqlite3_exec( mDatabase, sqlIndexes[i], 0, 0, 0 ); | ||
| if ( ret != SQLITE_OK ) | ||
| { | ||
| mError = "Error creating indexes!"; | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
||
| bool QgsOSMXmlImport::createDatabase() | ||
| { | ||
| if ( sqlite3_open_v2( mDbFileName.toUtf8().data(), &mDatabase, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0 ) != SQLITE_OK ) | ||
| return false; | ||
|
|
||
| const char* sqlInitStatements[] = | ||
| { | ||
| "PRAGMA cache_size = 100000", // TODO!!! | ||
| "PRAGMA synchronous = OFF", // TODO!!! | ||
| "SELECT InitSpatialMetadata('WGS84')", | ||
| "CREATE TABLE nodes ( id INTEGER PRIMARY KEY, lat REAL, lon REAL )", | ||
| "CREATE TABLE nodes_tags ( id INTEGER, k TEXT, v TEXT )", | ||
| "CREATE TABLE ways ( id INTEGER PRIMARY KEY )", | ||
| "CREATE TABLE ways_nodes ( way_id INTEGER, node_id INTEGER, way_pos INTEGER )", | ||
| "CREATE TABLE ways_tags ( id INTEGER, k TEXT, v TEXT )", | ||
| }; | ||
|
|
||
| int initCount = sizeof( sqlInitStatements ) / sizeof( const char* ); | ||
| for ( int i = 0; i < initCount; ++i ) | ||
| { | ||
| char* errMsg; | ||
| if ( sqlite3_exec( mDatabase, sqlInitStatements[i], 0, 0, &errMsg ) != SQLITE_OK ) | ||
| { | ||
| mError = QString( "Error executing SQL command:\n%1\nSQL:\n%2" ) | ||
| .arg( QString::fromUtf8( errMsg ) ).arg( QString::fromUtf8( sqlInitStatements[i] ) ); | ||
| sqlite3_free( errMsg ); | ||
| closeDatabase(); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| const char* sqlInsertStatements[] = | ||
| { | ||
| "INSERT INTO nodes ( id, lat, lon ) VALUES (?,?,?)", | ||
| "INSERT INTO nodes_tags ( id, k, v ) VALUES (?,?,?)", | ||
| "INSERT INTO ways ( id ) VALUES (?)", | ||
| "INSERT INTO ways_nodes ( way_id, node_id, way_pos ) VALUES (?,?,?)", | ||
| "INSERT INTO ways_tags ( id, k, v ) VALUES (?,?,?)" | ||
| }; | ||
| sqlite3_stmt** sqliteInsertStatements[] = | ||
| { | ||
| &mStmtInsertNode, | ||
| &mStmtInsertNodeTag, | ||
| &mStmtInsertWay, | ||
| &mStmtInsertWayNode, | ||
| &mStmtInsertWayTag | ||
| }; | ||
| Q_ASSERT( sizeof( sqlInsertStatements ) / sizeof( const char* ) == sizeof( sqliteInsertStatements ) / sizeof( sqlite3_stmt** ) ); | ||
| int insertCount = sizeof( sqlInsertStatements ) / sizeof( const char* ); | ||
|
|
||
| for ( int i = 0; i < insertCount; ++i ) | ||
| { | ||
| if ( sqlite3_prepare_v2( mDatabase, sqlInsertStatements[i], -1, sqliteInsertStatements[i], 0 ) != SQLITE_OK ) | ||
| { | ||
| const char* errMsg = sqlite3_errmsg( mDatabase ); // does not require free | ||
| mError = QString( "Error preparing SQL command:\n%1\nSQL:\n%2" ) | ||
| .arg( QString::fromUtf8( errMsg ) ).arg( QString::fromUtf8( sqlInsertStatements[i] ) ); | ||
| closeDatabase(); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMXmlImport::deleteStatement( sqlite3_stmt*& stmt ) | ||
| { | ||
| if ( stmt ) | ||
| { | ||
| sqlite3_finalize( stmt ); | ||
| stmt = 0; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| bool QgsOSMXmlImport::closeDatabase() | ||
| { | ||
| if ( !mDatabase ) | ||
| return false; | ||
|
|
||
| deleteStatement( mStmtInsertNode ); | ||
| deleteStatement( mStmtInsertNodeTag ); | ||
| deleteStatement( mStmtInsertWay ); | ||
| deleteStatement( mStmtInsertWayNode ); | ||
| deleteStatement( mStmtInsertWayTag ); | ||
|
|
||
| Q_ASSERT( mStmtInsertNode == 0 ); | ||
|
|
||
| sqlite3_close( mDatabase ); | ||
| mDatabase = 0; | ||
| return true; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMXmlImport::readRoot( QXmlStreamReader& xml ) | ||
| { | ||
| int i = 0; | ||
| int percent = -1; | ||
|
|
||
| while ( !xml.atEnd() ) | ||
| { | ||
| xml.readNext(); | ||
|
|
||
| if ( xml.isEndElement() ) // </osm> | ||
| break; | ||
|
|
||
| if ( xml.isStartElement() ) | ||
| { | ||
| if ( ++i == 500 ) | ||
| { | ||
| int new_percent = 100 * mInputFile.pos() / mInputFile.size(); | ||
| if ( new_percent > percent ) | ||
| { | ||
| emit progress( new_percent ); | ||
| percent = new_percent; | ||
| } | ||
| i = 0; | ||
| } | ||
|
|
||
| if ( xml.name() == "node" ) | ||
| readNode( xml ); | ||
| else if ( xml.name() == "way" ) | ||
| readWay( xml ); | ||
| else | ||
| xml.skipCurrentElement(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMXmlImport::readNode( QXmlStreamReader& xml ) | ||
| { | ||
| // <node id="2197214" lat="50.0682113" lon="14.4348483" user="viduka" uid="595326" visible="true" version="10" changeset="10714591" timestamp="2012-02-17T19:58:49Z"> | ||
| QXmlStreamAttributes attrs = xml.attributes(); | ||
| QgsOSMId id = attrs.value( "id" ).toString().toLongLong(); | ||
| double lat = attrs.value( "lat" ).toString().toDouble(); | ||
| double lon = attrs.value( "lon" ).toString().toDouble(); | ||
|
|
||
| // insert to DB | ||
| sqlite3_bind_int64( mStmtInsertNode, 1, id ); | ||
| sqlite3_bind_double( mStmtInsertNode, 2, lat ); | ||
| sqlite3_bind_double( mStmtInsertNode, 3, lon ); | ||
|
|
||
| if ( sqlite3_step( mStmtInsertNode ) != SQLITE_DONE ) | ||
| { | ||
| xml.raiseError( QString( "Storing node %1 failed." ).arg( id ) ); | ||
| } | ||
|
|
||
| sqlite3_reset( mStmtInsertNode ); | ||
|
|
||
| while ( !xml.atEnd() ) | ||
| { | ||
| xml.readNext(); | ||
|
|
||
| if ( xml.isEndElement() ) // </node> | ||
| break; | ||
|
|
||
| if ( xml.isStartElement() ) | ||
| { | ||
| if ( xml.name() == "tag" ) | ||
| readTag( false, id, xml ); | ||
| else | ||
| xml.raiseError( "Invalid tag in <node>" ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void QgsOSMXmlImport::readTag( bool way, QgsOSMId id, QXmlStreamReader& xml ) | ||
| { | ||
| QXmlStreamAttributes attrs = xml.attributes(); | ||
| QByteArray k = attrs.value( "k" ).toUtf8(); | ||
| QByteArray v = attrs.value( "v" ).toUtf8(); | ||
| xml.skipCurrentElement(); | ||
|
|
||
| sqlite3_stmt* stmtInsertTag = way ? mStmtInsertWayTag : mStmtInsertNodeTag; | ||
|
|
||
| sqlite3_bind_int64( stmtInsertTag, 1, id ); | ||
| sqlite3_bind_text( stmtInsertTag, 2, k.constData(), -1, SQLITE_STATIC ); | ||
| sqlite3_bind_text( stmtInsertTag, 3, v.constData(), -1, SQLITE_STATIC ); | ||
|
|
||
| int res = sqlite3_step( stmtInsertTag ); | ||
| if ( res != SQLITE_DONE ) | ||
| { | ||
| xml.raiseError( QString( "Storing tag failed [%1]" ).arg( res ) ); | ||
| } | ||
|
|
||
| sqlite3_reset( stmtInsertTag ); | ||
| } | ||
|
|
||
| void QgsOSMXmlImport::readWay( QXmlStreamReader& xml ) | ||
| { | ||
| /* | ||
| <way id="141756602" user="Vratislav Filler" uid="527259" visible="true" version="1" changeset="10145142" timestamp="2011-12-18T10:43:14Z"> | ||
| <nd ref="318529958"/> | ||
| <nd ref="1551725779"/> | ||
| <nd ref="1551725792"/> | ||
| <nd ref="809695938"/> | ||
| <nd ref="1551725689"/> | ||
| <nd ref="809695935"/> | ||
| <tag k="highway" v="service"/> | ||
| <tag k="oneway" v="yes"/> | ||
| </way> | ||
| */ | ||
| QXmlStreamAttributes attrs = xml.attributes(); | ||
| QgsOSMId id = attrs.value( "id" ).toString().toLongLong(); | ||
|
|
||
| // insert to DB | ||
| sqlite3_bind_int64( mStmtInsertWay, 1, id ); | ||
|
|
||
| if ( sqlite3_step( mStmtInsertWay ) != SQLITE_DONE ) | ||
| { | ||
| xml.raiseError( QString( "Storing way %1 failed." ).arg( id ) ); | ||
| } | ||
|
|
||
| sqlite3_reset( mStmtInsertWay ); | ||
|
|
||
| int way_pos = 0; | ||
|
|
||
| while ( !xml.atEnd() ) | ||
| { | ||
| xml.readNext(); | ||
|
|
||
| if ( xml.isEndElement() ) // </way> | ||
| break; | ||
|
|
||
| if ( xml.isStartElement() ) | ||
| { | ||
| if ( xml.name() == "nd" ) | ||
| { | ||
| QgsOSMId node_id = xml.attributes().value( "ref" ).toString().toLongLong(); | ||
|
|
||
| sqlite3_bind_int64( mStmtInsertWayNode, 1, id ); | ||
| sqlite3_bind_int64( mStmtInsertWayNode, 2, node_id ); | ||
| sqlite3_bind_int( mStmtInsertWayNode, 3, way_pos ); | ||
|
|
||
| if ( sqlite3_step( mStmtInsertWayNode ) != SQLITE_DONE ) | ||
| { | ||
| xml.raiseError( QString( "Storing ways_nodes %1 - %2 failed." ).arg( id ).arg( node_id ) ); | ||
| } | ||
|
|
||
| sqlite3_reset( mStmtInsertWayNode ); | ||
|
|
||
| way_pos++; | ||
|
|
||
| xml.skipCurrentElement(); | ||
| } | ||
| else if ( xml.name() == "tag" ) | ||
| readTag( true, id, xml ); | ||
| else | ||
| xml.skipCurrentElement(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #ifndef OSMIMPORT_H | ||
| #define OSMIMPORT_H | ||
|
|
||
| #include <QFile> | ||
| #include <QObject> | ||
|
|
||
| #include "qgsosmbase.h" | ||
|
|
||
| class QXmlStreamReader; | ||
|
|
||
|
|
||
| class ANALYSIS_EXPORT QgsOSMXmlImport : public QObject | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| explicit QgsOSMXmlImport( const QString& xmlFileName = QString(), const QString& dbFileName = QString() ); | ||
|
|
||
| void setInputXmlFileName( const QString& xmlFileName ) { mXmlFileName = xmlFileName; } | ||
| QString inputXmlFileName() const { return mXmlFileName; } | ||
|
|
||
| void setOutputDbFileName( const QString& dbFileName ) { mDbFileName = dbFileName; } | ||
| QString outputDbFileName() const { return mDbFileName; } | ||
|
|
||
| bool import(); | ||
|
|
||
| bool hasError() const { return !mError.isEmpty(); } | ||
| QString errorString() const { return mError; } | ||
|
|
||
| signals: | ||
| void progress( int percent ); | ||
|
|
||
| protected: | ||
|
|
||
| bool createDatabase(); | ||
| bool closeDatabase(); | ||
| void deleteStatement( sqlite3_stmt*& stmt ); | ||
|
|
||
| bool createIndexes(); | ||
|
|
||
| void readRoot( QXmlStreamReader& xml ); | ||
| void readNode( QXmlStreamReader& xml ); | ||
| void readWay( QXmlStreamReader& xml ); | ||
| void readTag( bool way, QgsOSMId id, QXmlStreamReader& xml ); | ||
|
|
||
| private: | ||
| QString mXmlFileName; | ||
| QString mDbFileName; | ||
|
|
||
| QString mError; | ||
|
|
||
| QFile mInputFile; | ||
|
|
||
| sqlite3* mDatabase; | ||
| sqlite3_stmt* mStmtInsertNode; | ||
| sqlite3_stmt* mStmtInsertNodeTag; | ||
| sqlite3_stmt* mStmtInsertWay; | ||
| sqlite3_stmt* mStmtInsertWayNode; | ||
| sqlite3_stmt* mStmtInsertWayTag; | ||
| }; | ||
|
|
||
|
|
||
|
|
||
| #endif // OSMIMPORT_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| #include "qgsosmdownloaddialog.h" | ||
|
|
||
| #include <QFileDialog> | ||
| #include <QMessageBox> | ||
| #include <QPushButton> | ||
|
|
||
| #include "qgisapp.h" | ||
| #include "qgsmapcanvas.h" | ||
| #include "qgsmaplayer.h" | ||
| #include "qgsmaplayerregistry.h" | ||
| #include "qgsrectangle.h" | ||
|
|
||
| #include "qgsosmdownload.h" | ||
|
|
||
| QgsOSMDownloadDialog::QgsOSMDownloadDialog( QWidget* parent ) | ||
| : QDialog( parent ), mDownload( new QgsOSMDownload ) | ||
| { | ||
| setupUi( this ); | ||
|
|
||
| editXMin->setValidator( new QDoubleValidator( -180, 180, 6 ) ); | ||
| editXMax->setValidator( new QDoubleValidator( -180, 180, 6 ) ); | ||
| editYMin->setValidator( new QDoubleValidator( -90, 90, 6 ) ); | ||
| editYMax->setValidator( new QDoubleValidator( -90, 90, 6 ) ); | ||
|
|
||
| populateLayers(); | ||
| onExtentCanvas(); | ||
|
|
||
| connect( radExtentCanvas, SIGNAL( clicked() ), this, SLOT( onExtentCanvas() ) ); | ||
| connect( radExtentLayer, SIGNAL( clicked() ), this, SLOT( onExtentLayer() ) ); | ||
| connect( radExtentManual, SIGNAL( clicked() ), this, SLOT( onExtentManual() ) ); | ||
| connect( cboLayers, SIGNAL( currentIndexChanged( int ) ), this, SLOT( onCurrentLayerChanged( int ) ) ); | ||
| connect( btnBrowse, SIGNAL( clicked() ), this, SLOT( onBrowseClicked() ) ); | ||
| connect( buttonBox, SIGNAL( accepted() ), this, SLOT( onOK() ) ); | ||
| connect( buttonBox, SIGNAL( rejected() ), this, SLOT( onClose() ) ); | ||
|
|
||
| connect( mDownload, SIGNAL( finished() ), this, SLOT( onFinished() ) ); | ||
| connect( mDownload, SIGNAL( downloadProgress( qint64, qint64 ) ), this, SLOT( onDownloadProgress( qint64, qint64 ) ) ); | ||
| } | ||
|
|
||
| QgsOSMDownloadDialog::~QgsOSMDownloadDialog() | ||
| { | ||
| delete mDownload; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMDownloadDialog::populateLayers() | ||
| { | ||
| QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers(); | ||
| QMap<QString, QgsMapLayer*>::iterator it; | ||
| for ( it = layers.begin(); it != layers.end(); ++it ) | ||
| { | ||
| cboLayers->addItem( it.value()->name(), it.key() ); | ||
| } | ||
| cboLayers->setCurrentIndex( 0 ); | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::setRect( const QgsRectangle& rect ) | ||
| { | ||
| // these coords should be already lat/lon | ||
| editXMin->setText( QString::number( rect.xMinimum() ) ); | ||
| editXMax->setText( QString::number( rect.xMaximum() ) ); | ||
| editYMin->setText( QString::number( rect.yMinimum() ) ); | ||
| editYMax->setText( QString::number( rect.yMaximum() ) ); | ||
| } | ||
|
|
||
| QgsRectangle QgsOSMDownloadDialog::rect() const | ||
| { | ||
| return QgsRectangle( editXMin->text().toDouble(), editYMin->text().toDouble(), | ||
| editXMax->text().toDouble(), editYMax->text().toDouble() ); | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMDownloadDialog::setRectReadOnly( bool readonly ) | ||
| { | ||
| editXMin->setReadOnly( readonly ); | ||
| editXMax->setReadOnly( readonly ); | ||
| editYMin->setReadOnly( readonly ); | ||
| editYMax->setReadOnly( readonly ); | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMDownloadDialog::onExtentCanvas() | ||
| { | ||
| setRect( QgisApp::instance()->mapCanvas()->extent() ); // TODO: transform to WGS84 | ||
| setRectReadOnly( true ); | ||
| cboLayers->setEnabled( false ); | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onExtentLayer() | ||
| { | ||
| onCurrentLayerChanged( cboLayers->currentIndex() ); | ||
| setRectReadOnly( true ); | ||
| cboLayers->setEnabled( true ); | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onExtentManual() | ||
| { | ||
| setRectReadOnly( false ); | ||
| cboLayers->setEnabled( false ); | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onCurrentLayerChanged( int index ) | ||
| { | ||
| if ( index < 0 ) | ||
| return; | ||
|
|
||
| QString layerId = cboLayers->itemData( index ).toString(); | ||
| QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerId ); | ||
| if ( !layer ) | ||
| return; | ||
|
|
||
| setRect( layer->extent() ); // TODO: transform to WGS84 | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onBrowseClicked() | ||
| { | ||
| QSettings settings; | ||
| QString lastDir = settings.value( "/osm/lastDir" ).toString(); | ||
|
|
||
| QString fileName = QFileDialog::getSaveFileName( this, QString(), lastDir, tr( "OpenStreetMap files (*.osm)" ) ); | ||
| if ( fileName.isNull() ) | ||
| return; | ||
|
|
||
| settings.setValue( "/osm/lastDir", QFileInfo( fileName ).absolutePath() ); | ||
| editFileName->setText( fileName ); | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onOK() | ||
| { | ||
| mDownload->setQuery( QgsOSMDownload::queryFromRect( rect() ) ); | ||
| mDownload->setOutputFileName( editFileName->text() ); | ||
| if ( !mDownload->start() ) | ||
| { | ||
| QMessageBox::critical( this, tr( "Download error" ), mDownload->errorString() ); | ||
| return; | ||
| } | ||
|
|
||
| buttonBox->button( QDialogButtonBox::Ok )->setEnabled( false ); | ||
| progress->setRange( 0, 0 ); // this will start animating progress bar | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onClose() | ||
| { | ||
| if ( !mDownload->isFinished() ) | ||
| { | ||
| int res = QMessageBox::question( this, tr( "OpenStreetMap download" ), | ||
| tr( "Would you like to abort download?" ), QMessageBox::Yes | QMessageBox::No ); | ||
| if ( res != QMessageBox::Yes ) | ||
| return; | ||
| } | ||
|
|
||
| reject(); | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onFinished() | ||
| { | ||
| buttonBox->button( QDialogButtonBox::Ok )->setEnabled( true ); | ||
| progress->setRange( 0, 1 ); | ||
|
|
||
| if ( mDownload->hasError() ) | ||
| { | ||
| QMessageBox::critical( this, tr( "OpenStreetMap download" ), tr( "Download failed.\n%1" ).arg( mDownload->errorString() ) ); | ||
| } | ||
| else | ||
| { | ||
| QMessageBox::information( this, tr( "OpenStreetMap download" ), tr( "Download has been successful." ) ); | ||
| } | ||
| } | ||
|
|
||
| void QgsOSMDownloadDialog::onDownloadProgress( qint64 bytesReceived, qint64 bytesTotal ) | ||
| { | ||
| Q_UNUSED( bytesTotal ); // it's -1 anyway (= unknown) | ||
| double mbytesReceived = ( double )bytesReceived / ( 1024 * 1024 ); | ||
| editSize->setText( QString( "%1 MB" ).arg( QString::number( mbytesReceived, 'f', 1 ) ) ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| #ifndef QGSOSMDOWNLOADDIALOG_H | ||
| #define QGSOSMDOWNLOADDIALOG_H | ||
|
|
||
| #include <QDialog> | ||
|
|
||
| #include "ui_qgsosmdownloaddialog.h" | ||
|
|
||
| class QgsRectangle; | ||
|
|
||
| class QgsOSMDownload; | ||
|
|
||
| class QgsOSMDownloadDialog : public QDialog, private Ui::QgsOSMDownloadDialog | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| explicit QgsOSMDownloadDialog( QWidget* parent = 0 ); | ||
| ~QgsOSMDownloadDialog(); | ||
|
|
||
| void setRect( const QgsRectangle& rect ); | ||
| void setRectReadOnly( bool readonly ); | ||
| QgsRectangle rect() const; | ||
|
|
||
| private: | ||
| void populateLayers(); | ||
|
|
||
| private slots: | ||
| void onExtentCanvas(); | ||
| void onExtentLayer(); | ||
| void onExtentManual(); | ||
| void onCurrentLayerChanged( int index ); | ||
| void onBrowseClicked(); | ||
| void onOK(); | ||
| void onClose(); | ||
| void onFinished(); | ||
| void onDownloadProgress( qint64, qint64 ); | ||
|
|
||
| private: | ||
| QgsOSMDownload* mDownload; | ||
| }; | ||
|
|
||
| #endif // QGSOSMDOWNLOADDIALOG_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| #include "qgsosmexportdialog.h" | ||
|
|
||
| #include "qgsosmdatabase.h" | ||
|
|
||
| #include <QApplication> | ||
| #include <QFileDialog> | ||
| #include <QMessageBox> | ||
| #include <QSettings> | ||
| #include <QStandardItemModel> | ||
|
|
||
| QgsOSMExportDialog::QgsOSMExportDialog( QWidget *parent ) : | ||
| QDialog( parent ), mDatabase( new QgsOSMDatabase ) | ||
| { | ||
| setupUi( this ); | ||
|
|
||
| connect( btnBrowseDb, SIGNAL( clicked() ), this, SLOT( onBrowse() ) ); | ||
| connect( buttonBox, SIGNAL( accepted() ), this, SLOT( onOK() ) ); | ||
| connect( buttonBox, SIGNAL( rejected() ), this, SLOT( onClose() ) ); | ||
| connect( editDbFileName, SIGNAL( textChanged( QString ) ), this, SLOT( updateLayerName() ) ); | ||
| connect( radPoints, SIGNAL( clicked() ), this, SLOT( updateLayerName() ) ); | ||
| connect( radPolylines, SIGNAL( clicked() ), this, SLOT( updateLayerName() ) ); | ||
| connect( radPolygons, SIGNAL( clicked() ), this, SLOT( updateLayerName() ) ); | ||
| connect( btnLoadTags, SIGNAL( clicked() ), this, SLOT( onLoadTags() ) ); | ||
|
|
||
| mTagsModel = new QStandardItemModel( this ); | ||
| mTagsModel->setHorizontalHeaderLabels( QStringList() << tr( "Tag" ) << tr( "Count" ) ); | ||
| viewTags->setModel( mTagsModel ); | ||
| } | ||
|
|
||
| QgsOSMExportDialog::~QgsOSMExportDialog() | ||
| { | ||
| delete mDatabase; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMExportDialog::onBrowse() | ||
| { | ||
| QSettings settings; | ||
| QString lastDir = settings.value( "/osm/lastDir" ).toString(); | ||
|
|
||
| QString fileName = QFileDialog::getOpenFileName( this, QString(), lastDir, tr( "SQLite databases (*.db)" ) ); | ||
| if ( fileName.isNull() ) | ||
| return; | ||
|
|
||
| settings.setValue( "/osm/lastDir", QFileInfo( fileName ).absolutePath() ); | ||
| editDbFileName->setText( fileName ); | ||
| } | ||
|
|
||
| void QgsOSMExportDialog::updateLayerName() | ||
| { | ||
| QString baseName = QFileInfo( editDbFileName->text() ).baseName(); | ||
|
|
||
| QString layerType; | ||
| if ( radPoints->isChecked() ) | ||
| layerType = "points"; | ||
| else if ( radPolylines->isChecked() ) | ||
| layerType = "polylines"; | ||
| else | ||
| layerType = "polygons"; | ||
| editLayerName->setText( QString( "%1_%2" ).arg( baseName ).arg( layerType ) ); | ||
| } | ||
|
|
||
|
|
||
| bool QgsOSMExportDialog::openDatabase() | ||
| { | ||
| mDatabase->setFileName( editDbFileName->text() ); | ||
|
|
||
| if ( !mDatabase->open() ) | ||
| { | ||
| QMessageBox::critical( this, QString(), tr( "Unable to open database:\n%1" ).arg( mDatabase->errorString() ) ); | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMExportDialog::onLoadTags() | ||
| { | ||
| if ( !openDatabase() ) | ||
| return; | ||
|
|
||
| QApplication::setOverrideCursor( Qt::WaitCursor ); | ||
|
|
||
| QList<QgsOSMTagCountPair> pairs = mDatabase->usedTags( !radPoints->isChecked() ); | ||
| mDatabase->close(); | ||
|
|
||
| mTagsModel->setColumnCount( 2 ); | ||
| mTagsModel->setRowCount( pairs.count() ); | ||
|
|
||
| for ( int i = 0; i < pairs.count(); ++i ) | ||
| { | ||
| const QgsOSMTagCountPair& p = pairs[i]; | ||
| QStandardItem* item = new QStandardItem( p.first ); | ||
| item->setCheckable( true ); | ||
| mTagsModel->setItem( i, 0, item ); | ||
| QStandardItem* item2 = new QStandardItem(); | ||
| item2->setData( p.second, Qt::DisplayRole ); | ||
| mTagsModel->setItem( i, 1, item2 ); | ||
| } | ||
|
|
||
| viewTags->resizeColumnToContents( 0 ); | ||
| viewTags->sortByColumn( 1, Qt::DescendingOrder ); | ||
|
|
||
| QApplication::restoreOverrideCursor(); | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMExportDialog::onOK() | ||
| { | ||
| if ( !openDatabase() ) | ||
| return; | ||
|
|
||
| QgsOSMDatabase::ExportType type; | ||
| if ( radPoints->isChecked() ) | ||
| type = QgsOSMDatabase::Point; | ||
| else if ( radPolylines->isChecked() ) | ||
| type = QgsOSMDatabase::Polyline; | ||
| else | ||
| type = QgsOSMDatabase::Polygon; | ||
|
|
||
| buttonBox->setEnabled( false ); | ||
| QApplication::setOverrideCursor( Qt::WaitCursor ); | ||
|
|
||
| QStringList tagKeys; | ||
|
|
||
| for ( int i = 0; i < mTagsModel->rowCount(); ++i ) | ||
| { | ||
| QStandardItem* item = mTagsModel->item( i, 0 ); | ||
| if ( item->checkState() == Qt::Checked ) | ||
| tagKeys << item->text(); | ||
| } | ||
|
|
||
| bool res = mDatabase->exportSpatiaLite( type, editLayerName->text(), tagKeys ); | ||
|
|
||
| QApplication::restoreOverrideCursor(); | ||
| buttonBox->setEnabled( true ); | ||
|
|
||
| if ( res ) | ||
| { | ||
| QMessageBox::information( this, tr( "OpenStreetMap export" ), tr( "Export has been successful." ) ); | ||
| } | ||
| else | ||
| { | ||
| QMessageBox::critical( this, tr( "OpenStreetMap import" ), tr( "Failed to export OSM data:\n%1" ).arg( mDatabase->errorString() ) ); | ||
| } | ||
|
|
||
| mDatabase->close(); | ||
| } | ||
|
|
||
| void QgsOSMExportDialog::onClose() | ||
| { | ||
| reject(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| #ifndef QGSOSMEXPORTDIALOG_H | ||
| #define QGSOSMEXPORTDIALOG_H | ||
|
|
||
| #include <QDialog> | ||
|
|
||
| #include "ui_qgsosmexportdialog.h" | ||
|
|
||
| class QgsOSMDatabase; | ||
|
|
||
| class QStandardItemModel; | ||
|
|
||
| class QgsOSMExportDialog : public QDialog, private Ui::QgsOSMExportDialog | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| explicit QgsOSMExportDialog( QWidget *parent = 0 ); | ||
| ~QgsOSMExportDialog(); | ||
|
|
||
| protected: | ||
| bool openDatabase(); | ||
|
|
||
| private slots: | ||
| void onBrowse(); | ||
| void updateLayerName(); | ||
| void onLoadTags(); | ||
|
|
||
| void onOK(); | ||
| void onClose(); | ||
|
|
||
| private: | ||
| QgsOSMDatabase* mDatabase; | ||
| QStandardItemModel* mTagsModel; | ||
| }; | ||
|
|
||
| #endif // QGSOSMEXPORTDIALOG_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| #include "qgsosmimportdialog.h" | ||
|
|
||
| #include <QApplication> | ||
| #include <QFileDialog> | ||
| #include <QMessageBox> | ||
| #include <QSettings> | ||
|
|
||
| #include "qgsosmimport.h" | ||
|
|
||
| QgsOSMImportDialog::QgsOSMImportDialog( QWidget* parent ) | ||
| : QDialog( parent ), mImport( new QgsOSMXmlImport ) | ||
| { | ||
| setupUi( this ); | ||
|
|
||
| connect( btnBrowseXml, SIGNAL( clicked() ), this, SLOT( onBrowseXml() ) ); | ||
| connect( btnBrowseDb, SIGNAL( clicked() ), this, SLOT( onBrowseDb() ) ); | ||
| connect( editXmlFileName, SIGNAL( textChanged( const QString& ) ), this, SLOT( xmlFileNameChanged( const QString& ) ) ); | ||
| connect( editDbFileName, SIGNAL( textChanged( const QString& ) ), this, SLOT( dbFileNameChanged( const QString& ) ) ); | ||
| connect( buttonBox, SIGNAL( accepted() ), this, SLOT( onOK() ) ); | ||
| connect( buttonBox, SIGNAL( rejected() ), this, SLOT( onClose() ) ); | ||
|
|
||
| connect( mImport, SIGNAL( progress( int ) ), this, SLOT( onProgress( int ) ) ); | ||
| } | ||
|
|
||
| QgsOSMImportDialog::~QgsOSMImportDialog() | ||
| { | ||
| delete mImport; | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMImportDialog::onBrowseXml() | ||
| { | ||
| QSettings settings; | ||
| QString lastDir = settings.value( "/osm/lastDir" ).toString(); | ||
|
|
||
| QString fileName = QFileDialog::getOpenFileName( this, QString(), lastDir, tr( "OpenStreetMap files (*.osm)" ) ); | ||
| if ( fileName.isNull() ) | ||
| return; | ||
|
|
||
| settings.setValue( "/osm/lastDir", QFileInfo( fileName ).absolutePath() ); | ||
| editXmlFileName->setText( fileName ); | ||
| } | ||
|
|
||
| void QgsOSMImportDialog::onBrowseDb() | ||
| { | ||
| QSettings settings; | ||
| QString lastDir = settings.value( "/osm/lastDir" ).toString(); | ||
|
|
||
| QString fileName = QFileDialog::getSaveFileName( this, QString(), lastDir, tr( "SQLite databases (*.db)" ) ); | ||
| if ( fileName.isNull() ) | ||
| return; | ||
|
|
||
| settings.setValue( "/osm/lastDir", QFileInfo( fileName ).absolutePath() ); | ||
| editDbFileName->setText( fileName ); | ||
| } | ||
|
|
||
|
|
||
| void QgsOSMImportDialog::xmlFileNameChanged( const QString& fileName ) | ||
| { | ||
| editDbFileName->setText( fileName + ".db" ); | ||
| } | ||
|
|
||
| void QgsOSMImportDialog::dbFileNameChanged( const QString& fileName ) | ||
| { | ||
| editConnName->setText( QFileInfo( fileName ).baseName() ); | ||
| } | ||
|
|
||
| void QgsOSMImportDialog::onOK() | ||
| { | ||
| // output file exists? | ||
| if ( QFileInfo( editDbFileName->text() ).exists() ) | ||
| { | ||
| int res = QMessageBox::question( this, tr( "OpenStreetMap import" ), tr( "Output database file exists already. Overwrite?" ), QMessageBox::Yes | QMessageBox::No ); | ||
| if ( res != QMessageBox::Yes ) | ||
| return; | ||
| } | ||
|
|
||
| mImport->setInputXmlFileName( editXmlFileName->text() ); | ||
| mImport->setOutputDbFileName( editDbFileName->text() ); | ||
|
|
||
| buttonBox->setEnabled( false ); | ||
| QApplication::setOverrideCursor( Qt::WaitCursor ); | ||
|
|
||
| bool res = mImport->import(); | ||
|
|
||
| QApplication::restoreOverrideCursor(); | ||
| buttonBox->setEnabled( true ); | ||
|
|
||
| progressBar->setValue( 0 ); | ||
|
|
||
| if ( !res ) | ||
| { | ||
| QMessageBox::critical( this, tr( "OpenStreetMap import" ), tr( "Failed to import import OSM data:\n%1" ).arg( mImport->errorString() ) ); | ||
| return; | ||
| } | ||
|
|
||
| if ( groupCreateConn->isChecked() ) | ||
| { | ||
| // create connection - this is a bit hacky, sorry for that. | ||
| QSettings settings; | ||
| settings.setValue( QString( "/SpatiaLite/connections/%1/sqlitepath" ).arg( editConnName->text() ), mImport->outputDbFileName() ); | ||
| } | ||
|
|
||
| QMessageBox::information( this, tr( "OpenStreetMap import" ), tr( "Import has been successful." ) ); | ||
| } | ||
|
|
||
| void QgsOSMImportDialog::onClose() | ||
| { | ||
| reject(); | ||
| } | ||
|
|
||
| void QgsOSMImportDialog::onProgress( int percent ) | ||
| { | ||
| progressBar->setValue( percent ); | ||
| qApp->processEvents( QEventLoop::ExcludeSocketNotifiers ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #ifndef QGSOSMIMPORTDIALOG_H | ||
| #define QGSOSMIMPORTDIALOG_H | ||
|
|
||
| #include <QDialog> | ||
|
|
||
| #include "ui_qgsosmimportdialog.h" | ||
|
|
||
| class QgsOSMXmlImport; | ||
|
|
||
| class QgsOSMImportDialog : public QDialog, private Ui::QgsOSMImportDialog | ||
| { | ||
| Q_OBJECT | ||
| public: | ||
| explicit QgsOSMImportDialog( QWidget* parent = 0 ); | ||
| ~QgsOSMImportDialog(); | ||
|
|
||
| private slots: | ||
| void onBrowseXml(); | ||
| void onBrowseDb(); | ||
|
|
||
| void xmlFileNameChanged( const QString& fileName ); | ||
| void dbFileNameChanged( const QString& fileName ); | ||
|
|
||
| void onOK(); | ||
| void onClose(); | ||
|
|
||
| void onProgress( int percent ); | ||
|
|
||
| private: | ||
| QgsOSMXmlImport* mImport; | ||
| }; | ||
|
|
||
| #endif // QGSOSMIMPORTDIALOG_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,185 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ui version="4.0"> | ||
| <class>QgsOSMDownloadDialog</class> | ||
| <widget class="QDialog" name="QgsOSMDownloadDialog"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>0</x> | ||
| <y>0</y> | ||
| <width>398</width> | ||
| <height>312</height> | ||
| </rect> | ||
| </property> | ||
| <property name="windowTitle"> | ||
| <string>Download OpenStreetMap data</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout_2"> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox"> | ||
| <property name="title"> | ||
| <string>Extent</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout"> | ||
| <item> | ||
| <widget class="QRadioButton" name="radExtentCanvas"> | ||
| <property name="text"> | ||
| <string>From map canvas</string> | ||
| </property> | ||
| <property name="checked"> | ||
| <bool>true</bool> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| <item> | ||
| <widget class="QRadioButton" name="radExtentLayer"> | ||
| <property name="text"> | ||
| <string>From layer</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QComboBox" name="cboLayers"/> | ||
| </item> | ||
| </layout> | ||
| </item> | ||
| <item> | ||
| <widget class="QRadioButton" name="radExtentManual"> | ||
| <property name="text"> | ||
| <string>Manual</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <layout class="QGridLayout" name="gridLayout"> | ||
| <item row="0" column="0"> | ||
| <spacer name="horizontalSpacer_4"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>40</width> | ||
| <height>20</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| <item row="0" column="1" colspan="2"> | ||
| <widget class="QLineEdit" name="editYMax"/> | ||
| </item> | ||
| <item row="0" column="3"> | ||
| <spacer name="horizontalSpacer_3"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>40</width> | ||
| <height>20</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| <item row="1" column="0" colspan="2"> | ||
| <widget class="QLineEdit" name="editXMin"/> | ||
| </item> | ||
| <item row="1" column="2" colspan="2"> | ||
| <widget class="QLineEdit" name="editXMax"/> | ||
| </item> | ||
| <item row="2" column="0"> | ||
| <spacer name="horizontalSpacer"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>40</width> | ||
| <height>20</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| <item row="2" column="1" colspan="2"> | ||
| <widget class="QLineEdit" name="editYMin"/> | ||
| </item> | ||
| <item row="2" column="3"> | ||
| <spacer name="horizontalSpacer_2"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>40</width> | ||
| <height>20</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| </layout> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox_2"> | ||
| <property name="title"> | ||
| <string>Output file</string> | ||
| </property> | ||
| <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| <item> | ||
| <widget class="QLineEdit" name="editFileName"/> | ||
| </item> | ||
| <item> | ||
| <widget class="QToolButton" name="btnBrowse"> | ||
| <property name="text"> | ||
| <string>...</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||
| <item> | ||
| <widget class="QLineEdit" name="editSize"> | ||
| <property name="readOnly"> | ||
| <bool>true</bool> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QProgressBar" name="progress"/> | ||
| </item> | ||
| <item> | ||
| <widget class="QDialogButtonBox" name="buttonBox"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="standardButtons"> | ||
| <set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| <tabstops> | ||
| <tabstop>radExtentCanvas</tabstop> | ||
| <tabstop>radExtentLayer</tabstop> | ||
| <tabstop>cboLayers</tabstop> | ||
| <tabstop>radExtentManual</tabstop> | ||
| <tabstop>editYMax</tabstop> | ||
| <tabstop>editXMin</tabstop> | ||
| <tabstop>editXMax</tabstop> | ||
| <tabstop>editYMin</tabstop> | ||
| <tabstop>editFileName</tabstop> | ||
| <tabstop>btnBrowse</tabstop> | ||
| <tabstop>buttonBox</tabstop> | ||
| </tabstops> | ||
| <resources/> | ||
| <connections/> | ||
| </ui> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ui version="4.0"> | ||
| <class>QgsOSMExportDialog</class> | ||
| <widget class="QDialog" name="QgsOSMExportDialog"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>0</x> | ||
| <y>0</y> | ||
| <width>458</width> | ||
| <height>436</height> | ||
| </rect> | ||
| </property> | ||
| <property name="windowTitle"> | ||
| <string>Export OpenStreetMap topology to SpatiaLite</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox"> | ||
| <property name="title"> | ||
| <string>Input DB file</string> | ||
| </property> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||
| <item> | ||
| <widget class="QLineEdit" name="editDbFileName"/> | ||
| </item> | ||
| <item> | ||
| <widget class="QToolButton" name="btnBrowseDb"> | ||
| <property name="text"> | ||
| <string>...</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox_4"> | ||
| <property name="title"> | ||
| <string>Export type</string> | ||
| </property> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| <item> | ||
| <widget class="QRadioButton" name="radPoints"> | ||
| <property name="text"> | ||
| <string>Points (nodes)</string> | ||
| </property> | ||
| <property name="checked"> | ||
| <bool>true</bool> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QRadioButton" name="radPolylines"> | ||
| <property name="text"> | ||
| <string>Polylines (open ways)</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QRadioButton" name="radPolygons"> | ||
| <property name="text"> | ||
| <string>Polygons (closed ways)</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox_2"> | ||
| <property name="title"> | ||
| <string>Output layer name</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout"> | ||
| <item> | ||
| <widget class="QLineEdit" name="editLayerName"/> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox_3"> | ||
| <property name="title"> | ||
| <string>Exported tags</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout_2"> | ||
| <item> | ||
| <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| <item> | ||
| <widget class="QPushButton" name="btnLoadTags"> | ||
| <property name="text"> | ||
| <string>Load from DB</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <spacer name="horizontalSpacer"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>40</width> | ||
| <height>20</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| </layout> | ||
| </item> | ||
| <item> | ||
| <widget class="QTreeView" name="viewTags"> | ||
| <property name="sortingEnabled"> | ||
| <bool>true</bool> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_4"> | ||
| <item> | ||
| <widget class="QProgressBar" name="progressBar"> | ||
| <property name="value"> | ||
| <number>0</number> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QDialogButtonBox" name="buttonBox"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="standardButtons"> | ||
| <set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| <tabstops> | ||
| <tabstop>editDbFileName</tabstop> | ||
| <tabstop>btnBrowseDb</tabstop> | ||
| <tabstop>radPoints</tabstop> | ||
| <tabstop>radPolylines</tabstop> | ||
| <tabstop>radPolygons</tabstop> | ||
| <tabstop>editLayerName</tabstop> | ||
| <tabstop>btnLoadTags</tabstop> | ||
| <tabstop>viewTags</tabstop> | ||
| <tabstop>buttonBox</tabstop> | ||
| </tabstops> | ||
| <resources/> | ||
| <connections/> | ||
| </ui> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ui version="4.0"> | ||
| <class>QgsOSMImportDialog</class> | ||
| <widget class="QDialog" name="QgsOSMImportDialog"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>0</x> | ||
| <y>0</y> | ||
| <width>396</width> | ||
| <height>257</height> | ||
| </rect> | ||
| </property> | ||
| <property name="windowTitle"> | ||
| <string>OpenStreetMap Import</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout"> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox_2"> | ||
| <property name="title"> | ||
| <string>Input XML file (.osm)</string> | ||
| </property> | ||
| <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| <item> | ||
| <widget class="QLineEdit" name="editXmlFileName"/> | ||
| </item> | ||
| <item> | ||
| <widget class="QToolButton" name="btnBrowseXml"> | ||
| <property name="text"> | ||
| <string>...</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox"> | ||
| <property name="title"> | ||
| <string>Output SpatiaLite DB file</string> | ||
| </property> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||
| <item> | ||
| <widget class="QLineEdit" name="editDbFileName"/> | ||
| </item> | ||
| <item> | ||
| <widget class="QToolButton" name="btnBrowseDb"> | ||
| <property name="text"> | ||
| <string>...</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupCreateConn"> | ||
| <property name="title"> | ||
| <string>Create connection (SpatiaLite) after import</string> | ||
| </property> | ||
| <property name="checkable"> | ||
| <bool>true</bool> | ||
| </property> | ||
| <layout class="QFormLayout" name="formLayout"> | ||
| <item row="0" column="0"> | ||
| <widget class="QLabel" name="label"> | ||
| <property name="text"> | ||
| <string>Connection name</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item row="0" column="1"> | ||
| <widget class="QLineEdit" name="editConnName"/> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <spacer name="verticalSpacer"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Vertical</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>20</width> | ||
| <height>21</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| <item> | ||
| <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| <item> | ||
| <widget class="QProgressBar" name="progressBar"> | ||
| <property name="value"> | ||
| <number>0</number> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QDialogButtonBox" name="buttonBox"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="standardButtons"> | ||
| <set>QDialogButtonBox::Close|QDialogButtonBox::Ok</set> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| <tabstops> | ||
| <tabstop>editXmlFileName</tabstop> | ||
| <tabstop>btnBrowseXml</tabstop> | ||
| <tabstop>editDbFileName</tabstop> | ||
| <tabstop>btnBrowseDb</tabstop> | ||
| <tabstop>groupCreateConn</tabstop> | ||
| <tabstop>editConnName</tabstop> | ||
| <tabstop>buttonBox</tabstop> | ||
| </tabstops> | ||
| <resources/> | ||
| <connections/> | ||
| </ui> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,194 @@ | ||
| /*************************************************************************** | ||
| testopenstreetmap.cpp | ||
| -------------------------------------- | ||
| Date : January 2013 | ||
| Copyright : (C) 2013 by Martin Dobias | ||
| Email : wonder dot sk at gmail dot com | ||
| *************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
|
|
||
| #include <QtTest> | ||
| #include <QSignalSpy> | ||
|
|
||
| #include <qgsapplication.h> | ||
| //#include <qgsproviderregistry.h> | ||
|
|
||
| #include "openstreetmap/qgsosmdatabase.h" | ||
| #include "openstreetmap/qgsosmdownload.h" | ||
| #include "openstreetmap/qgsosmimport.h" | ||
|
|
||
| class TestOpenStreetMap : public QObject | ||
| { | ||
| Q_OBJECT | ||
| private slots: | ||
| void initTestCase();// will be called before the first testfunction is executed. | ||
| void cleanupTestCase();// will be called after the last testfunction was executed. | ||
| void init() ;// will be called before each testfunction is executed. | ||
| void cleanup() ;// will be called after every testfunction. | ||
| /** Our tests proper begin here */ | ||
| void download(); | ||
| void importAndQueries(); | ||
| private: | ||
|
|
||
| }; | ||
|
|
||
| void TestOpenStreetMap::initTestCase() | ||
| { | ||
| // | ||
| // Runs once before any tests are run | ||
| // | ||
| // init QGIS's paths - true means that all path will be inited from prefix | ||
| QgsApplication::init(); | ||
| //QgsApplication::initQgis(); | ||
| //QgsApplication::showSettings(); | ||
|
|
||
| //create some objects that will be used in all tests... | ||
| //create a map layer that will be used in all tests... | ||
| //QString myBaseFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt | ||
| } | ||
| void TestOpenStreetMap::cleanupTestCase() | ||
| { | ||
|
|
||
| } | ||
| void TestOpenStreetMap::init() | ||
| { | ||
|
|
||
| } | ||
| void TestOpenStreetMap::cleanup() | ||
| { | ||
| } | ||
|
|
||
|
|
||
| void TestOpenStreetMap::download() | ||
| { | ||
| QgsRectangle rect( 7.148, 51.249, 7.152, 51.251 ); | ||
|
|
||
| // start download | ||
| OSMDownload download; | ||
| download.setQuery( OSMDownload::queryFromRect( rect ) ); | ||
| download.setOutputFileName( "/tmp/dl-test.osm" ); | ||
| bool res = download.start(); | ||
| QVERIFY( res ); | ||
|
|
||
| // wait for finished() signal | ||
| int timeout = 15000; // in miliseconds - max waiting time | ||
| int waitTime = 500; // in miliseconds - unit waiting time | ||
| QSignalSpy spy( &download, SIGNAL( finished() ) ); | ||
| while ( timeout > 0 && spy.count() == 0 ) | ||
| { | ||
| QTest::qWait( waitTime ); | ||
| timeout -= waitTime; | ||
| } | ||
|
|
||
| QVERIFY( spy.count() != 0 ); | ||
|
|
||
| if ( download.hasError() ) | ||
| qDebug( "ERROR: %s", download.errorString().toAscii().data() ); | ||
| } | ||
|
|
||
|
|
||
| void TestOpenStreetMap::importAndQueries() | ||
| { | ||
| QString dbFilename = "/tmp/testdata.db"; | ||
| //QString xmlFilename = "/tmp/130127_023233_downloaded.osm"; | ||
| QString xmlFilename = TEST_DATA_DIR "/openstreetmap/testdata.xml"; | ||
|
|
||
| QgsOSMXmlImport import( xmlFilename, dbFilename ); | ||
| bool res = import.import(); | ||
| if ( import.hasError() ) | ||
| qDebug( "XML ERR: %s", import.errorString().toAscii().data() ); | ||
| QCOMPARE( res, true ); | ||
| QCOMPARE( import.hasError(), false ); | ||
|
|
||
| qDebug( "import finished" ); | ||
|
|
||
| QgsOSMDatabase db( dbFilename ); | ||
| bool dbopenRes = db.open(); | ||
| if ( !db.errorString().isEmpty() ) | ||
| qDebug( "DB ERR: %s", db.errorString().toAscii().data() ); | ||
| QCOMPARE( dbopenRes, true ); | ||
|
|
||
| // query node | ||
|
|
||
| QgsOSMNode n = db.node( 11111 ); | ||
| QCOMPARE( n.isValid(), true ); | ||
| QCOMPARE( n.point().x(), 14.4277148 ); | ||
| QCOMPARE( n.point().y(), 50.0651387 ); | ||
|
|
||
| QgsOSMNode nNot = db.node( 22222 ); | ||
| QCOMPARE( nNot.isValid(), false ); | ||
|
|
||
| // query node tags | ||
|
|
||
| QgsOSMTags tags = db.tags( false, 11111 ); | ||
| QCOMPARE( tags.count(), 7 ); | ||
| QCOMPARE( tags.value( "addr:postcode" ), QString( "12800" ) ); | ||
|
|
||
| QgsOSMTags tags2 = db.tags( false, 360769661 ); | ||
| QCOMPARE( tags2.count(), 0 ); | ||
| QCOMPARE( tags2.value( "addr:postcode" ), QString() ); | ||
|
|
||
| QgsOSMTags tagsNot = db.tags( false, 22222 ); | ||
| QCOMPARE( tagsNot.count(), 0 ); | ||
|
|
||
| // list nodes | ||
|
|
||
| QgsOSMNodeIterator nodes = db.listNodes(); | ||
| QCOMPARE( nodes.next().id(), 11111 ); | ||
| QCOMPARE( nodes.next().id(), 360769661 ); | ||
| nodes.close(); | ||
|
|
||
| // query way | ||
|
|
||
| QgsOSMWay w = db.way( 32137532 ); | ||
| QCOMPARE( w.isValid(), true ); | ||
| QCOMPARE( w.nodes().count(), 5 ); | ||
| QCOMPARE( w.nodes()[0], ( qint64 )360769661 ); | ||
| QCOMPARE( w.nodes()[1], ( qint64 )360769664 ); | ||
|
|
||
| QgsOSMWay wNot = db.way( 1234567 ); | ||
| QCOMPARE( wNot.isValid(), false ); | ||
|
|
||
| // query way tags | ||
|
|
||
| QgsOSMTags tagsW = db.tags( true, 32137532 ); | ||
| QCOMPARE( tagsW.count(), 3 ); | ||
| QCOMPARE( tagsW.value( "building" ), QString( "yes" ) ); | ||
|
|
||
| QgsOSMTags tagsWNot = db.tags( true, 1234567 ); | ||
| QCOMPARE( tagsWNot.count(), 0 ); | ||
|
|
||
| // list ways | ||
|
|
||
| QgsOSMWayIterator ways = db.listWays(); | ||
| QCOMPARE( ways.next().id(), 32137532 ); | ||
| QCOMPARE( ways.next().isValid(), false ); | ||
| ways.close(); | ||
|
|
||
| bool exportRes1 = db.exportSpatiaLite( QgsOSMDatabase::Point, "sl_points", QStringList( "addr:postcode" ) ); | ||
| //bool exportRes = db.exportSpatiaLite( QStringList("amenity") << "name" << "highway" ); | ||
| if ( !db.errorString().isEmpty() ) | ||
| qDebug( "EXPORT-1 ERR: %s", db.errorString().toAscii().data() ); | ||
| QCOMPARE( exportRes1, true ); | ||
|
|
||
|
|
||
| bool exportRes2 = db.exportSpatiaLite( QgsOSMDatabase::Polyline, "sl_lines", QStringList( "building" ) ); | ||
| //bool exportRes2 = db.exportSpatiaLite( QStringList("amenity") << "name" << "highway" ); | ||
| if ( !db.errorString().isEmpty() ) | ||
| qDebug( "EXPORT-2 ERR: %s", db.errorString().toAscii().data() ); | ||
| QCOMPARE( exportRes2, true ); | ||
|
|
||
|
|
||
| // TODO: test exported data | ||
| } | ||
|
|
||
|
|
||
| QTEST_MAIN( TestOpenStreetMap ) | ||
|
|
||
| #include "moc_testopenstreetmap.cxx" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <osm version="0.6" generator="CGImap 0.0.2" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/"> | ||
|
|
||
| <bounds minlat="50.0607644" minlon="14.4217296" maxlat="50.0705202" maxlon="14.4366398"/> | ||
|
|
||
| <!-- node --> | ||
| <node id="11111" lat="50.0651387" lon="14.4277148" user="Radomír Černoch" uid="51295" visible="true" version="2" changeset="1984279" timestamp="2009-07-30T13:22:24Z"> | ||
| <tag k="addr:conscriptionnumber" v="455"/> | ||
| <tag k="addr:housenumber" v="455/23"/> | ||
| <tag k="addr:postcode" v="12800"/> | ||
| <tag k="addr:street" v="Jaromírova"/> | ||
| <tag k="addr:streetnumber" v="23"/> | ||
| <tag k="source:addr" v="uir_adr"/> | ||
| <tag k="uir_adr:ADRESA_KOD" v="21738092"/> | ||
| </node> | ||
|
|
||
| <!-- closed way --> | ||
| <node id="360769661" lat="50.0665514" lon="14.4270245" user="BiIbo" uid="3516" visible="true" version="1" changeset="819377" timestamp="2009-03-15T16:58:35Z"/> | ||
| <node id="360769664" lat="50.0665121" lon="14.4270254" user="BiIbo" uid="3516" visible="true" version="1" changeset="819377" timestamp="2009-03-15T16:58:36Z"/> | ||
| <node id="360769666" lat="50.0665127" lon="14.4270765" user="BiIbo" uid="3516" visible="true" version="1" changeset="819377" timestamp="2009-03-15T16:58:36Z"/> | ||
| <node id="360769670" lat="50.0665514" lon="14.4270765" user="BiIbo" uid="3516" visible="true" version="1" changeset="819377" timestamp="2009-03-15T16:58:36Z"/> | ||
| <way id="32137532" user="BiIbo" uid="3516" visible="true" version="1" changeset="819377" timestamp="2009-03-15T16:58:37Z"> | ||
| <nd ref="360769661"/> | ||
| <nd ref="360769664"/> | ||
| <nd ref="360769666"/> | ||
| <nd ref="360769670"/> | ||
| <nd ref="360769661"/> | ||
| <tag k="building" v="yes"/> | ||
| <tag k="layer" v="1"/> | ||
| <tag k="source" v="cuzk:km"/> | ||
| </way> | ||
|
|
||
| <!-- relation --> | ||
| <relation id="126753" user="BiIbo" uid="3516" visible="true" version="1" changeset="1078773" timestamp="2009-05-04T19:51:58Z"> | ||
| <member type="way" ref="32137532" role="outer"/> | ||
| <!-- todo <member type="way" ref="34075795" role="inner"/> --> | ||
| <!--<member type="way" ref="34075796" role="inner"/>--> | ||
| <tag k="type" v="multipolygon"/> | ||
| </relation> | ||
|
|
||
| </osm> |