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#ifndef QLOCATIONUTILS_P_H
40#define QLOCATIONUTILS_P_H
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists purely as an
47// implementation detail. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51//
52
53#include <QtCore/QtGlobal>
54#include <math.h> // needed for non-std:: versions of functions
55#include <qmath.h>
56#include <QtPositioning/QGeoCoordinate>
57#include <QtPositioning/private/qpositioningglobal_p.h>
58
59static const double offsetEpsilon = 1e-12; // = 0.000000000001
60static const double leftOffset = -180.0 + offsetEpsilon;
61static const double rightOffset = 180.0 - offsetEpsilon;
62
63QT_BEGIN_NAMESPACE
64class QTime;
65class QByteArray;
66
67class QGeoPositionInfo;
68class QGeoSatelliteInfo;
69class Q_POSITIONING_PRIVATE_EXPORT QLocationUtils
70{
71public:
72 enum CardinalDirection {
73 CardinalN,
74 CardinalE,
75 CardinalS,
76 CardinalW,
77 CardinalNE,
78 CardinalSE,
79 CardinalSW,
80 CardinalNW,
81 CardinalNNE,
82 CardinalENE,
83 CardinalESE,
84 CardinalSSE,
85 CardinalSSW,
86 CardinalWSW,
87 CardinalWNW,
88 CardinalNNW
89 };
90
91 enum NmeaSentence {
92 NmeaSentenceInvalid,
93 NmeaSentenceGGA, // Fix information
94 NmeaSentenceGSA, // Overall Satellite data, such as HDOP and VDOP
95 NmeaSentenceGLL, // Lat/Lon data
96 NmeaSentenceRMC, // Recommended minimum data for gps
97 NmeaSentenceVTG, // Vector track an Speed over the Ground
98 NmeaSentenceZDA, // Date and Time
99 NmeaSentenceGSV // Per-Satellite Info
100 };
101
102 inline static bool isValidLat(double lat) {
103 return lat >= -90.0 && lat <= 90.0;
104 }
105 inline static bool isValidLong(double lng) {
106 return lng >= -180.0 && lng <= 180.0;
107 }
108
109 inline static double clipLat(double lat, double clipValue = 90.0) {
110 if (lat > clipValue)
111 lat = clipValue;
112 else if (lat < -clipValue)
113 lat = -clipValue;
114 return lat;
115 }
116
117 inline static double wrapLong(double lng) {
118 if (lng > 180.0)
119 lng -= 360.0;
120 else if (lng < -180.0)
121 lng += 360.0;
122 return lng;
123 }
124
125 inline static CardinalDirection azimuthToCardinalDirection4(double azimuth)
126 {
127 azimuth = fmod(x: azimuth, y: 360.0);
128 if (azimuth < 45.0 || azimuth > 315.0 )
129 return CardinalN;
130 else if (azimuth < 135.0)
131 return CardinalE;
132 else if (azimuth < 225.0)
133 return CardinalS;
134 else
135 return CardinalW;
136 }
137
138 inline static CardinalDirection azimuthToCardinalDirection8(double azimuth)
139 {
140 azimuth = fmod(x: azimuth, y: 360.0);
141 if (azimuth < 22.5 || azimuth > 337.5 )
142 return CardinalN;
143 else if (azimuth < 67.5)
144 return CardinalNE;
145 else if (azimuth < 112.5)
146 return CardinalE;
147 else if (azimuth < 157.5)
148 return CardinalSE;
149 else if (azimuth < 202.5)
150 return CardinalS;
151
152 else if (azimuth < 247.5)
153 return CardinalSW;
154 else if (azimuth < 292.5)
155 return CardinalW;
156 else
157 return CardinalNW;
158 }
159
160 inline static CardinalDirection azimuthToCardinalDirection16(double azimuth)
161 {
162 azimuth = fmod(x: azimuth, y: 360.0);
163 if (azimuth < 11.5 || azimuth > 348.75 )
164 return CardinalN;
165 else if (azimuth < 33.75)
166 return CardinalNNE;
167 else if (azimuth < 56.25)
168 return CardinalNE;
169 else if (azimuth < 78.75)
170 return CardinalENE;
171 else if (azimuth < 101.25)
172 return CardinalE;
173 else if (azimuth < 123.75)
174 return CardinalESE;
175 else if (azimuth < 146.25)
176 return CardinalSE;
177 else if (azimuth < 168.75)
178 return CardinalSSE;
179 else if (azimuth < 191.25)
180 return CardinalS;
181
182 else if (azimuth < 213.75)
183 return CardinalSSW;
184 else if (azimuth < 236.25)
185 return CardinalSW;
186 else if (azimuth < 258.75)
187 return CardinalWSW;
188 else if (azimuth < 281.25)
189 return CardinalW;
190 else if (azimuth < 303.75)
191 return CardinalWNW;
192 else if (azimuth < 326.25)
193 return CardinalNW;
194 else
195 return CardinalNNW;
196 }
197
198 // For values exceeding +- 720.0
199 inline static double wrapLongExt(double lng) {
200 double remainder = fmod(x: lng + 180.0, y: 360.0);
201 return fmod(x: remainder + 360.0, y: 360.0) - 180.0;
202 }
203
204 // Mirrors the azimuth against the X axis. Azimuth assumed to be in [0,360[
205 inline static double mirrorAzimuthX(double azimuth) {
206 if (azimuth <= 90.0)
207 return 180.0 - azimuth;
208 else
209 return 180.0 + (360.0 - azimuth);
210 }
211
212 // Mirrors the azimuth against the Y axis. Azimuth assumed to be in [0,360[
213 inline static double mirrorAzimuthY(double azimuth) {
214 if (azimuth == 0.0)
215 return 0.0;
216 return 360.0 - azimuth;
217 }
218
219 inline static double radians(double degrees)
220 {
221 return qDegreesToRadians(degrees);
222 }
223
224 inline static double degrees(double radians)
225 {
226 return qRadiansToDegrees(radians);
227 }
228
229 inline static double earthMeanRadius()
230 {
231 return 6371007.2;
232 }
233
234 inline static double earthMeanCircumference()
235 {
236 return earthMeanRadius() * 2.0 * M_PI;
237 }
238
239 inline static double mercatorMaxLatitude()
240 {
241 return 85.05113;
242 }
243
244 inline static QGeoCoordinate antipodalPoint(const QGeoCoordinate &p)
245 {
246 return QGeoCoordinate(-p.latitude(), wrapLong(lng: p.longitude() + 180.0));
247 }
248
249 // Leftmost longitude before wrapping kicks in
250 inline static double mapLeftLongitude(double centerLongitude)
251 {
252 return wrapLong(lng: centerLongitude + leftOffset);
253 }
254
255 // Rightmost longitude before wrapping kicks in
256 inline static double mapRightLongitude(double centerLongitude)
257 {
258 return wrapLong(lng: centerLongitude - leftOffset);
259 }
260
261 inline static void split_double(double input, float *hipart, float *lopart)
262 {
263 *hipart = (float) input;
264 double delta = input - ((double) *hipart);
265 *lopart = (float) delta;
266 }
267
268 static qreal metersPerPixel(qreal zoomLevel, const QGeoCoordinate &coordinate)
269 {
270 const qreal metersPerTile = earthMeanCircumference() * std::cos(x: radians(degrees: coordinate.latitude())) / std::pow(x: 2, y: zoomLevel);
271 return metersPerTile / 256.0;
272 }
273
274 /*
275 returns the NMEA sentence type.
276 */
277 static NmeaSentence getNmeaSentenceType(const char *data, int size);
278
279 /*
280 Creates a QGeoPositionInfo from a GGA, GLL, RMC, VTG or ZDA sentence.
281
282 Note:
283 - GGA and GLL sentences have time but not date so the update's
284 QDateTime object will have an invalid date.
285 - RMC reports date with a two-digit year so in this case the year
286 is assumed to be after the year 2000.
287 */
288 static bool getPosInfoFromNmea(const char *data,
289 int size,
290 QGeoPositionInfo *info, double uere,
291 bool *hasFix = nullptr);
292
293 /*
294 Retruns a list of QGeoSatelliteInfo in the view.
295
296 Note: this function has to be called repeatedly until it returns true.
297 Reason being that GSV sentences can be split into multiple samples, so getting the full data
298 requires parsing multiple sentences.
299 */
300 enum GSVParseStatus {
301 GSVNotParsed,
302 GSVPartiallyParsed,
303 GSVFullyParsed
304 };
305 static GSVParseStatus getSatInfoFromNmea(const char *data,
306 int size,
307 QList<QGeoSatelliteInfo> &infos);
308
309 /*
310 Parses GSA for satellites in use.
311 */
312 static bool getSatInUseFromNmea(const char *data,
313 int size,
314 QList<int> &pnrsInUse);
315
316 /*
317 Returns true if the given NMEA sentence has a valid checksum.
318 */
319 static bool hasValidNmeaChecksum(const char *data, int size);
320
321 /*
322 Returns time from a string in hhmmss or hhmmss.z+ format.
323 */
324 static bool getNmeaTime(const QByteArray &bytes, QTime *time);
325
326 /*
327 Accepts for example ("2734.7964", 'S', "15306.0124", 'E') and returns the
328 lat-long values. Fails if lat or long fail isValidLat() or isValidLong().
329 */
330 static bool getNmeaLatLong(const QByteArray &latString,
331 char latDirection,
332 const QByteArray &lngString,
333 char lngDirection,
334 double *lat,
335 double *lon);
336};
337
338QT_END_NAMESPACE
339
340#endif
341

source code of qtlocation/src/positioning/qlocationutils_p.h