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.

jtr.cc 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. Support for the Jelbert GeoTagger JTR data file format.
  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 "csv_util.h"
  18. #include <QtCore/QHash>
  19. #include <cmath>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #define MYNAME "jtr"
  23. static
  24. arglist_t jtr_args[] = {
  25. ARG_TERMINATOR
  26. };
  27. static gbfile* fin, *fout;
  28. static QHash<QString, const Waypoint*> trkpts;
  29. static time_t
  30. jtr_parse_time(const char* str, struct tm* tm, int* milli)
  31. {
  32. long int hms;
  33. char* dot;
  34. hms = strtol(str, &dot, 10);
  35. if (hms > 0) {
  36. tm->tm_sec = hms % 100;
  37. hms = hms / 100;
  38. tm->tm_min = hms % 100;
  39. hms = hms / 100;
  40. tm->tm_hour = hms % 100;
  41. if ((*dot == '.') && (milli != NULL)) {
  42. *milli = atoi(dot + 1) * 10;
  43. }
  44. return mkgmtime(tm);
  45. } else {
  46. return 0;
  47. }
  48. }
  49. static time_t
  50. jtr_parse_date(const char* str, struct tm* tm)
  51. {
  52. int dmy = atoi(str);
  53. if (dmy > 0) {
  54. tm->tm_year = dmy % 100 + 100;
  55. dmy = dmy / 100;
  56. tm->tm_mon = dmy % 100 - 1;
  57. dmy = dmy / 100;
  58. tm->tm_mday = dmy;
  59. return mkgmtime(tm);
  60. } else {
  61. return 0;
  62. }
  63. }
  64. /*******************************************************************************
  65. * %%% global callbacks called by gpsbabel main process %%% *
  66. *******************************************************************************/
  67. static void
  68. jtr_rd_init(const QString& fname)
  69. {
  70. fin = gbfopen(fname, "r", MYNAME);
  71. }
  72. static void
  73. jtr_rd_deinit(void)
  74. {
  75. trkpts.clear();
  76. gbfclose(fin);
  77. }
  78. static void
  79. jtr_read(void)
  80. {
  81. char* str;
  82. int line = 0;
  83. route_head* trk = NULL;
  84. while ((str = gbfgetstr(fin))) {
  85. Waypoint* wpt;
  86. struct tm tm;
  87. char* tmp;
  88. int column = -1;
  89. char valid = 'V';
  90. double lat, lon;
  91. float speed, course, mcourse, mvar, mdev;
  92. time_t time = 0;
  93. int mills = 0;
  94. char buf[32];
  95. char mvardir, mdevdir;
  96. line++;
  97. str = lrtrim(str);
  98. if (*str == '\0') {
  99. continue;
  100. }
  101. if (strncmp(str, "GEOTAG2,", 8) != 0) {
  102. fatal(MYNAME ": Unknown or unsupported file (missing \"GEOTAG2\")!\n");
  103. }
  104. memset(&tm, 0, sizeof(tm));
  105. lat = lon = 999;
  106. speed = course = mcourse = mvar = mdev = -1;
  107. mvardir = mdevdir = 0;
  108. column = -1;
  109. tmp = str;
  110. while ((str = csv_lineparse(tmp, ",", "", column++))) {
  111. tmp = NULL;
  112. if (*str == '\0') {
  113. continue;
  114. }
  115. switch (column) {
  116. case 0:
  117. break; /* GEOTAG2 */
  118. case 1:
  119. jtr_parse_time(str, &tm, &mills);
  120. break;
  121. case 2:
  122. valid = *str;
  123. break;
  124. case 3:
  125. lat = ddmm2degrees(atof(str));
  126. break;
  127. case 4:
  128. if (*str == 'S') {
  129. lat *= -1;
  130. }
  131. break;
  132. case 5:
  133. lon = ddmm2degrees(atof(str));
  134. break;
  135. case 6:
  136. if (*str == 'W') {
  137. lon *= -1;
  138. }
  139. break;
  140. case 7:
  141. speed = KNOTS_TO_MPS(atof(str));
  142. break;
  143. case 8:
  144. course = atof(str);
  145. break;
  146. case 9:
  147. jtr_parse_date(str, &tm);
  148. break;
  149. case 13:
  150. mcourse = atof(str);
  151. break;
  152. case 14:
  153. mdev = atof(str);
  154. break;
  155. case 15:
  156. mdevdir = *str;
  157. break;
  158. case 16:
  159. mvar = atof(str);
  160. break;
  161. case 17:
  162. mvardir = *str;
  163. break;
  164. default:
  165. break;
  166. }
  167. }
  168. if ((lat == 999) || (lon == 999) || (valid != 'A')) {
  169. continue;
  170. }
  171. if (tm.tm_year > 0) {
  172. time = mkgmtime(&tm);
  173. } else {
  174. time = 0;
  175. }
  176. /* check for duplicates as suggested in format description */
  177. snprintf(buf, sizeof(buf), "%.6f\01%.6f\01%ld", lat, lon, (long)time);
  178. if (trkpts.contains(QString::fromUtf8(buf))) {
  179. continue;
  180. }
  181. wpt = new Waypoint;
  182. wpt->latitude = lat;
  183. wpt->longitude = lon;
  184. wpt->SetCreationTime(time, mills);
  185. if (speed >= 0) {
  186. WAYPT_SET(wpt, speed, speed);
  187. }
  188. if (mcourse >= 0) {
  189. course = mcourse;
  190. if (mvar >= 0) {
  191. if (mvardir == 'W') {
  192. course += mvar;
  193. } else if (mvardir == 'E') {
  194. course -= mvar;
  195. }
  196. }
  197. if (mdev >= 0) {
  198. if (mdevdir == 'W') {
  199. course += mdev;
  200. } else if (mdevdir == 'E') {
  201. course -= mdev;
  202. }
  203. }
  204. }
  205. if (course >= 0) {
  206. WAYPT_SET(wpt, course, course);
  207. }
  208. if (trk == NULL) {
  209. trk = route_head_alloc();
  210. track_add_head(trk);
  211. }
  212. trkpts.insert(QString::fromUtf8(buf), wpt);
  213. track_add_wpt(trk, wpt);
  214. }
  215. }
  216. static void
  217. jtr_wr_init(const QString& fname)
  218. {
  219. fout = gbfopen(fname, "wb", MYNAME);
  220. }
  221. static void
  222. jtr_wr_deinit(void)
  223. {
  224. gbfclose(fout);
  225. }
  226. static void
  227. jtr_trkpt_disp_cb(const Waypoint* wpt)
  228. {
  229. char* str, *tmp;
  230. char stime[10], sdate[7], scourse[6], sspeed[8];
  231. struct tm tm;
  232. if (wpt->creation_time.isValid()) {
  233. const time_t tt = wpt->GetCreationTime().toTime_t();
  234. tm = *gmtime(&tt);
  235. tm.tm_year += 1900;
  236. tm.tm_mon += 1;
  237. snprintf(sdate, sizeof(sdate), "%02d%02d%02d", tm.tm_mday, tm.tm_mon, tm.tm_year % 100);
  238. snprintf(stime, sizeof(stime), "%02d%02d%02d.%02d", tm.tm_hour, tm.tm_min, tm.tm_sec, wpt->creation_time.time().msec());
  239. if (wpt->creation_time.time().msec() == 0) {
  240. stime[6] = 0;
  241. }
  242. } else {
  243. stime[0] = 0;
  244. sdate[0] = 0;
  245. }
  246. if (WAYPT_HAS(wpt, speed) && (wpt->speed >= 0)) {
  247. snprintf(sspeed, sizeof(sspeed), "%.1f", MPS_TO_KNOTS(wpt->speed));
  248. } else {
  249. sspeed[0] = 0;
  250. }
  251. if (WAYPT_HAS(wpt, course) && (wpt->course >= 0)) {
  252. snprintf(scourse, sizeof(scourse), "%.1f", wpt->course);
  253. } else {
  254. scourse[0] = 0;
  255. }
  256. xasprintf(&str, "GEOTAG2,%s,%c,%09.4f,%c,%010.4f,%c,%s,%s,%s,,E,A",
  257. stime,
  258. wpt->creation_time.isValid() ? 'A' : 'V',
  259. fabs(degrees2ddmm(wpt->latitude)),
  260. wpt->latitude < 0 ? 'S' : 'N',
  261. fabs(degrees2ddmm(wpt->longitude)),
  262. wpt->longitude < 0 ? 'W' : 'E',
  263. sspeed,
  264. scourse,
  265. sdate);
  266. xasprintf(&tmp, "%s*%02X", str, nmea_cksum(str));
  267. xfree(str);
  268. str = tmp;
  269. xasprintf(&tmp, "%s,,,E,,E*%02X\r", str, nmea_cksum(str));
  270. xfree(str);
  271. str = tmp;
  272. gbfputs(str, fout);
  273. xfree(str);
  274. }
  275. static void
  276. jtr_write(void)
  277. {
  278. track_disp_all(NULL, NULL, jtr_trkpt_disp_cb);
  279. }
  280. /**************************************************************************/
  281. ff_vecs_t jtr_vecs = {
  282. ff_type_file,
  283. {
  284. ff_cap_none, /* waypoints */
  285. (ff_cap)(ff_cap_read | ff_cap_write), /* tracks */
  286. ff_cap_none /* routes */
  287. },
  288. jtr_rd_init,
  289. jtr_wr_init,
  290. jtr_rd_deinit,
  291. jtr_wr_deinit,
  292. jtr_read,
  293. jtr_write,
  294. NULL,
  295. jtr_args,
  296. CET_CHARSET_ASCII, 0 /* ascii is the expected character set */
  297. /* not fixed, can be changed through command line parameter */
  298. };
  299. /**************************************************************************/