main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /****************************************************************************
  2. *
  3. * MODULE: r.resamp.stats
  4. * AUTHOR(S): Glynn Clements <glynn gclements.plus.com> (original contributor)
  5. * Hamish Bowman <hamish_b yahoo.com>
  6. * PURPOSE:
  7. * COPYRIGHT: (C) 2006-2007 by the GRASS Development Team
  8. *
  9. * This program is free software under the GNU General Public
  10. * License (>=v2). Read the file COPYING that comes with GRASS
  11. * for details.
  12. *
  13. *****************************************************************************/
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <math.h>
  17. #include <grass/gis.h>
  18. #include <grass/raster.h>
  19. #include <grass/glocale.h>
  20. #include <grass/stats.h>
  21. static const struct menu
  22. {
  23. stat_func *method; /* routine to compute new value */
  24. stat_func_w *method_w; /* routine to compute new value (weighted) */
  25. char *name; /* method name */
  26. char *text; /* menu display - full description */
  27. } menu[] = {
  28. {c_ave, w_ave, "average", "average (mean) value"},
  29. {c_median, w_median, "median", "median value"},
  30. {c_mode, w_mode, "mode", "most frequently occurring value"},
  31. {c_min, w_min, "minimum", "lowest value"},
  32. {c_max, w_max, "maximum", "highest value"},
  33. {c_range, NULL, "range", "range value"},
  34. {c_quart1, w_quart1, "quart1", "first quartile"},
  35. {c_quart3, w_quart3, "quart3", "third quartile"},
  36. {c_perc90, w_perc90, "perc90", "ninetieth percentile"},
  37. {c_sum, w_sum, "sum", "sum of values"},
  38. {c_var, w_var, "variance", "variance value"},
  39. {c_stddev, w_stddev, "stddev", "standard deviation"},
  40. {c_quant, w_quant, "quantile", "arbitrary quantile"},
  41. {c_count, w_count, "count", "count of non-NULL values"},
  42. {c_divr, NULL, "diversity", "number of different values"},
  43. {NULL, NULL, NULL, NULL}
  44. };
  45. static char *build_method_list(void)
  46. {
  47. char *buf = G_malloc(1024);
  48. char *p = buf;
  49. int i;
  50. for (i = 0; menu[i].name; i++) {
  51. char *q;
  52. if (i)
  53. *p++ = ',';
  54. for (q = menu[i].name; *q; p++, q++)
  55. *p = *q;
  56. }
  57. *p = '\0';
  58. return buf;
  59. }
  60. static int find_method(const char *name)
  61. {
  62. int i;
  63. for (i = 0; menu[i].name; i++)
  64. if (strcmp(menu[i].name, name) == 0)
  65. return i;
  66. return -1;
  67. }
  68. static int nulls;
  69. static int infile, outfile;
  70. static struct Cell_head dst_w, src_w;
  71. static DCELL *outbuf;
  72. static DCELL **bufs;
  73. static int method;
  74. static const void *closure;
  75. static int row_scale, col_scale;
  76. static double quantile;
  77. static void resamp_unweighted(void)
  78. {
  79. stat_func *method_fn;
  80. DCELL *values;
  81. int *col_map, *row_map;
  82. int row, col;
  83. method_fn = menu[method].method;
  84. values = G_malloc(row_scale * col_scale * sizeof(DCELL));
  85. col_map = G_malloc((dst_w.cols + 1) * sizeof(int));
  86. row_map = G_malloc((dst_w.rows + 1) * sizeof(int));
  87. for (col = 0; col <= dst_w.cols; col++) {
  88. double x = Rast_col_to_easting(col, &dst_w);
  89. /* col_map[col] = (int)floor(Rast_easting_to_col(x, &src_w) + 0.5); */
  90. col_map[col] = (int)floor((x - src_w.west) / src_w.ew_res + 0.5);
  91. }
  92. for (row = 0; row <= dst_w.rows; row++) {
  93. double y = Rast_row_to_northing(row, &dst_w);
  94. row_map[row] = (int)floor(Rast_northing_to_row(y, &src_w) + 0.5);
  95. }
  96. for (row = 0; row < dst_w.rows; row++) {
  97. int maprow0 = row_map[row + 0];
  98. int maprow1 = row_map[row + 1];
  99. int count = maprow1 - maprow0;
  100. int i;
  101. G_percent(row, dst_w.rows, 4);
  102. for (i = 0; i < count; i++)
  103. Rast_get_d_row(infile, bufs[i], maprow0 + i);
  104. for (col = 0; col < dst_w.cols; col++) {
  105. int mapcol0 = col_map[col + 0];
  106. int mapcol1 = col_map[col + 1];
  107. int null = 0;
  108. int n = 0;
  109. int i, j;
  110. for (i = maprow0; i < maprow1; i++)
  111. for (j = mapcol0; j < mapcol1; j++) {
  112. DCELL *src = &bufs[i - maprow0][j];
  113. DCELL *dst = &values[n++];
  114. if (Rast_is_d_null_value(src)) {
  115. Rast_set_d_null_value(dst, 1);
  116. null = 1;
  117. }
  118. else
  119. *dst = *src;
  120. }
  121. if (null && nulls)
  122. Rast_set_d_null_value(&outbuf[col], 1);
  123. else
  124. (*method_fn) (&outbuf[col], values, n, closure);
  125. }
  126. Rast_put_d_row(outfile, outbuf);
  127. }
  128. }
  129. static void resamp_weighted(void)
  130. {
  131. stat_func_w *method_fn;
  132. DCELL(*values)[2];
  133. double *col_map, *row_map;
  134. int row, col;
  135. method_fn = menu[method].method_w;
  136. values = G_malloc(row_scale * col_scale * 2 * sizeof(DCELL));
  137. col_map = G_malloc((dst_w.cols + 1) * sizeof(double));
  138. row_map = G_malloc((dst_w.rows + 1) * sizeof(double));
  139. for (col = 0; col <= dst_w.cols; col++) {
  140. double x = Rast_col_to_easting(col, &dst_w);
  141. /* col_map[col] = Rast_easting_to_col(x, &src_w); */
  142. col_map[col] = (x - src_w.west) / src_w.ew_res;
  143. }
  144. for (row = 0; row <= dst_w.rows; row++) {
  145. double y = Rast_row_to_northing(row, &dst_w);
  146. row_map[row] = Rast_northing_to_row(y, &src_w);
  147. }
  148. for (row = 0; row < dst_w.rows; row++) {
  149. double y0 = row_map[row + 0];
  150. double y1 = row_map[row + 1];
  151. int maprow0 = (int)floor(y0);
  152. int maprow1 = (int)ceil(y1);
  153. int count = maprow1 - maprow0;
  154. int i;
  155. G_percent(row, dst_w.rows, 4);
  156. for (i = 0; i < count; i++)
  157. Rast_get_d_row(infile, bufs[i], maprow0 + i);
  158. for (col = 0; col < dst_w.cols; col++) {
  159. double x0 = col_map[col + 0];
  160. double x1 = col_map[col + 1];
  161. int mapcol0 = (int)floor(x0);
  162. int mapcol1 = (int)ceil(x1);
  163. int null = 0;
  164. int n = 0;
  165. int i, j;
  166. for (i = maprow0; i < maprow1; i++) {
  167. double ky = (i == maprow0) ? 1 - (y0 - maprow0)
  168. : (i == maprow1 - 1) ? 1 - (maprow1 - y1)
  169. : 1;
  170. for (j = mapcol0; j < mapcol1; j++) {
  171. double kx = (j == mapcol0) ? 1 - (x0 - mapcol0)
  172. : (j == mapcol1 - 1) ? 1 - (mapcol1 - x1)
  173. : 1;
  174. DCELL *src = &bufs[i - maprow0][j];
  175. DCELL *dst = &values[n++][0];
  176. if (Rast_is_d_null_value(src)) {
  177. Rast_set_d_null_value(&dst[0], 1);
  178. null = 1;
  179. }
  180. else {
  181. dst[0] = *src;
  182. dst[1] = kx * ky;
  183. }
  184. }
  185. }
  186. if (null && nulls)
  187. Rast_set_d_null_value(&outbuf[col], 1);
  188. else
  189. (*method_fn) (&outbuf[col], values, n, closure);
  190. }
  191. Rast_put_d_row(outfile, outbuf);
  192. }
  193. }
  194. int main(int argc, char *argv[])
  195. {
  196. struct GModule *module;
  197. struct
  198. {
  199. struct Option *rastin, *rastout, *method, *quantile;
  200. } parm;
  201. struct
  202. {
  203. struct Flag *nulls, *weight;
  204. } flag;
  205. struct History history;
  206. char title[64];
  207. char buf_nsres[100], buf_ewres[100];
  208. struct Colors colors;
  209. int row;
  210. G_gisinit(argv[0]);
  211. module = G_define_module();
  212. G_add_keyword(_("raster"));
  213. G_add_keyword(_("resample"));
  214. module->description =
  215. _("Resamples raster map layers to a coarser grid using aggregation.");
  216. parm.rastin = G_define_standard_option(G_OPT_R_INPUT);
  217. parm.rastout = G_define_standard_option(G_OPT_R_OUTPUT);
  218. parm.method = G_define_option();
  219. parm.method->key = "method";
  220. parm.method->type = TYPE_STRING;
  221. parm.method->required = NO;
  222. parm.method->description = _("Aggregation method");
  223. parm.method->options = build_method_list();
  224. parm.method->answer = "average";
  225. parm.quantile = G_define_option();
  226. parm.quantile->key = "quantile";
  227. parm.quantile->type = TYPE_DOUBLE;
  228. parm.quantile->required = NO;
  229. parm.quantile->description = _("Quantile to calculate for method=quantile");
  230. parm.quantile->options = "0.0-1.0";
  231. parm.quantile->answer = "0.5";
  232. flag.nulls = G_define_flag();
  233. flag.nulls->key = 'n';
  234. flag.nulls->description = _("Propagate NULLs");
  235. flag.weight = G_define_flag();
  236. flag.weight->key = 'w';
  237. flag.weight->description = _("Weight according to area (slower)");
  238. if (G_parser(argc, argv))
  239. exit(EXIT_FAILURE);
  240. nulls = flag.nulls->answer;
  241. method = find_method(parm.method->answer);
  242. if (method < 0)
  243. G_fatal_error(_("Unknown method <%s>"), parm.method->answer);
  244. if (menu[method].method == c_quant) {
  245. quantile = atoi(parm.quantile->answer);
  246. closure = &quantile;
  247. }
  248. G_get_set_window(&dst_w);
  249. /* set source window to old map */
  250. Rast_get_cellhd(parm.rastin->answer, "", &src_w);
  251. if (G_projection() == PROJECTION_LL) {
  252. /* try to shift source window to overlap with destination window */
  253. while (src_w.west >= dst_w.east && src_w.east - 360.0 > dst_w.west) {
  254. src_w.east -= 360.0;
  255. src_w.west -= 360.0;
  256. }
  257. while (src_w.east <= dst_w.west && src_w.west + 360.0 < dst_w.east) {
  258. src_w.east += 360.0;
  259. src_w.west += 360.0;
  260. }
  261. }
  262. /* adjust source window to cover destination window */
  263. {
  264. int r0 = (int)floor(Rast_northing_to_row(dst_w.north, &src_w));
  265. int r1 = (int)ceil(Rast_northing_to_row(dst_w.south, &src_w));
  266. /* do not use Rast_easting_to_col() because it does ll wrap */
  267. /*
  268. int c0 = (int)floor(Rast_easting_to_col(dst_w.west, &src_w));
  269. int c1 = (int)ceil(Rast_easting_to_col(dst_w.east, &src_w));
  270. */
  271. int c0 = (int)floor((dst_w.west - src_w.west) / src_w.ew_res);
  272. int c1 = src_w.cols + (int)ceil((dst_w.east - src_w.east) / src_w.ew_res);
  273. src_w.south -= src_w.ns_res * (r1 - src_w.rows);
  274. src_w.north += src_w.ns_res * (-r0);
  275. src_w.west -= src_w.ew_res * (-c0);
  276. src_w.east += src_w.ew_res * (c1 - src_w.cols);
  277. src_w.rows = r1 - r0;
  278. src_w.cols = c1 - c0;
  279. }
  280. Rast_set_input_window(&src_w);
  281. Rast_set_output_window(&dst_w);
  282. row_scale = 2 + ceil(dst_w.ns_res / src_w.ns_res);
  283. col_scale = 2 + ceil(dst_w.ew_res / src_w.ew_res);
  284. /* allocate buffers for input rows */
  285. bufs = G_malloc(row_scale * sizeof(DCELL *));
  286. for (row = 0; row < row_scale; row++)
  287. bufs[row] = Rast_allocate_d_input_buf();
  288. /* open old map */
  289. infile = Rast_open_old(parm.rastin->answer, "");
  290. /* allocate output buffer */
  291. outbuf = Rast_allocate_d_output_buf();
  292. /* open new map */
  293. outfile = Rast_open_new(parm.rastout->answer, DCELL_TYPE);
  294. if (flag.weight->answer && menu[method].method_w)
  295. resamp_weighted();
  296. else
  297. resamp_unweighted();
  298. G_percent(dst_w.rows, dst_w.rows, 2);
  299. Rast_close(infile);
  300. Rast_close(outfile);
  301. /* record map metadata/history info */
  302. sprintf(title, "Aggregate resample by %s", parm.method->answer);
  303. Rast_put_cell_title(parm.rastout->answer, title);
  304. Rast_short_history(parm.rastout->answer, "raster", &history);
  305. Rast_set_history(&history, HIST_DATSRC_1, parm.rastin->answer);
  306. G_format_resolution(src_w.ns_res, buf_nsres, src_w.proj);
  307. G_format_resolution(src_w.ew_res, buf_ewres, src_w.proj);
  308. Rast_format_history(&history, HIST_DATSRC_2,
  309. "Source map NS res: %s EW res: %s",
  310. buf_nsres, buf_ewres);
  311. Rast_command_history(&history);
  312. Rast_write_history(parm.rastout->answer, &history);
  313. /* copy color table from source map */
  314. if (strcmp(parm.method->answer, "sum") != 0 &&
  315. strcmp(parm.method->answer, "range") != 0 &&
  316. strcmp(parm.method->answer, "count") != 0 &&
  317. strcmp(parm.method->answer, "diversity") != 0) {
  318. if (Rast_read_colors(parm.rastin->answer, "", &colors) < 0)
  319. G_fatal_error(_("Unable to read color table for %s"),
  320. parm.rastin->answer);
  321. Rast_mark_colors_as_fp(&colors);
  322. Rast_write_colors(parm.rastout->answer, G_mapset(), &colors);
  323. }
  324. return (EXIT_SUCCESS);
  325. }