7#include "AutoNavigation.h"
9#include "GeoDataCoordinates.h"
10#include "MarbleDebug.h"
12#include "PositionTracking.h"
14#include "RoutingManager.h"
15#include "RoutingModel.h"
27class Q_DECL_HIDDEN AutoNavigation::Private
30 AutoNavigation *
const m_parent;
31 const MarbleModel *
const m_model;
32 const ViewportParams *
const m_viewport;
33 const PositionTracking *
const m_tracking;
34 AutoNavigation::CenterMode m_recenterMode;
36 QTimer m_lastWidgetInteraction;
37 bool m_selfInteraction;
40 Private(MarbleModel *model,
const ViewportParams *viewport, AutoNavigation *parent);
47 void moveOnBorderToCenter(
const GeoDataCoordinates &position, qreal speed);
54 GeoDataCoordinates findIntersection(qreal currentX, qreal currentY)
const;
60 void adjustZoom(
const GeoDataCoordinates ¤tPosition, qreal speed);
65 void centerOn(
const GeoDataCoordinates &position);
68AutoNavigation::Private::Private(MarbleModel *model,
const ViewportParams *viewport, AutoNavigation *parent)
71 , m_viewport(viewport)
72 , m_tracking(model->positionTracking())
73 , m_recenterMode(AutoNavigation::DontRecenter)
75 , m_selfInteraction(false)
77 m_lastWidgetInteraction.setInterval(10 * 1000);
78 m_lastWidgetInteraction.setSingleShot(
true);
81void AutoNavigation::Private::moveOnBorderToCenter(
const GeoDataCoordinates &position, qreal)
86 if (!(m_viewport->screenCoordinates(position, x, y))) {
89 qreal centerLon = m_viewport->centerLongitude();
90 qreal centerLat = m_viewport->centerLatitude();
95 m_viewport->screenCoordinates(centerLon, centerLat, centerX, centerY);
97 const qreal borderRatio = 0.25;
99 int shiftX = qRound(centerX * borderRatio);
100 int shiftY = qRound(centerY * borderRatio);
102 QRect recenterBorderBound;
103 recenterBorderBound.
setCoords(centerX - shiftX, centerY - shiftY, centerX + shiftX, centerY + shiftY);
105 if (!recenterBorderBound.
contains(x, y)) {
110GeoDataCoordinates AutoNavigation::Private::findIntersection(qreal currentX, qreal currentY)
const
112 qreal direction = m_tracking->direction();
113 if (direction >= 360) {
114 direction = fmod(direction, 360.0);
117 const qreal width = m_viewport->width();
118 const qreal height = m_viewport->height();
125 bool crossHorizontal =
false;
126 bool crossVertical =
false;
129 if (0 < direction && direction < 90) {
130 const qreal angle = direction * DEG2RAD;
133 intercept.
setX(width - currentX);
134 intercept.
setY(intercept.
x() / tan(angle));
135 destinationVertical.
setX(width);
136 destinationVertical.
setY(currentY - intercept.
y());
139 intercept.
setY(currentY);
140 intercept.
setX(intercept.
y() * tan(angle));
141 destinationHorizontal.
setX(currentX + intercept.
x());
142 destinationHorizontal.
setY(0);
144 if (destinationVertical.
y() < 0) {
145 crossHorizontal =
true;
146 }
else if (destinationHorizontal.
x() > width) {
147 crossVertical =
true;
150 }
else if (270 < direction && direction < 360) {
151 const qreal angle = (direction - 270) * DEG2RAD;
154 intercept.
setY(currentY);
155 intercept.
setX(intercept.
y() / tan(angle));
156 destinationHorizontal.
setX(currentX - intercept.
x());
157 destinationHorizontal.
setY(0);
160 intercept.
setX(currentX);
161 intercept.
setY(intercept.
x() * tan(angle));
162 destinationVertical.
setY(currentY - intercept.
y());
163 destinationVertical.
setX(0);
165 if (destinationHorizontal.
x() > width) {
166 crossVertical =
true;
167 }
else if (destinationVertical.
y() < 0) {
168 crossHorizontal =
true;
171 }
else if (180 < direction && direction < 270) {
172 const qreal angle = (direction - 180) * DEG2RAD;
175 intercept.
setX(currentX);
176 intercept.
setY(intercept.
x() / tan(angle));
177 destinationVertical.
setY(currentY + intercept.
y());
178 destinationVertical.
setX(0);
181 intercept.
setY(currentY);
182 intercept.
setX(intercept.
y() * tan(angle));
183 destinationHorizontal.
setX(currentX - intercept.
x());
184 destinationHorizontal.
setY(height);
186 if (destinationVertical.
y() > height) {
187 crossHorizontal =
true;
188 }
else if (destinationHorizontal.
x() < 0) {
189 crossVertical =
true;
192 }
else if (90 < direction && direction < 180) {
193 const qreal angle = (direction - 90) * DEG2RAD;
196 intercept.
setY(height - currentY);
197 intercept.
setX(intercept.
y() / tan(angle));
198 destinationHorizontal.
setX(currentX + intercept.
x());
199 destinationHorizontal.
setY(height);
202 intercept.
setX(width - currentX);
203 intercept.
setY(intercept.
x() * tan(angle));
204 destinationVertical.
setX(width);
205 destinationVertical.
setY(currentY + intercept.
y());
207 if (destinationHorizontal.
x() > width) {
208 crossVertical =
true;
209 }
else if (destinationVertical.
y() > height) {
210 crossHorizontal =
true;
213 }
else if (direction == 0) {
214 destinationHorizontal.
setX(currentX);
215 destinationHorizontal.
setY(0);
216 crossHorizontal =
true;
217 }
else if (direction == 90) {
218 destinationVertical.
setX(width);
219 destinationVertical.
setY(currentY);
220 crossVertical =
true;
221 }
else if (direction == 180) {
222 destinationHorizontal.
setX(currentX);
223 destinationHorizontal.
setY(height);
224 crossHorizontal =
true;
225 }
else if (direction == 270) {
226 destinationVertical.
setX(0);
227 destinationVertical.
setY(currentY);
228 crossVertical =
true;
231 if (crossHorizontal ==
true && crossVertical ==
false) {
232 destination.
setX(destinationHorizontal.
x());
233 destination.
setY(destinationHorizontal.
y());
234 }
else if (crossVertical ==
true && crossHorizontal ==
false) {
235 destination.
setX(destinationVertical.
x());
236 destination.
setY(destinationVertical.
y());
239 qreal destinationLon = 0.0;
240 qreal destinationLat = 0.0;
241 m_viewport->geoCoordinates(destination.
x(), destination.
y(), destinationLon, destinationLat, GeoDataCoordinates::Radian);
242 GeoDataCoordinates destinationCoord(destinationLon, destinationLat, GeoDataCoordinates::Radian);
244 return destinationCoord;
247void AutoNavigation::Private::adjustZoom(
const GeoDataCoordinates ¤tPosition, qreal speed)
251 if (!m_viewport->screenCoordinates(currentPosition, currentX, currentY)) {
255 const GeoDataCoordinates destination = findIntersection(currentX, currentY);
257 const qreal greatCircleDistance = currentPosition.sphericalDistanceTo(destination);
258 qreal radius = m_model->planetRadius();
259 qreal
distance = greatCircleDistance * radius;
263 qreal remainingTime =
distance / speed;
266 qreal thresholdLow = 15;
267 qreal thresholdHigh = 120;
269 m_selfInteraction =
true;
270 if (remainingTime < thresholdLow) {
271 Q_EMIT m_parent->zoomOut(Instant);
272 }
else if (remainingTime > thresholdHigh) {
273 Q_EMIT m_parent->zoomIn(Instant);
275 m_selfInteraction =
false;
279void AutoNavigation::Private::centerOn(
const GeoDataCoordinates &position)
281 m_selfInteraction =
true;
282 RoutingManager
const *routingManager = m_model->routingManager();
283 RoutingModel
const *routingModel = routingManager->routingModel();
284 if (!routingManager->guidanceModeEnabled() || routingModel->deviatedFromRoute()) {
285 Q_EMIT m_parent->centerOn(position,
false);
287 GeoDataCoordinates positionOnRoute = routingModel->route().positionOnRoute();
288 Q_EMIT m_parent->centerOn(positionOnRoute,
false);
290 m_selfInteraction =
false;
293AutoNavigation::AutoNavigation(MarbleModel *model,
const ViewportParams *viewport,
QObject *parent)
295 , d(new AutoNavigation::Private(model, viewport, this))
297 connect(d->m_tracking, &PositionTracking::gpsLocation,
this, &AutoNavigation::adjust);
300AutoNavigation::~AutoNavigation()
305void AutoNavigation::adjust(
const GeoDataCoordinates &position, qreal speed)
307 if (d->m_lastWidgetInteraction.isActive()) {
311 switch (d->m_recenterMode) {
316 d->centerOn(position);
318 case RecenterOnBorder:
319 d->moveOnBorderToCenter(position, speed);
323 if (d->m_adjustZoom) {
324 switch (d->m_recenterMode) {
329 case RecenterOnBorder:
330 d->adjustZoom(position, speed);
336void AutoNavigation::setAutoZoom(
bool autoZoom)
338 d->m_adjustZoom = autoZoom;
339 Q_EMIT autoZoomToggled(autoZoom);
342void AutoNavigation::setRecenter(CenterMode recenterMode)
344 d->m_recenterMode = recenterMode;
345 Q_EMIT recenterModeChanged(recenterMode);
348void AutoNavigation::inhibitAutoAdjustments()
350 if (!d->m_selfInteraction) {
351 d->m_lastWidgetInteraction.start();
355AutoNavigation::CenterMode AutoNavigation::recenterMode()
const
357 return d->m_recenterMode;
360bool AutoNavigation::autoZoom()
const
362 return d->m_adjustZoom;
367#include "moc_AutoNavigation.cpp"
This file contains the headers for MarbleModel.
This file contains the headers for ViewportParams.
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 contains(const QPoint &point, bool proper) const const
void setCoords(int x1, int y1, int x2, int y2)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)