main.c 12 KB

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