6#include "RoutingManager.h"
8#include "AlternativeRoutesModel.h"
9#include "GeoDataData.h"
10#include "GeoDataDocument.h"
11#include "GeoDataExtendedData.h"
12#include "GeoDataFolder.h"
13#include "GeoDataParser.h"
14#include "GeoDataPlacemark.h"
15#include "GeoDataTreeModel.h"
17#include "MarbleColors.h"
18#include "MarbleDebug.h"
19#include "MarbleDirs.h"
21#include "PluginManager.h"
22#include "PositionProviderPlugin.h"
23#include "PositionTracking.h"
25#include "RouteRequest.h"
26#include "RoutingModel.h"
27#include "RoutingProfilesModel.h"
28#include "RoutingRunnerManager.h"
29#include "RoutingRunnerPlugin.h"
30#include <KmlElementDictionary.h>
35#include <QMutexLocker>
40class RoutingManagerPrivate
43 RoutingManager *
const q;
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);
87 static QString stateFile(
const QString &name = QStringLiteral(
"route.kml"));
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,
QList<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)
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)
124 m_routeColorHighlighted.
setAlpha(200);
125 m_routeColorAlternative.
setAlpha(200);
128GeoDataFolder *RoutingManagerPrivate::createFolderFromRequest(
const RouteRequest &request)
130 auto result =
new GeoDataFolder;
132 result->setName(QStringLiteral(
"Route Request"));
134 for (
int i = 0; i < request.size(); ++i) {
135 auto placemark =
new GeoDataPlacemark(request[i]);
136 result->append(placemark);
144 QString const subdir = QStringLiteral(
"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)
166 QFile file(filename);
168 mDebug() <<
"Cannot write to " << file.fileName();
172 GeoDataDocument container;
173 container.setName(QStringLiteral(
"Route"));
174 GeoDataFolder *request = createFolderFromRequest(m_routeRequest);
176 container.append(request);
179 const GeoDataDocument *route = m_alternativeRoutesModel.currentRoute();
181 container.append(
new GeoDataDocument(*route));
184 if (!writer.write(&file, &container)) {
185 mDebug() <<
"Can not write route state to " << file.fileName();
190void RoutingManagerPrivate::loadRoute(
const QString &filename)
192 QFile file(filename);
194 mDebug() <<
"Can not read route from " << file.fileName();
198 GeoDataParser parser(GeoData_KML);
199 if (!parser.read(&file)) {
200 mDebug() <<
"Could not parse file: " << parser.errorString();
204 GeoDocument *doc = parser.releaseDocument();
208 auto container =
dynamic_cast<GeoDataDocument *
>(doc);
209 if (container && !container->isEmpty()) {
210 auto viaPoints =
dynamic_cast<GeoDataFolder *
>(&container->first());
214 for (
int i = 0; i < placemarks.
size(); ++i) {
215 if (i < m_routeRequest.size()) {
216 m_routeRequest[i] = *placemarks[i];
218 m_routeRequest.append(*placemarks[i]);
223 const int viaPoints_needed = placemarks.
size();
224 for (
int i = m_routeRequest.size(); i > viaPoints_needed; --i) {
225 m_routeRequest.remove(viaPoints_needed);
228 mDebug() <<
"Expected a GeoDataDocument with at least one child, didn't get one though";
232 if (container && container->size() == 2) {
233 auto route =
dynamic_cast<GeoDataDocument *
>(&container->last());
236 m_alternativeRoutesModel.clear();
237 m_alternativeRoutesModel.addRoute(
new GeoDataDocument(*route), AlternativeRoutesModel::Instant);
238 m_alternativeRoutesModel.setCurrentRoute(0);
239 m_state = RoutingManager::Retrieved;
240 Q_EMIT q->stateChanged(m_state);
241 Q_EMIT q->routeRetrieved(route);
243 mDebug() <<
"Expected a GeoDataDocument child, didn't get one though";
250 mDebug() <<
"File " << filename <<
" is not a valid Marble route .kml file";
252 m_treeModel->addDocument(container);
259 , d(new RoutingManagerPrivate(marbleModel, this))
262 connect(&d->m_runnerManager, SIGNAL(routingFinished()),
this, SLOT(routingFinished()));
264 connect(&d->m_routingModel, SIGNAL(deviatedFromRoute(
bool)),
this, SLOT(recalculateRoute(
bool)));
274 return &d->m_profilesModel;
279 return &d->m_routingModel;
284 return &d->m_routingModel;
289 return &d->m_routeRequest;
292RoutingManager::State RoutingManager::state()
const
299 d->m_haveRoute =
false;
302 for (
int i = 0; i < d->m_routeRequest.
size(); ++i) {
309 d->m_alternativeRoutesModel.newRequest(&d->m_routeRequest);
311 d->m_state = RoutingManager::Downloading;
312 d->m_runnerManager.retrieveRoute(&d->m_routeRequest);
314 d->m_routingModel.clear();
315 d->m_state = RoutingManager::Retrieved;
323 m_alternativeRoutesModel.addRoute(route);
327 m_haveRoute = route !=
nullptr;
330 Q_EMIT q->routeRetrieved(route);
333void RoutingManagerPrivate::routingFinished()
335 m_state = RoutingManager::Retrieved;
336 Q_EMIT q->stateChanged(m_state);
339void RoutingManagerPrivate::setCurrentRoute(
const GeoDataDocument *document)
342 RouteSegment outline;
344 if (document !=
nullptr) {
345 const auto folders = document->folderList();
346 for (
const auto folder : folders) {
347 for (
const auto placemark : folder->placemarkList()) {
348 importPlacemark(outline, segments, placemark);
352 for (
const auto placemark : document->placemarkList()) {
353 importPlacemark(outline, segments, placemark);
362 if (m_routeRequest.size() > 1 && segments.
size() > 1) {
364 for (
int j = 0; j < m_routeRequest.size(); ++j) {
365 QPair<int, qreal> minimum(-1, -1.0);
367 for (
int i = index; i < segments.
size(); ++i) {
368 const RouteSegment &segment = segments[i];
369 GeoDataCoordinates closest;
370 const qreal
distance = segment.distanceTo(m_routeRequest.at(j), closest, closest);
371 if (minimum.first < 0 || distance < minimum.second) {
378 if (minimum.first >= 0) {
379 index = minimum.first;
380 Maneuver viaPoint = segments[minimum.first].maneuver();
381 viaPoint.setWaypoint(m_routeRequest.at(viaIndex), viaIndex);
382 segments[minimum.first].setManeuver(viaPoint);
390 for (
const RouteSegment &segment : std::as_const(segments)) {
391 route.addRouteSegment(segment);
395 m_routingModel.setRoute(route);
398void RoutingManagerPrivate::importPlacemark(RouteSegment &outline,
QList<RouteSegment> &segments,
const GeoDataPlacemark *placemark)
400 const GeoDataGeometry *geometry = placemark->geometry();
401 const auto lineString =
dynamic_cast<const GeoDataLineString *
>(geometry);
403 RouteSegment segment;
404 bool isOutline =
true;
405 if (!blacklist.
contains(placemark->name())) {
408 maneuver.setInstructionText(placemark->name());
409 maneuver.setPosition(lineString->at(0));
411 if (placemark->extendedData().contains(QStringLiteral(
"turnType"))) {
412 QVariant turnType = placemark->extendedData().
value(QStringLiteral(
"turnType")).value();
416 maneuver.setDirection(Maneuver::Direction(turnType.
toInt()));
419 if (placemark->extendedData().contains(QStringLiteral(
"roadName"))) {
420 QVariant roadName = placemark->extendedData().
value(QStringLiteral(
"roadName")).value();
421 maneuver.setRoadName(roadName.
toString());
424 segment.setManeuver(maneuver);
430 segment.setPath(*lineString);
442 return &d->m_alternativeRoutesModel;
447 d->saveRoute(d->stateFile());
452 d->saveRoute(filename);
457 d->loadRoute(filename);
462 RoutingProfile profile;
463 RoutingProfilesModel::ProfileTemplate tpl = RoutingProfilesModel::CarFastestTemplate;
464 switch (transportType) {
465 case RoutingProfile::Motorcar:
466 tpl = RoutingProfilesModel::CarFastestTemplate;
467 profile.setName(QStringLiteral(
"Motorcar"));
468 profile.setTransportType(RoutingProfile::Motorcar);
470 case RoutingProfile::Bicycle:
471 tpl = RoutingProfilesModel::BicycleTemplate;
472 profile.setName(QStringLiteral(
"Bicycle"));
473 profile.setTransportType(RoutingProfile::Bicycle);
475 case RoutingProfile::Pedestrian:
476 tpl = RoutingProfilesModel::PedestrianTemplate;
477 profile.setName(QStringLiteral(
"Pedestrian"));
478 profile.setTransportType(RoutingProfile::Pedestrian);
483 if (plugin->supportsTemplate(tpl)) {
484 profile.pluginSettings()[plugin->nameId()] = plugin->templateSettings(tpl);
493 d->loadRoute(d->stateFile());
498 if (d->m_guidanceModeEnabled == enabled) {
502 d->m_guidanceModeEnabled = enabled;
505 d->saveRoute(d->stateFile(QStringLiteral(
"guidance.kml")));
507 if (d->m_guidanceModeWarning) {
509 +
tr(
"Road construction, weather and other unforeseen variables can result in the suggested route not to be the most expedient or safest route "
510 "to your destination.")
512 +
tr(
"The Marble development team wishes you a pleasant and safe journey.") +
QLatin1StringView(
"</p>");
515 showAgain->setChecked(
true);
516 showAgain->blockSignals(
true);
518 const bool smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
519 messageBox->resize(380, smallScreen ? 400 : 240);
521 if (!messageBox.isNull()) {
522 d->m_guidanceModeWarning = showAgain->isChecked();
527 d->loadRoute(d->stateFile(QStringLiteral(
"guidance.kml")));
531 if (!positionProvider && enabled) {
534 positionProvider = plugins.
first()->newInstance();
536 d->m_positionTracking->setPositionProviderPlugin(positionProvider);
537 d->m_shutdownPositionTracking =
true;
538 }
else if (positionProvider && !enabled && d->m_shutdownPositionTracking) {
539 d->m_shutdownPositionTracking =
false;
540 d->m_positionTracking->setPositionProviderPlugin(
nullptr);
543 Q_EMIT guidanceModeEnabledChanged(d->m_guidanceModeEnabled);
546void RoutingManagerPrivate::recalculateRoute(
bool deviated)
548 if (m_guidanceModeEnabled && deviated) {
549 for (
int i = m_routeRequest.size() - 3; i >= 0; --i) {
550 if (m_routeRequest.visited(i)) {
551 m_routeRequest.remove(i);
555 if (m_routeRequest.size() == 2 && m_routeRequest.visited(0) && !m_routeRequest.visited(1)) {
556 m_routeRequest.setPosition(0, m_positionTracking->currentLocation(),
QObject::tr(
"Current Location"));
558 }
else if (m_routeRequest.size() != 0 && !m_routeRequest.visited(m_routeRequest.size() - 1)) {
559 m_routeRequest.insert(0, m_positionTracking->currentLocation(),
QObject::tr(
"Current Location"));
567 d->m_routeRequest.reverse();
573 d->m_routeRequest.
clear();
579 d->m_guidanceModeWarning = show;
584 return d->m_guidanceModeWarning;
589 d->m_lastOpenPath = path;
594 return d->m_lastOpenPath;
599 d->m_lastSavePath = path;
604 return d->m_lastSavePath;
609 d->m_routeColorStandard = color;
614 return d->m_routeColorStandard;
619 d->m_routeColorHighlighted = color;
624 return d->m_routeColorHighlighted;
629 d->m_routeColorAlternative = color;
634 return d->m_routeColorAlternative;
637bool RoutingManager::guidanceModeEnabled()
const
639 return d->m_guidanceModeEnabled;
644#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)
bool isEmpty() const const
void push_back(parameter_type value)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString tr(const char *sourceText, const char *disambiguation, int n)
QString fromLatin1(QByteArrayView str)
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
int toInt(bool *ok) const const
QString toString() const const