1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtPositioning module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qquickgeocoordinateanimation_p.h"
41 #include "qquickgeocoordinateanimation_p_p.h"
42 #include <QtQuick/private/qquickanimation_p_p.h>
43 #include <QtPositioning/private/qdoublevector2d_p.h>
44 #include <QtPositioning/private/qwebmercator_p.h>
45 #include <QtPositioning/private/qgeocoordinate_p.h>
46 
47 QT_BEGIN_NAMESPACE
48 
49 /*!
50     \qmltype CoordinateAnimation
51     \inherits PropertyAnimation
52     \inqmlmodule QtPositioning
53     \since 5.3
54 
55     \brief A PropertyAnimation for geo coordinate properties.
56 
57     A specialized \l{PropertyAnimation} that defines an animation
58     between two \l{coordinate}{coordinates}.
59 
60     By default, a \l{latitude} of the \l{coordinate} is animated in the direction of shortest
61     (geodesic) distance between those coordinates. Since CoordinateAnimation uses Mercator
62     map projection, the \l{latitude} animation is always between -90 and 90 degrees.
63     The \l{longitude} animation path is not limited and can go over 180 degrees
64     in both west and east directions.
65 
66     The \l{direction} property can be set to specify the direction in which the \l{longitude}
67     animation should occur.
68 
69     \sa {Animation and Transitions in Qt Quick}
70 */
71 
q_coordinateInterpolator(const QGeoCoordinate & from,const QGeoCoordinate & to,qreal progress)72 QVariant q_coordinateInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
73 {
74     if (from == to) {
75         if (progress < 0.5) {
76             return QVariant::fromValue(from);
77         } else {
78             return QVariant::fromValue(to);
79         }
80     }
81 
82     QGeoCoordinate result = QWebMercator::coordinateInterpolation(from, to, progress);
83 
84     return QVariant::fromValue(result);
85 }
86 
q_coordinateShortestInterpolator(const QGeoCoordinate & from,const QGeoCoordinate & to,qreal progress)87 QVariant q_coordinateShortestInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
88 {
89     const QGeoMercatorCoordinatePrivate* fromMercator =
90             static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&from));
91     const QGeoMercatorCoordinatePrivate* toMercator =
92             static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&to));
93 
94     double toX = toMercator->m_mercatorX;
95     double toY = toMercator->m_mercatorY;
96     double fromX = fromMercator->m_mercatorX;
97     double fromY = fromMercator->m_mercatorY;
98     double x;
99     if (0.5 < qAbs(toX - fromX)) {
100         // handle dateline crossing
101         double ex = toX;
102         double sx = fromX;
103         if (ex < sx)
104             sx -= 1.0;
105         else if (sx < ex)
106             ex -= 1.0;
107 
108         x = fromX + (toX - fromX) * progress;
109 
110         if (x < 0.0)
111             x += 1.0;
112 
113     } else {
114         x = fromX + (toX - fromX) * progress;
115     }
116 
117     double y = fromY + (toY - fromY) * progress;
118 
119     QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
120     result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
121     return QVariant::fromValue(result);
122 }
123 
q_coordinateWestInterpolator(const QGeoCoordinate & from,const QGeoCoordinate & to,qreal progress)124 QVariant q_coordinateWestInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
125 {
126     const QGeoMercatorCoordinatePrivate* fromMercator =
127             static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&from));
128     const QGeoMercatorCoordinatePrivate* toMercator =
129             static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&to));
130 
131     double toX = toMercator->m_mercatorX;
132     double toY = toMercator->m_mercatorY;
133     double fromX = fromMercator->m_mercatorX;
134     double fromY = fromMercator->m_mercatorY;
135     double diff = toX - fromX;
136 
137     while (diff < 0.0) {
138         toX += 1.0;
139         diff += 1.0;
140     }
141 
142     double x = fromX + (toX - fromX) * progress;
143     double y = fromY + (toY - fromY) * progress;
144 
145     while (x > 1.0)
146         x -= 1.0;
147 
148     QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
149     result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
150 
151     return QVariant::fromValue(result);
152 }
153 
q_coordinateEastInterpolator(const QGeoCoordinate & from,const QGeoCoordinate & to,qreal progress)154 QVariant q_coordinateEastInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
155 {
156     const QGeoMercatorCoordinatePrivate* fromMercator =
157             static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&from));
158     const QGeoMercatorCoordinatePrivate* toMercator =
159             static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(&to));
160 
161     double toX = toMercator->m_mercatorX;
162     double toY = toMercator->m_mercatorY;
163     double fromX = fromMercator->m_mercatorX;
164     double fromY = fromMercator->m_mercatorY;
165     double diff = toX - fromX;
166 
167     while (diff > 0.0) {
168         toX -= 1.0;
169         diff -= 1.0;
170     }
171 
172     double x = fromX + (toX - fromX) * progress;
173     double y = fromY + (toY - fromY) * progress;
174 
175     while (x < 0.0)
176         x += 1.0;
177 
178     QGeoCoordinate result = QWebMercator::mercatorToCoord(QDoubleVector2D(x, y));
179     result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
180 
181     return QVariant::fromValue(result);
182 }
183 
QQuickGeoCoordinateAnimation(QObject * parent)184 QQuickGeoCoordinateAnimation::QQuickGeoCoordinateAnimation(QObject *parent)
185     : QQuickPropertyAnimation(*(new QQuickGeoCoordinateAnimationPrivate), parent)
186 
187 {
188     Q_D(QQuickGeoCoordinateAnimation);
189     d->interpolatorType = qMetaTypeId<QGeoCoordinate>();
190     d->defaultToInterpolatorType = true;
191     d->interpolator = QVariantAnimationPrivate::getInterpolator(d->interpolatorType);
192 }
193 
~QQuickGeoCoordinateAnimation()194 QQuickGeoCoordinateAnimation::~QQuickGeoCoordinateAnimation()
195 {
196 }
197 
198 /*!
199     \qmlproperty coordinate CoordinateAnimation::from
200     This property holds the coordinate where the animation should begin.
201 */
from() const202 QGeoCoordinate QQuickGeoCoordinateAnimation::from() const
203 {
204     Q_D(const QQuickGeoCoordinateAnimation);
205     return d->from.value<QGeoCoordinate>();
206 }
207 
setFrom(const QGeoCoordinate & f)208 void QQuickGeoCoordinateAnimation::setFrom(const QGeoCoordinate &f)
209 {
210     QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
211     QDoubleVector2D fromVector = QWebMercator::coordToMercator(f);
212     mercator->lat = f.latitude();
213     mercator->lng = f.longitude();
214     mercator->alt = f.altitude();
215     mercator->m_mercatorX = fromVector.x();
216     mercator->m_mercatorY = fromVector.y();
217     QGeoCoordinate from(*mercator);
218     QQuickPropertyAnimation::setFrom(QVariant::fromValue(from));
219 }
220 
221 /*!
222     \qmlproperty coordinate CoordinateAnimation::to
223     This property holds the coordinate where the animation should end.
224 */
to() const225 QGeoCoordinate QQuickGeoCoordinateAnimation::to() const
226 {
227     Q_D(const QQuickGeoCoordinateAnimation);
228     return d->to.value<QGeoCoordinate>();
229 }
230 
setTo(const QGeoCoordinate & t)231 void QQuickGeoCoordinateAnimation::setTo(const QGeoCoordinate &t)
232 {
233     QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
234     QDoubleVector2D toVector = QWebMercator::coordToMercator(t);
235     mercator->lat = t.latitude();
236     mercator->lng = t.longitude();
237     mercator->alt = t.altitude();
238     mercator->m_mercatorX = toVector.x();
239     mercator->m_mercatorY = toVector.y();
240     QGeoCoordinate to(*mercator);
241     QQuickPropertyAnimation::setTo(QVariant::fromValue(to));
242 }
243 
244 /*!
245     \qmlproperty enumeration CoordinateAnimation::direction
246     This property holds the direction of the \l{longitude} animation of the \l{coordinate}.
247 
248     Possible values are:
249 
250     \list
251     \li CoordinateAnimation.Shortest (default) - the longitude animation goes in the direction
252         that produces the shortest animation path.
253     \li CoordinateAnimation.West - the longitude animation always goes into western direction
254         and may cross the date line.
255     \li CoordinateAnimation.East - the longitude animation always goes into eastern direction
256         and may cross the date line.
257     \endlist
258     \since 5.5
259 */
260 
261 
direction() const262 QQuickGeoCoordinateAnimation::Direction QQuickGeoCoordinateAnimation::direction() const
263 {
264     Q_D(const QQuickGeoCoordinateAnimation);
265     return d->m_direction;
266 }
267 
setDirection(QQuickGeoCoordinateAnimation::Direction direction)268 void QQuickGeoCoordinateAnimation::setDirection(QQuickGeoCoordinateAnimation::Direction direction)
269 {
270     Q_D( QQuickGeoCoordinateAnimation);
271     if (d->m_direction == direction)
272         return;
273 
274     d->m_direction = direction;
275     switch (direction) {
276     case West:
277         d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&q_coordinateWestInterpolator));
278         break;
279     case East:
280         d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&q_coordinateEastInterpolator));
281         break;
282     case Shortest:
283     default:
284         d->interpolator = reinterpret_cast<QVariantAnimation::Interpolator>(reinterpret_cast<void *>(&q_coordinateShortestInterpolator));
285         break;
286     }
287     emit directionChanged();
288 
289 }
290 
QQuickGeoCoordinateAnimationPrivate()291 QQuickGeoCoordinateAnimationPrivate::QQuickGeoCoordinateAnimationPrivate():
292     m_direction(QQuickGeoCoordinateAnimation::Shortest)
293 {
294 }
295 
296 QT_END_NAMESPACE
297