summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-10-12 12:39:13 +0200
committerLiang Qi <liang.qi@qt.io>2016-10-12 12:39:13 +0200
commit3abe52c28d9d960b284586e5b6f0277f91362ee9 (patch)
tree201f539b5ac6dddc9543daaf7ad7b7a18c5f8f14
parent3f813d1c8c24e5da67d3f096eb3f5c73e760e641 (diff)
parent8bc909704986209e98feae8057b0e3ce07a28cd8 (diff)
downloadqtlocation-3abe52c28d9d960b284586e5b6f0277f91362ee9.tar.gz
Merge remote-tracking branch 'origin/5.6' into 5.7.1
Conflicts: src/location/maps/maps.pri Change-Id: I08158c8ba03d9345097cc4017556971ba3ec0dc6
-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.cpp326
-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, 1903 insertions, 326 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 c8e28bab..db43962e 100644
--- a/src/location/maps/maps.pri
+++ b/src/location/maps/maps.pri
@@ -54,6 +54,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 += \
@@ -84,6 +88,12 @@ SOURCES += \
maps/qgeotiledmapreply.cpp \
maps/qgeotilespec.cpp \
maps/qgeotiledmap.cpp \
- maps/qgeotiledmapscene.cpp
+ maps/qgeotiledmapscene.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 a104df54..da28317f 100644
--- a/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
+++ b/src/plugins/geoservices/osm/qgeoroutereplyosm.cpp
@@ -38,207 +38,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)
@@ -265,70 +68,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)
@@ -341,59 +80,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);
-
- 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 (m_reply->error() != QNetworkReply::NoError) {
+ setError(QGeoRouteReply::CommunicationError, m_reply->errorString());
+ m_reply->deleteLater();
+ m_reply = 0;
+ return;
+ }
- 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);
- }
- }
+ QGeoRoutingManagerEngineOsm *engine = qobject_cast<QGeoRoutingManagerEngineOsm *>(parent());
+ const QGeoRouteParser *parser = engine->routeParser();
- setRoutes(routes);
+ QList<QGeoRoute> routes;
+ QString errorString;
+ QGeoRouteReply::Error error = parser->parseReply(routes, errorString, m_reply->readAll());
+ if (error == QGeoRouteReply::NoError) {
+ 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 {
- 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 0d7277a5..12db22a9 100644
--- a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp
+++ b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp
@@ -39,6 +39,8 @@
#include "qgeoroutingmanagerengineosm.h"
#include "qgeoroutereplyosm.h"
+#include "QtLocation/private/qgeorouteparserosrmv4_p.h"
+#include "QtLocation/private/qgeorouteparserosrmv5_p.h"
#include <QtCore/QUrlQuery>
@@ -57,7 +59,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();
@@ -70,20 +79,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);
@@ -96,6 +94,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 0dac897a..8e2d7f50 100644
--- a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h
+++ b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.h
@@ -42,6 +42,7 @@
#include <QtLocation/QGeoServiceProvider>
#include <QtLocation/QGeoRoutingManagerEngine>
+#include <QtLocation/private/qgeorouteparser_p.h>
QT_BEGIN_NAMESPACE
@@ -58,6 +59,7 @@ public:
~QGeoRoutingManagerEngineOsm();
QGeoRouteReply *calculateRoute(const QGeoRouteRequest &request);
+ const QGeoRouteParser *routeParser() const;
private Q_SLOTS:
void replyFinished();
@@ -65,6 +67,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 b5d90b93..00c4d3e3 100644
--- a/src/positioning/qlocationutils_p.h
+++ b/src/positioning/qlocationutils_p.h
@@ -51,6 +51,7 @@
//
#include <QtCore/QtGlobal>
+#include <math.h>
QT_BEGIN_NAMESPACE
class QTime;
@@ -60,6 +61,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;
}
@@ -83,6 +103,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.