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
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"
8#include "qgeoroutesegment.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
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
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
67{
68 switch (direction) {
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");
74 return QGeoRouteParserOsrmV5::tr("East");
76 return QGeoRouteParserOsrmV5::tr("South");
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
137{
138 switch (direction) {
140 return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, straight ahead");
146 return QGeoRouteParserOsrmV5::tr("You have arrived at your destination, on the left");
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
159{
160 switch (direction) {
162 if (wayName.isEmpty())
163 return QGeoRouteParserOsrmV5::tr("Continue straight");
164 else
165 return QGeoRouteParserOsrmV5::tr("Continue straight on %1").arg(wayName);
168 if (wayName.isEmpty())
169 return QGeoRouteParserOsrmV5::tr("Continue left");
170 else
171 return QGeoRouteParserOsrmV5::tr("Continue left onto %1").arg(wayName);
174 if (wayName.isEmpty())
175 return QGeoRouteParserOsrmV5::tr("Continue slightly left");
176 else
177 return QGeoRouteParserOsrmV5::tr("Continue slightly left on %1").arg(wayName);
180 if (wayName.isEmpty())
181 return QGeoRouteParserOsrmV5::tr("Continue right");
182 else
183 return QGeoRouteParserOsrmV5::tr("Continue right onto %1").arg(wayName);
186 if (wayName.isEmpty())
187 return QGeoRouteParserOsrmV5::tr("Continue slightly right");
188 else
189 return QGeoRouteParserOsrmV5::tr("Continue slightly right on %1").arg(wayName);
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
222{
223 switch (direction) {
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);
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);
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);
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
269{
270 switch (direction) {
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);
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);
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);
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);
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);
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);
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);
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
323{
324 switch (direction) {
327 if (wayName.isEmpty())
328 return QGeoRouteParserOsrmV5::tr("Merge sharply left");
329 else
330 return QGeoRouteParserOsrmV5::tr("Merge sharply left onto %1").arg(wayName);
332 if (wayName.isEmpty())
333 return QGeoRouteParserOsrmV5::tr("Merge left");
334 else
335 return QGeoRouteParserOsrmV5::tr("Merge left onto %1").arg(wayName);
338 if (wayName.isEmpty())
339 return QGeoRouteParserOsrmV5::tr("Merge slightly left");
340 else
341 return QGeoRouteParserOsrmV5::tr("Merge slightly left on %1").arg(wayName);
344 if (wayName.isEmpty())
345 return QGeoRouteParserOsrmV5::tr("Merge sharply right");
346 else
347 return QGeoRouteParserOsrmV5::tr("Merge sharply right onto %1").arg(wayName);
349 if (wayName.isEmpty())
350 return QGeoRouteParserOsrmV5::tr("Merge right");
351 else
352 return QGeoRouteParserOsrmV5::tr("Merge right onto %1").arg(wayName);
355 if (wayName.isEmpty())
356 return QGeoRouteParserOsrmV5::tr("Merge slightly right");
357 else
358 return QGeoRouteParserOsrmV5::tr("Merge slightly right on %1").arg(wayName);
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
373{
374 switch (direction) {
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);
381 if (wayName.isEmpty())
382 return QGeoRouteParserOsrmV5::tr("Turn left");
383 else
384 return QGeoRouteParserOsrmV5::tr("Turn left onto %1").arg(wayName);
387 if (wayName.isEmpty())
388 return QGeoRouteParserOsrmV5::tr("Continue slightly left");
389 else
390 return QGeoRouteParserOsrmV5::tr("Continue slightly left onto %1").arg(wayName);
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);
397 if (wayName.isEmpty())
398 return QGeoRouteParserOsrmV5::tr("Turn right");
399 else
400 return QGeoRouteParserOsrmV5::tr("Turn right onto %1").arg(wayName);
403 if (wayName.isEmpty())
404 return QGeoRouteParserOsrmV5::tr("Continue slightly right");
405 else
406 return QGeoRouteParserOsrmV5::tr("Continue slightly right onto %1").arg(wayName);
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);
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
427{
428 switch (direction) {
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);
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);
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
457{
458 switch (direction) {
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);
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);
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
490
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
527{
528 switch (direction) {
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);
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);
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);
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
572{
573 switch (direction) {
575 if (wayName.isEmpty())
576 return QGeoRouteParserOsrmV5::tr("Go straight");
577 else
578 return QGeoRouteParserOsrmV5::tr("Go straight onto %1").arg(wayName);
581 if (wayName.isEmpty())
582 return QGeoRouteParserOsrmV5::tr("Turn left");
583 else
584 return QGeoRouteParserOsrmV5::tr("Turn left onto %1").arg(wayName);
587 if (wayName.isEmpty())
588 return QGeoRouteParserOsrmV5::tr("Turn slightly left");
589 else
590 return QGeoRouteParserOsrmV5::tr("Turn slightly left onto %1").arg(wayName);
593 if (wayName.isEmpty())
594 return QGeoRouteParserOsrmV5::tr("Turn right");
595 else
596 return QGeoRouteParserOsrmV5::tr("Turn right onto %1").arg(wayName);
599 if (wayName.isEmpty())
600 return QGeoRouteParserOsrmV5::tr("Turn slightly right");
601 else
602 return QGeoRouteParserOsrmV5::tr("Turn slightly right onto %1").arg(wayName);
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
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) {
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);
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);
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);
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);
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);
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);
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);
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
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"))
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
741{
742 QString modifier;
743 if (maneuver.value(QLatin1String("modifier")).isString())
744 modifier = maneuver.value(QLatin1String("modifier")).toString();
745
746 if (modifier.isEmpty())
748 else if (modifier == QLatin1String("straight"))
750 else if (modifier == QLatin1String("right"))
752 else if (modifier == QLatin1String("sharp right"))
754 else if (modifier == QLatin1String("slight right"))
756 else if (modifier == QLatin1String("uturn")) {
757 switch (trafficSide) {
762 }
764 } else if (modifier == QLatin1String("left"))
766 else if (modifier == QLatin1String("sharp left"))
768 else if (modifier == QLatin1String("slight left"))
770 else
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
796
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".
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
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;
883 }
884 if (!object.value(QLatin1String("routes")).isArray()) {
885 errorString = QLatin1String("No routes found");
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();
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
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);
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
985 } else {
986 errorString = QLatin1String("Couldn't parse json.");
988 }
989}
990
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);
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)
1013 return url;
1014}
1015
1020
1024
1031
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtPositioning
\inmodule QtLocation
void setDirection(InstructionDirection direction)
InstructionDirection
\qmltype routeManeuver \inqmlmodule QtLocation
\inmodule QtPositioning
Definition qgeopath.h:16
virtual void updateQuery(QUrlQuery &query) const =0
virtual void updateSegment(QGeoRouteSegment &segment, const QJsonObject &step, const QJsonObject &maneuver) const =0
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
void setExtension(const QGeoRouteParserOsrmV5Extension *extension)
QGeoRouteParserOsrmV5(QObject *parent=nullptr)
QGeoRouteParser::TrafficSide trafficSide
Error
Describes an error which prevented the completion of the operation.
\inmodule QtLocation
static QGeoRouteSegmentPrivate * get(QGeoRouteSegment &segment)
\inmodule QtLocation
\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)
void setRouteLegs(const QList< QGeoRoute > &legs)
void setBounds(const QGeoRectangle &bounds)
Q_INVOKABLE QGeoRectangle boundingGeoRectangle() const
Returns a QGeoRectangle representing the geographical bounding rectangle of the geo shape,...
\inmodule QtCore\reentrant
Definition qjsonarray.h:18
qsizetype size() const
Returns the number of values stored in the array.
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
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
iterator find(const QString &key)
Returns an iterator pointing to the item with key key in the map.
QJsonValue value(const QString &key) const
Returns a QJsonValue representing the value for the key key.
\inmodule QtCore\reentrant
Definition qjsonvalue.h:25
int toInt(int defaultValue=0) const
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...
double toDouble(double defaultValue=0) const
Converts the value to a double and returns it.
QString toString() const
Converts the value to a QString and returns it.
bool isObject() const
Returns true if the value contains an object.
Definition qjsonvalue.h:77
QVariant toVariant() const
Converts the value to a \l {QVariant::}{QVariant()}.
static CardinalDirection azimuthToCardinalDirection4(double azimuth)
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
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
void extension()
[6]
Definition dialogs.cpp:230
direction
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
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
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 QT_BEGIN_NAMESPACE QList< QGeoCoordinate > decodePolyline(const QString &polylineString)
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)
GLboolean r
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLfloat distance
GLdouble s
[6]
Definition qopenglext.h:235
GLenum query
const GLubyte * c
GLuint segment
GLuint coord
GLsizei const GLchar *const * path
GLuint segments
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
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