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

Dennis Nienhüser earthwings at gentoo.org
Mon Sep 6 20:20:16 CEST 2010


SVN commit 1172217 by nienhueser:

Use the new monav daemon to retrieve routes. It will run out of the box, given that
- MoNavD, the monav daemon, r225 or later is available in PATH
- A compatible monav map lies in ~/.local/share/marble/maps/earth/monav. Version 0.0.1 is not compatible. You only need the contraction hierarchies and gps grid files.
- A plugins.ini file with the content

[General]
router=Contraction Hierarchies
gpsLookup=GPS Grid

lies in the same dir.
signals.h (daemon socket interface) is taken from monav. It has a dual license for that purpose.
Note that the daemon uses little resources (map is not held in RAM) and can be left running in the background fine.

 M  +1 -1      CMakeLists.txt  
 M  +57 -41    monav/MonavPlugin.cpp  
 M  +0 -3      monav/MonavPlugin.h  
 M  +60 -56    monav/MonavRunner.cpp  
 M  +1 -1      monav/MonavRunner.h  
 A             monav/signals.h   [License: GPL (v3+) LGPL (v3+)]


--- trunk/KDE/kdeedu/marble/src/plugins/runner/CMakeLists.txt #1172216:1172217
@@ -14,6 +14,6 @@
 #add_subdirectory( traveling-salesman )
 
 # monav works, but you need a custom shell client
-#add_subdirectory( monav )
+add_subdirectory( monav )
 
 add_subdirectory( yours )
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavPlugin.cpp #1172216:1172217
@@ -8,6 +8,7 @@
 // Copyright 2010      Dennis Nienhüser <earthwings at gentoo.org>
 //
 
+#include "signals.h"
 #include "MonavPlugin.h"
 #include "MonavRunner.h"
 #include "MarbleDirs.h"
@@ -15,8 +16,8 @@
 
 #include <QtCore/QProcess>
 #include <QtCore/QDir>
-#include <QtCore/QMutexLocker>
 #include <QtCore/QTimer>
