File indexing completed on 2025-02-16 12:59:05
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"