File indexing completed on 2024-07-14 10:58:48

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org>
0004 // SPDX-FileCopyrightText: 2016 Piotr Wójcik <chocimier@tlen.pl>
0005 //
0006 
0007 #include "YoursRunner.h"
0008 
0009 #include "MarbleDebug.h"
0010 #include "MarbleLocale.h"
0011 #include "GeoDataDocument.h"
0012 #include "GeoDataPlacemark.h"
0013 #include "GeoDataParser.h"
0014 #include "GeoDataFolder.h"
0015 #include "GeoDataLineString.h"
0016 #include "routing/RouteRequest.h"
0017 
0018 #include <QString>
0019 #include <QVector>
0020 #include <QUrl>
0021 #include <QBuffer>
0022 #include <QTimer>
0023 
0024 namespace Marble
0025 {
0026 
0027 YoursRunner::YoursRunner( QObject *parent ) :
0028         RoutingRunner( parent ),
0029         m_networkAccessManager()
0030 {
0031     connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
0032              this, SLOT(retrieveData(QNetworkReply*)) );
0033 }
0034 
0035 YoursRunner::~YoursRunner()
0036 {
0037     // nothing to do
0038 }
0039 
0040 void YoursRunner::retrieveRoute( const RouteRequest *route )
0041 {
0042     if ( route->size() != 2 ) {
0043         return;
0044     }
0045 
0046     GeoDataCoordinates source = route->source();
0047     GeoDataCoordinates destination = route->destination();
0048 
0049     double fLon = source.longitude( GeoDataCoordinates::Degree );
0050     double fLat = source.latitude( GeoDataCoordinates::Degree );
0051 
0052     double tLon = destination.longitude( GeoDataCoordinates::Degree );
0053     double tLat = destination.latitude( GeoDataCoordinates::Degree );
0054 
0055     QString base = "http://www.yournavigation.org/api/1.0/gosmore.php";
0056     //QString base = "http://nroets.dev.openstreetmap.org/demo/gosmore.php";
0057     QString args = "?flat=%1&flon=%2&tlat=%3&tlon=%4";
0058     args = args.arg( fLat, 0, 'f', 6 ).arg( fLon, 0, 'f', 6 ).arg( tLat, 0, 'f', 6 ).arg( tLon, 0, 'f', 6 );
0059 
0060     QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()[QStringLiteral("yours")];
0061     QString transport = settings[QStringLiteral("transport")].toString();
0062     QString fast;
0063 
0064     if (settings[QStringLiteral("method")] == QLatin1String("shortest")) {
0065         fast = "0";
0066     } else {
0067         fast = "1";
0068     }
0069 
0070     QString preferences = "&v=%1&fast=%2&layer=mapnik;";
0071     preferences = preferences.arg(transport).arg(fast);
0072     QString request = base + args + preferences;
0073     // mDebug() << "GET: " << request;
0074 
0075     m_request = QNetworkRequest( QUrl( request ) );
0076     m_request.setRawHeader( "X-Yours-client", "Marble" );
0077 
0078     QEventLoop eventLoop;
0079 
0080     QTimer timer;
0081     timer.setSingleShot( true );
0082     timer.setInterval( 15000 );
0083 
0084     connect( &timer, SIGNAL(timeout()),
0085              &eventLoop, SLOT(quit()));
0086     connect( this, SIGNAL(routeCalculated(GeoDataDocument*)),
0087              &eventLoop, SLOT(quit()) );
0088 
0089     // @todo FIXME Must currently be done in the main thread, see bug 257376
0090     QTimer::singleShot( 0, this, SLOT(get()) );
0091     timer.start();
0092 
0093     eventLoop.exec();
0094 }
0095 
0096 void YoursRunner::get()
0097 {
0098     QNetworkReply *reply = m_networkAccessManager.get( m_request );
0099     connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
0100              this, SLOT(handleError(QNetworkReply::NetworkError)) );
0101 }
0102 
0103 void YoursRunner::retrieveData( QNetworkReply *reply )
0104 {
0105     if ( reply->isFinished() ) {
0106         QByteArray data = reply->readAll();
0107         reply->deleteLater();
0108         //mDebug() << "Download completed: " << data;
0109         GeoDataDocument* result = parse( data );
0110         if ( result ) {
0111             QString name = "%1 %2 (Yours)";
0112             QString unit = QLatin1String( "m" );
0113             qreal length = distance( result );
0114             if ( length == 0.0 ) {
0115                 delete result;
0116                 emit routeCalculated( nullptr );
0117                 return;
0118             } else if ( length >= 1000 ) {
0119                 length /= 1000.0;
0120                 unit = "km";
0121             }
0122             result->setName( name.arg( length, 0, 'f', 1 ).arg( unit ) );
0123         }
0124         emit routeCalculated( result );
0125     }
0126 }
0127 
0128 void YoursRunner::handleError( QNetworkReply::NetworkError error )
0129 {
0130     mDebug() << " Error when retrieving yournavigation.org route: " << error;
0131     emit routeCalculated( nullptr );
0132 }
0133 
0134 GeoDataDocument* YoursRunner::parse( const QByteArray &content )
0135 {
0136     GeoDataParser parser( GeoData_UNKNOWN );
0137 
0138     // Open file in right mode
0139     QBuffer buffer;
0140     buffer.setData( content );
0141     buffer.open( QIODevice::ReadOnly );
0142 
0143     if ( !parser.read( &buffer ) ) {
0144         mDebug() << "Cannot parse kml data! Input is " << content ;
0145         return nullptr;
0146     }
0147     GeoDataDocument* document = static_cast<GeoDataDocument*>( parser.releaseDocument() );
0148     return document;
0149 }
0150 
0151 qreal YoursRunner::distance( const GeoDataDocument* document )
0152 {
0153     QVector<GeoDataFolder*> folders = document->folderList();
0154     for( const GeoDataFolder *folder: folders ) {
0155         for( const GeoDataPlacemark *placemark: folder->placemarkList() ) {
0156             const GeoDataGeometry* geometry = placemark->geometry();
0157             if ( geometry->geometryId() == GeoDataLineStringId ) {
0158                 const GeoDataLineString* lineString = dynamic_cast<const GeoDataLineString*>( geometry );
0159                 Q_ASSERT( lineString && "Internal error: geometry ID does not match class type" );
0160                 return lineString->length( EARTH_RADIUS );
0161             }
0162         }
0163     }
0164 
0165     return 0.0;
0166 }
0167 
0168 } // namespace Marble
0169 
0170 #include "moc_YoursRunner.cpp"