main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /****************************************************************************
  2. *
  3. * MODULE: r.what
  4. * AUTHOR(S): Michael Shapiro, CERL (original contributor)
  5. * Markus Neteler <neteler itc.it>,Brad Douglas <rez touchofmadness.com>,
  6. * Huidae Cho <grass4u gmail.com>, Glynn Clements <glynn gclements.plus.com>,
  7. * Hamish Bowman <hamish_b yahoo.com>, Soeren Gebbert <soeren.gebbert gmx.de>
  8. * Martin Landa <landa.martin gmail.com>
  9. * PURPOSE:
  10. * COPYRIGHT: (C) 1999-2006, 2012 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #define NFILES 400
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <grass/gis.h>
  23. #include <grass/raster.h>
  24. #include <grass/vector.h>
  25. #include <grass/glocale.h>
  26. struct order
  27. {
  28. int point;
  29. int row;
  30. int col;
  31. char north_buf[256];
  32. char east_buf[256];
  33. char lab_buf[256];
  34. char clr_buf[NFILES][256];
  35. CELL value[NFILES];
  36. DCELL dvalue[NFILES];
  37. };
  38. static int oops(int, const char *, const char *);
  39. static int by_row(const void *, const void *);
  40. static int by_point(const void *, const void *);
  41. static int tty = 0;
  42. int main(int argc, char *argv[])
  43. {
  44. int i, j;
  45. int nfiles;
  46. char *name;
  47. int fd[NFILES];
  48. struct Categories cats[NFILES];
  49. struct Cell_head window;
  50. struct Colors ncolor[NFILES];
  51. struct Colors colors;
  52. RASTER_MAP_TYPE out_type[NFILES];
  53. CELL *cell[NFILES];
  54. DCELL *dcell[NFILES];
  55. struct Map_info Map;
  56. struct line_pnts *Points;
  57. /* int row, col; */
  58. double drow, dcol;
  59. int row_in_window, in_window;
  60. double east, north;
  61. int line, ltype;
  62. char buffer[1024];
  63. char **ptr;
  64. struct _opt {
  65. struct Option *input, *cache, *null, *coords, *fs, *points, *output;
  66. } opt;
  67. struct _flg {
  68. struct Flag *label, *cache, *cat_int, *color, *header;
  69. } flg;
  70. char *fs;
  71. int Cache_size;
  72. int done = FALSE;
  73. int point, point_cnt;
  74. struct order *cache;
  75. int cur_row;
  76. int cache_hit = 0, cache_miss = 0;
  77. int cache_hit_tot = 0, cache_miss_tot = 0;
  78. int pass = 0;
  79. int cache_report = FALSE;
  80. char tmp_buf[500], *null_str;
  81. int red, green, blue;
  82. struct GModule *module;
  83. G_gisinit(argv[0]);
  84. /* Set description */
  85. module = G_define_module();
  86. G_add_keyword(_("raster"));
  87. G_add_keyword(_("querying"));
  88. G_add_keyword(_("position"));
  89. module->description =
  90. _("Queries raster maps on their category values and category labels.");
  91. /* TODO: should be G_OPT_R_INPUTS for consistency but needs overall change where used */
  92. opt.input = G_define_standard_option(G_OPT_R_MAPS);
  93. opt.input->description = _("Name of existing raster map(s) to query");
  94. opt.coords = G_define_standard_option(G_OPT_M_COORDS);
  95. opt.coords->description = _("Coordinates for query");
  96. opt.coords->guisection = _("Query");
  97. opt.points = G_define_standard_option(G_OPT_V_MAP);
  98. opt.points->key = "points";
  99. opt.points->label = _("Name of vector points map for query");
  100. opt.points->required = NO;
  101. opt.points->guisection = _("Query");
  102. opt.null = G_define_option();
  103. opt.null->key = "null";
  104. opt.null->type = TYPE_STRING;
  105. opt.null->required = NO;
  106. opt.null->answer = "*";
  107. opt.null->description = _("Char string to represent no data cell");
  108. opt.null->guisection = _("Print");
  109. opt.output = G_define_standard_option(G_OPT_F_OUTPUT);
  110. opt.output->required = NO;
  111. opt.output->description =
  112. _("Name for output file (if omitted or \"-\" output to stdout)");
  113. opt.fs = G_define_standard_option(G_OPT_F_SEP);
  114. opt.fs->guisection = _("Print");
  115. opt.cache = G_define_option();
  116. opt.cache->key = "cache";
  117. opt.cache->type = TYPE_INTEGER;
  118. opt.cache->required = NO;
  119. opt.cache->multiple = NO;
  120. opt.cache->description = _("Size of point cache");
  121. opt.cache->answer = "500";
  122. opt.cache->guisection = _("Advanced");
  123. flg.header = G_define_flag();
  124. flg.header->key = 'n';
  125. flg.header->description = _("Output header row");
  126. flg.header->guisection = _("Print");
  127. flg.label = G_define_flag();
  128. flg.label->key = 'f';
  129. flg.label->description = _("Show the category labels of the grid cell(s)");
  130. flg.label->guisection = _("Print");
  131. flg.color = G_define_flag();
  132. flg.color->key = 'r';
  133. flg.color->description = _("Output color values as RRR:GGG:BBB");
  134. flg.color->guisection = _("Print");
  135. flg.cat_int = G_define_flag();
  136. flg.cat_int->key = 'i';
  137. flg.cat_int->description = _("Output integer category values, not cell values");
  138. flg.cat_int->guisection = _("Print");
  139. flg.cache = G_define_flag();
  140. flg.cache->key = 'c';
  141. flg.cache->description = _("Turn on cache reporting");
  142. flg.cache->guisection = _("Advanced");
  143. if (G_parser(argc, argv))
  144. exit(EXIT_FAILURE);
  145. name = opt.output->answer;
  146. if (name != NULL && strcmp(name, "-") != 0) {
  147. if (NULL == freopen(name, "w", stdout)) {
  148. G_fatal_error(_("Unable to open file <%s> for writing"), name);
  149. }
  150. }
  151. tty = isatty(0);
  152. fs = G_option_to_separator(opt.fs);
  153. null_str = opt.null->answer;
  154. if (tty)
  155. Cache_size = 1;
  156. else
  157. Cache_size = atoi(opt.cache->answer);
  158. if (Cache_size < 1)
  159. Cache_size = 1;
  160. cache = (struct order *)G_malloc(sizeof(struct order) * Cache_size);
  161. /* enable cache report */
  162. if (flg.cache->answer)
  163. cache_report = TRUE;
  164. /* open raster maps to query */
  165. ptr = opt.input->answers;
  166. nfiles = 0;
  167. for (; *ptr != NULL; ptr++) {
  168. char name[GNAME_MAX];
  169. if (nfiles >= NFILES)
  170. G_fatal_error(_("Can only do up to %d raster maps (%d given)"),
  171. NFILES, nfiles);
  172. strcpy(name, *ptr);
  173. fd[nfiles] = Rast_open_old(name, "");
  174. out_type[nfiles] = Rast_get_map_type(fd[nfiles]);
  175. if (flg.cat_int->answer)
  176. out_type[nfiles] = CELL_TYPE;
  177. if (flg.color->answer) {
  178. Rast_read_colors(name, "", &colors);
  179. ncolor[nfiles] = colors;
  180. }
  181. if (flg.label->answer && Rast_read_cats(name, "", &cats[nfiles]) < 0)
  182. G_fatal_error(_("Unable to read category file for <%s>"), name);
  183. nfiles++;
  184. }
  185. /* allocate row buffers */
  186. for (i = 0; i < nfiles; i++) {
  187. if (flg.cat_int->answer)
  188. out_type[i] = CELL_TYPE;
  189. cell[i] = Rast_allocate_c_buf();
  190. if (out_type[i] != CELL_TYPE)
  191. dcell[i] = Rast_allocate_d_buf();
  192. }
  193. /* open vector points map */
  194. if (opt.points->answer) {
  195. Vect_set_open_level(1); /* topology not required */
  196. if (Vect_open_old(&Map, opt.points->answer, "") < 0)
  197. G_fatal_error(_("Unable to open vector map <%s>"), opt.points->answer);
  198. }
  199. Points = Vect_new_line_struct();
  200. G_get_window(&window);
  201. /* print header row */
  202. if(flg.header->answer) {
  203. fprintf(stdout, "easting%snorthing%ssite_name", fs, fs);
  204. ptr = opt.input->answers;
  205. for (; *ptr != NULL; ptr++) {
  206. char name[GNAME_MAX];
  207. strcpy(name, *ptr);
  208. fprintf(stdout, "%s%s", fs, name);
  209. if (flg.label->answer)
  210. fprintf(stdout, "%s%s_label", fs, name);
  211. if (flg.color->answer)
  212. fprintf(stdout, "%s%s_color", fs, name);
  213. }
  214. fprintf(stdout, "\n");
  215. }
  216. line = 0;
  217. if (!opt.coords->answers && !opt.points->answers && tty)
  218. fprintf(stderr, "enter points, \"end\" to quit\n");
  219. j = 0;
  220. done = FALSE;
  221. while (!done) {
  222. pass++;
  223. if (cache_report & !tty)
  224. fprintf(stderr, "Pass %3d Line %6d - ", pass, line);
  225. cache_hit = cache_miss = 0;
  226. if (!opt.coords->answers && !opt.points->answers && tty) {
  227. fprintf(stderr, "\neast north [label] > ");
  228. Cache_size = 1;
  229. }
  230. {
  231. point_cnt = 0;
  232. for (i = 0; i < Cache_size; i++) {
  233. if (!opt.coords->answers && !opt.points->answers &&
  234. fgets(buffer, 1000, stdin) == NULL)
  235. done = TRUE;
  236. else {
  237. line++;
  238. if ((!opt.coords->answers && !opt.points->answers &&
  239. (strncmp(buffer, "end\n", 4) == 0 ||
  240. strncmp(buffer, "exit\n", 5) == 0)) ||
  241. (opt.coords->answers && !opt.coords->answers[j])) {
  242. done = TRUE;
  243. }
  244. else {
  245. if (opt.points->answer) {
  246. ltype = Vect_read_next_line(&Map, Points, NULL);
  247. if (ltype == -1)
  248. G_fatal_error(_("Unable to read vector map <%s>"), Vect_get_full_name(&Map));
  249. else if (ltype == -2)
  250. done = TRUE;
  251. else if (!(ltype & GV_POINTS)) {
  252. G_warning(_("Line %d is not point or centroid, skipped"), line);
  253. continue;
  254. }
  255. else {
  256. east = Points->x[0];
  257. north = Points->y[0];
  258. sprintf(cache[point_cnt].east_buf, "%f", east);
  259. sprintf(cache[point_cnt].north_buf, "%f", north);
  260. }
  261. }
  262. else {
  263. *(cache[point_cnt].lab_buf) =
  264. *(cache[point_cnt].east_buf) =
  265. *(cache[point_cnt].north_buf) = 0;
  266. if (!opt.coords->answers)
  267. sscanf(buffer, "%s %s %[^\n]",
  268. cache[point_cnt].east_buf,
  269. cache[point_cnt].north_buf,
  270. cache[point_cnt].lab_buf);
  271. else {
  272. strcpy(cache[point_cnt].east_buf,
  273. opt.coords->answers[j++]);
  274. strcpy(cache[point_cnt].north_buf,
  275. opt.coords->answers[j++]);
  276. }
  277. if (*(cache[point_cnt].east_buf) == 0)
  278. continue; /* skip blank lines */
  279. if (*(cache[point_cnt].north_buf) == 0) {
  280. oops(line, buffer,
  281. "two coordinates (east north) required");
  282. continue;
  283. }
  284. if (!G_scan_northing(cache[point_cnt].north_buf, &north, window.proj) ||
  285. !G_scan_easting(cache[point_cnt].east_buf, &east, window.proj)) {
  286. oops(line, buffer, "invalid coordinate(s)");
  287. continue;
  288. }
  289. }
  290. /* convert north, east to row and col */
  291. drow = Rast_northing_to_row(north, &window);
  292. dcol = Rast_easting_to_col(east, &window);
  293. /* a special case.
  294. * if north falls at southern edge, or east falls on eastern edge,
  295. * the point will appear outside the window.
  296. * So, for these edges, bring the point inside the window
  297. */
  298. if (drow == window.rows)
  299. drow--;
  300. if (dcol == window.cols)
  301. dcol--;
  302. cache[point_cnt].row = (int)drow;
  303. cache[point_cnt].col = (int)dcol;
  304. cache[point_cnt].point = point_cnt;
  305. point_cnt++;
  306. }
  307. }
  308. }
  309. }
  310. if (Cache_size > 1)
  311. qsort(cache, point_cnt, sizeof(struct order), by_row);
  312. /* extract data from files and store in cache */
  313. cur_row = -99;
  314. for (point = 0; point < point_cnt; point++) {
  315. row_in_window = 1;
  316. in_window = 1;
  317. if (cache[point].row < 0 || cache[point].row >= window.rows)
  318. row_in_window = in_window = 0;
  319. if (cache[point].col < 0 || cache[point].col >= window.cols)
  320. in_window = 0;
  321. if (!in_window) {
  322. if (tty)
  323. G_warning(_("%s %s is outside your current region"),
  324. cache[point].east_buf, cache[point].north_buf);
  325. }
  326. if (cur_row != cache[point].row) {
  327. cache_miss++;
  328. if (row_in_window)
  329. for (i = 0; i < nfiles; i++) {
  330. Rast_get_c_row(fd[i], cell[i], cache[point].row);
  331. if (out_type[i] != CELL_TYPE)
  332. Rast_get_d_row(fd[i], dcell[i], cache[point].row);
  333. }
  334. cur_row = cache[point].row;
  335. }
  336. else
  337. cache_hit++;
  338. for (i = 0; i < nfiles; i++) {
  339. if (in_window)
  340. cache[point].value[i] = cell[i][cache[point].col];
  341. else
  342. Rast_set_c_null_value(&(cache[point].value[i]), 1);
  343. if (out_type[i] != CELL_TYPE) {
  344. if (in_window)
  345. cache[point].dvalue[i] = dcell[i][cache[point].col];
  346. else
  347. Rast_set_d_null_value(&(cache[point].dvalue[i]), 1);
  348. }
  349. if (flg.color->answer) {
  350. if (out_type[i] == CELL_TYPE)
  351. Rast_get_c_color(&cell[i][cache[point].col],
  352. &red, &green, &blue, &ncolor[i]);
  353. else
  354. Rast_get_d_color(&dcell[i][cache[point].col],
  355. &red, &green, &blue, &ncolor[i]);
  356. sprintf(cache[point].clr_buf[i], "%03d:%03d:%03d", red,
  357. green, blue);
  358. }
  359. }
  360. } /* point loop */
  361. if (Cache_size > 1)
  362. qsort(cache, point_cnt, sizeof(struct order), by_point);
  363. /* report data from re-ordered cache */
  364. for (point = 0; point < point_cnt; point++) {
  365. G_debug(1, "%s|%s at col %d, row %d\n",
  366. cache[point].east_buf, cache[point].north_buf,
  367. cache[point].col, cache[point].row);
  368. fprintf(stdout, "%s%s%s%s%s", cache[point].east_buf, fs,
  369. cache[point].north_buf, fs, cache[point].lab_buf);
  370. for (i = 0; i < nfiles; i++) {
  371. if (out_type[i] == CELL_TYPE) {
  372. if (Rast_is_c_null_value(&cache[point].value[i])) {
  373. fprintf(stdout, "%s%s", fs, null_str);
  374. if (flg.label->answer)
  375. fprintf(stdout, "%s", fs);
  376. if (flg.color->answer)
  377. fprintf(stdout, "%s", fs);
  378. continue;
  379. }
  380. fprintf(stdout, "%s%ld", fs, (long)cache[point].value[i]);
  381. }
  382. else { /* FCELL or DCELL */
  383. if (Rast_is_d_null_value(&cache[point].dvalue[i])) {
  384. fprintf(stdout, "%s%s", fs, null_str);
  385. if (flg.label->answer)
  386. fprintf(stdout, "%s", fs);
  387. if (flg.color->answer)
  388. fprintf(stdout, "%s", fs);
  389. continue;
  390. }
  391. if (out_type[i] == FCELL_TYPE)
  392. sprintf(tmp_buf, "%.7g", cache[point].dvalue[i]);
  393. else /* DCELL */
  394. sprintf(tmp_buf, "%.15g", cache[point].dvalue[i]);
  395. G_trim_decimal(tmp_buf); /* not needed with %g? */
  396. fprintf(stdout, "%s%s", fs, tmp_buf);
  397. }
  398. if (flg.label->answer)
  399. fprintf(stdout, "%s%s", fs,
  400. Rast_get_c_cat(&(cache[point].value[i]), &cats[i]));
  401. if (flg.color->answer)
  402. fprintf(stdout, "%s%s", fs, cache[point].clr_buf[i]);
  403. }
  404. fprintf(stdout, "\n");
  405. }
  406. if (cache_report & !tty)
  407. fprintf(stderr, "Cache Hit: %6d Miss: %6d\n",
  408. cache_hit, cache_miss);
  409. cache_hit_tot += cache_hit;
  410. cache_miss_tot += cache_miss;
  411. cache_hit = cache_miss = 0;
  412. }
  413. if (!opt.coords->answers && !opt.points->answers && tty)
  414. fprintf(stderr, "\n");
  415. if (cache_report & !tty)
  416. fprintf(stderr, "Total: Cache Hit: %6d Miss: %6d\n",
  417. cache_hit_tot, cache_miss_tot);
  418. /* close vector points map */
  419. if (opt.points->answer) {
  420. Vect_close(&Map);
  421. }
  422. Vect_destroy_line_struct(Points);
  423. exit(EXIT_SUCCESS);
  424. }
  425. /* *************************************************************** */
  426. /* *************************************************************** */
  427. /* *************************************************************** */
  428. static int oops(int line, const char *buf, const char *msg)
  429. {
  430. static int first = 1;
  431. if (!tty) {
  432. if (first) {
  433. G_warning("Input errors:");
  434. first = 0;
  435. }
  436. G_warning("line %d: %s", line, buf);
  437. }
  438. G_warning("%s", msg);
  439. return 0;
  440. }
  441. /* *************************************************************** */
  442. /* for qsort, order list by row ********************************* */
  443. /* *************************************************************** */
  444. static int by_row(const void *ii, const void *jj)
  445. {
  446. const struct order *i = ii, *j = jj;
  447. return i->row - j->row;
  448. }
  449. /* *************************************************************** */
  450. /* for qsort, order list by point ******************************* */
  451. /* *************************************************************** */
  452. /* for qsort, order list by point */
  453. static int by_point(const void *ii, const void *jj)
  454. {
  455. const struct order *i = ii, *j = jj;
  456. return i->point - j->point;
  457. }