+#include <QtNetwork/QLocalSocket>
 
 namespace Marble
 {
@@ -24,23 +25,66 @@
 class MonavPluginPrivate
 {
 public:
-    QProcess* m_monavProcess;
-
     QDir m_mapDir;
 
-    QMutex m_processMutex;
+    bool m_ownsServer;
 
-    QTimer m_shutdownTimer;
+    MonavPluginPrivate();
 
-    MonavPluginPrivate();
+    bool startDaemon();
+
+    void stopDaemon();
+
+    bool isDaemonRunning() const;
 };
 
-MonavPluginPrivate::MonavPluginPrivate() : m_monavProcess( 0 )
+MonavPluginPrivate::MonavPluginPrivate() : m_ownsServer( false )
 {
-    m_shutdownTimer.setInterval( 30 * 1000 );
-    m_shutdownTimer.setSingleShot( true );
+    // nothing to do
 }
 
+bool MonavPluginPrivate::isDaemonRunning() const
+{
+    QLocalSocket socket;
+    socket.connectToServer( "MoNavD" );
+    return socket.waitForConnected();
+}
+
+bool MonavPluginPrivate::startDaemon()
+{
+    if ( !isDaemonRunning() ) {
+        QProcess process;
+        if ( process.startDetached( "MoNavD" ) ) {
+            m_ownsServer = true;
+
+            // 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 )
+            {
+                if ( isDaemonRunning() ) {
+                    break;
+                }
+                usleep(100 * 1000);
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
+void MonavPluginPrivate::stopDaemon()
+{
+    if ( m_ownsServer ) {
+        m_ownsServer = false;
+        QProcess process;
+        process.startDetached( "MoNavD", QStringList() << "-t" );
+    }
+}
+
 MonavPlugin::MonavPlugin( QObject *parent ) : RunnerPlugin( parent ), d( new MonavPluginPrivate )
 {
     setSupportedCelestialBodies( QStringList() << "earth" );
@@ -52,54 +96,26 @@
 
     // Check installation
     d->m_mapDir = QDir( MarbleDirs::localPath() + "/maps/earth/monav/" );
-    bool haveMap = QFileInfo( d->m_mapDir, "Contraction Hierarchies" ).exists();
+    bool haveMap = QFileInfo( d->m_mapDir, "plugins.ini" ).exists();
     setCapabilities( haveMap ? Routing : None );
-
-    connect( &d->m_shutdownTimer, SIGNAL( timeout() ), this, SLOT( killProcess( ) ) );
 }
 
 MonavPlugin::~MonavPlugin()
 {
-    killProcess();
     delete d;
 }
 
 MarbleAbstractRunner* MonavPlugin::newRunner() const
 {
-    QMutexLocker locker( &d->m_processMutex );
-    if ( !d->m_monavProcess ) {
-        d->m_monavProcess = new QProcess;
-        d->m_monavProcess->start( "monav", QStringList() << "--pipe" << d->m_mapDir.absolutePath() );
-
-        if ( !d->m_monavProcess->waitForStarted( 5000 ) )
-        {
-            mDebug() << "Couldn't start monav from the current PATH. Install it to retrieve routing results from monav.";
+    if ( !d->startDaemon() ) {
+        mDebug() << "Failed to connect to MoNavD daemon";
         }
-    }
 
-    d->m_shutdownTimer.start();
-    return new MonavRunner( d->m_monavProcess );
+    return new MonavRunner;
 }
 
-void MonavPlugin::killProcess()
-{
-    QMutexLocker locker( &d->m_processMutex );
-
-    if ( d->m_monavProcess ) {
-        QProcess* dying = d->m_monavProcess;
-        d->m_monavProcess = 0;
-        dying->closeWriteChannel();
-        if ( !dying->waitForFinished( 1000 ) ) {
-            dying->terminate();
-            if ( !dying->waitForFinished( 1000 ) ) {
-                mDebug() << "monav process did not terminate properly.";
             }
-        }
-    }
-}
 
-}
-
 Q_EXPORT_PLUGIN2( MonavPlugin, Marble::MonavPlugin )
 
 #include "MonavPlugin.moc"
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavPlugin.h #1172216:1172217
@@ -30,9 +30,6 @@
 
     virtual MarbleAbstractRunner* newRunner() const;
 
-private Q_SLOTS:
-    void killProcess();
-
 private:
     MonavPluginPrivate* const d;
 };
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavRunner.cpp #1172216:1172217
@@ -9,12 +9,16 @@
 //
 
 #include "MonavRunner.h"
+#include "signals.h"
 
+#include "MarbleDebug.h"
 #include "MarbleDirs.h"
 #include "routing/RouteRequest.h"
 #include "GeoDataDocument.h"
 
 #include <QtCore/QProcess>
+#include <QtCore/QTime>
+#include <QtNetwork/QLocalSocket>
 
 namespace Marble
 {
@@ -22,80 +26,88 @@
 class MonavRunnerPrivate
 {
 public:
-    QProcess* m_monavProcess;
+    QDir m_mapDir;
 
-    MonavRunnerPrivate( QProcess* monav );
+    MonavRunnerPrivate();
 
-    GeoDataLineString* retrieveWaypoints( const QString &params );
+    GeoDataLineString* retrieveRoute( RouteRequest *route ) const;
 
-    GeoDataDocument* createDocument( GeoDataLineString* routeWaypoints ) const;
-
-    GeoDataLineString* parseMonavOutput( const QByteArray &content ) const;
+    GeoDataDocument* createDocument( GeoDataLineString* geometry ) const;
 };
 
-MonavRunnerPrivate::MonavRunnerPrivate( QProcess* monav ) :
-        m_monavProcess( monav )
+MonavRunnerPrivate::MonavRunnerPrivate() :
+        m_mapDir( MarbleDirs::localPath() + "/maps/earth/monav/" )
 {
     // nothing to do
 }
 
-GeoDataLineString* MonavRunnerPrivate::retrieveWaypoints( const QString &params )
+GeoDataLineString* MonavRunnerPrivate::retrieveRoute( RouteRequest *route ) const
 {
-    Q_ASSERT( m_monavProcess );
-    m_monavProcess->write( params.toAscii() );
-    QByteArray data;
-    for ( int i=1; i<15; ++i ) {
-        if ( m_monavProcess->bytesAvailable() ) {
-            data += m_monavProcess->readAllStandardOutput();
-            bool haveRoute = data.endsWith("\n\n");
-            if ( haveRoute ) {
-                return parseMonavOutput( data );
-            }
-        } else {
-            ++i;
-            usleep( 1000 * pow( 2, i ) );
-        }
-    }
+    GeoDataLineString* geometry = new GeoDataLineString;
 
-    return 0;
-}
+    QLocalSocket socket;
+    socket.connectToServer( "MoNavD" );
+    if ( socket.waitForConnected() ) {
+        RoutingDaemonCommand command;
+        QVector<RoutingDaemonCoordinate> waypoints;
 
-GeoDataLineString* MonavRunnerPrivate::parseMonavOutput( const QByteArray &content ) const
+        for ( int i = 0; i < route->size(); ++i )
 {
-    GeoDataLineString* routeWaypoints = new GeoDataLineString;
+            RoutingDaemonCoordinate coordinate;
+            coordinate.longitude = route->at( i ).longitude( GeoDataCoordinates::Degree );
+            coordinate.latitude = route->at( i ).latitude( GeoDataCoordinates::Degree );
+            waypoints << coordinate;
+        }
 
-    QStringList lines = QString::fromUtf8( content ).split( '\n' );
-    foreach( const QString &line, lines )
+        command.dataDirectory = m_mapDir.absolutePath();
+        command.lookupRadius = 1500;
+        command.waypoints = waypoints;
+
+        command.post( &socket );
+        socket.flush();
+
+        RoutingDaemonResult reply;
+        if ( reply.read( &socket ) )
     {
-        QStringList fields = line.split( ';' );
-        if ( fields.size() >= 2 )
+            switch (reply.type)
         {
-            qreal lat = fields.at( 0 ).trimmed().toDouble();
-            qreal lon = fields.at( 1 ).trimmed().toDouble();
-            GeoDataCoordinates coordinates( lon, lat, 0.0, GeoDataCoordinates::Degree );
-            routeWaypoints->append( coordinates );
+            case RoutingDaemonResult::LoadFail:
+                mDebug() << "failed to load monav map from " << m_mapDir.absolutePath();
+                break;
+            case RoutingDaemonResult::RouteFail:
+                mDebug() << "failed to retrieve route from monav daemon";
+                break;
+            case RoutingDaemonResult::Success:
+                /** @todo: make use of reply.seconds, the estimated travel time */
+                for ( int i = 0; i < reply.path.size(); i++ ) {
+                    qreal lon = reply.path[i].longitude;
+                    qreal lat = reply.path[i].latitude;
+                    GeoDataCoordinates coordinates( lon, lat, 0, GeoDataCoordinates::Degree );
+                    geometry->append( coordinates );
         }
+                break;
     }
+        }
+    }
 
-    return routeWaypoints;
+    return geometry;
 }
 
-GeoDataDocument* MonavRunnerPrivate::createDocument( GeoDataLineString* routeWaypoints ) const
+GeoDataDocument* MonavRunnerPrivate::createDocument( GeoDataLineString *geometry ) const
 {
-    if ( !routeWaypoints || routeWaypoints->isEmpty() )
-    {
+    if ( !geometry || geometry->isEmpty() ) {
         return 0;
     }
 
-    GeoDataDocument* result = new GeoDataDocument();
+    GeoDataDocument* result = new GeoDataDocument;
     GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
     routePlacemark->setName( "Route" );
-    routePlacemark->setGeometry( routeWaypoints );
+    routePlacemark->setGeometry( geometry );
     result->append( routePlacemark );
 
     QString name = "%1 %2 (Monav)";
     QString unit = "m";
-    qreal length = routeWaypoints->length( EARTH_RADIUS );
+    qreal length = geometry->length( EARTH_RADIUS );
     if ( length >= 1000 )
     {
         length /= 1000.0;
@@ -105,10 +117,11 @@
     return result;
 }
 
-MonavRunner::MonavRunner( QProcess* monav, QObject *parent ) :
+MonavRunner::MonavRunner( QObject *parent ) :
         MarbleAbstractRunner( parent ),
-        d( new MonavRunnerPrivate( monav ) )
+        d( new MonavRunnerPrivate )
 {
+    // nothing to do
 }
 
 MonavRunner::~MonavRunner()
@@ -123,17 +136,8 @@
 
 void MonavRunner::retrieveRoute( RouteRequest *route )
 {
-    QString params;
-    for ( int i = 0; i < route->size(); ++i )
-    {
-        double lon = route->at( i ).longitude( GeoDataCoordinates::Degree );
-        double lat = route->at( i ).latitude( GeoDataCoordinates::Degree );
-        params += QString( " --lat%1=%2" ).arg( i + 1 ).arg( lat, 0, 'f', 8 );
-        params += QString( " --lon%1=%2" ).arg( i + 1 ).arg( lon, 0, 'f', 8 );
-    }
-
-    GeoDataLineString* wayPoints = d->retrieveWaypoints( params.trimmed() + "\n" );
-    GeoDataDocument* result = d->createDocument( wayPoints );
+    GeoDataLineString* waypoints = d->retrieveRoute( route );
+    GeoDataDocument* result = d->createDocument( waypoints );
     emit routeCalculated( result );
 }
 
--- trunk/KDE/kdeedu/marble/src/plugins/runner/monav/MonavRunner.h #1172216:1172217
@@ -25,7 +25,7 @@
 {
     Q_OBJECT
 public:
-    explicit MonavRunner( QProcess* monav, QObject *parent = 0 );
+    explicit MonavRunner( QObject *parent = 0 );
 
     ~MonavRunner();
 


More information about the Marble-commits mailing list