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"