• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.14
  • kdeedu
  • marble
  • src
  • plugins
  • runner
  • mapquest
MapQuestRunner.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
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
6 // the source code.
7 //
8 // Copyright 2012 Dennis Nienhüser <earthwings@gentoo.org>
9 //
10 
11 #include "MapQuestRunner.h"
12 
13 #include "MarbleDebug.h"
14 #include "MarbleLocale.h"
15 #include "GeoDataDocument.h"
16 #include "GeoDataPlacemark.h"
17 #include "GeoDataExtendedData.h"
18 #include "TinyWebBrowser.h"
19 #include "routing/Maneuver.h"
20 #include "routing/RouteRequest.h"
21 
22 #include <QString>
23 #include <QVector>
24 #include <QUrl>
25 #include <QTime>
26 #include <QTimer>
27 #include <QNetworkReply>
28 #include <QDomDocument>
29 
30 #if QT_VERSION >= 0x050000
31  #include <QUrlQuery>
32 #endif
33 namespace Marble
34 {
35 
36 MapQuestRunner::MapQuestRunner( QObject *parent ) :
37  RoutingRunner( parent ),
38  m_networkAccessManager(),
39  m_request()
40 {
41  connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
42  this, SLOT(retrieveData(QNetworkReply*)) );
43 }
44 
45 MapQuestRunner::~MapQuestRunner()
46 {
47  // nothing to do
48 }
49 
50 void MapQuestRunner::retrieveRoute( const RouteRequest *route )
51 {
52  if ( route->size() < 2 ) {
53  return;
54  }
55 
56  QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()["mapquest"];
57 
58  if ( settings.value( "appKey" ).toString().isEmpty() )
59  {
60  return;
61  }
62 
63  QString url = "http://open.mapquestapi.com/directions/v1/route?callback=renderAdvancedNarrative&outFormat=xml&narrativeType=text&shapeFormat=raw&generalize=0";
64  GeoDataCoordinates::Unit const degree = GeoDataCoordinates::Degree;
65  append( &url, "from", QString::number( route->source().latitude( degree ), 'f', 6 ) + ',' + QString::number( route->source().longitude( degree ), 'f', 6 ) );
66  for ( int i=1; i<route->size(); ++i ) {
67  append( &url, "to", QString::number( route->at( i ).latitude( degree ), 'f', 6 ) + ',' + QString::number( route->at( i ).longitude( degree ), 'f', 6 ) );
68  }
69 
70  QString const unit = MarbleGlobal::getInstance()->locale()->measurementSystem() == MarbleLocale::MetricSystem ? "k" : "m";
71  append( &url, "units", unit );
72 
73  if ( settings["noMotorways"].toInt() ) {
74  append( &url, "avoids", "Limited Access" );
75  }
76  if ( settings["noTollroads"].toInt() ) {
77  append( &url, "avoids", "Toll road" );
78  }
79  if ( settings["noFerries"].toInt() ) {
80  append( &url, "avoids", "Ferry" );
81  }
82 
83  if ( !settings["preference"].toString().isEmpty() ) {
84  append( &url, "routeType", settings["preference"].toString() );
85  }
86 
87  if ( !settings["ascending"].toString().isEmpty() && !settings["descending"].toString().isEmpty() ) {
88  if ( settings["ascending"].toString() == "AVOID_UP_HILL"
89  && settings["descending"].toString() == "AVOID_DOWN_HILL" ) {
90  append( &url, "roadGradeStrategy", "AVOID_ALL_HILLS" );
91  }
92  else if ( settings["ascending"].toString() == "FAVOR_UP_HILL"
93  && settings["descending"].toString() == "FAVOR_DOWN_HILL" ) {
94  append( &url, "roadGradeStrategy", "FAVOR_ALL_HILLS" );
95  }
96  else if ( settings["ascending"].toString() == "DEFAULT_STRATEGY"
97  && settings["descending"].toString() == "DEFAULT_STRATEGY" ) {
98  append( &url, "roadGradeStrategy", "DEFAULT_STRATEGY" );
99  }
100  else if ( settings["ascending"].toString() == "DEFAULT_STRATEGY" ) {
101  append( &url, "roadGradeStrategy", settings["descending"].toString() );
102  }
103  else if ( settings["descending"].toString() == "DEFAULT_STRATEGY" ) {
104  append( &url, "roadGradeStrategy", settings["ascending"].toString() );
105  }
106  else if ( settings["descending"].toString() == "AVOID_DOWN_HILL" ) {
107  append( &url, "roadGradeStrategy", settings["descending"].toString() );
108  }
109  else if ( settings["ascending"].toString() == "AVOID_UP_HILL" ) {
110  append( &url, "roadGradeStrategy", settings["ascending"].toString() );
111  }
112  }
113  QUrl qurl(url);
114 // FIXME: verify that this works with special characters.
115 #if QT_VERSION >= 0x050000
116  QUrlQuery urlQuery;
117  urlQuery.addQueryItem( "key", settings.value( "appKey" ).toByteArray() );
118  qurl.setQuery(urlQuery);
119 #else
120  qurl.addEncodedQueryItem( "key", settings.value( "appKey" ).toByteArray() );
121 #endif
122  m_request.setUrl( qurl );
123  m_request.setRawHeader( "User-Agent", TinyWebBrowser::userAgent( "Browser", "MapQuestRunner" ) );
124 
125  QEventLoop eventLoop;
126 
127  QTimer timer;
128  timer.setSingleShot( true );
129  timer.setInterval( 15000 );
130 
131  connect( &timer, SIGNAL(timeout()),
132  &eventLoop, SLOT(quit()));
133  connect( this, SIGNAL(routeCalculated(GeoDataDocument*)),
134  &eventLoop, SLOT(quit()) );
135 
136  // @todo FIXME Must currently be done in the main thread, see bug 257376
137  QTimer::singleShot( 0, this, SLOT(get()) );
138  timer.start();
139 
140  eventLoop.exec();
141 }
142 
143 void MapQuestRunner::get()
144 {
145  QNetworkReply *reply = m_networkAccessManager.get( m_request );
146  connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
147  this, SLOT(handleError(QNetworkReply::NetworkError)), Qt::DirectConnection );
148 }
149 
150 void MapQuestRunner::retrieveData( QNetworkReply *reply )
151 {
152  if ( reply->isFinished() ) {
153  QByteArray data = reply->readAll();
154  reply->deleteLater();
155  //mDebug() << "Download completed: " << data;
156  GeoDataDocument* document = parse( data );
157 
158  if ( !document ) {
159  mDebug() << "Failed to parse the downloaded route data" << data;
160  }
161 
162  emit routeCalculated( document );
163  }
164 }
165 
166 void MapQuestRunner::handleError( QNetworkReply::NetworkError error )
167 {
168  mDebug() << " Error when retrieving mapquest.org route: " << error;
169 }
170 
171 void MapQuestRunner::append(QString *input, const QString &key, const QString &value)
172 {
173  *input += '&' + key + '=' + value;
174 }
175 
176 int MapQuestRunner::maneuverType( int mapQuestId )
177 {
179  switch( mapQuestId ) {
180  case 0: return Maneuver::Straight ; // straight
181  case 1: return Maneuver::SlightRight ; // slight right
182  case 2: return Maneuver::Right ; // right
183  case 3: return Maneuver::SharpRight ; // sharp right
184  case 4: return Maneuver::TurnAround ; // reverse
185  case 5: return Maneuver::SharpLeft ; // sharp left
186  case 6: return Maneuver::Left ; // left
187  case 7: return Maneuver::SlightLeft ; // slight left
188  case 8: return Maneuver::TurnAround ; // right u-turn
189  case 9: return Maneuver::TurnAround ; // left u-turn
190  case 10: return Maneuver::Merge ; // right merge
191  case 11: return Maneuver::Merge ; // left merge
192  case 12: return Maneuver::Merge ; // right on ramp
193  case 13: return Maneuver::Merge ; // left on ramp
194  case 14: return Maneuver::ExitRight ; // right off ramp
195  case 15: return Maneuver::ExitLeft ; // left off ramp
196  case 16: return Maneuver::Right ; // right fork
197  case 17: return Maneuver::Left ; // left fork
198  case 18: return Maneuver::Continue ; // straight fork
199  }
200 
201  return Maneuver::Unknown;
202 }
203 
204 GeoDataDocument* MapQuestRunner::parse( const QByteArray &content ) const
205 {
206  QDomDocument xml;
207  if ( !xml.setContent( content ) ) {
208  mDebug() << "Cannot parse xml file with routing instructions.";
209  return 0;
210  }
211 
212  // mDebug() << xml.toString(2);
213  QDomElement root = xml.documentElement();
214 
215  GeoDataDocument* result = new GeoDataDocument();
216  result->setName( "MapQuest" );
217  GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
218  routePlacemark->setName( "Route" );
219 
220  GeoDataLineString* routeWaypoints = new GeoDataLineString;
221  QDomNodeList shapePoints = root.elementsByTagName( "shapePoints" );
222  if ( shapePoints.size() == 1 ) {
223  QDomNodeList geometry = shapePoints.at( 0 ).toElement().elementsByTagName( "latLng" );
224  for ( int i=0; i<geometry.size(); ++i ) {
225  double const lat = geometry.item( i ).namedItem( "lat" ).toElement().text().toDouble();
226  double const lon = geometry.item( i ).namedItem( "lng" ).toElement().text().toDouble();
227  GeoDataCoordinates const position( lon, lat, 0.0, GeoDataCoordinates::Degree );
228  routeWaypoints->append( position );
229  }
230  }
231  routePlacemark->setGeometry( routeWaypoints );
232 
233  QTime time;
234  time = time.addSecs( root.elementsByTagName( "time" ).at( 0 ).toElement().text().toInt() );
235  qreal length = routeWaypoints->length( EARTH_RADIUS );
236  const QString name = nameString( "MQ", length, time );
237  const GeoDataExtendedData data = routeData( length, time );
238  routePlacemark->setExtendedData( data );
239  result->setName( name );
240  result->append( routePlacemark );
241 
242  QMap<int,int> mapping;
243  QDomNodeList maneuvers = root.elementsByTagName( "maneuverIndexes" );
244  if ( maneuvers.size() == 1 ) {
245  maneuvers = maneuvers.at( 0 ).childNodes();
246  for ( int i=0; i<maneuvers.size(); ++i ) {
247  mapping[i] = maneuvers.at( i ).toElement().text().toInt();
248  if ( mapping[i] == routeWaypoints->size() ) {
249  --mapping[i];
250  }
251  }
252  }
253 
254  QDomNodeList instructions = root.elementsByTagName( "maneuver" );
255  unsigned int const lastInstruction = qMax<int>( 0, instructions.length()-1 ); // ignore the last 'Welcome to xy' instruction
256  for ( unsigned int i = 0; i < lastInstruction; ++i ) {
257  QDomElement node = instructions.item( i ).toElement();
258 
259  QDomNodeList maneuver = node.elementsByTagName( "turnType" );
260  QDomNodeList textNodes = node.elementsByTagName( "narrative" );
261  QDomNodeList points = node.elementsByTagName( "startPoint" );
262  QDomNodeList streets = node.elementsByTagName( "streets" );
263 
264  Q_ASSERT( mapping.contains( i ) );
265  if ( textNodes.size() == 1 && maneuver.size() == 1 && points.size() == 1 && mapping.contains( i ) ) {
266  GeoDataPlacemark* instruction = new GeoDataPlacemark;
267  instruction->setName( textNodes.at( 0 ).toElement().text() );
268 
269  GeoDataExtendedData extendedData;
270  GeoDataData turnType;
271  turnType.setName( "turnType" );
272  turnType.setValue( maneuverType( maneuver.at( 0 ).toElement().text().toInt() ) );
273  extendedData.addValue( turnType );
274  if ( streets.size() == 1 ) {
275  GeoDataData roadName;
276  roadName.setName( "roadName" );
277  roadName.setValue( streets.at( 0 ).toElement().text() );
278  extendedData.addValue( roadName );
279  }
280  instruction->setExtendedData( extendedData );
281 
282  int const start = mapping[i];
283  int const end = mapping.contains(i+1) ? mapping[i+1] : routeWaypoints->size()-1;
284  if ( start >= 0 && start < routeWaypoints->size() && end < routeWaypoints->size() ) {
285  instruction->setName( textNodes.item( 0 ).toElement().text() );
286  GeoDataLineString *lineString = new GeoDataLineString;
287  for ( int j=start; j<=end; ++j ) {
288  *lineString << GeoDataCoordinates( routeWaypoints->at( j ).longitude(), routeWaypoints->at( j ).latitude() );
289  }
290 
291  if ( !lineString->isEmpty() ) {
292  instruction->setGeometry( lineString );
293  result->append( instruction );
294  }
295  }
296  }
297  }
298 
299  if ( routeWaypoints->size() < 1 ) {
300  delete result;
301  result = 0;
302  }
303 
304  return result;
305 }
306 
307 
308 } // namespace Marble
309 
310 #include "MapQuestRunner.moc"
Marble::GeoDataCoordinates::Unit
Unit
enum used constructor to specify the units used
Definition: GeoDataCoordinates.h:64
Marble::Maneuver::TurnAround
Definition: Maneuver.h:34
GeoDataDocument.h
QTimer::setInterval
void setInterval(int msec)
Marble::RouteRequest::size
int size() const
Number of points in the route.
Definition: RouteRequest.cpp:126
QDomElement::elementsByTagName
QDomNodeList elementsByTagName(const QString &tagname) const
Marble::MapQuestRunner::~MapQuestRunner
~MapQuestRunner()
Definition: MapQuestRunner.cpp:45
TinyWebBrowser.h
QDomNodeList::item
QDomNode item(int index) const
Marble::GeoDataDocument
A container for Features, Styles and in the future Schemas.
Definition: GeoDataDocument.h:65
Marble::Maneuver::SharpRight
Definition: Maneuver.h:33
QUrl::setQuery
void setQuery(const QString &txt)
QEventLoop
QMap::contains
bool contains(const Key &key) const
Marble::MarbleLocale::measurementSystem
MarbleLocale::MeasurementSystem measurementSystem() const
Definition: MarbleLocale.cpp:45
QNetworkRequest::setUrl
void setUrl(const QUrl &url)
QByteArray
QNetworkReply
Marble::Maneuver::Left
Definition: Maneuver.h:36
QDomNodeList
QMap
QDomDocument::documentElement
QDomElement documentElement() const
GeoDataExtendedData.h
Marble::GeoDataCoordinates::latitude
qreal latitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the latitude of the GeoDataCoordinates object use the unit parameter to switch between Radi...
Definition: GeoDataCoordinates.cpp:751
Marble::Maneuver::ExitRight
Definition: Maneuver.h:43
QString::toDouble
double toDouble(bool *ok) const
QDomNode::childNodes
QDomNodeList childNodes() const
QTime
MarbleDebug.h
Marble::Maneuver::Straight
Definition: Maneuver.h:30
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
QUrl::addEncodedQueryItem
void addEncodedQueryItem(const QByteArray &key, const QByteArray &value)
Marble::Maneuver::Right
Definition: Maneuver.h:32
Maneuver.h
Marble::RoutingRunner::nameString
const QString nameString(const QString &name, qreal length, const QTime &duration) const
Definition: RoutingRunner.cpp:55
QDomNode::toElement
QDomElement toElement() const
Marble::RouteRequest
Points to be included in a route.
Definition: RouteRequest.h:31
QObject::name
const char * name() const
Marble::RouteRequest::routingProfile
RoutingProfile routingProfile() const
Definition: RouteRequest.cpp:321
QString::number
QString number(int n, int base)
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:257
Marble::MapQuestRunner::retrieveRoute
virtual void retrieveRoute(const RouteRequest *request)
Start a route download orw calculation.
Definition: MapQuestRunner.cpp:50
QDomElement::text
QString text() const
QTimer
QHash< QString, QVariant >
QEventLoop::exec
int exec(QFlags< QEventLoop::ProcessEventsFlag > flags)
QObject
QString::toInt
int toInt(bool *ok, int base) const
QNetworkReply::isFinished
bool isFinished() const
QIODevice::readAll
QByteArray readAll()
QTime::addSecs
QTime addSecs(int s) const
Marble::Maneuver::SlightRight
Definition: Maneuver.h:31
Marble::RoutingRunner::routeData
const GeoDataExtendedData routeData(qreal length, const QTime &duration) const
Definition: RoutingRunner.cpp:61
QObject::deleteLater
void deleteLater()
Marble::MarbleGlobal::locale
MarbleLocale * locale() const
Definition: MarbleGlobal.cpp:43
QString
MarbleLocale.h
GeoDataPlacemark.h
QHash::value
const T value(const Key &key) const
QDomNode::namedItem
QDomNode namedItem(const QString &name) const
Marble::GeoDataCoordinates::longitude
qreal longitude(GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian) const
retrieves the longitude of the GeoDataCoordinates object use the unit parameter to switch between Rad...
Definition: GeoDataCoordinates.cpp:739
QUrl
QDomDocument
Marble::MarbleGlobal::getInstance
static MarbleGlobal * getInstance()
Definition: MarbleGlobal.cpp:37
Marble::Maneuver::Continue
Definition: Maneuver.h:28
Marble::RoutingProfile::pluginSettings
const QHash< QString, QHash< QString, QVariant > > & pluginSettings() const
Definition: RoutingProfile.cpp:33
Marble::RoutingRunner::routeCalculated
void routeCalculated(GeoDataDocument *route)
Route download/calculation is finished, result in the given route object.
Marble::MarbleLocale::MetricSystem
Definition: MarbleLocale.h:38
Marble::MapQuestRunner::MapQuestRunner
MapQuestRunner(QObject *parent=0)
Definition: MapQuestRunner.cpp:36
Marble::RoutingRunner
Definition: RoutingRunner.h:28
QNetworkRequest::setRawHeader
void setRawHeader(const QByteArray &headerName, const QByteArray &headerValue)
Marble::Maneuver::Merge
Definition: Maneuver.h:29
QTimer::start
void start(int msec)
RouteRequest.h
Marble::TinyWebBrowser::userAgent
static QByteArray userAgent(const QString &platform, const QString &plugin)
Definition: TinyWebBrowser.cpp:106
QNetworkAccessManager::get
QNetworkReply * get(const QNetworkRequest &request)
Marble::Maneuver::Unknown
Definition: Maneuver.h:27
Marble::Maneuver::SlightLeft
Definition: Maneuver.h:37
QDomNodeList::size
int size() const
QDomNodeList::length
uint length() const
MapQuestRunner.h
Marble::Maneuver::SharpLeft
Definition: Maneuver.h:35
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QDomElement
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
Marble::RouteRequest::source
GeoDataCoordinates source() const
The first point, or a default constructed if empty.
Definition: RouteRequest.cpp:131
QMap::size
int size() const
QDomNodeList::at
QDomNode at(int index) const
QDomDocument::setContent
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
Marble::Maneuver::ExitLeft
Definition: Maneuver.h:42
QTimer::setSingleShot
void setSingleShot(bool singleShot)
Marble::RouteRequest::at
GeoDataCoordinates at(int index) const
Accessor for the n-th position.
Definition: RouteRequest.cpp:149
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:40 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal