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