cell_stats.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. /*!
  2. * \file lib/raster/cell_stats.c
  3. *
  4. * \brief Raster Library - Raster cell statistics
  5. *
  6. * (C) 2001-2009 GRASS Development Team
  7. *
  8. * This program is free software under the GNU General Public License
  9. * (>=v2). Read the file COPYING that comes with GRASS for details.
  10. *
  11. * \author Original author CERL
  12. */
  13. #include <stdlib.h>
  14. #include <grass/gis.h>
  15. #include <grass/raster.h>
  16. #define INCR 10
  17. #define SHIFT 6
  18. static const int NCATS = 1 << SHIFT;
  19. #define NODE struct Cell_stats_node
  20. static int next_node(struct Cell_stats *);
  21. static void init_node(NODE *, int, int);
  22. /*!
  23. * \brief Initialize cell stats
  24. *
  25. * This routine, which must be called first, initializes the
  26. * Cell_stats structure.
  27. *
  28. * Set the count for NULL-values to zero.
  29. *
  30. * \param s pointer to Cell_stats structure
  31. */
  32. void Rast_init_cell_stats(struct Cell_stats *s)
  33. {
  34. s->N = 0;
  35. s->tlen = INCR;
  36. s->node = (NODE *) G_malloc(s->tlen * sizeof(NODE));
  37. s->null_data_count = 0;
  38. }
  39. /*!
  40. * \brief Add data to cell stats
  41. *
  42. * The <i>n</i> CELL values in the <i>data</i> array are inserted (and
  43. * counted) in the Cell_stats structure.
  44. *
  45. * Look for NULLs and update the NULL-value count.
  46. *
  47. * \param cell raster values
  48. * \param n number of values
  49. * \param s pointer to Cell_stats structure which holds cell stats info
  50. *
  51. * \return 1 on failure
  52. * \return 0 on success
  53. */
  54. int Rast_update_cell_stats(const CELL * cell, int n, struct Cell_stats *s)
  55. {
  56. CELL cat;
  57. int p, q;
  58. int idx, offset;
  59. int N;
  60. NODE *node, *pnode;
  61. NODE *new_node;
  62. if (n <= 0)
  63. return 1;
  64. node = s->node;
  65. /* first non-null node is special case */
  66. if ((N = s->N) == 0) {
  67. cat = *cell++;
  68. while (Rast_is_c_null_value(&cat)) {
  69. s->null_data_count++;
  70. cat = *cell++;
  71. n--;
  72. }
  73. if (n > 0) { /* if there are some non-null cells */
  74. N = 1;
  75. if (cat < 0) {
  76. idx = -((-cat) >> SHIFT) - 1;
  77. offset = cat + ((-idx) << SHIFT) - 1;
  78. }
  79. else {
  80. idx = cat >> SHIFT;
  81. offset = cat - (idx << SHIFT);
  82. }
  83. fflush(stderr);
  84. init_node(&node[1], idx, offset);
  85. node[1].right = 0;
  86. n--;
  87. }
  88. }
  89. while (n-- > 0) {
  90. cat = *cell++;
  91. if (Rast_is_c_null_value(&cat)) {
  92. s->null_data_count++;
  93. continue;
  94. }
  95. if (cat < 0) {
  96. idx = -((-cat) >> SHIFT) - 1;
  97. offset = cat + ((-idx) << SHIFT) - 1;
  98. }
  99. else {
  100. idx = cat >> SHIFT;
  101. offset = cat - (idx << SHIFT);
  102. }
  103. q = 1;
  104. while (q > 0) {
  105. pnode = &node[p = q];
  106. if (pnode->idx == idx) {
  107. pnode->count[offset]++;
  108. break;
  109. }
  110. if (pnode->idx > idx)
  111. q = pnode->left; /* go left */
  112. else
  113. q = pnode->right; /* go right */
  114. }
  115. if (q > 0)
  116. continue; /* found */
  117. /* new node */
  118. N++;
  119. /* grow the tree? */
  120. if (N >= s->tlen) {
  121. node =
  122. (NODE *) G_realloc((char *)node,
  123. sizeof(NODE) * (s->tlen += INCR));
  124. pnode = &node[p]; /* realloc moves node, must reassign pnode */
  125. }
  126. /* add node to tree */
  127. init_node(new_node = &node[N], idx, offset);
  128. if (pnode->idx > idx) {
  129. new_node->right = -p; /* create thread */
  130. pnode->left = N; /* insert left */
  131. }
  132. else {
  133. new_node->right = pnode->right; /* copy right link/thread */
  134. pnode->right = N; /* add right */
  135. }
  136. } /* while n-- > 0 */
  137. s->N = N;
  138. s->node = node;
  139. return 0;
  140. }
  141. static void init_node(NODE * node, int idx, int offset)
  142. {
  143. long *count;
  144. int i;
  145. count = node->count = (long *)G_calloc(i = NCATS, sizeof(long));
  146. while (i--)
  147. *count++ = 0;
  148. node->idx = idx;
  149. node->count[offset] = 1;
  150. node->left = 0;
  151. }
  152. /*!
  153. * \brief Random query of cell stats
  154. *
  155. * This routine allows a random query of the Cell_stats structure. The
  156. * \p count associated with the raster value \p cat is
  157. * set. The routine returns 1 if \p cat was found in the
  158. * structure, 0 otherwise.
  159. *
  160. * Allow finding the count for the NULL-value.
  161. *
  162. * \param cat raster value
  163. * \param[out] count count
  164. * \param s pointer to Cell_stats structure which holds cell stats info
  165. *
  166. * \return 1 if found
  167. * \return 0 if not found
  168. */
  169. int Rast_find_cell_stat(CELL cat, long *count, const struct Cell_stats *s)
  170. {
  171. int q;
  172. int idx;
  173. int offset;
  174. *count = 0;
  175. if (Rast_is_c_null_value(&cat)) {
  176. *count = s->null_data_count;
  177. return (*count != 0);
  178. }
  179. if (s->N <= 0)
  180. return 0;
  181. /*
  182. if (cat < 0)
  183. {
  184. idx = -(-cat/NCATS) - 1;
  185. offset = cat - idx*NCATS - 1;
  186. }
  187. else
  188. {
  189. idx = cat/NCATS;
  190. offset = cat - idx*NCATS;
  191. }
  192. */
  193. if (cat < 0) {
  194. idx = -((-cat) >> SHIFT) - 1;
  195. offset = cat + ((-idx) << SHIFT) - 1;
  196. }
  197. else {
  198. idx = cat >> SHIFT;
  199. offset = cat - (idx << SHIFT);
  200. }
  201. q = 1;
  202. while (q > 0) {
  203. if (s->node[q].idx == idx) {
  204. *count = s->node[q].count[offset];
  205. return (*count != 0);
  206. }
  207. if (s->node[q].idx > idx)
  208. q = s->node[q].left; /* go left */
  209. else
  210. q = s->node[q].right; /* go right */
  211. }
  212. return 0;
  213. }
  214. /*!
  215. * \brief Reset/rewind cell stats
  216. *
  217. * The structure <i>s</i> is rewound (i.e., positioned at the first
  218. * raster category) so that sorted sequential retrieval can begin.
  219. *
  220. * \param s pointer to Cell_stats structure which holds cell stats info
  221. *
  222. * \return 0
  223. */
  224. int Rast_rewind_cell_stats(struct Cell_stats *s)
  225. {
  226. int q;
  227. if (s->N <= 0)
  228. return 1;
  229. /* start at root and go all the way to the left */
  230. s->curp = 1;
  231. while ((q = s->node[s->curp].left))
  232. s->curp = q;
  233. s->curoffset = -1;
  234. return 0;
  235. }
  236. static int next_node(struct Cell_stats *s)
  237. {
  238. int q;
  239. /* go to the right */
  240. s->curp = s->node[s->curp].right;
  241. if (s->curp == 0) /* no more */
  242. return 0;
  243. if (s->curp < 0) { /* thread. stop here */
  244. s->curp = -(s->curp);
  245. return 1;
  246. }
  247. while ((q = s->node[s->curp].left)) /* now go all the way left */
  248. s->curp = q;
  249. return 1;
  250. }
  251. /*!
  252. * \brief Retrieve sorted cell stats
  253. *
  254. * Retrieves the next <i>cat, count</i> combination from the
  255. * structure. Returns 0 if there are no more items, non-zero if there
  256. * are more. For example:
  257. *
  258. \code
  259. struct Cell_stats s;
  260. CELL cat;
  261. long count;
  262. // updating <b>s</b> occurs here
  263. Rast_rewind_cell_stats(&s);
  264. while (Rast_next_cell_stat(&cat,&count,&s)
  265. fprintf(stdout, "%ld %ld\n", (long) cat, count);
  266. \endcode
  267. *
  268. * Do not return a record for the NULL-value
  269. *
  270. * \param cat raster value
  271. * \param[out] count
  272. * \param s pointer to Cell_stats structure which holds cell stats info
  273. *
  274. * \return 0 if there are no more items
  275. * \return non-zero if there are more
  276. */
  277. int Rast_next_cell_stat(CELL * cat, long *count, struct Cell_stats *s)
  278. {
  279. int idx;
  280. /* first time report stats for null */
  281. /* decided not to return stats for null in this function
  282. static int null_reported = 0;
  283. if(!null_reported && s->null_data_count > 0)
  284. {
  285. *count = s->null_data_count;
  286. Rast_set_c_null_value(&cat,1);
  287. null_reported = 1;
  288. return 1;
  289. }
  290. */
  291. if (s->N <= 0)
  292. return 0;
  293. for (;;) {
  294. s->curoffset++;
  295. if (s->curoffset >= NCATS) {
  296. if (!next_node(s))
  297. return 0;
  298. s->curoffset = -1;
  299. continue;
  300. }
  301. if ((*count = s->node[s->curp].count[s->curoffset])) {
  302. idx = s->node[s->curp].idx;
  303. /*
  304. if (idx < 0)
  305. *cat = idx*NCATS + s->curoffset+1;
  306. else
  307. *cat = idx*NCATS + s->curoffset;
  308. */
  309. if (idx < 0)
  310. *cat = -((-idx) << SHIFT) + s->curoffset + 1;
  311. else
  312. *cat = (idx << SHIFT) + s->curoffset;
  313. return 1;
  314. }
  315. }
  316. }
  317. /*!
  318. * \brief Get number of null values.
  319. *
  320. * Get a number of null values from stats structure.
  321. *
  322. * Note: when reporting values which appear in a map using
  323. * Rast_next_cell_stats(), to get stats for null, call
  324. * Rast_get_stats_for_null_value() first, since Rast_next_cell_stats() does
  325. * not report stats for null.
  326. *
  327. * \param count count
  328. * \param s pointer to Cell_stats structure which holds cell stats info
  329. */
  330. void Rast_get_stats_for_null_value(long *count, const struct Cell_stats *s)
  331. {
  332. *count = s->null_data_count;
  333. }
  334. /*!
  335. * \brief Free cell stats structure
  336. *
  337. * The memory associated with structure <i>s</i> is freed. This
  338. * routine may be called any time after calling Rast_init_cell_stats().
  339. *
  340. * \param s pointer to Cell_stats structure
  341. */
  342. void Rast_free_cell_stats(struct Cell_stats *s)
  343. {
  344. int i;
  345. for (i = 1; i <= s->N; i++)
  346. G_free(s->node[i].count);
  347. G_free(s->node);
  348. }