main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. /****************************************************************************
  2. *
  3. * MODULE: r.stats
  4. * AUTHOR(S): Michael Shapiro, CERL (original contributor)
  5. * Markus Neteler <neteler itc.it>,
  6. * Brad Douglas <rez touchofmadness.com>,
  7. * Huidae Cho <grass4u gmail.com>,
  8. * Glynn Clements <glynn gclements.plus.com>,
  9. * Hamish Bowman <hamish_b yahoo.com>,
  10. * Jachym Cepicky <jachym les-ejk.cz>,
  11. * Jan-Oliver Wagner <jan intevation.de>,
  12. * Sort parameter by Martin Landa <landa.martin gmail.com>
  13. * PURPOSE: Calculates the area present in each of the categories of
  14. * user-selected raster map layer(s)
  15. * COPYRIGHT: (C) 1999-2006, 2013-2014 by the GRASS Development Team
  16. *
  17. * This program is free software under the GNU General Public
  18. * License (>=v2). Read the file COPYING that comes with GRASS
  19. * for details.
  20. *
  21. *****************************************************************************/
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <grass/glocale.h>
  26. #include "global.h"
  27. char *no_data_str;
  28. int nfiles;
  29. int nrows;
  30. int ncols, no_nulls, no_nulls_all;
  31. int nsteps, cat_ranges, raw_output, as_int, averaged;
  32. int *is_fp;
  33. DCELL *DMAX, *DMIN;
  34. CELL NULL_CELL;
  35. char *fs;
  36. struct Categories *labels;
  37. int main(int argc, char *argv[])
  38. {
  39. int *fd;
  40. char **names;
  41. char *name;
  42. /* flags */
  43. int raw_data;
  44. int with_coordinates;
  45. int with_xy;
  46. int with_percents;
  47. int with_counts;
  48. int with_areas;
  49. int with_labels;
  50. int do_sort;
  51. /* printf format */
  52. char fmt[20];
  53. int dp;
  54. struct Range range;
  55. struct FPRange fp_range;
  56. struct Quant q;
  57. CELL min, max, null_set = 0;
  58. DCELL dmin, dmax;
  59. struct GModule *module;
  60. struct
  61. {
  62. struct Flag *A; /* print averaged values instead of intervals */
  63. struct Flag *a; /* area */
  64. struct Flag *c; /* cell counts */
  65. struct Flag *p; /* percents */
  66. struct Flag *l; /* with labels */
  67. struct Flag *n; /* Suppress reporting of any NULLs */
  68. struct Flag *N; /* Suppress reporting of NULLs when
  69. all values are NULL */
  70. struct Flag *one; /* one cell per line */
  71. struct Flag *x; /* with row/col */
  72. struct Flag *g; /* with east/north */
  73. struct Flag *i; /* use quant rules for fp map, i.e. read it as int */
  74. struct Flag *r; /* raw output: when nsteps option is used,
  75. report indexes of ranges instead of ranges
  76. themselves; when -C (cats) option is used
  77. reports indexes of fp ranges = ind. of labels */
  78. struct Flag *C; /* report stats for labeled ranges in cats files */
  79. } flag;
  80. struct
  81. {
  82. struct Option *cell;
  83. struct Option *fs;
  84. struct Option *nv;
  85. struct Option *output;
  86. struct Option *nsteps; /* divide data range into nsteps and report stats
  87. for these ranges: only for fp maps
  88. NOTE: when -C flag is used, and there are
  89. explicit fp ranges in cats or when the map
  90. is int, nsteps is ignored */
  91. struct Option *sort; /* sort by cell counts */
  92. } option;
  93. G_gisinit(argv[0]);
  94. module = G_define_module();
  95. G_add_keyword(_("raster"));
  96. G_add_keyword(_("statistics"));
  97. module->description =
  98. _("Generates area statistics for raster map.");
  99. /* Define the different options */
  100. option.cell = G_define_standard_option(G_OPT_R_INPUTS);
  101. option.cell->description = _("Name of raster map(s) to report on");
  102. option.output = G_define_standard_option(G_OPT_F_OUTPUT);
  103. option.output->required = NO;
  104. option.output->description =
  105. _("Name for output file (if omitted or \"-\" output to stdout)");
  106. option.fs = G_define_standard_option(G_OPT_F_SEP);
  107. option.fs->answer = "space";
  108. option.fs->guisection = _("Formatting");
  109. option.nv = G_define_standard_option(G_OPT_M_NULL_VALUE);
  110. option.nv->answer = "*";
  111. option.nv->guisection = _("Formatting");
  112. option.nsteps = G_define_option();
  113. option.nsteps->key = "nsteps";
  114. option.nsteps->type = TYPE_INTEGER;
  115. option.nsteps->required = NO;
  116. option.nsteps->multiple = NO;
  117. option.nsteps->answer = "255";
  118. option.nsteps->description =
  119. _("Number of floating-point subranges to collect stats from");
  120. option.nsteps->guisection = _("Floating point");
  121. option.sort = G_define_option();
  122. option.sort->key = "sort";
  123. option.sort->type = TYPE_STRING;
  124. option.sort->required = NO;
  125. option.sort->multiple = NO;
  126. option.sort->label = _("Sort output statistics by cell counts");
  127. option.sort->description = _("Default: sorted by categories or intervals");
  128. option.sort->options = "asc,desc";
  129. G_asprintf((char **)&(option.sort->descriptions),
  130. "asc;%s;desc;%s",
  131. _("Sort by cell counts in ascending order"),
  132. _("Sort by cell counts in descending order"));
  133. option.sort->guisection = _("Formatting");
  134. /* Define the different flags */
  135. flag.a = G_define_flag();
  136. flag.a->key = 'a';
  137. flag.a->description = _("Print area totals in square meters");
  138. flag.a->guisection = _("Statistics");
  139. flag.c = G_define_flag();
  140. flag.c->key = 'c';
  141. flag.c->description = _("Print cell counts (sortable)");
  142. flag.c->guisection = _("Statistics");
  143. flag.p = G_define_flag();
  144. flag.p->key = 'p';
  145. flag.p->description =
  146. _("Print approximate (total percent may not be 100%) percents");
  147. flag.p->guisection = _("Statistics");
  148. flag.l = G_define_flag();
  149. flag.l->key = 'l';
  150. flag.l->description = _("Print category labels");
  151. flag.one = G_define_flag();
  152. flag.one->key = '1';
  153. flag.one->description = _("One cell (range) per line");
  154. flag.g = G_define_flag();
  155. flag.g->key = 'g';
  156. flag.g->description = _("Print grid coordinates (east and north)");
  157. flag.g->guisection = _("Coordinates");
  158. flag.x = G_define_flag();
  159. flag.x->key = 'x';
  160. flag.x->description = _("Print x and y (column and row)");
  161. flag.x->guisection = _("Coordinates");
  162. flag.A = G_define_flag();
  163. flag.A->key = 'A';
  164. flag.A->description = _("Print averaged values instead of intervals (floating-point maps only)");
  165. flag.A->guisection = _("Floating point");
  166. flag.r = G_define_flag();
  167. flag.r->key = 'r';
  168. flag.r->description = _("Print raw indexes of floating-point ranges (floating-point maps only)");
  169. flag.r->guisection = _("Floating point");
  170. flag.n = G_define_flag();
  171. flag.n->key = 'n';
  172. flag.n->description = _("Do not report no data value");
  173. flag.n->guisection = _("No data");
  174. flag.N = G_define_flag();
  175. flag.N->key = 'N';
  176. flag.N->description = _("Do not report cells where all maps have no data");
  177. flag.N->guisection = _("No data");
  178. flag.C = G_define_flag();
  179. flag.C->key = 'C';
  180. flag.C->description = _("Report for cats floating-point ranges (floating-point maps only)");
  181. flag.C->guisection = _("Floating point");
  182. flag.i = G_define_flag();
  183. flag.i->key = 'i';
  184. flag.i->description = _("Read floating-point map as integer (use map's quant rules)");
  185. flag.i->guisection = _("Floating point");
  186. if (G_parser(argc, argv))
  187. exit(EXIT_FAILURE);
  188. name = option.output->answer;
  189. if (name != NULL && strcmp(name, "-") != 0) {
  190. if (NULL == freopen(name, "w", stdout)) {
  191. G_fatal_error(_("Unable to open file <%s> for writing"), name);
  192. }
  193. }
  194. sscanf(option.nsteps->answer, "%d", &nsteps);
  195. if (nsteps <= 0) {
  196. G_warning(_("'%s' must be greater than zero; using %s=255"),
  197. option.nsteps->key, option.nsteps->key);
  198. nsteps = 255;
  199. }
  200. cat_ranges = flag.C->answer;
  201. averaged = flag.A->answer;
  202. raw_output = flag.r->answer;
  203. as_int = flag.i->answer;
  204. nrows = Rast_window_rows();
  205. ncols = Rast_window_cols();
  206. fd = NULL;
  207. nfiles = 0;
  208. dp = -1;
  209. with_percents = flag.p->answer;
  210. with_counts = flag.c->answer;
  211. with_areas = flag.a->answer;
  212. with_labels = flag.l->answer;
  213. /* determine sorting method */
  214. do_sort = SORT_DEFAULT; /* sort by cats by default */
  215. if (option.sort->answer) {
  216. switch(option.sort->answer[0]) {
  217. case 'a':
  218. do_sort = SORT_ASC;
  219. break;
  220. case 'd':
  221. do_sort = SORT_DESC;
  222. break;
  223. default:
  224. G_debug(1, "Sorting by '%s' not supported", option.sort->answer);
  225. break;
  226. }
  227. }
  228. no_nulls = flag.n->answer;
  229. no_nulls_all = flag.N->answer;
  230. no_data_str = option.nv->answer;
  231. raw_data = flag.one->answer;
  232. with_coordinates = flag.g->answer;
  233. with_xy = flag.x->answer;
  234. if (with_coordinates || with_xy)
  235. raw_data = TRUE;
  236. /* get field separator */
  237. fs = G_option_to_separator(option.fs);
  238. /* open all raster maps */
  239. if (option.cell->answers[0] == NULL)
  240. G_fatal_error(_("Raster map not found"));
  241. names = option.cell->answers;
  242. for (; *names != NULL; names++) {
  243. name = *names;
  244. fd = (int *)G_realloc(fd, (nfiles + 1) * sizeof(int));
  245. is_fp = (int *)G_realloc(is_fp, (nfiles + 1) * sizeof(int));
  246. DMAX = (DCELL *) G_realloc(DMAX, (nfiles + 1) * sizeof(DCELL));
  247. DMIN = (DCELL *) G_realloc(DMIN, (nfiles + 1) * sizeof(DCELL));
  248. fd[nfiles] = Rast_open_old(name, "");
  249. if (!as_int)
  250. is_fp[nfiles] = Rast_map_is_fp(name, "");
  251. else {
  252. is_fp[nfiles] = 0;
  253. if (cat_ranges || nsteps != 255)
  254. G_warning(_("Raster map <%s> is reading as integer map! "
  255. "Flag '-%c' and/or '%s' option will be ignored."),
  256. name, flag.C->key, option.nsteps->key);
  257. }
  258. if (with_labels || (cat_ranges && is_fp[nfiles])) {
  259. labels = (struct Categories *)
  260. G_realloc(labels, (nfiles + 1) * sizeof(struct Categories));
  261. if (Rast_read_cats(name, "", &labels[nfiles]) < 0)
  262. Rast_init_cats("", &labels[nfiles]);
  263. }
  264. if (is_fp[nfiles])
  265. /* floating point map */
  266. {
  267. Rast_quant_init(&q);
  268. if (cat_ranges) {
  269. if (!Rast_quant_nof_rules(&labels[nfiles].q)) {
  270. G_warning(_("Cats for raster map <%s> are either missing or have no explicit labels. "
  271. "Using %s=%d."),
  272. name, option.nsteps->key, nsteps);
  273. cat_ranges = 0;
  274. }
  275. else if (nsteps != 255)
  276. G_warning(_("Flag '-%c' was given, using cats fp ranges of raster map <%s>, "
  277. "ignoring '%s' option"),
  278. flag.C->key, name, option.nsteps->key);
  279. }
  280. if (!cat_ranges) { /* DO NOT use else here, cat_ranges can change */
  281. if (Rast_read_fp_range(name, "", &fp_range) < 0)
  282. G_fatal_error(_("Unable to read fp range of raster map <%s>"),
  283. name);
  284. Rast_get_fp_range_min_max(&fp_range, &DMIN[nfiles],
  285. &DMAX[nfiles]);
  286. G_debug(3, "file %2d: dmin=%f dmax=%f", nfiles, DMIN[nfiles],
  287. DMAX[nfiles]);
  288. Rast_quant_add_rule(&q, DMIN[nfiles], DMAX[nfiles], 1, nsteps+1);
  289. /* set the quant rules for reading the map */
  290. Rast_set_quant_rules(fd[nfiles], &q);
  291. Rast_quant_get_limits(&q, &dmin, &dmax, &min, &max);
  292. G_debug(2, "overall: dmin=%f dmax=%f, qmin=%d qmax=%d",
  293. dmin, dmax, min, max);
  294. Rast_quant_free(&q);
  295. }
  296. else { /* cats ranges */
  297. /* set the quant rules for reading the map */
  298. Rast_set_quant_rules(fd[nfiles], &labels[nfiles].q);
  299. Rast_quant_get_limits(&labels[nfiles].q, &dmin, &dmax, &min,
  300. &max);
  301. }
  302. }
  303. else {
  304. if (Rast_read_range(name, "", &range) < 0)
  305. G_fatal_error(_("Unable to read range for map <%s>"), name);
  306. Rast_get_range_min_max(&range, &min, &max);
  307. }
  308. if (!null_set) {
  309. null_set = 1;
  310. NULL_CELL = max + 1;
  311. }
  312. else if (NULL_CELL < max + 1)
  313. NULL_CELL = max + 1;
  314. nfiles++;
  315. }
  316. if (dp < 0)
  317. strcpy(fmt, "%lf");
  318. else
  319. sprintf(fmt, "%%.%dlf", dp);
  320. if (raw_data)
  321. raw_stats(fd, with_coordinates, with_xy, with_labels);
  322. else
  323. cell_stats(fd, with_percents, with_counts, with_areas, do_sort,
  324. with_labels, fmt);
  325. exit(EXIT_SUCCESS);
  326. }