1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtLocation module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include "qgeoroutexmlparser.h" |
38 | |
39 | #include <QXmlStreamReader> |
40 | #include <QStringList> |
41 | #include <QString> |
42 | #include <QtCore/QThreadPool> |
43 | #include <QDebug> |
44 | |
45 | #include <QtPositioning/QGeoRectangle> |
46 | #include <QtPositioning/QGeoPath> |
47 | #include <QtLocation/QGeoRoute> |
48 | #include <QtLocation/private/qgeoroutesegment_p.h> |
49 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | QGeoDynamicSpeedInfoContainer::QGeoDynamicSpeedInfoContainer() |
53 | : trafficSpeed(0) |
54 | , baseSpeed(0) |
55 | , trafficTime(0) |
56 | , baseTime(0) |
57 | {} |
58 | |
59 | QGeoRouteXmlParser::QGeoRouteXmlParser(const QGeoRouteRequest &request) |
60 | : m_request(request) |
61 | { |
62 | } |
63 | |
64 | QGeoRouteXmlParser::~QGeoRouteXmlParser() |
65 | { |
66 | } |
67 | |
68 | void QGeoRouteXmlParser::parse(const QByteArray &data) |
69 | { |
70 | m_data = data; |
71 | // QFile file("/tmp/here.xml"); |
72 | // file.open(QIODevice::WriteOnly); |
73 | // file.write(data); |
74 | // file.close(); |
75 | QThreadPool::globalInstance()->start(runnable: this); |
76 | } |
77 | |
78 | void QGeoRouteXmlParser::run() |
79 | { |
80 | m_reader = new QXmlStreamReader(m_data); |
81 | |
82 | if (!parseRootElement()) |
83 | emit error(errorString: m_reader->errorString()); |
84 | else |
85 | emit results(routes: m_results); |
86 | |
87 | delete m_reader; |
88 | m_reader = 0; |
89 | } |
90 | |
91 | bool QGeoRouteXmlParser::parseRootElement() |
92 | { |
93 | if (!m_reader->readNextStartElement()) { |
94 | m_reader->raiseError(message: "Expected a root element named \"CalculateRoute\" (no root element found)." ); |
95 | return false; |
96 | } |
97 | |
98 | if (m_reader->name() == QLatin1String("Error" )) { |
99 | QXmlStreamAttributes attributes = m_reader->attributes(); |
100 | if (attributes.value(QStringLiteral("type" )) == QLatin1String("ApplicationError" ) |
101 | && attributes.value(qualifiedName: "subtype" ) == QLatin1String("NoRouteFound" )) |
102 | return true; |
103 | } |
104 | |
105 | bool updateroute = false; |
106 | if (m_reader->name() != "CalculateRoute" && m_reader->name() != "GetRoute" ) { |
107 | m_reader->raiseError(message: QString("The root element is expected to have the name \"CalculateRoute\" or \"GetRoute\" (root element was named \"%1\")." ).arg(a: m_reader->name().toString())); |
108 | return false; |
109 | } else if (m_reader->name() == "GetRoute" ) { |
110 | updateroute = true; |
111 | } |
112 | |
113 | if (m_reader->readNextStartElement()) { |
114 | if (m_reader->name() != "Response" ) { |
115 | m_reader->raiseError(message: QString("Expected a element named \"Response\" (element was named \"%1\")." ).arg(a: m_reader->name().toString())); |
116 | return false; |
117 | } |
118 | } |
119 | |
120 | while (m_reader->readNextStartElement() && !m_reader->hasError()) { |
121 | if (m_reader->name() == "Route" ) { |
122 | QGeoRoute route; |
123 | route.setRequest(m_request); |
124 | if (updateroute) |
125 | route.setTravelMode(QGeoRouteRequest::TravelMode(int(m_request.travelModes()))); |
126 | if (!parseRoute(route: &route)) |
127 | continue; //route parsing failed move on to the next |
128 | m_results.append(t: route); |
129 | } else if (m_reader->name() == "Progress" ) { |
130 | //TODO: updated route progress |
131 | m_reader->skipCurrentElement(); |
132 | } else { |
133 | m_reader->skipCurrentElement(); |
134 | } |
135 | } |
136 | |
137 | return !m_reader->hasError(); |
138 | } |
139 | |
140 | bool QGeoRouteXmlParser::parseRoute(QGeoRoute *route) |
141 | { |
142 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Route" ); |
143 | m_maneuvers.clear(); |
144 | // m_segments.clear(); |
145 | m_legs.clear(); |
146 | int legIndex = 0; |
147 | m_reader->readNext(); |
148 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Route" ) && |
149 | !m_reader->hasError()) { |
150 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
151 | if (m_reader->name() == "RouteId" ) { |
152 | route->setRouteId(m_reader->readElementText()); |
153 | } |
154 | //else if (m_reader->name() == "Waypoint") { |
155 | // succeeded = parseWaypoint(route); |
156 | //} |
157 | else if (m_reader->name() == "Mode" ) { |
158 | if (!parseMode(route)) |
159 | return false; |
160 | } else if (m_reader->name() == "Shape" ) { |
161 | QString elementName = m_reader->name().toString(); |
162 | QList<QGeoCoordinate> path; |
163 | if (!parseGeoPoints(strPoints: m_reader->readElementText(), geoPoints: &path, elementName)) |
164 | return false; |
165 | route->setPath(path); |
166 | } else if (m_reader->name() == "BoundingBox" ) { |
167 | QGeoRectangle bounds; |
168 | if (!parseBoundingBox(bounds)) |
169 | return false; |
170 | route->setBounds(bounds); |
171 | } else if (m_reader->name() == "Leg" ) { |
172 | if (!parseLeg(legIndex: legIndex++)) |
173 | return false; |
174 | } else if (m_reader->name() == "Summary" ) { |
175 | if (!parseSummary(route)) |
176 | return false; |
177 | } else { |
178 | m_reader->skipCurrentElement(); |
179 | } |
180 | } |
181 | m_reader->readNext(); |
182 | } |
183 | |
184 | if (m_reader->hasError()) |
185 | return false; |
186 | |
187 | return postProcessRoute(route); |
188 | } |
189 | |
190 | bool QGeoRouteXmlParser::parseLeg(int legIndex) |
191 | { |
192 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == QStringLiteral("Leg" )); |
193 | QGeoRouteLeg leg; |
194 | leg.setLegIndex(legIndex); |
195 | m_reader->readNext(); |
196 | QList<QGeoManeuverContainer> maneuvers; |
197 | QList<QGeoRouteSegmentContainer> links; |
198 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement |
199 | && m_reader->name() == QStringLiteral("Leg" )) && |
200 | !m_reader->hasError()) { |
201 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
202 | if (m_reader->name() == QStringLiteral("Maneuver" )) { |
203 | if (!parseManeuver(maneuvers)) |
204 | return false; |
205 | } |
206 | // Currently unused, after requesting shape attribute in maneuvers. |
207 | // Links, however, contain additional info, such as speed limits, and might become needed in the future. |
208 | // else if (m_reader->name() == QStringLiteral("Link")) { |
209 | // if (!parseLink(links)) |
210 | // return false; |
211 | // } |
212 | else if (m_reader->name() == "TravelTime" ) { |
213 | leg.setTravelTime(qRound(d: m_reader->readElementText().toDouble())); |
214 | } else if (m_reader->name() == "Length" ) { |
215 | leg.setDistance(m_reader->readElementText().toDouble()); |
216 | } else { |
217 | m_reader->skipCurrentElement(); |
218 | } |
219 | } |
220 | m_reader->readNext(); |
221 | } |
222 | |
223 | if (m_reader->hasError()) |
224 | return false; |
225 | |
226 | m_legs << leg; |
227 | // m_segments << links; |
228 | m_maneuvers << maneuvers; |
229 | return true; |
230 | } |
231 | |
232 | //static bool fuzzyCompare(const QGeoCoordinate &a, const QGeoCoordinate& b) |
233 | //{ |
234 | // return qFuzzyCompare(a.latitude(), b.latitude()) && qFuzzyCompare(a.longitude(), b.longitude()); |
235 | //} |
236 | |
237 | bool QGeoRouteXmlParser::postProcessRoute(QGeoRoute *route) |
238 | { |
239 | QList<QList<QGeoRouteSegment>> legSegments; |
240 | Q_ASSERT(m_maneuvers.size()); |
241 | |
242 | |
243 | // Step 3: populate the linkMap, linkId -> linkContainer |
244 | for (int i = 0; i < m_maneuvers.size(); i++) { |
245 | legSegments << QList<QGeoRouteSegment>(); |
246 | QList<QGeoRouteSegment> &segments = legSegments[i]; |
247 | QList<QGeoManeuverContainer> &maneuvers = m_maneuvers[i]; |
248 | for (int j = 0; j < m_maneuvers.at(i).size(); j++) { |
249 | QGeoManeuverContainer &maneuver = maneuvers[j]; |
250 | QGeoRouteSegment segment; |
251 | |
252 | QVariantMap extendedAttributes; |
253 | extendedAttributes["first" ] = maneuver.first; |
254 | extendedAttributes["last" ] = maneuver.last; |
255 | extendedAttributes["legIndex" ] = i; |
256 | extendedAttributes["id" ] = maneuver.id; |
257 | extendedAttributes["toLink" ] = maneuver.toLink; |
258 | extendedAttributes["index" ] = j; |
259 | maneuver.maneuver.setExtendedAttributes(extendedAttributes); |
260 | |
261 | segment.setDistance(maneuver.maneuver.distanceToNextInstruction()); |
262 | segment.setTravelTime(maneuver.maneuver.timeToNextInstruction()); |
263 | segment.setPath(maneuver.path); |
264 | segment.setManeuver(maneuver.maneuver); |
265 | segments << segment; |
266 | } |
267 | } |
268 | |
269 | // Step 7: connect all segments. |
270 | QGeoRouteSegment segment; |
271 | QGeoRouteSegment firstSegment; |
272 | for (auto &segments: legSegments) { |
273 | for (int j = 0; j < segments.size(); j++) { |
274 | if (segment.isValid()) { |
275 | segment.setNextRouteSegment(segments[j]); |
276 | } else { |
277 | firstSegment = segments[j]; |
278 | } |
279 | segment = segments[j]; |
280 | if (j == segments.size() - 1) { |
281 | QGeoRouteSegmentPrivate *sp = QGeoRouteSegmentPrivate::get(segment); |
282 | sp->setLegLastSegment(true); |
283 | } |
284 | } |
285 | } |
286 | |
287 | if (firstSegment.isValid()) |
288 | route->setFirstRouteSegment(firstSegment); |
289 | |
290 | // Step 8: fill route legs. |
291 | for (int i = 0; i < m_legs.size(); i++) { |
292 | m_legs[i].setTravelMode(route->travelMode()); |
293 | m_legs[i].setRequest(route->request()); |
294 | m_legs[i].setOverallRoute(*route); |
295 | m_legs[i].setLegIndex(i); |
296 | |
297 | m_legs[i].setFirstRouteSegment(legSegments[i].first()); |
298 | |
299 | // handle path |
300 | QList<QGeoCoordinate> path; |
301 | QGeoRouteSegment s = m_legs[i].firstRouteSegment(); |
302 | while (s.isValid()) { |
303 | path.append(t: s.path()); |
304 | if (s.isLegLastSegment()) |
305 | break; |
306 | s = s.nextRouteSegment(); |
307 | } |
308 | m_legs[i].setPath(path); |
309 | m_legs[i].setBounds(QGeoPath(path).boundingGeoRectangle()); |
310 | } |
311 | route->setRouteLegs(m_legs); |
312 | m_legs.clear(); |
313 | // m_segments.clear(); |
314 | m_maneuvers.clear(); |
315 | return true; |
316 | } |
317 | |
318 | /* |
319 | bool QGeoRouteXmlParser::parseWaypoint(QGeoRoute *route) |
320 | { |
321 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Waypoint"); |
322 | m_reader->readNext(); |
323 | QList<QGeoCoordinate> path(route->pathSummary()); |
324 | |
325 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Waypoint")) { |
326 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
327 | if (m_reader->name() == "MappedPosition") { |
328 | QGeoCoordinate coordinates; |
329 | if(!parseCoordinates(coordinates)) |
330 | return false; |
331 | path.append(coordinates); |
332 | } |
333 | else { |
334 | m_reader->skipCurrentElement(); |
335 | } |
336 | } |
337 | m_reader->readNext(); |
338 | } |
339 | route->setPathSummary(path); |
340 | return true; |
341 | } |
342 | */ |
343 | |
344 | bool QGeoRouteXmlParser::parseMode(QGeoRoute *route) |
345 | { |
346 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Mode" ); |
347 | m_reader->readNext(); |
348 | |
349 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Mode" ) && |
350 | !m_reader->hasError()) { |
351 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
352 | if (m_reader->name() == "TransportModes" ) { |
353 | QString value = m_reader->readElementText(); |
354 | if (value == "car" ) |
355 | route->setTravelMode(QGeoRouteRequest::CarTravel); |
356 | else if (value == "pedestrian" ) |
357 | route->setTravelMode(QGeoRouteRequest::PedestrianTravel); |
358 | else if (value == "publicTransport" ) |
359 | route->setTravelMode(QGeoRouteRequest::PublicTransitTravel); |
360 | else if (value == "bicycle" ) |
361 | route->setTravelMode(QGeoRouteRequest::BicycleTravel); |
362 | else if (value == "truck" ) |
363 | route->setTravelMode(QGeoRouteRequest::TruckTravel); |
364 | else { |
365 | // unsupported mode |
366 | m_reader->raiseError(message: QString("Unsupported travel mode '\"%1\"'" ).arg(a: value)); |
367 | return false; |
368 | } |
369 | } else { |
370 | m_reader->skipCurrentElement(); |
371 | } |
372 | } |
373 | m_reader->readNext(); |
374 | } |
375 | return !m_reader->hasError(); |
376 | } |
377 | |
378 | bool QGeoRouteXmlParser::parseSummary(QGeoRoute *route) |
379 | { |
380 | Q_ASSERT(route); |
381 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Summary" ); |
382 | m_reader->readNext(); |
383 | |
384 | double baseTime = -1, trafficTime = -1; |
385 | |
386 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Summary" ) && |
387 | !m_reader->hasError()) { |
388 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
389 | if (m_reader->name() == "Distance" ) { |
390 | route->setDistance(m_reader->readElementText().toDouble()); |
391 | } else if (m_reader->name() == "TrafficTime" ) { |
392 | trafficTime = m_reader->readElementText().toDouble(); |
393 | } else if (m_reader->name() == "BaseTime" ) { |
394 | baseTime = m_reader->readElementText().toDouble(); |
395 | } else { |
396 | m_reader->skipCurrentElement(); |
397 | } |
398 | } |
399 | m_reader->readNext(); |
400 | } |
401 | |
402 | if (m_reader->hasError()) |
403 | return false; |
404 | |
405 | if (trafficTime >= 0) |
406 | route->setTravelTime(trafficTime); |
407 | else if (baseTime >= 0) |
408 | route->setTravelTime(baseTime); |
409 | |
410 | return true; |
411 | } |
412 | |
413 | bool QGeoRouteXmlParser::parseCoordinates(QGeoCoordinate &coord) |
414 | { |
415 | QString currentElement = m_reader->name().toString(); |
416 | m_reader->readNext(); |
417 | |
418 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == currentElement) && |
419 | !m_reader->hasError()) { |
420 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
421 | QString name = m_reader->name().toString(); |
422 | QString value = m_reader->readElementText(); |
423 | if (name == "Latitude" ) |
424 | coord.setLatitude(value.toDouble()); |
425 | else if (name == "Longitude" ) |
426 | coord.setLongitude(value.toDouble()); |
427 | } |
428 | m_reader->readNext(); |
429 | } |
430 | |
431 | return !m_reader->hasError(); |
432 | } |
433 | |
434 | bool QGeoRouteXmlParser::parseManeuver(QList<QGeoManeuverContainer> &maneuvers) |
435 | { |
436 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "Maneuver" ); |
437 | |
438 | if (!m_reader->attributes().hasAttribute(qualifiedName: "id" )) { |
439 | m_reader->raiseError(message: "The element \"Maneuver\" did not have the required attribute \"id\"." ); |
440 | return false; |
441 | } |
442 | QGeoManeuverContainer maneuverContainter; |
443 | maneuverContainter.id = m_reader->attributes().value(qualifiedName: "id" ).toString(); |
444 | |
445 | m_reader->readNext(); |
446 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "Maneuver" ) && |
447 | !m_reader->hasError()) { |
448 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
449 | if (m_reader->name() == "Position" ) { |
450 | QGeoCoordinate coordinates; |
451 | if (parseCoordinates(coord&: coordinates)) |
452 | maneuverContainter.maneuver.setPosition(coordinates); |
453 | } else if (m_reader->name() == "Instruction" ) { |
454 | maneuverContainter.maneuver.setInstructionText(m_reader->readElementText()); |
455 | } else if (m_reader->name() == "Shape" ) { |
456 | QString elementName = m_reader->name().toString(); |
457 | QList<QGeoCoordinate> path; |
458 | if (!parseGeoPoints(strPoints: m_reader->readElementText(), geoPoints: &path, elementName)) |
459 | return false; |
460 | maneuverContainter.path = path; |
461 | } else if (m_reader->name() == "ToLink" ) { |
462 | maneuverContainter.toLink = m_reader->readElementText(); |
463 | } else if (m_reader->name() == "TravelTime" ) { |
464 | maneuverContainter.maneuver.setTimeToNextInstruction(qRound(d: m_reader->readElementText().toDouble())); |
465 | } else if (m_reader->name() == "Length" ) { |
466 | maneuverContainter.maneuver.setDistanceToNextInstruction(m_reader->readElementText().toDouble()); |
467 | } else if (m_reader->name() == "Direction" ) { |
468 | QString value = m_reader->readElementText(); |
469 | if (value == "forward" ) |
470 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionForward); |
471 | else if (value == "bearRight" ) |
472 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionBearRight); |
473 | else if (value == "lightRight" ) |
474 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionLightRight); |
475 | else if (value == "right" ) |
476 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionRight); |
477 | else if (value == "hardRight" ) |
478 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionHardRight); |
479 | else if (value == "uTurnRight" ) |
480 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionUTurnRight); |
481 | else if (value == "uTurnLeft" ) |
482 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionUTurnLeft); |
483 | else if (value == "hardLeft" ) |
484 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionHardLeft); |
485 | else if (value == "left" ) |
486 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionLeft); |
487 | else if (value == "lightLeft" ) |
488 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionLightLeft); |
489 | else if (value == "bearLeft" ) |
490 | maneuverContainter.maneuver.setDirection(QGeoManeuver::DirectionBearLeft); |
491 | else |
492 | maneuverContainter.maneuver.setDirection(QGeoManeuver::NoDirection); |
493 | } else { |
494 | m_reader->skipCurrentElement(); |
495 | } |
496 | } |
497 | m_reader->readNext(); |
498 | } |
499 | |
500 | if (m_reader->hasError()) |
501 | return false; |
502 | |
503 | maneuvers.append(t: maneuverContainter); |
504 | return true; |
505 | } |
506 | |
507 | bool QGeoRouteXmlParser::parseLink(QList<QGeoRouteSegmentContainer> &links) |
508 | { |
509 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == QStringLiteral("Link" )); |
510 | m_reader->readNext(); |
511 | |
512 | QGeoRouteSegmentContainer segmentContainer; |
513 | |
514 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == QStringLiteral("Link" )) && |
515 | !m_reader->hasError()) { |
516 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
517 | if (m_reader->name() == QStringLiteral("LinkId" )) { |
518 | segmentContainer.id = m_reader->readElementText(); |
519 | } else if (m_reader->name() == QStringLiteral("Shape" )) { |
520 | QString elementName = m_reader->name().toString(); |
521 | QList<QGeoCoordinate> path; |
522 | parseGeoPoints(strPoints: m_reader->readElementText(), geoPoints: &path, elementName); |
523 | segmentContainer.segment.setPath(path); |
524 | } else if (m_reader->name() == QStringLiteral("Length" )) { |
525 | segmentContainer.segment.setDistance(m_reader->readElementText().toDouble()); |
526 | } else if (m_reader->name() == QStringLiteral("Maneuver" )) { |
527 | segmentContainer.maneuverId = m_reader->readElementText(); |
528 | } else if (m_reader->name() == QStringLiteral("DynamicSpeedInfo" )) { |
529 | QGeoDynamicSpeedInfoContainer speedInfo; |
530 | if (!parseDynamicSpeedInfo(speedInfo)) |
531 | return false; |
532 | const double time = speedInfo.trafficTime >= 0 ? speedInfo.trafficTime : speedInfo.baseTime; |
533 | if (time >= 0) |
534 | segmentContainer.segment.setTravelTime(time); |
535 | } else { |
536 | m_reader->skipCurrentElement(); |
537 | } |
538 | } |
539 | m_reader->readNext(); |
540 | } |
541 | |
542 | if (m_reader->hasError()) |
543 | return false; |
544 | links.append(t: segmentContainer); |
545 | return true; |
546 | } |
547 | |
548 | bool QGeoRouteXmlParser::parseGeoPoints(const QString &strPoints, QList<QGeoCoordinate> *geoPoints, const QString &elementName) |
549 | { |
550 | QStringList rawPoints = strPoints.split(sep: ' '); |
551 | |
552 | for (int i = 0; i < rawPoints.length(); ++i) { |
553 | QStringList coords = rawPoints[i].split(sep: ','); |
554 | |
555 | if (coords.length() != 2) { |
556 | m_reader->raiseError(message: QString("Each of the space separated values of \"%1\" is expected to be a comma separated pair of coordinates (value was \"%2\")" ).arg(a: elementName).arg(a: rawPoints[i])); |
557 | return false; |
558 | } |
559 | |
560 | bool ok = false; |
561 | QString latString = coords[0]; |
562 | double lat = latString.toDouble(ok: &ok); |
563 | |
564 | if (!ok) { |
565 | m_reader->raiseError(message: QString("The latitude portions of \"%1\" are expected to have a value convertable to a double (value was \"%2\")" ).arg(a: elementName).arg(a: latString)); |
566 | return false; |
567 | } |
568 | |
569 | QString lngString = coords[1]; |
570 | double lng = lngString.toDouble(ok: &ok); |
571 | |
572 | if (!ok) { |
573 | m_reader->raiseError(message: QString("The longitude portions of \"%1\" are expected to have a value convertable to a double (value was \"%2\")" ).arg(a: elementName).arg(a: lngString)); |
574 | return false; |
575 | } |
576 | |
577 | QGeoCoordinate geoPoint(lat, lng); |
578 | geoPoints->append(t: geoPoint); |
579 | } |
580 | |
581 | return true; |
582 | } |
583 | |
584 | bool QGeoRouteXmlParser::parseBoundingBox(QGeoRectangle &bounds) |
585 | { |
586 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == "BoundingBox" ); |
587 | |
588 | QGeoCoordinate tl; |
589 | QGeoCoordinate br; |
590 | |
591 | m_reader->readNext(); |
592 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == "BoundingBox" ) && |
593 | !m_reader->hasError()) { |
594 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
595 | if (m_reader->name() == "TopLeft" ) { |
596 | QGeoCoordinate coordinates; |
597 | if (parseCoordinates(coord&: coordinates)) |
598 | tl = coordinates; |
599 | } else if (m_reader->name() == "BottomRight" ) { |
600 | QGeoCoordinate coordinates; |
601 | if (parseCoordinates(coord&: coordinates)) |
602 | br = coordinates; |
603 | } else { |
604 | m_reader->skipCurrentElement(); |
605 | } |
606 | } |
607 | m_reader->readNext(); |
608 | } |
609 | |
610 | if (m_reader->hasError()) |
611 | return false; |
612 | |
613 | if (tl.isValid() && br.isValid()) { |
614 | bounds = QGeoRectangle(tl, br); |
615 | return true; |
616 | } |
617 | |
618 | return false; |
619 | } |
620 | |
621 | bool QGeoRouteXmlParser::parseDynamicSpeedInfo(QGeoDynamicSpeedInfoContainer &speedInfo) |
622 | { |
623 | Q_ASSERT(m_reader->isStartElement() && m_reader->name() == QStringLiteral("DynamicSpeedInfo" )); |
624 | |
625 | m_reader->readNext(); |
626 | while (!(m_reader->tokenType() == QXmlStreamReader::EndElement && m_reader->name() == QStringLiteral("DynamicSpeedInfo" )) && |
627 | !m_reader->hasError()) { |
628 | if (m_reader->tokenType() == QXmlStreamReader::StartElement) { |
629 | if (m_reader->name() == QStringLiteral("TrafficSpeed" )) { |
630 | speedInfo.trafficSpeed = m_reader->readElementText().toDouble(); |
631 | } else if (m_reader->name() == QStringLiteral("TrafficTime" )) { |
632 | speedInfo.trafficTime = qRound(d: m_reader->readElementText().toDouble()); |
633 | } else if (m_reader->name() == QStringLiteral("BaseSpeed" )) { |
634 | speedInfo.baseSpeed = m_reader->readElementText().toDouble(); |
635 | } else if (m_reader->name() == QStringLiteral("BaseTime" )) { |
636 | speedInfo.baseTime = qRound(d: m_reader->readElementText().toDouble()); |
637 | } else { |
638 | m_reader->skipCurrentElement(); |
639 | } |
640 | } |
641 | m_reader->readNext(); |
642 | } |
643 | |
644 | return !m_reader->hasError(); |
645 | } |
646 | |
647 | QT_END_NAMESPACE |
648 | |