[Marble-commits] KDE/kdeedu/marble/src/plugins/runner/monav

Dennis Nienhüser earthwings at gentoo.org
Fri Oct 8 23:20:38 CEST 2010


SVN commit 1183964 by nienhueser:

Support multiple, non-overlapping maps. Maps can be placed in any subdirectory of ../maps/earth/monav/ now and will be recognized automatically if they contain the plugins.ini required by monavd. Optionally (recommended) a $dirname/$dirname.poly file in osmosis polygon filter file format (in the tiling scheme from cloudmade; might switch to kml instead) can be provided to determine if the map is applicable for a route request (i.e. all via points in the route request are inside the map polygon). The .poly files can be downloaded directly from cloudmade (CC-BY-SA, distributed with the country osm.bz2 files). They correspond to simplified country borders.

 M  +151 -7    MonavPlugin.cpp  
 M  +2 -0      MonavPlugin.h  
 M  +14 -8     MonavRunner.cpp  
 M  +2 -1      MonavRunner.h  


--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavPlugin.cpp #1183963:1183964
@@ -13,23 +13,43 @@
 #include "MonavRunner.h"
 #include "MarbleDirs.h"
 #include "MarbleDebug.h"
+#include "GeoDataLatLonBox.h"
 
 #include <QtCore/QProcess>
 #include <QtCore/QDir>
+#include <QtCore/QDirIterator>
 #include <QtCore/QTimer>
 #include <QtNetwork/QLocalSocket>
+
 #include <unistd.h>
 
-
-
 namespace Marble
 {
 
+class MonavMap
+{
+public:
+    QDir m_directory;
+
+    GeoDataLatLonBox m_boundingBox;
+
+    QVector<GeoDataLatLonBox> m_tiles;
+
+    void setDirectory( const QDir &dir );
+
+    bool containsPoint( const GeoDataCoordinates &point ) const;
+
+private:
+    void parseBoundingBox( const QFileInfo &file );
+};
+
 class MonavPluginPrivate
 {
 public:
     QDir m_mapDir;
 
+    QVector<MonavMap> m_maps;
+
     bool m_ownsServer;
 
     MonavPluginPrivate();
@@ -41,8 +61,75 @@
     void stopDaemon();
 
     bool isDaemonRunning() const;
+
+    void loadMaps();
+
+    static bool bordersFirst( const MonavMap &first, const MonavMap &second );
+
+private:
+    void loadMap( const QString &path );
 };
 
+void MonavMap::setDirectory( const QDir &dir )
+{
+    m_directory = dir;
+    QFileInfo boundingBox( dir, dir.dirName() + ".poly" );
+    if ( boundingBox.exists() ) {
+        parseBoundingBox( boundingBox );
+    } else {
+        mDebug() << "No monav bounding box given for " << boundingBox.absoluteFilePath();
+    }
+}
+
+void MonavMap::parseBoundingBox( const QFileInfo &file )
+{
+    QFile input( file.absoluteFilePath() );
+    if ( input.open( QFile::ReadOnly ) ) {
+        GeoDataLineString boundingBox;
+        QTextStream stream( &input );
+        stream.readLine();
+        qreal lat( 0.0 ), lon( 0.0 );
+        while ( !stream.atEnd() ) {
+            if ( stream.readLine() == "END" ) {
+                continue;
+            }
+            GeoDataLineString box;
+            for ( int i = 0; i < 5; ++i ) {
+                stream >> lon;
+                stream >> lat;
+                GeoDataCoordinates point( lon, lat, 0.0, GeoDataCoordinates::Degree );
+                box << point;
+                boundingBox << point;
+            }
+            m_tiles.append( box.latLonAltBox() );
+            stream.readLine();
+        }
+        stream.readLine();
+        m_boundingBox = boundingBox.latLonAltBox();
+    }
+}
+
+bool MonavMap::containsPoint( const GeoDataCoordinates &point ) const
+{
+    // If we do not have a bounding box at all, we err on the safe side
+    if ( m_tiles.isEmpty() ) {
+        return true;
+    }
+
+    // Quick check for performance reasons
+    if ( !m_boundingBox.contains( point ) ) {
+        return false;
+    }
+
+    foreach( const GeoDataLatLonBox &box, m_tiles ) {
+        if ( box.contains( point ) ) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 MonavPluginPrivate::MonavPluginPrivate() : m_ownsServer( false )
 {
     // nothing to do
@@ -69,8 +156,7 @@
 
             // Give MoNavD up to one second to set up its server
             // Without that, the first route request would fail
-            for ( int i=0; i<10; ++i )
-            {
+            for ( int i = 0; i < 10; ++i ) {
                 if ( isDaemonRunning() ) {
                     break;
                 }
@@ -95,6 +181,44 @@
     }
 }
 
+void MonavPluginPrivate::loadMaps()
+{
+    QString base = MarbleDirs::localPath() + "/maps/earth/monav/";
+    loadMap( base );
+    QDir::Filters filters = QDir::AllDirs | QDir::Readable | QDir::NoDotAndDotDot;
+    QDirIterator iter( base, filters, QDirIterator::Subdirectories );
+    while ( iter.hasNext() ) {
+        iter.next();
+        loadMap( iter.filePath() );
+    }
+    // Prefer maps where bounding boxes are known
+    qSort( m_maps.begin(), m_maps.end(), MonavPluginPrivate::bordersFirst );
+}
+
+void MonavPluginPrivate::loadMap( const QString &path )
+{
+    QDir mapDir( path );
+    QFileInfo pluginsFile( mapDir, "plugins.ini" );
+    if ( pluginsFile.exists() ) {
+        MonavMap map;
+        map.setDirectory( mapDir );
+        m_maps.append( map );
+    }
+}
+
+bool MonavPluginPrivate::bordersFirst( const MonavMap &first, const MonavMap &second )
+{
+    if ( !first.m_tiles.isEmpty() && second.m_tiles.isEmpty() ) {
+        return true;
+    }
+
+    if ( first.m_tiles.isEmpty() && !second.m_tiles.isEmpty() ) {
+        return false;
+    }
+
+    return first.m_directory.absolutePath() < second.m_directory.absolutePath();
+}
+
 MonavPlugin::MonavPlugin( QObject *parent ) : RunnerPlugin( parent ), d( new MonavPluginPrivate )
 {
     setSupportedCelestialBodies( QStringList() << "earth" );
@@ -105,8 +229,8 @@
     setGuiString( tr( "Monav Routing" ) );
 
     // Check installation
-    d->m_mapDir = QDir( MarbleDirs::localPath() + "/maps/earth/monav/" );
-    bool haveMap = QFileInfo( d->m_mapDir, "plugins.ini" ).exists();
+    d->loadMaps();
+    bool const haveMap = !d->m_maps.isEmpty();
     setCapabilities( haveMap ? Routing /*| ReverseGeocoding */ : None );
 }
 
@@ -121,11 +245,31 @@
         mDebug() << "Failed to connect to MoNavD daemon";
     }
 
-    return new MonavRunner;
+    return new MonavRunner( this );
 }
 
+QString MonavPlugin::mapDirectoryForRequest( RouteRequest* request ) const
+{
+    foreach( const MonavMap &map, d->m_maps ) {
+        bool containsAllPoints = true;
+        for ( int i = 0; i < request->size(); ++i ) {
+            GeoDataCoordinates via = request->at( i );
+            if ( !map.containsPoint( via ) ) {
+                containsAllPoints = false;
+                break;
 }
+        }
 
+        if ( containsAllPoints ) {
+            return map.m_directory.absolutePath();
+        }
+    }
+
+    return QString();
+}
+
+}
+
 Q_EXPORT_PLUGIN2( MonavPlugin, Marble::MonavPlugin )
 
 #include "MonavPlugin.moc"
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavPlugin.h #1183963:1183964
@@ -30,6 +30,8 @@
 
     virtual MarbleAbstractRunner* newRunner() const;
 
+    QString mapDirectoryForRequest( RouteRequest* request ) const;
+
 private:
     MonavPluginPrivate* const d;
 };
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavRunner.cpp #1183963:1183964
@@ -9,6 +9,7 @@
 //
 
 #include "MonavRunner.h"
