summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@theqtcompany.com>2016-09-27 18:45:49 +0200
committerPaolo Angelelli <paolo.angelelli@qt.io>2016-10-06 08:33:06 +0000
commita7c7a9bfc1f1d75f23f1e67ba3859e698e2e8965 (patch)
treebc7855bd5807a69a443f113038b74a19c5696108
parent26b2f917861e63091cf97a5acba04d7b813c2fed (diff)
downloadqtlocation-a7c7a9bfc1f1d75f23f1e67ba3859e698e2e8965.tar.gz
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 <paolo.angelelli@qt.io>
-rw-r--r--src/location/doc/src/plugins/osm.qdoc8
-rw-r--r--src/location/maps/maps.pri12
-rw-r--r--src/location/maps/qgeorouteparser.cpp90
-rw-r--r--src/location/maps/qgeorouteparser_p.h79
-rw-r--r--src/location/maps/qgeorouteparser_p_p.h60
-rw-r--r--src/location/maps/qgeorouteparserosrmv4.cpp404
-rw-r--r--src/location/maps/qgeorouteparserosrmv4_p.h72
-rw-r--r--src/location/maps/qgeorouteparserosrmv5.cpp979
-rw-r--r--src/location/maps/qgeorouteparserosrmv5_p.h72
-rw-r--r--src/plugins/geoservices/osm/qgeoroutereplyosm.cpp324
-rw-r--r--src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp31
-rw-r--r--src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h3
-rw-r--r--src/positioning/qlocationutils_p.h93
13 files changed, 1902 insertions, 325 deletions
diff --git a/src/location/doc/src/plugins/osm.qdoc b/src/location/doc/src/plugins/osm.qdoc
index 1960fae9..a0f2bc2b 100644
--- a/src/location/doc/src/plugins/osm.qdoc
+++ b/src/location/doc/src/plugins/osm.qdoc
@@ -94,8 +94,14 @@ a prefix.
\row
\li osm.routing.host
\li Url string set when making network requests to the routing server. This parameter should be set to a
- valid server url with the correct osrm API. If not specified the default \l {http://router.project-osrm.org/viaroute}{url} will be used.
+ valid server url with the correct osrm API. If not specified the default \l {http://router.project-osrm.org/route/v1/driving/}{url} will be used.
\note The API documentation and sources are available at \l {http://project-osrm.org/}{Project OSRM}.
+
+\row
+ \li osm.routing.apiversion
+ \li String defining the api version of the (custom) OSRM server. Valid values are \b{v4} and \b{v5}. The default is \b{v5}.
+ This parameter should be set only if \tt{osm.routing.host} is set, and is an OSRM v4 server.
+
\row
\li osm.geocoding.host
\li Url string set when making network requests to the geocoding server. This parameter should be set to a
diff --git a/src/location/maps/maps.pri b/src/location/maps/maps.pri
index 93af4f4d..a4ca73d0 100644
--- a/src/location/maps/maps.pri
+++ b/src/location/maps/maps.pri
@@ -55,6 +55,10 @@ PRIVATE_HEADERS += \
maps/qgeotiledmapreply_p_p.h \
maps/qgeotilespec_p.h \
maps/qgeotilespec_p_p.h \
+ maps/qgeorouteparser_p.h \
+ maps/qgeorouteparser_p_p.h \
+ maps/qgeorouteparserosrmv5_p.h \
+ maps/qgeorouteparserosrmv4_p.h \
maps/qcache3q_p.h
SOURCES += \
@@ -86,6 +90,12 @@ SOURCES += \
maps/qgeofiletilecache.cpp \
maps/qgeotiledmapreply.cpp \
maps/qgeotilespec.cpp \
- maps/qgeotiledmap.cpp
+ maps/qgeotiledmap.cpp \
+ maps/qgeorouteparser.cpp \
+ maps/qgeorouteparserosrmv5.cpp \
+ maps/qgeorouteparserosrmv4.cpp
+
+
+
diff --git a/src/location/maps/qgeorouteparser.cpp b/src/location/maps/qgeorouteparser.cpp
new file mode 100644
index 00000000..646902e0
--- /dev/null
+++ b/src/location/maps/qgeorouteparser.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeorouteparser_p.h"
+#include "qgeorouteparser_p_p.h"
+#include "qgeoroutesegment.h"
+#include "qgeomaneuver.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtPositioning/private/qlocationutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Private class implementations
+*/
+
+QGeoRouteParserPrivate::QGeoRouteParserPrivate() : QObjectPrivate()
+{
+}
+
+QGeoRouteParserPrivate::~QGeoRouteParserPrivate()
+{
+}
+
+/*
+ Public class implementations
+*/
+
+QGeoRouteParser::~QGeoRouteParser()
+{
+
+}
+
+QGeoRouteParser::QGeoRouteParser(QGeoRouteParserPrivate &dd, QObject *parent) : QObject(dd, parent)
+{
+
+}
+
+QGeoRouteReply::Error QGeoRouteParser::parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const
+{
+ Q_D(const QGeoRouteParser);
+ return d->parseReply(routes, errorString, reply);
+}
+
+QUrl QGeoRouteParser::requestUrl(const QGeoRouteRequest &request, const QString &prefix) const
+{
+ Q_D(const QGeoRouteParser);
+ return d->requestUrl(request, prefix);
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/location/maps/qgeorouteparser_p.h b/src/location/maps/qgeorouteparser_p.h
new file mode 100644
index 00000000..da1c09f2
--- /dev/null
+++ b/src/location/maps/qgeorouteparser_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOSRMROUTEPARSER_P_H
+#define QOSRMROUTEPARSER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLocation/qlocationglobal.h>
+#include <QtLocation/qgeoroutereply.h>
+#include <QtLocation/qgeorouterequest.h>
+#include <QtCore/QByteArray>
+#include <QtCore/QUrl>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoRouteParserPrivate;
+class Q_LOCATION_EXPORT QGeoRouteParser : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGeoRouteParser)
+
+public:
+ virtual ~QGeoRouteParser();
+ QGeoRouteReply::Error parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const;
+ QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const;
+
+protected:
+ QGeoRouteParser(QGeoRouteParserPrivate &dd, QObject *parent = Q_NULLPTR);
+
+private:
+ Q_DISABLE_COPY(QGeoRouteParser)
+};
+
+QT_END_NAMESPACE
+
+#endif // QOSRMROUTEPARSER_P_H
diff --git a/src/location/maps/qgeorouteparser_p_p.h b/src/location/maps/qgeorouteparser_p_p.h
new file mode 100644
index 00000000..7bf41f87
--- /dev/null
+++ b/src/location/maps/qgeorouteparser_p_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGEOROUTEPARSER_P_P_H
+#define QGEOROUTEPARSER_P_P_H
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/QUrl>
+#include <QtLocation/qgeoroutereply.h>
+#include <QtLocation/qgeorouterequest.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoRouteParserPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGeoRouteParser)
+public:
+ QGeoRouteParserPrivate();
+ virtual ~QGeoRouteParserPrivate();
+
+ virtual QGeoRouteReply::Error parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const = 0;
+ virtual QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOROUTEPARSER_P_P_H
diff --git a/src/location/maps/qgeorouteparserosrmv4.cpp b/src/location/maps/qgeorouteparserosrmv4.cpp
new file mode 100644
index 00000000..7321fb6f
--- /dev/null
+++ b/src/location/maps/qgeorouteparserosrmv4.cpp
@@ -0,0 +1,404 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeorouteparserosrmv4_p.h"
+#include "qgeorouteparser_p_p.h"
+#include "qgeoroutesegment.h"
+#include "qgeomaneuver.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QUrlQuery>
+
+QT_BEGIN_NAMESPACE
+
+static QList<QGeoCoordinate> parsePolyline(const QByteArray &data)
+{
+ QList<QGeoCoordinate> 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;
+}
+
+static QString osrmInstructionText(const QString &instructionCode, const QString &wayname)
+{
+ if (instructionCode == QLatin1String("0")) {
+ return QString();
+ } else if (instructionCode == QLatin1String("1")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Go straight.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Go straight onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("2")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Turn slightly right.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Turn slightly right onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("3")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Turn right.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Turn right onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("4")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Make a sharp right.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Make a sharp right onto %1.").arg(wayname);
+ }
+ else if (instructionCode == QLatin1String("5")) {
+ return QGeoRouteParserOsrmV4::tr("When it is safe to do so, perform a U-turn.");
+ } else if (instructionCode == QLatin1String("6")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Make a sharp left.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Make a sharp left onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("7")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Turn left.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Turn left onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("8")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Turn slightly left.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Turn slightly left onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("9")) {
+ return QGeoRouteParserOsrmV4::tr("Reached waypoint.");
+ } else if (instructionCode == QLatin1String("10")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Head on.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Head onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11")) {
+ return QGeoRouteParserOsrmV4::tr("Enter the roundabout.");
+ } else if (instructionCode == QLatin1String("11-1")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the first exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the first exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-2")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the second exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the second exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-3")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the third exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the third exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-4")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the fourth exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the fourth exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-5")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the fifth exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the fifth exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-6")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the sixth exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the sixth exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-7")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the seventh exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the seventh exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-8")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the eighth exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the eighth exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("11-9")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the ninth exit.");
+ else
+ return QGeoRouteParserOsrmV4::tr("At the roundabout take the ninth exit onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("12")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Leave the roundabout.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Leave the roundabout onto %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("13")) {
+ return QGeoRouteParserOsrmV4::tr("Stay on the roundabout.");
+ } else if (instructionCode == QLatin1String("14")) {
+ if (wayname.isEmpty())
+ return QGeoRouteParserOsrmV4::tr("Start at the end of the street.");
+ else
+ return QGeoRouteParserOsrmV4::tr("Start at the end of %1.").arg(wayname);
+ } else if (instructionCode == QLatin1String("15")) {
+ return QGeoRouteParserOsrmV4::tr("You have reached your destination.");
+ } else {
+ return QGeoRouteParserOsrmV4::tr("Don't know what to say for '%1'").arg(instructionCode);
+ }
+}
+
+static QGeoRoute constructRoute(const QByteArray &geometry, const QJsonArray &instructions,
+ const QJsonObject &summary)
+{
+ QGeoRoute route;
+
+ QList<QGeoCoordinate> 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;
+}
+
+class QGeoRouteParserOsrmV4Private : public QGeoRouteParserPrivate
+{
+ Q_DECLARE_PUBLIC(QGeoRouteParserOsrmV4)
+public:
+ QGeoRouteParserOsrmV4Private();
+ virtual ~QGeoRouteParserOsrmV4Private();
+
+ QGeoRouteReply::Error parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const Q_DECL_OVERRIDE;
+ QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const Q_DECL_OVERRIDE;
+};
+
+QGeoRouteParserOsrmV4Private::QGeoRouteParserOsrmV4Private() : QGeoRouteParserPrivate()
+{
+}
+
+QGeoRouteParserOsrmV4Private::~QGeoRouteParserOsrmV4Private()
+{
+}
+
+QGeoRouteReply::Error QGeoRouteParserOsrmV4Private::parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const
+{
+ // OSRM v4 specs: https://github.com/Project-OSRM/osrm-backend/wiki/Server-API---v4,-old
+ QJsonDocument document = QJsonDocument::fromJson(reply);
+
+ 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) {
+ errorString = statusMessage;
+ return QGeoRouteReply::UnknownError;
+ }
+
+ 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);
+
+ routes.append(route);
+
+ QJsonArray alternativeSummaries =
+ object.value(QStringLiteral("alternative_summaries")).toArray();
+ QJsonArray alternativeGeometries =
+ object.value(QStringLiteral("alternative_geometries")).toArray();
+ QJsonArray alternativeInstructions =
+ object.value(QStringLiteral("alternative_instructions")).toArray();
+
+ 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);
+ }
+ }
+
+ return QGeoRouteReply::NoError;
+ } else {
+ errorString = QStringLiteral("Couldn't parse json.");
+ return QGeoRouteReply::ParseError;
+ }
+}
+
+QUrl QGeoRouteParserOsrmV4Private::requestUrl(const QGeoRouteRequest &request, const QString &prefix) const
+{
+ QUrl url(prefix);
+ QUrlQuery query;
+
+ query.addQueryItem(QStringLiteral("instructions"), QStringLiteral("true"));
+
+ foreach (const QGeoCoordinate &c, request.waypoints()) {
+ query.addQueryItem(QStringLiteral("loc"), QString::number(c.latitude()) + QLatin1Char(',') +
+ QString::number(c.longitude()));
+ }
+
+ url.setQuery(query);
+ return url;
+}
+
+QGeoRouteParserOsrmV4::QGeoRouteParserOsrmV4(QObject *parent) : QGeoRouteParser(*new QGeoRouteParserOsrmV4Private(), parent)
+{
+}
+
+QGeoRouteParserOsrmV4::~QGeoRouteParserOsrmV4()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/maps/qgeorouteparserosrmv4_p.h b/src/location/maps/qgeorouteparserosrmv4_p.h
new file mode 100644
index 00000000..3d38cbf7
--- /dev/null
+++ b/src/location/maps/qgeorouteparserosrmv4_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGEOROUTEPARSEROSRMV4_H
+#define QGEOROUTEPARSEROSRMV4_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtLocation/private/qgeorouteparser_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoRouteParserOsrmV4Private;
+class Q_LOCATION_EXPORT QGeoRouteParserOsrmV4 : public QGeoRouteParser
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGeoRouteParserOsrmV4)
+
+public:
+ QGeoRouteParserOsrmV4(QObject *parent = Q_NULLPTR);
+ virtual ~QGeoRouteParserOsrmV4();
+
+private:
+ Q_DISABLE_COPY(QGeoRouteParserOsrmV4)
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOROUTEPARSEROSRMV4_H
diff --git a/src/location/maps/qgeorouteparserosrmv5.cpp b/src/location/maps/qgeorouteparserosrmv5.cpp
new file mode 100644
index 00000000..cbbf7fc4
--- /dev/null
+++ b/src/location/maps/qgeorouteparserosrmv5.cpp
@@ -0,0 +1,979 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgeorouteparserosrmv5_p.h"
+#include "qgeorouteparser_p_p.h"
+#include "qgeoroutesegment.h"
+#include "qgeomaneuver.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/QJsonDocument>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+#include <QtCore/QUrlQuery>
+#include <QtPositioning/private/qlocationutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QList<QGeoCoordinate> decodePolyline(const QString &polylineString)
+{
+ QList<QGeoCoordinate> path;
+ if (polylineString.isEmpty())
+ return path;
+
+ QByteArray data = polylineString.toLatin1();
+
+ 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/1e5);
+ } else {
+ coord.setLongitude(coord.longitude() + (double)diff/1e5);
+ path.append(coord);
+ }
+
+ parsingLatitude = !parsingLatitude;
+
+ value = 0;
+ shift = 0;
+ }
+
+ return path;
+}
+
+static QString cardinalDirection4(QLocationUtils::CardinalDirection direction)
+{
+ switch (direction) {
+ case QLocationUtils::CardinalN:
+ //: Always used in "Head %1 [onto <street name>]"
+ return QGeoRouteParserOsrmV5::tr("North");
+ case QLocationUtils::CardinalE:
+ return QGeoRouteParserOsrmV5::tr("East");
+ case QLocationUtils::CardinalS:
+ return QGeoRouteParserOsrmV5::tr("South");
+ case QLocationUtils::CardinalW:
+ return QGeoRouteParserOsrmV5::tr("West");
+ default:
+ return QString();
+ }
+}
+
+static QString exitOrdinal(int exit)
+{
+ static QList<QString> ordinals;
+
+ if (!ordinals.size()) {
+ ordinals.append(QStringLiteral(""));
+ //: always used in " and take the %1 exit [onto <street name>]"
+ ordinals.append(QGeoRouteParserOsrmV5::tr("first", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("second", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("third", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("fourth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("fifth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("sixth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("seventh", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("eighth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("ninth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("tenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("eleventh", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("twelfth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("thirteenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("fourteenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("fifteenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("sixteenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("seventeenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("eighteenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("nineteenth", "roundabout exit"));
+ ordinals.append(QGeoRouteParserOsrmV5::tr("twentieth", "roundabout exit"));
+ };
+
+ if (exit < 1 || exit > ordinals.size())
+ return QString();
+ return ordinals[exit];
+}
+
+static QString exitDirection(int exit, const QString &wayName)
+{
+ /*: Always appended to one of the following strings:
+ - "Enter the roundabout"
+ - "Enter the rotary"
+ - "Enter the rotary <rotaryname>"
+ */
+ static QString directionExit = QGeoRouteParserOsrmV5::tr(" and take the %1 exit");
+ static QString directionExitOnto = QGeoRouteParserOsrmV5::tr(" and take the %1 exit onto %2");
+
+ if (exit < 1 || exit > 20)
+ return QString();
+ if (wayName.isEmpty())
+ return directionExit.arg(exitOrdinal(exit));
+ else
+ return directionExitOnto.arg(exitOrdinal(exit), wayName);
+}
+
+static QString instructionArrive(QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionForward:
+ return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, straight ahead");
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, on the left");
+ case QGeoManeuver::DirectionUTurnRight:
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, on the right");
+ default:
+ return QGeoRouteParserOsrmV5::tr("You have arrived at your destination");
+ }
+}
+
+static QString instructionContinue(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue straight on %1").arg(wayName);
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue slightly left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue slightly left on %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue slightly right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue slightly right on %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn");
+ else
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue on %1").arg(wayName);
+ }
+}
+
+static QString instructionDepart(const QJsonObject &maneuver, const QString &wayName)
+{
+ double bearing = maneuver.value(QLatin1String("bearing_after")).toDouble(-1.0);
+ if (bearing >= 0.0) {
+ if (wayName.isEmpty())
+ //: %1 is "North", "South", "East" or "West"
+ return QGeoRouteParserOsrmV5::tr("Head %1").arg(cardinalDirection4(QLocationUtils::azimuthToCardinalDirection4(bearing)));
+ else
+ return QGeoRouteParserOsrmV5::tr("Head %1 onto %2").arg(cardinalDirection4(QLocationUtils::azimuthToCardinalDirection4(bearing)), wayName);
+ } else {
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Depart");
+ else
+ return QGeoRouteParserOsrmV5::tr("Depart onto %1").arg(wayName);
+ }
+}
+
+static QString instructionEndOfRoad(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, turn left");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, turn left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, turn right");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, turn right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, make a U-turn");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, make a U-turn onto %1").arg(wayName);
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, continue straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, continue straight onto %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, continue");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the end of the road, continue onto %1").arg(wayName);
+ }
+}
+
+static QString instructionFerry(const QString &wayName)
+{
+ QString instruction = QGeoRouteParserOsrmV5::tr("Take the ferry");
+ if (!wayName.isEmpty())
+ instruction += QLatin1String(" [") + wayName + QLatin1Char(']');
+
+ return instruction;
+}
+
+static QString instructionFork(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionHardLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp left");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, turn left");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, turn left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, keep left");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, keep left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp right");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, turn right");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, turn right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, keep right");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, keep right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn");
+ else
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, continue straight ahead");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, continue straight ahead onto %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the fork, continue");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the fork, continue onto %1").arg(wayName);
+ }
+}
+
+static QString instructionMerge(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionHardLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge sharply left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge sharply left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge slightly left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge slightly left on %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnRight:
+ case QGeoManeuver::DirectionHardRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge sharply right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge sharply right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge slightly right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge slightly right on %1").arg(wayName);
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge straight on %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Merge");
+ else
+ return QGeoRouteParserOsrmV5::tr("Merge onto %1").arg(wayName);
+ }
+}
+
+static QString instructionNewName(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionHardLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Take a sharp left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Take a sharp left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue slightly left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue slightly left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Take a sharp right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Take a sharp right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Contine slightly right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Contine slightly right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn");
+ else
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue straight onto %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue onto %1").arg(wayName);
+ }
+}
+
+static QString instructionNotification(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue on the left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue on the left on %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnRight:
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Contine on the right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Contine on the right on %1").arg(wayName);
+ case QGeoManeuver::DirectionForward:
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue on %1").arg(wayName);
+ }
+}
+
+static QString instructionOffRamp(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Take the ramp on the left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Take the ramp on the left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnRight:
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Take the ramp on the right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Take the ramp on the right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionForward:
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Take the ramp");
+ else
+ return QGeoRouteParserOsrmV5::tr("Take the ramp onto %1").arg(wayName);
+ }
+}
+
+static QString instructionOnRamp(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ return instructionOffRamp(wayName, direction);
+}
+
+static QString instructionPushingBike(const QString &wayName)
+{
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Get off the bike and push");
+ else
+ return QGeoRouteParserOsrmV5::tr("Get off the bike and push onto %1").arg(wayName);
+}
+
+static QString instructionRotary(const QJsonObject &step, const QJsonObject &maneuver, const QString &wayName)
+{
+ QString instruction;
+ QString rotaryName = step.value(QLatin1String("rotary_name")).toString();
+ //QString modifier = maneuver.value(QLatin1String("modifier")).toString(); // Apparently not used for rotaries
+ int exit = maneuver.value(QLatin1String("exit")).toInt(0);
+
+ //: This string will be prepended to " and take the <nth> exit [onto <streetname>]
+ instruction += QGeoRouteParserOsrmV5::tr("Enter the rotary");
+ if (!rotaryName.isEmpty())
+ instruction += QLatin1Char(' ') + rotaryName;
+ instruction += exitDirection(exit, wayName);
+ return instruction;
+}
+
+static QString instructionRoundabout(const QJsonObject &maneuver, const QString &wayName)
+{
+ QString instruction;
+ //QString modifier = maneuver.value(QLatin1String("modifier")).toString(); // Apparently not used for rotaries
+ int exit = maneuver.value(QLatin1String("exit")).toInt(0);
+
+ //: This string will be prepended to " and take the <nth> exit [onto <streetname>]
+ instruction += QGeoRouteParserOsrmV5::tr("Enter the roundabout");
+ instruction += exitDirection(exit, wayName);
+ return instruction;
+}
+
+static QString instructionRoundaboutTurn(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, continue straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, continue straight on %1").arg(wayName);
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, turn left");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, turn left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, turn right");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, turn right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, turn around");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, turn around onto %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, continue");
+ else
+ return QGeoRouteParserOsrmV5::tr("At the roundabout, continue onto %1").arg(wayName);
+ }
+}
+
+static QString instructionTrain(const QString &wayName)
+{
+ QString instruction = QGeoRouteParserOsrmV5::tr("Take the train");
+ if (!wayName.isEmpty())
+ instruction += QLatin1String(" [") + wayName + QLatin1Char(']');
+
+ return instruction;
+}
+
+static QString instructionTurn(const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ switch (direction) {
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Go straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("Go straight onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardLeft:
+ case QGeoManeuver::DirectionLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn slightly left");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn slightly left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ case QGeoManeuver::DirectionRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn slightly right");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn slightly right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn");
+ else
+ return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
+ default:
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Turn");
+ else
+ return QGeoRouteParserOsrmV5::tr("Turn onto %1").arg(wayName);
+ }
+}
+
+static QString instructionUseLane(const QJsonObject &maneuver, const QString &wayName, QGeoManeuver::InstructionDirection direction)
+{
+ QString laneTypes = maneuver.value(QLatin1String("laneTypes")).toString();
+ QString laneInstruction;
+ if (laneTypes == QLatin1String("xo") || laneTypes == QLatin1String("xoo") || laneTypes == QLatin1String("xxo"))
+ //: "and <instruction direction> [onto <street name>] will be appended to this string. E.g., "Keep right and make a sharp left"
+ laneInstruction = QLatin1String("Keep right");
+ else if (laneTypes == QLatin1String("ox") || laneTypes == QLatin1String("oox") || laneTypes == QLatin1String("oxx"))
+ laneInstruction = QLatin1String("Keep left");
+ else if (laneTypes == QLatin1String("xox"))
+ laneInstruction = QLatin1String("Use the middle lane");
+ else if (laneTypes == QLatin1String("oxo"))
+ laneInstruction = QLatin1String("Use the left or the right lane");
+
+ if (laneInstruction.isEmpty()) {
+ if (wayName.isEmpty())
+ return QGeoRouteParserOsrmV5::tr("Continue straight");
+ else
+ return QGeoRouteParserOsrmV5::tr("Continue straight onto %1").arg(wayName);
+ }
+
+ switch (direction) {
+ case QGeoManeuver::DirectionForward:
+ if (wayName.isEmpty())
+ //: This string will be prepended with lane instructions. E.g., "Use the left or the right lane and continue straight"
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and continue straight");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and continue straight onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardLeft:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp left");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLeft:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn left");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightLeft:
+ case QGeoManeuver::DirectionBearLeft:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight left");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight left onto %1").arg(wayName);
+ case QGeoManeuver::DirectionHardRight:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp right");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionRight:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn right");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionLightRight:
+ case QGeoManeuver::DirectionBearRight:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight right");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight right onto %1").arg(wayName);
+ case QGeoManeuver::DirectionUTurnLeft:
+ case QGeoManeuver::DirectionUTurnRight:
+ if (wayName.isEmpty())
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a U-turn");
+ else
+ return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a U-turn onto %1").arg(wayName);
+ default:
+ return laneInstruction;
+ }
+}
+
+static QString instructionText(const QJsonObject &step, const QJsonObject &maneuver, QGeoManeuver::InstructionDirection direction) {
+ QString modifier;
+ if (maneuver.value(QLatin1String("modifier")).isString())
+ modifier = maneuver.value(QLatin1String("modifier")).toString();
+ QString maneuverType;
+ if (maneuver.value(QLatin1String("type")).isString())
+ maneuverType = maneuver.value(QLatin1String("type")).toString();
+ QString wayName = QStringLiteral("unknown street");
+ if (step.value(QLatin1String("name")).isString())
+ wayName = step.value(QLatin1String("name")).toString();
+
+
+ if (maneuverType == QLatin1String("arrive"))
+ return instructionArrive(direction);
+ else if (maneuverType == QLatin1String("continue"))
+ return instructionContinue(wayName, direction);
+ else if (maneuverType == QLatin1String("depart"))
+ return instructionDepart(maneuver, wayName);
+ else if (maneuverType == QLatin1String("end of road"))
+ return instructionEndOfRoad(wayName, direction);
+ else if (maneuverType == QLatin1String("ferry"))
+ return instructionFerry(wayName);
+ else if (maneuverType == QLatin1String("fork"))
+ return instructionFork(wayName, direction);
+ else if (maneuverType == QLatin1String("merge"))
+ return instructionMerge(wayName, direction);
+ else if (maneuverType == QLatin1String("new name"))
+ return instructionNewName(wayName, direction);
+ else if (maneuverType == QLatin1String("notification"))
+ return instructionNotification(wayName, direction);
+ else if (maneuverType == QLatin1String("off ramp"))
+ return instructionOffRamp(wayName, direction);
+ else if (maneuverType == QLatin1String("on ramp"))
+ return instructionOnRamp(wayName, direction);
+ else if (maneuverType == QLatin1String("pushing bike"))
+ return instructionPushingBike(wayName);
+ else if (maneuverType == QLatin1String("rotary"))
+ return instructionRotary(step, maneuver, wayName);
+ else if (maneuverType == QLatin1String("roundabout"))
+ return instructionRoundabout(maneuver, wayName);
+ else if (maneuverType == QLatin1String("roundabout turn"))
+ return instructionRoundaboutTurn(wayName, direction);
+ else if (maneuverType == QLatin1String("train"))
+ return instructionTrain(wayName);
+ else if (maneuverType == QLatin1String("turn"))
+ return instructionTurn(wayName, direction);
+ else if (maneuverType == QLatin1String("use lane"))
+ return instructionUseLane(maneuver, wayName, direction);
+ else
+ return maneuverType + QLatin1String(" to/onto ") + wayName;
+}
+
+static QGeoManeuver::InstructionDirection instructionDirection(const QJsonObject &maneuver)
+{
+ QString modifier;
+ if (maneuver.value(QLatin1String("modifier")).isString())
+ modifier = maneuver.value(QLatin1String("modifier")).toString();
+
+ if (modifier.isEmpty())
+ return QGeoManeuver::NoDirection;
+ else if (modifier == QLatin1String("straight"))
+ return QGeoManeuver::DirectionForward;
+ else if (modifier == QLatin1String("right"))
+ return QGeoManeuver::DirectionRight;
+ else if (modifier == QLatin1String("sharp right"))
+ return QGeoManeuver::DirectionHardRight;
+ else if (modifier == QLatin1String("slight right"))
+ return QGeoManeuver::DirectionLightRight;
+ else if (modifier == QLatin1String("uturn"))
+ return QGeoManeuver::DirectionUTurnRight;
+ else if (modifier == QLatin1String("left"))
+ return QGeoManeuver::DirectionLeft;
+ else if (modifier == QLatin1String("sharp left"))
+ return QGeoManeuver::DirectionHardLeft;
+ else if (modifier == QLatin1String("slight left"))
+ return QGeoManeuver::DirectionLightLeft;
+ else
+ return QGeoManeuver::NoDirection;
+}
+
+static QGeoRouteSegment parseStep(const QJsonObject &step) {
+ // OSRM Instructions documentation: https://github.com/Project-OSRM/osrm-text-instructions/blob/master/instructions.json
+ QGeoRouteSegment segment;
+ if (!step.value(QLatin1String("maneuver")).isObject())
+ return segment;
+ QJsonObject maneuver = step.value(QLatin1String("maneuver")).toObject();
+ if (!step.value(QLatin1String("duration")).isDouble())
+ return segment;
+ if (!step.value(QLatin1String("distance")).isDouble())
+ return segment;
+ if (!step.value(QLatin1String("intersections")).isArray())
+ return segment;
+ if (!maneuver.value(QLatin1String("location")).isArray())
+ return segment;
+
+ double time = step.value(QLatin1String("duration")).toDouble();
+ double distance = step.value(QLatin1String("distance")).toDouble();
+
+ QJsonArray position = maneuver.value(QLatin1String("location")).toArray();
+ if (position.isEmpty())
+ return segment;
+ double latitude = position[1].toDouble();
+ double longitude = position[0].toDouble();
+ QGeoCoordinate coord(latitude, longitude);
+
+ QString geometry = step.value(QLatin1String("geometry")).toString();
+ QList<QGeoCoordinate> path = decodePolyline(geometry);
+
+ QGeoManeuver geoManeuver;
+ geoManeuver.setDirection(instructionDirection(maneuver));
+ geoManeuver.setDistanceToNextInstruction(distance);
+ geoManeuver.setTimeToNextInstruction(time);
+ geoManeuver.setInstructionText(instructionText(step, maneuver, geoManeuver.direction()));
+ geoManeuver.setPosition(coord);
+ geoManeuver.setWaypoint(coord);
+
+ segment.setDistance(distance);
+ segment.setPath(path);
+ segment.setTravelTime(time);
+ segment.setManeuver(geoManeuver);
+ return segment;
+}
+
+class QGeoRouteParserOsrmV5Private : public QGeoRouteParserPrivate
+{
+ Q_DECLARE_PUBLIC(QGeoRouteParserOsrmV5)
+public:
+ QGeoRouteParserOsrmV5Private();
+ virtual ~QGeoRouteParserOsrmV5Private();
+
+ QGeoRouteReply::Error parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const Q_DECL_OVERRIDE;
+ QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const Q_DECL_OVERRIDE;
+};
+
+QGeoRouteParserOsrmV5Private::QGeoRouteParserOsrmV5Private() : QGeoRouteParserPrivate()
+{
+}
+
+QGeoRouteParserOsrmV5Private::~QGeoRouteParserOsrmV5Private()
+{
+}
+
+QGeoRouteReply::Error QGeoRouteParserOsrmV5Private::parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const
+{
+ // OSRM v5 specs: https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md
+ QJsonDocument document = QJsonDocument::fromJson(reply);
+ if (document.isObject()) {
+ QJsonObject object = document.object();
+
+ QString status = object.value(QStringLiteral("code")).toString();
+ if (status != QLatin1String("Ok")) {
+ errorString = status;
+ return QGeoRouteReply::UnknownError;
+ }
+ if (!object.value(QLatin1String("routes")).isArray()) {
+ errorString = QLatin1String("No routes found");
+ return QGeoRouteReply::ParseError;
+ }
+
+ QJsonArray osrmRoutes = object.value(QLatin1String("routes")).toArray();
+ foreach (const QJsonValue &r, osrmRoutes) {
+ if (!r.isObject())
+ continue;
+ QJsonObject route = r.toObject();
+ if (!route.value(QLatin1String("legs")).isArray())
+ continue;
+ if (!route.value(QLatin1String("duration")).isDouble())
+ continue;
+ if (!route.value(QLatin1String("distance")).isDouble())
+ continue;
+
+ double distance = route.value(QLatin1String("distance")).toDouble();
+ double travelTime = route.value(QLatin1String("duration")).toDouble();
+ bool error = false;
+ QList<QGeoRouteSegment> segments;
+
+ QJsonArray legs = route.value(QLatin1String("legs")).toArray();
+ foreach (const QJsonValue &l, legs) {
+ if (!l.isObject()) { // invalid leg record
+ error = true;
+ break;
+ }
+ QJsonObject leg = l.toObject();
+ if (!leg.value(QLatin1String("steps")).isArray()) { // Invalid steps field
+ error = true;
+ break;
+ }
+ QJsonArray steps = leg.value(QLatin1String("steps")).toArray();
+ foreach (const QJsonValue &s, steps) {
+ if (!s.isObject()) {
+ error = true;
+ break;
+ }
+ QGeoRouteSegment segment = parseStep(s.toObject());
+ if (segment.isValid()) {
+ segments.append(segment);
+ } else {
+ error = true;
+ break;
+ }
+ }
+ if (error)
+ break;
+ }
+
+ if (!error) {
+ QList<QGeoCoordinate> path;
+ foreach (const QGeoRouteSegment &s, segments)
+ path.append(s.path());
+
+ for (int i = segments.size() - 1; i > 0; --i)
+ segments[i-1].setNextRouteSegment(segments[i]);
+
+ QGeoRoute r;
+ r.setDistance(distance);
+ r.setTravelTime(travelTime);
+ if (!path.isEmpty()) {
+ r.setPath(path);
+ r.setFirstRouteSegment(segments.first());
+ }
+ //r.setTravelMode(QGeoRouteRequest::CarTravel); // The only one supported by OSRM demo service, but other OSRM servers might do cycle or pedestrian too
+ routes.append(r);
+ }
+ }
+
+ // setError(QGeoRouteReply::NoError, status); // can't do this, or NoError is emitted and does damages
+ return QGeoRouteReply::NoError;
+ } else {
+ errorString = QStringLiteral("Couldn't parse json.");
+ return QGeoRouteReply::ParseError;
+ }
+}
+
+QUrl QGeoRouteParserOsrmV5Private::requestUrl(const QGeoRouteRequest &request, const QString &prefix) const
+{
+ QString routingUrl = prefix;
+ int notFirst = 0;
+ foreach (const QGeoCoordinate &c, request.waypoints()) {
+ if (notFirst)
+ routingUrl.append(QLatin1Char(';'));
+ routingUrl.append(QString::number(c.longitude())).append(QLatin1Char(',')).append(QString::number(c.latitude()));
+ ++notFirst;
+ }
+
+ QUrl url(routingUrl);
+ QUrlQuery query;
+ query.addQueryItem(QStringLiteral("overview"), QStringLiteral("full"));
+ query.addQueryItem(QStringLiteral("steps"), QStringLiteral("true"));
+ query.addQueryItem(QStringLiteral("geometries"), QStringLiteral("polyline"));
+ query.addQueryItem(QStringLiteral("alternatives"), QStringLiteral("true"));
+ url.setQuery(query);
+ return url;
+}
+
+QGeoRouteParserOsrmV5::QGeoRouteParserOsrmV5(QObject *parent) : QGeoRouteParser(*new QGeoRouteParserOsrmV5Private(), parent)
+{
+}
+
+QGeoRouteParserOsrmV5::~QGeoRouteParserOsrmV5()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/location/maps/qgeorouteparserosrmv5_p.h b/src/location/maps/qgeorouteparserosrmv5_p.h
new file mode 100644
index 00000000..47c68919
--- /dev/null
+++ b/src/location/maps/qgeorouteparserosrmv5_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtLocation module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGEOROUTEPARSEROSRMV5_H
+#define QGEOROUTEPARSEROSRMV5_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <QtLocation/private/qgeorouteparser_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGeoRouteParserOsrmV5Private;
+class Q_LOCATION_EXPORT QGeoRouteParserOsrmV5 : public QGeoRouteParser
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGeoRouteParserOsrmV5)
+
+public:
+ QGeoRouteParserOsrmV5(QObject *parent = Q_NULLPTR);
+ virtual ~QGeoRouteParserOsrmV5();
+
+private:
+ Q_DISABLE_COPY(QGeoRouteParserOsrmV5)
+};
+
+QT_END_NAMESPACE
+
+#endif // QGEOROUTEPARSEROSRMV5_H
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 <QtCore/QJsonDocument>
-#include <QtCore/QJsonObject>
-#include <QtCore/QJsonArray>
-#include <QtLocation/QGeoRouteSegment>
-#include <QtLocation/QGeoManeuver>
+#include "qgeoroutingmanagerengineosm.h"
QT_BEGIN_NAMESPACE
-static QList<QGeoCoordinate> parsePolyline(const QByteArray &data)
-{
- QList<QGeoCoordinate> 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<QGeoCoordinate> 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<QGeoRoute> 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<QGeoRoutingManagerEngineOsm *>(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<QGeoRoute> 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 <QtCore/QUrlQuery>
@@ -51,7 +53,14 @@ QGeoRoutingManagerEngineOsm::QGeoRoutingManagerEngineOsm(const QVariantMap &para
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<QGeoRouteReply *>(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 <QtLocation/QGeoServiceProvider>
#include <QtLocation/QGeoRoutingManagerEngine>
+#include <QtLocation/private/qgeorouteparser_p.h>
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;
};
diff --git a/src/positioning/qlocationutils_p.h b/src/positioning/qlocationutils_p.h
index 8c39463f..31df06fe 100644
--- a/src/positioning/qlocationutils_p.h
+++ b/src/positioning/qlocationutils_p.h
@@ -45,6 +45,7 @@
//
#include <QtCore/QtGlobal>
+#include <math.h>
QT_BEGIN_NAMESPACE
class QTime;
@@ -54,6 +55,25 @@ class QGeoPositionInfo;
class QLocationUtils
{
public:
+ enum CardinalDirection {
+ CardinalN,
+ CardinalE,
+ CardinalS,
+ CardinalW,
+ CardinalNE,
+ CardinalSE,
+ CardinalSW,
+ CardinalNW,
+ CardinalNNE,
+ CardinalENE,
+ CardinalESE,
+ CardinalSSE,
+ CardinalSSW,
+ CardinalWSW,
+ CardinalWNW,
+ CardinalNNW
+ };
+
inline static bool isValidLat(double lat) {
return lat >= -90 && lat <= 90;
}
@@ -77,6 +97,79 @@ public:
return lng;
}
+ inline static CardinalDirection azimuthToCardinalDirection4(double azimuth)
+ {
+ azimuth = fmod(azimuth, 360.0);
+ if (azimuth < 45.0 || azimuth > 315.0 )
+ return CardinalN;
+ else if (azimuth < 135.0)
+ return CardinalE;
+ else if (azimuth < 225.0)
+ return CardinalS;
+ else
+ return CardinalW;
+ }
+
+ inline static CardinalDirection azimuthToCardinalDirection8(double azimuth)
+ {
+ azimuth = fmod(azimuth, 360.0);
+ if (azimuth < 22.5 || azimuth > 337.5 )
+ return CardinalN;
+ else if (azimuth < 67.5)
+ return CardinalNE;
+ else if (azimuth < 112.5)
+ return CardinalE;
+ else if (azimuth < 157.5)
+ return CardinalSE;
+ else if (azimuth < 202.5)
+ return CardinalS;
+
+ else if (azimuth < 247.5)
+ return CardinalSW;
+ else if (azimuth < 292.5)
+ return CardinalW;
+ else
+ return CardinalNW;
+ }
+
+ inline static CardinalDirection azimuthToCardinalDirection16(double azimuth)
+ {
+ azimuth = fmod(azimuth, 360.0);
+ if (azimuth < 11.5 || azimuth > 348.75 )
+ return CardinalN;
+ else if (azimuth < 33.75)
+ return CardinalNNE;
+ else if (azimuth < 56.25)
+ return CardinalNE;
+ else if (azimuth < 78.75)
+ return CardinalENE;
+ else if (azimuth < 101.25)
+ return CardinalE;
+ else if (azimuth < 123.75)
+ return CardinalESE;
+ else if (azimuth < 146.25)
+ return CardinalSE;
+ else if (azimuth < 168.75)
+ return CardinalSSE;
+ else if (azimuth < 191.25)
+ return CardinalS;
+
+ else if (azimuth < 213.75)
+ return CardinalSSW;
+ else if (azimuth < 236.25)
+ return CardinalSW;
+ else if (azimuth < 258.75)
+ return CardinalWSW;
+ else if (azimuth < 281.25)
+ return CardinalW;
+ else if (azimuth < 303.75)
+ return CardinalWNW;
+ else if (azimuth < 326.25)
+ return CardinalNW;
+ else
+ return CardinalNNW;
+ }
+
/*
Creates a QGeoPositionInfo from a GGA, GLL, RMC, VTG or ZDA sentence.