Marble

Navigation.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2011 Dennis Nienhüser <[email protected]>
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 
20 namespace Marble {
21 
22 class NavigationPrivate
23 {
24 public:
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 
58 NavigationPrivate::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 
65 void 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 
102 MarbleModel * NavigationPrivate::model() const
103 {
104  return m_marbleQuickItem ? m_marbleQuickItem->model() : nullptr;
105 }
106 
107 RouteSegment NavigationPrivate::nextRouteSegment() const
108 {
109  // Not using m_currentSegment on purpose
110  return m_marbleQuickItem ? model()->routingManager()->routingModel()->route().currentSegment().nextRouteSegment() : RouteSegment();
111 }
112 
113 Navigation::Navigation( QObject* parent) :
114  QObject( parent ), d( new NavigationPrivate )
115 {
116  connect( &d->m_voiceNavigation, SIGNAL(instructionChanged()), this, SIGNAL(voiceNavigationAnnouncementChanged()) );
117 }
118 
119 Navigation::~Navigation()
120 {
121  delete d;
122 }
123 
124 
125 bool Navigation::guidanceModeEnabled() const
126 {
127  return d->m_marbleQuickItem ? d->model()->routingManager()->guidanceModeEnabled() : false;
128 }
129 
130 void 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 
143 bool Navigation::muted() const
144 {
145  return d->m_muted;
146 }
147 
148 void Navigation::setMuted(bool enabled)
149 {
150  d->m_muted = enabled;
151 }
152 
153 QString Navigation::nextInstructionText() const
154 {
155  return d->nextRouteSegment().maneuver().instructionText();
156 }
157 
158 QString Navigation::nextRoad() const
159 {
160  return d->nextRouteSegment().maneuver().roadName();
161 }
162 
163 QString 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 
188 qreal Navigation::nextInstructionDistance() const
189 {
190  return d->m_nextInstructionDistance;
191 }
192 
193 qreal Navigation::destinationDistance() const
194 {
195  return d->m_destinationDistance;
196 }
197 
198 QString Navigation::voiceNavigationAnnouncement() const
199 {
200  return d->m_voiceNavigation.instruction();
201 }
202 
203 QString Navigation::speaker() const
204 {
205  return d->m_voiceNavigation.speaker();
206 }
207 
208 void Navigation::setSpeaker( const QString &speaker )
209 {
210  d->m_voiceNavigation.setSpeaker( speaker );
211 }
212 
213 bool 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 
223 MarbleQuickItem *Navigation::marbleQuickItem() const
224 {
225  return d->m_marbleQuickItem;
226 }
227 
228 QPointF 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 
240 QPointF 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 
249 QPointF Navigation::screenPosition() const
250 {
251  return d->m_screenPosition;
252 }
253 
254 double Navigation::screenAccuracy() const
255 {
256  return d->m_screenAccuracy;
257 }
258 
259 void 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 
310 void 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 
335 void 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"
QAction * zoomOut(const QObject *recvr, const char *slot, QObject *parent)
KOSM_EXPORT double distance(const std::vector< const OSM::Node * > &path, Coordinate coord)
Binds a QML item to a specific geodetic location in screen coordinates.
FlyToMode
Describes possible flight mode (interpolation between source and target camera positions)
Definition: MarbleGlobal.h:162
QAction * zoomIn(const QObject *recvr, const char *slot, QObject *parent)
void update(Part *part, const QByteArray &data, qint64 dataSize)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Thu Sep 21 2023 04:12:27 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.