From kde-commits Tue Jan 31 23:39:31 2012 From: =?utf-8?q?Dennis_Nienh=C3=BCser?= Date: Tue, 31 Jan 2012 23:39:31 +0000 To: kde-commits Subject: [marble] src: Routing runner using the MapQuest routing service. Message-Id: <20120131233931.69944A60A6 () git ! kde ! org> X-MARC-Message: https://marc.info/?l=kde-commits&m=132805337627018 Git commit 526683505900e1b7d0ff3d3069dfb4f65b1eca92 by Dennis Nienh=C3=BCse= r. Committed on 01/02/2012 at 00:33. Pushed by nienhueser into branch 'master'. Routing runner using the MapQuest routing service. CCBUG: 292832 M +8 -1 src/lib/MarbleAboutDialog.cpp M +5 -8 src/plugins/runner/CMakeLists.txt A +16 -0 src/plugins/runner/mapquest/CMakeLists.txt A +49 -0 src/plugins/runner/mapquest/MapQuestConfigWidget.ui A +127 -0 src/plugins/runner/mapquest/MapQuestPlugin.cpp [License:= LGPL] A +39 -0 src/plugins/runner/mapquest/MapQuestPlugin.h [License: L= GPL] A +251 -0 src/plugins/runner/mapquest/MapQuestRunner.cpp [License:= LGPL] A +60 -0 src/plugins/runner/mapquest/MapQuestRunner.h [License: L= GPL] M +1 -1 src/qt-components/marble-touch/AboutMarblePage.qml http://commits.kde.org/marble/526683505900e1b7d0ff3d3069dfb4f65b1eca92 diff --git a/src/lib/MarbleAboutDialog.cpp b/src/lib/MarbleAboutDialog.cpp index db46ff4..b266602 100644 --- a/src/lib/MarbleAboutDialog.cpp +++ b/src/lib/MarbleAboutDialog.cpp @@ -236,11 +236,18 @@ void MarbleAboutDialog::loadPageContents( int idx ) "These icons can be used freely under the terms of the " "CC0 1.0 Universal license.

") + tr("

