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
47QT_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
72QVariant q_coordinateInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
73{
74 if (from == to) {
75 if (progress < 0.5) {
76 return QVariant::fromValue(value: from);
77 } else {
78 return QVariant::fromValue(value: to);
79 }
80 }
81
82 QGeoCoordinate result = QWebMercator::coordinateInterpolation(from, to, progress);
83
84 return QVariant::fromValue(value: result);
85}
86
87QVariant q_coordinateShortestInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
88{
89 const QGeoMercatorCoordinatePrivate* fromMercator =
90 static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(c: &from));
91 const QGeoMercatorCoordinatePrivate* toMercator =
92 static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(c: &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(t: 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(mercator: QDoubleVector2D(x, y));
120 result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
121 return QVariant::fromValue(value: result);
122}
123
124QVariant q_coordinateWestInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
125{
126 const QGeoMercatorCoordinatePrivate* fromMercator =
127 static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(c: &from));
128 const QGeoMercatorCoordinatePrivate* toMercator =
129 static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(c: &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(mercator: QDoubleVector2D(x, y));
149 result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
150
151 return QVariant::fromValue(value: result);
152}
153
154QVariant q_coordinateEastInterpolator(const QGeoCoordinate &from, const QGeoCoordinate &to, qreal progress)
155{
156 const QGeoMercatorCoordinatePrivate* fromMercator =
157 static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(c: &from));
158 const QGeoMercatorCoordinatePrivate* toMercator =
159 static_cast<const QGeoMercatorCoordinatePrivate*>(QGeoCoordinatePrivate::get(c: &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(mercator: QDoubleVector2D(x, y));
179 result.setAltitude(from.altitude() + (to.altitude() - from.altitude()) * progress);
180
181 return QVariant::fromValue(value: result);
182}
183
184QQuickGeoCoordinateAnimation::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(interpolationType: d->interpolatorType);
192}
193
194QQuickGeoCoordinateAnimation::~QQuickGeoCoordinateAnimation()
195{
196}
197
198/*!
199 \qmlproperty coordinate CoordinateAnimation::from
200 This property holds the coordinate where the animation should begin.
201*/
202QGeoCoordinate QQuickGeoCoordinateAnimation::from() const
203{
204 Q_D(const QQuickGeoCoordinateAnimation);
205 return d->from.value<QGeoCoordinate>();
206}
207
208void QQuickGeoCoordinateAnimation::setFrom(const QGeoCoordinate &f)
209{
210 QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
211 QDoubleVector2D fromVector = QWebMercator::coordToMercator(coord: 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(value: from));
219}
220
221/*!
222 \qmlproperty coordinate CoordinateAnimation::to
223 This property holds the coordinate where the animation should end.
224*/
225QGeoCoordinate QQuickGeoCoordinateAnimation::to() const
226{
227 Q_D(const QQuickGeoCoordinateAnimation);
228 return d->to.value<QGeoCoordinate>();
229}
230
231void QQuickGeoCoordinateAnimation::setTo(const QGeoCoordinate &t)
232{
233 QGeoMercatorCoordinatePrivate *mercator = new QGeoMercatorCoordinatePrivate();
234 QDoubleVector2D toVector = QWebMercator::coordToMercator(coord: 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(value: 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
262QQuickGeoCoordinateAnimation::Direction QQuickGeoCoordinateAnimation::direction() const
263{
264 Q_D(const QQuickGeoCoordinateAnimation);
265 return d->m_direction;
266}
267
268void 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
291QQuickGeoCoordinateAnimationPrivate::QQuickGeoCoordinateAnimationPrivate():
292 m_direction(QQuickGeoCoordinateAnimation::Shortest)
293{
294}
295
296QT_END_NAMESPACE
297

source code of qtlocation/src/positioningquick/qquickgeocoordinateanimation.cpp