10#include "GeoDataGeometry.h"
11#include "GeoDataLatLonAltBox.h"
14#include <GeoDataLookAt.h>
15#include <GeoDataPlacemark.h>
16#include <MarbleAbstractPresenter.h>
17#include <MarbleClock.h>
18#include <MarbleDebug.h>
19#include <MarbleLocale.h>
22#include <Quaternion.h>
27MarbleAbstractPresenter::MarbleAbstractPresenter(MarbleMap *map,
QObject *parent)
31 , m_animationsEnabled(false)
33 , m_zoomStep(MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ? 60 : 40)
38MarbleAbstractPresenter::~MarbleAbstractPresenter() =
default;
40qreal MarbleAbstractPresenter::zoom(qreal radius)
const
42 return (200.0 * log(radius));
45qreal MarbleAbstractPresenter::radius(qreal zoom)
const
47 return pow(M_E, (zoom / 200.0));
50void MarbleAbstractPresenter::rotateBy(
const qreal deltaLon,
const qreal deltaLat, FlyToMode mode)
52 GeoDataLookAt target = lookAt();
53 GeoDataCoordinates coords(
map()->viewport()->centerLongitude(),
map()->viewport()->centerLatitude());
54 GeoDataCoordinates movedCoords = coords.moveByBearing(-
map()->heading() * DEG2RAD, -deltaLat * DEG2RAD);
55 movedCoords = movedCoords.moveByBearing((-
map()->heading() - 90) * DEG2RAD, -deltaLon * DEG2RAD *
map()->viewport()->polarity());
57 target.setLongitude(movedCoords.longitude());
58 target.setLatitude(movedCoords.latitude());
63void MarbleAbstractPresenter::flyTo(
const GeoDataLookAt &newLookAt, FlyToMode mode)
65 if (!m_animationsEnabled || mode == Instant) {
66 const int radius = qRound(radiusFromDistance(newLookAt.range() * METER2KM));
67 qreal
const zoomVal =
zoom(radius);
70 if (qRound(zoomVal) >= minimumZoom() && qRound(zoomVal) <= maximumZoom()) {
71 map()->setRadius(radius);
72 m_logzoom = qRound(
zoom(radius));
74 GeoDataCoordinates::Unit deg = GeoDataCoordinates::Degree;
75 map()->centerOn(newLookAt.longitude(deg), newLookAt.latitude(deg));
77 Q_EMIT zoomChanged(m_logzoom);
78 Q_EMIT distanceChanged(distanceString());
81 m_physics.flyTo(newLookAt, mode);
85QString MarbleAbstractPresenter::distanceString()
const
88 qreal dist =
distance() * KM2METER, convertedDistance;
90 MarbleLocale::MeasureUnit unit;
91 MarbleLocale *locale = MarbleGlobal::getInstance()->locale();
92 locale->meterToTargetUnit(dist, locale->measurementSystem(), convertedDistance, unit);
93 QString unitString = locale->unitAbbreviation(unit);
95 return QStringLiteral(
"%L1 %2").
arg(convertedDistance, 8,
'f', 1,
QLatin1Char(
' ')).
arg(unitString);
98GeoDataLookAt MarbleAbstractPresenter::lookAt()
const
100 GeoDataLookAt result;
102 result.setLongitude(
map()->viewport()->centerLongitude());
103 result.setLatitude(
map()->viewport()->centerLatitude());
104 result.setAltitude(0.0);
105 result.setRange(
distance() * KM2METER);
110qreal MarbleAbstractPresenter::distance()
const
112 return distanceFromRadius(radius());
115qreal MarbleAbstractPresenter::distanceFromRadius(qreal radius)
const
127 return (model()->planet()->radius() * 0.4 / radius / tan(0.5 * m_viewAngle * DEG2RAD));
130qreal MarbleAbstractPresenter::radiusFromDistance(qreal distance)
const
132 return model()->planet()->radius() / (
distance * tan(0.5 * m_viewAngle * DEG2RAD) / 0.4);
135int MarbleAbstractPresenter::polarity()
const
137 return map()->viewport()->polarity();
140int MarbleAbstractPresenter::zoom()
const
145int MarbleAbstractPresenter::minimumZoom()
const
147 return map()->minimumZoom();
150int MarbleAbstractPresenter::maximumZoom()
const
152 return map()->maximumZoom();
155void MarbleAbstractPresenter::setZoom(
int newZoom, FlyToMode mode)
158 if (!m_animationsEnabled || mode == Instant) {
160 if (newZoom < minimumZoom())
161 newZoom = minimumZoom();
162 else if (newZoom > maximumZoom())
163 newZoom = maximumZoom();
166 if (newZoom == m_logzoom)
169 map()->setRadius(radius(newZoom));
172 Q_EMIT zoomChanged(m_logzoom);
173 Q_EMIT distanceChanged(distanceString());
175 GeoDataLookAt target = lookAt();
176 target.setRange(KM2METER * distanceFromZoom(newZoom));
181void MarbleAbstractPresenter::zoomView(
int zoom, FlyToMode mode)
186void MarbleAbstractPresenter::zoomViewBy(
int zoomStep, FlyToMode mode)
188 setZoom(
zoom() + zoomStep, mode);
191void MarbleAbstractPresenter::zoomIn(FlyToMode mode)
193 if (
map()->tileZoomLevel() < 0) {
194 zoomViewBy(m_zoomStep, mode);
196 qreal radiusVal =
map()->preferredRadiusCeil(
map()->radius() / 0.95);
197 radiusVal = qBound(radius(minimumZoom()), radiusVal, radius(maximumZoom()));
199 GeoDataLookAt target = lookAt();
200 target.setRange(KM2METER * distanceFromRadius(radiusVal));
206void MarbleAbstractPresenter::zoomOut(FlyToMode mode)
208 if (
map()->tileZoomLevel() <= 0) {
209 zoomViewBy(-m_zoomStep, mode);
211 qreal radiusVal =
map()->preferredRadiusFloor(
map()->radius() * 0.95);
212 radiusVal = qBound(radius(minimumZoom()), radiusVal, radius(maximumZoom()));
214 GeoDataLookAt target = lookAt();
215 target.setRange(KM2METER * distanceFromRadius(radiusVal));
221void MarbleAbstractPresenter::zoomAtBy(
const QPoint &pos,
int zoomStep)
224 if (
map()->tileZoomLevel() <= 0) {
225 radiusVal = radius(
zoom() + zoomStep);
227 radiusVal = zoomStep > 0 ?
map()->preferredRadiusCeil(
map()->radius() / 0.95) :
map()->preferredRadiusFloor(
map()->radius() * 0.95);
228 radiusVal = qBound(radius(minimumZoom()), radiusVal, radius(maximumZoom()));
231 zoomAt(pos, distanceFromRadius(radiusVal));
234qreal MarbleAbstractPresenter::distanceFromZoom(qreal zoom)
const
236 return distanceFromRadius(radius(zoom));
239qreal MarbleAbstractPresenter::zoomFromDistance(qreal distance)
const
241 return zoom(radiusFromDistance(distance));
244void MarbleAbstractPresenter::goHome(FlyToMode mode)
249 model()->home(homeLon, homeLat, homeZoom);
251 GeoDataLookAt target;
252 target.setLongitude(homeLon, GeoDataCoordinates::Degree);
253 target.setLatitude(homeLat, GeoDataCoordinates::Degree);
254 target.setRange(1000 * distanceFromZoom(homeZoom));
259void MarbleAbstractPresenter::moveByStep(
int stepsRight,
int stepsDown, FlyToMode mode)
261 int polarity =
map()->viewport()->polarity();
262 qreal
left = polarity * stepsRight * moveStep();
263 qreal down = stepsDown * moveStep();
264 rotateBy(left, down, mode);
267qreal MarbleAbstractPresenter::moveStep()
const
269 int width =
map()->width();
270 int height =
map()->height();
272 if (radius() < qSqrt((qreal)(width * width + height * height)))
275 return 180.0 * qAtan((qreal)width / (qreal)(2 * radius())) * 0.2;
278int MarbleAbstractPresenter::radius()
const
280 return map()->radius();
283void MarbleAbstractPresenter::setRadius(
int radiusVal)
285 Q_ASSERT(radiusVal >= 0);
286 bool adjustRadius = radiusVal !=
map()->radius();
288 qreal
const zoomVal =
zoom(radiusVal);
291 if (zoomVal < minimumZoom()) {
292 radiusVal = radius(minimumZoom());
294 }
else if (zoomVal > maximumZoom()) {
295 radiusVal = radius(maximumZoom());
300 map()->setRadius(radiusVal);
301 m_logzoom = qRound(zoomVal);
303 Q_EMIT zoomChanged(m_logzoom);
304 Q_EMIT distanceChanged(distanceString());
309void MarbleAbstractPresenter::zoomAt(
const QPoint &pos, qreal newDistance)
311 Q_ASSERT(newDistance > 0.0);
315 if (!
map()->geoCoordinates(pos.
x(), pos.
y(), destLon, destLat, GeoDataCoordinates::Degree)) {
319 ViewportParams *now =
map()->viewport();
321 if (!now->screenCoordinates(destLon * DEG2RAD, destLat * DEG2RAD, x, y)) {
326 soon.setProjection(now->projection());
327 soon.centerOn(now->centerLongitude(), now->centerLatitude());
328 soon.setSize(now->size());
330 qreal newRadius = radiusFromDistance(newDistance);
331 soon.setRadius(newRadius);
333 qreal mouseLon, mouseLat;
334 if (!soon.geoCoordinates(
int(x),
int(y), mouseLon, mouseLat, GeoDataCoordinates::Degree)) {
338 const qreal lon = destLon - (mouseLon -
map()->centerLongitude());
339 const qreal lat = destLat - (mouseLat -
map()->centerLatitude());
341 GeoDataLookAt lookAt;
342 lookAt.setLongitude(lon, GeoDataCoordinates::Degree);
343 lookAt.setLatitude(lat, GeoDataCoordinates::Degree);
344 lookAt.setAltitude(0.0);
345 lookAt.setRange(newDistance * KM2METER);
347 map()->viewport()->setFocusPoint(GeoDataCoordinates(destLon, destLat, 0, GeoDataCoordinates::Degree));
348 flyTo(lookAt, Linear);
351void MarbleAbstractPresenter::moveTo(
const QPoint &pos, qreal factor)
353 Q_ASSERT(factor > 0.0);
357 map()->geoCoordinates(pos.
x(), pos.
y(), destLon, destLat, GeoDataCoordinates::Radian);
359 GeoDataLookAt lookAt;
360 lookAt.setLongitude(destLon);
361 lookAt.setLatitude(destLat);
362 lookAt.setAltitude(0.0);
363 lookAt.setRange(
distance() * factor * KM2METER);
368void MarbleAbstractPresenter::centerOn(
const qreal lon,
const qreal lat,
bool animated)
370 GeoDataCoordinates target(lon, lat, 0.0, GeoDataCoordinates::Degree);
371 centerOn(target, animated);
374void MarbleAbstractPresenter::centerOn(
const GeoDataCoordinates &position,
bool animated)
376 GeoDataLookAt target = lookAt();
377 target.setCoordinates(position);
378 flyTo(target, animated ? Automatic : Instant);
381void MarbleAbstractPresenter::centerOn(
const GeoDataLatLonBox &box,
bool animated)
387 int newRadius = radius();
388 ViewportParams *viewparams =
map()->viewport();
390 if (box.height() && box.width()) {
392 int const horizontalRadius = (0.25 * M_PI) * (viewparams->height() / box.height());
393 int const verticalRadius = (0.25 * M_PI) * (viewparams->width() / box.width());
394 newRadius = qMin<int>(horizontalRadius, verticalRadius);
395 newRadius = qMax<int>(radius(minimumZoom()), qMin<int>(newRadius, radius(maximumZoom())));
399 GeoDataLookAt target;
400 target.setCoordinates(box.center());
401 target.setAltitude(box.center().altitude());
402 target.setRange(KM2METER * distanceFromRadius(newRadius));
403 flyTo(target, animated ? Automatic : Instant);
406void MarbleAbstractPresenter::centerOn(
const GeoDataPlacemark &placemark,
bool animated)
408 const GeoDataLookAt *lookAt(placemark.lookAt());
410 flyTo(*lookAt, animated ? Automatic : Instant);
413 GeoDataCoordinates coords = placemark.coordinate(model()->clock()->dateTime(), &icon);
415 centerOn(coords, animated);
417 centerOn(placemark.geometry()->latLonAltBox(), animated);
422void MarbleAbstractPresenter::headingOn(qreal heading)
424 map()->setHeading(heading);
427void MarbleAbstractPresenter::setCenterLatitude(qreal lat, FlyToMode mode)
429 centerOn(centerLongitude(), lat, mode);
432void MarbleAbstractPresenter::setCenterLongitude(qreal lon, FlyToMode mode)
434 centerOn(lon, centerLatitude(), mode);
437qreal MarbleAbstractPresenter::centerLatitude()
const
439 return map()->centerLatitude();
442qreal MarbleAbstractPresenter::centerLongitude()
const
444 return map()->centerLongitude();
447ViewContext MarbleAbstractPresenter::viewContext()
const
449 return map()->viewContext();
452void MarbleAbstractPresenter::setViewContext(ViewContext viewContext)
454 map()->setViewContext(viewContext);
457bool MarbleAbstractPresenter::animationsEnabled()
const
459 return m_animationsEnabled;
462void MarbleAbstractPresenter::setAnimationsEnabled(
bool enabled)
464 m_animationsEnabled = enabled;
467int MarbleAbstractPresenter::logzoom()
const
472void MarbleAbstractPresenter::setLogzoom(
int value)
477int MarbleAbstractPresenter::zoomStep()
const
482qreal MarbleAbstractPresenter::viewAngle()
const
487MarbleMap *MarbleAbstractPresenter::map()
492const MarbleMap *MarbleAbstractPresenter::map()
const
497MarbleModel *MarbleAbstractPresenter::model()
499 return m_map->model();
502const MarbleModel *MarbleAbstractPresenter::model()
const
504 return m_map->model();
507ViewportParams *MarbleAbstractPresenter::viewport()
509 return map()->viewport();
512const ViewportParams *MarbleAbstractPresenter::viewport()
const
514 return map()->viewport();
517void MarbleAbstractPresenter::setDistance(qreal newDistance)
519 qreal minDistance = 0.001;
521 if (newDistance <= minDistance) {
522 mDebug() <<
"Invalid distance: 0 m";
523 newDistance = minDistance;
526 int newRadius = radiusFromDistance(newDistance);
527 setRadius(newRadius);
530void MarbleAbstractPresenter::setSelection(
const QRect ®ion)
534 mDebug() <<
"Selection region: (" << tl.
x() <<
", " << tl.
y() <<
") (" << br.
x() <<
", " << br.
y() <<
")" <<
Qt::endl;
536 const GeoDataLatLonAltBox box = viewport()->latLonAltBox(region);
538 Q_EMIT regionSelected(box);
543#include "moc_MarbleAbstractPresenter.cpp"
This file contains the headers for MarbleMap.
This file contains the headers for MarbleModel.
This file contains the headers for ViewportParams.
QAction * zoom(const QObject *recvr, const char *slot, QObject *parent)
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)
QPoint bottomRight() const const
QPoint topLeft() const const
QString arg(Args &&... args) const const
QTextStream & endl(QTextStream &stream)
QTextStream & left(QTextStream &stream)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)