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 *oname;
  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_standard_option(G_OPT_M_NULL_VALUE);
  103. opt.null->answer = "*";
  104. opt.null->guisection = _("Print");
  105. opt.output = G_define_standard_option(G_OPT_F_OUTPUT);
  106. opt.output->required = NO;
  107. opt.output->description =
  108. _("Name for output file (if omitted or \"-\" output to stdout)");
  109. opt.fs = G_define_standard_option(G_OPT_F_SEP);
  110. opt.fs->guisection = _("Print");
  111. opt.cache = G_define_option();
  112. opt.cache->key = "cache";
  113. opt.cache->type = TYPE_INTEGER;
  114. opt.cache->required = NO;
  115. opt.cache->multiple = NO;
  116. opt.cache->description = _("Size of point cache");
  117. opt.cache->answer = "500";
  118. opt.cache->guisection = _("Advanced");
  119. flg.header = G_define_flag();
  120. flg.header->key = 'n';
  121. flg.header->description = _("Output header row");
  122. flg.header->guisection = _("Print");
  123. flg.label = G_define_flag();
  124. flg.label->key = 'f';
  125. flg.label->description = _("Show the category labels of the grid cell(s)");
  126. flg.label->guisection = _("Print");
  127. flg.color = G_define_flag();
  128. flg.color->key = 'r';
  129. flg.color->description = _("Output color values as RRR:GGG:BBB");
  130. flg.color->guisection = _("Print");
  131. flg.cat_int = G_define_flag();
  132. flg.cat_int->key = 'i';
  133. flg.cat_int->description = _("Output integer category values, not cell values");
  134. flg.cat_int->guisection = _("Print");
  135. flg.cache = G_define_flag();
  136. flg.cache->key = 'c';
  137. flg.cache->description = _("Turn on cache reporting");
  138. flg.cache->guisection = _("Advanced");
  139. if (G_parser(argc, argv))
  140. exit(EXIT_FAILURE);
  141. oname = opt.output->answer;
  142. if (oname != NULL && strcmp(oname, "-") != 0) {
  143. if (NULL == freopen(oname, "w", stdout)) {
  144. G_fatal_error(_("Unable to open file <%s> for writing"), oname);
  145. }
  146. }
  147. tty = isatty(0);
  148. fs = G_option_to_separator(opt.fs);
  149. null_str = opt.null->answer;
  150. if (tty)
  151. Cache_size = 1;
  152. else
  153. Cache_size = atoi(opt.cache->answer);
  154. if (Cache_size < 1)
  155. Cache_size = 1;
  156. cache = (struct order *)G_malloc(sizeof(struct order) * Cache_size);
  157. /* enable cache report */
  158. if (flg.cache->answer)
  159. cache_report = TRUE;
  160. /* open raster maps to query */
  161. ptr = opt.input->answers;
  162. nfiles = 0;
  163. for (; *ptr != NULL; ptr++) {
  164. char name[GNAME_MAX];
  165. if (nfiles >= NFILES)
  166. G_fatal_error(_("Can only do up to %d raster maps"
  167. " (more than %d given)"),
  168. NFILES, NFILES);
  169. strcpy(name, *ptr);
  170. fd[nfiles] = Rast_open_old(name, "");
  171. out_type[nfiles] = Rast_get_map_type(fd[nfiles]);
  172. if (flg.cat_int->answer)
  173. out_type[nfiles] = CELL_TYPE;
  174. if (flg.color->answer) {
  175. Rast_read_colors(name, "", &colors);
  176. ncolor[nfiles] = colors;
  177. }
  178. if (flg.label->answer && Rast_read_cats(name, "", &cats[nfiles]) < 0)
  179. G_fatal_error(_("Unable to read category file for <%s>"), name);
  180. nfiles++;
  181. }
  182. /* allocate row buffers */
  183. for (i = 0; i < nfiles; i++) {
  184. if (flg.cat_int->answer)
  185. out_type[i] = CELL_TYPE;
  186. cell[i] = Rast_allocate_c_buf();
  187. if (out_type[i] != CELL_TYPE)
  188. dcell[i] = Rast_allocate_d_buf();
  189. }
  190. /* open vector points map */
  191. if (opt.points->answer) {
  192. Vect_set_open_level(1); /* topology not required */
  193. if (Vect_open_old(&Map, opt.points->answer, "") < 0)
  194. G_fatal_error(_("Unable to open vector map <%s>"), opt.points->answer);
  195. }
  196. Points = Vect_new_line_struct();
  197. G_get_window(&window);
  198. /* print header row */
  199. if(flg.header->answer) {
  200. fprintf(stdout, "easting%snorthing%ssite_name", fs, fs);
  201. ptr = opt.input->answers;
  202. for (; *ptr != NULL; ptr++) {
  203. char name[GNAME_MAX];
  204. strcpy(name, *ptr);
  205. fprintf(stdout, "%s%s", fs, name);
  206. if (flg.label->answer)
  207. fprintf(stdout, "%s%s_label", fs, name);
  208. if (flg.color->answer)
  209. fprintf(stdout, "%s%s_color", fs, name);
  210. }
  211. fprintf(stdout, "\n");
  212. }
  213. line = 0;
  214. if (!opt.coords->answers && !opt.points->answers && tty)
  215. fprintf(stderr, "enter points, \"end\" to quit\n");
  216. j = 0;
  217. done = FALSE;
  218. while (!done) {
  219. pass++;
  220. if (cache_report & !tty)
  221. fprintf(stderr, "Pass %3d Line %6d - ", pass, line);
  222. cache_hit = cache_miss = 0;
  223. if (!opt.coords->answers && !opt.points->answers && tty) {
  224. fprintf(stderr, "\neast north [label] > ");
  225. Cache_size = 1;
  226. }
  227. {
  228. point_cnt = 0;
  229. for (i = 0; i < Cache_size; i++) {
  230. if (!opt.coords->answers && !opt.points->answers &&
  231. fgets(buffer, 1000, stdin) == NULL)
  232. done = TRUE;
  233. else {
  234. line++;
  235. if ((!opt.coords->answers && !opt.points->answers &&
  236. (strncmp(buffer, "end\n", 4) == 0 ||
  237. strncmp(buffer, "exit\n", 5) == 0)) ||
  238. (opt.coords->answers && !opt.coords->answers[j])) {
  239. done = TRUE;
  240. }
  241. else {
  242. if (opt.points->answer) {
  243. ltype = Vect_read_next_line(&Map, Points, NULL);
  244. if (ltype == -1)
  245. G_fatal_error(_("Unable to read vector map <%s>"), Vect_get_full_name(&Map));
  246. else if (ltype == -2)
  247. done = TRUE;
  248. else if (!(ltype & GV_POINTS)) {
  249. G_warning(_("Line %d is not point or centroid, skipped"), line);
  250. continue;
  251. }
  252. else {
  253. east = Points->x[0];
  254. north = Points->y[0];
  255. sprintf(cache[point_cnt].east_buf, "%.15g", east);
  256. sprintf(cache[point_cnt].north_buf, "%.15g", north);
  257. }
  258. }
  259. else {
  260. *(cache[point_cnt].lab_buf) =
  261. *(cache[point_cnt].east_buf) =
  262. *(cache[point_cnt].north_buf) = 0;
  263. if (!opt.coords->answers)
  264. sscanf(buffer, "%s %s %[^\n]",
  265. cache[point_cnt].east_buf,
  266. cache[point_cnt].north_buf,
  267. cache[point_cnt].lab_buf);
  268. else {
  269. strcpy(cache[point_cnt].east_buf,
  270. opt.coords->answers[j++]);
  271. strcpy(cache[point_cnt].north_buf,
  272. opt.coords->answers[j++]);
  273. }
  274. if (*(cache[point_cnt].east_buf) == 0)
  275. continue; /* skip blank lines */
  276. if (*(cache[point_cnt].north_buf) == 0) {
  277. oops(line, buffer,
  278. "two coordinates (east north) required");
  279. continue;
  280. }
  281. if (!G_scan_northing(cache[point_cnt].north_buf, &north, window.proj) ||
  282. !G_scan_easting(cache[point_cnt].east_buf, &east, window.proj)) {
  283. oops(line, buffer, "invalid coordinate(s)");
  284. continue;
  285. }
  286. }
  287. /* convert north, east to row and col */
  288. drow = Rast_northing_to_row(north, &window);
  289. dcol = Rast_easting_to_col(east, &window);
  290. /* a special case.
  291. * if north falls at southern edge, or east falls on eastern edge,
  292. * the point will appear outside the window.
  293. * So, for these edges, bring the point inside the window
  294. */
  295. if (drow == window.rows)
  296. drow--;
  297. if (dcol == window.cols)
  298. dcol--;
  299. if (!done) {
  300. cache[point_cnt].row = (int)drow;
  301. cache[point_cnt].col = (int)dcol;
  302. cache[point_cnt].point = point_cnt;
  303. point_cnt++;
  304. }
  305. }
  306. }
  307. }
  308. }
  309. if (Cache_size > 1)
  310. qsort(cache, point_cnt, sizeof(struct order), by_row);
  311. /* extract data from files and store in cache */
  312. cur_row = -99;
  313. for (point = 0; point < point_cnt; point++) {
  314. row_in_window = 1;
  315. in_window = 1;
  316. if (cache[point].row < 0 || cache[point].row >= window.rows)
  317. row_in_window = in_window = 0;
  318. if (cache[point].col < 0 || cache[point].col >= window.cols)
  319. in_window = 0;
  320. if (!in_window) {
  321. if (tty)
  322. G_warning(_("%s %s is outside your current region"),
  323. cache[point].east_buf, cache[point].north_buf);
  324. }
  325. if (cur_row != cache[point].row) {
  326. cache_miss++;
  327. if (row_in_window)
  328. for (i = 0; i < nfiles; i++) {
  329. Rast_get_c_row(fd[i], cell[i], cache[point].row);
  330. if (out_type[i] != CELL_TYPE)
  331. Rast_get_d_row(fd[i], dcell[i], cache[point].row);
  332. }
  333. cur_row = cache[point].row;
  334. }
  335. else
  336. cache_hit++;
  337. for (i = 0; i < nfiles; i++) {
  338. if (in_window)
  339. cache[point].value[i] = cell[i][cache[point].col];
  340. else
  341. Rast_set_c_null_value(&(cache[point].value[i]), 1);
  342. if (out_type[i] != CELL_TYPE) {
  343. if (in_window)
  344. cache[point].dvalue[i] = dcell[i][cache[point].col];
  345. else
  346. Rast_set_d_null_value(&(cache[point].dvalue[i]), 1);
  347. }
  348. if (flg.color->answer) {
  349. if (out_type[i] == CELL_TYPE)
  350. Rast_get_c_color(&(cache[point].value[i]),
  351. &red, &green, &blue, &ncolor[i]);
  352. else
  353. Rast_get_d_color(&(cache[point].dvalue[i]),
  354. &red, &green, &blue, &ncolor[i]);
  355. sprintf(cache[point].clr_buf[i], "%03d:%03d:%03d", red,
  356. green, blue);
  357. }
  358. }
  359. } /* point loop */
  360. if (Cache_size > 1)
  361. qsort(cache, point_cnt, sizeof(struct order), by_point);
  362. /* report data from re-ordered cache */
  363. for (point = 0; point < point_cnt; point++) {
  364. G_debug(1, "%s|%s at col %d, row %d\n",
  365. cache[point].east_buf, cache[point].north_buf,
  366. cache[point].col, cache[point].row);
  367. fprintf(stdout, "%s%s%s%s%s", cache[point].east_buf, fs,
  368. cache[point].north_buf, fs, cache[point].lab_buf);
  369. for (i = 0; i < nfiles; i++) {
  370. if (out_type[i] == CELL_TYPE) {
  371. if (Rast_is_c_null_value(&cache[point].value[i])) {
  372. fprintf(stdout, "%s%s", fs, null_str);
  373. if (flg.label->answer)
  374. fprintf(stdout, "%s", fs);
  375. if (flg.color->answer)
  376. fprintf(stdout, "%s", fs);
  377. continue;
  378. }
  379. fprintf(stdout, "%s%ld", fs, (long)cache[point].value[i]);
  380. cache[point].dvalue[i] = 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_d_cat(&(cache[point].dvalue[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. }