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 
59 static const double offsetEpsilon = 1e-12; // = 0.000000000001
60 static const double leftOffset = -180.0 + offsetEpsilon;
61 static const double rightOffset = 180.0 - offsetEpsilon;
62 
63 QT_BEGIN_NAMESPACE
64 class QTime;
65 class QByteArray;
66 
67 class QGeoPositionInfo;
68 class QGeoSatelliteInfo;
69 class Q_POSITIONING_PRIVATE_EXPORT QLocationUtils
70 {
71 public:
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 
isValidLat(double lat)102     inline static bool isValidLat(double lat) {
103         return lat >= -90.0 && lat <= 90.0;
104     }
isValidLong(double lng)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 
wrapLong(double lng)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 
azimuthToCardinalDirection4(double azimuth)125     inline static CardinalDirection azimuthToCardinalDirection4(double azimuth)
126     {
127         azimuth = fmod(azimuth, 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 
azimuthToCardinalDirection8(double azimuth)138     inline static CardinalDirection azimuthToCardinalDirection8(double azimuth)
139     {
140         azimuth = fmod(azimuth, 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 
azimuthToCardinalDirection16(double azimuth)160     inline static CardinalDirection azimuthToCardinalDirection16(double azimuth)
161     {
162         azimuth = fmod(azimuth, 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
wrapLongExt(double lng)199     inline static double wrapLongExt(double lng) {
200         double remainder = fmod(lng + 180.0, 360.0);
201         return fmod(remainder + 360.0, 360.0) - 180.0;
202     }
203 
204     // Mirrors the azimuth against the X axis. Azimuth assumed to be in [0,360[
mirrorAzimuthX(double azimuth)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[
mirrorAzimuthY(double azimuth)213     inline static double mirrorAzimuthY(double azimuth) {
214         if (azimuth == 0.0)
215             return 0.0;
216         return 360.0 - azimuth;
217     }
218 
radians(double degrees)219     inline static double radians(double degrees)
220     {
221         return qDegreesToRadians(degrees);
222     }
223 
degrees(double radians)224     inline static double degrees(double radians)
225     {
226         return qRadiansToDegrees(radians);
227     }
228 
earthMeanRadius()229     inline static double earthMeanRadius()
230     {
231         return 6371007.2;
232     }
233 
earthMeanCircumference()234     inline static double earthMeanCircumference()
235     {
236         return earthMeanRadius() * 2.0 * M_PI;
237     }
238 
mercatorMaxLatitude()239     inline static double mercatorMaxLatitude()
240     {
241         return 85.05113;
242     }
243 
antipodalPoint(const QGeoCoordinate & p)244     inline static QGeoCoordinate antipodalPoint(const QGeoCoordinate &p)
245     {
246         return QGeoCoordinate(-p.latitude(), wrapLong(p.longitude() + 180.0));
247     }
248 
249     // Leftmost longitude before wrapping kicks in
mapLeftLongitude(double centerLongitude)250     inline static double mapLeftLongitude(double centerLongitude)
251     {
252         return wrapLong(centerLongitude + leftOffset);
253     }
254 
255     // Rightmost longitude before wrapping kicks in
mapRightLongitude(double centerLongitude)256     inline static double  mapRightLongitude(double centerLongitude)
257     {
258         return wrapLong(centerLongitude - leftOffset);
259     }
260 
split_double(double input,float * hipart,float * lopart)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 
metersPerPixel(qreal zoomLevel,const QGeoCoordinate & coordinate)268     static qreal metersPerPixel(qreal zoomLevel, const QGeoCoordinate &coordinate)
269     {
270         const qreal metersPerTile = earthMeanCircumference() * std::cos(radians(coordinate.latitude())) / std::pow(2, 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 
338 QT_END_NAMESPACE
339 
340 #endif
341