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