Revision control
Copy as Markdown
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qquickgeocoordinateanimation_p.h"
#include "qquickgeocoordinateanimation_p_p.h"
#include <QtQuick/private/qquickanimation_p_p.h>
#include <QtPositioning/private/qdoublevector2d_p.h>
#include <QtPositioning/private/qwebmercator_p.h>
#include <QtPositioning/private/qgeocoordinate_p.h>
QT_BEGIN_NAMESPACE
/*!
\qmltype CoordinateAnimation
\inherits PropertyAnimation
\inqmlmodule QtPositioning
\since 5.3
\brief A PropertyAnimation for geo coordinate properties.
A specialized \l{PropertyAnimation} that defines an animation
between two \l{geoCoordinate}{coordinates}.
By default, a \l{geoCoordinate::latitude}{latitude} of the
\l geoCoordinate is animated in the direction of shortest
(geodesic) distance between those coordinates. Since CoordinateAnimation uses Mercator
map projection, the \l{geoCoordinate::latitude}{latitude} animation
is always between -90 and 90 degrees.
The \l{geoCoordinate::longitude}{longitude} animation path is not
limited and can go over 180 degrees in both west and east directions.
The \l{direction} property can be set to specify the direction in which the
\l{geoCoordinate::longitude}{longitude} animation should occur.
\sa {Animation and Transitions in Qt Quick}
*/
QVariant q_coordinateInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
{
if (from == to) {
if (progress < 0.5) {
return QVariant::fromValue(from);
} else {
return QVariant::fromValue(to);
}
}
QGeoCoordinate result = QWebMercator::coordinateInterpolation(from, to, progress);
return QVariant::fromValue(result);
}
QVariant q_coordinateShortestInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
{
const QGeoMercatorCoordinatePrivate* fromMercator =
static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&from));
const QGeoMercatorCoordinatePrivate* toMercator =
static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&to));
double toX = toMercator->m_mercatorX;
double toY = toMercator->m_mercatorY;
double fromX = fromMercator->m_mercatorX;
double fromY = fromMercator->m_mercatorY;
double x;
if (0.5 < qAbs(toX - fromX)) {
// handle dateline crossing
double ex = toX;
double sx = fromX;
if (ex < sx)
sx -= 1.0;
else if (sx < ex)
ex -= 1.0;
x = sx + (ex - sx) * progress;
if (x < 0.0)
x += 1.0;
} else {
x = fromX + (toX - fromX) * progress;
}
double y = fromY + (toY - fromY) * progress;
QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
return QVariant::fromValue(result);
}
QVariant q_coordinateEastInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
{
const QGeoMercatorCoordinatePrivate* fromMercator =
static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&from));
const QGeoMercatorCoordinatePrivate* toMercator =
static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&to));
double toX = toMercator->m_mercatorX;
double toY = toMercator->m_mercatorY;
double fromX = fromMercator->m_mercatorX;
double fromY = fromMercator->m_mercatorY;
double diff = toX - fromX;
while (diff < 0.0) {
toX += 1.0;
diff += 1.0;
}
double x = fromX + (toX - fromX) * progress;
double y = fromY + (toY - fromY) * progress;
while (x > 1.0)
x -= 1.0;
QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
return QVariant::fromValue(result);
}
QVariant q_coordinateWestInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
{
const QGeoMercatorCoordinatePrivate* fromMercator =
static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&from));
const QGeoMercatorCoordinatePrivate* toMercator =
static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&to));
double toX = toMercator->m_mercatorX;
double toY = toMercator->m_mercatorY;
double fromX = fromMercator->m_mercatorX;
double fromY = fromMercator->m_mercatorY;
double diff = toX - fromX;
while (diff > 0.0) {
toX -= 1.0;
diff -= 1.0;
}
double x = fromX + (toX - fromX) * progress;
double y = fromY + (toY - fromY) * progress;
while (x < 0.0)
x += 1.0;
QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
return QVariant::fromValue(result);
}
QQuickGeoCoordinateAnimation::QQuickGeoCoordinateAnimation(QObject *parent)
: QQuickPropertyAnimation(*(new QQuickGeoCoordinateAnimationPrivate), parent)
{
Q_D(QQuickGeoCoordinateAnimation);
d->interpolatorType = qMetaTypeId<QGeoCoordinate>();
d->defaultToInterpolatorType = true;
d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
}
QQuickGeoCoordinateAnimation::~QQuickGeoCoordinateAnimation()
{
}
/*!
\qmlproperty coordinate CoordinateAnimation::from
This property holds the coordinate where the animation should begin.
*/
QGeoCoordinate QQuickGeoCoordinateAnimation::from() const
{
Q_D(const QQuickGeoCoordinateAnimation);
return d->from.value<QGeoCoordinate>();
}
void QQuickGeoCoordinateAnimation::setFrom(const QGeoCoordinate &f)
{
QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
QDoubleVector2D fromVector = QWebMercator::coordToMercator(f);
mercator->lat = f.latitude();
mercator->lng = f.longitude();
mercator->alt = f.altitude();
mercator->m_mercatorX = fromVector.x();
mercator->m_mercatorY = fromVector.y();
QGeoCoordinate from(*mercator);
QQuickPropertyAnimation::setFrom(QVariant::fromValue(from));
}
/*!
\qmlproperty coordinate CoordinateAnimation::to
This property holds the coordinate where the animation should end.
*/
QGeoCoordinate QQuickGeoCoordinateAnimation::to() const
{
Q_D(const QQuickGeoCoordinateAnimation);
return d->to.value<QGeoCoordinate>();
}
void QQuickGeoCoordinateAnimation::setTo(const QGeoCoordinate &t)
{
QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
QDoubleVector2D toVector = QWebMercator::coordToMercator(t);
mercator->lat = t.latitude();
mercator->lng = t.longitude();
mercator->alt = t.altitude();
mercator->m_mercatorX = toVector.x();
mercator->m_mercatorY = toVector.y();
QGeoCoordinate to(*mercator);
QQuickPropertyAnimation::setTo(QVariant::fromValue(to));
}
/*!
\qmlproperty enumeration CoordinateAnimation::direction
This property holds the direction of the
\l{geoCoordinate::longitude}{longitude} animation of the
\l geoCoordinate.
\value CoordinateAnimation.Shortest
The longitude animation goes in the direction
that produces the shortest animation path. This is the default.
\value CoordinateAnimation.West
The longitude animation always goes into western direction
and may cross the date line.
\value CoordinateAnimation.East
The longitude animation always goes into eastern direction
and may cross the date line.
\since 5.5
*/
QQuickGeoCoordinateAnimation::Direction QQuickGeoCoordinateAnimation::direction() const
{
Q_D(const QQuickGeoCoordinateAnimation);
return d->m_direction.value();
}
void QQuickGeoCoordinateAnimation::setDirection(QQuickGeoCoordinateAnimation::Direction direction)
{
Q_D( QQuickGeoCoordinateAnimation);
d->m_direction.removeBindingUnlessInWrapper();
if (d->m_direction.valueBypassingBindings() == direction)
return;
d->m_direction.setValueBypassingBindings(direction);
switch (direction) {
case West:
d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&q_coordinateWestInterpolator));
break;
case East:
d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&q_coordinateEastInterpolator));
break;
case Shortest:
default:
d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&q_coordinateShortestInterpolator));
break;
}
d->m_direction.notify();
}
QBindable<QQuickGeoCoordinateAnimation::Direction> QQuickGeoCoordinateAnimation::bindableDirection()
{
Q_D(QQuickGeoCoordinateAnimation);
return QBindable<Direction>(&d->m_direction);
}
QT_END_NAMESPACE
#include "moc_qquickgeocoordinateanimation_p.cpp"