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.

394 lines
7.9KB

  1. /*
  2. Support for SkymapII / SkymapIIIC & KMD150 ascii files
  3. Copyright (C) 2008 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 <math.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #define MYNAME "skyforce"
  21. static
  22. arglist_t skyforce_args[] = {
  23. ARG_TERMINATOR
  24. };
  25. static gbfile* fin, *fout;
  26. static int rte_num, wpt_num;
  27. static short_handle short_h;
  28. static const Waypoint* prev_wpt;
  29. static Waypoint*
  30. skyforce_parse_coords(const char* str)
  31. {
  32. Waypoint* wpt;
  33. if (strlen(str) < 38) {
  34. fatal(MYNAME ": Incomplete line!\n");
  35. }
  36. wpt = new Waypoint;
  37. wpt->latitude = atof(str + 21);
  38. if (str[20] == 'S') {
  39. wpt->latitude = -wpt->latitude;
  40. }
  41. wpt->latitude = ddmm2degrees(wpt->latitude);
  42. wpt->longitude = atof(str + 30);
  43. if (str[29] == 'W') {
  44. wpt->longitude = -wpt->longitude;
  45. }
  46. wpt->longitude = ddmm2degrees(wpt->longitude);
  47. return wpt;
  48. }
  49. static Waypoint*
  50. skyforce_parse_wpt(const char* str, int* rte_num)
  51. {
  52. Waypoint* wpt;
  53. wpt = skyforce_parse_coords(str);
  54. if (wpt == NULL) {
  55. return NULL;
  56. }
  57. // The line has fixed columns and starts like:
  58. // R 001 029 BEARHILL N42...
  59. // Grab "BEARHILL" and whack trailing space.
  60. wpt->shortname = QString(str).mid(10,9).trimmed();
  61. if (rte_num) {
  62. *rte_num = atoi(str + 2);
  63. }
  64. return wpt;
  65. }
  66. static Waypoint*
  67. skyforce_parse_trk(const char* str)
  68. {
  69. char buf[15];
  70. int len;
  71. Waypoint* wpt;
  72. wpt = skyforce_parse_coords(str);
  73. if (wpt == NULL) {
  74. return NULL;
  75. }
  76. strncpy(buf, str + 2, sizeof(buf) - 1);
  77. buf[14] = 0;
  78. QDateTime dt = QDateTime::fromString(buf, "ddMMyy hhmmss");
  79. dt.setTimeSpec(Qt::UTC);
  80. dt = dt.addYears(100);
  81. wpt->SetCreationTime(dt);
  82. len = strlen(str);
  83. if (len >= 45) {
  84. WAYPT_SET(wpt, speed, KNOTS_TO_MPS(atof(str + 39)));
  85. }
  86. if (len >= 59) {
  87. wpt->altitude = FEET_TO_METERS(atof(str + 54));
  88. if (str[53] == '-') {
  89. wpt->altitude = -wpt->altitude;
  90. }
  91. }
  92. return wpt;
  93. }
  94. static void
  95. skyforce_head_disp_cb(const route_head* head)
  96. {
  97. prev_wpt = NULL;
  98. if (head->rte_waypt_ct <= 0) {
  99. return;
  100. }
  101. wpt_num = 0;
  102. rte_num++;
  103. if (rte_num > 999) {
  104. if (rte_num == 1000) {
  105. warning(MYNAME ": Can't store more than 999 routes. Some routes skipped!\n");
  106. }
  107. return;
  108. }
  109. }
  110. static void
  111. skyforce_waypt_disp_cb(const Waypoint* wpt)
  112. {
  113. char buf[75]; /* long enough for all data types */
  114. double lat, lon;
  115. memset(buf, ' ', sizeof(buf));
  116. buf[sizeof(buf) - 1] = '\0';
  117. switch (global_opts.objective) {
  118. case wptdata:
  119. buf[0] = 'W';
  120. break;
  121. case trkdata:
  122. buf[0] = 'L';
  123. break;
  124. case rtedata:
  125. buf[0] = 'R';
  126. break;
  127. default: ; /* should never happen */
  128. }
  129. if (global_opts.objective == trkdata) {
  130. struct tm tm;
  131. const time_t tt = wpt->GetCreationTime().toTime_t();
  132. tm = *gmtime(&tt);
  133. strftime(buf + 2, sizeof(buf) - 2, "%d%m%y %H%M%S ", &tm);
  134. } else {
  135. if (rte_num > 999) {
  136. return;
  137. }
  138. wpt_num++;
  139. if (wpt_num > 999) {
  140. if (wpt_num == 1000) {
  141. warning(MYNAME ": Can't store more than 999 waypoints. Some waypoints skipped!\n");
  142. }
  143. return;
  144. }
  145. QString name;
  146. if (global_opts.synthesize_shortnames) {
  147. name = mkshort_from_wpt(short_h, wpt);
  148. } else {
  149. name = mkshort(short_h, wpt->shortname);
  150. }
  151. if (global_opts.objective == rtedata) {
  152. snprintf(buf + 2, sizeof(buf) - 2, "%03d ", rte_num);
  153. }
  154. snprintf(buf + 6, sizeof(buf) - 6, "%03d %-9s ", wpt_num, CSTR(name));
  155. }
  156. lat = degrees2ddmm(wpt->latitude);
  157. buf[20] = (wpt->latitude < 0) ? 'S' : 'N';
  158. snprintf(&buf[21], sizeof(buf) - 21, "%06.2f ", fabs(lat));
  159. lon = degrees2ddmm(wpt->longitude);
  160. buf[29] = (wpt->longitude < 0) ? 'W' : 'E';
  161. snprintf(&buf[30], sizeof(buf) - 30, "%08.2f ", fabs(lon));
  162. if (global_opts.objective == trkdata) {
  163. double alt, speed;
  164. if (wpt->altitude == unknown_alt) {
  165. alt = 0;
  166. } else {
  167. alt = METERS_TO_FEET(wpt->altitude);
  168. }
  169. speed = MPS_TO_KNOTS(waypt_speed(prev_wpt, wpt));
  170. snprintf(&buf[39], sizeof(buf) - 39, "%06.2f 000.00 %c%05d",
  171. speed,
  172. alt < 0 ? '-' : '+', si_round(fabs(alt)));
  173. }
  174. rtrim(buf);
  175. gbfprintf(fout, "%s\n", buf);
  176. prev_wpt = wpt;
  177. }
  178. /*******************************************************************************
  179. * %%% global callbacks called by gpsbabel main process %%% *
  180. *******************************************************************************/
  181. static void
  182. skyforce_rd_init(const QString& fname)
  183. {
  184. fin = gbfopen(fname, "r", MYNAME);
  185. }
  186. static void
  187. skyforce_rd_deinit(void)
  188. {
  189. gbfclose(fin);
  190. }
  191. static void
  192. skyforce_read(void)
  193. {
  194. char* str;
  195. route_head* rte, *trk;
  196. wpt_num = 0;
  197. rte = trk = NULL;
  198. rte_num = -1;
  199. while ((str = gbfgetstr(fin))) {
  200. Waypoint* wpt;
  201. int i;
  202. str = lrtrim(str);
  203. if (*str == '\0') {
  204. continue;
  205. }
  206. switch (*str) {
  207. case 'W':
  208. wpt = skyforce_parse_wpt(str, NULL);
  209. if (wpt == NULL) {
  210. continue;
  211. }
  212. waypt_add(wpt);
  213. break;
  214. case 'R':
  215. wpt = skyforce_parse_wpt(str, &i);
  216. if (wpt == NULL) {
  217. continue;
  218. }
  219. if (i != rte_num) {
  220. rte_num = i;
  221. rte = NULL;
  222. }
  223. if (rte == NULL) {
  224. rte = route_head_alloc();
  225. route_add_head(rte);
  226. rte->rte_num = rte_num;
  227. }
  228. route_add_wpt(rte, wpt);
  229. break;
  230. case 'L':
  231. wpt = skyforce_parse_trk(str);
  232. if (wpt == NULL) {
  233. continue;
  234. }
  235. if (trk == NULL) {
  236. trk = route_head_alloc();
  237. track_add_head(trk);
  238. }
  239. track_add_wpt(trk, wpt);
  240. break;
  241. default:
  242. fatal(MYNAME ": Invalid line marker '%c'!\n", *str);
  243. }
  244. }
  245. }
  246. static void
  247. skyforce_wr_init(const QString& fname)
  248. {
  249. fout = gbfopen(fname, "w", MYNAME);
  250. short_h = mkshort_new_handle();
  251. setshort_length(short_h, 9);
  252. setshort_badchars(short_h, "\r\n\t");
  253. setshort_mustupper(short_h, 1);
  254. setshort_mustuniq(short_h, 1);
  255. setshort_whitespace_ok(short_h, 0);
  256. setshort_repeating_whitespace_ok(short_h, 0);
  257. wpt_num = 0;
  258. rte_num = 0;
  259. }
  260. static void
  261. skyforce_wr_deinit(void)
  262. {
  263. mkshort_del_handle(&short_h);
  264. gbfclose(fout);
  265. }
  266. static void
  267. skyforce_write(void)
  268. {
  269. switch (global_opts.objective) { /* We can only write one data type at a time */
  270. case wptdata:
  271. setshort_defname(short_h, "WPT");
  272. waypt_disp_all(skyforce_waypt_disp_cb);
  273. break;
  274. case rtedata:
  275. setshort_defname(short_h, "RTE");
  276. setshort_mustuniq(short_h, 0);
  277. route_disp_all(skyforce_head_disp_cb, NULL, skyforce_waypt_disp_cb);
  278. break;
  279. case trkdata:
  280. track_disp_all(skyforce_head_disp_cb, NULL, skyforce_waypt_disp_cb);
  281. break;
  282. case posndata:
  283. fatal(MYNAME ": Realtime positioning not supported.\n");
  284. break;
  285. default:
  286. fatal(MYNAME ": Unknown data mode!\n");
  287. }
  288. }
  289. /**************************************************************************/
  290. ff_vecs_t skyforce_vecs = {
  291. ff_type_file,
  292. FF_CAP_RW_ALL, /* read and write waypoints, tracks and routes*/
  293. skyforce_rd_init,
  294. skyforce_wr_init,
  295. skyforce_rd_deinit,
  296. skyforce_wr_deinit,
  297. skyforce_read,
  298. skyforce_write,
  299. NULL,
  300. skyforce_args,
  301. CET_CHARSET_ASCII, 1
  302. };
  303. /**************************************************************************/