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
qgeoroutingmanagerengine_nokia.cpp
Go to the documentation of this file.
1// Copyright (C) 2015 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
9
10#include <QStringList>
11#include <QUrl>
12#include <QLocale>
13#include <QtPositioning/QGeoRectangle>
14
16
18 QGeoNetworkAccessManager *networkManager,
19 const QVariantMap &parameters,
20 QGeoServiceProvider::Error *error,
21 QString *errorString)
22 : QGeoRoutingManagerEngine(parameters)
23 , m_networkManager(networkManager)
24 , m_uriProvider(new QGeoUriProvider(this, parameters, QStringLiteral("here.routing.host"), ROUTING_HOST))
25
26{
27 Q_ASSERT(networkManager);
28 m_networkManager->setParent(this);
29
30 m_apiKey = parameters.value(QStringLiteral("here.apiKey")).toString();
31
32 QGeoRouteRequest::FeatureTypes featureTypes;
33 featureTypes |= QGeoRouteRequest::TollFeature;
34 featureTypes |= QGeoRouteRequest::HighwayFeature;
35 featureTypes |= QGeoRouteRequest::FerryFeature;
36 featureTypes |= QGeoRouteRequest::TunnelFeature;
37 featureTypes |= QGeoRouteRequest::DirtRoadFeature;
38 featureTypes |= QGeoRouteRequest::ParksFeature;
39 setSupportedFeatureTypes(featureTypes);
40
41 QGeoRouteRequest::FeatureWeights featureWeights;
42 featureWeights |= QGeoRouteRequest::DisallowFeatureWeight;
43 featureWeights |= QGeoRouteRequest::AvoidFeatureWeight;
44 featureWeights |= QGeoRouteRequest::PreferFeatureWeight;
45 setSupportedFeatureWeights(featureWeights);
46
47 QGeoRouteRequest::ManeuverDetails maneuverDetails;
48 maneuverDetails |= QGeoRouteRequest::BasicManeuvers;
49 setSupportedManeuverDetails(maneuverDetails);
50
51 QGeoRouteRequest::RouteOptimizations optimizations;
52 optimizations |= QGeoRouteRequest::ShortestRoute;
53 optimizations |= QGeoRouteRequest::FastestRoute;
54 setSupportedRouteOptimizations(optimizations);
55
56 QGeoRouteRequest::TravelModes travelModes;
57 travelModes |= QGeoRouteRequest::CarTravel;
58 travelModes |= QGeoRouteRequest::PedestrianTravel;
59 travelModes |= QGeoRouteRequest::PublicTransitTravel;
60 travelModes |= QGeoRouteRequest::BicycleTravel;
61 setSupportedTravelModes(travelModes);
62
63 QGeoRouteRequest::SegmentDetails segmentDetails;
64 segmentDetails |= QGeoRouteRequest::BasicSegmentData;
65 setSupportedSegmentDetails(segmentDetails);
66
67 if (error)
68 *error = QGeoServiceProvider::NoError;
69
70 if (errorString)
71 *errorString = QString();
72}
73
75
76QGeoRouteReply *QGeoRoutingManagerEngineNokia::calculateRoute(const QGeoRouteRequest &request)
77{
78 const QStringList reqStrings = calculateRouteRequestString(request);
79
80 if (reqStrings.isEmpty()) {
81 QGeoRouteReply *reply = new QGeoRouteReply(QGeoRouteReply::UnsupportedOptionError, "The given route request options are not supported by this service provider.", this);
82 emit errorOccurred(reply, reply->error(), reply->errorString());
83 return reply;
84 }
85
86 QList<QNetworkReply*> replies;
87 for (const QString &reqString : reqStrings)
88 replies.append(m_networkManager->get(QNetworkRequest(QUrl(reqString))));
89
90 QGeoRouteReplyNokia *reply = new QGeoRouteReplyNokia(request, replies, this);
91
92 connect(reply, &QGeoRouteReplyNokia::finished,
93 this, &QGeoRoutingManagerEngineNokia::routeFinished);
94 connect(reply, &QGeoRouteReplyNokia::errorOccurred,
95 this, &QGeoRoutingManagerEngineNokia::routeError);
96
97 return reply;
98}
99
100QGeoRouteReply *QGeoRoutingManagerEngineNokia::updateRoute(const QGeoRoute &route, const QGeoCoordinate &position)
101{
102 const QStringList reqStrings = updateRouteRequestString(route, position);
103
104 if (reqStrings.isEmpty()) {
105 QGeoRouteReply *reply = new QGeoRouteReply(QGeoRouteReply::UnsupportedOptionError, "The given route request options are not supported by this service provider.", this);
106 emit errorOccurred(reply, reply->error(), reply->errorString());
107 return reply;
108 }
109
110 QList<QNetworkReply*> replies;
111 for (const QString &reqString : reqStrings)
112 replies.append(m_networkManager->get(QNetworkRequest(QUrl(reqString))));
113
114 QGeoRouteRequest updateRequest(route.request());
115 updateRequest.setTravelModes(route.travelMode());
116 QGeoRouteReplyNokia *reply = new QGeoRouteReplyNokia(updateRequest, replies, this);
117
118 connect(reply, &QGeoRouteReplyNokia::finished,
119 this, &QGeoRoutingManagerEngineNokia::routeFinished);
120 connect(reply, &QGeoRouteReplyNokia::errorOccurred,
121 this, &QGeoRoutingManagerEngineNokia::routeError);
122
123 return reply;
124}
125
126bool QGeoRoutingManagerEngineNokia::checkEngineSupport(const QGeoRouteRequest &request,
127 QGeoRouteRequest::TravelModes travelModes) const
128{
129 const QList<QGeoRouteRequest::FeatureType> featureTypeList = request.featureTypes();
130 QGeoRouteRequest::FeatureTypes featureTypeFlag = QGeoRouteRequest::NoFeature;
131 QGeoRouteRequest::FeatureWeights featureWeightFlag = QGeoRouteRequest::NeutralFeatureWeight;
132
133 for (const auto &featureType : featureTypeList) {
134 featureTypeFlag |= featureType;
135 featureWeightFlag |= request.featureWeight(featureType);
136 }
137
138 if ((featureTypeFlag & supportedFeatureTypes()) != featureTypeFlag)
139 return false;
140
141 if ((featureWeightFlag & supportedFeatureWeights()) != featureWeightFlag)
142 return false;
143
144
145 if ((request.maneuverDetail() & supportedManeuverDetails()) != request.maneuverDetail())
146 return false;
147
148 if ((request.segmentDetail() & supportedSegmentDetails()) != request.segmentDetail())
149 return false;
150
151 if ((request.routeOptimization() & supportedRouteOptimizations()) != request.routeOptimization())
152 return false;
153
154 if ((travelModes & supportedTravelModes()) != travelModes)
155 return false;
156
157 // Count the number of set bits (= number of travel modes) (popcount)
158 int count = 0;
159
160 for (unsigned bits = travelModes; bits; bits >>= 1)
161 count += (bits & 1);
162
163 // We only allow one travel mode at a time
164 if (count != 1)
165 return false;
166
167 return true;
168}
169
170QStringList QGeoRoutingManagerEngineNokia::calculateRouteRequestString(const QGeoRouteRequest &request) const
171{
172 bool supported = checkEngineSupport(request, request.travelModes());
173
174 if (!supported)
175 return QStringList();
176 QStringList requests;
177
178 QString baseRequest = QStringLiteral("https://");
179 baseRequest += m_uriProvider->getCurrentHost();
180 baseRequest += QStringLiteral("/routing/7.2/calculateroute.xml");
181
182 baseRequest += QStringLiteral("?alternatives=");
183 baseRequest += QString::number(request.numberAlternativeRoutes());
184
185 if (!m_apiKey.isEmpty()) {
186 baseRequest += QStringLiteral("&apiKey=");
187 baseRequest += m_apiKey;
188 }
189
190 const QList<QGeoCoordinate> waypoints = request.waypoints();
191 int numWaypoints = waypoints.size();
192 if (numWaypoints < 2)
193 return QStringList();
194 // Details: https://developer.here.com/documentation/routing/topics/resource-param-type-waypoint.html
195 for (int i = 0;i < numWaypoints;++i) {
196 const QGeoCoordinate &c = waypoints.at(i);
197 baseRequest += QStringLiteral("&waypoint");
198 baseRequest += QString::number(i);
199 baseRequest += QStringLiteral("=geo!");
200 baseRequest += trimDouble(c.latitude());
201 baseRequest += ',';
202 baseRequest += trimDouble(c.longitude());
203 baseRequest += QStringLiteral(";;"); // ;<TransitRadius>;<UserLabel>
204 }
205
206 QGeoRouteRequest::RouteOptimizations optimization = request.routeOptimization();
207
208 QStringList types;
209 if (optimization.testFlag(QGeoRouteRequest::ShortestRoute))
210 types.append("shortest");
211 if (optimization.testFlag(QGeoRouteRequest::FastestRoute))
212 types.append("fastest");
213
214 for (const QString &optimization : types) {
215 QString requestString = baseRequest;
216 requestString += modesRequestString(request, request.travelModes(), optimization);
217 requestString += routeRequestString(request);
218 requests << requestString;
219 }
220
221 return requests;
222}
223
224QStringList QGeoRoutingManagerEngineNokia::updateRouteRequestString(const QGeoRoute &route, const QGeoCoordinate &position)
225{
226 if (!checkEngineSupport(route.request(), route.travelMode()))
227 return QStringList();
228 QStringList requests;
229
230 QString baseRequest = "https://";
231 baseRequest += m_uriProvider->getCurrentHost();
232 baseRequest += "/routing/7.2/getroute.xml";
233
234 baseRequest += "?routeid=";
235 baseRequest += route.routeId();
236
237 baseRequest += "&pos=";
238 baseRequest += QString::number(position.latitude());
239 baseRequest += ',';
240 baseRequest += QString::number(position.longitude());
241
242 QGeoRouteRequest::RouteOptimizations optimization = route.request().routeOptimization();
243
244 QStringList types;
245 if (optimization.testFlag(QGeoRouteRequest::ShortestRoute))
246 types.append("shortest");
247 if (optimization.testFlag(QGeoRouteRequest::FastestRoute))
248 types.append("fastest");
249
250 for (const QString &optimization : types) {
251 QString requestString = baseRequest;
252 requestString += modesRequestString(route.request(), route.travelMode(), optimization);
253 requestString += routeRequestString(route.request());
254 requests << requestString;
255 }
256
257 return requests;
258}
259
260QString QGeoRoutingManagerEngineNokia::modesRequestString(const QGeoRouteRequest &request,
261 QGeoRouteRequest::TravelModes travelModes, const QString &optimization) const
262{
263 QString requestString;
264
265 QStringList modes;
266 if (travelModes.testFlag(QGeoRouteRequest::CarTravel))
267 modes.append("car");
268 if (travelModes.testFlag(QGeoRouteRequest::PedestrianTravel))
269 modes.append("pedestrian");
270 if (travelModes.testFlag(QGeoRouteRequest::PublicTransitTravel))
271 modes.append("publicTransport");
272
273 QStringList featureStrings;
274 QList<QGeoRouteRequest::FeatureType> featureTypes = request.featureTypes();
275 for (int i = 0; i < featureTypes.size(); ++i) {
276 QGeoRouteRequest::FeatureWeight weight = request.featureWeight(featureTypes.at(i));
277
278 if (weight == QGeoRouteRequest::NeutralFeatureWeight)
279 continue;
280
281 QString weightString = "";
282 switch (weight) {
283 case QGeoRouteRequest::PreferFeatureWeight:
284 weightString = '1';
285 break;
286 case QGeoRouteRequest::AvoidFeatureWeight:
287 weightString = "-1";
288 break;
289 case QGeoRouteRequest::DisallowFeatureWeight:
290 weightString = "-3";
291 break;
292 case QGeoRouteRequest::NeutralFeatureWeight:
293 case QGeoRouteRequest::RequireFeatureWeight:
294 break;
295 }
296
297 if (weightString.isEmpty())
298 continue;
299
300 switch (featureTypes.at(i)) {
301 case QGeoRouteRequest::TollFeature:
302 featureStrings.append("tollroad:" + weightString);
303 break;
304 case QGeoRouteRequest::HighwayFeature:
305 featureStrings.append("motorway:" + weightString);
306 break;
307 case QGeoRouteRequest::FerryFeature:
308 featureStrings.append("boatFerry:" + weightString);
309 featureStrings.append("railFerry:" + weightString);
310 break;
311 case QGeoRouteRequest::TunnelFeature:
312 featureStrings.append("tunnel:" + weightString);
313 break;
314 case QGeoRouteRequest::DirtRoadFeature:
315 featureStrings.append("dirtRoad:" + weightString);
316 break;
317 case QGeoRouteRequest::PublicTransitFeature:
318 case QGeoRouteRequest::ParksFeature:
319 case QGeoRouteRequest::MotorPoolLaneFeature:
320 case QGeoRouteRequest::TrafficFeature:
321 case QGeoRouteRequest::NoFeature:
322 break;
323 }
324 }
325
326 requestString += "&mode=";
327 requestString += optimization + ';' + modes.join(',');
328 if (featureStrings.count())
329 requestString += ';' + featureStrings.join(',');
330 return requestString;
331}
332
333QString QGeoRoutingManagerEngineNokia::routeRequestString(const QGeoRouteRequest &request) const
334{
335 QString requestString;
336
337 for (const QGeoRectangle &area : request.excludeAreas()) {
338 requestString += QLatin1String("&avoidareas=");
339 requestString += trimDouble(area.topLeft().latitude());
340 requestString += QLatin1String(",");
341 requestString += trimDouble(area.topLeft().longitude());
342 requestString += QLatin1String(";");
343 requestString += trimDouble(area.bottomRight().latitude());
344 requestString += QLatin1String(",");
345 requestString += trimDouble(area.bottomRight().longitude());
346 }
347
348 QStringList legAttributes;
349// if (request.segmentDetail() & QGeoRouteRequest::BasicSegmentData) // QTBUG-70501, this code expects to find links
350 {
351 requestString += "&linkattributes=sh,le"; //shape,length
352 legAttributes.append("links");
353 }
354
355// if (request.maneuverDetail() & QGeoRouteRequest::BasicManeuvers) // QTBUG-70501, this code expects to find maneuvers
356 {
357 legAttributes.append("maneuvers");
358 //requestString += "&maneuverattributes=po,tt,le,di"; //position,traveltime,length,direction
359 requestString += "&maneuverattributes=all";
360 if (!(request.segmentDetail() & QGeoRouteRequest::NoSegmentData))
361 requestString += ",li"; //link
362 }
363
364 // Handle QTBUG-70502, when API fixes it
365 requestString += "&routeattributes=sm,sh,bb,lg"; //summary,shape,boundingBox,legs
366 if (legAttributes.count() > 0) {
367 requestString += "&legattributes=";
368 requestString += legAttributes.join(",");
369 }
370
371 // Handle QTBUG-70503, when API fixes it
372 requestString += "&departure=";
373 requestString += QDateTime::currentDateTime().toUTC().toString("yyyy-MM-ddThh:mm:ssZ");
374
375 requestString += "&instructionformat=text";
376
377 // ToDo: make this request-able
378 requestString += "&metricSystem=";
379 if (QLocale::MetricSystem == measurementSystem())
380 requestString += "metric";
381 else
382 requestString += "imperial";
383
384 const QLocale loc(locale());
385
386 // ToDo: make this request-able
387 if (QLocale::C != loc.language() && QLocale::AnyLanguage != loc.language()) {
388 requestString += "&language=";
389 requestString += loc.name();
390 //If the first language isn't supported, english will be selected automatically
391 if (QLocale::English != loc.language())
392 requestString += ",en_US";
393 }
394
395 return requestString;
396}
397
398QString QGeoRoutingManagerEngineNokia::trimDouble(double degree, int decimalDigits)
399{
400 QString sDegree = QString::number(degree, 'g', decimalDigits);
401
402 int index = sDegree.indexOf('.');
403
404 if (index == -1)
405 return sDegree;
406 else
407 return QString::number(degree, 'g', decimalDigits + index);
408}
409
410void QGeoRoutingManagerEngineNokia::routeFinished()
411{
412 QGeoRouteReply *reply = qobject_cast<QGeoRouteReply *>(sender());
413
414 if (!reply)
415 return;
416
417 if (receivers(SIGNAL(finished(QGeoRouteReply*))) == 0) {
418 reply->deleteLater();
419 return;
420 }
421
422 emit finished(reply);
423}
424
425void QGeoRoutingManagerEngineNokia::routeError(QGeoRouteReply::Error error, const QString &errorString)
426{
427 QGeoRouteReply *reply = qobject_cast<QGeoRouteReply *>(sender());
428
429 if (!reply)
430 return;
431
432 if (receivers(SIGNAL(errorOccurred(QGeoRouteReply*,QGeoRouteReply::Error,QString))) == 0) {
433 reply->deleteLater();
434 return;
435 }
436
437 emit errorOccurred(reply, error, errorString);
438}
439
440QT_END_NAMESPACE
QGeoRouteReply * updateRoute(const QGeoRoute &route, const QGeoCoordinate &position) override
Begins the process of updating route based on the current position position.