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
48QT_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
85namespace
86{
87
88bool equalOrNaN(qreal a, qreal b)
89{
90 return a == b || (qIsNaN(d: a) && qIsNaN(d: b));
91}
92
93bool exclusiveNaN(qreal a, qreal b)
94{
95 return qIsNaN(d: a) != qIsNaN(d: b);
96}
97
98}
99
100QDeclarativePosition::QDeclarativePosition(QObject *parent)
101: QObject(parent)
102{
103}
104
105QDeclarativePosition::~QDeclarativePosition()
106{
107}
108
109void 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(a: pCoordinate.latitude(), b: coordinate.latitude());
121 bool emitLongitudeValidChanged = exclusiveNaN(a: pCoordinate.longitude(), b: coordinate.longitude());
122 bool emitAltitudeValidChanged = exclusiveNaN(a: pCoordinate.altitude(), b: coordinate.altitude());
123
124 // direction
125 const qreal pDirection = m_info.attribute(attribute: QGeoPositionInfo::Direction);
126 const qreal direction = info.attribute(attribute: QGeoPositionInfo::Direction);
127 bool emitDirectionChanged = !equalOrNaN(a: pDirection, b: direction);
128 bool emitDirectionValidChanged = exclusiveNaN(a: pDirection, b: direction);
129
130 // ground speed
131 const qreal pSpeed = m_info.attribute(attribute: QGeoPositionInfo::GroundSpeed);
132 const qreal speed = info.attribute(attribute: QGeoPositionInfo::GroundSpeed);
133 bool emitSpeedChanged = !equalOrNaN(a: pSpeed, b: speed);
134 bool emitSpeedValidChanged = exclusiveNaN(a: pSpeed, b: speed);
135
136 // vertical speed
137 const qreal pVerticalSpeed = m_info.attribute(attribute: QGeoPositionInfo::VerticalSpeed);
138 const qreal verticalSpeed = info.attribute(attribute: QGeoPositionInfo::VerticalSpeed);
139 bool emitVerticalSpeedChanged = !equalOrNaN(a: pVerticalSpeed, b: verticalSpeed);
140 bool emitVerticalSpeedValidChanged = exclusiveNaN(a: pVerticalSpeed, b: verticalSpeed);
141
142 // magnetic variation
143 const qreal pMagneticVariation = m_info.attribute(attribute: QGeoPositionInfo::MagneticVariation);
144 const qreal magneticVariation = info.attribute(attribute: QGeoPositionInfo::MagneticVariation);
145 bool emitMagneticVariationChanged = !equalOrNaN(a: pMagneticVariation, b: magneticVariation);
146 bool emitMagneticVariationValidChanged = exclusiveNaN(a: pMagneticVariation, b: magneticVariation);
147
148 // horizontal accuracy
149 const qreal pHorizontalAccuracy = m_info.attribute(attribute: QGeoPositionInfo::HorizontalAccuracy);
150 const qreal horizontalAccuracy = info.attribute(attribute: QGeoPositionInfo::HorizontalAccuracy);
151 bool emitHorizontalAccuracyChanged = !equalOrNaN(a: pHorizontalAccuracy, b: horizontalAccuracy);
152 bool emitHorizontalAccuracyValidChanged = exclusiveNaN(a: pHorizontalAccuracy, b: horizontalAccuracy);
153
154 // vertical accuracy
155 const qreal pVerticalAccuracy = m_info.attribute(attribute: QGeoPositionInfo::VerticalAccuracy);
156 const qreal verticalAccuracy = info.attribute(attribute: QGeoPositionInfo::VerticalAccuracy);
157 bool emitVerticalAccuracyChanged = !equalOrNaN(a: pVerticalAccuracy, b: verticalAccuracy);
158 bool emitVerticalAccuracyValidChanged = exclusiveNaN(a: pVerticalAccuracy, b: 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
198const 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*/
212QGeoCoordinate 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*/
226bool QDeclarativePosition::isLatitudeValid() const
227{
228 return !qIsNaN(d: 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*/
241bool QDeclarativePosition::isLongitudeValid() const
242{
243 return !qIsNaN(d: 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*/
256bool QDeclarativePosition::isSpeedValid() const
257{
258 return !qIsNaN(d: m_info.attribute(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*/
270bool QDeclarativePosition::isAltitudeValid() const
271{
272 return !qIsNaN(d: 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*/
284double QDeclarativePosition::speed() const
285{
286 return m_info.attribute(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*/
296void QDeclarativePosition::setHorizontalAccuracy(qreal horizontalAccuracy)
297{
298 const qreal pHorizontalAccuracy = m_info.attribute(attribute: QGeoPositionInfo::HorizontalAccuracy);
299
300 if (equalOrNaN(a: pHorizontalAccuracy, b: horizontalAccuracy))
301 return;
302
303 bool validChanged = exclusiveNaN(a: pHorizontalAccuracy, b: horizontalAccuracy);
304
305 m_info.setAttribute(attribute: QGeoPositionInfo::HorizontalAccuracy, value: horizontalAccuracy);
306 emit horizontalAccuracyChanged();
307 if (validChanged)
308 emit horizontalAccuracyValidChanged();
309}
310
311qreal QDeclarativePosition::horizontalAccuracy() const
312{
313 return m_info.attribute(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*/
325bool QDeclarativePosition::isHorizontalAccuracyValid() const
326{
327 return !qIsNaN(d: m_info.attribute(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*/
337void QDeclarativePosition::setVerticalAccuracy(qreal verticalAccuracy)
338{
339 const qreal pVerticalAccuracy = m_info.attribute(attribute: QGeoPositionInfo::VerticalAccuracy);
340
341 if (equalOrNaN(a: pVerticalAccuracy, b: verticalAccuracy))
342 return;
343
344 bool validChanged = exclusiveNaN(a: pVerticalAccuracy, b: verticalAccuracy);
345
346 m_info.setAttribute(attribute: QGeoPositionInfo::VerticalAccuracy, value: verticalAccuracy);
347 emit verticalAccuracyChanged();
348 if (validChanged)
349 emit verticalAccuracyValidChanged();
350}
351
352qreal QDeclarativePosition::verticalAccuracy() const
353{
354 return m_info.attribute(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*/
366bool QDeclarativePosition::isVerticalAccuracyValid() const
367{
368 return !qIsNaN(d: m_info.attribute(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*/
379QDateTime 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*/
393bool QDeclarativePosition::isDirectionValid() const
394{
395 return !qIsNaN(d: m_info.attribute(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*/
408double QDeclarativePosition::direction() const
409{
410 return m_info.attribute(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*/
422bool QDeclarativePosition::isVerticalSpeedValid() const
423{
424 return !qIsNaN(d: m_info.attribute(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*/
437double QDeclarativePosition::verticalSpeed() const
438{
439 return m_info.attribute(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*/
451bool QDeclarativePosition::isMagneticVariationValid() const
452{
453 return !qIsNaN(d: m_info.attribute(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*/
469double QDeclarativePosition::magneticVariation() const
470{
471 return m_info.attribute(attribute: QGeoPositionInfo::MagneticVariation);
472}
473
474QT_END_NAMESPACE
475

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