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 | |
88 | bool equalOrNaN(qreal a, qreal b) |
89 | { |
90 | return a == b || (qIsNaN(d: a) && qIsNaN(d: b)); |
91 | } |
92 | |
93 | bool exclusiveNaN(qreal a, qreal b) |
94 | { |
95 | return qIsNaN(d: a) != qIsNaN(d: b); |
96 | } |
97 | |
98 | } |
99 | |
100 | QDeclarativePosition::QDeclarativePosition(QObject *parent) |
101 | : QObject(parent) |
102 | { |
103 | } |
104 | |
105 | QDeclarativePosition::~QDeclarativePosition() |
106 | { |
107 | } |
108 | |
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(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 | |
198 | 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 | */ |
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 | */ |
226 | bool 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 | */ |
241 | bool 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 | */ |
256 | bool 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 | */ |
270 | bool 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 | */ |
284 | double 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 | */ |
296 | void 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 | |
311 | qreal 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 | */ |
325 | bool 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 | */ |
337 | void 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 | |
352 | qreal 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 | */ |
366 | bool 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 | */ |
379 | 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 | */ |
393 | bool 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 | */ |
408 | double 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 | */ |
422 | bool 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 | */ |
437 | double 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 | */ |
451 | bool 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 | */ |
469 | double QDeclarativePosition::magneticVariation() const |
470 | { |
471 | return m_info.attribute(attribute: QGeoPositionInfo::MagneticVariation); |
472 | } |
473 | |
474 | QT_END_NAMESPACE |
475 | |