Changeset View
Changeset View
Standalone View
Standalone View
src/plugins/runner/cyclestreets/CycleStreetsRunner.cpp
1 | // | 1 | // | ||
---|---|---|---|---|---|
2 | // This file is part of the Marble Virtual Globe. | 2 | // This file is part of the Marble Virtual Globe. | ||
3 | // | 3 | // | ||
4 | // This program is free software licensed under the GNU LGPL. You can | 4 | // This program is free software licensed under the GNU LGPL. You can | ||
5 | // find a copy of this license in LICENSE.txt in the top directory of | 5 | // find a copy of this license in LICENSE.txt in the top directory of | ||
6 | // the source code. | 6 | // the source code. | ||
7 | // | 7 | // | ||
8 | // Copyright 2013 Mihail Ivchenko <ematirov@gmail.com> | 8 | // Copyright 2013 Mihail Ivchenko <ematirov@gmail.com> | ||
9 | // Copyright 2017 Sergey Popov <sergobot@protonmail.com> | ||||
9 | // | 10 | // | ||
10 | 11 | | |||
11 | #include "CycleStreetsRunner.h" | 12 | #include "CycleStreetsRunner.h" | ||
12 | 13 | | |||
13 | #include "MarbleDebug.h" | 14 | #include "MarbleDebug.h" | ||
14 | #include "GeoDataDocument.h" | 15 | #include "GeoDataDocument.h" | ||
15 | #include "GeoDataExtendedData.h" | 16 | #include "GeoDataExtendedData.h" | ||
16 | #include "GeoDataData.h" | 17 | #include "GeoDataData.h" | ||
17 | #include "GeoDataPlacemark.h" | 18 | #include "GeoDataPlacemark.h" | ||
18 | #include "GeoDataLineString.h" | 19 | #include "GeoDataLineString.h" | ||
19 | #include "HttpDownloadManager.h" | 20 | #include "HttpDownloadManager.h" | ||
20 | #include "routing/Maneuver.h" | 21 | #include "routing/Maneuver.h" | ||
21 | #include "routing/RouteRequest.h" | 22 | #include "routing/RouteRequest.h" | ||
22 | 23 | | |||
23 | #include <QUrl> | 24 | #include <QUrl> | ||
24 | #include <QTimer> | 25 | #include <QTimer> | ||
25 | #include <QNetworkReply> | 26 | #include <QNetworkReply> | ||
26 | #include <QDomDocument> | 27 | #include <QJsonDocument> | ||
28 | #include <QJsonObject> | ||||
29 | #include <QJsonArray> | ||||
27 | 30 | | |||
28 | #include <QUrlQuery> | 31 | #include <QUrlQuery> | ||
29 | 32 | | |||
30 | namespace Marble | 33 | namespace Marble | ||
31 | { | 34 | { | ||
32 | 35 | | |||
33 | CycleStreetsRunner::CycleStreetsRunner( QObject *parent ) : | 36 | CycleStreetsRunner::CycleStreetsRunner( QObject *parent ) : | ||
34 | RoutingRunner( parent ), | 37 | RoutingRunner( parent ), | ||
Show All 29 Lines | |||||
64 | void CycleStreetsRunner::retrieveRoute( const RouteRequest *route ) | 67 | void CycleStreetsRunner::retrieveRoute( const RouteRequest *route ) | ||
65 | { | 68 | { | ||
66 | if ( route->size() < 2 || route->size() > 12 ) { | 69 | if ( route->size() < 2 || route->size() > 12 ) { | ||
67 | return; | 70 | return; | ||
68 | } | 71 | } | ||
69 | 72 | | |||
70 | QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()[QStringLiteral("cyclestreets")]; | 73 | QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()[QStringLiteral("cyclestreets")]; | ||
71 | 74 | | |||
72 | QUrl url("https://www.cyclestreets.net/api/journey.xml"); | 75 | QUrl url("https://www.cyclestreets.net/api/journey.json"); | ||
73 | QMap<QString, QString> queryStrings; | 76 | QMap<QString, QString> queryStrings; | ||
74 | queryStrings["key"] = "cdccf13997d59e70"; | 77 | queryStrings["key"] = "cdccf13997d59e70"; | ||
75 | queryStrings["useDom"] = QLatin1Char('1'); | 78 | queryStrings["reporterrors"] = QLatin1Char('1'); | ||
76 | queryStrings["plan"] = settings[QStringLiteral("plan")].toString(); | 79 | queryStrings["plan"] = settings[QStringLiteral("plan")].toString(); | ||
77 | if (queryStrings["plan"].isEmpty()) { | 80 | if (queryStrings["plan"].isEmpty()) { | ||
78 | mDebug() << Q_FUNC_INFO << "Missing a value for 'plan' in the settings, falling back to 'balanced'"; | 81 | mDebug() << Q_FUNC_INFO << "Missing a value for 'plan' in the settings, falling back to 'balanced'"; | ||
79 | queryStrings["plan"] = QStringLiteral("balanced"); | 82 | queryStrings["plan"] = QStringLiteral("balanced"); | ||
80 | } | 83 | } | ||
81 | queryStrings["speed"] = settings[QStringLiteral("speed")].toString(); | 84 | queryStrings["speed"] = settings[QStringLiteral("speed")].toString(); | ||
82 | if (queryStrings["speed"].isEmpty()) { | 85 | if (queryStrings["speed"].isEmpty()) { | ||
83 | mDebug() << Q_FUNC_INFO << "Missing a value for 'speed' in the settings, falling back to '20'"; | 86 | mDebug() << Q_FUNC_INFO << "Missing a value for 'speed' in the settings, falling back to '20'"; | ||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Line(s) | 148 | { | |||
146 | if ( turns.contains( cycleStreetsName ) ) { | 149 | if ( turns.contains( cycleStreetsName ) ) { | ||
147 | return turns[cycleStreetsName]; | 150 | return turns[cycleStreetsName]; | ||
148 | } | 151 | } | ||
149 | return Maneuver::Unknown; | 152 | return Maneuver::Unknown; | ||
150 | } | 153 | } | ||
151 | 154 | | |||
152 | GeoDataDocument *CycleStreetsRunner::parse( const QByteArray &content ) const | 155 | GeoDataDocument *CycleStreetsRunner::parse( const QByteArray &content ) const | ||
153 | { | 156 | { | ||
154 | QDomDocument xml; | 157 | QJsonParseError error; | ||
155 | if ( !xml.setContent( content ) ) { | 158 | QJsonDocument json = QJsonDocument::fromJson(content, &error); | ||
156 | mDebug() << "Cannot parse xml file with routing instructions."; | 159 | | ||
157 | return 0; | 160 | if ( json.isEmpty() ) { | ||
161 | mDebug() << "Cannot parse json file with routing instructions: " << error.errorString(); | ||||
162 | return Q_NULLPTR; | ||||
163 | } | ||||
164 | | ||||
165 | // Check if CycleStreets has found any error | ||||
166 | if ( !json.object()["error"].isNull() ) { | ||||
167 | mDebug() << "CycleStreets reported an error: " << json.object()["error"].toString(); | ||||
168 | return Q_NULLPTR; | ||||
158 | } | 169 | } | ||
170 | | ||||
159 | GeoDataDocument *result = new GeoDataDocument(); | 171 | GeoDataDocument *result = new GeoDataDocument(); | ||
160 | result->setName(QStringLiteral("CycleStreets")); | 172 | result->setName(QStringLiteral("CycleStreets")); | ||
161 | GeoDataPlacemark *routePlacemark = new GeoDataPlacemark; | 173 | GeoDataPlacemark *routePlacemark = new GeoDataPlacemark; | ||
162 | routePlacemark->setName(QStringLiteral("Route")); | 174 | routePlacemark->setName(QStringLiteral("Route")); | ||
163 | 175 | | |||
164 | GeoDataLineString *routeWaypoints = new GeoDataLineString; | 176 | GeoDataLineString *routeWaypoints = new GeoDataLineString; | ||
165 | QDomNodeList features = xml.elementsByTagName(QStringLiteral("gml:featureMember")); | 177 | QJsonArray features = json.object()["marker"].toArray(); | ||
166 | 178 | | |||
167 | if ( features.isEmpty() ) { | 179 | if ( features.isEmpty() ) { | ||
168 | return 0; | 180 | return Q_NULLPTR ; | ||
169 | } | 181 | } | ||
170 | QDomElement route = features.at( 0 ).toElement().firstChild().toElement(); | 182 | QJsonObject route = features.first().toObject()["@attributes"].toObject(); | ||
171 | QDomElement lineString = route.elementsByTagName(QStringLiteral("gml:LineString")).at(0).toElement(); | 183 | QJsonValue coordinates = route["coordinates"]; | ||
172 | QDomElement coordinates = lineString.toElement().elementsByTagName(QStringLiteral("gml:coordinates")).at(0).toElement(); | 184 | QStringList coordinatesList = coordinates.toString().split(QLatin1Char(' ')); | ||
173 | QStringList coordinatesList = coordinates.text().split(QLatin1Char(' ')); | | |||
174 | 185 | | |||
175 | QStringList::iterator iter = coordinatesList.begin(); | 186 | QStringList::iterator iter = coordinatesList.begin(); | ||
176 | QStringList::iterator end = coordinatesList.end(); | 187 | QStringList::iterator end = coordinatesList.end(); | ||
177 | 188 | | |||
178 | for( ; iter != end; ++iter) { | 189 | for( ; iter != end; ++iter) { | ||
179 | const QStringList coordinate = iter->split(QLatin1Char(',')); | 190 | const QStringList coordinate = iter->split(QLatin1Char(',')); | ||
180 | if ( coordinate.size() == 2 ) { | 191 | if ( coordinate.size() == 2 ) { | ||
181 | double const lon = coordinate.at( 0 ).toDouble(); | 192 | double const lon = coordinate.at( 0 ).toDouble(); | ||
182 | double const lat = coordinate.at( 1 ).toDouble(); | 193 | double const lat = coordinate.at( 1 ).toDouble(); | ||
183 | GeoDataCoordinates const position( lon, lat, 0.0, GeoDataCoordinates::Degree ); | 194 | GeoDataCoordinates const position( lon, lat, 0.0, GeoDataCoordinates::Degree ); | ||
184 | routeWaypoints->append( position ); | 195 | routeWaypoints->append( position ); | ||
185 | } | 196 | } | ||
186 | } | 197 | } | ||
187 | routePlacemark->setGeometry( routeWaypoints ); | 198 | routePlacemark->setGeometry( routeWaypoints ); | ||
188 | 199 | | |||
189 | QDomElement durationElement = route.elementsByTagName(QStringLiteral("cs:time")).at(0).toElement(); | | |||
190 | QTime duration; | 200 | QTime duration; | ||
191 | duration = duration.addSecs( durationElement.text().toInt() ); | 201 | duration = duration.addSecs( route["time"].toInt() ); | ||
192 | qreal length = routeWaypoints->length( EARTH_RADIUS ); | 202 | qreal length = routeWaypoints->length( EARTH_RADIUS ); | ||
193 | 203 | | |||
194 | const QString name = nameString( "CS", length, duration ); | 204 | const QString name = nameString( "CS", length, duration ); | ||
195 | const GeoDataExtendedData data = routeData( length, duration ); | 205 | const GeoDataExtendedData data = routeData( length, duration ); | ||
196 | routePlacemark->setExtendedData( data ); | 206 | routePlacemark->setExtendedData( data ); | ||
197 | result->setName( name ); | 207 | result->setName( name ); | ||
198 | result->append( routePlacemark ); | 208 | result->append( routePlacemark ); | ||
199 | 209 | | |||
200 | int i; | 210 | for (int i = 1; i < features.count(); ++i) { | ||
201 | for (i = 1; i < features.count() && features.at( i ).firstChildElement().tagName() != QLatin1String("cs:segment"); ++i); | 211 | QJsonObject segment = features.at( i ).toObject()["@attributes"].toObject(); | ||
202 | for ( ; i < features.count(); ++i) { | 212 | | ||
203 | QDomElement segment = features.at( i ).toElement(); | 213 | QString name = segment["name"].toString(); | ||
204 | 214 | QString maneuver = segment["turn"].toString(); | |||
205 | QString name = segment.elementsByTagName(QStringLiteral("cs:name")).at(0).toElement().text(); | 215 | QStringList points = segment["points"].toString().split(QLatin1Char(' ')); | ||
206 | QString maneuver = segment.elementsByTagName(QStringLiteral("cs:turn")).at(0).toElement().text(); | 216 | QStringList const elevation = segment["elevations"].toString().split(QLatin1Char(',')); | ||
207 | QStringList points = segment.elementsByTagName(QStringLiteral("cs:points")).at(0).toElement().text().split(QLatin1Char(' ')); | | |||
208 | QStringList const elevation = segment.elementsByTagName(QStringLiteral("cs:elevations")).at(0).toElement().text().split(QLatin1Char(',')); | | |||
209 | 217 | | |||
210 | GeoDataPlacemark *instructions = new GeoDataPlacemark; | 218 | GeoDataPlacemark *instructions = new GeoDataPlacemark; | ||
211 | QString instructionName; | 219 | QString instructionName; | ||
212 | if ( !maneuver.isEmpty() ) { | 220 | if ( !maneuver.isEmpty() ) { | ||
213 | instructionName = maneuver.left( 1 ).toUpper() + maneuver.mid( 1 ); | 221 | instructionName = maneuver.left( 1 ).toUpper() + maneuver.mid( 1 ); | ||
214 | } else { | 222 | } else { | ||
215 | instructionName = "Straight"; | 223 | instructionName = "Straight"; | ||
216 | } | 224 | } | ||
Show All 38 Lines |