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