diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2022-10-28 11:35:20 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2022-12-02 10:48:15 +0100 |
commit | 5b1981a36d1ee3fbf0104bb3a7e7667408d7126a (patch) | |
tree | 245704ec7da60d3de1e5b134c7403b92317759f2 /src/plugins | |
parent | 0ee94fbbba4f91209e6075fa033cd58300549286 (diff) | |
download | qtlocation-5b1981a36d1ee3fbf0104bb3a7e7667408d7126a.tar.gz |
Clean up: move QGeoRouteParserOsrmV4 into OSM plugin
It's only used there. Need to privately export QGeoRouteParserPrivate
for this.
Change-Id: I0342dc31836a9db731f495434b9d4c7dd5973af2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Diffstat (limited to 'src/plugins')
4 files changed, 488 insertions, 1 deletions
diff --git a/src/plugins/geoservices/osm/CMakeLists.txt b/src/plugins/geoservices/osm/CMakeLists.txt index f7f54c78..c35f4480 100644 --- a/src/plugins/geoservices/osm/CMakeLists.txt +++ b/src/plugins/geoservices/osm/CMakeLists.txt @@ -17,6 +17,7 @@ qt_internal_add_plugin(QGeoServiceProviderFactoryOsmPlugin qgeotiledmaposm.h qgeotiledmaposm.cpp qgeofiletilecacheosm.h qgeofiletilecacheosm.cpp qgeotileproviderosm.h qgeotileproviderosm.cpp + qgeorouteparserosrmv4_p.h qgeorouteparserosrmv4.cpp LIBRARIES Qt::Core Qt::Network diff --git a/src/plugins/geoservices/osm/qgeorouteparserosrmv4.cpp b/src/plugins/geoservices/osm/qgeorouteparserosrmv4.cpp new file mode 100644 index 00000000..d8e162ae --- /dev/null +++ b/src/plugins/geoservices/osm/qgeorouteparserosrmv4.cpp @@ -0,0 +1,411 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgeorouteparserosrmv4_p.h" +#include "qgeoroutesegment.h" +#include "qgeomaneuver.h" + +#include <QtLocation/private/qgeorouteparser_p_p.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, QGeoRouteParser::TrafficSide trafficSide) +{ + 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")) { + switch (trafficSide) { + case QGeoRouteParser::RightHandTraffic: + return QGeoManeuver::DirectionUTurnLeft; + case QGeoRouteParser::LeftHandTraffic: + return QGeoManeuver::DirectionUTurnRight; + } + 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, QGeoRouteParser::TrafficSide trafficSide) +{ + QGeoRoute route; + + const QList<QGeoCoordinate> path = parsePolyline(geometry); + + QGeoRouteSegment firstSegment; + int firstPosition = -1; + + for (qsizetype i = instructions.count() - 1; i >= 0; --i) { + const 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, trafficSide)); + 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)); + + 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 override; + QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const 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, trafficSide); + + routes.append(route); + + const QJsonArray alternativeSummaries = + object.value(QStringLiteral("alternative_summaries")).toArray(); + const QJsonArray alternativeGeometries = + object.value(QStringLiteral("alternative_geometries")).toArray(); + const QJsonArray alternativeInstructions = + object.value(QStringLiteral("alternative_instructions")).toArray(); + + if (alternativeSummaries.count() == alternativeGeometries.count() && + alternativeSummaries.count() == alternativeInstructions.count()) { + for (qsizetype i = 0; i < alternativeSummaries.count(); ++i) { + route = constructRoute(alternativeGeometries.at(i).toString().toLatin1(), + alternativeInstructions.at(i).toArray(), + alternativeSummaries.at(i).toObject(), + trafficSide); + //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")); + + for (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/plugins/geoservices/osm/qgeorouteparserosrmv4_p.h b/src/plugins/geoservices/osm/qgeorouteparserosrmv4_p.h new file mode 100644 index 00000000..fde2e759 --- /dev/null +++ b/src/plugins/geoservices/osm/qgeorouteparserosrmv4_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtLocation module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.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 QGeoRouteParserOsrmV4 : public QGeoRouteParser +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QGeoRouteParserOsrmV4) + +public: + QGeoRouteParserOsrmV4(QObject *parent = nullptr); + virtual ~QGeoRouteParserOsrmV4(); + +private: + Q_DISABLE_COPY(QGeoRouteParserOsrmV4) +}; + +QT_END_NAMESPACE + +#endif // QGEOROUTEPARSEROSRMV4_H diff --git a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp index 3bbe6576..680a2b72 100644 --- a/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp +++ b/src/plugins/geoservices/osm/qgeoroutingmanagerengineosm.cpp @@ -39,7 +39,7 @@ #include "qgeoroutingmanagerengineosm.h" #include "qgeoroutereplyosm.h" -#include "QtLocation/private/qgeorouteparserosrmv4_p.h" +#include "qgeorouteparserosrmv4_p.h" #include "QtLocation/private/qgeorouteparserosrmv5_p.h" #include <QtCore/QUrlQuery> |