1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Jolla Ltd.
4 ** Contact: Aaron McCarthy <aaron.mccarthy@jollamobile.com>
5 ** Copyright (C) 2016 The Qt Company Ltd.
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtPositioning module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QtCore/QtNumeric>
43 #include "qdeclarativeposition_p.h"
44 #include <QtQml/qqml.h>
45 #include <qnmeapositioninfosource.h>
46 #include <QFile>
47 
48 QT_BEGIN_NAMESPACE
49 
50 /*!
51     \qmltype Position
52     //! \instantiates QDeclarativePosition
53     \inqmlmodule QtPositioning
54     \since 5.2
55 
56     \brief The Position type holds positional data at a particular point in time,
57     such as coordinate (longitude, latitude, altitude) and speed.
58 
59     The Position type holds values related to geographic location such as
60     a \l coordinate (longitude, latitude, and altitude), the \l timestamp when
61     the Position was obtained, the \l speed at that time, and the accuracy of
62     the data.
63 
64     Primarily, it is used in the \l{PositionSource::position}{position} property
65     of a \l{PositionSource}, as the basic unit of data available from the system
66     location data source.
67 
68     Not all properties of a Position object are necessarily valid or available
69     (for example latitude and longitude may be valid, but speed update has not been
70     received or set manually). As a result, corresponding "valid" properties
71     are available (for example \l{coordinate} and \l{longitudeValid}, \l{latitudeValid}
72     etc) to discern whether the data is available and valid in this position
73     update.
74 
75     Position objects are read-only and can only be produced by a PositionSource.
76 
77     \section2 Example Usage
78 
79     See the example given for the \l{PositionSource} type, or the
80     \l{geoflickr}{GeoFlickr} example application.
81 
82     \sa PositionSource, coordinate
83 */
84 
85 namespace
86 {
87 
equalOrNaN(qreal a,qreal b)88 bool equalOrNaN(qreal a, qreal b)
89 {
90     return a == b || (qIsNaN(a) && qIsNaN(b));
91 }
92 
exclusiveNaN(qreal a,qreal b)93 bool exclusiveNaN(qreal a, qreal b)
94 {
95     return qIsNaN(a) != qIsNaN(b);
96 }
97 
98 }
99 
QDeclarativePosition(QObject * parent)100 QDeclarativePosition::QDeclarativePosition(QObject *parent)
101 :   QObject(parent)
102 {
103 }
104 
~QDeclarativePosition()105 QDeclarativePosition::~QDeclarativePosition()
106 {
107 }
108 
setPosition(const QGeoPositionInfo & info)109 void QDeclarativePosition::setPosition(const QGeoPositionInfo &info)
110 {
111     // timestamp
112     const QDateTime pTimestamp = m_info.timestamp();
113     const QDateTime timestamp = info.timestamp();
114     bool emitTimestampChanged = pTimestamp != timestamp;
115 
116     // coordinate
117     const QGeoCoordinate pCoordinate = m_info.coordinate();
118     const QGeoCoordinate coordinate = info.coordinate();
119     bool emitCoordinateChanged = pCoordinate != coordinate;
120     bool emitLatitudeValidChanged = exclusiveNaN(pCoordinate.latitude(), coordinate.latitude());
121     bool emitLongitudeValidChanged = exclusiveNaN(pCoordinate.longitude(), coordinate.longitude());
122     bool emitAltitudeValidChanged = exclusiveNaN(pCoordinate.altitude(), coordinate.altitude());
123 
124     // direction
125     const qreal pDirection = m_info.attribute(QGeoPositionInfo::Direction);
126     const qreal direction = info.attribute(QGeoPositionInfo::Direction);
127     bool emitDirectionChanged = !equalOrNaN(pDirection, direction);
128     bool emitDirectionValidChanged = exclusiveNaN(pDirection, direction);
129 
130     // ground speed
131     const qreal pSpeed = m_info.attribute(QGeoPositionInfo::GroundSpeed);
132     const qreal speed = info.attribute(QGeoPositionInfo::GroundSpeed);
133     bool emitSpeedChanged = !equalOrNaN(pSpeed, speed);
134     bool emitSpeedValidChanged = exclusiveNaN(pSpeed, speed);
135 
136     // vertical speed
137     const qreal pVerticalSpeed = m_info.attribute(QGeoPositionInfo::VerticalSpeed);
138     const qreal verticalSpeed = info.attribute(QGeoPositionInfo::VerticalSpeed);
139     bool emitVerticalSpeedChanged = !equalOrNaN(pVerticalSpeed, verticalSpeed);
140     bool emitVerticalSpeedValidChanged = exclusiveNaN(pVerticalSpeed, verticalSpeed);
141 
142     // magnetic variation
143     const qreal pMagneticVariation = m_info.attribute(QGeoPositionInfo::MagneticVariation);
144     const qreal magneticVariation = info.attribute(QGeoPositionInfo::MagneticVariation);
145     bool emitMagneticVariationChanged = !equalOrNaN(pMagneticVariation, magneticVariation);
146     bool emitMagneticVariationValidChanged = exclusiveNaN(pMagneticVariation, magneticVariation);
147 
148     // horizontal accuracy
149     const qreal pHorizontalAccuracy = m_info.attribute(QGeoPositionInfo::HorizontalAccuracy);
150     const qreal horizontalAccuracy = info.attribute(QGeoPositionInfo::HorizontalAccuracy);
151     bool emitHorizontalAccuracyChanged = !equalOrNaN(pHorizontalAccuracy, horizontalAccuracy);
152     bool emitHorizontalAccuracyValidChanged = exclusiveNaN(pHorizontalAccuracy, horizontalAccuracy);
153 
154     // vertical accuracy
155     const qreal pVerticalAccuracy = m_info.attribute(QGeoPositionInfo::VerticalAccuracy);
156     const qreal verticalAccuracy = info.attribute(QGeoPositionInfo::VerticalAccuracy);
157     bool emitVerticalAccuracyChanged = !equalOrNaN(pVerticalAccuracy, verticalAccuracy);
158     bool emitVerticalAccuracyValidChanged = exclusiveNaN(pVerticalAccuracy, verticalAccuracy);
159 
160     m_info = info;
161 
162     if (emitTimestampChanged)
163         emit timestampChanged();
164     if (emitCoordinateChanged)
165         emit coordinateChanged();
166     if (emitLatitudeValidChanged)
167         emit latitudeValidChanged();
168     if (emitLongitudeValidChanged)
169         emit longitudeValidChanged();
170     if (emitAltitudeValidChanged)
171         emit altitudeValidChanged();
172     if (emitDirectionChanged)
173         emit directionChanged();
174     if (emitDirectionValidChanged)
175         emit directionValidChanged();
176     if (emitSpeedChanged)
177         emit speedChanged();
178     if (emitSpeedValidChanged)
179         emit speedValidChanged();
180     if (emitVerticalSpeedChanged)
181         emit verticalSpeedChanged();
182     if (emitVerticalSpeedValidChanged)
183         emit verticalSpeedValidChanged();
184     if (emitHorizontalAccuracyChanged)
185         emit horizontalAccuracyChanged();
186     if (emitHorizontalAccuracyValidChanged)
187         emit horizontalAccuracyValidChanged();
188     if (emitVerticalAccuracyChanged)
189         emit verticalAccuracyChanged();
190     if (emitVerticalAccuracyValidChanged)
191         emit verticalAccuracyValidChanged();
192     if (emitMagneticVariationChanged)
193         emit magneticVariationChanged();
194     if (emitMagneticVariationValidChanged)
195         emit magneticVariationValidChanged();
196 }
197 
position() const198 const QGeoPositionInfo &QDeclarativePosition::position() const
199 {
200     return m_info;
201 }
202 
203 /*!
204     \qmlproperty coordinate Position::coordinate
205 
206     This property holds the latitude, longitude, and altitude value of the Position.
207 
208     It is a read-only property.
209 
210     \sa longitudeValid, latitudeValid, altitudeValid
211 */
coordinate()212 QGeoCoordinate QDeclarativePosition::coordinate()
213 {
214     return m_info.coordinate();
215 }
216 
217 /*!
218     \qmlproperty bool Position::latitudeValid
219 
220     This property is true if coordinate's latitude has been set
221     (to indicate whether that data has been received or not, as every update
222     does not necessarily contain all data).
223 
224     \sa coordinate
225 */
isLatitudeValid() const226 bool QDeclarativePosition::isLatitudeValid() const
227 {
228     return !qIsNaN(m_info.coordinate().latitude());
229 }
230 
231 
232 /*!
233     \qmlproperty bool Position::longitudeValid
234 
235     This property is true if coordinate's longitude has been set
236     (to indicate whether that data has been received or not, as every update
237     does not necessarily contain all data).
238 
239     \sa coordinate
240 */
isLongitudeValid() const241 bool QDeclarativePosition::isLongitudeValid() const
242 {
243     return !qIsNaN(m_info.coordinate().longitude());
244 }
245 
246 
247 /*!
248     \qmlproperty bool Position::speedValid
249 
250     This property is true if \l speed has been set
251     (to indicate whether that data has been received or not, as every update
252     does not necessarily contain all data).
253 
254     \sa speed
255 */
isSpeedValid() const256 bool QDeclarativePosition::isSpeedValid() const
257 {
258     return !qIsNaN(m_info.attribute(QGeoPositionInfo::GroundSpeed));
259 }
260 
261 /*!
262     \qmlproperty bool Position::altitudeValid
263 
264     This property is true if coordinate's altitude has been set
265     (to indicate whether that data has been received or not, as every update
266     does not necessarily contain all data).
267 
268     \sa coordinate
269 */
isAltitudeValid() const270 bool QDeclarativePosition::isAltitudeValid() const
271 {
272     return !qIsNaN(m_info.coordinate().altitude());
273 }
274 
275 /*!
276     \qmlproperty double Position::speed
277 
278     This property holds the value of speed (groundspeed, meters / second).
279 
280     It is a read-only property.
281 
282     \sa speedValid, coordinate
283 */
speed() const284 double QDeclarativePosition::speed() const
285 {
286     return m_info.attribute(QGeoPositionInfo::GroundSpeed);
287 }
288 
289 /*!
290     \qmlproperty real Position::horizontalAccuracy
291 
292     This property holds the horizontal accuracy of the coordinate (in meters).
293 
294     \sa horizontalAccuracyValid, coordinate
295 */
setHorizontalAccuracy(qreal horizontalAccuracy)296 void QDeclarativePosition::setHorizontalAccuracy(qreal horizontalAccuracy)
297 {
298     const qreal pHorizontalAccuracy = m_info.attribute(QGeoPositionInfo::HorizontalAccuracy);
299 
300     if (equalOrNaN(pHorizontalAccuracy, horizontalAccuracy))
301         return;
302 
303     bool validChanged = exclusiveNaN(pHorizontalAccuracy, horizontalAccuracy);
304 
305     m_info.setAttribute(QGeoPositionInfo::HorizontalAccuracy, horizontalAccuracy);
306     emit horizontalAccuracyChanged();
307     if (validChanged)
308         emit horizontalAccuracyValidChanged();
309 }
310 
horizontalAccuracy() const311 qreal QDeclarativePosition::horizontalAccuracy() const
312 {
313     return m_info.attribute(QGeoPositionInfo::HorizontalAccuracy);
314 }
315 
316 /*!
317     \qmlproperty bool Position::horizontalAccuracyValid
318 
319     This property is true if \l horizontalAccuracy has been set
320     (to indicate whether that data has been received or not, as every update
321     does not necessarily contain all data).
322 
323     \sa horizontalAccuracy
324 */
isHorizontalAccuracyValid() const325 bool QDeclarativePosition::isHorizontalAccuracyValid() const
326 {
327     return !qIsNaN(m_info.attribute(QGeoPositionInfo::HorizontalAccuracy));
328 }
329 
330 /*!
331     \qmlproperty real Position::verticalAccuracy
332 
333     This property holds the vertical accuracy of the coordinate (in meters).
334 
335     \sa verticalAccuracyValid, coordinate
336 */
setVerticalAccuracy(qreal verticalAccuracy)337 void QDeclarativePosition::setVerticalAccuracy(qreal verticalAccuracy)
338 {
339     const qreal pVerticalAccuracy = m_info.attribute(QGeoPositionInfo::VerticalAccuracy);
340 
341     if (equalOrNaN(pVerticalAccuracy, verticalAccuracy))
342         return;
343 
344     bool validChanged = exclusiveNaN(pVerticalAccuracy, verticalAccuracy);
345 
346     m_info.setAttribute(QGeoPositionInfo::VerticalAccuracy, verticalAccuracy);
347     emit verticalAccuracyChanged();
348     if (validChanged)
349         emit verticalAccuracyValidChanged();
350 }
351 
verticalAccuracy() const352 qreal QDeclarativePosition::verticalAccuracy() const
353 {
354     return m_info.attribute(QGeoPositionInfo::VerticalAccuracy);
355 }
356 
357 /*!
358     \qmlproperty bool Position::verticalAccuracyValid
359 
360     This property is true if \l verticalAccuracy has been set
361     (to indicate whether that data has been received or not, as every update
362     does not necessarily contain all data).
363 
364     \sa verticalAccuracy
365 */
isVerticalAccuracyValid() const366 bool QDeclarativePosition::isVerticalAccuracyValid() const
367 {
368     return !qIsNaN(m_info.attribute(QGeoPositionInfo::VerticalAccuracy));
369 }
370 
371 /*!
372     \qmlproperty date Position::timestamp
373 
374     This property holds the timestamp when this position
375     was received. If the property has not been set, it is invalid.
376 
377     It is a read-only property.
378 */
timestamp() const379 QDateTime QDeclarativePosition::timestamp() const
380 {
381     return m_info.timestamp();
382 }
383 
384 /*!
385     \qmlproperty bool Position::directionValid
386     \since Qt Positioning 5.3
387 
388     This property is true if \l direction has been set (to indicate whether that data has been
389     received or not, as every update does not necessarily contain all data).
390 
391     \sa direction
392 */
isDirectionValid() const393 bool QDeclarativePosition::isDirectionValid() const
394 {
395     return !qIsNaN(m_info.attribute(QGeoPositionInfo::Direction));
396 }
397 
398 /*!
399     \qmlproperty double Position::direction
400     \since Qt Positioning 5.3
401 
402     This property holds the value of the direction of travel in degrees from true north.
403 
404     It is a read-only property.
405 
406     \sa directionValid
407 */
direction() const408 double QDeclarativePosition::direction() const
409 {
410     return m_info.attribute(QGeoPositionInfo::Direction);
411 }
412 
413 /*!
414     \qmlproperty bool Position::verticalSpeedValid
415     \since Qt Positioning 5.3
416 
417     This property is true if \l verticalSpeed has been set (to indicate whether that data has been
418     received or not, as every update does not necessarily contain all data).
419 
420     \sa verticalSpeed
421 */
isVerticalSpeedValid() const422 bool QDeclarativePosition::isVerticalSpeedValid() const
423 {
424     return !qIsNaN(m_info.attribute(QGeoPositionInfo::VerticalSpeed));
425 }
426 
427 /*!
428     \qmlproperty double Position::verticalSpeed
429     \since Qt Positioning 5.3
430 
431     This property holds the value of the vertical speed in meters per second.
432 
433     It is a read-only property.
434 
435     \sa verticalSpeedValid
436 */
verticalSpeed() const437 double QDeclarativePosition::verticalSpeed() const
438 {
439     return m_info.attribute(QGeoPositionInfo::VerticalSpeed);
440 }
441 
442 /*!
443     \qmlproperty bool Position::magneticVariationValid
444     \since Qt Positioning 5.4
445 
446     This property is true if \l magneticVariation has been set (to indicate whether that data has been
447     received or not, as every update does not necessarily contain all data).
448 
449     \sa magneticVariation
450 */
isMagneticVariationValid() const451 bool QDeclarativePosition::isMagneticVariationValid() const
452 {
453     return !qIsNaN(m_info.attribute(QGeoPositionInfo::MagneticVariation));
454 }
455 
456 /*!
457     \qmlproperty double Position::magneticVariation
458     \since Qt Positioning 5.4
459 
460     This property holds the angle between the horizontal component of the
461     magnetic field and true north, in degrees. Also known as magnetic
462     declination. A positive value indicates a clockwise direction from
463     true north and a negative value indicates a counter-clockwise direction.
464 
465     It is a read-only property.
466 
467     \sa magneticVariationValid
468 */
magneticVariation() const469 double QDeclarativePosition::magneticVariation() const
470 {
471     return m_info.attribute(QGeoPositionInfo::MagneticVariation);
472 }
473 
474 QT_END_NAMESPACE
475