| /**************************************************************************** |
| ** |
| ** Copyright (C) 2013-2018 Esri <contracts@esri.com> |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtLocation module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "georoutejsonparser_esri.h" |
| |
| #include <QJsonArray> |
| #include <QGeoRectangle> |
| #include <QGeoManeuver> |
| #include <QGeoRouteSegment> |
| |
| QT_BEGIN_NAMESPACE |
| |
| // JSON reference: http://resources.arcgis.com/en/help/arcgis-rest-api/#/Route_service_with_synchronous_execution/02r300000036000000/ |
| |
| static const QString kErrorMessage(QStringLiteral("Error %1: %2.")); |
| static const QString kErrorJson(QStringLiteral("Error: invalide JSON document.")); |
| |
| static const QString kErrorKey(QStringLiteral("error")); |
| static const QString kErrorCodeKey(QStringLiteral("code")); |
| static const QString kErrorMessageKey(QStringLiteral("message")); |
| static const QString kErrorDetailsKey(QStringLiteral("details")); |
| static const QString kDirectionsKey(QStringLiteral("directions")); |
| static const QString kRoutesKey(QStringLiteral("routes")); |
| static const QString kBarriersKey(QStringLiteral("barriers")); |
| static const QString kMessagesKey(QStringLiteral("messages")); |
| static const QString kDirectionsRouteIdKey(QStringLiteral("routeId")); |
| static const QString kDirectionsRouteNameKey(QStringLiteral("routeName")); |
| static const QString kDirectionsSummaryKey(QStringLiteral("summary")); |
| static const QString kDirectionsTotalLengthKey(QStringLiteral("totalLength")); |
| static const QString kDirectionsTotalTimeKey(QStringLiteral("totalTime")); |
| static const QString kDirectionsTotalDriveTimeKey(QStringLiteral("totalDriveTime")); |
| static const QString kDirectionsEnvelopeKey(QStringLiteral("envelope")); |
| static const QString kDirectionsEnvelopeXminKey(QStringLiteral("xmin")); |
| static const QString kDirectionsEnvelopeYminKey(QStringLiteral("ymin")); |
| static const QString kDirectionsEnvelopeXmaxKey(QStringLiteral("xmax")); |
| static const QString kDirectionsEnvelopeYmaxKey(QStringLiteral("ymax")); |
| static const QString kDirectionsFeaturesKey(QStringLiteral("features")); |
| static const QString kDirectionsFeaturesAttributesKey(QStringLiteral("attributes")); |
| static const QString kDirectionsFeaturesCompressedGeometryKey(QStringLiteral("compressedGeometry")); |
| static const QString kDirectionsFeaturesAttributesLengthKey(QStringLiteral("length")); |
| static const QString kDirectionsFeaturesAttributesTimeKey(QStringLiteral("time")); |
| static const QString kDirectionsFeaturesAttributesTextKey(QStringLiteral("text")); |
| static const QString kDirectionsFeaturesAttributesEtaKey(QStringLiteral("ETA")); |
| static const QString kDirectionsFeaturesAttributesManeuverTypeKey(QStringLiteral("maneuverType")); |
| static const QString kRoutesFeaturesKey(QStringLiteral("features")); |
| static const QString kRoutesFeaturesAttributesKey(QStringLiteral("attributes")); |
| static const QString kRoutesFeaturesObjectIdKey(QStringLiteral("ObjectID")); |
| static const QString kRoutesFeaturesGeometryKey(QStringLiteral("geometry")); |
| static const QString kRoutesFeaturesGeometryPathsKey(QStringLiteral("paths")); |
| |
| GeoRouteJsonParserEsri::GeoRouteJsonParserEsri(const QJsonDocument &document) |
| { |
| if (!document.isObject()) |
| { |
| m_error = kErrorJson; |
| return; |
| } |
| |
| m_json = document.object(); |
| if (m_json.contains(kErrorKey)) |
| { |
| QJsonObject error = m_json.value(kErrorKey).toObject(); |
| int code = error.value(kErrorCodeKey).toInt(); |
| QString message = error.value(kErrorMessageKey).toString(); |
| |
| m_error = kErrorMessage.arg(code).arg(message); |
| return; |
| } |
| |
| parseDirections(); |
| parseRoutes(); |
| } |
| |
| QList<QGeoRoute> GeoRouteJsonParserEsri::routes() const |
| { |
| return m_routes.values(); |
| } |
| |
| bool GeoRouteJsonParserEsri::isValid() const |
| { |
| return (m_error.isEmpty()); |
| } |
| |
| QString GeoRouteJsonParserEsri::errorString() const |
| { |
| return m_error; |
| } |
| |
| void GeoRouteJsonParserEsri::parseDirections() |
| { |
| QJsonArray directions = m_json.value(kDirectionsKey).toArray(); |
| foreach (const QJsonValue &direction, directions) |
| parseDirection(direction.toObject()); |
| } |
| |
| void GeoRouteJsonParserEsri::parseDirection(const QJsonObject &direction) |
| { |
| QGeoRoute &geoRoute = m_routes[direction.value(kDirectionsRouteIdKey).toInt()]; |
| |
| // parse summary |
| geoRoute.setRouteId(direction.value(kDirectionsRouteNameKey).toString()); |
| |
| QJsonObject summary = direction.value(kDirectionsSummaryKey).toObject(); |
| geoRoute.setDistance(summary.value(kDirectionsTotalLengthKey).toDouble()); |
| |
| geoRoute.setTravelTime(summary.value(kDirectionsTotalTimeKey).toDouble() * 60); |
| // default units is minutes, see directionsTimeAttributeName param |
| |
| geoRoute.setTravelMode(QGeoRouteRequest::CarTravel); |
| // default request is time for car, see directionsTimeAttributeName param |
| |
| QJsonObject enveloppe = summary.value(kDirectionsEnvelopeKey).toObject(); |
| |
| QGeoCoordinate topLeft(enveloppe.value(kDirectionsEnvelopeXminKey).toDouble(), |
| enveloppe.value(kDirectionsEnvelopeYmaxKey).toDouble()); |
| QGeoCoordinate bottomRight(enveloppe.value(kDirectionsEnvelopeXmaxKey).toDouble(), |
| enveloppe.value(kDirectionsEnvelopeYminKey).toDouble()); |
| geoRoute.setBounds(QGeoRectangle(topLeft, bottomRight)); |
| |
| // parse features |
| QJsonArray features = direction.value(kDirectionsFeaturesKey).toArray(); |
| |
| static const QMap<QString, QGeoManeuver::InstructionDirection> esriDirectionsManeuverTypes |
| { |
| { QStringLiteral("esriDMTUnknown"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTStop"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTStraight"), QGeoManeuver::DirectionForward }, |
| { QStringLiteral("esriDMTBearLeft"), QGeoManeuver::DirectionBearLeft }, |
| { QStringLiteral("esriDMTBearRight"), QGeoManeuver::DirectionBearRight }, |
| { QStringLiteral("esriDMTTurnLeft"), QGeoManeuver::DirectionLeft }, |
| { QStringLiteral("esriDMTTurnRight"), QGeoManeuver::DirectionRight }, |
| { QStringLiteral("esriDMTSharpLeft"), QGeoManeuver::DirectionLightLeft }, |
| { QStringLiteral("esriDMTSharpRight"), QGeoManeuver::DirectionLightRight }, |
| { QStringLiteral("esriDMTUTurn"), QGeoManeuver::DirectionUTurnRight }, |
| { QStringLiteral("esriDMTFerry"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTRoundabout"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTHighwayMerge"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTHighwayExit"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTHighwayChange"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTForkCenter"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTForkLeft"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTForkRight"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTDepart"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTTripItem"), QGeoManeuver::NoDirection }, |
| { QStringLiteral("esriDMTEndOfFerry"), QGeoManeuver::NoDirection } |
| }; |
| |
| QGeoRouteSegment firstSegment; |
| for (int i = features.size() - 1; i >= 0; --i) |
| { |
| QJsonObject feature = features.at(i).toObject(); |
| QJsonObject attributes = feature.value(kDirectionsFeaturesAttributesKey).toObject(); |
| |
| QGeoRouteSegment segment; |
| double length = attributes.value(kDirectionsFeaturesAttributesLengthKey).toDouble(); |
| segment.setDistance(length); |
| |
| double time = attributes.value(kDirectionsFeaturesAttributesTimeKey).toDouble() * 60; |
| // default units is minutes, see directionsTimeAttributeName param |
| segment.setTravelTime(time); |
| |
| QGeoManeuver maneuver; |
| QString type = attributes.value(kDirectionsFeaturesAttributesManeuverTypeKey).toString(); |
| maneuver.setDirection(esriDirectionsManeuverTypes.value(type)); |
| |
| maneuver.setInstructionText(attributes.value(kDirectionsFeaturesAttributesTextKey).toString() + "."); |
| maneuver.setDistanceToNextInstruction(length); |
| maneuver.setTimeToNextInstruction(time); |
| |
| segment.setManeuver(maneuver); |
| |
| segment.setNextRouteSegment(firstSegment); |
| firstSegment = segment; |
| } |
| geoRoute.setFirstRouteSegment(firstSegment); |
| } |
| |
| void GeoRouteJsonParserEsri::parseRoutes() |
| { |
| QJsonObject routes = m_json.value(kRoutesKey).toObject(); |
| QJsonArray features = routes.value(kRoutesFeaturesKey).toArray(); |
| foreach (const QJsonValue &feature, features) |
| parseRoute(feature.toObject()); |
| } |
| |
| void GeoRouteJsonParserEsri::parseRoute(const QJsonObject &route) |
| { |
| QJsonObject attributes = route.value(kRoutesFeaturesAttributesKey).toObject(); |
| QGeoRoute &geoRoute = m_routes[attributes.value(kRoutesFeaturesObjectIdKey).toInt()]; |
| |
| QJsonObject geometry = route.value(kRoutesFeaturesGeometryKey).toObject(); |
| QJsonArray paths = geometry.value(kRoutesFeaturesGeometryPathsKey).toArray(); |
| |
| if (!paths.isEmpty()) |
| { |
| QList<QGeoCoordinate> geoCoordinates; |
| foreach (const QJsonValue &value, paths.first().toArray()) // only first polyline? |
| { |
| QJsonArray geoCoordinate = value.toArray(); |
| if (geoCoordinate.size() == 2) // ignore 3rd coordinate |
| { |
| geoCoordinates.append(QGeoCoordinate(geoCoordinate[1].toDouble(), |
| geoCoordinate[0].toDouble())); |
| } |
| } |
| geoRoute.setPath(geoCoordinates); |
| } |
| } |
| |
| QT_END_NAMESPACE |