Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgeorouteparserosrmv5.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 "qgeoroute.h"
6#include "qgeoroute_p.h"
10#include "qgeomaneuver.h"
11
12#include <QtCore/QJsonDocument>
13#include <QtCore/QJsonObject>
14#include <QtCore/QJsonArray>
15#include <QtCore/QUrlQuery>
16#include <QtPositioning/qgeopath.h>
17
18#include <QtCore/private/qobject_p.h>
19#include <QtPositioning/private/qlocationutils_p.h>
20
21QT_BEGIN_NAMESPACE
22
23static QList<QGeoCoordinate> decodePolyline(const QString &polylineString)
24{
25 QList<QGeoCoordinate> path;
26 if (polylineString.isEmpty())
27 return path;
28
29 const QByteArray data = polylineString.toLatin1();
30
31 bool parsingLatitude = true;
32
33 int shift = 0;
34 int value = 0;
35
36 QGeoCoordinate coord(0, 0);
37
38 for (qsizetype i = 0; i < data.length(); ++i) {
39 unsigned char c = data.at(i) - 63;
40
41 value |= (c & 0x1f) << shift;
42 shift += 5;
43
44 // another chunk
45 if (c & 0x20)
46 continue;
47
48 int diff = (value & 1) ? ~(value >> 1) : (value >> 1);
49
50 if (parsingLatitude) {
51 coord.setLatitude(coord.latitude() + (double)diff/1e6);
52 } else {
53 coord.setLongitude(coord.longitude() + (double)diff/1e6);
54 path.append(coord);
55 }
56
57 parsingLatitude = !parsingLatitude;
58
59 value = 0;
60 shift = 0;
61 }
62
63 return path;
64}
65
66static QString cardinalDirection4(QLocationUtils::CardinalDirection direction)
67{
68 switch (direction) {
69 case QLocationUtils::CardinalN:
70 //: Translations exist at https://github.com/Project-OSRM/osrm-text-instructions.
71 //: Always used in "Head %1 [onto <street name>]"
72 return QGeoRouteParserOsrmV5::tr("North");
73 case QLocationUtils::CardinalE:
74 return QGeoRouteParserOsrmV5::tr("East");
75 case QLocationUtils::CardinalS:
76 return QGeoRouteParserOsrmV5::tr("South");
77 case QLocationUtils::CardinalW:
78 return QGeoRouteParserOsrmV5::tr("West");
79 default:
80 return QString();
81 }
82}
83
84static QString exitOrdinal(int exit)
85{
86 static QList<QString> ordinals;
87
88 if (!ordinals.size()) {
89 ordinals.append(QLatin1String(""));
90 //: always used in " and take the %1 exit [onto <street name>]"
91 ordinals.append(QGeoRouteParserOsrmV5::tr("first", "roundabout exit"));
92 ordinals.append(QGeoRouteParserOsrmV5::tr("second", "roundabout exit"));
93 ordinals.append(QGeoRouteParserOsrmV5::tr("third", "roundabout exit"));
94 ordinals.append(QGeoRouteParserOsrmV5::tr("fourth", "roundabout exit"));
95 ordinals.append(QGeoRouteParserOsrmV5::tr("fifth", "roundabout exit"));
96 ordinals.append(QGeoRouteParserOsrmV5::tr("sixth", "roundabout exit"));
97 ordinals.append(QGeoRouteParserOsrmV5::tr("seventh", "roundabout exit"));
98 ordinals.append(QGeoRouteParserOsrmV5::tr("eighth", "roundabout exit"));
99 ordinals.append(QGeoRouteParserOsrmV5::tr("ninth", "roundabout exit"));
100 ordinals.append(QGeoRouteParserOsrmV5::tr("tenth", "roundabout exit"));
101 ordinals.append(QGeoRouteParserOsrmV5::tr("eleventh", "roundabout exit"));
102 ordinals.append(QGeoRouteParserOsrmV5::tr("twelfth", "roundabout exit"));
103 ordinals.append(QGeoRouteParserOsrmV5::tr("thirteenth", "roundabout exit"));
104 ordinals.append(QGeoRouteParserOsrmV5::tr("fourteenth", "roundabout exit"));
105 ordinals.append(QGeoRouteParserOsrmV5::tr("fifteenth", "roundabout exit"));
106 ordinals.append(QGeoRouteParserOsrmV5::tr("sixteenth", "roundabout exit"));
107 ordinals.append(QGeoRouteParserOsrmV5::tr("seventeenth", "roundabout exit"));
108 ordinals.append(QGeoRouteParserOsrmV5::tr("eighteenth", "roundabout exit"));
109 ordinals.append(QGeoRouteParserOsrmV5::tr("nineteenth", "roundabout exit"));
110 ordinals.append(QGeoRouteParserOsrmV5::tr("twentieth", "roundabout exit"));
111 };
112
113 if (exit < 1 || exit > ordinals.size())
114 return QString();
115 return ordinals[exit];
116}
117
118static QString exitDirection(int exit, const QString &wayName)
119{
120 /*: Always appended to one of the following strings:
121 - "Enter the roundabout"
122 - "Enter the rotary"
123 - "Enter the rotary <rotaryname>"
124 */
125 static QString directionExit = QGeoRouteParserOsrmV5::tr(" and take the %1 exit");
126 static QString directionExitOnto = QGeoRouteParserOsrmV5::tr(" and take the %1 exit onto %2");
127
128 if (exit < 1 || exit > 20)
129 return QString();
130 if (wayName.isEmpty())
131 return directionExit.arg(exitOrdinal(exit));
132 else
133 return directionExitOnto.arg(exitOrdinal(exit), wayName);
134}
135
136static QString instructionArrive(QGeoManeuver::InstructionDirection direction)
137{
138 switch (direction) {
139 case QGeoManeuver::DirectionForward:
140 return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, straight ahead");
141 case QGeoManeuver::DirectionUTurnLeft:
142 case QGeoManeuver::DirectionHardLeft:
143 case QGeoManeuver::DirectionLeft:
144 case QGeoManeuver::DirectionLightLeft:
145 case QGeoManeuver::DirectionBearLeft:
146 return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, on the left");
147 case QGeoManeuver::DirectionUTurnRight:
148 case QGeoManeuver::DirectionHardRight:
149 case QGeoManeuver::DirectionRight:
150 case QGeoManeuver::DirectionLightRight:
151 case QGeoManeuver::DirectionBearRight:
152 return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, on the right");
153 default:
154 return QGeoRouteParserOsrmV5::tr("You have arrived at your destination");
155 }
156}
157
158static QString instructionContinue(const QString &wayName, QGeoManeuver::InstructionDirection direction)
159{
160 switch (direction) {
161 case QGeoManeuver::DirectionForward:
162 if (wayName.isEmpty())
163 return QGeoRouteParserOsrmV5::tr("Continue straight");
164 else
165 return QGeoRouteParserOsrmV5::tr("Continue straight on %1").arg(wayName);
166 case QGeoManeuver::DirectionHardLeft:
167 case QGeoManeuver::DirectionLeft:
168 if (wayName.isEmpty())
169 return QGeoRouteParserOsrmV5::tr("Continue left");
170 else
171 return QGeoRouteParserOsrmV5::tr("Continue left onto %1").arg(wayName);
172 case QGeoManeuver::DirectionLightLeft:
173 case QGeoManeuver::DirectionBearLeft:
174 if (wayName.isEmpty())
175 return QGeoRouteParserOsrmV5::tr("Continue slightly left");
176 else
177 return QGeoRouteParserOsrmV5::tr("Continue slightly left on %1").arg(wayName);
178 case QGeoManeuver::DirectionHardRight:
179 case QGeoManeuver::DirectionRight:
180 if (wayName.isEmpty())
181 return QGeoRouteParserOsrmV5::tr("Continue right");
182 else
183 return QGeoRouteParserOsrmV5::tr("Continue right onto %1").arg(wayName);
184 case QGeoManeuver::DirectionLightRight:
185 case QGeoManeuver::DirectionBearRight:
186 if (wayName.isEmpty())
187 return QGeoRouteParserOsrmV5::tr("Continue slightly right");
188 else
189 return QGeoRouteParserOsrmV5::tr("Continue slightly right on %1").arg(wayName);
190 case QGeoManeuver::DirectionUTurnLeft:
191 case QGeoManeuver::DirectionUTurnRight:
192 if (wayName.isEmpty())
193 return QGeoRouteParserOsrmV5::tr("Make a U-turn");
194 else
195 return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
196 default:
197 if (wayName.isEmpty())
198 return QGeoRouteParserOsrmV5::tr("Continue");
199 else
200 return QGeoRouteParserOsrmV5::tr("Continue on %1").arg(wayName);
201 }
202}
203
204static QString instructionDepart(const QJsonObject &maneuver, const QString &wayName)
205{
206 double bearing = maneuver.value(QLatin1String("bearing_after")).toDouble(-1.0);
207 if (bearing >= 0.0) {
208 if (wayName.isEmpty())
209 //: %1 is "North", "South", "East" or "West"
210 return QGeoRouteParserOsrmV5::tr("Head %1").arg(cardinalDirection4(QLocationUtils::azimuthToCardinalDirection4(bearing)));
211 else
212 return QGeoRouteParserOsrmV5::tr("Head %1 onto %2").arg(cardinalDirection4(QLocationUtils::azimuthToCardinalDirection4(bearing)), wayName);
213 } else {
214 if (wayName.isEmpty())
215 return QGeoRouteParserOsrmV5::tr("Depart");
216 else
217 return QGeoRouteParserOsrmV5::tr("Depart onto %1").arg(wayName);
218 }
219}
220
221static QString instructionEndOfRoad(const QString &wayName, QGeoManeuver::InstructionDirection direction)
222{
223 switch (direction) {
224 case QGeoManeuver::DirectionHardLeft:
225 case QGeoManeuver::DirectionLeft:
226 case QGeoManeuver::DirectionLightLeft:
227 case QGeoManeuver::DirectionBearLeft:
228 if (wayName.isEmpty())
229 return QGeoRouteParserOsrmV5::tr("At the end of the road, turn left");
230 else
231 return QGeoRouteParserOsrmV5::tr("At the end of the road, turn left onto %1").arg(wayName);
232 case QGeoManeuver::DirectionHardRight:
233 case QGeoManeuver::DirectionRight:
234 case QGeoManeuver::DirectionLightRight:
235 case QGeoManeuver::DirectionBearRight:
236 if (wayName.isEmpty())
237 return QGeoRouteParserOsrmV5::tr("At the end of the road, turn right");
238 else
239 return QGeoRouteParserOsrmV5::tr("At the end of the road, turn right onto %1").arg(wayName);
240 case QGeoManeuver::DirectionUTurnLeft:
241 case QGeoManeuver::DirectionUTurnRight:
242 if (wayName.isEmpty())
243 return QGeoRouteParserOsrmV5::tr("At the end of the road, make a U-turn");
244 else
245 return QGeoRouteParserOsrmV5::tr("At the end of the road, make a U-turn onto %1").arg(wayName);
246 case QGeoManeuver::DirectionForward:
247 if (wayName.isEmpty())
248 return QGeoRouteParserOsrmV5::tr("At the end of the road, continue straight");
249 else
250 return QGeoRouteParserOsrmV5::tr("At the end of the road, continue straight onto %1").arg(wayName);
251 default:
252 if (wayName.isEmpty())
253 return QGeoRouteParserOsrmV5::tr("At the end of the road, continue");
254 else
255 return QGeoRouteParserOsrmV5::tr("At the end of the road, continue onto %1").arg(wayName);
256 }
257}
258
259static QString instructionFerry(const QString &wayName)
260{
261 QString instruction = QGeoRouteParserOsrmV5::tr("Take the ferry");
262 if (!wayName.isEmpty())
263 instruction += QLatin1String(" [") + wayName + QLatin1Char(']');
264
265 return instruction;
266}
267
268static QString instructionFork(const QString &wayName, QGeoManeuver::InstructionDirection direction)
269{
270 switch (direction) {
271 case QGeoManeuver::DirectionHardLeft:
272 if (wayName.isEmpty())
273 return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp left");
274 else
275 return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp left onto %1").arg(wayName);
276 case QGeoManeuver::DirectionLeft:
277 if (wayName.isEmpty())
278 return QGeoRouteParserOsrmV5::tr("At the fork, turn left");
279 else
280 return QGeoRouteParserOsrmV5::tr("At the fork, turn left onto %1").arg(wayName);
281 case QGeoManeuver::DirectionLightLeft:
282 case QGeoManeuver::DirectionBearLeft:
283 if (wayName.isEmpty())
284 return QGeoRouteParserOsrmV5::tr("At the fork, keep left");
285 else
286 return QGeoRouteParserOsrmV5::tr("At the fork, keep left onto %1").arg(wayName);
287 case QGeoManeuver::DirectionHardRight:
288 if (wayName.isEmpty())
289 return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp right");
290 else
291 return QGeoRouteParserOsrmV5::tr("At the fork, take a sharp right onto %1").arg(wayName);
292 case QGeoManeuver::DirectionRight:
293 if (wayName.isEmpty())
294 return QGeoRouteParserOsrmV5::tr("At the fork, turn right");
295 else
296 return QGeoRouteParserOsrmV5::tr("At the fork, turn right onto %1").arg(wayName);
297 case QGeoManeuver::DirectionLightRight:
298 case QGeoManeuver::DirectionBearRight:
299 if (wayName.isEmpty())
300 return QGeoRouteParserOsrmV5::tr("At the fork, keep right");
301 else
302 return QGeoRouteParserOsrmV5::tr("At the fork, keep right onto %1").arg(wayName);
303 case QGeoManeuver::DirectionUTurnLeft:
304 case QGeoManeuver::DirectionUTurnRight:
305 if (wayName.isEmpty())
306 return QGeoRouteParserOsrmV5::tr("Make a U-turn");
307 else
308 return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
309 case QGeoManeuver::DirectionForward:
310 if (wayName.isEmpty())
311 return QGeoRouteParserOsrmV5::tr("At the fork, continue straight ahead");
312 else
313 return QGeoRouteParserOsrmV5::tr("At the fork, continue straight ahead onto %1").arg(wayName);
314 default:
315 if (wayName.isEmpty())
316 return QGeoRouteParserOsrmV5::tr("At the fork, continue");
317 else
318 return QGeoRouteParserOsrmV5::tr("At the fork, continue onto %1").arg(wayName);
319 }
320}
321
322static QString instructionMerge(const QString &wayName, QGeoManeuver::InstructionDirection direction)
323{
324 switch (direction) {
325 case QGeoManeuver::DirectionUTurnLeft:
326 case QGeoManeuver::DirectionHardLeft:
327 if (wayName.isEmpty())
328 return QGeoRouteParserOsrmV5::tr("Merge sharply left");
329 else
330 return QGeoRouteParserOsrmV5::tr("Merge sharply left onto %1").arg(wayName);
331 case QGeoManeuver::DirectionLeft:
332 if (wayName.isEmpty())
333 return QGeoRouteParserOsrmV5::tr("Merge left");
334 else
335 return QGeoRouteParserOsrmV5::tr("Merge left onto %1").arg(wayName);
336 case QGeoManeuver::DirectionLightLeft:
337 case QGeoManeuver::DirectionBearLeft:
338 if (wayName.isEmpty())
339 return QGeoRouteParserOsrmV5::tr("Merge slightly left");
340 else
341 return QGeoRouteParserOsrmV5::tr("Merge slightly left on %1").arg(wayName);
342 case QGeoManeuver::DirectionUTurnRight:
343 case QGeoManeuver::DirectionHardRight:
344 if (wayName.isEmpty())
345 return QGeoRouteParserOsrmV5::tr("Merge sharply right");
346 else
347 return QGeoRouteParserOsrmV5::tr("Merge sharply right onto %1").arg(wayName);
348 case QGeoManeuver::DirectionRight:
349 if (wayName.isEmpty())
350 return QGeoRouteParserOsrmV5::tr("Merge right");
351 else
352 return QGeoRouteParserOsrmV5::tr("Merge right onto %1").arg(wayName);
353 case QGeoManeuver::DirectionLightRight:
354 case QGeoManeuver::DirectionBearRight:
355 if (wayName.isEmpty())
356 return QGeoRouteParserOsrmV5::tr("Merge slightly right");
357 else
358 return QGeoRouteParserOsrmV5::tr("Merge slightly right on %1").arg(wayName);
359 case QGeoManeuver::DirectionForward:
360 if (wayName.isEmpty())
361 return QGeoRouteParserOsrmV5::tr("Merge straight");
362 else
363 return QGeoRouteParserOsrmV5::tr("Merge straight on %1").arg(wayName);
364 default:
365 if (wayName.isEmpty())
366 return QGeoRouteParserOsrmV5::tr("Merge");
367 else
368 return QGeoRouteParserOsrmV5::tr("Merge onto %1").arg(wayName);
369 }
370}
371
372static QString instructionNewName(const QString &wayName, QGeoManeuver::InstructionDirection direction)
373{
374 switch (direction) {
375 case QGeoManeuver::DirectionHardLeft:
376 if (wayName.isEmpty())
377 return QGeoRouteParserOsrmV5::tr("Take a sharp left");
378 else
379 return QGeoRouteParserOsrmV5::tr("Take a sharp left onto %1").arg(wayName);
380 case QGeoManeuver::DirectionLeft:
381 if (wayName.isEmpty())
382 return QGeoRouteParserOsrmV5::tr("Turn left");
383 else
384 return QGeoRouteParserOsrmV5::tr("Turn left onto %1").arg(wayName);
385 case QGeoManeuver::DirectionLightLeft:
386 case QGeoManeuver::DirectionBearLeft:
387 if (wayName.isEmpty())
388 return QGeoRouteParserOsrmV5::tr("Continue slightly left");
389 else
390 return QGeoRouteParserOsrmV5::tr("Continue slightly left onto %1").arg(wayName);
391 case QGeoManeuver::DirectionHardRight:
392 if (wayName.isEmpty())
393 return QGeoRouteParserOsrmV5::tr("Take a sharp right");
394 else
395 return QGeoRouteParserOsrmV5::tr("Take a sharp right onto %1").arg(wayName);
396 case QGeoManeuver::DirectionRight:
397 if (wayName.isEmpty())
398 return QGeoRouteParserOsrmV5::tr("Turn right");
399 else
400 return QGeoRouteParserOsrmV5::tr("Turn right onto %1").arg(wayName);
401 case QGeoManeuver::DirectionLightRight:
402 case QGeoManeuver::DirectionBearRight:
403 if (wayName.isEmpty())
404 return QGeoRouteParserOsrmV5::tr("Continue slightly right");
405 else
406 return QGeoRouteParserOsrmV5::tr("Continue slightly right onto %1").arg(wayName);
407 case QGeoManeuver::DirectionUTurnLeft:
408 case QGeoManeuver::DirectionUTurnRight:
409 if (wayName.isEmpty())
410 return QGeoRouteParserOsrmV5::tr("Make a U-turn");
411 else
412 return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
413 case QGeoManeuver::DirectionForward:
414 if (wayName.isEmpty())
415 return QGeoRouteParserOsrmV5::tr("Continue straight");
416 else
417 return QGeoRouteParserOsrmV5::tr("Continue straight onto %1").arg(wayName);
418 default:
419 if (wayName.isEmpty())
420 return QGeoRouteParserOsrmV5::tr("Continue");
421 else
422 return QGeoRouteParserOsrmV5::tr("Continue onto %1").arg(wayName);
423 }
424}
425
426static QString instructionNotification(const QString &wayName, QGeoManeuver::InstructionDirection direction)
427{
428 switch (direction) {
429 case QGeoManeuver::DirectionUTurnLeft:
430 case QGeoManeuver::DirectionHardLeft:
431 case QGeoManeuver::DirectionLeft:
432 case QGeoManeuver::DirectionLightLeft:
433 case QGeoManeuver::DirectionBearLeft:
434 if (wayName.isEmpty())
435 return QGeoRouteParserOsrmV5::tr("Continue on the left");
436 else
437 return QGeoRouteParserOsrmV5::tr("Continue on the left on %1").arg(wayName);
438 case QGeoManeuver::DirectionUTurnRight:
439 case QGeoManeuver::DirectionHardRight:
440 case QGeoManeuver::DirectionRight:
441 case QGeoManeuver::DirectionLightRight:
442 case QGeoManeuver::DirectionBearRight:
443 if (wayName.isEmpty())
444 return QGeoRouteParserOsrmV5::tr("Continue on the right");
445 else
446 return QGeoRouteParserOsrmV5::tr("Continue on the right on %1").arg(wayName);
447 case QGeoManeuver::DirectionForward:
448 default:
449 if (wayName.isEmpty())
450 return QGeoRouteParserOsrmV5::tr("Continue");
451 else
452 return QGeoRouteParserOsrmV5::tr("Continue on %1").arg(wayName);
453 }
454}
455
456static QString instructionOffRamp(const QString &wayName, QGeoManeuver::InstructionDirection direction)
457{
458 switch (direction) {
459 case QGeoManeuver::DirectionUTurnLeft:
460 case QGeoManeuver::DirectionHardLeft:
461 case QGeoManeuver::DirectionLeft:
462 case QGeoManeuver::DirectionLightLeft:
463 case QGeoManeuver::DirectionBearLeft:
464 if (wayName.isEmpty())
465 return QGeoRouteParserOsrmV5::tr("Take the ramp on the left");
466 else
467 return QGeoRouteParserOsrmV5::tr("Take the ramp on the left onto %1").arg(wayName);
468 case QGeoManeuver::DirectionUTurnRight:
469 case QGeoManeuver::DirectionHardRight:
470 case QGeoManeuver::DirectionRight:
471 case QGeoManeuver::DirectionLightRight:
472 case QGeoManeuver::DirectionBearRight:
473 if (wayName.isEmpty())
474 return QGeoRouteParserOsrmV5::tr("Take the ramp on the right");
475 else
476 return QGeoRouteParserOsrmV5::tr("Take the ramp on the right onto %1").arg(wayName);
477 case QGeoManeuver::DirectionForward:
478 default:
479 if (wayName.isEmpty())
480 return QGeoRouteParserOsrmV5::tr("Take the ramp");
481 else
482 return QGeoRouteParserOsrmV5::tr("Take the ramp onto %1").arg(wayName);
483 }
484}
485
486static QString instructionOnRamp(const QString &wayName, QGeoManeuver::InstructionDirection direction)
487{
488 return instructionOffRamp(wayName, direction);
489}
490
491static QString instructionPushingBike(const QString &wayName)
492{
493 if (wayName.isEmpty())
494 return QGeoRouteParserOsrmV5::tr("Get off the bike and push");
495 else
496 return QGeoRouteParserOsrmV5::tr("Get off the bike and push onto %1").arg(wayName);
497}
498
499static QString instructionRotary(const QJsonObject &step, const QJsonObject &maneuver, const QString &wayName)
500{
501 QString instruction;
502 QString rotaryName = step.value(QLatin1String("rotary_name")).toString();
503 //QString modifier = maneuver.value(QLatin1String("modifier")).toString(); // Apparently not used for rotaries
504 int exit = maneuver.value(QLatin1String("exit")).toInt(0);
505
506 //: This string will be prepended to " and take the <nth> exit [onto <streetname>]
507 instruction += QGeoRouteParserOsrmV5::tr("Enter the rotary");
508 if (!rotaryName.isEmpty())
509 instruction += QLatin1Char(' ') + rotaryName;
510 instruction += exitDirection(exit, wayName);
511 return instruction;
512}
513
514static QString instructionRoundabout(const QJsonObject &maneuver, const QString &wayName)
515{
516 QString instruction;
517 //QString modifier = maneuver.value(QLatin1String("modifier")).toString(); // Apparently not used for rotaries
518 int exit = maneuver.value(QLatin1String("exit")).toInt(0);
519
520 //: This string will be prepended to " and take the <nth> exit [onto <streetname>]
521 instruction += QGeoRouteParserOsrmV5::tr("Enter the roundabout");
522 instruction += exitDirection(exit, wayName);
523 return instruction;
524}
525
526static QString instructionRoundaboutTurn(const QString &wayName, QGeoManeuver::InstructionDirection direction)
527{
528 switch (direction) {
529 case QGeoManeuver::DirectionForward:
530 if (wayName.isEmpty())
531 return QGeoRouteParserOsrmV5::tr("At the roundabout, continue straight");
532 else
533 return QGeoRouteParserOsrmV5::tr("At the roundabout, continue straight on %1").arg(wayName);
534 case QGeoManeuver::DirectionHardLeft:
535 case QGeoManeuver::DirectionLeft:
536 case QGeoManeuver::DirectionLightLeft:
537 case QGeoManeuver::DirectionBearLeft:
538 if (wayName.isEmpty())
539 return QGeoRouteParserOsrmV5::tr("At the roundabout, turn left");
540 else
541 return QGeoRouteParserOsrmV5::tr("At the roundabout, turn left onto %1").arg(wayName);
542 case QGeoManeuver::DirectionHardRight:
543 case QGeoManeuver::DirectionRight:
544 case QGeoManeuver::DirectionLightRight:
545 case QGeoManeuver::DirectionBearRight:
546 if (wayName.isEmpty())
547 return QGeoRouteParserOsrmV5::tr("At the roundabout, turn right");
548 else
549 return QGeoRouteParserOsrmV5::tr("At the roundabout, turn right onto %1").arg(wayName);
550 case QGeoManeuver::DirectionUTurnLeft:
551 case QGeoManeuver::DirectionUTurnRight:
552 if (wayName.isEmpty())
553 return QGeoRouteParserOsrmV5::tr("At the roundabout, turn around");
554 else
555 return QGeoRouteParserOsrmV5::tr("At the roundabout, turn around onto %1").arg(wayName);
556 default:
557 if (wayName.isEmpty())
558 return QGeoRouteParserOsrmV5::tr("At the roundabout, continue");
559 else
560 return QGeoRouteParserOsrmV5::tr("At the roundabout, continue onto %1").arg(wayName);
561 }
562}
563
564static QString instructionTrain(const QString &wayName)
565{
566 return wayName.isEmpty()
567 ? QGeoRouteParserOsrmV5::tr("Take the train")
568 : QGeoRouteParserOsrmV5::tr("Take the train [%1]").arg(wayName);
569}
570
571static QString instructionTurn(const QString &wayName, QGeoManeuver::InstructionDirection direction)
572{
573 switch (direction) {
574 case QGeoManeuver::DirectionForward:
575 if (wayName.isEmpty())
576 return QGeoRouteParserOsrmV5::tr("Go straight");
577 else
578 return QGeoRouteParserOsrmV5::tr("Go straight onto %1").arg(wayName);
579 case QGeoManeuver::DirectionHardLeft:
580 case QGeoManeuver::DirectionLeft:
581 if (wayName.isEmpty())
582 return QGeoRouteParserOsrmV5::tr("Turn left");
583 else
584 return QGeoRouteParserOsrmV5::tr("Turn left onto %1").arg(wayName);
585 case QGeoManeuver::DirectionLightLeft:
586 case QGeoManeuver::DirectionBearLeft:
587 if (wayName.isEmpty())
588 return QGeoRouteParserOsrmV5::tr("Turn slightly left");
589 else
590 return QGeoRouteParserOsrmV5::tr("Turn slightly left onto %1").arg(wayName);
591 case QGeoManeuver::DirectionHardRight:
592 case QGeoManeuver::DirectionRight:
593 if (wayName.isEmpty())
594 return QGeoRouteParserOsrmV5::tr("Turn right");
595 else
596 return QGeoRouteParserOsrmV5::tr("Turn right onto %1").arg(wayName);
597 case QGeoManeuver::DirectionLightRight:
598 case QGeoManeuver::DirectionBearRight:
599 if (wayName.isEmpty())
600 return QGeoRouteParserOsrmV5::tr("Turn slightly right");
601 else
602 return QGeoRouteParserOsrmV5::tr("Turn slightly right onto %1").arg(wayName);
603 case QGeoManeuver::DirectionUTurnLeft:
604 case QGeoManeuver::DirectionUTurnRight:
605 if (wayName.isEmpty())
606 return QGeoRouteParserOsrmV5::tr("Make a U-turn");
607 else
608 return QGeoRouteParserOsrmV5::tr("Make a U-turn onto %1").arg(wayName);
609 default:
610 if (wayName.isEmpty())
611 return QGeoRouteParserOsrmV5::tr("Turn");
612 else
613 return QGeoRouteParserOsrmV5::tr("Turn onto %1").arg(wayName);
614 }
615}
616
617static QString instructionUseLane(const QJsonObject &maneuver, const QString &wayName, QGeoManeuver::InstructionDirection direction)
618{
619 QString laneTypes = maneuver.value(QLatin1String("laneTypes")).toString();
620 QString laneInstruction;
621 if (laneTypes == QLatin1String("xo") || laneTypes == QLatin1String("xoo") || laneTypes == QLatin1String("xxo"))
622 //: "and <instruction direction> [onto <street name>] will be appended to this string. E.g., "Keep right and make a sharp left"
623 laneInstruction = QLatin1String("Keep right");
624 else if (laneTypes == QLatin1String("ox") || laneTypes == QLatin1String("oox") || laneTypes == QLatin1String("oxx"))
625 laneInstruction = QLatin1String("Keep left");
626 else if (laneTypes == QLatin1String("xox"))
627 laneInstruction = QLatin1String("Use the middle lane");
628 else if (laneTypes == QLatin1String("oxo"))
629 laneInstruction = QLatin1String("Use the left or the right lane");
630
631 if (laneInstruction.isEmpty()) {
632 if (wayName.isEmpty())
633 return QGeoRouteParserOsrmV5::tr("Continue straight");
634 else
635 return QGeoRouteParserOsrmV5::tr("Continue straight onto %1").arg(wayName);
636 }
637
638 switch (direction) {
639 case QGeoManeuver::DirectionForward:
640 if (wayName.isEmpty())
641 //: This string will be prepended with lane instructions. E.g., "Use the left or the right lane and continue straight"
642 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and continue straight");
643 else
644 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and continue straight onto %1").arg(wayName);
645 case QGeoManeuver::DirectionHardLeft:
646 if (wayName.isEmpty())
647 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp left");
648 else
649 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp left onto %1").arg(wayName);
650 case QGeoManeuver::DirectionLeft:
651 if (wayName.isEmpty())
652 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn left");
653 else
654 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn left onto %1").arg(wayName);
655 case QGeoManeuver::DirectionLightLeft:
656 case QGeoManeuver::DirectionBearLeft:
657 if (wayName.isEmpty())
658 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight left");
659 else
660 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight left onto %1").arg(wayName);
661 case QGeoManeuver::DirectionHardRight:
662 if (wayName.isEmpty())
663 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp right");
664 else
665 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a sharp right onto %1").arg(wayName);
666 case QGeoManeuver::DirectionRight:
667 if (wayName.isEmpty())
668 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn right");
669 else
670 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and turn right onto %1").arg(wayName);
671 case QGeoManeuver::DirectionLightRight:
672 case QGeoManeuver::DirectionBearRight:
673 if (wayName.isEmpty())
674 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight right");
675 else
676 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a slight right onto %1").arg(wayName);
677 case QGeoManeuver::DirectionUTurnLeft:
678 case QGeoManeuver::DirectionUTurnRight:
679 if (wayName.isEmpty())
680 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a U-turn");
681 else
682 return laneInstruction + QGeoRouteParserOsrmV5::tr(" and make a U-turn onto %1").arg(wayName);
683 default:
684 return laneInstruction;
685 }
686}
687
688static QString instructionText(const QJsonObject &step, const QJsonObject &maneuver, QGeoManeuver::InstructionDirection direction) {
689 QString modifier;
690 if (maneuver.value(QLatin1String("modifier")).isString())
691 modifier = maneuver.value(QLatin1String("modifier")).toString();
692 QString maneuverType;
693 if (maneuver.value(QLatin1String("type")).isString())
694 maneuverType = maneuver.value(QLatin1String("type")).toString();
695 QString wayName = QLatin1String("unknown street");
696 if (step.value(QLatin1String("name")).isString())
697 wayName = step.value(QLatin1String("name")).toString();
698
699
700 if (maneuverType == QLatin1String("arrive"))
701 return instructionArrive(direction);
702 else if (maneuverType == QLatin1String("continue"))
703 return instructionContinue(wayName, direction);
704 else if (maneuverType == QLatin1String("depart"))
705 return instructionDepart(maneuver, wayName);
706 else if (maneuverType == QLatin1String("end of road"))
707 return instructionEndOfRoad(wayName, direction);
708 else if (maneuverType == QLatin1String("ferry"))
709 return instructionFerry(wayName);
710 else if (maneuverType == QLatin1String("fork"))
711 return instructionFork(wayName, direction);
712 else if (maneuverType == QLatin1String("merge"))
713 return instructionMerge(wayName, direction);
714 else if (maneuverType == QLatin1String("new name"))
715 return instructionNewName(wayName, direction);
716 else if (maneuverType == QLatin1String("notification"))
717 return instructionNotification(wayName, direction);
718 else if (maneuverType == QLatin1String("off ramp"))
719 return instructionOffRamp(wayName, direction);
720 else if (maneuverType == QLatin1String("on ramp"))
721 return instructionOnRamp(wayName, direction);
722 else if (maneuverType == QLatin1String("pushing bike"))
723 return instructionPushingBike(wayName);
724 else if (maneuverType == QLatin1String("rotary"))
725 return instructionRotary(step, maneuver, wayName);
726 else if (maneuverType == QLatin1String("roundabout"))
727 return instructionRoundabout(maneuver, wayName);
728 else if (maneuverType == QLatin1String("roundabout turn"))
729 return instructionRoundaboutTurn(wayName, direction);
730 else if (maneuverType == QLatin1String("train"))
731 return instructionTrain(wayName);
732 else if (maneuverType == QLatin1String("turn"))
733 return instructionTurn(wayName, direction);
734 else if (maneuverType == QLatin1String("use lane"))
735 return instructionUseLane(maneuver, wayName, direction);
736 else
737 return maneuverType + QLatin1String(" to/onto ") + wayName;
738}
739
740static QGeoManeuver::InstructionDirection instructionDirection(const QJsonObject &maneuver, QGeoRouteParser::TrafficSide trafficSide)
741{
742 QString modifier;
743 if (maneuver.value(QLatin1String("modifier")).isString())
744 modifier = maneuver.value(QLatin1String("modifier")).toString();
745
746 if (modifier.isEmpty())
747 return QGeoManeuver::NoDirection;
748 else if (modifier == QLatin1String("straight"))
749 return QGeoManeuver::DirectionForward;
750 else if (modifier == QLatin1String("right"))
751 return QGeoManeuver::DirectionRight;
752 else if (modifier == QLatin1String("sharp right"))
753 return QGeoManeuver::DirectionHardRight;
754 else if (modifier == QLatin1String("slight right"))
755 return QGeoManeuver::DirectionLightRight;
756 else if (modifier == QLatin1String("uturn")) {
757 switch (trafficSide) {
758 case QGeoRouteParser::RightHandTraffic:
759 return QGeoManeuver::DirectionUTurnLeft;
760 case QGeoRouteParser::LeftHandTraffic:
761 return QGeoManeuver::DirectionUTurnRight;
762 }
763 return QGeoManeuver::DirectionUTurnLeft;
764 } else if (modifier == QLatin1String("left"))
765 return QGeoManeuver::DirectionLeft;
766 else if (modifier == QLatin1String("sharp left"))
767 return QGeoManeuver::DirectionHardLeft;
768 else if (modifier == QLatin1String("slight left"))
769 return QGeoManeuver::DirectionLightLeft;
770 else
771 return QGeoManeuver::NoDirection;
772}
773
775{
776 Q_DECLARE_PUBLIC(QGeoRouteParserOsrmV5)
777public:
780
781 QGeoRouteSegment parseStep(const QJsonObject &step, int legIndex, int stepIndex) const;
782
783 // QGeoRouteParserPrivate
784
785 QGeoRouteReply::Error parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const override;
786 QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const override;
787
790};
791
792QGeoRouteParserOsrmV5Private::QGeoRouteParserOsrmV5Private()
793 : QGeoRouteParserPrivate()
794{
795}
796
798{
799 delete m_extension;
800}
801
802QGeoRouteSegment QGeoRouteParserOsrmV5Private::parseStep(const QJsonObject &step, int legIndex, int stepIndex) const {
803 // OSRM Instructions documentation: https://github.com/Project-OSRM/osrm-text-instructions
804 // This goes on top of OSRM: https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md
805 // Mapbox however, includes this in the reply, under "instruction".
806 QGeoRouteSegment segment;
807 if (!step.value(QLatin1String("maneuver")).isObject())
808 return segment;
809 QJsonObject maneuver = step.value(QLatin1String("maneuver")).toObject();
810 if (!step.value(QLatin1String("duration")).isDouble())
811 return segment;
812 if (!step.value(QLatin1String("distance")).isDouble())
813 return segment;
814 if (!step.value(QLatin1String("intersections")).isArray())
815 return segment;
816 if (!maneuver.value(QLatin1String("location")).isArray())
817 return segment;
818
819 double time = step.value(QLatin1String("duration")).toDouble();
820 double distance = step.value(QLatin1String("distance")).toDouble();
821
822 QJsonArray position = maneuver.value(QLatin1String("location")).toArray();
823 if (position.isEmpty())
824 return segment;
825 double latitude = position[1].toDouble();
826 double longitude = position[0].toDouble();
827 QGeoCoordinate coord(latitude, longitude);
828
829 QString geometry = step.value(QLatin1String("geometry")).toString();
830 QList<QGeoCoordinate> path = decodePolyline(geometry);
831
832 QGeoManeuver::InstructionDirection maneuverInstructionDirection = instructionDirection(maneuver, trafficSide);
833
834 QString maneuverInstructionText = instructionText(step, maneuver, maneuverInstructionDirection);
835
836 QGeoManeuver geoManeuver;
837 geoManeuver.setDirection(maneuverInstructionDirection);
838 geoManeuver.setDistanceToNextInstruction(distance);
839 geoManeuver.setTimeToNextInstruction(time);
840 geoManeuver.setInstructionText(maneuverInstructionText);
841 geoManeuver.setPosition(coord);
842 geoManeuver.setWaypoint(coord);
843
844 QVariantMap extraAttributes;
845 static const QStringList extras {
846 QLatin1String("bearing_before"),
847 QLatin1String("bearing_after"),
848 QLatin1String("instruction"),
849 QLatin1String("type"),
850 QLatin1String("modifier") };
851 for (const QString &e: extras) {
852 if (maneuver.find(e) != maneuver.end())
853 extraAttributes.insert(e, maneuver.value(e).toVariant());
854 }
855 // These should be removed as soon as route leg support is introduced.
856 // Ref: http://project-osrm.org/docs/v5.15.2/api/#routeleg-object
857 extraAttributes.insert(QLatin1String("leg_index"), legIndex);
858 extraAttributes.insert(QLatin1String("step_index"), stepIndex);
859
860 geoManeuver.setExtendedAttributes(extraAttributes);
861
862 segment.setDistance(distance);
863 segment.setPath(path);
864 segment.setTravelTime(time);
865 segment.setManeuver(geoManeuver);
866 if (m_extension)
867 m_extension->updateSegment(segment, step, maneuver);
868 return segment;
869}
870
871QGeoRouteReply::Error QGeoRouteParserOsrmV5Private::parseReply(QList<QGeoRoute> &routes, QString &errorString, const QByteArray &reply) const
872{
873 // OSRM v5 specs: https://github.com/Project-OSRM/osrm-backend/blob/master/docs/http.md
874 // Mapbox Directions API spec: https://www.mapbox.com/api-documentation/#directions
875 QJsonDocument document = QJsonDocument::fromJson(reply);
876 if (document.isObject()) {
877 QJsonObject object = document.object();
878
879 QString status = object.value(QLatin1String("code")).toString();
880 if (status != QLatin1String("Ok")) {
881 errorString = status;
882 return QGeoRouteReply::UnknownError;
883 }
884 if (!object.value(QLatin1String("routes")).isArray()) {
885 errorString = QLatin1String("No routes found");
886 return QGeoRouteReply::ParseError;
887 }
888
889 const QJsonArray osrmRoutes = object.value(QLatin1String("routes")).toArray();
890 for (const QJsonValueConstRef r : osrmRoutes) {
891 if (!r.isObject())
892 continue;
893 QJsonObject routeObject = r.toObject();
894 if (!routeObject.value(QLatin1String("legs")).isArray())
895 continue;
896 if (!routeObject.value(QLatin1String("duration")).isDouble())
897 continue;
898 if (!routeObject.value(QLatin1String("distance")).isDouble())
899 continue;
900
901 double distance = routeObject.value(QLatin1String("distance")).toDouble();
902 double travelTime = routeObject.value(QLatin1String("duration")).toDouble();
903 bool error = false;
904 QList<QGeoRouteSegment> segments;
905
906 const QJsonArray legs = routeObject.value(QLatin1String("legs")).toArray();
907 QList<QGeoRoute> routeLegs;
908 QGeoRoute route;
909 for (int legIndex = 0; legIndex < legs.size(); ++legIndex) {
910 const QJsonValue &l = legs.at(legIndex);
911 QGeoRoute routeLeg;
912 QList<QGeoRouteSegment> legSegments;
913 if (!l.isObject()) { // invalid leg record
914 error = true;
915 break;
916 }
917 const QJsonObject leg = l.toObject();
918 if (!leg.value(QLatin1String("steps")).isArray()) { // Invalid steps field
919 error = true;
920 break;
921 }
922 const double legDistance = leg.value(QLatin1String("distance")).toDouble();
923 const double legTravelTime = leg.value(QLatin1String("duration")).toDouble();
924 const QJsonArray steps = leg.value(QLatin1String("steps")).toArray();
925 QGeoRouteSegment segment;
926 for (int stepIndex = 0; stepIndex < steps.size(); ++stepIndex) {
927 const QJsonValue &s = steps.at(stepIndex);
928 if (!s.isObject()) {
929 error = true;
930 break;
931 }
932 segment = parseStep(s.toObject(), legIndex, stepIndex);
933 if (segment.isValid()) {
934 // setNextRouteSegment done below for all segments in the route.
935 legSegments.append(segment);
936 } else {
937 error = true;
938 break;
939 }
940 }
941 if (error)
942 break;
943
944 QGeoRouteSegmentPrivate *segmentPrivate = QGeoRouteSegmentPrivate::get(segment);
945 segmentPrivate->setLegLastSegment(true);
946 QList<QGeoCoordinate> path;
947 for (const QGeoRouteSegment &s: std::as_const(legSegments))
948 path.append(s.path());
949 routeLeg.setLegIndex(legIndex);
950 routeLeg.setOverallRoute(route); // QGeoRoute::d_ptr is explicitlySharedDataPointer. Modifiers below won't detach it.
951 routeLeg.setDistance(legDistance);
952 routeLeg.setTravelTime(legTravelTime);
953 if (!path.isEmpty()) {
954 routeLeg.setPath(path);
955 routeLeg.setFirstRouteSegment(legSegments.first());
956 }
957 routeLegs << routeLeg;
958
959 segments.append(legSegments);
960 }
961
962 if (!error) {
963 QList<QGeoCoordinate> path;
964 for (const QGeoRouteSegment &s : segments)
965 path.append(s.path());
966
967 for (qsizetype i = segments.size() - 1; i > 0; --i)
968 segments[i-1].setNextRouteSegment(segments[i]);
969
970 route.setDistance(distance);
971 route.setTravelTime(travelTime);
972 if (!path.isEmpty()) {
973 route.setPath(path);
974 route.setBounds(QGeoPath(path).boundingGeoRectangle());
975 route.setFirstRouteSegment(segments.first());
976 }
977 route.setRouteLegs(routeLegs);
978 //r.setTravelMode(QGeoRouteRequest::CarTravel); // The only one supported by OSRM demo service, but other OSRM servers might do cycle or pedestrian too
979 routes.append(route);
980 }
981 }
982
983 // setError(QGeoRouteReply::NoError, status); // can't do this, or NoError is emitted and does damages
984 return QGeoRouteReply::NoError;
985 } else {
986 errorString = QLatin1String("Couldn't parse json.");
987 return QGeoRouteReply::ParseError;
988 }
989}
990
991QUrl QGeoRouteParserOsrmV5Private::requestUrl(const QGeoRouteRequest &request, const QString &prefix) const
992{
993 QString routingUrl = prefix;
994 int notFirst = 0;
995 const QList<QGeoCoordinate> waypoints = request.waypoints();
996 for (qsizetype i = 0; i < waypoints.size(); i++) {
997 const QGeoCoordinate &c = waypoints.at(i);
998 if (notFirst)
999 routingUrl.append(QLatin1Char(';'));
1000 routingUrl.append(QString::number(c.longitude(), 'f', 7)).append(QLatin1Char(',')).append(QString::number(c.latitude(), 'f', 7));
1001 ++notFirst;
1002 }
1003
1004 QUrl url(routingUrl);
1005 QUrlQuery query;
1006 query.addQueryItem(QLatin1String("overview"), QLatin1String("full"));
1007 query.addQueryItem(QLatin1String("steps"), QLatin1String("true"));
1008 query.addQueryItem(QLatin1String("geometries"), QLatin1String("polyline6"));
1009 query.addQueryItem(QLatin1String("alternatives"), QLatin1String("true"));
1010 if (m_extension)
1011 m_extension->updateQuery(query);
1012 url.setQuery(query);
1013 return url;
1014}
1015
1016QGeoRouteParserOsrmV5::QGeoRouteParserOsrmV5(QObject *parent)
1017 : QGeoRouteParser(*new QGeoRouteParserOsrmV5Private(), parent)
1018{
1019}
1020
1021QGeoRouteParserOsrmV5::~QGeoRouteParserOsrmV5()
1022{
1023}
1024
1025void QGeoRouteParserOsrmV5::setExtension(const QGeoRouteParserOsrmV5Extension *extension)
1026{
1027 Q_D(QGeoRouteParserOsrmV5);
1028 if (extension)
1029 d->m_extension = extension;
1030}
1031
1032QT_END_NAMESPACE
QGeoRouteReply::Error parseReply(QList< QGeoRoute > &routes, QString &errorString, const QByteArray &reply) const override
const QGeoRouteParserOsrmV5Extension * m_extension
QUrl requestUrl(const QGeoRouteRequest &request, const QString &prefix) const override
QGeoRouteSegment parseStep(const QJsonObject &step, int legIndex, int stepIndex) const
static QString instructionArrive(QGeoManeuver::InstructionDirection direction)
static QString instructionRoundaboutTurn(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionNotification(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionNewName(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionUseLane(const QJsonObject &maneuver, const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionTrain(const QString &wayName)
static QString instructionOffRamp(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QGeoManeuver::InstructionDirection instructionDirection(const QJsonObject &maneuver, QGeoRouteParser::TrafficSide trafficSide)
static QString exitDirection(int exit, const QString &wayName)
static QString instructionDepart(const QJsonObject &maneuver, const QString &wayName)
static QString instructionRoundabout(const QJsonObject &maneuver, const QString &wayName)
static QString instructionPushingBike(const QString &wayName)
static QString cardinalDirection4(QLocationUtils::CardinalDirection direction)
static QString instructionMerge(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionRotary(const QJsonObject &step, const QJsonObject &maneuver, const QString &wayName)
static QString instructionOnRamp(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionFork(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString exitOrdinal(int exit)
static QString instructionContinue(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionTurn(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionText(const QJsonObject &step, const QJsonObject &maneuver, QGeoManeuver::InstructionDirection direction)
static QString instructionEndOfRoad(const QString &wayName, QGeoManeuver::InstructionDirection direction)
static QString instructionFerry(const QString &wayName)