main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /****************************************************************************
  2. *
  3. * MODULE: r.grow.distance
  4. *
  5. * AUTHOR(S): Marjorie Larson - CERL
  6. * Glynn Clements
  7. *
  8. * PURPOSE: Generates a raster map layer with contiguous areas
  9. * grown by one cell.
  10. *
  11. * COPYRIGHT: (C) 2006-2013 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General Public
  14. * License (>=v2). Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. ***************************************************************************/
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include <unistd.h>
  23. #include <fcntl.h>
  24. #include <grass/gis.h>
  25. #include <grass/raster.h>
  26. #include <grass/glocale.h>
  27. static struct Cell_head window;
  28. static int nrows, ncols;
  29. static DCELL *in_row;
  30. static CELL *old_x_row, *old_y_row;
  31. static CELL *new_x_row, *new_y_row;
  32. static DCELL *dist_row;
  33. static DCELL *old_val_row, *new_val_row;
  34. static double (*distance) (double dx, double dy);
  35. static double xres, yres;
  36. #undef MAX
  37. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  38. static double distance_euclidean_squared(double dx, double dy)
  39. {
  40. return dx * dx + dy * dy;
  41. }
  42. static double distance_maximum(double dx, double dy)
  43. {
  44. return MAX(abs(dx), abs(dy));
  45. }
  46. static double distance_manhattan(double dx, double dy)
  47. {
  48. return abs(dx) + abs(dy);
  49. }
  50. static double geodesic_distance(int x1, int y1, int x2, int y2)
  51. {
  52. double lat1 = Rast_row_to_northing(y1 + 0.5, &window);
  53. double lat2 = Rast_row_to_northing(y2 + 0.5, &window);
  54. double lon1 = Rast_col_to_easting(x1 + 0.5, &window);
  55. double lon2 = Rast_col_to_easting(x2 + 0.5, &window);
  56. return G_geodesic_distance(lon1, lat1, lon2, lat2);
  57. }
  58. void swap_rows(void)
  59. {
  60. CELL *temp;
  61. DCELL *dtemp;
  62. temp = old_x_row;
  63. old_x_row = new_x_row;
  64. new_x_row = temp;
  65. temp = old_y_row;
  66. old_y_row = new_y_row;
  67. new_y_row = temp;
  68. dtemp = old_val_row;
  69. old_val_row = new_val_row;
  70. new_val_row = dtemp;
  71. }
  72. static void check(int row, int col, int dx, int dy)
  73. {
  74. const CELL *xrow = dy ? old_x_row : new_x_row;
  75. const CELL *yrow = dy ? old_y_row : new_y_row;
  76. const DCELL *vrow = dy ? old_val_row : new_val_row;
  77. int x, y;
  78. double d, v;
  79. if (dist_row[col] == 0)
  80. return;
  81. if (col + dx < 0)
  82. return;
  83. if (col + dx >= ncols)
  84. return;
  85. if (Rast_is_c_null_value(&xrow[col + dx]))
  86. return;
  87. x = xrow[col + dx] + dx;
  88. y = yrow[col + dx] + dy;
  89. v = vrow[col + dx];
  90. d = distance
  91. ? (*distance) (xres * x, yres * y)
  92. : geodesic_distance(col, row, col + x, row + y);
  93. if (!Rast_is_d_null_value(&dist_row[col]) && dist_row[col] < d)
  94. return;
  95. dist_row[col] = d;
  96. new_val_row[col] = v;
  97. new_x_row[col] = x;
  98. new_y_row[col] = y;
  99. }
  100. int main(int argc, char **argv)
  101. {
  102. struct GModule *module;
  103. struct
  104. {
  105. struct Option *in, *dist, *val, *met;
  106. } opt;
  107. struct
  108. {
  109. struct Flag *m, *n;
  110. } flag;
  111. const char *in_name;
  112. const char *dist_name;
  113. const char *val_name;
  114. int in_fd;
  115. int dist_fd, val_fd;
  116. char *temp_name;
  117. int temp_fd;
  118. int row, col;
  119. struct Colors colors;
  120. struct History hist;
  121. DCELL *out_row;
  122. double scale = 1.0;
  123. int invert;
  124. G_gisinit(argv[0]);
  125. module = G_define_module();
  126. G_add_keyword(_("raster"));
  127. G_add_keyword(_("distance"));
  128. G_add_keyword(_("proximity"));
  129. module->description =
  130. _("Generates a raster map containing distances to nearest raster features.");
  131. opt.in = G_define_standard_option(G_OPT_R_INPUT);
  132. opt.dist = G_define_standard_option(G_OPT_R_OUTPUT);
  133. opt.dist->key = "distance";
  134. opt.dist->required = NO;
  135. opt.dist->description = _("Name for distance output raster map");
  136. opt.dist->guisection = _("Output");
  137. opt.val = G_define_standard_option(G_OPT_R_OUTPUT);
  138. opt.val->key = "value";
  139. opt.val->required = NO;
  140. opt.val->description = _("Name for value output raster map");
  141. opt.val->guisection = _("Output");
  142. opt.met = G_define_option();
  143. opt.met->key = "metric";
  144. opt.met->type = TYPE_STRING;
  145. opt.met->required = NO;
  146. opt.met->description = _("Metric");
  147. opt.met->options = "euclidean,squared,maximum,manhattan,geodesic";
  148. opt.met->answer = "euclidean";
  149. flag.m = G_define_flag();
  150. flag.m->key = 'm';
  151. flag.m->description = _("Output distances in meters instead of map units");
  152. flag.n = G_define_flag();
  153. flag.n->key = 'n';
  154. flag.n->description = _("Calculate distance to nearest NULL cell");
  155. if (G_parser(argc, argv))
  156. exit(EXIT_FAILURE);
  157. in_name = opt.in->answer;
  158. dist_name = opt.dist->answer;
  159. val_name = opt.val->answer;
  160. if ((invert = flag.n->answer)) {
  161. if (!dist_name)
  162. G_fatal_error(_("Distance output is required for distance to NULL cells"));
  163. if (val_name) {
  164. G_warning(_("Value output is meaningless for distance to NULL cells"));
  165. val_name = NULL;
  166. }
  167. }
  168. if (!dist_name && !val_name)
  169. G_fatal_error(_("At least one of distance= and value= must be given"));
  170. G_get_window(&window);
  171. if (strcmp(opt.met->answer, "euclidean") == 0)
  172. distance = &distance_euclidean_squared;
  173. else if (strcmp(opt.met->answer, "squared") == 0)
  174. distance = &distance_euclidean_squared;
  175. else if (strcmp(opt.met->answer, "maximum") == 0)
  176. distance = &distance_maximum;
  177. else if (strcmp(opt.met->answer, "manhattan") == 0)
  178. distance = &distance_manhattan;
  179. else if (strcmp(opt.met->answer, "geodesic") == 0) {
  180. double a, e2;
  181. if (window.proj != PROJECTION_LL)
  182. G_fatal_error(_("metric=geodesic is only valid for lat/lon"));
  183. distance = NULL;
  184. G_get_ellipsoid_parameters(&a, &e2);
  185. G_begin_geodesic_distance(a, e2);
  186. }
  187. else
  188. G_fatal_error(_("Unknown metric: '%s'"), opt.met->answer);
  189. if (flag.m->answer) {
  190. if (window.proj == PROJECTION_LL &&
  191. strcmp(opt.met->answer, "geodesic") != 0) {
  192. G_fatal_error(_("Output distance in meters for lat/lon is only possible with '%s=%s'"),
  193. opt.met->key, "geodesic");
  194. }
  195. scale = G_database_units_to_meters_factor();
  196. if (strcmp(opt.met->answer, "squared") == 0)
  197. scale *= scale;
  198. }
  199. in_fd = Rast_open_old(in_name, "");
  200. if (dist_name)
  201. dist_fd = Rast_open_new(dist_name, DCELL_TYPE);
  202. if (val_name)
  203. val_fd = Rast_open_new(val_name, DCELL_TYPE);
  204. temp_name = G_tempfile();
  205. temp_fd = open(temp_name, O_RDWR | O_CREAT | O_EXCL, 0700);
  206. if (temp_fd < 0)
  207. G_fatal_error(_("Unable to create temporary file <%s>"), temp_name);
  208. nrows = window.rows;
  209. ncols = window.cols;
  210. xres = window.ew_res;
  211. yres = window.ns_res;
  212. in_row = Rast_allocate_d_buf();
  213. old_val_row = Rast_allocate_d_buf();
  214. new_val_row = Rast_allocate_d_buf();
  215. old_x_row = Rast_allocate_c_buf();
  216. old_y_row = Rast_allocate_c_buf();
  217. new_x_row = Rast_allocate_c_buf();
  218. new_y_row = Rast_allocate_c_buf();
  219. dist_row = Rast_allocate_d_buf();
  220. if (dist_name && strcmp(opt.met->answer, "euclidean") == 0)
  221. out_row = Rast_allocate_d_buf();
  222. else
  223. out_row = dist_row;
  224. Rast_set_c_null_value(old_x_row, ncols);
  225. Rast_set_c_null_value(old_y_row, ncols);
  226. G_message(_("Reading raster map <%s>..."), opt.in->answer);
  227. for (row = 0; row < nrows; row++) {
  228. int irow = nrows - 1 - row;
  229. G_percent(row, nrows, 2);
  230. Rast_set_c_null_value(new_x_row, ncols);
  231. Rast_set_c_null_value(new_y_row, ncols);
  232. Rast_set_d_null_value(dist_row, ncols);
  233. Rast_get_d_row(in_fd, in_row, irow);
  234. for (col = 0; col < ncols; col++) {
  235. if (Rast_is_d_null_value(&in_row[col]) == invert) {
  236. new_x_row[col] = 0;
  237. new_y_row[col] = 0;
  238. dist_row[col] = 0;
  239. new_val_row[col] = in_row[col];
  240. }
  241. }
  242. for (col = 0; col < ncols; col++)
  243. check(irow, col, -1, 0);
  244. for (col = ncols - 1; col >= 0; col--)
  245. check(irow, col, 1, 0);
  246. for (col = 0; col < ncols; col++) {
  247. check(irow, col, -1, 1);
  248. check(irow, col, 0, 1);
  249. check(irow, col, 1, 1);
  250. }
  251. write(temp_fd, new_x_row, ncols * sizeof(CELL));
  252. write(temp_fd, new_y_row, ncols * sizeof(CELL));
  253. write(temp_fd, dist_row, ncols * sizeof(DCELL));
  254. write(temp_fd, new_val_row, ncols * sizeof(DCELL));
  255. swap_rows();
  256. }
  257. G_percent(row, nrows, 2);
  258. Rast_close(in_fd);
  259. Rast_set_c_null_value(old_x_row, ncols);
  260. Rast_set_c_null_value(old_y_row, ncols);
  261. G_message(_("Writing output raster maps..."));
  262. for (row = 0; row < nrows; row++) {
  263. int irow = nrows - 1 - row;
  264. off_t offset =
  265. (off_t) irow * ncols * (2 * sizeof(CELL) + 2 * sizeof(DCELL));
  266. G_percent(row, nrows, 2);
  267. lseek(temp_fd, offset, SEEK_SET);
  268. read(temp_fd, new_x_row, ncols * sizeof(CELL));
  269. read(temp_fd, new_y_row, ncols * sizeof(CELL));
  270. read(temp_fd, dist_row, ncols * sizeof(DCELL));
  271. read(temp_fd, new_val_row, ncols * sizeof(DCELL));
  272. for (col = 0; col < ncols; col++) {
  273. check(row, col, -1, -1);
  274. check(row, col, 0, -1);
  275. check(row, col, 1, -1);
  276. }
  277. for (col = 0; col < ncols; col++)
  278. check(row, col, -1, 0);
  279. for (col = ncols - 1; col >= 0; col--)
  280. check(row, col, 1, 0);
  281. if (dist_name) {
  282. if (out_row != dist_row)
  283. for (col = 0; col < ncols; col++)
  284. out_row[col] = sqrt(dist_row[col]);
  285. if (scale != 1.0)
  286. for (col = 0; col < ncols; col++)
  287. out_row[col] *= scale;
  288. Rast_put_d_row(dist_fd, out_row);
  289. }
  290. if (val_name)
  291. Rast_put_d_row(val_fd, new_val_row);
  292. swap_rows();
  293. }
  294. G_percent(row, nrows, 2);
  295. close(temp_fd);
  296. remove(temp_name);
  297. if (dist_name)
  298. Rast_close(dist_fd);
  299. if (val_name)
  300. Rast_close(val_fd);
  301. if (val_name) {
  302. if (Rast_read_colors(in_name, "", &colors) < 0)
  303. G_fatal_error(_("Unable to read color table for raster map <%s>"), in_name);
  304. Rast_write_colors(val_name, G_mapset(), &colors);
  305. Rast_short_history(val_name, "raster", &hist);
  306. Rast_set_history(&hist, HIST_DATSRC_1, in_name);
  307. Rast_append_format_history(&hist, "value of nearest feature");
  308. Rast_command_history(&hist);
  309. Rast_write_history(val_name, &hist);
  310. }
  311. if (dist_name) {
  312. Rast_short_history(dist_name, "raster", &hist);
  313. Rast_set_history(&hist, HIST_DATSRC_1, in_name);
  314. Rast_append_format_history(&hist, "%s distance to nearest feature", opt.met->answer);
  315. Rast_command_history(&hist);
  316. Rast_write_history(dist_name, &hist);
  317. }
  318. return EXIT_SUCCESS;
  319. }