6#include "RoutingModel.h"
8#include "GeoDataAccuracy.h"
9#include "MarbleGlobal.h"
11#include "PlanetFactory.h"
12#include "PositionTracking.h"
14#include "RouteRequest.h"
22class RoutingModelPrivate
31 explicit RoutingModelPrivate(PositionTracking *positionTracking, RouteRequest *request);
35 PositionTracking *
const m_positionTracking;
36 RouteRequest *
const m_request;
38 RouteDeviation m_deviation;
40 void updateViaPoints(
const GeoDataCoordinates &position);
43RoutingModelPrivate::RoutingModelPrivate(PositionTracking *positionTracking, RouteRequest *request)
44 : m_positionTracking(positionTracking)
51void RoutingModelPrivate::updateViaPoints(
const GeoDataCoordinates &position)
54 qreal
const threshold = 500 / EARTH_RADIUS;
55 for (
int i = 0; i < m_request->size(); ++i) {
56 if (!m_request->visited(i)) {
57 if (position.sphericalDistanceTo(m_request->at(i)) < threshold) {
58 m_request->setVisited(i,
true);
64RoutingModel::RoutingModel(RouteRequest *request, PositionTracking *positionTracking,
QObject *parent)
66 , d(new RoutingModelPrivate(positionTracking, request))
68 connect(d->m_positionTracking, SIGNAL(gpsLocation(GeoDataCoordinates, qreal)),
this, SLOT(updatePosition(GeoDataCoordinates, qreal)));
72 roles.
insert(RoutingModel::TurnTypeIconRole,
"turnTypeIcon");
73 roles.
insert(RoutingModel::LongitudeRole,
"longitude");
74 roles.
insert(RoutingModel::LatitudeRole,
"latitude");
75 d->m_roleNames = roles;
78RoutingModel::~RoutingModel()
83int RoutingModel::rowCount(
const QModelIndex &parent)
const
85 return parent.
isValid() ? 0 : d->m_route.turnPoints().size();
91 return QStringLiteral(
"Instruction");
103 if (index.
row() < d->m_route.turnPoints().size() && index.
column() == 0) {
104 const RouteSegment &segment = d->m_route.at(index.
row());
108 return segment.maneuver().instructionText();
110 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
111 if (segment.maneuver().hasWaypoint()) {
112 int const size = smallScreen ? 64 : 32;
113 return d->m_request->pixmap(segment.maneuver().waypointIndex(), size, size / 4);
116 QPixmap const pixmap = segment.maneuver().directionPixmap();
117 return smallScreen ? pixmap : pixmap.
scaled(32, 32);
120 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
121 int const size = smallScreen ? 64 : 32;
122 return QSize(size, size);
124 case RoutingModel::CoordinateRole:
126 case RoutingModel::LongitudeRole:
127 return {segment.maneuver().position().longitude(GeoDataCoordinates::Degree)};
128 case RoutingModel::LatitudeRole:
129 return {segment.maneuver().position().latitude(GeoDataCoordinates::Degree)};
130 case RoutingModel::TurnTypeIconRole:
131 return segment.maneuver().directionPixmap();
142 return d->m_roleNames;
145void RoutingModel::setRoute(
const Route &route)
148 d->m_deviation = RoutingModelPrivate::Unknown;
152 Q_EMIT currentRouteChanged();
155void RoutingModel::exportGpx(
QIODevice *device)
const
158 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n"
159 "<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" creator=\"Marble\" version=\"1.1\" "
160 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
161 "xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 "
162 "http://www.topografix.com/GPX/1/1/gpx.xsd\">\n"
163 "<metadata>\n <link href=\"http://edu.kde.org/marble\">\n "
164 "<text>Marble Virtual Globe</text>\n </link>\n</metadata>\n"
165 " <rte>\n <name>Route</name>\n");
166 bool hasAltitude =
false;
167 for (
int i = 0; !hasAltitude && i < d->m_route.size(); ++i) {
168 hasAltitude = d->m_route.at(i).maneuver().position().altitude() != 0.0;
170 for (
int i = 0; i < d->m_route.size(); ++i) {
171 const Maneuver &maneuver = d->m_route.at(i).maneuver();
172 qreal lon = maneuver.position().longitude(GeoDataCoordinates::Degree);
173 qreal lat = maneuver.position().latitude(GeoDataCoordinates::Degree);
174 QString const text = maneuver.instructionText();
175 content += QStringLiteral(
" <rtept lat=\"%1\" lon=\"%2\">\n").
arg(lat, 0,
'f', 7).
arg(lon, 0,
'f', 7);
176 content += QStringLiteral(
" <name>%1</name>\n").
arg(text);
178 content += QStringLiteral(
" <ele>%1</ele>\n").
arg(maneuver.position().altitude(), 0,
'f', 2);
180 content += QStringLiteral(
" </rtept>\n");
184 "<trk>\n <name>Route</name>\n <trkseg>\n");
185 GeoDataLineString points = d->m_route.path();
187 for (
int i = 0; !hasAltitude && i < points.size(); ++i) {
188 hasAltitude = points[i].altitude() != 0.0;
190 for (
int i = 0; i < points.size(); ++i) {
191 GeoDataCoordinates
const &point = points[i];
192 qreal lon = point.longitude(GeoDataCoordinates::Degree);
193 qreal lat = point.latitude(GeoDataCoordinates::Degree);
194 content += QStringLiteral(
" <trkpt lat=\"%1\" lon=\"%2\">\n").
arg(lat, 0,
'f', 7).
arg(lon, 0,
'f', 7);
196 content += QStringLiteral(
" <ele>%1</ele>\n").
arg(point.altitude(), 0,
'f', 2);
198 content += QStringLiteral(
" </trkpt>\n");
201 " </trkseg>\n </trk>\n"
207void RoutingModel::clear()
209 d->m_route = Route();
212 Q_EMIT currentRouteChanged();
215int RoutingModel::rightNeighbor(
const GeoDataCoordinates &position, RouteRequest
const *
const route)
const
217 Q_ASSERT(route &&
"Must not pass a null route ");
220 if (route->size() < 3) {
221 return route->size() - 1;
225 GeoDataLineString points = d->m_route.path();
233 for (
int j = 1; j < route->size() - 1; ++j) {
234 qreal minDistance = -1.0;
235 for (
int i = mapping[j - 1]; i < points.size(); ++i) {
236 const qreal
distance = points[i].sphericalDistanceTo(route->at(j));
237 if (minDistance < 0.0 || distance < minDistance) {
245 qreal minWaypointDistance = -1.0;
247 for (
int i = 0; i < points.size(); ++i) {
248 const qreal waypointDistance = points[i].sphericalDistanceTo(position);
249 if (minWaypointDistance < 0.0 || waypointDistance < minWaypointDistance) {
250 minWaypointDistance = waypointDistance;
256 mapping[route->size() - 1] = points.
size() - 1;
260 for (; iter != mapping.
constEnd(); ++iter) {
261 if (iter.value() > waypoint) {
262 int index = iter.key();
263 Q_ASSERT(index >= 0 && index <= route->size());
268 return route->size() - 1;
271void RoutingModel::updatePosition(
const GeoDataCoordinates &location, qreal speed)
273 d->m_route.setPosition(location);
275 d->updateViaPoints(location);
276 const qreal planetRadius = PlanetFactory::construct(QStringLiteral(
"earth")).radius();
277 const qreal
distance = planetRadius *
location.sphericalDistanceTo(d->m_route.positionOnRoute());
278 Q_EMIT positionChanged();
280 qreal deviation = 0.0;
281 if (d->m_positionTracking && d->m_positionTracking->accuracy().vertical > 0.0) {
282 deviation = qMax<qreal>(d->m_positionTracking->accuracy().vertical, d->m_positionTracking->accuracy().horizontal);
284 qreal
const threshold = deviation + qBound(10.0, speed * 10.0, 150.0);
286 RoutingModelPrivate::RouteDeviation
const deviated =
distance < threshold ? RoutingModelPrivate::OnRoute : RoutingModelPrivate::OffRoute;
287 if (d->m_deviation != deviated) {
288 d->m_deviation = deviated;
289 Q_EMIT deviatedFromRoute(deviated == RoutingModelPrivate::OffRoute);
293bool RoutingModel::deviatedFromRoute()
const
295 return d->m_deviation == RoutingModelPrivate::OffRoute;
298const Route &RoutingModel::route()
const
305#include "moc_RoutingModel.cpp"
QVariant location(const QVariant &res)
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)
iterator insert(const Key &key, const T &value)
qint64 write(const QByteArray &data)
const_iterator constBegin() const const
const_iterator constEnd() const const
size_type size() const const
bool isValid() const const
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QString arg(Args &&... args) const const
QByteArray toUtf8() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QVariant fromValue(T &&value)