26 #include <QNetworkReply> 
   27 #include <QDomDocument> 
   34         m_networkAccessManager()
 
   36     connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
 
   37              this, SLOT(retrieveData(QNetworkReply*)));
 
   47     if ( route->
size() < 2 ) {
 
   56     QString request = xmlHeader();
 
   58     QString preference = 
"Fastest";
 
   59     if ( settings.contains( 
"preference" ) ) {
 
   60         preference = settings[
"preference"].toString();
 
   62     if ( preference == 
"Pedestrian" ) {
 
   66     request += requestHeader( unit, preference );
 
   67     request += requestPoint( StartPoint, source );
 
   69     if ( route->
size() > 2 ) {
 
   70         for ( 
int i = 1; i < route->
size() - 1; ++i ) {
 
   71             request += requestPoint( ViaPoint, route->
at( i ) );
 
   75     request += requestPoint( EndPoint, destination );
 
   76     request += requestFooter( settings );
 
   77     request += xmlFooter();
 
   82     QUrl url = QUrl( 
"http://openls.geog.uni-heidelberg.de/osm/eu/routing" );
 
   83     m_request = QNetworkRequest( url );
 
   84     m_request.setHeader( QNetworkRequest::ContentTypeHeader, 
"application/xml" );
 
   85     m_requestData = request.toLatin1();
 
   89     timer.setSingleShot( 
true );
 
   90     timer.setInterval( 15000 );
 
   92     connect( &timer, SIGNAL(timeout()),
 
   93              &eventLoop, SLOT(quit()));
 
   95              &eventLoop, SLOT(quit()));
 
   98     QTimer::singleShot( 0, 
this, SLOT(
get()));
 
  104 void OpenRouteServiceRunner::get()
 
  106     QNetworkReply *reply = m_networkAccessManager.post( m_request, m_requestData );
 
  107     connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
 
  108              this, SLOT(handleError(QNetworkReply::NetworkError)), Qt::DirectConnection);
 
  111 void OpenRouteServiceRunner::retrieveData( QNetworkReply *reply )
 
  113     if ( reply->isFinished() ) {
 
  114         QByteArray data = reply->readAll();
 
  115         reply->deleteLater();
 
  117         GeoDataDocument* document = parse( data );
 
  120             mDebug() << 
"Failed to parse the downloaded route data" << data;
 
  127 void OpenRouteServiceRunner::handleError( QNetworkReply::NetworkError error )
 
  129     mDebug() << 
" Error when retrieving openrouteservice.org route: " << error;
 
  132 QString OpenRouteServiceRunner::xmlHeader()
 const 
  134     QString result = 
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
 
  135     result += 
"<xls:XLS xmlns:xls=\"http://www.opengis.net/xls\" xmlns:sch=\"http://www.ascc.net/xml/schematron\" ";
 
  136     result += 
"xmlns:gml=\"http://www.opengis.net/gml\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ";
 
  137     result += 
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
 
  138     result += 
"xsi:schemaLocation=\"http://www.opengis.net/xls ";
 
  139     result += 
"http://schemas.opengis.net/ols/1.1.0/RouteService.xsd\" version=\"1.1\" xls:lang=\"en\">\n";
 
  140     result += 
"<xls:RequestHeader/>\n";
 
  144 QString OpenRouteServiceRunner::requestHeader( 
const QString &unit, 
const QString &routePreference )
 const 
  146     QString result = 
"<xls:Request methodName=\"RouteRequest\" requestID=\"123456789\" version=\"1.1\">\n";
 
  147     result += 
"<xls:DetermineRouteRequest distanceUnit=\"%1\">\n";
 
  148     result += 
"<xls:RoutePlan>\n";
 
  149     result += 
"<xls:RoutePreference>%2</xls:RoutePreference>\n";
 
  150     result += 
"<xls:WayPointList>\n";
 
  151     return result.arg( unit ).arg( routePreference );
 
  154 QString OpenRouteServiceRunner::requestPoint( PointType pointType, 
const GeoDataCoordinates &coordinates )
 const 
  156     QString result = 
"<xls:%1>\n";
 
  157     result += 
"<xls:Position>\n";
 
  158     result += 
"<gml:Point srsName=\"EPSG:4326\">\n";
 
  159     result += 
"<gml:pos>%2 %3</gml:pos>\n";
 
  160     result += 
"</gml:Point>\n";
 
  161     result += 
"</xls:Position>\n";
 
  162     result += 
"</xls:%1>\n";
 
  164     result = result.arg( pointType == StartPoint ? 
"StartPoint" : ( pointType == ViaPoint ? 
"ViaPoint" : 
"EndPoint" ) );
 
  170 QString OpenRouteServiceRunner::requestFooter( 
const QHash<QString, QVariant>& settings )
 const 
  172     QString result = 
"</xls:WayPointList>\n";
 
  174     if (settings[
"noMotorways"].toInt() || settings[
"noTollways"].toInt() ) {
 
  175         result += 
"<xls:AvoidList>\n";
 
  176         if ( settings[
"noTollways"].toInt() ) {
 
  177             result += 
"<xls:AvoidFeature>Tollway</xls:AvoidFeature>";
 
  179         if ( settings[
"noMotorways"].toInt() ) {
 
  180             result += 
"<xls:AvoidFeature>Highway</xls:AvoidFeature>";
 
  182         result += 
"</xls:AvoidList>\n";
 
  185     result += 
"</xls:RoutePlan>\n";
 
  186     result += 
"<xls:RouteInstructionsRequest provideGeometry=\"true\" />\n";
 
  187     result += 
"<xls:RouteGeometryRequest/>\n";
 
  188     result += 
"</xls:DetermineRouteRequest>\n";
 
  189     result += 
"</xls:Request>\n";
 
  193 QString OpenRouteServiceRunner::xmlFooter()
 const 
  195     return "</xls:XLS>\n";
 
  198 GeoDataDocument* OpenRouteServiceRunner::parse( 
const QByteArray &content )
 const 
  201     if ( !xml.setContent( content ) ) {
 
  202         mDebug() << 
"Cannot parse xml file with routing instructions.";
 
  206     QDomElement root = xml.documentElement();
 
  208     GeoDataDocument* result = 
new GeoDataDocument();
 
  209     result->setName( 
"OpenRouteService" );
 
  211     QDomNodeList errors = root.elementsByTagName( 
"xls:Error" );
 
  212     if ( errors.size() > 0 ) {
 
  218         for ( 
unsigned int i = 0; i < errors.length(); ++i ) {
 
  219             QDomNode node = errors.item( i );
 
  220             QString errorMessage = node.attributes().namedItem( 
"message" ).nodeValue();
 
  221             QRegExp regexp = QRegExp( 
"^(.*) Please Check your Position: (-?[0-9]+.[0-9]+) (-?[0-9]+.[0-9]+) !" );
 
  222             if ( regexp.indexIn( errorMessage ) == 0 ) {
 
  223                 if ( regexp.capturedTexts().size() == 4 ) {
 
  224                     GeoDataPlacemark* placemark = 
new GeoDataPlacemark;
 
  225                     placemark->setName( regexp.capturedTexts().at( 1 ) );
 
  226                     GeoDataCoordinates position;
 
  229                     placemark->setCoordinate( position );
 
  230                     result->append( placemark );
 
  233                 mDebug() << 
"Error message " << errorMessage << 
" not parsable.";
 
  244     GeoDataPlacemark* routePlacemark = 
new GeoDataPlacemark;
 
  245     routePlacemark->setName( 
"Route" );
 
  247     QDomNodeList summary = root.elementsByTagName( 
"xls:RouteSummary" );
 
  248     if ( summary.size() > 0 ) {
 
  249         QDomNodeList time = summary.item( 0 ).toElement().elementsByTagName( 
"xls:TotalTime" );
 
  250         QDomNodeList distance = summary.item( 0 ).toElement().elementsByTagName( 
"xls:TotalDistance" );
 
  251         if ( time.size() == 1 && distance.size() == 1 ) {
 
  252             QRegExp regexp = QRegExp( 
"^P(?:(\\d+)D)?T(?:(\\d+)H)?(?:(\\d+)M)?(\\d+)S" );
 
  253             if ( regexp.indexIn( time.item( 0 ).toElement().text() ) == 0 ) {
 
  254                 QStringList matches = regexp.capturedTexts();
 
  255                 unsigned int hours( 0 ), minutes( 0 ), seconds( 0 );
 
  256                 switch ( matches.size() ) {
 
  261                     hours   = regexp.cap( matches.size() - 3 ).toInt();
 
  264                     minutes = regexp.cap( matches.size() - 2 ).toInt();
 
  267                     seconds = regexp.cap( matches.size() - 1 ).toInt();
 
  270                     mDebug() << 
"Unable to parse time string " << time.item( 0 ).toElement().text();
 
  273                 QTime time( hours, minutes, seconds, 0 );
 
  274                 qreal totalDistance = distance.item( 0 ).attributes().namedItem( 
"value" ).nodeValue().toDouble();
 
  275                 QString unit = distance.item( 0 ).attributes().namedItem( 
"uom" ).nodeValue();
 
  279                 else if ( unit != 
"KM" ) {
 
  280                     mDebug() << 
"Cannot parse distance unit " << unit << 
", treated as km.";
 
  283                 QString description = 
"";
 
  284                 routePlacemark->setDescription( description );
 
  289     GeoDataLineString* routeWaypoints = 
new GeoDataLineString;
 
  290     QDomNodeList geometry = root.elementsByTagName( 
"xls:RouteGeometry" );
 
  291     if ( geometry.size() > 0 ) {
 
  292         QDomNodeList waypoints = geometry.item( 0 ).toElement().elementsByTagName( 
"gml:pos" );
 
  293         for ( 
unsigned int i = 0; i < waypoints.length(); ++i ) {
 
  294             QDomNode node = waypoints.item( i );
 
  295             QStringList content = node.toElement().text().split( 
' ' );
 
  296             if ( content.length() == 2 ) {
 
  297                 GeoDataCoordinates position;
 
  300                 routeWaypoints->append( position );
 
  304     routePlacemark->setGeometry( routeWaypoints );
 
  306     QString name = 
"%1 %2 (OpenRouteService)";
 
  307     QString unit = QLatin1String( 
"m" );
 
  309     if (length >= 1000) {
 
  313     result->setName( name.arg( length, 0, 
'f', 1 ).arg( unit ) );
 
  315     result->append( routePlacemark );
 
  317     QDomNodeList instructionList = root.elementsByTagName( 
"xls:RouteInstructionsList" );
 
  318     if ( instructionList.size() > 0 ) {
 
  319         QDomNodeList instructions = instructionList.item( 0 ).toElement().elementsByTagName( 
"xls:RouteInstruction" );
 
  320         for ( 
unsigned int i = 0; i < instructions.length(); ++i ) {
 
  321             QDomElement node = instructions.item( i ).toElement();
 
  323             QDomNodeList textNodes = node.elementsByTagName( 
"xls:Instruction" );
 
  324             QDomNodeList positions = node.elementsByTagName( 
"gml:pos" );
 
  326             if ( textNodes.size() > 0 && positions.size() > 0 ) {
 
  327                 QStringList content = positions.at( 0 ).toElement().text().split( 
' ' );
 
  328                 if ( content.length() == 2 ) {
 
  329                     GeoDataLineString *lineString = 
new GeoDataLineString;
 
  331                     for( 
int i = 0; i < positions.count(); ++i ) {
 
  332                          QStringList pointList = positions.at( i ).toElement().text().split( 
' ' );
 
  333                          GeoDataCoordinates position;
 
  336                          lineString->append( position );
 
  339                     GeoDataPlacemark* instruction = 
new GeoDataPlacemark;
 
  341                     QString 
const text = textNodes.item( 0 ).toElement().text();
 
  342                     GeoDataExtendedData extendedData;
 
  343                     GeoDataData turnTypeData;
 
  344                     turnTypeData.setName( 
"turnType" );
 
  347                     turnTypeData.setValue( turnType );
 
  348                     extendedData.addValue( turnTypeData );
 
  349                     if ( !road.isEmpty() ) {
 
  350                         GeoDataData roadName;
 
  351                         roadName.setName( 
"roadName" );
 
  352                         roadName.setValue( road );
 
  353                         extendedData.addValue( roadName );
 
  357                     instruction->setName( instructionText );
 
  358                     instruction->setExtendedData( extendedData );
 
  359                     instruction->setGeometry( lineString );
 
  360                     result->append( instruction );
 
  371     QRegExp syntax( 
"^(Go|Drive) (half left|left|sharp left|straight forward|half right|right|sharp right)( on )?(.*)?$", Qt::CaseSensitive, QRegExp::RegExp2 );
 
  373     if ( syntax.indexIn( text ) == 0 ) {
 
  374         if ( syntax.captureCount() > 1 ) {
 
  375             instruction = syntax.cap( 2 );
 
  376             if ( syntax.captureCount() == 4 ) {
 
  377                 *road = syntax.cap( 4 ).remove(QLatin1String( 
" - Arrived at destination!"));
 
  382     if ( instruction == 
"Continue" ) {
 
  384     } 
else if ( instruction == 
"half right" ) {
 
  386     } 
else if ( instruction == 
"right" ) {
 
  388     } 
else if ( instruction == 
"sharp right" ) {
 
  390     } 
else if ( instruction == 
"straight forward" ) {
 
  392     } 
else if ( instruction == 
"turn" ) {
 
  394     } 
else if ( instruction == 
"sharp left" ) {
 
  396     } 
else if ( instruction == 
"left" ) {
 
  398     } 
else if ( instruction == 
"half left" ) {
 
  407 #include "OpenRouteServiceRunner.moc" 
OpenRouteServiceRunner(QObject *parent=0)
 
int size() const 
Number of points in the route. 
 
A 3d point representation. 
 
A container for Features, Styles and in the future Schemas. 
 
GeoDataCoordinates destination() const 
The last point, or a default constructed if empty. 
 
static QString generateRoadInstruction(TurnType turnType, const QString &roadName)
 
Points to be included in a route. 
 
~OpenRouteServiceRunner()
 
RoutingProfile routingProfile() const 
 
virtual void retrieveRoute(const RouteRequest *request)
Start a route download orw calculation. 
 
const QHash< QString, QHash< QString, QVariant > > & pluginSettings() const 
 
void routeCalculated(GeoDataDocument *route)
Route download/calculation is finished, result in the given route object. 
 
QDebug mDebug()
a function to replace qDebug() in Marble library code 
 
GeoDataCoordinates source() const 
The first point, or a default constructed if empty. 
 
GeoDataCoordinates at(int index) const 
Accessor for the n-th position.