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.

485 lines
12KB

  1. /*
  2. Read various Delorme routes including anr, rte, and rtd.
  3. Copyright (C) 2003 Ron Parker and Robert Lipe.
  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. #define MYNAME "saroute"
  17. #include "defs.h"
  18. #include "grtcirc.h"
  19. #include <stddef.h>
  20. gbfile* infile;
  21. char* turns_important = NULL;
  22. char* turns_only = NULL;
  23. char* controls = NULL;
  24. char* split = NULL;
  25. char* timesynth = NULL;
  26. int control = 0;
  27. static
  28. arglist_t saroute_args[] = {
  29. {
  30. "turns_important", &turns_important,
  31. "Keep turns if simplify filter is used",
  32. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  33. },
  34. {
  35. "turns_only", &turns_only, "Only read turns; skip all other points",
  36. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  37. },
  38. {
  39. "split", &split, "Split into multiple routes at turns",
  40. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  41. },
  42. {
  43. "controls", &controls, "Read control points as waypoint/route/none",
  44. "none", ARGTYPE_STRING, ARG_NOMINMAX
  45. },
  46. {
  47. "times", &timesynth, "Synthesize track times",
  48. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  49. },
  50. ARG_TERMINATOR
  51. };
  52. #define ReadShort(f) gbfgetint16(f)
  53. #define ReadLong(f) gbfgetint32(f)
  54. unsigned char*
  55. ReadRecord(gbfile* f, gbsize_t size)
  56. {
  57. unsigned char* result = (unsigned char*) xmalloc(size);
  58. (void)gbfread(result, size, 1, f);
  59. return result;
  60. }
  61. void
  62. Skip(gbfile* f, gbsize_t distance)
  63. {
  64. gbfseek(f, distance, SEEK_CUR);
  65. }
  66. static void
  67. rd_init(const QString& fname)
  68. {
  69. infile = gbfopen(fname, "rb", MYNAME);
  70. if (split && (turns_important || turns_only)) {
  71. fatal(MYNAME
  72. ": turns options are not compatible with split\n");
  73. }
  74. if (controls) {
  75. switch (controls[0]) {
  76. case 'n':
  77. control = 0;
  78. break;
  79. case 'r':
  80. control = 1;
  81. break;
  82. case 'w':
  83. control = 2;
  84. break;
  85. default:
  86. fatal(MYNAME
  87. ": unrecognized value for 'controls'\n");
  88. break;
  89. }
  90. }
  91. }
  92. static void
  93. rd_deinit(void)
  94. {
  95. gbfclose(infile);
  96. }
  97. static void
  98. my_read(void)
  99. {
  100. uint16_t version;
  101. uint32_t count;
  102. uint32_t outercount;
  103. uint32_t recsize;
  104. uint16_t stringlen;
  105. unsigned char* record;
  106. static int serial = 0;
  107. struct ll {
  108. int32_t lat;
  109. int32_t lon;
  110. } *latlon;
  111. struct ll mylatlon;
  112. uint16_t coordcount;
  113. route_head* track_head = NULL;
  114. route_head* old_track_head = NULL;
  115. Waypoint* wpt_tmp;
  116. char* routename = NULL;
  117. double seglen = 0.0;
  118. int32_t starttime = 0;
  119. int32_t transittime = 0;
  120. double totaldist = 0.0;
  121. double oldlat = 0;
  122. double oldlon = 0;
  123. int first = 0;
  124. ReadShort(infile); /* magic */
  125. version = ReadShort(infile);
  126. ReadLong(infile);
  127. if (version >= 6) {
  128. ReadLong(infile);
  129. ReadLong(infile);
  130. }
  131. /*
  132. * end of header
  133. */
  134. ReadShort(infile);
  135. recsize = ReadLong(infile);
  136. /*
  137. * the first recsize, oddly, doesn't include the filename string
  138. * but it does include the header.
  139. */
  140. record = ReadRecord(infile, recsize);
  141. stringlen = le_read16((uint16_t*)(record + 0x1a));
  142. if (stringlen) {
  143. routename = (char*)xmalloc(stringlen + 1);
  144. routename[stringlen] = '\0';
  145. memcpy(routename, record+0x1c, stringlen);
  146. }
  147. Skip(infile, stringlen - 4);
  148. xfree(record);
  149. /*
  150. * end of filename record
  151. */
  152. /*
  153. * here lie the route description records
  154. */
  155. if (version < 6 || (control == 1)) {
  156. track_head = route_head_alloc();
  157. route_add_head(track_head);
  158. if (control) {
  159. track_head->rte_name = "control points";
  160. } else {
  161. track_head->rte_name = routename;
  162. }
  163. }
  164. count = ReadLong(infile);
  165. while (count) {
  166. ReadShort(infile);
  167. recsize = ReadLong(infile);
  168. if (version < 6 || control) {
  169. double lat;
  170. double lon;
  171. record = ReadRecord(infile, recsize);
  172. latlon = (struct ll*)(record);
  173. /* These records are backwards for some reason */
  174. lat = (0x80000000UL -
  175. le_read32(&latlon->lon)) / (double)(0x800000);
  176. lon = (0x80000000UL -
  177. le_read32(&latlon->lat)) / (double)(0x800000);
  178. wpt_tmp = new Waypoint;
  179. wpt_tmp->latitude = lat;
  180. wpt_tmp->longitude = -lon;
  181. if (control) {
  182. int obase, addrlen, cmtlen;
  183. /* Somewhere around TopoUSA 6.0, these moved */
  184. /* This block also seems to get miscompiled
  185. * at -O0 on Linux. I tried rewriting it to
  186. * reduce/eliminate some of the really funky
  187. * pointer math and casting that was here.
  188. */
  189. if (version >= 11) {
  190. obase = 20;
  191. } else {
  192. obase = 18;
  193. }
  194. addrlen = le_read16(&record[obase]);
  195. cmtlen = le_read16(&record[obase+2+addrlen]);
  196. (void) cmtlen;
  197. #if NEW_STRINGS
  198. // That we've had no bugreports on this strongly indicates this code
  199. // is never used...
  200. wpt_tmp->shortname = "booger";
  201. wpt_tmp->notes = "goober";
  202. #else
  203. wpt_tmp->shortname = (char*) xmalloc(addrlen+1);
  204. wpt_tmp->shortname[addrlen]='\0';
  205. wpt_tmp->notes = (char*) xmalloc(cmtlen+1);
  206. wpt_tmp->notes[cmtlen] = '\0';
  207. memcpy(wpt_tmp->notes,
  208. record+obase+4+addrlen,
  209. cmtlen);
  210. memcpy(wpt_tmp->shortname,
  211. record+obase+2,
  212. addrlen);
  213. #endif
  214. } else {
  215. #if NEW_STRINGS
  216. wpt_tmp->shortname = QString().sprintf("\\%5.5x", serial++);
  217. #else
  218. wpt_tmp->shortname = (char*) xmalloc(7);
  219. sprintf(wpt_tmp->shortname, "\\%5.5x", serial++);
  220. #endif
  221. }
  222. if (control == 2) {
  223. waypt_add(wpt_tmp);
  224. } else {
  225. route_add_wpt(track_head, wpt_tmp);
  226. }
  227. xfree(record);
  228. if (version >= 6) {
  229. /*
  230. * two longs of scrap after each record, don't know why
  231. */
  232. ReadLong(infile);
  233. ReadLong(infile);
  234. }
  235. } else {
  236. Skip(infile, recsize);
  237. /*
  238. * two longs of scrap after each record, don't know why
  239. */
  240. ReadLong(infile);
  241. ReadLong(infile);
  242. }
  243. count--;
  244. }
  245. /*
  246. * end of route desc records
  247. */
  248. /*
  249. * outercount is the number of route segments (start+end+stops+vias-1)
  250. */
  251. outercount = ReadLong(infile);
  252. while (outercount) {
  253. /*
  254. * unknown record (route params?) lives here
  255. */
  256. ReadShort(infile);
  257. recsize = ReadLong(infile);
  258. Skip(infile, recsize);
  259. /*
  260. * end of unknown record
  261. */
  262. /*
  263. * routing begins here
  264. */
  265. count = ReadLong(infile);
  266. if (count) {
  267. track_head = route_head_alloc();
  268. if (timesynth) {
  269. track_add_head(track_head);
  270. } else {
  271. route_add_head(track_head);
  272. }
  273. if (routename && !split) {
  274. track_head->rte_name = routename;
  275. }
  276. }
  277. while (count) {
  278. old_track_head = NULL;
  279. ReadShort(infile);
  280. recsize = ReadLong(infile);
  281. record = ReadRecord(infile, recsize);
  282. stringlen = le_read16((uint16_t*)record);
  283. if (split && stringlen) {
  284. if (track_head->rte_waypt_ct) {
  285. old_track_head = track_head;
  286. track_head = route_head_alloc();
  287. if (timesynth) {
  288. track_add_head(track_head);
  289. } else {
  290. route_add_head(track_head);
  291. }
  292. } // end if
  293. #if NEW_STRINGS
  294. if (track_head->rte_name.isEmpty()) {
  295. track_head->rte_name = "I made this up";
  296. }
  297. #else
  298. if (!track_head->rte_name) {
  299. track_head->rte_name =
  300. (char*)xmalloc(stringlen+1);
  301. strncpy(track_head->rte_name,
  302. (const char*) record+2, stringlen);
  303. track_head->rte_name[stringlen] = '\0';
  304. }
  305. #endif
  306. }
  307. if (timesynth) {
  308. seglen = le_read_double(
  309. record + 2 + stringlen + 0x08);
  310. starttime = le_read32((uint32_t*)
  311. (record + 2 + stringlen + 0x30));
  312. transittime = le_read32((uint32_t*)
  313. (record + 2 + stringlen + 0x10));
  314. seglen /= 5280*12*2.54/100000; /* to miles */
  315. }
  316. coordcount = le_read16((uint16_t*)
  317. (record + 2 + stringlen + 0x3c));
  318. latlon = (struct ll*)(record + 2 + stringlen + 0x3c + 2);
  319. count--;
  320. if (count) {
  321. coordcount--;
  322. }
  323. first = 1;
  324. while (coordcount) {
  325. double lat;
  326. double lon;
  327. wpt_tmp = new Waypoint;
  328. // copy to make sure we don't violate alignment restrictions.
  329. memcpy(&mylatlon,latlon,sizeof(mylatlon));
  330. lat = (0x80000000UL -
  331. le_read32(&mylatlon.lat)) /
  332. (double)(0x800000);
  333. lon = (0x80000000UL -
  334. le_read32(&mylatlon.lon)) /
  335. (double)(0x800000);
  336. wpt_tmp->latitude = lat;
  337. wpt_tmp->longitude = -lon;
  338. if (stringlen && ((coordcount>1) || count)) {
  339. #if NEW_STRINGS
  340. wpt_tmp->shortname = QString(((char*)record)+2);
  341. #else
  342. wpt_tmp->shortname = (char*) xmalloc(stringlen+1);
  343. wpt_tmp->shortname[stringlen] = '\0';
  344. memcpy(wpt_tmp->shortname,
  345. ((char*)record)+2,
  346. stringlen);
  347. #endif
  348. } else {
  349. #if NEW_STRINGS
  350. wpt_tmp->shortname = QString().sprintf("\\%5.5x", serial++);
  351. #else
  352. wpt_tmp->shortname = (char*) xmalloc(7);
  353. sprintf(wpt_tmp->shortname, "\\%5.5x",
  354. serial++);
  355. #endif
  356. }
  357. if (timesynth) {
  358. if (!first) {
  359. double dist = radtomiles(gcdist(
  360. RAD(lat), RAD(-lon),
  361. RAD(oldlat),
  362. RAD(-oldlon)));
  363. totaldist += dist;
  364. if (totaldist > seglen) {
  365. totaldist = seglen;
  366. }
  367. wpt_tmp->SetCreationTime(
  368. gpsbabel_time+starttime+
  369. transittime * totaldist/seglen);
  370. } else {
  371. wpt_tmp->SetCreationTime(gpsbabel_time+starttime);
  372. totaldist = 0;
  373. }
  374. oldlat = lat;
  375. oldlon = lon;
  376. }
  377. if (turns_important && stringlen) {
  378. wpt_tmp->route_priority=1;
  379. }
  380. if (!turns_only || stringlen) {
  381. if (timesynth) {
  382. track_add_wpt(track_head,wpt_tmp);
  383. } else {
  384. route_add_wpt(track_head, wpt_tmp);
  385. }
  386. if (old_track_head) {
  387. if (timesynth) {
  388. track_add_wpt(old_track_head,
  389. new Waypoint(*wpt_tmp));
  390. } else {
  391. route_add_wpt(old_track_head,
  392. new Waypoint(*wpt_tmp));
  393. }
  394. old_track_head = NULL;
  395. }
  396. }
  397. latlon++;
  398. coordcount--;
  399. stringlen = 0;
  400. /* the stop point is a "turn" */
  401. if (coordcount == 1 && count == 0) {
  402. stringlen = 1;
  403. }
  404. first = 0;
  405. }
  406. if (version > 10) {
  407. Skip(infile,2*sizeof(uint32_t));
  408. }
  409. xfree(record);
  410. }
  411. /*
  412. * end of routing
  413. */
  414. outercount--;
  415. }
  416. if (routename) {
  417. xfree(routename);
  418. }
  419. }
  420. static void
  421. wr_init(const QString& fname)
  422. {
  423. fatal(MYNAME ":Not enough information is known about this format to write it.\n");
  424. }
  425. ff_vecs_t saroute_vecs = {
  426. ff_type_file,
  427. { ff_cap_none, ff_cap_read, ff_cap_none},
  428. rd_init,
  429. wr_init,
  430. rd_deinit,
  431. NULL,
  432. my_read,
  433. NULL,
  434. NULL,
  435. saroute_args,
  436. CET_CHARSET_UTF8, 1 /* do nothing | CET-REVIEW */
  437. };