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();
55 movedCoords = movedCoords.
moveByBearing((-
map()->heading() - 90) * DEG2RAD, -deltaLon * DEG2RAD *
map()->viewport()->polarity());
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));
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)
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.
A 3d point representation.
GeoDataCoordinates moveByBearing(qreal bearing, qreal distance) const
Returns the coordinates of the resulting point after moving this point according to the distance and ...
Unit
enum used constructor to specify the units used
void setLongitude(qreal lon, GeoDataCoordinates::Unit unit=GeoDataCoordinates::Radian)
set the longitude in a GeoDataCoordinates object
A class that can paint a view of the earth.
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)