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.

tpg.cc 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. National Geographic Topo! TPG file support (Waypoints/Routes)
  3. Contributed to gpsbabel by Alex Mottram
  4. For Topo! version 2.x. Routes are currently not implemented.
  5. Copyright (C) 2002 Alex Mottram, geo_alexm at cox-internet.com
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  17. */
  18. #include "defs.h"
  19. #include "jeeps/gpsmath.h" /* for datum conversions */
  20. #define MYNAME "TPG"
  21. #define MAXTPGSTRINGSIZE 256
  22. #define MAXTPGOUTPUTPINS 65535
  23. static gbfile* tpg_file_in;
  24. static gbfile* tpg_file_out;
  25. static short_handle mkshort_handle;
  26. static char* tpg_datum_opt;
  27. static int tpg_datum_idx;
  28. static unsigned int waypt_out_count;
  29. static
  30. arglist_t tpg_args[] = {
  31. {"datum", &tpg_datum_opt, "Datum (default=NAD27)", "N. America 1927 mean", ARGTYPE_STRING, ARG_NOMINMAX },
  32. ARG_TERMINATOR
  33. };
  34. static int
  35. valid_tpg_header(char* header, int len)
  36. {
  37. unsigned char header_bytes[] = { 0xFF, 0xFF, 0x01, 0x00, 0x0D,
  38. 0x00, 0x43, 0x54, 0x6F, 0x70,
  39. 0x6F, 0x57, 0x61, 0x79, 0x70,
  40. 0x6F, 0x69, 0x6E, 0x74
  41. };
  42. if (len != 19) {
  43. return (-1);
  44. }
  45. return memcmp(header_bytes, header, len);
  46. }
  47. static void
  48. tpg_common_init(void)
  49. {
  50. tpg_datum_idx = GPS_Lookup_Datum_Index(tpg_datum_opt);
  51. if (tpg_datum_idx < 0) {
  52. fatal(MYNAME ": Datum '%s' is not recognized.\n", tpg_datum_opt);
  53. }
  54. }
  55. static void
  56. tpg_rd_init(const QString& fname)
  57. {
  58. tpg_common_init();
  59. tpg_file_in = gbfopen_le(fname, "rb", MYNAME);
  60. }
  61. static void
  62. tpg_rd_deinit(void)
  63. {
  64. gbfclose(tpg_file_in);
  65. }
  66. static void
  67. tpg_wr_init(const QString& fname)
  68. {
  69. tpg_common_init();
  70. tpg_file_out = gbfopen_le(fname, "wb", MYNAME);
  71. mkshort_handle = mkshort_new_handle();
  72. waypt_out_count = 0;
  73. }
  74. static void
  75. tpg_wr_deinit(void)
  76. {
  77. mkshort_del_handle(&mkshort_handle);
  78. gbfclose(tpg_file_out);
  79. }
  80. static void
  81. tpg_read(void)
  82. {
  83. char buff[MAXTPGSTRINGSIZE + 1];
  84. Waypoint* wpt_tmp;
  85. double lat, lon, elev;
  86. double amt;
  87. short int pointcount;
  88. pointcount = gbfgetint16(tpg_file_in);
  89. /* the rest of the header */
  90. gbfread(&buff[0], 19, 1, tpg_file_in);
  91. if (valid_tpg_header(buff, 19) != 0) {
  92. fatal(MYNAME ": input file does not appear to be a valid .TPG file.\n");
  93. }
  94. while (pointcount--) {
  95. wpt_tmp = new Waypoint;
  96. /* pascal-like shortname */
  97. wpt_tmp->shortname = gbfgetpstr(tpg_file_in);
  98. /* for some very odd reason, signs on longitude are swapped */
  99. /* coordinates are in NAD27/CONUS datum */
  100. /* 8 bytes - longitude, sign swapped */
  101. lon = gbfgetdbl(tpg_file_in);
  102. /* 8 bytes - latitude */
  103. lat = gbfgetdbl(tpg_file_in);
  104. /* swap sign before we do datum conversions */
  105. lon *= -1.0;
  106. /* 2 bytes - elevation in feet */
  107. elev = FEET_TO_METERS(gbfgetint16(tpg_file_in));
  108. /* convert incoming NAD27/CONUS coordinates to WGS84 */
  109. GPS_Math_Known_Datum_To_WGS84_M(
  110. lat,
  111. lon,
  112. 0.0,
  113. &wpt_tmp->latitude,
  114. &wpt_tmp->longitude,
  115. &amt,
  116. tpg_datum_idx);
  117. wpt_tmp->altitude = elev;
  118. /* 4 bytes? */
  119. (void) gbfgetint32(tpg_file_in);
  120. /* pascal-like description */
  121. wpt_tmp->description = gbfgetpstr(tpg_file_in);
  122. /* 2 bytes */
  123. (void) gbfgetint16(tpg_file_in);
  124. waypt_add(wpt_tmp);
  125. }
  126. }
  127. static void
  128. tpg_waypt_pr(const Waypoint* wpt)
  129. {
  130. double lon, lat;
  131. double amt;
  132. short int elev;
  133. char tbuf[64];
  134. char c,ocount;
  135. QString shortname;
  136. QString description;
  137. int i;
  138. /* these unknown 4 are probably point properties (color, icon, etc..) */
  139. unsigned char unknown4[] = { 0x78, 0x56, 0x34, 0x12 };
  140. /* these 2 appear to be constant across test files */
  141. unsigned char unknown2[] = { 0x01, 0x80 };
  142. /* our personal waypoint counter */
  143. waypt_out_count++;
  144. /* this output format pretty much requires a description
  145. * and a shortname
  146. */
  147. if ((wpt->shortname.isEmpty()) || (global_opts.synthesize_shortnames)) {
  148. if (!wpt->description.isEmpty()) {
  149. if (global_opts.synthesize_shortnames) {
  150. shortname = mkshort_from_wpt(mkshort_handle, wpt);
  151. } else {
  152. shortname = wpt->description;
  153. }
  154. } else {
  155. /* no description available */
  156. shortname = "";
  157. }
  158. } else {
  159. shortname = wpt->shortname;
  160. }
  161. if (wpt->description.isEmpty()) {
  162. if (!shortname.isEmpty()) {
  163. description = shortname;
  164. } else {
  165. description = "";
  166. }
  167. } else {
  168. description = wpt->description;
  169. }
  170. /* convert lat/long to NAD27/CONUS datum */
  171. GPS_Math_WGS84_To_Known_Datum_M(
  172. wpt->latitude,
  173. wpt->longitude,
  174. 0.0,
  175. &lat,
  176. &lon,
  177. &amt,
  178. tpg_datum_idx);
  179. /* swap the sign back *after* the datum conversion */
  180. lon *= -1.0;
  181. /* convert meters back to feets */
  182. elev = (short int) METERS_TO_FEET(wpt->altitude);
  183. /* 1 bytes stringsize for shortname */
  184. c = shortname.length();
  185. ocount = 0;
  186. /*
  187. * It's reported the only legal characters are upper case
  188. * A-Z and 0-9. Wow. We have to make two passes: one to
  189. * count and one to output.
  190. */
  191. for (i = 0; i < c; i++) {
  192. char oc = shortname[i].toUpper().cell();
  193. if (isalnum(oc) || oc == ' ') {
  194. ocount++;
  195. }
  196. }
  197. gbfwrite(&ocount, 1, 1, tpg_file_out);
  198. for (i = 0; i < c; i++) {
  199. char oc = shortname[i].toUpper().cell();
  200. if (isalnum(oc) || oc == ' ') {
  201. gbfputc(oc, tpg_file_out);
  202. }
  203. }
  204. /* 8 bytes - longitude */
  205. gbfputdbl(lon, tpg_file_out);
  206. /* 8 bytes - latitude */
  207. gbfputdbl(lat, tpg_file_out);
  208. /* 2 bytes - elevation_feet */
  209. gbfputint16(elev, tpg_file_out);
  210. /* 4 unknown bytes */
  211. memset(tbuf, '\0', sizeof(tbuf));
  212. gbfwrite(unknown4, 1, 4, tpg_file_out);
  213. /* pascal-like description */
  214. gbfputpstr(description, tpg_file_out);
  215. /* and finally 2 unknown bytes */
  216. if (waypt_out_count == waypt_count()) {
  217. /* last point gets 0x0000 instead of 0x0180 */
  218. gbfputint16(0, tpg_file_out);
  219. } else {
  220. gbfwrite(unknown2, 1, 2, tpg_file_out);
  221. }
  222. }
  223. static void
  224. tpg_write(void)
  225. {
  226. int s;
  227. unsigned char header_bytes[] = { 0xFF, 0xFF, 0x01, 0x00, 0x0D,
  228. 0x00, 0x43, 0x54, 0x6F, 0x70,
  229. 0x6F, 0x57, 0x61, 0x79, 0x70,
  230. 0x6F, 0x69, 0x6E, 0x74
  231. };
  232. s = waypt_count();
  233. if (global_opts.synthesize_shortnames) {
  234. setshort_length(mkshort_handle, 32);
  235. setshort_whitespace_ok(mkshort_handle, 1);
  236. setshort_mustupper(mkshort_handle, 1);
  237. }
  238. if (s > MAXTPGOUTPUTPINS) {
  239. fatal(MYNAME ": attempt to output too many points (%d). The max is %d. Sorry.\n", s, MAXTPGOUTPUTPINS);
  240. }
  241. /* write the waypoint count */
  242. gbfputint16(s, tpg_file_out);
  243. /* write the rest of the header */
  244. gbfwrite(header_bytes, 1, 19, tpg_file_out);
  245. waypt_disp_all(tpg_waypt_pr);
  246. }
  247. ff_vecs_t tpg_vecs = {
  248. ff_type_file,
  249. FF_CAP_RW_WPT,
  250. tpg_rd_init,
  251. tpg_wr_init,
  252. tpg_rd_deinit,
  253. tpg_wr_deinit,
  254. tpg_read,
  255. tpg_write,
  256. NULL,
  257. tpg_args,
  258. CET_CHARSET_ASCII, 0 /* CET-REVIEW */
  259. };