From a7c7a9bfc1f1d75f23f1e67ba3859e698e2e8965 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Tue, 27 Sep 2016 18:45:49 +0200 Subject: Add OSRMv5 support in osm plugin This patch adds support for the OSRMv5 protocol (the only one currently available on the OSRM demo server router.project.osrm.org). Support for the old v4 protocol is retained, in case of users who supply their own osm.routing.host parameter pointing at a self hosted OSRMv4 server. The support for OSRMv4 and v5 has been moved away from the osm plugin and into the location module because this should be used in the mapbox plugin in a subsequent patch (the routing support in the mapbox plugin currently uses the text direction coming from the server, which does not support i18n) Task-number: QTBUG-56119 Change-Id: Id30fd536c7fd434011795f643221f55becfc9e18 Reviewed-by: Paolo Angelelli --- src/plugins/geoservices/osm/qgeoroutereplyosm.cpp | 324 +-------------------- .../osm/qgeoroutingmanagerengineosm.cpp | 31 +- .../geoservices/osm/qgeoroutingmanagerengineosm.h | 3 + 3 files changed, 35 insertions(+), 323 deletions(-) (limited to 'src/plugins/geoservices/osm') diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp index f704a714..81ada01d 100644 --- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp +++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp @@ -32,207 +32,10 @@ ****************************************************************************/ #include "qgeoroutereplyosm.h" - -#include -#include -#include -#include -#include +#include "qgeoroutingmanagerengineosm.h" QT_BEGIN_NAMESPACE -static QList parsePolyline(const QByteArray &data) -{ - QList path; - - bool parsingLatitude = true; - - int shift = 0; - int value = 0; - - QGeoCoordinate coord(0, 0); - - for (int i = 0; i < data.length(); ++i) { - unsigned char c = data.at(i) - 63; - - value |= (c & 0x1f) << shift; - shift += 5; - - // another chunk - if (c & 0x20) - continue; - - int diff = (value & 1) ? ~(value >> 1) : (value >> 1); - - if (parsingLatitude) { - coord.setLatitude(coord.latitude() + (double)diff/1e6); - } else { - coord.setLongitude(coord.longitude() + (double)diff/1e6); - path.append(coord); - } - - parsingLatitude = !parsingLatitude; - - value = 0; - shift = 0; - } - - return path; -} - -static QGeoManeuver::InstructionDirection osrmInstructionDirection(const QString &instructionCode) -{ - if (instructionCode == QLatin1String("0")) - return QGeoManeuver::NoDirection; - else if (instructionCode == QLatin1String("1")) - return QGeoManeuver::DirectionForward; - else if (instructionCode == QLatin1String("2")) - return QGeoManeuver::DirectionBearRight; - else if (instructionCode == QLatin1String("3")) - return QGeoManeuver::DirectionRight; - else if (instructionCode == QLatin1String("4")) - return QGeoManeuver::DirectionHardRight; - else if (instructionCode == QLatin1String("5")) - return QGeoManeuver::DirectionUTurnLeft; - else if (instructionCode == QLatin1String("6")) - return QGeoManeuver::DirectionHardLeft; - else if (instructionCode == QLatin1String("7")) - return QGeoManeuver::DirectionLeft; - else if (instructionCode == QLatin1String("8")) - return QGeoManeuver::DirectionBearLeft; - else if (instructionCode == QLatin1String("9")) - return QGeoManeuver::NoDirection; - else if (instructionCode == QLatin1String("10")) - return QGeoManeuver::DirectionForward; - else if (instructionCode == QLatin1String("11")) - return QGeoManeuver::NoDirection; - else if (instructionCode == QLatin1String("12")) - return QGeoManeuver::NoDirection; - else if (instructionCode == QLatin1String("13")) - return QGeoManeuver::NoDirection; - else if (instructionCode == QLatin1String("14")) - return QGeoManeuver::NoDirection; - else if (instructionCode == QLatin1String("15")) - return QGeoManeuver::NoDirection; - else - return QGeoManeuver::NoDirection; -} - -const QString osrmInstructionText(const QString &instructionCode, const QString &wayname) -{ - if (instructionCode == QLatin1String("0")) { - return QString(); - } else if (instructionCode == QLatin1String("1")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Go straight."); - else - return QGeoRouteReplyOsm::tr("Go straight onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("2")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Turn slightly right."); - else - return QGeoRouteReplyOsm::tr("Turn slightly right onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("3")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Turn right."); - else - return QGeoRouteReplyOsm::tr("Turn right onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("4")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Make a sharp right."); - else - return QGeoRouteReplyOsm::tr("Make a sharp right onto %1.").arg(wayname); - } - else if (instructionCode == QLatin1String("5")) { - return QGeoRouteReplyOsm::tr("When it is safe to do so, perform a U-turn."); - } else if (instructionCode == QLatin1String("6")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Make a sharp left."); - else - return QGeoRouteReplyOsm::tr("Make a sharp left onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("7")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Turn left."); - else - return QGeoRouteReplyOsm::tr("Turn left onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("8")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Turn slightly left."); - else - return QGeoRouteReplyOsm::tr("Turn slightly left onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("9")) { - return QGeoRouteReplyOsm::tr("Reached waypoint."); - } else if (instructionCode == QLatin1String("10")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Head on."); - else - return QGeoRouteReplyOsm::tr("Head onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11")) { - return QGeoRouteReplyOsm::tr("Enter the roundabout."); - } else if (instructionCode == QLatin1String("11-1")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the first exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the first exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-2")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the second exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the second exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-3")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the third exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the third exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-4")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the fourth exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the fourth exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-5")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the fifth exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the fifth exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-6")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the sixth exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the sixth exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-7")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the seventh exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the seventh exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-8")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the eighth exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the eighth exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("11-9")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("At the roundabout take the ninth exit."); - else - return QGeoRouteReplyOsm::tr("At the roundabout take the ninth exit onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("12")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Leave the roundabout."); - else - return QGeoRouteReplyOsm::tr("Leave the roundabout onto %1.").arg(wayname); - } else if (instructionCode == QLatin1String("13")) { - return QGeoRouteReplyOsm::tr("Stay on the roundabout."); - } else if (instructionCode == QLatin1String("14")) { - if (wayname.isEmpty()) - return QGeoRouteReplyOsm::tr("Start at the end of the street."); - else - return QGeoRouteReplyOsm::tr("Start at the end of %1.").arg(wayname); - } else if (instructionCode == QLatin1String("15")) { - return QGeoRouteReplyOsm::tr("You have reached your destination."); - } else { - return QGeoRouteReplyOsm::tr("Don't know what to say for '%1'").arg(instructionCode); - } -} - QGeoRouteReplyOsm::QGeoRouteReplyOsm(QNetworkReply *reply, const QGeoRouteRequest &request, QObject *parent) : QGeoRouteReply(request, parent), m_reply(reply) @@ -259,70 +62,6 @@ void QGeoRouteReplyOsm::abort() m_reply = 0; } -static QGeoRoute constructRoute(const QByteArray &geometry, const QJsonArray &instructions, - const QJsonObject &summary) -{ - QGeoRoute route; - - QList path = parsePolyline(geometry); - - QGeoRouteSegment firstSegment; - int firstPosition = -1; - - int segmentPathLengthCount = 0; - - for (int i = instructions.count() - 1; i >= 0; --i) { - QJsonArray instruction = instructions.at(i).toArray(); - - if (instruction.count() < 8) { - qWarning("Instruction does not contain enough fields."); - continue; - } - - const QString instructionCode = instruction.at(0).toString(); - const QString wayname = instruction.at(1).toString(); - double segmentLength = instruction.at(2).toDouble(); - int position = instruction.at(3).toDouble(); - int time = instruction.at(4).toDouble(); - //const QString segmentLengthString = instruction.at(5).toString(); - //const QString direction = instruction.at(6).toString(); - //double azimuth = instruction.at(7).toDouble(); - - QGeoRouteSegment segment; - segment.setDistance(segmentLength); - - QGeoManeuver maneuver; - maneuver.setDirection(osrmInstructionDirection(instructionCode)); - maneuver.setDistanceToNextInstruction(segmentLength); - maneuver.setInstructionText(osrmInstructionText(instructionCode, wayname)); - maneuver.setPosition(path.at(position)); - maneuver.setTimeToNextInstruction(time); - - segment.setManeuver(maneuver); - - if (firstPosition == -1) - segment.setPath(path.mid(position)); - else - segment.setPath(path.mid(position, firstPosition - position)); - - segmentPathLengthCount += segment.path().length(); - - segment.setTravelTime(time); - - segment.setNextRouteSegment(firstSegment); - - firstSegment = segment; - firstPosition = position; - } - - route.setDistance(summary.value(QStringLiteral("total_distance")).toDouble()); - route.setTravelTime(summary.value(QStringLiteral("total_time")).toDouble()); - route.setFirstRouteSegment(firstSegment); - route.setPath(path); - - return route; -} - void QGeoRouteReplyOsm::networkReplyFinished() { if (!m_reply) @@ -335,59 +74,26 @@ void QGeoRouteReplyOsm::networkReplyFinished() return; } - QJsonDocument document = QJsonDocument::fromJson(m_reply->readAll()); - - if (document.isObject()) { - QJsonObject object = document.object(); - - //double version = object.value(QStringLiteral("version")).toDouble(); - int status = object.value(QStringLiteral("status")).toDouble(); - QString statusMessage = object.value(QStringLiteral("status_message")).toString(); - - // status code 0 or 200 are case of success - // status code is 207 if no route was found - // an error occurred when trying to find a route - if (0 != status && 200 != status) { - setError(QGeoRouteReply::UnknownError, statusMessage); - m_reply->deleteLater(); - m_reply = 0; - return; - } - - QJsonObject routeSummary = object.value(QStringLiteral("route_summary")).toObject(); - - QByteArray routeGeometry = - object.value(QStringLiteral("route_geometry")).toString().toLatin1(); - - QJsonArray routeInstructions = object.value(QStringLiteral("route_instructions")).toArray(); - - QGeoRoute route = constructRoute(routeGeometry, routeInstructions, routeSummary); - - QList routes; - routes.append(route); + if (m_reply->error() != QNetworkReply::NoError) { + setError(QGeoRouteReply::CommunicationError, m_reply->errorString()); + m_reply->deleteLater(); + m_reply = 0; + return; + } - QJsonArray alternativeSummaries = - object.value(QStringLiteral("alternative_summaries")).toArray(); - QJsonArray alternativeGeometries = - object.value(QStringLiteral("alternative_geometries")).toArray(); - QJsonArray alternativeInstructions = - object.value(QStringLiteral("alternative_instructions")).toArray(); + QGeoRoutingManagerEngineOsm *engine = qobject_cast(parent()); + const QGeoRouteParser *parser = engine->routeParser(); - if (alternativeSummaries.count() == alternativeGeometries.count() && - alternativeSummaries.count() == alternativeInstructions.count()) { - for (int i = 0; i < alternativeSummaries.count(); ++i) { - route = constructRoute(alternativeGeometries.at(i).toString().toLatin1(), - alternativeInstructions.at(i).toArray(), - alternativeSummaries.at(i).toObject()); - //routes.append(route); - } - } + QList routes; + QString errorString; + QGeoRouteReply::Error error = parser->parseReply(routes, errorString, m_reply->readAll()); + if (error == QGeoRouteReply::NoError) { setRoutes(routes); - + // setError(QGeoRouteReply::NoError, status); // can't do this, or NoError is emitted and does damages setFinished(true); } else { - setError(QGeoRouteReply::ParseError, QStringLiteral("Couldn't parse json.")); + setError(error, errorString); } m_reply->deleteLater(); diff --git a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp index df3351c2..4e18049a 100644 --- a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp @@ -33,6 +33,8 @@ #include "qgeoroutingmanagerengineosm.h" #include "qgeoroutereplyosm.h" +#include "QtLocation/private/qgeorouteparserosrmv4_p.h" +#include "QtLocation/private/qgeorouteparserosrmv5_p.h" #include @@ -51,7 +53,14 @@ QGeoRoutingManagerEngineOsm::QGeoRoutingManagerEngineOsm(const QVariantMap ¶ if (parameters.contains(QStringLiteral("osm.routing.host"))) m_urlPrefix = parameters.value(QStringLiteral("osm.routing.host")).toString().toLatin1(); else - m_urlPrefix = QStringLiteral("http://router.project-osrm.org/viaroute"); + m_urlPrefix = QStringLiteral("http://router.project-osrm.org/route/v1/driving/"); + // for v4 it was "http://router.project-osrm.org/viaroute" + + if (parameters.contains(QStringLiteral("osm.routing.apiversion")) + && (parameters.value(QStringLiteral("osm.routing.apiversion")).toString().toLatin1() == QByteArray("v4"))) + m_routeParser = new QGeoRouteParserOsrmV4(this); + else + m_routeParser = new QGeoRouteParserOsrmV5(this); *error = QGeoServiceProvider::NoError; errorString->clear(); @@ -64,20 +73,9 @@ QGeoRoutingManagerEngineOsm::~QGeoRoutingManagerEngineOsm() QGeoRouteReply* QGeoRoutingManagerEngineOsm::calculateRoute(const QGeoRouteRequest &request) { QNetworkRequest networkRequest; - networkRequest.setRawHeader("User-Agent", m_userAgent); - - QUrl url(m_urlPrefix); - QUrlQuery query; - - query.addQueryItem(QStringLiteral("instructions"), QStringLiteral("true")); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, m_userAgent); - foreach (const QGeoCoordinate &c, request.waypoints()) { - query.addQueryItem(QStringLiteral("loc"), QString::number(c.latitude()) + QLatin1Char(',') + - QString::number(c.longitude())); - } - - url.setQuery(query); - networkRequest.setUrl(url); + networkRequest.setUrl(routeParser()->requestUrl(request, m_urlPrefix)); QNetworkReply *reply = m_networkManager->get(networkRequest); @@ -90,6 +88,11 @@ QGeoRouteReply* QGeoRoutingManagerEngineOsm::calculateRoute(const QGeoRouteReque return routeReply; } +const QGeoRouteParser *QGeoRoutingManagerEngineOsm::routeParser() const +{ + return m_routeParser; +} + void QGeoRoutingManagerEngineOsm::replyFinished() { QGeoRouteReply *reply = qobject_cast(sender()); diff --git a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h index 618ef900..8ffba6e3 100644 --- a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h +++ b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h @@ -36,6 +36,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -52,6 +53,7 @@ public: ~QGeoRoutingManagerEngineOsm(); QGeoRouteReply *calculateRoute(const QGeoRouteRequest &request); + const QGeoRouteParser *routeParser() const; private Q_SLOTS: void replyFinished(); @@ -59,6 +61,7 @@ private Q_SLOTS: private: QNetworkAccessManager *m_networkManager; + QGeoRouteParser *m_routeParser; QByteArray m_userAgent; QString m_urlPrefix; }; -- cgit v1.2.1 From 8bc909704986209e98feae8057b0e3ce07a28cd8 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Fri, 7 Oct 2016 14:19:16 +0200 Subject: Return only one route from osm plugin Until we figure out a way to deliver also the id of the route from the RouteModel, it's better to return only the first route or otherwise it's hard, in the mapItemView to either create only one delegate or treat delegates after the first differently Change-Id: Ibaa92ce93349619a31c105546ee9c3ff760c5b0b Reviewed-by: Alex Blasche --- src/plugins/geoservices/osm/qgeoroutereplyosm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/plugins/geoservices/osm') diff --git a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp index 81ada01d..701d1224 100644 --- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp +++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp @@ -89,7 +89,7 @@ void QGeoRouteReplyOsm::networkReplyFinished() QGeoRouteReply::Error error = parser->parseReply(routes, errorString, m_reply->readAll()); if (error == QGeoRouteReply::NoError) { - setRoutes(routes); + setRoutes(routes.mid(0,1)); // TODO QTBUG-56426 // setError(QGeoRouteReply::NoError, status); // can't do this, or NoError is emitted and does damages setFinished(true); } else { -- cgit v1.2.1