+#include "MonavPlugin.h"
 #include "signals.h"
 
 #include "MarbleDebug.h"
@@ -29,9 +30,9 @@
 class MonavRunnerPrivate
 {
 public:
-    QDir m_mapDir;
+    const MonavPlugin* m_plugin;
 
-    MonavRunnerPrivate();
+    MonavRunnerPrivate( const MonavPlugin* plugin );
 
     bool retrieveData( RouteRequest *route, RoutingDaemonResult* result ) const;
 
@@ -40,14 +41,19 @@
     GeoDataDocument* createDocument( GeoDataLineString* geometry, const QVector<GeoDataPlacemark*> &instructions  ) const;
 };
 
-MonavRunnerPrivate::MonavRunnerPrivate() :
-        m_mapDir( MarbleDirs::localPath() + "/maps/earth/monav/" )
+MonavRunnerPrivate::MonavRunnerPrivate( const MonavPlugin* plugin ) :
+        m_plugin( plugin )
 {
     // nothing to do
 }
 
 bool MonavRunnerPrivate::retrieveData( RouteRequest *route, RoutingDaemonResult* reply ) const
 {
+    QString mapDir = m_plugin->mapDirectoryForRequest( route );
+    if ( mapDir.isEmpty() ) {
+        return false;
+    }
+
     QLocalSocket socket;
     socket.connectToServer( "MoNavD" );
     if ( socket.waitForConnected() ) {
@@ -61,7 +67,7 @@
             waypoints << coordinate;
         }
 
-        command.dataDirectory = m_mapDir.absolutePath();
+        command.dataDirectory = mapDir;
         command.lookupRadius = 1500;
         command.waypoints = waypoints;
         command.lookupStrings = true;
@@ -72,7 +78,7 @@
         if ( reply->read( &socket ) ) {
             switch ( reply->type ) {
             case RoutingDaemonResult::LoadFailed:
-                mDebug() << "failed to load monav map from " << m_mapDir.absolutePath();
+                mDebug() << "failed to load monav map from " << mapDir;
                 return false;
                 break;
             case RoutingDaemonResult::RouteFailed:
@@ -180,9 +186,9 @@
     return result;
 }
 
-MonavRunner::MonavRunner( QObject *parent ) :
+MonavRunner::MonavRunner( const MonavPlugin* plugin, QObject *parent ) :
         MarbleAbstractRunner( parent ),
-        d( new MonavRunnerPrivate )
+        d( new MonavRunnerPrivate( plugin ) )
 {
     // nothing to do
 }
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavRunner.h #1183963:1183964
@@ -20,12 +20,13 @@
 {
 
 class MonavRunnerPrivate;
+class MonavPlugin;
 
 class MonavRunner : public MarbleAbstractRunner
 {
     Q_OBJECT
 public:
-    explicit MonavRunner( QObject *parent = 0 );
+    explicit MonavRunner( const MonavPlugin* plugin, QObject *parent = 0 );
 
     ~MonavRunner();
 


More information about the Marble-commits mailing list