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

marble

  • sources
  • kde-4.12
  • 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 namespace Marble
31 {
32 
33 MapQuestRunner::MapQuestRunner( QObject *parent ) :
34  RoutingRunner( parent ),
35  m_networkAccessManager(),
36  m_request()
37 {
38  connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
39  this, SLOT(retrieveData(QNetworkReply*)) );
40 }
41 
42 MapQuestRunner::~MapQuestRunner()
43 {
44  // nothing to do
45 }
46 
47 void MapQuestRunner::retrieveRoute( const RouteRequest *route )
48 {
49  if ( route->size() < 2 ) {
50  return;
51  }
52 
53  QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()["mapquest"];
54 
55  QString url = "http://open.mapquestapi.com/directions/v1/route?callback=renderAdvancedNarrative&outFormat=xml&narrativeType=text&shapeFormat=raw&generalize=0";
56  GeoDataCoordinates::Unit const degree = GeoDataCoordinates::Degree;
57  append( &url, "from", QString::number( route->source().latitude( degree ), 'f', 6 ) + ',' + QString::number( route->source().longitude( degree ), 'f', 6 ) );
58  for ( int i=1; i<route->size(); ++i ) {
59  append( &url, "to", QString::number( route->at( i ).latitude( degree ), 'f', 6 ) + ',' + QString::number( route->at( i ).longitude( degree ), 'f', 6 ) );
60  }
61 
62  QString const unit = MarbleGlobal::getInstance()->locale()->measurementSystem() == QLocale::MetricSystem ? "k" : "m";
63  append( &url, "units", unit );
64 
65  if ( settings["noMotorways"].toInt() ) {
66  append( &url, "avoids", "Limited Access" );
67  }
68  if ( settings["noTollroads"].toInt() ) {
69  append( &url, "avoids", "Toll road" );
70  }
71  if ( settings["noFerries"].toInt() ) {
72  append( &url, "avoids", "Ferry" );
73  }
74 
75  if ( !settings["preference"].toString().isEmpty() ) {
76  append( &url, "routeType", settings["preference"].toString() );
77  }
78 
79  m_request.setUrl( QUrl( url ) );
80  m_request.setRawHeader( "User-Agent", TinyWebBrowser::userAgent( "Browser", "MapQuestRunner" ) );
81 
82  QEventLoop eventLoop;
83 
84  QTimer timer;
85  timer.setSingleShot( true );
86  timer.setInterval( 15000 );
87 
88  connect( &timer, SIGNAL(timeout()),
89  &eventLoop, SLOT(quit()));
90  connect( this, SIGNAL(routeCalculated(GeoDataDocument*)),
91  &eventLoop, SLOT(quit()) );
92 
93  // @todo FIXME Must currently be done in the main thread, see bug 257376
94  QTimer::singleShot( 0, this, SLOT(get()) );
95  timer.start();
96 
97  eventLoop.exec();
98 }
99 
100 void MapQuestRunner::get()
101 {
102  QNetworkReply *reply = m_networkAccessManager.get( m_request );
103  connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
104  this, SLOT(handleError(QNetworkReply::NetworkError)), Qt::DirectConnection );
105 }
106 
107 void MapQuestRunner::retrieveData( QNetworkReply *reply )
108 {
109  if ( reply->isFinished() ) {
110  QByteArray data = reply->readAll();
111  reply->deleteLater();
112  //mDebug() << "Download completed: " << data;
113  GeoDataDocument* document = parse( data );
114 
115  if ( !document ) {
116  mDebug() << "Failed to parse the downloaded route data" << data;
117  }
118 
119  emit routeCalculated( document );
120  }
121 }
122 
123 void MapQuestRunner::handleError( QNetworkReply::NetworkError error )
124 {
125  mDebug() << " Error when retrieving mapquest.org route: " << error;
126 }
127 
128 void MapQuestRunner::append(QString *input, const QString &key, const QString &value)
129 {
130  *input += '&' + key + '=' + value;
131 }
132 
133 int MapQuestRunner::maneuverType( int mapQuestId ) const
134 {
136  switch( mapQuestId ) {
137  case 0: return Maneuver::Straight ; // straight
138  case 1: return Maneuver::SlightRight ; // slight right
139  case 2: return Maneuver::Right ; // right
140  case 3: return Maneuver::SharpRight ; // sharp right
141  case 4: return Maneuver::TurnAround ; // reverse
142  case 5: return Maneuver::SharpLeft ; // sharp left
143  case 6: return Maneuver::Left ; // left
144  case 7: return Maneuver::SlightLeft ; // slight left
145  case 8: return Maneuver::TurnAround ; // right u-turn
146  case 9: return Maneuver::TurnAround ; // left u-turn
147  case 10: return Maneuver::Merge ; // right merge
148  case 11: return Maneuver::Merge ; // left merge
149  case 12: return Maneuver::Merge ; // right on ramp
150  case 13: return Maneuver::Merge ; // left on ramp
151  case 14: return Maneuver::ExitRight ; // right off ramp
152  case 15: return Maneuver::ExitLeft ; // left off ramp
153  case 16: return Maneuver::Right ; // right fork
154  case 17: return Maneuver::Left ; // left fork
155  case 18: return Maneuver::Continue ; // straight fork
156  }
157 
158  return Maneuver::Unknown;
159 }
160 
161 GeoDataDocument* MapQuestRunner::parse( const QByteArray &content ) const
162 {
163  QDomDocument xml;
164  if ( !xml.setContent( content ) ) {
165  mDebug() << "Cannot parse xml file with routing instructions.";
166  return 0;
167  }
168 
169  // mDebug() << xml.toString(2);
170  QDomElement root = xml.documentElement();
171 
172  GeoDataDocument* result = new GeoDataDocument();
173  result->setName( "MapQuest" );
174  GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
175  routePlacemark->setName( "Route" );
176 
177  GeoDataLineString* routeWaypoints = new GeoDataLineString;
178  QDomNodeList shapePoints = root.elementsByTagName( "shapePoints" );
179  if ( shapePoints.size() == 1 ) {
180  QDomNodeList geometry = shapePoints.at( 0 ).toElement().elementsByTagName( "latLng" );
181  for ( int i=0; i<geometry.size(); ++i ) {
182  double const lat = geometry.item( i ).namedItem( "lat" ).toElement().text().toDouble();
183  double const lon = geometry.item( i ).namedItem( "lng" ).toElement().text().toDouble();
184  GeoDataCoordinates const position( lon, lat, 0.0, GeoDataCoordinates::Degree );
185  routeWaypoints->append( position );
186  }
187  }
188  routePlacemark->setGeometry( routeWaypoints );
189 
190  QString name = "%1 %2 (MapQuest)";
191  QString unit = QLatin1String( "m" );
192  qreal length = routeWaypoints->length( EARTH_RADIUS );
193  if (length >= 1000) {
194  length /= 1000.0;
195  unit = "km";
196  }
197  result->setName( name.arg( length, 0, 'f', 1 ).arg( unit ) );
198  result->append( routePlacemark );
199 
200  QMap<int,int> mapping;
201  QDomNodeList maneuvers = root.elementsByTagName( "maneuverIndexes" );
202  if ( maneuvers.size() == 1 ) {
203  maneuvers = maneuvers.at( 0 ).childNodes();
204  for ( int i=0; i<maneuvers.size(); ++i ) {
205  mapping[i] = maneuvers.at( i ).toElement().text().toInt();
206  if ( mapping[i] == routeWaypoints->size() ) {
207  --mapping[i];
208  }
209  }
210  }
211 
212  QDomNodeList instructions = root.elementsByTagName( "maneuver" );
213  unsigned int const lastInstruction = qMax<int>( 0, instructions.length()-1 ); // ignore the last 'Welcome to xy' instruction
214  for ( unsigned int i = 0; i < lastInstruction; ++i ) {
215  QDomElement node = instructions.item( i ).toElement();
216 
217  QDomNodeList maneuver = node.elementsByTagName( "turnType" );
218  QDomNodeList textNodes = node.elementsByTagName( "narrative" );
219  QDomNodeList points = node.elementsByTagName( "startPoint" );
220  QDomNodeList streets = node.elementsByTagName( "streets" );
221 
222  Q_ASSERT( mapping.contains( i ) );
223  if ( textNodes.size() == 1 && maneuver.size() == 1 && points.size() == 1 && mapping.contains( i ) ) {
224  GeoDataPlacemark* instruction = new GeoDataPlacemark;
225  instruction->setName( textNodes.at( 0 ).toElement().text() );
226 
227  GeoDataExtendedData extendedData;
228  GeoDataData turnType;
229  turnType.setName( "turnType" );
230  turnType.setValue( maneuverType( maneuver.at( 0 ).toElement().text().toInt() ) );
231  extendedData.addValue( turnType );
232  if ( streets.size() == 1 ) {
233  GeoDataData roadName;
234  roadName.setName( "roadName" );
235  roadName.setValue( streets.at( 0 ).toElement().text() );
236  extendedData.addValue( roadName );
237  }
238  instruction->setExtendedData( extendedData );
239 
240  int const start = mapping[i];
241  int const end = mapping.contains(i+1) ? mapping[i+1] : routeWaypoints->size()-1;
242  if ( start >= 0 && start < routeWaypoints->size() && end < routeWaypoints->size() ) {
243  instruction->setName( textNodes.item( 0 ).toElement().text() );
244  GeoDataLineString *lineString = new GeoDataLineString;
245  for ( int j=start; j<=end; ++j ) {
246  *lineString << GeoDataCoordinates( routeWaypoints->at( j ).longitude(), routeWaypoints->at( j ).latitude() );
247  }
248 
249  if ( !lineString->isEmpty() ) {
250  instruction->setGeometry( lineString );
251  result->append( instruction );
252  }
253  }
254  }
255  }
256 
257  if ( routeWaypoints->size() < 1 ) {
258  delete result;
259  result = 0;
260  }
261 
262  return result;
263 }
264 
265 
266 } // namespace Marble
267 
268 #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
Marble::RouteRequest::size
int size() const
Number of points in the route.
Definition: RouteRequest.cpp:126
Marble::MapQuestRunner::~MapQuestRunner
~MapQuestRunner()
Definition: MapQuestRunner.cpp:42
TinyWebBrowser.h
Marble::GeoDataDocument
A container for Features, Styles and in the future Schemas.
Definition: GeoDataDocument.h:64
Marble::Maneuver::SharpRight
Definition: Maneuver.h:33
Marble::MarbleLocale::measurementSystem
QLocale::MeasurementSystem measurementSystem() const
Definition: MarbleLocale.cpp:45
Marble::Maneuver::Left
Definition: Maneuver.h:36
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
QObject
Marble::Maneuver::ExitRight
Definition: Maneuver.h:43
MarbleDebug.h
Marble::Maneuver::Straight
Definition: Maneuver.h:30
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
Marble::Maneuver::Right
Definition: Maneuver.h:32
Maneuver.h
Marble::RouteRequest
Points to be included in a route.
Definition: RouteRequest.h:31
Marble::RouteRequest::routingProfile
RoutingProfile routingProfile() const
Definition: RouteRequest.cpp:321
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:238
Marble::MapQuestRunner::retrieveRoute
virtual void retrieveRoute(const RouteRequest *request)
Start a route download orw calculation.
Definition: MapQuestRunner.cpp:47
Marble::Maneuver::SlightRight
Definition: Maneuver.h:31
Marble::MarbleGlobal::locale
MarbleLocale * locale() const
Definition: MarbleGlobal.cpp:43
MarbleLocale.h
GeoDataPlacemark.h
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
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::MapQuestRunner::MapQuestRunner
MapQuestRunner(QObject *parent=0)
Definition: MapQuestRunner.cpp:33
Marble::RoutingRunner
Definition: RoutingRunner.h:27
Marble::Maneuver::Merge
Definition: Maneuver.h:29
RouteRequest.h
Marble::TinyWebBrowser::userAgent
static QByteArray userAgent(const QString &platform, const QString &plugin)
Definition: TinyWebBrowser.cpp:106
Marble::Maneuver::Unknown
Definition: Maneuver.h:27
Marble::Maneuver::SlightLeft
Definition: Maneuver.h:37
MapQuestRunner.h
Marble::Maneuver::SharpLeft
Definition: Maneuver.h:35
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
Marble::RouteRequest::source
GeoDataCoordinates source() const
The first point, or a default constructed if empty.
Definition: RouteRequest.cpp:131
Marble::Maneuver::ExitLeft
Definition: Maneuver.h:42
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-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:38:51 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
  • kstars
  • libkdeedu
  •   keduvocdocument
  • 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