Marble

Navigation.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2011 Dennis Nienhüser <nienhueser@kde.org>
4//
5
6#include "Navigation.h"
7
8#include "Planet.h"
9#include "MarbleModel.h"
10#include "MarbleQuickItem.h"
11#include "routing/Route.h"
12#include "routing/RoutingManager.h"
13#include "routing/RoutingModel.h"
14#include "PositionTracking.h"
15#include "AutoNavigation.h"
16#include "routing/VoiceNavigationModel.h"
17#include "ViewportParams.h"
18#include "GeoDataAccuracy.h"
19
20namespace Marble {
21
22class NavigationPrivate
23{
24public:
25 NavigationPrivate();
26
27 MarbleQuickItem * m_marbleQuickItem;
28
29 bool m_muted;
30
31 RouteSegment m_currentSegment;
32
33 AutoNavigation* m_autoNavigation;
34
35 VoiceNavigationModel m_voiceNavigation;
36
37 qreal m_nextInstructionDistance;
38
39 qreal m_destinationDistance;
40
41 double m_screenAccuracy;
42 QPointF m_screenPosition;
43
44 RouteSegment nextRouteSegment() const;
45
46 void updateNextInstructionDistance( const Route &route );
47
48 MarbleModel * model() const;
49
50 QPointF positionOnRoute() const;
51 QPointF currentPosition() const;
52
53 RouteSegment m_secondLastSegment;
54 RouteSegment m_lastSegment;
55
56};
57
58NavigationPrivate::NavigationPrivate() :
59 m_marbleQuickItem( nullptr ), m_muted( false ), m_autoNavigation( nullptr ), m_nextInstructionDistance( 0.0 ),
60 m_destinationDistance( 0.0 ), m_screenAccuracy(0)
61{
62 // nothing to do
63}
64
65void NavigationPrivate::updateNextInstructionDistance( const Route &route )
66{
67 const GeoDataCoordinates position = route.position();
68 const GeoDataCoordinates interpolated = route.positionOnRoute();
69 const GeoDataCoordinates onRoute = route.currentWaypoint();
70
71 qreal planetRadius = 0;
72 if (model()){
73 planetRadius = model()->planet()->radius();
74 }
75 qreal distance = planetRadius * (position.sphericalDistanceTo(interpolated) + interpolated.sphericalDistanceTo(onRoute));
76 qreal remaining = 0.0;
77 const RouteSegment &segment = route.currentSegment();
78 for ( int i=0; i<segment.path().size(); ++i ) {
79 if ( segment.path()[i] == onRoute ) {
80 distance += segment.path().length( planetRadius, i );
81 break;
82 }
83 }
84
85 bool upcoming = false;
86 for ( int i=0; i<route.size(); ++i ) {
87 const RouteSegment &segment = route.at( i );
88
89 if ( upcoming ) {
90 remaining += segment.path().length( planetRadius );
91 }
92
93 if ( segment == route.currentSegment() ) {
94 upcoming = true;
95 }
96 }
97
98 m_nextInstructionDistance = distance;
99 m_destinationDistance = distance + remaining;
100}
101
102MarbleModel * NavigationPrivate::model() const
103{
104 return m_marbleQuickItem ? m_marbleQuickItem->model() : nullptr;
105}
106
107RouteSegment NavigationPrivate::nextRouteSegment() const
108{
109 // Not using m_currentSegment on purpose
110 return m_marbleQuickItem ? model()->routingManager()->routingModel()->route().currentSegment().nextRouteSegment() : RouteSegment();
111}
112
113Navigation::Navigation( QObject* parent) :
114 QObject( parent ), d( new NavigationPrivate )
115{
116 connect( &d->m_voiceNavigation, SIGNAL(instructionChanged()), this, SIGNAL(voiceNavigationAnnouncementChanged()) );
117}
118
119Navigation::~Navigation()
120{
121 delete d;
122}
123
124
125bool Navigation::guidanceModeEnabled() const
126{
127 return d->m_marbleQuickItem ? d->model()->routingManager()->guidanceModeEnabled() : false;
128}
129
130void Navigation::setGuidanceModeEnabled( bool enabled )
131{
132 if ( d->m_marbleQuickItem ) {
133 d->model()->routingManager()->setGuidanceModeEnabled( enabled );
134 d->m_autoNavigation->setAutoZoom( enabled );
135 d->m_autoNavigation->setRecenter( enabled ? AutoNavigation::RecenterOnBorder : AutoNavigation::DontRecenter );
136
137 if ( enabled && !d->m_muted ) {
138 //d->m_audio.announceStart();
139 }
140 }
141}
142
143bool Navigation::muted() const
144{
145 return d->m_muted;
146}
147
148void Navigation::setMuted(bool enabled)
149{
150 d->m_muted = enabled;
151}
152
153QString Navigation::nextInstructionText() const
154{
155 return d->nextRouteSegment().maneuver().instructionText();
156}
157
158QString Navigation::nextRoad() const
159{
160 return d->nextRouteSegment().maneuver().roadName();
161}
162
163QString Navigation::nextInstructionImage() const
164{
165 switch ( d->nextRouteSegment().maneuver().direction() ) {
166 case Maneuver::Continue: return QStringLiteral("qrc:/marble/turn-continue.svg");
167 case Maneuver::Merge: return QStringLiteral("qrc:/marble/turn-merge.svg");
168 case Maneuver::Straight: return QStringLiteral("qrc:/marble/turn-continue.svg");
169 case Maneuver::SlightRight: return QStringLiteral("qrc:/marble/turn-slight-right.svg");
170 case Maneuver::Right: return QStringLiteral("qrc:/marble/turn-right.svg");
171 case Maneuver::SharpRight: return QStringLiteral("qrc:/marble/turn-sharp-right.svg");
172 case Maneuver::TurnAround: return QStringLiteral("qrc:/marble/turn-around.svg");
173 case Maneuver::SharpLeft: return QStringLiteral("qrc:/marble/turn-sharp-left.svg");
174 case Maneuver::Left: return QStringLiteral("qrc:/marble/turn-left.svg");
175 case Maneuver::SlightLeft: return QStringLiteral("qrc:/marble/turn-slight-left.svg");
176 case Maneuver::RoundaboutFirstExit: return QStringLiteral("qrc:/marble/turn-roundabout-first.svg");
177 case Maneuver::RoundaboutSecondExit: return QStringLiteral("qrc:/marble/turn-roundabout-second.svg");
178 case Maneuver::RoundaboutThirdExit: return QStringLiteral("qrc:/marble/turn-roundabout-third.svg");
179 case Maneuver::RoundaboutExit: return QStringLiteral("qrc:/marble/turn-roundabout-far.svg");
180 case Maneuver::ExitLeft: return QStringLiteral("qrc:/marble/turn-exit-left.svg");
181 case Maneuver::ExitRight: return QStringLiteral("qrc:/marble/turn-exit-right.svg");
182 case Maneuver::Unknown:
183 default:
184 return QString();
185 }
186}
187
188qreal Navigation::nextInstructionDistance() const
189{
190 return d->m_nextInstructionDistance;
191}
192
193qreal Navigation::destinationDistance() const
194{
195 return d->m_destinationDistance;
196}
197
198QString Navigation::voiceNavigationAnnouncement() const
199{
200 return d->m_voiceNavigation.instruction();
201}
202
203QString Navigation::speaker() const
204{
205 return d->m_voiceNavigation.speaker();
206}
207
208void Navigation::setSpeaker( const QString &speaker )
209{
210 d->m_voiceNavigation.setSpeaker( speaker );
211}
212
213bool Navigation::deviated() const
214{
215 if ( d->m_marbleQuickItem ) {
216 RoutingModel const * routingModel = d->model()->routingManager()->routingModel();
217 return routingModel->deviatedFromRoute();
218 }
219
220 return true;
221}
222
223MarbleQuickItem *Navigation::marbleQuickItem() const
224{
225 return d->m_marbleQuickItem;
226}
227
228QPointF NavigationPrivate::positionOnRoute() const
229{
230 RoutingModel const * routingModel = model()->routingManager()->routingModel();
231 GeoDataCoordinates coordinates = routingModel->route().positionOnRoute();
232 qreal x = 0;
233 qreal y = 0;
234 if (coordinates.isValid()) {
235 m_marbleQuickItem->map()->viewport()->screenCoordinates(coordinates, x, y);
236 }
237 return QPointF(x,y);
238}
239
240QPointF NavigationPrivate::currentPosition() const
241{
242 GeoDataCoordinates coordinates = model()->positionTracking()->currentLocation();
243 qreal x = 0;
244 qreal y = 0;
245 m_marbleQuickItem->map()->viewport()->screenCoordinates(coordinates, x, y);
246 return QPointF(x,y);
247}
248
249QPointF Navigation::screenPosition() const
250{
251 return d->m_screenPosition;
252}
253
254double Navigation::screenAccuracy() const
255{
256 return d->m_screenAccuracy;
257}
258
259void Navigation::setMarbleQuickItem(MarbleQuickItem *marbleQuickItem)
260{
261 if ( d->m_marbleQuickItem == marbleQuickItem) {
262 return;
263 }
264
265 if (d->m_marbleQuickItem) {
266 disconnect( d->model()->routingManager()->routingModel(),
267 SIGNAL(positionChanged()), this, SLOT(update()) );
268 disconnect( d->m_autoNavigation, SIGNAL(zoomIn(FlyToMode)),
269 d->m_marbleQuickItem, SLOT(zoomIn()) );
270 disconnect( d->m_autoNavigation, SIGNAL(zoomOut(FlyToMode)),
271 d->m_marbleQuickItem, SLOT(zoomOut()) );
272 disconnect( d->m_autoNavigation, SIGNAL(centerOn(GeoDataCoordinates,bool)),
273 d->m_marbleQuickItem, SLOT(centerOn(GeoDataCoordinates)) );
274
275 disconnect( d->m_marbleQuickItem, SIGNAL(visibleLatLonAltBoxChanged()),
276 d->m_autoNavigation, SLOT(inhibitAutoAdjustments()) );
277 }
278
279 d->m_marbleQuickItem = marbleQuickItem;
280 if ( d->m_marbleQuickItem ) {
281 d->model()->routingManager()->setShowGuidanceModeStartupWarning( false );
282 connect( d->model()->routingManager()->routingModel(),
283 SIGNAL(positionChanged()), this, SLOT(update()) );
284 connect( d->model()->routingManager()->routingModel(),
285 SIGNAL(deviatedFromRoute(bool)), this, SIGNAL(deviationChanged()) );
286
287 delete d->m_autoNavigation;
288 d->m_autoNavigation = new AutoNavigation( d->model(), d->m_marbleQuickItem->map()->viewport(), this );
289 connect( d->m_autoNavigation, SIGNAL(zoomIn(FlyToMode)),
290 d->m_marbleQuickItem, SLOT(zoomIn()) );
291 connect( d->m_autoNavigation, SIGNAL(zoomOut(FlyToMode)),
292 d->m_marbleQuickItem, SLOT(zoomOut()) );
293 connect( d->m_autoNavigation, SIGNAL(centerOn(GeoDataCoordinates,bool)),
294 d->m_marbleQuickItem, SLOT(centerOn(GeoDataCoordinates)) );
295
296 connect( d->m_marbleQuickItem, SIGNAL(visibleLatLonAltBoxChanged()),
297 d->m_autoNavigation, SLOT(inhibitAutoAdjustments()) );
298
299 connect( d->m_marbleQuickItem, SIGNAL(visibleLatLonAltBoxChanged()),
300 this, SLOT(updateScreenPosition()) );
301 connect( d->model()->positionTracking(), SIGNAL(gpsLocation(GeoDataCoordinates,qreal)),
302 this, SLOT(updateScreenPosition()) );
303 connect( d->model()->positionTracking(), SIGNAL(statusChanged(PositionProviderStatus)),
304 this, SLOT(updateScreenPosition()) );
305
306 }
307 emit marbleQuickItemChanged(marbleQuickItem);
308}
309
310void Navigation::update()
311{
312 if (!d->model()) {
313 return;
314 }
315
316 RoutingModel const * routingModel = d->model()->routingManager()->routingModel();
317 d->updateNextInstructionDistance( routingModel->route() );
318 emit nextInstructionDistanceChanged();
319 emit destinationDistanceChanged();
320 RouteSegment segment = routingModel->route().currentSegment();
321
322 if ( !d->m_muted ) {
323 d->m_voiceNavigation.update( routingModel->route(), d->m_nextInstructionDistance, d->m_destinationDistance, routingModel->deviatedFromRoute() );
324 }
325 if ( segment != d->m_currentSegment ) {
326 d->m_currentSegment = segment;
327 emit nextInstructionTextChanged();
328 emit nextInstructionImageChanged();
329 emit nextRoadChanged();
330 }
331
332 updateScreenPosition();
333}
334
335void Navigation::updateScreenPosition()
336{
337 if(d->m_marbleQuickItem) {
338 double distanceMeter = d->model()->positionTracking()->accuracy().horizontal;
339 d->m_screenAccuracy = distanceMeter * d->m_marbleQuickItem->map()->radius() / d->model()->planetRadius();
340 emit screenAccuracyChanged();
341
342 d->m_screenPosition = deviated() ? d->currentPosition() : d->positionOnRoute();
343 emit screenPositionChanged();
344 }
345}
346
347}
348
349#include "moc_Navigation.cpp"
This file contains the headers for MarbleModel.
This file contains the headers for ViewportParams.
void update(Part *part, const QByteArray &data, qint64 dataSize)
const QList< QKeySequence > & zoomIn()
const QList< QKeySequence > & zoomOut()
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)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:16 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.