File indexing completed on 2024-12-01 09:46:04

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org>
0004 //
0005 
0006 #include "MonavRunner.h"
0007 #include "MonavPlugin.h"
0008 #include "signals.h"
0009 
0010 #include "MarbleDebug.h"
0011 #include "MarbleDirs.h"
0012 #include "routing/RouteRequest.h"
0013 #include "routing/instructions/InstructionTransformation.h"
0014 #include "GeoDataDocument.h"
0015 #include "GeoDataData.h"
0016 #include "GeoDataExtendedData.h"
0017 #include "GeoDataPlacemark.h"
0018 #include "GeoDataLineString.h"
0019 
0020 #include <QTime>
0021 #include <QLocalSocket>
0022 
0023 using namespace MoNav;
0024 
0025 namespace Marble
0026 {
0027 
0028 class MonavRunnerPrivate
0029 {
0030 public:
0031     const MonavPlugin* m_plugin;
0032 
0033     MonavRunnerPrivate( const MonavPlugin* plugin );
0034 
0035     bool retrieveData( const RouteRequest *route, RoutingResult* result ) const;
0036 
0037     bool retrieveData( const RouteRequest *route, const QString &mapDir, RoutingResult* result ) const;
0038 
0039     int retrieveRoute( const RouteRequest *route, QVector<GeoDataPlacemark*> *instructions, GeoDataLineString* geometry ) const;
0040 
0041     static GeoDataDocument* createDocument( GeoDataLineString *geometry, const QVector<GeoDataPlacemark*> &instructions, const QString &name, const GeoDataExtendedData &data );
0042 };
0043 
0044 MonavRunnerPrivate::MonavRunnerPrivate( const MonavPlugin* plugin ) :
0045         m_plugin( plugin )
0046 {
0047     // nothing to do
0048 }
0049 
0050 bool MonavRunnerPrivate::retrieveData( const RouteRequest *route, RoutingResult* reply ) const
0051 {
0052     QString mapDir = m_plugin->mapDirectoryForRequest( route );
0053     if ( mapDir.isEmpty() ) {
0054         return false;
0055     }
0056 
0057     if ( retrieveData( route, mapDir, reply ) ) {
0058         return true;
0059     }
0060 
0061     // The separation into two different methods to determine a first country candidate
0062     // and a list of alternative ones if the first candidate fails is intentional
0063     // for performance reasons. Do not merge both.
0064     QStringList alternatives = m_plugin->mapDirectoriesForRequest( route );
0065     alternatives.removeOne( mapDir );
0066     for( const QString &mapDir: alternatives ) {
0067         if ( retrieveData( route, mapDir, reply ) ) {
0068             return true;
0069         }
0070     }
0071 
0072     return false;
0073 }
0074 
0075 bool MonavRunnerPrivate::retrieveData( const RouteRequest *route, const QString &mapDir, RoutingResult* reply ) const
0076 {
0077     QLocalSocket socket;
0078     socket.connectToServer( "MoNavD" );
0079     if ( socket.waitForConnected() ) {
0080         if ( m_plugin->monavVersion() == MonavPlugin::Monav_0_3 ) {
0081             CommandType commandType;
0082             commandType.value = CommandType::RoutingCommand;
0083             commandType.post( &socket );
0084         }
0085 
0086         RoutingCommand command;
0087         QVector<Node> waypoints;
0088 
0089         for ( int i = 0; i < route->size(); ++i ) {
0090             Node coordinate;
0091             coordinate.longitude = route->at( i ).longitude( GeoDataCoordinates::Degree );
0092             coordinate.latitude = route->at( i ).latitude( GeoDataCoordinates::Degree );
0093             waypoints << coordinate;
0094         }
0095 
0096         command.dataDirectory = mapDir;
0097         command.lookupRadius = 1500;
0098         command.waypoints = waypoints;
0099         command.lookupStrings = true;
0100 
0101         command.post( &socket );
0102         socket.flush();
0103 
0104         if ( reply->read( &socket ) ) {
0105             switch ( reply->type ) {
0106             case RoutingResult::LoadFailed:
0107                 mDebug() << "failed to load monav map from " << mapDir;
0108                 return false;
0109             case RoutingResult::RouteFailed:
0110                 mDebug() << "failed to retrieve route from monav daemon";
0111                 return false;
0112             case RoutingResult::TypeLookupFailed:
0113                 mDebug() << "failed to lookup type from monav daemon";
0114                 return false;
0115             case RoutingResult::NameLookupFailed:
0116                 mDebug() << "failed to lookup name from monav daemon";
0117                 return false;
0118             case RoutingResult::Success:
0119                 return true;
0120             }
0121         } else {
0122             mDebug() << "Failed to read reply";
0123         }
0124     } else {
0125         mDebug() << "No connection to MoNavD";
0126     }
0127 
0128     return false;
0129 }
0130 
0131 int MonavRunnerPrivate::retrieveRoute( const Marble::RouteRequest* route, QVector< Marble::GeoDataPlacemark* >* instructions, Marble::GeoDataLineString* geometry ) const
0132 {
0133     RoutingResult reply;
0134     if ( retrieveData( route, &reply ) ) {
0135         /** @todo: make use of reply.seconds, the estimated travel time */
0136         for ( int i = 0; i < reply.pathNodes.size(); ++i ) {
0137             qreal lon = reply.pathNodes[i].longitude;
0138             qreal lat = reply.pathNodes[i].latitude;
0139             GeoDataCoordinates coordinates( lon, lat, 0, GeoDataCoordinates::Degree );
0140             geometry->append( coordinates );
0141         }
0142 
0143         RoutingWaypoints waypoints;
0144         int k = 0;
0145         for ( int i = 0; i < reply.pathEdges.size(); ++i ) {
0146             QString road = reply.nameStrings[reply.pathEdges[i].name];
0147             QString type = reply.typeStrings[reply.pathEdges[i].type];
0148             RoutingWaypoint::JunctionType junction = RoutingWaypoint::Other;
0149             if (type == QLatin1String("roundabout") && reply.pathEdges[i].branchingPossible) {
0150                 junction = RoutingWaypoint::Roundabout;
0151             }
0152             for ( unsigned int l = 0; l < reply.pathEdges[i].length; ++k, ++l ) {
0153                 qreal lon = reply.pathNodes[k].longitude;
0154                 qreal lat = reply.pathNodes[k].latitude;
0155                 RoutingPoint point( lon, lat );
0156                 bool const last = l == reply.pathEdges[i].length - 1;
0157                 RoutingWaypoint::JunctionType finalJunction = last ? junction : ( reply.pathEdges[i].branchingPossible ? RoutingWaypoint::Other : RoutingWaypoint::None );
0158                 RoutingWaypoint waypoint( point, finalJunction, "", type, -1, road );
0159                 waypoints.push_back( waypoint );
0160             }
0161         }
0162 
0163         RoutingInstructions directions = InstructionTransformation::process( waypoints );
0164         for ( int i = 0; i < directions.size(); ++i ) {
0165             GeoDataPlacemark* placemark = new GeoDataPlacemark( directions[i].instructionText() );
0166             GeoDataExtendedData extendedData;
0167             GeoDataData turnType;
0168             turnType.setName(QStringLiteral("turnType"));
0169             turnType.setValue( QVariant::fromValue( int( directions[i].turnType() ) ) );
0170             extendedData.addValue( turnType );
0171             GeoDataData roadName;
0172             roadName.setName(QStringLiteral("roadName"));
0173             roadName.setValue( directions[i].roadName() );
0174             extendedData.addValue( roadName );
0175             placemark->setExtendedData( extendedData );
0176             Q_ASSERT( !directions[i].points().isEmpty() );
0177             GeoDataLineString* geometry = new GeoDataLineString;
0178             QVector<RoutingWaypoint> items = directions[i].points();
0179             for ( int j = 0; j < items.size(); ++j ) {
0180                 RoutingPoint point = items[j].point();
0181                 GeoDataCoordinates coordinates( point.lon(), point.lat(), 0.0, GeoDataCoordinates::Degree );
0182                 geometry->append( coordinates );
0183             }
0184             placemark->setGeometry( geometry );
0185             instructions->push_back( placemark );
0186         }
0187         int duration = (int) reply.seconds;
0188         return duration;
0189     }
0190     return 0;
0191 }
0192 
0193 GeoDataDocument* MonavRunnerPrivate::createDocument( Marble::GeoDataLineString* geometry, const QVector< Marble::GeoDataPlacemark* >& instructions, const QString& name, const Marble::GeoDataExtendedData& data )
0194 {
0195     if ( !geometry || geometry->isEmpty() ) {
0196         return nullptr;
0197     }
0198 
0199     GeoDataDocument* result = new GeoDataDocument;
0200     GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
0201     routePlacemark->setName(QStringLiteral("Route"));
0202     routePlacemark->setGeometry( geometry );
0203     routePlacemark->setExtendedData( data );
0204     result->append( routePlacemark );
0205 
0206     for( GeoDataPlacemark* placemark: instructions ) {
0207         result->append( placemark );
0208     }
0209 
0210     result->setName( name );
0211     return result;
0212 }
0213 
0214 MonavRunner::MonavRunner( const MonavPlugin* plugin, QObject *parent ) :
0215         RoutingRunner( parent ),
0216         d( new MonavRunnerPrivate( plugin ) )
0217 {
0218     // nothing to do
0219 }
0220 
0221 MonavRunner::~MonavRunner()
0222 {
0223     delete d;
0224 }
0225 
0226 void MonavRunner::retrieveRoute( const RouteRequest *route )
0227 {
0228     QVector<GeoDataPlacemark*> instructions;
0229     QTime time;
0230     GeoDataLineString* waypoints = new GeoDataLineString();
0231     int duration = d->retrieveRoute( route, &instructions, waypoints );
0232     time = time.addSecs( duration );
0233     qreal length = waypoints->length( EARTH_RADIUS );
0234     const QString name = nameString( "Monav", length, time );
0235     const GeoDataExtendedData data = routeData( length, time );
0236     GeoDataDocument *result = d->createDocument( waypoints, instructions, name, data );
0237     emit routeCalculated( result );
0238 }
0239 
0240 #if 0
0241 void MonavRunner::reverseGeocoding( const GeoDataCoordinates &coordinates )
0242 {
0243     GeoDataPlacemark placemark;
0244     placemark.setCoordinate( GeoDataPoint( coordinates ) );
0245 
0246     RouteRequest route;
0247     route.append( coordinates );
0248     route.append( coordinates );
0249     RoutingResult reply;
0250 
0251     if ( d->retrieveData( &route, &reply ) && !reply.pathEdges.isEmpty() ) {
0252         QString road = reply.nameStrings[reply.pathEdges[0].name];
0253         placemark.setAddress( road );
0254         GeoDataExtendedData extendedData;
0255         extendedData.addValue( GeoDataData( "road", road ) );
0256         placemark.setExtendedData( extendedData );
0257     }
0258 
0259     emit reverseGeocodingFinished( coordinates, placemark );
0260 }
0261 #endif
0262 
0263 } // namespace Marble
0264 
0265 #include "moc_MonavRunner.cpp"