2
// This file is part of the Marble Virtual Globe.
4
// This program is free software licensed under the GNU LGPL. You can
5
// find a copy of this license in LICENSE.txt in the top directory of
8
// Copyright 2010 Dennis Nienhüser <earthwings@gentoo.org>
9
// Copyright 2010 Niko Sams <niko.sams@gmail.com>
12
#include "RoutinoRunner.h"
14
#include "MarbleDebug.h"
15
#include "MarbleDirs.h"
16
#include "routing/RouteRequest.h"
17
#include "routing/instructions/WaypointParser.h"
18
#include "routing/instructions/InstructionTransformation.h"
19
#include "GeoDataDocument.h"
20
#include "GeoDataExtendedData.h"
22
#include <QtCore/QProcess>
23
#include <QtCore/QMap>
24
#include <QtCore/QTemporaryFile>
25
#include <MarbleMap.h>
26
#include <MarbleModel.h>
27
#include <routing/RoutingManager.h>
28
#include <routing/RoutingModel.h>
29
#include <routing/RoutingProfilesModel.h>
34
class RoutinoRunnerPrivate
39
WaypointParser m_parser;
41
QByteArray retrieveWaypoints( const QStringList ¶ms ) const;
43
GeoDataDocument* createDocument( GeoDataLineString* routeWaypoints, const QVector<GeoDataPlacemark*> instructions ) const;
45
GeoDataLineString* parseRoutinoOutput( const QByteArray &content ) const;
47
QVector<GeoDataPlacemark*> parseRoutinoInstructions( const QByteArray &content ) const;
49
RoutinoRunnerPrivate();
52
RoutinoRunnerPrivate::RoutinoRunnerPrivate()
54
m_parser.setLineSeparator("\n");
55
m_parser.setFieldSeparator('\t');
56
m_parser.setFieldIndex( WaypointParser::RoadName, 10 );
64
f.setAutoRemove( false );
66
m_dirName = f.fileName();
69
QFileInfo( m_dirName ).dir().mkdir( m_dirName );
73
QDir dir( m_dirName );
74
QFileInfoList entries = dir.entryInfoList( QDir::Files );
75
foreach ( const QFileInfo &file, entries ) {
76
QFile( file.absoluteFilePath() ).remove();
78
dir.rmdir( dir.absolutePath() );
81
QString dirName() const
89
QByteArray RoutinoRunnerPrivate::retrieveWaypoints( const QStringList ¶ms ) const
92
QProcess routinoProcess;
93
routinoProcess.setWorkingDirectory( dir.dirName() );
95
QStringList routinoParams;
96
routinoParams << params;
97
routinoParams << "--dir=" + m_mapDir.absolutePath();
98
routinoParams << "--output-text-all";
99
mDebug() << routinoParams;
100
routinoProcess.start( "routino-router", routinoParams );
101
if ( !routinoProcess.waitForStarted( 5000 ) ) {
102
mDebug() << "Couldn't start routino-router from the current PATH. Install it to retrieve routing results from routino.";
106
if ( routinoProcess.waitForFinished(60 * 1000) ) {
107
mDebug() << routinoProcess.readAll();
108
mDebug() << "routino finished";
109
QFile file( routinoProcess.workingDirectory() + "/shortest-all.txt" );
110
if ( !file.exists() ) {
111
file.setFileName( routinoProcess.workingDirectory() + "/quickest-all.txt" );
113
if ( !file.exists() ) {
114
mDebug() << "Can't get results";
116
file.open( QIODevice::ReadOnly );
117
return file.readAll();
121
mDebug() << "Couldn't stop routino";
126
GeoDataLineString* RoutinoRunnerPrivate::parseRoutinoOutput( const QByteArray &content ) const
128
GeoDataLineString* routeWaypoints = new GeoDataLineString;
130
QStringList lines = QString::fromUtf8( content ).split( '\n' );
131
mDebug() << lines.count() << "lines";
132
foreach( const QString &line, lines ) {
133
if ( line.left(1) == QString('#') ) {
137
QStringList fields = line.split('\t');
138
if ( fields.size() >= 10 ) {
139
qreal lon = fields.at(1).trimmed().toDouble();
140
qreal lat = fields.at(0).trimmed().toDouble();
141
GeoDataCoordinates coordinates( lon, lat, 0.0, GeoDataCoordinates::Degree );
142
routeWaypoints->append( coordinates );
146
return routeWaypoints;
149
QVector<GeoDataPlacemark*> RoutinoRunnerPrivate::parseRoutinoInstructions( const QByteArray &content ) const
151
QVector<GeoDataPlacemark*> result;
152
QTextStream stream( content );
153
stream.setCodec("UTF8");
154
stream.setAutoDetectUnicode( true );
156
RoutingInstructions directions = InstructionTransformation::process( m_parser.parse( stream ) );
157
for( int i=0; i<directions.size(); ++i ) {
158
GeoDataPlacemark* placemark = new GeoDataPlacemark( directions[i].instructionText() );
159
GeoDataExtendedData extendedData;
160
GeoDataData turnType;
161
turnType.setName( "turnType" );
162
turnType.setValue( qVariantFromValue<int>( int( directions[i].turnType() ) ) );
163
extendedData.addValue( turnType );
164
placemark->setExtendedData( extendedData );
165
Q_ASSERT( !directions[i].points().isEmpty() );
166
GeoDataLineString* geometry = new GeoDataLineString;
167
QVector<RoutingWaypoint> items = directions[i].points();
168
for (int j=0; j<items.size(); ++j ) {
169
RoutingPoint point = items[j].point();
170
GeoDataCoordinates coordinates( point.lon(), point.lat(), 0.0, GeoDataCoordinates::Degree );
171
geometry->append( coordinates );
173
placemark->setGeometry( geometry );
174
result.push_back( placemark );
180
GeoDataDocument* RoutinoRunnerPrivate::createDocument( GeoDataLineString* routeWaypoints, const QVector<GeoDataPlacemark*> instructions ) const
182
if ( !routeWaypoints || routeWaypoints->isEmpty() ) {
186
GeoDataDocument* result = new GeoDataDocument();
187
GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
188
routePlacemark->setName( "Route" );
189
routePlacemark->setGeometry( routeWaypoints );
190
result->append( routePlacemark );
192
QString name = "%1 %2 (Routino)";
194
qreal length = routeWaypoints->length( EARTH_RADIUS );
195
if (length >= 1000) {
199
result->setName( name.arg( length, 0, 'f', 1 ).arg( unit ) );
201
foreach( GeoDataPlacemark* placemark, instructions )
203
result->append( placemark );
209
RoutinoRunner::RoutinoRunner( QObject *parent ) :
210
MarbleAbstractRunner( parent ),
211
d( new RoutinoRunnerPrivate )
213
// Check installation
214
d->m_mapDir = QDir( MarbleDirs::localPath() + "/maps/earth/routino/" );
217
RoutinoRunner::~RoutinoRunner()
222
GeoDataFeature::GeoDataVisualCategory RoutinoRunner::category() const
224
return GeoDataFeature::OsmSite;
227
void RoutinoRunner::retrieveRoute( RouteRequest *route )
231
if ( ! QFileInfo( d->m_mapDir, "nodes.mem" ).exists() )
233
emit routeCalculated( 0 );
238
for( int i=0; i<route->size(); ++i )
240
double fLon = route->at(i).longitude( GeoDataCoordinates::Degree );
241
double fLat = route->at(i).latitude( GeoDataCoordinates::Degree );
242
params << QString("--lat%1=%2").arg(i+1).arg(fLat, 0, 'f', 8);
243
params << QString("--lon%1=%2").arg(i+1).arg(fLon, 0, 'f', 8);
246
QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()["routino"];
247
QString transport = settings["transport"].toString();
248
params << QString( "--transport=%0" ).arg( transport );
250
if ( settings["method"] == "shortest" ) {
251
params << "--shortest";
253
params << "--quickest";
256
if ( route->avoidFeatures() & RouteRequest::AvoidHighway ) {
257
params << "--highway-motorway=0";
261
QByteArray output = d->retrieveWaypoints( params );
262
GeoDataLineString* wayPoints = d->parseRoutinoOutput( output );
263
QVector<GeoDataPlacemark*> instructions = d->parseRoutinoInstructions( output );
265
GeoDataDocument* result = d->createDocument( wayPoints, instructions );
266
mDebug() << this << "routeCalculated";
267
emit routeCalculated( result );
270
} // namespace Marble
272
#include "RoutinoRunner.moc"