stats.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. #include <stdlib.h>
  2. #include "global.h"
  3. /* hash definitions (these should be prime numbers) ************* */
  4. #define HASHSIZE 7307
  5. #define HASHMOD 89
  6. static CELL *values;
  7. static struct Node *node_pool;
  8. static int node_pool_count;
  9. static CELL *value_pool;
  10. static int value_pool_count;
  11. #define NODE_INCR 32
  12. #define VALUE_INCR 32
  13. static struct Node **sorted_list;
  14. struct Node
  15. {
  16. CELL *values;
  17. struct Node *left;
  18. struct Node *right;
  19. struct Node *list;
  20. long count;
  21. double area;
  22. };
  23. static struct Node **hashtable;
  24. static struct Node *node_list = NULL;
  25. static int node_count = 0, total_count = 0;
  26. int initialize_cell_stats(int n)
  27. {
  28. int i;
  29. /* record nilfes first */
  30. nfiles = n;
  31. /* allocate a pool of value arrays */
  32. value_pool_count = 0;
  33. allocate_values();
  34. /* set Node pool to empty */
  35. node_pool_count = 0;
  36. /* empty the has table */
  37. hashtable = (struct Node **)G_malloc(HASHSIZE * sizeof(struct Node *));
  38. for (i = 0; i < HASHSIZE; i++)
  39. hashtable[i] = NULL;
  40. return 0;
  41. }
  42. int allocate_values(void)
  43. {
  44. value_pool_count = VALUE_INCR;
  45. value_pool = (CELL *) G_calloc(nfiles * value_pool_count, sizeof(CELL));
  46. values = value_pool;
  47. return 0;
  48. }
  49. struct Node *NewNode(double area)
  50. {
  51. struct Node *node;
  52. if (node_pool_count <= 0)
  53. node_pool = (struct Node *)G_calloc(node_pool_count =
  54. NODE_INCR, sizeof(struct Node));
  55. node = &node_pool[--node_pool_count];
  56. node->count = 1;
  57. node->area = area;
  58. node->values = values;
  59. if (--value_pool_count <= 0)
  60. allocate_values();
  61. else
  62. values += nfiles;
  63. node->left = node->right = NULL;
  64. node->list = node_list;
  65. node_list = node;
  66. node_count++;
  67. return node;
  68. }
  69. /* Essentially, Rast_quant_add_rule() treats the ranges as half-open,
  70. * i.e. the values range from low (inclusive) to high (exclusive).
  71. * While half-open ranges are a common concept (e.g. floor() behaves
  72. * the same way), the range of a GRASS raster is closed, i.e. both the
  73. * low and high values are inclusive.
  74. * Therefore the quantized max FP cell gets put in the nsteps+1'th bin
  75. * and we need to manually place it back in the previous bin. */
  76. void fix_max_fp_val(CELL *cell, int ncols)
  77. {
  78. while (ncols-- > 0) {
  79. if (cell[ncols] > nsteps)
  80. cell[ncols] = (CELL)nsteps;
  81. /* { G_debug(5, ". resetting %d to %d", cell[ncols], nsteps); } */
  82. }
  83. return;
  84. }
  85. /* we can't compute hash on null values, so we change all
  86. * nulls to max+1, set NULL_CELL to max+1, and later compare
  87. * with NULL_CELL to chack for nulls */
  88. void reset_null_vals(CELL *cell, int ncols)
  89. {
  90. while (ncols-- > 0) {
  91. if (Rast_is_c_null_value(&cell[ncols]))
  92. cell[ncols] = NULL_CELL;
  93. }
  94. return;
  95. }
  96. int update_cell_stats(CELL ** cell, int ncols, double area)
  97. {
  98. register int i;
  99. register int hash;
  100. register struct Node *q, *p = NULL;
  101. register int dir = 0;
  102. while (ncols-- > 0) {
  103. /* copy this cell to an array, compute hash */
  104. hash = values[0] = cell[0][ncols];
  105. for (i = 1; i < nfiles; i++)
  106. hash = hash * HASHMOD + (values[i] = cell[i][ncols]);
  107. if (hash < 0)
  108. hash = -hash;
  109. hash %= HASHSIZE;
  110. /* look it up and update/insert */
  111. if ((q = hashtable[hash]) == NULL) {
  112. hashtable[hash] = NewNode(area);
  113. }
  114. else {
  115. while (1) {
  116. for (i = 0; i < nfiles; i++) {
  117. if (values[i] < q->values[i]) {
  118. dir = -1;
  119. p = q->left;
  120. break;
  121. }
  122. if (values[i] > q->values[i]) {
  123. dir = 1;
  124. p = q->right;
  125. break;
  126. }
  127. }
  128. if (i == nfiles) { /* match */
  129. q->count++;
  130. q->area += area;
  131. total_count++;
  132. break;
  133. }
  134. else if (p == NULL) {
  135. if (dir < 0)
  136. q->left = NewNode(area);
  137. else
  138. q->right = NewNode(area);
  139. break;
  140. }
  141. else
  142. q = p;
  143. }
  144. }
  145. }
  146. return 0;
  147. }
  148. static int node_compare(const void *pp, const void *qq)
  149. {
  150. struct Node *const *p = pp, *const *q = qq;
  151. register int i, x;
  152. register const CELL *a, *b;
  153. a = (*p)->values;
  154. b = (*q)->values;
  155. for (i = nfiles; --i >= 0;)
  156. if (x = (*a++ - *b++), x)
  157. return x;
  158. return 0;
  159. }
  160. static int node_compare_count_asc(const void *pp, const void *qq)
  161. {
  162. struct Node *const *p = pp, *const *q = qq;
  163. long a, b;
  164. a = (*p)->count;
  165. b = (*q)->count;
  166. return (a - b);
  167. }
  168. static int node_compare_count_desc(const void *pp, const void *qq)
  169. {
  170. struct Node *const *p = pp, *const *q = qq;
  171. long a, b;
  172. a = (*p)->count;
  173. b = (*q)->count;
  174. return (b - a);
  175. }
  176. int sort_cell_stats(int do_sort)
  177. {
  178. struct Node **q, *p;
  179. if (node_count <= 0)
  180. return 0;
  181. G_free(hashtable); /* make a bit more room */
  182. sorted_list = (struct Node **)G_calloc(node_count, sizeof(struct Node *));
  183. for (q = sorted_list, p = node_list; p; p = p->list)
  184. *q++ = p;
  185. if (do_sort == SORT_DEFAULT)
  186. qsort(sorted_list, node_count, sizeof(struct Node *), node_compare);
  187. else if (do_sort == SORT_ASC)
  188. qsort(sorted_list, node_count, sizeof(struct Node *), node_compare_count_asc);
  189. else if (do_sort == SORT_DESC)
  190. qsort(sorted_list, node_count, sizeof(struct Node *), node_compare_count_desc);
  191. return 0;
  192. }
  193. int print_node_count(void)
  194. {
  195. fprintf(stdout, "%d nodes\n", node_count);
  196. return 0;
  197. }
  198. int print_cell_stats(char *fmt, int with_percents, int with_counts,
  199. int with_areas, int with_labels, char *fs)
  200. {
  201. int i, n, nulls_found;
  202. struct Node *node;
  203. CELL tmp_cell, null_cell;
  204. DCELL dLow, dHigh;
  205. char str1[50], str2[50];
  206. if (no_nulls)
  207. total_count -= sorted_list[node_count - 1]->count;
  208. Rast_set_c_null_value(&null_cell, 1);
  209. if (node_count <= 0) {
  210. fprintf(stdout, "0");
  211. for (i = 1; i < nfiles; i++)
  212. fprintf(stdout, "%s%s", fs, no_data_str);
  213. if (with_areas)
  214. fprintf(stdout, "%s0.0", fs);
  215. if (with_counts)
  216. fprintf(stdout, "%s0", fs);
  217. if (with_percents)
  218. fprintf(stdout, "%s0.00%%", fs);
  219. if (with_labels)
  220. fprintf(stdout, "%s%s", fs, Rast_get_c_cat(&null_cell, &labels[i]));
  221. fprintf(stdout, "\n");
  222. }
  223. else {
  224. for (n = 0; n < node_count; n++) {
  225. node = sorted_list[n];
  226. if (no_nulls || no_nulls_all) {
  227. nulls_found = 0;
  228. for (i = 0; i < nfiles; i++)
  229. /*
  230. if (node->values[i] || (!raw_output && is_fp[i]))
  231. break;
  232. */
  233. if (node->values[i] == NULL_CELL)
  234. nulls_found++;
  235. if (nulls_found == nfiles)
  236. continue;
  237. if (no_nulls && nulls_found)
  238. continue;
  239. }
  240. for (i = 0; i < nfiles; i++) {
  241. if (node->values[i] == NULL_CELL) {
  242. fprintf(stdout, "%s%s", i ? fs : "", no_data_str);
  243. if (with_labels && !(raw_output && is_fp[i]))
  244. fprintf(stdout, "%s%s", fs,
  245. Rast_get_c_cat(&null_cell, &labels[i]));
  246. }
  247. else if (raw_output || !is_fp[i] || as_int) {
  248. fprintf(stdout, "%s%ld", i ? fs : "",
  249. (long)node->values[i]);
  250. if (with_labels && !is_fp[i])
  251. fprintf(stdout, "%s%s", fs,
  252. Rast_get_c_cat((CELL*) &(node->values[i]),
  253. &labels[i]));
  254. }
  255. else { /* find out which floating point range to print */
  256. if (cat_ranges)
  257. Rast_quant_get_ith_rule(&labels[i].q, node->values[i],
  258. &dLow, &dHigh, &tmp_cell,
  259. &tmp_cell);
  260. else {
  261. dLow = (DMAX[i] - DMIN[i]) / nsteps *
  262. (double)(node->values[i] - 1) + DMIN[i];
  263. dHigh = (DMAX[i] - DMIN[i]) / nsteps *
  264. (double)node->values[i] + DMIN[i];
  265. }
  266. if (averaged) {
  267. /* print averaged values */
  268. sprintf(str1, "%10f", (dLow + dHigh) / 2.0);
  269. G_trim_decimal(str1);
  270. G_strip(str1);
  271. fprintf(stdout, "%s%s", i ? fs : "", str1);
  272. }
  273. else {
  274. /* print intervals */
  275. sprintf(str1, "%10f", dLow);
  276. sprintf(str2, "%10f", dHigh);
  277. G_trim_decimal(str1);
  278. G_trim_decimal(str2);
  279. G_strip(str1);
  280. G_strip(str2);
  281. fprintf(stdout, "%s%s-%s", i ? fs : "", str1, str2);
  282. }
  283. if (with_labels) {
  284. if (cat_ranges)
  285. fprintf(stdout, "%s%s", fs,
  286. labels[i].labels[node->values[i]]);
  287. else
  288. fprintf(stdout, "%sfrom %s to %s", fs,
  289. Rast_get_d_cat(&dLow, &labels[i]),
  290. Rast_get_d_cat(&dHigh, &labels[i]));
  291. }
  292. }
  293. }
  294. if (with_areas) {
  295. fprintf(stdout, "%s", fs);
  296. fprintf(stdout, fmt, node->area);
  297. }
  298. if (with_counts)
  299. fprintf(stdout, "%s%ld", fs, (long)node->count);
  300. if (with_percents)
  301. fprintf(stdout, "%s%.2f%%", fs,
  302. (double)100 * node->count / total_count);
  303. fprintf(stdout, "\n");
  304. }
  305. }
  306. return 0;
  307. }