OpenRouteService
" - "The routes used in Marble via download are provided by the OpenRouteService Project= (\"ORS\").
" "License: OpenRouteService data can be used freely under= the terms of the " "" "Creative Commons Attribution-ShareAlike 2.0 license.

")+ + tr("

MapQuest
" + "Some of the routes used in Marble via download are provided by= MapQuest and their Open Data Ma= p APIs and Web Services.
" + "Directions courtesy of MapQuest working on OpenStreetMap data = that can be used freely under the terms of the " + "" + "Creative Commons Attribution-ShareAlike 2.0 license. Usage= of the MapQuest routing " + "service is subject to the MapQuest terms of use.

")+ tr("Cities and Locations")+ tr("

World Gazetteer
Stefan Helders " "http://www.world-= gazetteer.com

")+ diff --git a/src/plugins/runner/CMakeLists.txt b/src/plugins/runner/CMakeLi= sts.txt index fd644a6..61aa14b 100644 --- a/src/plugins/runner/CMakeLists.txt +++ b/src/plugins/runner/CMakeLists.txt @@ -7,8 +7,13 @@ add_subdirectory( nominatim ) = # Routing add_subdirectory( gosmore ) +add_subdirectory( mapquest ) +add_subdirectory( monav ) add_subdirectory( openrouteservice ) add_subdirectory( routino ) +add_subdirectory( yours ) +# traveling-salesman works, but it is quite slow (tested version 1.0.3-RC1) +#add_subdirectory( traveling-salesman ) = #Parsing add_subdirectory( cache ) @@ -16,11 +21,3 @@ add_subdirectory( gpx ) add_subdirectory( kml ) add_subdirectory( osm ) add_subdirectory( pnt ) - -# traveling-salesman works, but it is quite slow (tested version 1.0.3-RC1) -#add_subdirectory( traveling-salesman ) - -# waiting for signals.h being released under lgpl-2 -add_subdirectory( monav ) - -add_subdirectory( yours ) diff --git a/src/plugins/runner/mapquest/CMakeLists.txt b/src/plugins/runne= r/mapquest/CMakeLists.txt new file mode 100644 index 0000000..ed75a6e --- /dev/null +++ b/src/plugins/runner/mapquest/CMakeLists.txt @@ -0,0 +1,16 @@ +PROJECT( MapQuestPlugin ) + +INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_SOURCE_DIR}/src/plugins/runner/mapquest + ${CMAKE_BINARY_DIR}/src/plugins/runner/mapquest + ${QT_INCLUDE_DIR} +) +INCLUDE(${QT_USE_FILE}) + +set( mapquest_SRCS MapQuestRunner.cpp MapQuestPlugin.cpp ) + +set( mapquest_UI MapQuestConfigWidget.ui ) + +qt4_wrap_ui( mapquest_SRCS ${mapquest_UI} ) + +marble_add_plugin( MapQuestPlugin ${mapquest_SRCS} ) diff --git a/src/plugins/runner/mapquest/MapQuestConfigWidget.ui b/src/plug= ins/runner/mapquest/MapQuestConfigWidget.ui new file mode 100644 index 0000000..d072d93 --- /dev/null +++ b/src/plugins/runner/mapquest/MapQuestConfigWidget.ui @@ -0,0 +1,49 @@ + + + MapQuestConfigWidget + + + + 0 + 0 + 284 + 145 + + + + + + + Preference: + + + + + + + + + + Avoid motorways + + + + + + + Avoid tollways + + + + + + + Avoid ferries + + + + + + + + diff --git a/src/plugins/runner/mapquest/MapQuestPlugin.cpp b/src/plugins/r= unner/mapquest/MapQuestPlugin.cpp new file mode 100644 index 0000000..d08d95d --- /dev/null +++ b/src/plugins/runner/mapquest/MapQuestPlugin.cpp @@ -0,0 +1,127 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2012 Dennis Nienh=C3=BCser +// + +#include "MapQuestPlugin.h" +#include "MapQuestRunner.h" + +#include "ui_MapQuestConfigWidget.h" + +namespace Marble +{ + +MapQuestPlugin::MapQuestPlugin( QObject *parent ) : RunnerPlugin( parent ) +{ + setCapabilities( Routing ); + setSupportedCelestialBodies( QStringList() << "earth" ); + setCanWorkOffline( false ); + setName( tr( "MapQuest" ) ); + setNameId( "mapquest" ); + setDescription( tr( "Worldwide routing using mapquest.org" ) ); + setStatusMessage( tr ( "This service requires an Internet connection."= ) ); + setGuiString( tr( "MapQuest Routing" ) ); +} + +MarbleAbstractRunner* MapQuestPlugin::newRunner() const +{ + return new MapQuestRunner; +} + +class MapQuestConfigWidget : public RunnerPlugin::ConfigWidget +{ +public: + + MapQuestConfigWidget() + : RunnerPlugin::ConfigWidget() + { + ui_configWidget =3D new Ui::MapQuestConfigWidget; + ui_configWidget->setupUi( this ); + + ui_configWidget->preference->addItem( tr( "Car (fastest way)" ), "= fastest" ); + ui_configWidget->preference->addItem( tr( "Car (shortest way)" ), = "shortest" ); + ui_configWidget->preference->addItem( tr( "Pedestrian" ), "pedestr= ian" ); + ui_configWidget->preference->addItem( tr( "Bicycle" ), "bicycle" ); + ui_configWidget->preference->addItem( tr( "Transit (Public Transpo= rt)" ), "multimodal" ); + } + + virtual void loadSettings( const QHash &settings_ ) + { + QHash settings =3D settings_; + + // Check if all fields are filled and fill them with default value= s. + if ( !settings.contains( "preference" ) ) { + settings.insert( "preference", "fastest" ); + } + ui_configWidget->preference->setCurrentIndex( + ui_configWidget->preference->findData( settings.value(= "preference" ).toString() ) ); + ui_configWidget->noMotorways->setCheckState( static_cast( settings.value( "noMotorways" ).toInt() ) ); + ui_configWidget->noTollways->setCheckState( static_cast( settings.value( "noTollways" ).toInt() ) ); + ui_configWidget->noFerries->setCheckState( static_cast( settings.value( "noFerries" ).toInt() ) ); + } + + virtual QHash settings() const + { + QHash settings; + settings.insert( "preference", + ui_configWidget->preference->itemData( ui_configW= idget->preference->currentIndex() ) ); + settings.insert( "noMotorways", ui_configWidget->noMotorways->chec= kState() ); + settings.insert( "noTollways", ui_configWidget->noTollways->checkS= tate() ); + settings.insert( "noFerries", ui_configWidget->noFerries->checkSta= te() ); + return settings; + } +private: + Ui::MapQuestConfigWidget *ui_configWidget; +}; + +RunnerPlugin::ConfigWidget *MapQuestPlugin::configWidget() +{ + return new MapQuestConfigWidget(); +} + + +bool MapQuestPlugin::supportsTemplate( RoutingProfilesModel::ProfileTempla= te profileTemplate ) const +{ + QSet availableTemplates; + availableTemplates.insert( RoutingProfilesModel::CarFastestTemplate ); + availableTemplates.insert( RoutingProfilesModel::CarShortestTemplate ); + availableTemplates.insert( RoutingProfilesModel::BicycleTemplate ); + availableTemplates.insert( RoutingProfilesModel::PedestrianTemplate ); + return availableTemplates.contains( profileTemplate ); +} + +QHash< QString, QVariant > MapQuestPlugin::templateSettings( RoutingProfil= esModel::ProfileTemplate profileTemplate ) const +{ + QHash result; + switch ( profileTemplate ) { + case RoutingProfilesModel::CarFastestTemplate: + result["preference"] =3D "fastest"; + break; + case RoutingProfilesModel::CarShortestTemplate: + result["preference"] =3D "shortest"; + break; + case RoutingProfilesModel::CarEcologicalTemplate: + break; + case RoutingProfilesModel::BicycleTemplate: + result["preference"] =3D "bicycle"; + break; + case RoutingProfilesModel::PedestrianTemplate: + result["preference"] =3D "pedestrian"; + break; + case RoutingProfilesModel::LastTemplate: + Q_ASSERT( false ); + break; + } + return result; +} + +} + +Q_EXPORT_PLUGIN2( MapQuestPlugin, Marble::MapQuestPlugin ) + +#include "MapQuestPlugin.moc" diff --git a/src/plugins/runner/mapquest/MapQuestPlugin.h b/src/plugins/run= ner/mapquest/MapQuestPlugin.h new file mode 100644 index 0000000..295194a --- /dev/null +++ b/src/plugins/runner/mapquest/MapQuestPlugin.h @@ -0,0 +1,39 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2012 Dennis Nienh=C3=BCser +// + + +#ifndef MARBLE_MAPQUESTPLUGIN_H +#define MARBLE_MAPQUESTPLUGIN_H + +#include "RunnerPlugin.h" + +namespace Marble +{ + +class MapQuestPlugin : public RunnerPlugin +{ + Q_OBJECT + Q_INTERFACES( Marble::RunnerPlugin ) + +public: + explicit MapQuestPlugin( QObject *parent =3D 0 ); + + virtual MarbleAbstractRunner* newRunner() const; + + ConfigWidget* configWidget(); + + virtual bool supportsTemplate( RoutingProfilesModel::ProfileTemplate p= rofileTemplate ) const; + virtual QHash templateSettings( RoutingProfilesMode= l::ProfileTemplate profileTemplate ) const; + +}; + +} + +#endif diff --git a/src/plugins/runner/mapquest/MapQuestRunner.cpp b/src/plugins/r= unner/mapquest/MapQuestRunner.cpp new file mode 100644 index 0000000..ab09747 --- /dev/null +++ b/src/plugins/runner/mapquest/MapQuestRunner.cpp @@ -0,0 +1,251 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2012 Dennis Nienh=C3=BCser +// + +#include "MapQuestRunner.h" + +#include "MarbleAbstractRunner.h" +#include "MarbleDebug.h" +#include "MarbleLocale.h" +#include "GeoDataDocument.h" +#include "GeoDataPlacemark.h" +#include "GeoDataExtendedData.h" +#include "TinyWebBrowser.h" +#include "routing/Maneuver.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Marble +{ + +MapQuestRunner::MapQuestRunner( QObject *parent ) : + MarbleAbstractRunner( parent ), + m_networkAccessManager( new QNetworkAccessManager( this ) ) +{ + connect( m_networkAccessManager, SIGNAL( finished( QNetworkReply * ) ), + this, SLOT( retrieveData( QNetworkReply * ) ) ); +} + +MapQuestRunner::~MapQuestRunner() +{ + // nothing to do +} + +GeoDataFeature::GeoDataVisualCategory MapQuestRunner::category() const +{ + return GeoDataFeature::OsmSite; +} + +void MapQuestRunner::retrieveRoute( const RouteRequest *route ) +{ + if ( route->size() < 2 ) { + return; + } + + QHash settings =3D route->routingProfile().pluginSe= ttings()["mapquest"]; + + QString url =3D "http://open.mapquestapi.com/directions/v0/route?callb= ack=3DrenderAdvancedNarrative&outFormat=3Dxml&narrativeType=3Dtext&shapeFor= mat=3Draw&generalize=3D0"; + GeoDataCoordinates::Unit const degree =3D GeoDataCoordinates::Degree; + append( &url, "from", QString::number( route->source().latitude( degre= e ), 'f', 6 ) + "," + QString::number( route->source().longitude( degree ),= 'f', 6 ) ); + for ( int i=3D1; isize(); ++i ) { + append( &url, "to", QString::number( route->at( i ).latitude( degr= ee ), 'f', 6 ) + "," + QString::number( route->at( i ).longitude( degree ),= 'f', 6 ) ); + } + + QString const unit =3D MarbleGlobal::getInstance()->locale()->measurem= entSystem() =3D=3D QLocale::MetricSystem ? "k" : "m"; + append( &url, "units", unit ); + + if ( settings["noMotorways"].toInt() ) { + append( &url, "avoids", "Limited Access" ); + } + if ( settings["noTollroads"].toInt() ) { + append( &url, "avoids", "Toll road" ); + } + if ( settings["noFerries"].toInt() ) { + append( &url, "avoids", "Ferry" ); + } + + if ( !settings["preference"].toString().isEmpty() ) { + append( &url, "routeType", settings["preference"].toString() ); + } + + QNetworkReply *reply =3D m_networkAccessManager->get( QNetworkRequest(= QUrl( url ) ) ); + connect( reply, SIGNAL( error( QNetworkReply::NetworkError ) ), + this, SLOT( handleError( QNetworkReply::NetworkError ) ) ); + + QEventLoop eventLoop; + + connect( this, SIGNAL( routeCalculated( GeoDataDocument* ) ), + &eventLoop, SLOT( quit() ) ); + + eventLoop.exec(); +} + +void MapQuestRunner::retrieveData( QNetworkReply *reply ) +{ + if ( reply->isFinished() ) { + QByteArray data =3D reply->readAll(); + reply->deleteLater(); + //mDebug() << "Download completed: " << data; + GeoDataDocument* document =3D parse( data ); + + if ( !document ) { + mDebug() << "Failed to parse the downloaded route data" << dat= a; + } + + emit routeCalculated( document ); + } +} + +void MapQuestRunner::handleError( QNetworkReply::NetworkError error ) +{ + mDebug() << " Error when retrieving mapquest.org route: " << error; +} + +void MapQuestRunner::append(QString *input, const QString &key, const QStr= ing &value) +{ + *input +=3D "&" + key + "=3D" + value; +} + +int MapQuestRunner::maneuverType( int mapQuestId ) const +{ + /** @todo FIXME: review 10, 11 */ + switch( mapQuestId ) { + case 0: return Maneuver::Straight ; // straight + case 1: return Maneuver::SlightRight ; // slight right + case 2: return Maneuver::Right ; // right + case 3: return Maneuver::SharpRight ; // sharp right + case 4: return Maneuver::TurnAround ; // reverse + case 5: return Maneuver::SharpLeft ; // sharp left + case 6: return Maneuver::Left ; // left + case 7: return Maneuver::SlightLeft ; // slight left + case 8: return Maneuver::TurnAround ; // right u-turn + case 9: return Maneuver::TurnAround ; // left u-turn + case 10: return Maneuver::SlightRight ; // right merge + case 11: return Maneuver::SlightLeft ; // left merge + case 12: return Maneuver::Right ; // right on ramp + case 13: return Maneuver::Left ; // left on ramp + case 14: return Maneuver::Right ; // right off ramp + case 15: return Maneuver::Left ; // left off ramp + case 16: return Maneuver::Right ; // right fork + case 17: return Maneuver::Left ; // left form + case 18: return Maneuver::Straight ; // straight fork + } + + return Maneuver::Unknown; +} + +GeoDataDocument* MapQuestRunner::parse( const QByteArray &content ) const +{ + QDomDocument xml; + if ( !xml.setContent( content ) ) { + mDebug() << "Cannot parse xml file with routing instructions."; + return 0; + } + + // mDebug() << xml.toString(2); + QDomElement root =3D xml.documentElement(); + + GeoDataDocument* result =3D new GeoDataDocument(); + result->setName( "MapQuest" ); + GeoDataPlacemark* routePlacemark =3D new GeoDataPlacemark; + routePlacemark->setName( "Route" ); + + GeoDataLineString* routeWaypoints =3D new GeoDataLineString; + QDomNodeList shapePoints =3D root.elementsByTagName( "shapePoints" ); + if ( shapePoints.size() =3D=3D 1 ) { + QDomNodeList geometry =3D shapePoints.at( 0 ).toElement().elements= ByTagName( "latLng" ); + for ( int i=3D0; iappend( position ); + } + } + routePlacemark->setGeometry( routeWaypoints ); + + QString name =3D "%1 %2 (MapQuest)"; + QString unit =3D "m"; + qreal length =3D routeWaypoints->length( EARTH_RADIUS ); + if (length >=3D 1000) { + length /=3D 1000.0; + unit =3D "km"; + } + result->setName( name.arg( length, 0, 'f', 1 ).arg( unit ) ); + result->append( routePlacemark ); + + QMap mapping; + QDomNodeList maneuvers =3D root.elementsByTagName( "maneuverIndexes" ); + if ( maneuvers.size() =3D=3D 1 ) { + maneuvers =3D maneuvers.at( 0 ).childNodes(); + for ( int i=3D0; isize() ) { + --mapping[i]; + } + } + } + + QDomNodeList instructions =3D root.elementsByTagName( "maneuver" ); + for ( unsigned int i =3D 0; i < instructions.length(); ++i ) { + QDomElement node =3D instructions.item( i ).toElement(); + + QDomNodeList maneuver =3D node.elementsByTagName( "turnType" ); + QDomNodeList textNodes =3D node.elementsByTagName( "narrative" ); + QDomNodeList points =3D node.elementsByTagName( "startPoint" ); + QDomNodeList streets =3D node.elementsByTagName( "streets" ); + + Q_ASSERT( mapping.contains( i ) ); + if ( textNodes.size() =3D=3D 1 && maneuver.size() =3D=3D 1 && poin= ts.size() =3D=3D 1 && mapping.contains( i ) ) { + GeoDataPlacemark* instruction =3D new GeoDataPlacemark; + instruction->setName( textNodes.at( 0 ).toElement().text() ); + + GeoDataExtendedData extendedData; + GeoDataData turnType; + turnType.setName( "turnType" ); + turnType.setValue( maneuverType( maneuver.at( 0 ).toElement().= text().toInt() ) ); + extendedData.addValue( turnType ); + if ( streets.size() =3D=3D 1 ) { + GeoDataData roadName; + roadName.setName( "roadName" ); + roadName.setValue( streets.at( 0 ).toElement().text() ); + extendedData.addValue( roadName ); + } + instruction->setExtendedData( extendedData ); + + int const start =3D mapping[i]; + int const end =3D mapping.contains(i+1) ? mapping[i+1] : route= Waypoints->size()-1; + if ( start >=3D 0 && start < routeWaypoints->size() && end < r= outeWaypoints->size() ) { + instruction->setName( textNodes.item( 0 ).toElement().text= () ); + GeoDataLineString *lineString =3D new GeoDataLineString; + for ( int j=3Dstart; j<=3Dend; ++j ) { + *lineString << GeoDataCoordinates( routeWaypoints->at(= j ).longitude(), routeWaypoints->at( j ).latitude() ); + } + + if ( !lineString->isEmpty() ) { + instruction->setGeometry( lineString ); + result->append( instruction ); + } + } + } + } + + return result; +} + + +} // namespace Marble + +#include "MapQuestRunner.moc" diff --git a/src/plugins/runner/mapquest/MapQuestRunner.h b/src/plugins/run= ner/mapquest/MapQuestRunner.h new file mode 100644 index 0000000..0500ea3 --- /dev/null +++ b/src/plugins/runner/mapquest/MapQuestRunner.h @@ -0,0 +1,60 @@ +// +// This file is part of the Marble Virtual Globe. +// +// This program is free software licensed under the GNU LGPL. You can +// find a copy of this license in LICENSE.txt in the top directory of +// the source code. +// +// Copyright 2012 Dennis Nienh=C3=BCser +// + + +#ifndef MARBLE_OSMMAPQUESTRUNNER_H +#define MARBLE_OSMMAPQUESTRUNNER_H + +#include "MarbleAbstractRunner.h" +#include "routing/RouteRequest.h" + +#include +#include + +class QNetworkAccessManager; + +namespace Marble +{ + +class MapQuestRunner : public MarbleAbstractRunner +{ + Q_OBJECT + +public: + explicit MapQuestRunner(QObject *parent =3D 0); + + ~MapQuestRunner(); + + // Overriding MarbleAbstractRunner + GeoDataFeature::GeoDataVisualCategory category() const; + + // Overriding MarbleAbstractRunner + virtual void retrieveRoute( const RouteRequest *request ); + +private Q_SLOTS: + /** Route data was retrieved via http */ + void retrieveData( QNetworkReply *reply ); + + /** A network error occurred */ + void handleError( QNetworkReply::NetworkError ); + +private: + void append( QString* input, const QString &key, const QString &value = ); + + int maneuverType( int mapQuestId ) const; + + GeoDataDocument* parse( const QByteArray &input ) const; + + QNetworkAccessManager *m_networkAccessManager; +}; + +} + +#endif diff --git a/src/qt-components/marble-touch/AboutMarblePage.qml b/src/qt-co= mponents/marble-touch/AboutMarblePage.qml index 18aa5ff..aae34f8 100644 --- a/src/qt-components/marble-touch/AboutMarblePage.qml +++ b/src/qt-components/marble-touch/AboutMarblePage.qml @@ -152,7 +152,7 @@ Page { } = Label { - text: "

Street Maps. OpenStreetMap. The street maps used= in Marble via download are provided by the OpenStreetMap Project (\"OSM\")= . OSM is an open community which creates free editable maps. License: OpenS= treetMap data can be used freely under the terms of the Creative Commons At= tribution-ShareAlike 2.0 license. Icons. Some icons are taken from SJJB Man= agement and NounProject. These icons can be used freely under the terms of = the CC0 1.0 Universal license. OpenRouteService. The routes used in Marble = via download are provided by the OpenRouteService Project (\"ORS\"). Licens= e: OpenRouteService data can be used freely under the terms of the Creative= Commons Attribution-ShareAlike 2.0 license.

" + text: "

Street Maps. OpenStreetMap. The street maps used= in Marble via download are provided by the OpenStreetMap Project (\"OSM\")= . OSM is an open community which creates free editable maps. License: OpenS= treetMap data can be used freely under the terms of the Creative Commons At= tribution-ShareAlike 2.0 license. Icons. Some icons are taken from SJJB Man= agement and NounProject. These icons can be used freely under the terms of = the CC0 1.0 Universal license. OpenRouteService. The routes used in Marble = via download are provided by the OpenRouteService Project (\"ORS\"). Licens= e: OpenRouteService data can be used freely under the terms of the Creative= Commons Attribution-ShareAlike 2.0 license. MapQuest. Some of the routes u= sed in Marble via download are provided by MapQuest (www.mapquest.com) and = their Open Data Map APIs and Web Services. Directions courtesy of MapQuest = working on OpenStreetMap data that can be used freely under the terms of th= e Creative Commons Attribution-ShareAlike 2.0 license. Usage of the MapQues= t routing service is subject to the MapQuest terms of use (http://info.mapq= uest.com/terms-of-use/).

" platformStyle: LabelStyle { fontPixelSize: 16 } width: parent.width horizontalAlignment: Text.AlignJustify