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.

tiger.cc 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. Access to U.S. Census Bureau "tiger" format.
  3. Copyright (C) 2002-2014 Robert Lipe, robertlipe+source@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 "cet_util.h"
  18. #include "csv_util.h"
  19. #include <math.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. static gbfile* file_in, *file_out;
  23. static short_handle mkshort_handle;
  24. static short_handle mkshort_whandle;
  25. #define MYNAME "GPSUTIL"
  26. static double maxlat, maxlon, minlat, minlon;
  27. static int rec_cnt;
  28. static char* nolabels = NULL;
  29. static char* genurl = NULL;
  30. static char* suppresswhite = NULL;
  31. static char* iconismarker = NULL;
  32. static char* snlen = NULL;
  33. static char* margin = NULL;
  34. static char* xpixels = NULL;
  35. static char* ypixels = NULL;
  36. static char* oldthresh = NULL;
  37. static char* oldmarker = NULL;
  38. static char* newmarker = NULL;
  39. static char* unfoundmarker = NULL;
  40. static int short_length;
  41. static double thresh_days;
  42. /*
  43. * The code bracketed by CLICKMAP is to generate clickable image maps
  44. * for a web browser. It's functional, but is missing the math to do
  45. * the projection transformations. Some trig geek can finish that.
  46. */
  47. #if CLICKMAP
  48. static gbfile* linkf;
  49. static char* clickmap = NULL;
  50. #endif
  51. static
  52. arglist_t tiger_args[] = {
  53. {
  54. "nolabels", &nolabels, "Suppress labels on generated pins",
  55. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  56. },
  57. {
  58. "genurl", &genurl, "Generate file with lat/lon for centering map",
  59. NULL, ARGTYPE_OUTFILE, ARG_NOMINMAX
  60. },
  61. {
  62. "margin", &margin, "Margin for map. Degrees or percentage",
  63. "15%", ARGTYPE_FLOAT, ARG_NOMINMAX
  64. },
  65. {
  66. "snlen", &snlen, "Max shortname length when used with -s",
  67. "10", ARGTYPE_INT, "1", NULL
  68. },
  69. {
  70. "oldthresh", &oldthresh,
  71. "Days after which points are considered old",
  72. "14", ARGTYPE_INT, ARG_NOMINMAX
  73. },
  74. {
  75. "oldmarker", &oldmarker, "Marker type for old points",
  76. "redpin", ARGTYPE_STRING, ARG_NOMINMAX
  77. },
  78. {
  79. "newmarker", &newmarker, "Marker type for new points",
  80. "greenpin", ARGTYPE_STRING, ARG_NOMINMAX
  81. },
  82. {
  83. "suppresswhite", &suppresswhite,
  84. "Suppress whitespace in generated shortnames",
  85. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  86. },
  87. {
  88. "unfoundmarker", &unfoundmarker, "Marker type for unfound points",
  89. "bluepin", ARGTYPE_STRING, ARG_NOMINMAX
  90. },
  91. {
  92. "xpixels", &xpixels, "Width in pixels of map",
  93. "768", ARGTYPE_INT, ARG_NOMINMAX
  94. },
  95. {
  96. "ypixels", &ypixels, "Height in pixels of map",
  97. "768", ARGTYPE_INT, ARG_NOMINMAX
  98. },
  99. {
  100. "iconismarker", &iconismarker,
  101. "The icon description is already the marker", NULL,
  102. ARGTYPE_BOOL, ARG_NOMINMAX
  103. },
  104. #if CLICKMAP
  105. {
  106. "clickmap", &clickmap, "Generate Clickable map web page",
  107. NULL, ARGTYPE_BOOL, ARG_NOMINMAX
  108. },
  109. #endif
  110. ARG_TERMINATOR
  111. };
  112. static void
  113. rd_init(const QString& fname)
  114. {
  115. file_in = gbfopen(fname, "rb", MYNAME);
  116. mkshort_handle = mkshort_new_handle();
  117. }
  118. static void
  119. rd_deinit(void)
  120. {
  121. gbfclose(file_in);
  122. mkshort_del_handle(&mkshort_handle);
  123. }
  124. static void
  125. wr_init(const QString& fname)
  126. {
  127. file_out = gbfopen(fname, "w", MYNAME);
  128. thresh_days = strtod(oldthresh, NULL);
  129. }
  130. static void
  131. wr_deinit(void)
  132. {
  133. gbfclose(file_out);
  134. }
  135. static void
  136. data_read(void)
  137. {
  138. double lat,lon;
  139. char desc[101];
  140. char icon[101];
  141. char* ibuf;
  142. Waypoint* wpt_tmp;
  143. int line = 0;
  144. while ((ibuf = gbfgetstr(file_in))) {
  145. if ((line++ == 0) && file_in->unicode) {
  146. cet_convert_init(CET_CHARSET_UTF8, 1);
  147. }
  148. if (sscanf(ibuf, "%lf,%lf:%100[^:]:%100[^\n]",
  149. &lon, &lat, icon, desc)) {
  150. wpt_tmp = new Waypoint;
  151. wpt_tmp->longitude = lon;
  152. wpt_tmp->latitude = lat;
  153. wpt_tmp->description = desc;
  154. wpt_tmp->shortname = mkshort(mkshort_handle, QString(desc));
  155. waypt_add(wpt_tmp);
  156. }
  157. }
  158. }
  159. static void
  160. tiger_disp(const Waypoint* wpt)
  161. {
  162. QString pin;
  163. double lat = wpt->latitude;
  164. double lon = wpt->longitude;
  165. if (iconismarker) {
  166. pin = wpt->icon_descr;
  167. } else if (wpt->icon_descr.contains("-unfound")) {
  168. pin = unfoundmarker;
  169. } else if (wpt->GetCreationTime() > current_time().addSecs(-3600 * 24 * thresh_days)) {
  170. pin = newmarker;
  171. } else {
  172. pin = oldmarker;
  173. }
  174. if (genurl) {
  175. if (lat > maxlat) {
  176. maxlat = lat;
  177. }
  178. if (lon > maxlon) {
  179. maxlon = lon;
  180. }
  181. if (lat < minlat) {
  182. minlat = lat;
  183. }
  184. if (lon < minlon) {
  185. minlon = lon;
  186. }
  187. }
  188. gbfprintf(file_out, "%f,%f:%s", lon, lat, CSTR(pin));
  189. if (!nolabels) {
  190. QString temp;
  191. QString desc = csv_stringclean(wpt->description, ":");
  192. if (global_opts.synthesize_shortnames) {
  193. temp = desc;
  194. desc = mkshort(mkshort_whandle, desc);
  195. }
  196. gbfprintf(file_out, ":%s", CSTR(desc));
  197. if (temp != NULL) {
  198. desc = temp;
  199. }
  200. }
  201. gbfprintf(file_out, "\n");
  202. }
  203. #if CLICKMAP
  204. static void
  205. map_plot(const Waypoint* wpt)
  206. {
  207. static int x,y;
  208. /* Replace with real math. */
  209. x+=10;
  210. y+=10;
  211. gbfprintf(linkf, "<area shape=\"circle\" coords=\"%d,%d,7\" href=\"%s\" alt=\"%s\"\n", x, y, wpt->url, wpt->description);
  212. }
  213. #endif /* CLICKMAP */
  214. static double
  215. dscale(double distance)
  216. {
  217. /*
  218. * If we have any specified margin options factor those in now.
  219. * A additional little boundary is helpful because Tiger always
  220. * puts the pin above the actual coord and if we don't pad the
  221. * top will be clipped. It also makes the maps more useful to
  222. * have a little bit of context around the pins on the border.
  223. */
  224. if (strchr(margin, '%')) {
  225. return distance + strtod(margin, NULL) / 100.0 * distance;
  226. } else {
  227. return strtod(margin, NULL) + distance;
  228. }
  229. }
  230. static void
  231. data_write(void)
  232. {
  233. double latsz,lonsz;
  234. maxlat = -9999.0;
  235. maxlon = -9999.0;
  236. minlat = 9999.0;
  237. minlon = 9999.0;
  238. rec_cnt = 0;
  239. short_length = atoi(snlen);
  240. mkshort_whandle = mkshort_new_handle();
  241. if (suppresswhite) {
  242. setshort_whitespace_ok(mkshort_whandle, 0);
  243. }
  244. setshort_length(mkshort_whandle, short_length);
  245. gbfprintf(file_out, "#tms-marker\n");
  246. waypt_disp_all(tiger_disp);
  247. if (genurl) {
  248. gbfile* urlf;
  249. urlf = gbfopen(genurl, "w", MYNAME);
  250. latsz = fabs(maxlat - minlat);
  251. lonsz = fabs(maxlon - minlon);
  252. /*
  253. * Center the map along X and Y axis the midpoint of
  254. * our min and max coords each way.
  255. */
  256. gbfprintf(urlf, "lat=%f&lon=%f&ht=%f&wid=%f",
  257. minlat + (latsz/2.0),
  258. minlon + (lonsz/2.0),
  259. dscale(latsz),
  260. dscale(lonsz));
  261. gbfprintf(urlf, "&iwd=%s&iht=%s", xpixels, ypixels);
  262. gbfclose(urlf);
  263. #if CLICKMAP
  264. if (clickmap) {
  265. linkf = gbfopen(clickmap, "w", MYNAME);
  266. gbfprintf(linkf, "<map name=\"map\">\n");
  267. waypt_disp_all(map_plot);
  268. gbfprintf(linkf, "</map>\n");
  269. gbfclose(linkf);
  270. linkf = NULL;
  271. }
  272. #endif
  273. }
  274. mkshort_del_handle(&mkshort_whandle);
  275. }
  276. ff_vecs_t tiger_vecs = {
  277. ff_type_file,
  278. FF_CAP_RW_WPT,
  279. rd_init,
  280. wr_init,
  281. rd_deinit,
  282. wr_deinit,
  283. data_read,
  284. data_write,
  285. NULL,
  286. tiger_args,
  287. CET_CHARSET_ASCII, 0 /* CET-REVIEW */
  288. };