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.