6#include "RoutingManager.h"
8#include "AlternativeRoutesModel.h"
10#include "RouteRequest.h"
11#include "RoutingModel.h"
12#include "RoutingProfilesModel.h"
13#include "RoutingRunnerPlugin.h"
15#include "GeoDataDocument.h"
16#include "GeoDataExtendedData.h"
17#include "GeoDataData.h"
18#include "GeoDataFolder.h"
19#include "GeoDataParser.h"
20#include "GeoDataPlacemark.h"
21#include "GeoDataTreeModel.h"
22#include "MarbleColors.h"
23#include "MarbleDirs.h"
24#include "MarbleDebug.h"
25#include "PositionTracking.h"
26#include "PluginManager.h"
27#include "PositionProviderPlugin.h"
29#include "RoutingRunnerManager.h"
30#include <KmlElementDictionary.h>
35#include <QMutexLocker>
40class RoutingManagerPrivate
45 RouteRequest m_routeRequest;
47 RoutingModel m_routingModel;
49 RoutingProfilesModel m_profilesModel;
51 RoutingManager::State m_state;
53 const PluginManager *
const m_pluginManager;
55 GeoDataTreeModel *
const m_treeModel;
57 PositionTracking *
const m_positionTracking;
59 AlternativeRoutesModel m_alternativeRoutesModel;
61 RoutingRunnerManager m_runnerManager;
65 bool m_guidanceModeEnabled;
69 bool m_shutdownPositionTracking;
71 bool m_guidanceModeWarning;
77 QColor m_routeColorStandard;
79 QColor m_routeColorHighlighted;
81 QColor m_routeColorAlternative;
83 RoutingManagerPrivate(MarbleModel *marbleModel, RoutingManager *manager);
85 static GeoDataFolder *createFolderFromRequest(
const RouteRequest &request);
89 void saveRoute(
const QString &filename );
91 void loadRoute(
const QString &filename );
93 void addRoute( GeoDataDocument* route );
95 void routingFinished();
97 void setCurrentRoute(
const GeoDataDocument *route);
99 void recalculateRoute(
bool deviated );
101 static void importPlacemark( RouteSegment &outline,
QVector<RouteSegment> &segments,
const GeoDataPlacemark *placemark );
104RoutingManagerPrivate::RoutingManagerPrivate(MarbleModel *model, RoutingManager *manager) :
106 m_routeRequest( manager ),
107 m_routingModel(&m_routeRequest, model->positionTracking(), manager),
108 m_profilesModel( model->pluginManager() ),
109 m_state( RoutingManager::Retrieved ),
110 m_pluginManager( model->pluginManager() ),
111 m_treeModel( model->treeModel() ),
112 m_positionTracking( model->positionTracking() ),
113 m_alternativeRoutesModel(manager),
114 m_runnerManager(model, manager),
115 m_haveRoute( false ),
116 m_guidanceModeEnabled( false ),
117 m_shutdownPositionTracking( false ),
118 m_guidanceModeWarning( true ),
119 m_routeColorStandard( Oxygen::skyBlue4 ),
120 m_routeColorHighlighted( Oxygen::skyBlue1 ),
121 m_routeColorAlternative( Oxygen::aluminumGray4 )
123 m_routeColorStandard.
setAlpha( 200 );
124 m_routeColorHighlighted.
setAlpha( 200 );
125 m_routeColorAlternative.
setAlpha( 200 );
128GeoDataFolder *RoutingManagerPrivate::createFolderFromRequest(
const RouteRequest &request)
130 GeoDataFolder* result =
new GeoDataFolder;
132 result->setName(QStringLiteral(
"Route Request"));
134 for (
int i = 0; i < request.size(); ++i) {
135 GeoDataPlacemark *placemark =
new GeoDataPlacemark(request[i]);
136 result->append( placemark );
144 QString const subdir =
"routing";
145 QDir dir( MarbleDirs::localPath() );
146 if ( !
dir.exists( subdir ) ) {
147 if ( !
dir.mkdir( subdir ) ) {
148 mDebug() <<
"Unable to create dir " <<
dir.absoluteFilePath( subdir );
149 return dir.absolutePath();
153 if ( !
dir.cd( subdir ) ) {
154 mDebug() <<
"Cannot change into " <<
dir.absoluteFilePath( subdir );
157 return dir.absoluteFilePath( name );
160void RoutingManagerPrivate::saveRoute(
const QString &filename)
163 writer.setDocumentType( kml::kmlTag_nameSpaceOgc22 );
166 QFile file( filename );
169 mDebug() <<
"Cannot write to " << file.fileName();
173 GeoDataDocument container;
174 container.setName(QStringLiteral(
"Route"));
175 GeoDataFolder *request = createFolderFromRequest(m_routeRequest);
177 container.append( request );
180 const GeoDataDocument *route = m_alternativeRoutesModel.currentRoute();
182 container.append(
new GeoDataDocument( *route ) );
185 if ( !writer.write( &file, &container ) ) {
186 mDebug() <<
"Can not write route state to " << file.fileName();
191void RoutingManagerPrivate::loadRoute(
const QString &filename)
193 QFile file( filename );
195 mDebug() <<
"Can not read route from " << file.fileName();
199 GeoDataParser parser( GeoData_KML );
200 if ( !parser.read( &file ) ) {
201 mDebug() <<
"Could not parse file: " << parser.errorString();
205 GeoDocument *doc = parser.releaseDocument();
209 GeoDataDocument* container =
dynamic_cast<GeoDataDocument*
>( doc );
210 if (container && !container->isEmpty()) {
211 GeoDataFolder* viaPoints =
dynamic_cast<GeoDataFolder*
>( &container->first() );
215 for(
int i=0; i<placemarks.
size(); ++i ) {
216 if ( i < m_routeRequest.size() ) {
217 m_routeRequest[i] = *placemarks[i];
219 m_routeRequest.
append( *placemarks[i] );
224 const int viaPoints_needed = placemarks.
size();
225 for (
int i = m_routeRequest.size(); i > viaPoints_needed; --i ) {
226 m_routeRequest.remove( viaPoints_needed );
229 mDebug() <<
"Expected a GeoDataDocument with at least one child, didn't get one though";
233 if ( container && container->size() == 2 ) {
234 GeoDataDocument* route =
dynamic_cast<GeoDataDocument*
>(&container->last());
237 m_alternativeRoutesModel.clear();
238 m_alternativeRoutesModel.addRoute(
new GeoDataDocument(*route), AlternativeRoutesModel::Instant );
239 m_alternativeRoutesModel.setCurrentRoute( 0 );
240 m_state = RoutingManager::Retrieved;
241 emit q->stateChanged( m_state );
242 emit q->routeRetrieved( route );
244 mDebug() <<
"Expected a GeoDataDocument child, didn't get one though";
251 mDebug() <<
"File " << filename <<
" is not a valid Marble route .kml file";
253 m_treeModel->addDocument( container );
260 d(new RoutingManagerPrivate(marbleModel, this))
265 this,
SLOT(routingFinished()) );
268 connect( &d->m_routingModel,
SIGNAL(deviatedFromRoute(
bool)),
269 this,
SLOT(recalculateRoute(
bool)) );
279 return &d->m_profilesModel;
284 return &d->m_routingModel;
289 return &d->m_routingModel;
294 return &d->m_routeRequest;
297RoutingManager::State RoutingManager::state()
const
304 d->m_haveRoute =
false;
307 for (
int i = 0;
i < d->m_routeRequest.
size(); ++
i ) {
314 d->m_alternativeRoutesModel.newRequest( &d->m_routeRequest );
316 d->m_state = RoutingManager::Downloading;
317 d->m_runnerManager.retrieveRoute( &d->m_routeRequest );
319 d->m_routingModel.clear();
320 d->m_state = RoutingManager::Retrieved;
328 m_alternativeRoutesModel.addRoute( route );
331 if ( !m_haveRoute ) {
332 m_haveRoute = route !=
nullptr;
335 emit q->routeRetrieved( route );
338void RoutingManagerPrivate::routingFinished()
340 m_state = RoutingManager::Retrieved;
341 emit q->stateChanged( m_state );
344void RoutingManagerPrivate::setCurrentRoute(
const GeoDataDocument *document)
347 RouteSegment outline;
349 if (document !=
nullptr) {
350 const auto folders = document->folderList();
351 for (
const auto folder : folders) {
352 for (
const auto placemark : folder->placemarkList()) {
353 importPlacemark(outline, segments, placemark);
357 for (
const auto placemark : document->placemarkList()) {
358 importPlacemark(outline, segments, placemark);
367 if ( m_routeRequest.size() > 1 && segments.
size() > 1 ) {
369 for (
int j = 0; j < m_routeRequest.size(); ++j ) {
370 QPair<int, qreal> minimum( -1, -1.0 );
372 for (
int i = index; i < segments.
size(); ++i ) {
373 const RouteSegment &segment = segments[i];
374 GeoDataCoordinates closest;
375 const qreal
distance = segment.distanceTo( m_routeRequest.at( j ), closest, closest );
376 if ( minimum.first < 0 || distance < minimum.second ) {
383 if ( minimum.first >= 0 ) {
384 index = minimum.first;
385 Maneuver viaPoint = segments[ minimum.first ].maneuver();
386 viaPoint.setWaypoint( m_routeRequest.at( viaIndex ), viaIndex );
387 segments[ minimum.first ].setManeuver( viaPoint );
394 if ( segments.
size() > 0 ) {
395 for(
const RouteSegment &segment: segments ) {
396 route.addRouteSegment( segment );
400 m_routingModel.setRoute( route );
403void RoutingManagerPrivate::importPlacemark( RouteSegment &outline,
QVector<RouteSegment> &segments,
const GeoDataPlacemark *placemark )
405 const GeoDataGeometry* geometry = placemark->geometry();
406 const GeoDataLineString* lineString =
dynamic_cast<const GeoDataLineString*
>( geometry );
408 RouteSegment segment;
409 bool isOutline =
true;
410 if ( !blacklist.
contains( placemark->name() ) ) {
413 maneuver.setInstructionText( placemark->name() );
414 maneuver.setPosition( lineString->at( 0 ) );
416 if (placemark->extendedData().contains(QStringLiteral(
"turnType"))) {
417 QVariant turnType = placemark->extendedData().
value(QStringLiteral(
"turnType")).value();
421 maneuver.setDirection( Maneuver::Direction( turnType.
toInt() ) );
424 if (placemark->extendedData().contains(QStringLiteral(
"roadName"))) {
425 QVariant roadName = placemark->extendedData().
value(QStringLiteral(
"roadName")).value();
426 maneuver.setRoadName( roadName.
toString() );
429 segment.setManeuver( maneuver );
435 segment.setPath( *lineString );
447 return &d->m_alternativeRoutesModel;
452 d->saveRoute( d->stateFile() );
457 d->saveRoute( filename );
462 d->loadRoute( filename );
467 RoutingProfile profile;
468 RoutingProfilesModel::ProfileTemplate
tpl = RoutingProfilesModel::CarFastestTemplate;
469 switch ( transportType ) {
470 case RoutingProfile::Motorcar:
471 tpl = RoutingProfilesModel::CarFastestTemplate;
472 profile.setName(QStringLiteral(
"Motorcar"));
473 profile.setTransportType( RoutingProfile::Motorcar );
475 case RoutingProfile::Bicycle:
476 tpl = RoutingProfilesModel::BicycleTemplate;
477 profile.setName(QStringLiteral(
"Bicycle"));
478 profile.setTransportType( RoutingProfile::Bicycle );
480 case RoutingProfile::Pedestrian:
481 tpl = RoutingProfilesModel::PedestrianTemplate;
482 profile.setName(QStringLiteral(
"Pedestrian"));
483 profile.setTransportType( RoutingProfile::Pedestrian );
488 if ( plugin->supportsTemplate(
tpl ) ) {
489 profile.pluginSettings()[plugin->nameId()] = plugin->templateSettings(
tpl );
498 d->loadRoute( d->stateFile() );
503 if ( d->m_guidanceModeEnabled == enabled ) {
507 d->m_guidanceModeEnabled = enabled;
510 d->saveRoute( d->stateFile(
"guidance.kml" ) );
512 if ( d->m_guidanceModeWarning ) {
514 QLatin1Char(
' ') +
tr(
"Road construction, weather and other unforeseen variables can result in the suggested route not to be the most expedient or safest route to your destination.") +
522 const bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
523 messageBox->resize( 380,
smallScreen ? 400 : 240 );
525 if ( !messageBox.isNull() ) {
526 d->m_guidanceModeWarning =
showAgain->isChecked();
531 d->loadRoute( d->stateFile(
"guidance.kml" ) );
535 if ( !positionProvider && enabled ) {
537 if ( plugins.
size() > 0 ) {
538 positionProvider = plugins.
first()->newInstance();
540 d->m_positionTracking->setPositionProviderPlugin( positionProvider );
541 d->m_shutdownPositionTracking =
true;
542 }
else if ( positionProvider && !enabled && d->m_shutdownPositionTracking ) {
543 d->m_shutdownPositionTracking =
false;
544 d->m_positionTracking->setPositionProviderPlugin(
nullptr );
547 emit guidanceModeEnabledChanged( d->m_guidanceModeEnabled );
550void RoutingManagerPrivate::recalculateRoute(
bool deviated )
552 if ( m_guidanceModeEnabled && deviated ) {
553 for (
int i=m_routeRequest.size()-3; i>=0; --i ) {
554 if ( m_routeRequest.visited( i ) ) {
555 m_routeRequest.remove( i );
559 if ( m_routeRequest.size() == 2 && m_routeRequest.visited( 0 ) && !m_routeRequest.visited( 1 ) ) {
560 m_routeRequest.setPosition( 0, m_positionTracking->currentLocation(),
QObject::tr(
"Current Location" ) );
562 }
else if ( m_routeRequest.size() != 0 && !m_routeRequest.visited( m_routeRequest.size()-1 ) ) {
563 m_routeRequest.insert( 0, m_positionTracking->currentLocation(),
QObject::tr(
"Current Location" ) );
571 d->m_routeRequest.reverse();
577 d->m_routeRequest.
clear();
583 d->m_guidanceModeWarning = show;
588 return d->m_guidanceModeWarning;
593 d->m_lastOpenPath = path;
598 return d->m_lastOpenPath;
603 d->m_lastSavePath = path;
608 return d->m_lastSavePath;
613 d->m_routeColorStandard = color;
618 return d->m_routeColorStandard;
623 d->m_routeColorHighlighted = color;
628 return d->m_routeColorHighlighted;
633 d->m_routeColorAlternative = color;
638 return d->m_routeColorAlternative;
641bool RoutingManager::guidanceModeEnabled()
const
643 return d->m_guidanceModeEnabled;
648#include "moc_RoutingManager.cpp"
This file contains the headers for MarbleModel.
bool isValid() const
Returns.
A container for Features, Styles and in the future Schemas.
The data model (not based on QAbstractModel) for a MarbleWidget.
QList< const PositionProviderPlugin * > positionProviderPlugins() const
Returns all available PositionProviderPlugins.
QList< RoutingRunnerPlugin * > routingRunnerPlugins() const
Returns all routing runner plugins.
The abstract class that provides position information.
Points to be included in a route.
int size() const
Number of points in the route.
void clear()
Remove all elements.
GeoDataCoordinates at(int index) const
Accessor for the n-th position.
QString lastOpenPath() const
Return last directory the user opened a route from.
void setGuidanceModeEnabled(bool enabled)
Toggle turn by turn navigation mode.
void clearRoute()
Clear all via points.
~RoutingManager() override
Destructor.
RoutingProfile defaultProfile(RoutingProfile::TransportType transportType) const
Generates a routing profile with default settings for the given transport type.
void loadRoute(const QString &filename)
Opens the given filename (kml format) and loads the route contained in it.
QColor routeColorStandard() const
Get color for standard route rendering.
void setRouteColorAlternative(const QColor &color)
Set color for alternative route rendering.
RoutingModel * routingModel()
Provides access to the routing model which contains a list of routing instructions describing steps t...
void setShowGuidanceModeStartupWarning(bool show)
Set whether a warning message should be shown to the user before starting guidance mode.
RouteRequest * routeRequest()
Returns the current route request.
RoutingProfilesModel * profilesModel()
Provides access to the model which contains all possible routing profiles.
AlternativeRoutesModel * alternativeRoutesModel()
Provides access to the model which contains a list of alternative routes.
void setRouteColorStandard(const QColor &color)
Set color for standard route rendering.
void setRouteColorHighlighted(const QColor &color)
Set color for highlighted route rendering.
void stateChanged(RoutingManager::State newState)
Directions and waypoints for the given route are being downloaded or have been retrieved – newState t...
bool showGuidanceModeStartupWarning() const
Returns true (default) if a warning is shown to the user when starting guidance mode.
void setLastSavePath(const QString &path)
Set last directory the user saved a route to.
void retrieveRoute()
Retrieve a route suiting the routeRequest.
void setLastOpenPath(const QString &path)
Set last directory the user opened a route from.
void saveRoute(const QString &filename) const
Saves the current route to the file with the given filename.
QColor routeColorHighlighted() const
Get color for highlighted route rendering.
QColor routeColorAlternative() const
Get color for alternative route rendering.
void reverseRoute()
Reverse the previously requested route, i.e.
void writeSettings() const
Saves the current route request and the current route to disk.
QString lastSavePath() const
Return last directory the user saved a route to.
void readSettings()
Restores a previously saved route request and route from disk, if any.
A plugin for Marble to execute a routing task.
KIOCORE_EXPORT QString dir(const QString &fileClass)
Binds a QML item to a specific geodetic location in screen coordinates.
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
void append(QList< T > &&value)
bool isEmpty() const const
void push_back(parameter_type value)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
int toInt(bool *ok) const const
QString toString() const const