Hi all, in OSRM plugin the api v5 implementation is only valid for qt 5 . Also instructions like before are missing.
i am working on qt 4.8 , because of this i implemented api v5 for OsrmRunner.cpp , find attached working code, maybe someone needs or like to merge to qt5, br, konrad
// // This file is part of the Marble Virtual Globe. // // This program is free software licensed under the GNU LGPL. You can // find a copy of this license in LICENSE.txt in the top directory of // the source code. // // Copyright 2012 Dennis Nienhüser <[email protected]> // #include "OSRMRunner.h" #include "MarbleAbstractRunner.h" #include "MarbleDebug.h" #include "MarbleLocale.h" #include "GeoDataDocument.h" #include "GeoDataPlacemark.h" #include "GeoDataExtendedData.h" #include "routing/Maneuver.h" #include "TinyWebBrowser.h" #include <QtCore/QString> #include <QtCore/QVector> #include <QtCore/QUrl> #include <QtCore/QTime> #include <QtCore/QTimer> #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkReply> #include <QtScript/QScriptValue> #include <QtScript/QScriptEngine> #include <QtScript/QScriptValueIterator> namespace Marble { QVector<QPair<GeoDataCoordinates,QString> > OSRMRunner:: m_cachedHints; QString OSRMRunner:: m_hintChecksum; OSRMRunner::OSRMRunner( QObject *parent ) : MarbleAbstractRunner( parent ), m_networkAccessManager( new QNetworkAccessManager( this ) ) { connect( m_networkAccessManager, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( retrieveData( QNetworkReply * ) ) ); } OSRMRunner::~OSRMRunner() { // nothing to do } GeoDataFeature::GeoDataVisualCategory OSRMRunner::category() const { return GeoDataFeature::OsmSite; } void OSRMRunner::retrieveRoute(const RouteRequest *route) { if (route->size() < 2) { return; } QString url = "http://router.project-osrm.org/route/v1/driving/"; GeoDataCoordinates::Unit const degree = GeoDataCoordinates::Degree; for (int i = 0; i<route->size(); ++i) { GeoDataCoordinates const coordinates = route->at(i); url += QString::number(coordinates.longitude(degree), 'f', 6); url += ','; url += QString::number(coordinates.latitude(degree), 'f', 6); if (i + 1<route->size()) { url += ';'; } } //add options url += "?alternatives=false&overview=full&geometries=polyline6&steps=true"; QNetworkRequest request = QNetworkRequest(QUrl(url)); request.setRawHeader("User-Agent", TinyWebBrowser::userAgent("Browser", "OSRMRunner")); QNetworkReply *reply = m_networkAccessManager->get(request); connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleError(QNetworkReply::NetworkError))); QEventLoop eventLoop; QTimer timer; timer.setSingleShot(true); timer.setInterval(15000); connect(&timer, SIGNAL(timeout()), &eventLoop, SLOT(quit())); connect(this, SIGNAL(routeCalculated(GeoDataDocument*)), &eventLoop, SLOT(quit())); // @todo FIXME Must currently be done in the main thread, see bug 257376 QTimer::singleShot(0, this, SLOT(get())); timer.start(); eventLoop.exec(); } void OSRMRunner::retrieveData( QNetworkReply *reply ) { if ( reply->isFinished() ) { QByteArray data = reply->readAll(); reply->deleteLater(); GeoDataDocument* document = parse( data ); if ( !document ) { mDebug() << "Failed to parse the downloaded route data" << data; } emit routeCalculated( document ); } } void OSRMRunner::handleError( QNetworkReply::NetworkError error ) { mDebug() << " Error when retrieving OSRM route: " << error; } void OSRMRunner::append(QString *input, const QString &key, const QString &value) const { *input += QLatin1Char('&') + key + QLatin1Char('=') + value; } GeoDataLineString *OSRMRunner::decodePolyline( const QString &geometry ) const { // See https://developers.google.com/maps/documentation/utilities/polylinealgorithm GeoDataLineString* lineString = new GeoDataLineString; int coordinates[2] = { 0, 0 }; int const length = geometry.length(); for( int i=0; i<length; /* increment happens below */ ) { for ( int j=0; j<2; ++j ) { // lat and lon int block( 0 ), shift( 0 ), result( 0 ); do { block = geometry.at( i++ /* increment for outer loop */ ).toAscii() - 63; result |= ( block & 0x1F ) << shift; shift += 5; } while ( block >= 0x20 ); coordinates[j] += ( ( result & 1 ) != 0 ? ~( result >> 1 ) : ( result >> 1 ) ); } //enz int value = coordinates[1]; if(1)//value>10000000) lineString->append( GeoDataCoordinates( double( coordinates[1] ) / 1E6, double( coordinates[0] ) / 1E6, 0.0, GeoDataCoordinates::Degree ) ); else lineString->append( GeoDataCoordinates( double( coordinates[1] ) / 1E5, double( coordinates[0] ) / 1E5, 0.0, GeoDataCoordinates::Degree ) ); } return lineString; } /** enz: changed parsing related to new OSRM api */ RoutingInstruction::TurnType OSRMRunner::parseTurnType( const QString &instruction ) const { if ( instruction == "straight" ) { return RoutingInstruction::Straight; } else if ( instruction == "slight right" ) { return RoutingInstruction::SlightRight; } else if ( instruction == "right" ) { return RoutingInstruction::Right; } else if ( instruction == "sharp right" ) { return RoutingInstruction::SharpRight; } else if ( instruction == "turn around" ) { return RoutingInstruction::TurnAround; } else if (instruction == "turn") { return RoutingInstruction::TurnAround; } else if (instruction == "sharp left") { return RoutingInstruction::SharpLeft; } else if ( instruction == "left" ) { return RoutingInstruction::Left; } else if ( instruction == "slight left" ) { return RoutingInstruction::SlightLeft; } else if ( instruction == "continue" ) { return RoutingInstruction::Continue; } else if ( instruction == "roundabout first exit" ){ return RoutingInstruction::RoundaboutFirstExit; } else if (instruction == "roundabout second exit"){ return RoutingInstruction::RoundaboutSecondExit; } else if (instruction == "roundabout third exit"){ return RoutingInstruction::RoundaboutThirdExit; } else if (instruction == "roundabout exit"){ return RoutingInstruction::RoundaboutExit; } // ignoring ReachViaPoint = 9; // ignoring StayOnRoundAbout = 13; // ignoring StartAtEndOfStreet = 14; // ignoring ReachedYourDestination = 15; return RoutingInstruction::Unknown; } /** enz: completely changed parsing related to new OSRM api v5 */ GeoDataDocument *OSRMRunner::parse(const QByteArray &input) { QScriptEngine engine; // Qt requires parentheses around json code QScriptValue const data = engine.evaluate("(" + QString::fromUtf8(input) + ")"); GeoDataDocument* result = 0; bool ret = data.property("routes").isArray(); if (!ret)return result; result = new GeoDataDocument(); if (result == NULL)return result; result->setName("Open Source Routing Machine"); GeoDataPlacemark* routePlacemark = new GeoDataPlacemark; routePlacemark->setName("Route"); QScriptValue rt = data.property("routes").property("0"); GeoDataLineString* routeWaypoints = decodePolyline(rt.property("geometry").toString()); routePlacemark->setGeometry(routeWaypoints); qreal duration = data.property("routes").property("0").property("duration").toNumber(); qreal distance = data.property("routes").property("0").property("distance").toNumber(); QString tunit = "min"; duration /= 60.0;//min if (duration > 60.0) { duration /= 60.0;//h tunit = "h"; } QString name = "%1 %2 %3 %4 (OSRM)"; QString unit = "m"; qreal length = routeWaypoints->length(EARTH_RADIUS); if (length >= 1000) { length /= 1000.0; unit = "km"; } result->setName(name.arg(length, 0, 'f', 1).arg(unit).arg(duration, 0, 'f', 1).arg(tunit)); result->append(routePlacemark); if (routeWaypoints) { int x = routeWaypoints->size(); if (x < 2)return result; } else return result; if (data.property("waypoints").isArray()) { QScriptValue wp = data.property("waypoints"); QVariantList details = wp.toVariant().toList(); int wpcount = details.count(); for (int wpx = 0; wpx < wpcount; wpx++) { bool first = true; GeoDataCoordinates pos1; QScriptValue leg = data.property("routes").property("0").property("legs").property(wpx).property("steps"); bool ret = leg.isArray(); QVariantList details = leg.toVariant().toList(); int count = details.count(); for (int i = 0; i < count; i++) { //GeoDataLineString *lineString = new GeoDataLineString; GeoDataPlacemark* instruction = new GeoDataPlacemark; QScriptValue step = leg.property(i); QString road = step.property("name").toString(); QScriptValue man = step.property("maneuver"); QString type = man.property("type").toString(); QString mod = man.property("modifier").toString(); int exit=-1; if (type == "roundabout") { exit = man.property("exit").toInteger(); switch (exit) { case 1: mod = "roundabout first exit"; break; case 2: mod = "roundabout second exit"; break; case 3: mod = "roundabout third exit"; break; default: mod = "roundabout exit"; break; } } qreal lon = man.property("location").property("0").toNumber(); qreal lat = man.property("location").property("1").toNumber(); GeoDataCoordinates pos(lon, lat, 0, GeoDataCoordinates::Degree); if (1) { QString geom = step.property("geometry").toString(); GeoDataLineString *lineString = decodePolyline(geom); pos1 = pos; instruction->setGeometry(lineString); // result->append(instruction); // instruction = new GeoDataPlacemark; } GeoDataExtendedData extendedData; GeoDataData turnTypeData; turnTypeData.setName("turnType"); RoutingInstruction::TurnType turnType = parseTurnType(mod); turnTypeData.setValue(turnType); extendedData.addValue(turnTypeData); if (!road.isEmpty()) { GeoDataData roadName; roadName.setName("roadName"); roadName.setValue(road); extendedData.addValue(roadName); } if (first) { turnType = RoutingInstruction::Continue; first = false; } if (turnType == RoutingInstruction::Unknown) { instruction->setName(mod); } else { instruction->setName(RoutingInstruction::generateRoadInstruction(turnType, road)); } instruction->setExtendedData(extendedData); result->append(instruction); }//for steps count }//for legs count } return result; } } // namespace Marble #include "moc_OSRMRunner.cpp"
