Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgeorouteparserosrmv4.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include "qgeoroutesegment.h"
6#include "qgeomaneuver.h"
7
8#include <QtLocation/private/qgeorouteparser_p_p.h>
9#include <QtCore/private/qobject_p.h>
10#include <QtCore/QJsonDocument>
11#include <QtCore/QJsonObject>
12#include <QtCore/QJsonArray>
13#include <QtCore/QUrlQuery>
14
16
17static QList<QGeoCoordinate> parsePolyline(const QByteArray &data)
18{
19 QList<QGeoCoordinate> path;
20
21 bool parsingLatitude = true;
22
23 int shift = 0;
24 int value = 0;
25
27
28 for (int i = 0; i < data.length(); ++i) {
29 unsigned char c = data.at(i) - 63;
30
31 value |= (c & 0x1f) << shift;
32 shift += 5;
33
34 // another chunk
35 if (c & 0x20)
36 continue;
37
38 int diff = (value & 1) ? ~(value >> 1) : (value >> 1);
39
40 if (parsingLatitude) {
41 coord.setLatitude(coord.latitude() + (double)diff/1e6);
42 } else {
43 coord.setLongitude(coord.longitude() + (double)diff/1e6);
44 path.append(coord);
45 }
46
47 parsingLatitude = !parsingLatitude;
48
49 value = 0;
50 shift = 0;
51 }
52
53 return path;
54}
55
57{
58 if (instructionCode == QLatin1String("0"))
60 else if (instructionCode == QLatin1String("1"))
62 else if (instructionCode == QLatin1String("2"))
64 else if (instructionCode == QLatin1String("3"))
66 else if (instructionCode == QLatin1String("4"))
68 else if (instructionCode == QLatin1String("5")) {
69 switch (trafficSide) {
74 }
76 } else if (instructionCode == QLatin1String("6"))
78 else if (instructionCode == QLatin1String("7"))
80 else if (instructionCode == QLatin1String("8"))
82 else if (instructionCode == QLatin1String("9"))
84 else if (instructionCode == QLatin1String("10"))
86 else if (instructionCode == QLatin1String("11"))
88 else if (instructionCode == QLatin1String("12"))
90 else if (instructionCode == QLatin1String("13"))
92 else if (instructionCode == QLatin1String("14"))
94 else if (instructionCode == QLatin1String("15"))
96 else
98}
99
100static QString osrmInstructionText(const QString &instructionCode, const QString &wayname)
101{
102 if (instructionCode == QLatin1String("0")) {
103 return QString();
104 } else if (instructionCode == QLatin1String("1")) {
105 if (wayname.isEmpty())
106 return QGeoRouteParserOsrmV4::tr("Go straight.");
107 else
108 return QGeoRouteParserOsrmV4::tr("Go straight onto %1.").arg(wayname);
109 } else if (instructionCode == QLatin1String("2")) {
110 if (wayname.isEmpty())
111 return QGeoRouteParserOsrmV4::tr("Turn slightly right.");
112 else
113 return QGeoRouteParserOsrmV4::tr("Turn slightly right onto %1.").arg(wayname);
114 } else if (instructionCode == QLatin1String("3")) {
115 if (wayname.isEmpty())
116 return QGeoRouteParserOsrmV4::tr("Turn right.");
117 else
118 return QGeoRouteParserOsrmV4::tr("Turn right onto %1.").arg(wayname);
119 } else if (instructionCode == QLatin1String("4")) {
120 if (wayname.isEmpty())
121 return QGeoRouteParserOsrmV4::tr("Make a sharp right.");
122 else
123 return QGeoRouteParserOsrmV4::tr("Make a sharp right onto %1.").arg(wayname);
124 }
125 else if (instructionCode == QLatin1String("5")) {
126 return QGeoRouteParserOsrmV4::tr("When it is safe to do so, perform a U-turn.");
127 } else if (instructionCode == QLatin1String("6")) {
128 if (wayname.isEmpty())
129 return QGeoRouteParserOsrmV4::tr("Make a sharp left.");
130 else
131 return QGeoRouteParserOsrmV4::tr("Make a sharp left onto %1.").arg(wayname);
132 } else if (instructionCode == QLatin1String("7")) {
133 if (wayname.isEmpty())
134 return QGeoRouteParserOsrmV4::tr("Turn left.");
135 else
136 return QGeoRouteParserOsrmV4::tr("Turn left onto %1.").arg(wayname);
137 } else if (instructionCode == QLatin1String("8")) {
138 if (wayname.isEmpty())
139 return QGeoRouteParserOsrmV4::tr("Turn slightly left.");
140 else
141 return QGeoRouteParserOsrmV4::tr("Turn slightly left onto %1.").arg(wayname);
142 } else if (instructionCode == QLatin1String("9")) {
143 return QGeoRouteParserOsrmV4::tr("Reached waypoint.");
144 } else if (instructionCode == QLatin1String("10")) {
145 if (wayname.isEmpty())
146 return QGeoRouteParserOsrmV4::tr("Head on.");
147 else
148 return QGeoRouteParserOsrmV4::tr("Head onto %1.").arg(wayname);
149 } else if (instructionCode == QLatin1String("11")) {
150 return QGeoRouteParserOsrmV4::tr("Enter the roundabout.");
151 } else if (instructionCode == QLatin1String("11-1")) {
152 if (wayname.isEmpty())
153 return QGeoRouteParserOsrmV4::tr("At the roundabout take the first exit.");
154 else
155 return QGeoRouteParserOsrmV4::tr("At the roundabout take the first exit onto %1.").arg(wayname);
156 } else if (instructionCode == QLatin1String("11-2")) {
157 if (wayname.isEmpty())
158 return QGeoRouteParserOsrmV4::tr("At the roundabout take the second exit.");
159 else
160 return QGeoRouteParserOsrmV4::tr("At the roundabout take the second exit onto %1.").arg(wayname);
161 } else if (instructionCode == QLatin1String("11-3")) {
162 if (wayname.isEmpty())
163 return QGeoRouteParserOsrmV4::tr("At the roundabout take the third exit.");
164 else
165 return QGeoRouteParserOsrmV4::tr("At the roundabout take the third exit onto %1.").arg(wayname);
166 } else if (instructionCode == QLatin1String("11-4")) {
167 if (wayname.isEmpty())
168 return QGeoRouteParserOsrmV4::tr("At the roundabout take the fourth exit.");
169 else
170 return QGeoRouteParserOsrmV4::tr("At the roundabout take the fourth exit onto %1.").arg(wayname);
171 } else if (instructionCode == QLatin1String("11-5")) {
172 if (wayname.isEmpty())
173 return QGeoRouteParserOsrmV4::tr("At the roundabout take the fifth exit.");
174 else
175 return QGeoRouteParserOsrmV4::tr("At the roundabout take the fifth exit onto %1.").arg(wayname);
176 } else if (instructionCode == QLatin1String("11-6")) {
177 if (wayname.isEmpty())
178 return QGeoRouteParserOsrmV4::tr("At the roundabout take the sixth exit.");
179 else
180 return QGeoRouteParserOsrmV4::tr("At the roundabout take the sixth exit onto %1.").arg(wayname);
181 } else if (instructionCode == QLatin1String("11-7")) {
182 if (wayname.isEmpty())
183 return QGeoRouteParserOsrmV4::tr("At the roundabout take the seventh exit.");
184 else
185 return QGeoRouteParserOsrmV4::tr("At the roundabout take the seventh exit onto %1.").arg(wayname);
186 } else if (instructionCode == QLatin1String("11-8")) {
187 if (wayname.isEmpty())
188 return QGeoRouteParserOsrmV4::tr("At the roundabout take the eighth exit.");
189 else
190 return QGeoRouteParserOsrmV4::tr("At the roundabout take the eighth exit onto %1.").arg(wayname);
191 } else if (instructionCode == QLatin1String("11-9")) {
192 if (wayname.isEmpty())
193 return QGeoRouteParserOsrmV4::tr("At the roundabout take the ninth exit.");
194 else
195 return QGeoRouteParserOsrmV4::tr("At the roundabout take the ninth exit onto %1.").arg(wayname);
196 } else if (instructionCode == QLatin1String("12")) {
197 if (wayname.isEmpty())
198 return QGeoRouteParserOsrmV4::tr("Leave the roundabout.");
199 else
200 return QGeoRouteParserOsrmV4::tr("Leave the roundabout onto %1.").arg(wayname);
201 } else if (instructionCode == QLatin1String("13")) {
202 return QGeoRouteParserOsrmV4::tr("Stay on the roundabout.");
203 } else if (instructionCode == QLatin1String("14")) {
204 if (wayname.isEmpty())
205 return QGeoRouteParserOsrmV4::tr("Start at the end of the street.");
206 else
207 return QGeoRouteParserOsrmV4::tr("Start at the end of %1.").arg(wayname);
208 } else if (instructionCode == QLatin1String("15")) {
209 return QGeoRouteParserOsrmV4::tr("You have reached your destination.");
210 } else {
211 return QGeoRouteParserOsrmV4::tr("Don't know what to say for '%1'").arg(instructionCode);
212 }
213}
214
215static QGeoRoute constructRoute(const QByteArray &geometry, const QJsonArray &instructions,
216 const QJsonObject &summary, QGeoRouteParser::TrafficSide trafficSide)
217{
218 QGeoRoute route;
219
220 const QList<QGeoCoordinate> path = parsePolyline(geometry);
221
222 QGeoRouteSegment firstSegment;
223 int firstPosition = -1;
224
225 for (qsizetype i = instructions.count() - 1; i >= 0; --i) {
226 const QJsonArray instruction = instructions.at(i).toArray();
227
228 if (instruction.count() < 8) {
229 qWarning("Instruction does not contain enough fields.");
230 continue;
231 }
232
233 const QString instructionCode = instruction.at(0).toString();
234 const QString wayname = instruction.at(1).toString();
235 double segmentLength = instruction.at(2).toDouble();
236 int position = instruction.at(3).toDouble();
237 int time = instruction.at(4).toDouble();
238 //const QString segmentLengthString = instruction.at(5).toString();
239 //const QString direction = instruction.at(6).toString();
240 //double azimuth = instruction.at(7).toDouble();
241
243 segment.setDistance(segmentLength);
244
245 QGeoManeuver maneuver;
246 maneuver.setDirection(osrmInstructionDirection(instructionCode, trafficSide));
247 maneuver.setDistanceToNextInstruction(segmentLength);
248 maneuver.setInstructionText(osrmInstructionText(instructionCode, wayname));
249 maneuver.setPosition(path.at(position));
251
252 segment.setManeuver(maneuver);
253
254 if (firstPosition == -1)
255 segment.setPath(path.mid(position));
256 else
257 segment.setPath(path.mid(position, firstPosition - position));
258
259 segment.setTravelTime(time);
260
261 segment.setNextRouteSegment(firstSegment);
262
263 firstSegment = segment;
264 firstPosition = position;
265 }
266
267 route.setDistance(summary.value(QStringLiteral("total_distance")).toDouble());
268 route.setTravelTime(summary.value(QStringLiteral("total_time")).toDouble());
269 route.setFirstRouteSegment(firstSegment);
270 route.setPath(path);
271
272 return route;
273}
274
276{
277 Q_DECLARE_PUBLIC(QGeoRouteParserOsrmV4)
278public:
281
282 QGeoRouteReply::Error parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const override;
283 QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const override;
284};
285
289
293
294QGeoRouteReply::Error QGeoRouteParserOsrmV4Private::parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const
295{
296 // OSRM v4 specs: https://github.com/Project-OSRM/osrm-backend/wiki/Server-API---v4,-old
298
299 if (document.isObject()) {
300 QJsonObject object = document.object();
301
302 //double version = object.value(QStringLiteral("version")).toDouble();
303 int status = object.value(QStringLiteral("status")).toDouble();
304 QString statusMessage = object.value(QStringLiteral("status_message")).toString();
305
306 // status code 0 or 200 are case of success
307 // status code is 207 if no route was found
308 // an error occurred when trying to find a route
309 if (0 != status && 200 != status) {
310 errorString = statusMessage;
312 }
313
314 QJsonObject routeSummary = object.value(QStringLiteral("route_summary")).toObject();
315
316 QByteArray routeGeometry =
317 object.value(QStringLiteral("route_geometry")).toString().toLatin1();
318
319 QJsonArray routeInstructions = object.value(QStringLiteral("route_instructions")).toArray();
320
321 QGeoRoute route = constructRoute(routeGeometry, routeInstructions, routeSummary, trafficSide);
322
323 routes.append(route);
324
325 const QJsonArray alternativeSummaries =
326 object.value(QStringLiteral("alternative_summaries")).toArray();
327 const QJsonArray alternativeGeometries =
328 object.value(QStringLiteral("alternative_geometries")).toArray();
329 const QJsonArray alternativeInstructions =
330 object.value(QStringLiteral("alternative_instructions")).toArray();
331
332 if (alternativeSummaries.count() == alternativeGeometries.count() &&
333 alternativeSummaries.count() == alternativeInstructions.count()) {
334 for (qsizetype i = 0; i < alternativeSummaries.count(); ++i) {
335 route = constructRoute(alternativeGeometries.at(i).toString().toLatin1(),
336 alternativeInstructions.at(i).toArray(),
337 alternativeSummaries.at(i).toObject(),
339 //routes.append(route);
340 }
341 }
342
344 } else {
345 errorString = QStringLiteral("Couldn't parse json.");
347 }
348}
349
351{
352 QUrl url(prefix);
354
355 query.addQueryItem(QStringLiteral("instructions"), QStringLiteral("true"));
356
357 for (const QGeoCoordinate &c : request.waypoints()) {
358 query.addQueryItem(QStringLiteral("loc"), QString::number(c.latitude()) + QLatin1Char(',') +
359 QString::number(c.longitude()));
360 }
361
363 return url;
364}
365
370
374
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtPositioning
\inmodule QtLocation
void setInstructionText(const QString &instructionText)
void setTimeToNextInstruction(int secs)
void setDirection(InstructionDirection direction)
void setDistanceToNextInstruction(qreal distance)
void setPosition(const QGeoCoordinate &position)
InstructionDirection
\qmltype routeManeuver \inqmlmodule QtLocation
QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const override
QGeoRouteReply::Error parseReply(QList< QGeoRoute > &routes, QString &errorString, const QByteArray &reply) const override
QGeoRouteParserOsrmV4(QObject *parent=nullptr)
QGeoRouteParser::TrafficSide trafficSide
Error
Describes an error which prevented the completion of the operation.
\inmodule QtLocation
\inmodule QtLocation
void setDistance(qreal distance)
\inmodule QtLocation
Definition qgeoroute.h:24
void setFirstRouteSegment(const QGeoRouteSegment &routeSegment)
Sets the first route segment in the route to routeSegment.
void setDistance(qreal distance)
void setTravelTime(int secs)
void setPath(const QList< QGeoCoordinate > &path)
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
qsizetype count() const
Same as size().
Definition qjsonarray.h:42
QJsonValue at(qsizetype i) const
Returns a QJsonValue representing the value for index i.
\inmodule QtCore\reentrant
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
Parses json as a UTF-8 encoded JSON document, and creates a QJsonDocument from it.
\inmodule QtCore\reentrant
Definition qjsonobject.h:20
QJsonValue value(const QString &key) const
Returns a QJsonValue representing the value for the key key.
QJsonObject toObject() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QJsonArray toArray() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
\inmodule QtCore
Definition qobject.h:103
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
Definition qurlquery.h:20
void addQueryItem(const QString &key, const QString &value)
Appends the pair key = value to the end of the query string of the URL.
\inmodule QtCore
Definition qurl.h:94
void setQuery(const QString &query, ParsingMode mode=TolerantMode)
Sets the query string of the URL to query.
Definition qurl.cpp:2550
Combined button and popup list for selecting options.
static QT_WARNING_DISABLE_FLOAT_COMPARE ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
Definition qbezier.cpp:207
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static QGeoManeuver::InstructionDirection osrmInstructionDirection(const QString &instructionCode, QGeoRouteParser::TrafficSide trafficSide)
static QGeoRoute constructRoute(const QByteArray &geometry, const QJsonArray &instructions, const QJsonObject &summary, QGeoRouteParser::TrafficSide trafficSide)
static QString osrmInstructionText(const QString &instructionCode, const QString &wayname)
static QT_BEGIN_NAMESPACE QList< QGeoCoordinate > parsePolyline(const QByteArray &data)
#define qWarning
Definition qlogging.h:166
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum query
const GLubyte * c
GLuint segment
GLuint coord
GLsizei const GLchar *const * path
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
ptrdiff_t qsizetype
Definition qtypes.h:165
static double toDouble(Value v)
QUrl url("example.com")
[constructor-url-reference]
QNetworkRequest request(url)
QNetworkReply * reply
\inmodule QtCore \reentrant
Definition qchar.h:18