You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
7.7KB

  1. /*
  2. Misc GPS (text to data) parsers.
  3. Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include "jeeps/gpsmath.h"
  18. #include <math.h>
  19. #include <stdio.h>
  20. #include <stdlib.h> //strtod
  21. /*
  22. * parse_distance:
  23. *
  24. * str: input string, i.e. "128.2 km" or "22mi"
  25. * val: pointer to resulting value
  26. * scale: scaling parameter for unit-less values
  27. * module: calling module, i.e. "garmin_txt"
  28. */
  29. int
  30. parse_distance(const char* str, double* val, double scale, const char* module)
  31. {
  32. char* unit;
  33. if ((str == NULL) || (*str == '\0')) {
  34. return 0;
  35. }
  36. *val = strtod(str, &unit);
  37. if (unit == NULL) {
  38. fatal("%s: Unconvertable numeric value (%s)!\n", module, str);
  39. }
  40. if (fabs(*val) + 1 >= 1.0e25) {
  41. return 0; /* not only Garmin uses this as 'unknown value' */
  42. }
  43. while (isspace(*unit)) {
  44. unit++;
  45. }
  46. if (*unit == '\0') {
  47. *val *= scale;
  48. return 1;
  49. }
  50. if (case_ignore_strcmp(unit, "m") == 0) /* do nothing, that's our standard */;
  51. else if (case_ignore_strcmp(unit, "ft") == 0) {
  52. *val = FEET_TO_METERS(*val);
  53. } else if (case_ignore_strcmp(unit, "feet") == 0) {
  54. *val = FEET_TO_METERS(*val);
  55. } else if (case_ignore_strcmp(unit, "k") == 0) {
  56. *val *= 1000.0;
  57. } else if (case_ignore_strcmp(unit, "km") == 0) {
  58. *val *= 1000.0;
  59. } else if (case_ignore_strcmp(unit, "nm") == 0) {
  60. *val = NMILES_TO_METERS(*val);
  61. } else if (case_ignore_strcmp(unit, "mi") == 0) {
  62. *val = MILES_TO_METERS(*val);
  63. } else if (case_ignore_strcmp(unit, "fa") == 0) {
  64. *val = FATHOMS_TO_METERS(*val);
  65. } else {
  66. fatal("%s: Unsupported distance unit in item '%s'!\n", module, str);
  67. }
  68. return 2;
  69. }
  70. int
  71. parse_distance(const QString& str, double* val, double scale, const char* module) {
  72. return parse_distance(CSTR(str), val, scale, module);
  73. }
  74. /*
  75. * parse_speed:
  76. *
  77. * str: input string, i.e. "22.3 km/h" or "40mph"
  78. * val: pointer to resulting value
  79. * scale: scaling parameter for unit-less values
  80. * module: calling module, i.e. "garmin_txt"
  81. */
  82. int
  83. parse_speed(const char* str, double* val, const double scale, const char* module)
  84. {
  85. char* unit;
  86. if ((str == NULL) || (*str == '\0')) {
  87. return 0;
  88. }
  89. *val = strtod(str, &unit);
  90. if (unit == NULL) {
  91. fatal("%s: Unconvertable numeric value (%s)!\n", module, str);
  92. }
  93. while (isspace(*unit)) {
  94. unit++;
  95. }
  96. if (*unit == '\0') {
  97. *val *= scale;
  98. return 1;
  99. }
  100. if (case_ignore_strcmp(unit, "m/s") == 0) ;
  101. else if (case_ignore_strcmp(unit, "mps") == 0) ;
  102. else if (case_ignore_strcmp(unit, "kph") == 0) {
  103. *val = KPH_TO_MPS(*val);
  104. } else if (case_ignore_strcmp(unit, "km/h") == 0) {
  105. *val = KPH_TO_MPS(*val);
  106. } else if (case_ignore_strcmp(unit, "kmh") == 0) {
  107. *val = KPH_TO_MPS(*val);
  108. } else if (case_ignore_strcmp(unit, "kt") == 0) {
  109. *val = KNOTS_TO_MPS(*val);
  110. } else if (case_ignore_strcmp(unit, "knot") == 0) {
  111. *val = KNOTS_TO_MPS(*val);
  112. } else if (case_ignore_strcmp(unit, "mph") == 0) {
  113. *val = MPH_TO_MPS(*val);
  114. } else if (case_ignore_strcmp(unit, "mi/h") == 0) {
  115. *val = MPH_TO_MPS(*val);
  116. } else if (case_ignore_strcmp(unit, "mih") == 0) {
  117. *val = MPH_TO_MPS(*val);
  118. } else {
  119. warning("%s: Unsupported speed unit '%s' in item '%s'!\n", module, unit, str);
  120. }
  121. return 2;
  122. }
  123. int
  124. parse_speed(const QString& str, double* val, const double scale, const char* module)
  125. {
  126. return parse_speed(CSTR(str), val, scale, module);
  127. }
  128. /*
  129. * Convert string 'str' into geodetic latitide & longitude values. The format
  130. * will be interpreted depending on 'grid' parameter.
  131. *
  132. * return value: number of characters efective parsed
  133. */
  134. int
  135. parse_coordinates(const char* str, int datum, const grid_type grid,
  136. double* latitude, double* longitude, const char* module)
  137. {
  138. double lat, lon;
  139. unsigned char lathemi=0, lonhemi=0;
  140. int deg_lat, deg_lon, min_lat, min_lon;
  141. char map[3];
  142. int utmz;
  143. double utme, utmn;
  144. char utmc;
  145. int valid, result, ct;
  146. double lx, ly;
  147. const char* format;
  148. valid = 1;
  149. switch (grid) {
  150. case grid_lat_lon_ddd:
  151. format = "%c%lf %c%lf%n";
  152. ct = sscanf(str, format,
  153. &lathemi, &lat, &lonhemi, &lon, &result);
  154. valid = (ct == 4);
  155. break;
  156. case grid_lat_lon_dmm:
  157. format = "%c%d %lf %c%d %lf%n";
  158. ct = sscanf(str, format,
  159. &lathemi, &deg_lat, &lat, &lonhemi, &deg_lon, &lon, &result);
  160. valid = (ct == 6);
  161. if (valid) {
  162. lat = (double)deg_lat + (lat / (double)60);
  163. lon = (double)deg_lon + (lon / (double)60);
  164. }
  165. break;
  166. case grid_lat_lon_dms:
  167. format = "%c%d %d %lf %c%d %d %lf%n";
  168. ct = sscanf(str, format,
  169. &lathemi, &deg_lat, &min_lat, &lat, &lonhemi, &deg_lon, &min_lon, &lon,
  170. &result);
  171. valid = (ct == 8);
  172. if (valid) {
  173. lat = (double)deg_lat + ((double)min_lat / (double)60) + (lat / (double)3600.0);
  174. lon = (double)deg_lon + ((double)min_lon / (double)60) + (lon / (double)3600.0);
  175. }
  176. break;
  177. case grid_bng:
  178. datum = DATUM_WGS84; /* fix */
  179. format = "%2s %lf %lf%n";
  180. ct = sscanf(str, format,
  181. map, &lx, &ly,
  182. &result);
  183. valid = (ct == 3);
  184. if (valid) {
  185. if (! GPS_Math_UKOSMap_To_WGS84_M(map, lx, ly, &lat, &lon))
  186. fatal("%s: Unable to convert BNG coordinates (%s)!\n",
  187. module, str);
  188. }
  189. lathemi = lonhemi = '\0';
  190. break;
  191. case grid_utm:
  192. format = "%d %c %lf %lf%n";
  193. ct = sscanf(str, format,
  194. &utmz, &utmc, &utme, &utmn,
  195. &result);
  196. valid = (ct == 4);
  197. if (valid) {
  198. if (! GPS_Math_UTM_EN_To_Known_Datum(&lat, &lon, utme, utmn, utmz, utmc, datum))
  199. fatal("%s: Unable to convert UTM coordinates (%s)!\n",
  200. module, str);
  201. }
  202. lathemi = lonhemi = '\0';
  203. break;
  204. case grid_swiss: {
  205. double east, north;
  206. datum = DATUM_WGS84; /* fix */
  207. format = "%lf %lf%n";
  208. ct = sscanf(str, format,
  209. &east, &north, &result);
  210. valid = (ct == 2);
  211. GPS_Math_Swiss_EN_To_WGS84(east, north, &lat, &lon);
  212. break;
  213. }
  214. default:
  215. /* this should never happen in a release version */
  216. fatal("%s/util: Unknown grid in parse_coordinates (%d)!\n",
  217. module, (int)grid);
  218. }
  219. if (! valid) {
  220. warning("%s: sscanf error using format \"%s\"!\n", module, format);
  221. warning("%s: parsing has stopped at parameter number %d.\n", module, ct);
  222. fatal("%s: could not convert coordinates \"%s\"!\n", module, str);
  223. }
  224. if (lathemi == 'S') {
  225. lat = -lat;
  226. }
  227. if (lonhemi == 'W') {
  228. lon = -lon;
  229. }
  230. if (datum != DATUM_WGS84) {
  231. double alt;
  232. GPS_Math_Known_Datum_To_WGS84_M(lat, lon, (double) 0.0,
  233. &lat, &lon, &alt, datum);
  234. }
  235. if (latitude) {
  236. *latitude = lat;
  237. }
  238. if (longitude) {
  239. *longitude = lon;
  240. }
  241. return result;
  242. }
  243. int
  244. parse_coordinates(const QString& str, int datum, const grid_type grid,
  245. double* latitude, double* longitude, const char* module)
  246. {
  247. return parse_coordinates(CSTR(str), datum, grid,
  248. latitude, longitude, module);
  249. }