123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- /*!
- * \file lib/raster/cell_stats.c
- *
- * \brief Raster Library - Raster cell statistics
- *
- * (C) 2001-2009 GRASS Development Team
- *
- * This program is free software under the GNU General Public License
- * (>=v2). Read the file COPYING that comes with GRASS for details.
- *
- * \author Original author CERL
- */
- #include <stdlib.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #define INCR 10
- #define SHIFT 6
- static const int NCATS = 1 << SHIFT;
- #define NODE struct Cell_stats_node
- static int next_node(struct Cell_stats *);
- static void init_node(NODE *, int, int);
- /*!
- * \brief Initialize cell stats
- *
- * This routine, which must be called first, initializes the
- * Cell_stats structure.
- *
- * Set the count for NULL-values to zero.
- *
- * \param s pointer to Cell_stats structure
- */
- void Rast_init_cell_stats(struct Cell_stats *s)
- {
- s->N = 0;
- s->tlen = INCR;
- s->node = (NODE *) G_malloc(s->tlen * sizeof(NODE));
- s->null_data_count = 0;
- }
- /*!
- * \brief Add data to cell stats
- *
- * The <i>n</i> CELL values in the <i>data</i> array are inserted (and
- * counted) in the Cell_stats structure.
- *
- * Look for NULLs and update the NULL-value count.
- *
- * \param cell raster values
- * \param n number of values
- * \param s pointer to Cell_stats structure which holds cell stats info
- *
- * \return 1 on failure
- * \return 0 on success
- */
- int Rast_update_cell_stats(const CELL * cell, int n, struct Cell_stats *s)
- {
- CELL cat;
- int p, q;
- int idx, offset;
- int N;
- NODE *node, *pnode;
- NODE *new_node;
- if (n <= 0)
- return 1;
- node = s->node;
- /* first non-null node is special case */
- if ((N = s->N) == 0) {
- cat = *cell++;
- while (Rast_is_c_null_value(&cat)) {
- s->null_data_count++;
- cat = *cell++;
- n--;
- }
- if (n > 0) { /* if there are some non-null cells */
- N = 1;
- if (cat < 0) {
- idx = -((-cat) >> SHIFT) - 1;
- offset = cat + ((-idx) << SHIFT) - 1;
- }
- else {
- idx = cat >> SHIFT;
- offset = cat - (idx << SHIFT);
- }
- fflush(stderr);
- init_node(&node[1], idx, offset);
- node[1].right = 0;
- n--;
- }
- }
- while (n-- > 0) {
- cat = *cell++;
- if (Rast_is_c_null_value(&cat)) {
- s->null_data_count++;
- continue;
- }
- if (cat < 0) {
- idx = -((-cat) >> SHIFT) - 1;
- offset = cat + ((-idx) << SHIFT) - 1;
- }
- else {
- idx = cat >> SHIFT;
- offset = cat - (idx << SHIFT);
- }
- q = 1;
- while (q > 0) {
- pnode = &node[p = q];
- if (pnode->idx == idx) {
- pnode->count[offset]++;
- break;
- }
- if (pnode->idx > idx)
- q = pnode->left; /* go left */
- else
- q = pnode->right; /* go right */
- }
- if (q > 0)
- continue; /* found */
- /* new node */
- N++;
- /* grow the tree? */
- if (N >= s->tlen) {
- node =
- (NODE *) G_realloc((char *)node,
- sizeof(NODE) * (s->tlen += INCR));
- pnode = &node[p]; /* realloc moves node, must reassign pnode */
- }
- /* add node to tree */
- init_node(new_node = &node[N], idx, offset);
- if (pnode->idx > idx) {
- new_node->right = -p; /* create thread */
- pnode->left = N; /* insert left */
- }
- else {
- new_node->right = pnode->right; /* copy right link/thread */
- pnode->right = N; /* add right */
- }
- } /* while n-- > 0 */
- s->N = N;
- s->node = node;
- return 0;
- }
- static void init_node(NODE * node, int idx, int offset)
- {
- long *count;
- int i;
- count = node->count = (long *)G_calloc(i = NCATS, sizeof(long));
- while (i--)
- *count++ = 0;
- node->idx = idx;
- node->count[offset] = 1;
- node->left = 0;
- }
- /*!
- * \brief Random query of cell stats
- *
- * This routine allows a random query of the Cell_stats structure. The
- * \p count associated with the raster value \p cat is
- * set. The routine returns 1 if \p cat was found in the
- * structure, 0 otherwise.
- *
- * Allow finding the count for the NULL-value.
- *
- * \param cat raster value
- * \param[out] count count
- * \param s pointer to Cell_stats structure which holds cell stats info
- *
- * \return 1 if found
- * \return 0 if not found
- */
- int Rast_find_cell_stat(CELL cat, long *count, const struct Cell_stats *s)
- {
- int q;
- int idx;
- int offset;
- *count = 0;
- if (Rast_is_c_null_value(&cat)) {
- *count = s->null_data_count;
- return (*count != 0);
- }
- if (s->N <= 0)
- return 0;
- /*
- if (cat < 0)
- {
- idx = -(-cat/NCATS) - 1;
- offset = cat - idx*NCATS - 1;
- }
- else
- {
- idx = cat/NCATS;
- offset = cat - idx*NCATS;
- }
- */
- if (cat < 0) {
- idx = -((-cat) >> SHIFT) - 1;
- offset = cat + ((-idx) << SHIFT) - 1;
- }
- else {
- idx = cat >> SHIFT;
- offset = cat - (idx << SHIFT);
- }
- q = 1;
- while (q > 0) {
- if (s->node[q].idx == idx) {
- *count = s->node[q].count[offset];
- return (*count != 0);
- }
- if (s->node[q].idx > idx)
- q = s->node[q].left; /* go left */
- else
- q = s->node[q].right; /* go right */
- }
- return 0;
- }
- /*!
- * \brief Reset/rewind cell stats
- *
- * The structure <i>s</i> is rewound (i.e., positioned at the first
- * raster category) so that sorted sequential retrieval can begin.
- *
- * \param s pointer to Cell_stats structure which holds cell stats info
- *
- * \return 0
- */
- int Rast_rewind_cell_stats(struct Cell_stats *s)
- {
- int q;
- if (s->N <= 0)
- return 1;
- /* start at root and go all the way to the left */
- s->curp = 1;
- while ((q = s->node[s->curp].left))
- s->curp = q;
- s->curoffset = -1;
- return 0;
- }
- static int next_node(struct Cell_stats *s)
- {
- int q;
- /* go to the right */
- s->curp = s->node[s->curp].right;
- if (s->curp == 0) /* no more */
- return 0;
- if (s->curp < 0) { /* thread. stop here */
- s->curp = -(s->curp);
- return 1;
- }
- while ((q = s->node[s->curp].left)) /* now go all the way left */
- s->curp = q;
- return 1;
- }
- /*!
- * \brief Retrieve sorted cell stats
- *
- * Retrieves the next <i>cat, count</i> combination from the
- * structure. Returns 0 if there are no more items, non-zero if there
- * are more. For example:
- *
- \code
- struct Cell_stats s;
- CELL cat;
- long count;
- // updating <b>s</b> occurs here
- Rast_rewind_cell_stats(&s);
- while (Rast_next_cell_stat(&cat,&count,&s)
- fprintf(stdout, "%ld %ld\n", (long) cat, count);
- \endcode
- *
- * Do not return a record for the NULL-value
- *
- * \param cat raster value
- * \param[out] count
- * \param s pointer to Cell_stats structure which holds cell stats info
- *
- * \return 0 if there are no more items
- * \return non-zero if there are more
- */
- int Rast_next_cell_stat(CELL * cat, long *count, struct Cell_stats *s)
- {
- int idx;
- /* first time report stats for null */
- /* decided not to return stats for null in this function
- static int null_reported = 0;
- if(!null_reported && s->null_data_count > 0)
- {
- *count = s->null_data_count;
- Rast_set_c_null_value(&cat,1);
- null_reported = 1;
- return 1;
- }
- */
- if (s->N <= 0)
- return 0;
- for (;;) {
- s->curoffset++;
- if (s->curoffset >= NCATS) {
- if (!next_node(s))
- return 0;
- s->curoffset = -1;
- continue;
- }
- if ((*count = s->node[s->curp].count[s->curoffset])) {
- idx = s->node[s->curp].idx;
- /*
- if (idx < 0)
- *cat = idx*NCATS + s->curoffset+1;
- else
- *cat = idx*NCATS + s->curoffset;
- */
- if (idx < 0)
- *cat = -((-idx) << SHIFT) + s->curoffset + 1;
- else
- *cat = (idx << SHIFT) + s->curoffset;
- return 1;
- }
- }
- }
- /*!
- * \brief Get number of null values.
- *
- * Get a number of null values from stats structure.
- *
- * Note: when reporting values which appear in a map using
- * Rast_next_cell_stats(), to get stats for null, call
- * Rast_get_stats_for_null_value() first, since Rast_next_cell_stats() does
- * not report stats for null.
- *
- * \param count count
- * \param s pointer to Cell_stats structure which holds cell stats info
- */
- void Rast_get_stats_for_null_value(long *count, const struct Cell_stats *s)
- {
- *count = s->null_data_count;
- }
- /*!
- * \brief Free cell stats structure
- *
- * The memory associated with structure <i>s</i> is freed. This
- * routine may be called any time after calling Rast_init_cell_stats().
- *
- * \param s pointer to Cell_stats structure
- */
- void Rast_free_cell_stats(struct Cell_stats *s)
- {
- int i;
- for (i = 1; i <= s->N; i++)
- G_free(s->node[i].count);
- G_free(s->node);
- }
|