GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-112dd97adf
histogram.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 
3 #include <grass/gis.h>
4 #include <grass/raster.h>
5 #include <grass/glocale.h>
6 
7 #define LIST struct Histogram_list
8 
9 static FILE *fopen_histogram_new(const char *);
10 static int cmp(const void *, const void *);
11 static int cmp_count(const void *, const void *);
12 
13 /*!
14  * \brief initializes the histogram structure
15  *
16  * initializes the histogram structure for calls to Rast_set_histogram()
17  * and Rast_add_histogram()
18  * \param histogram
19  * \return
20  */
21 
22 void Rast_init_histogram(struct Histogram *histogram)
23 {
24  histogram->num = 0;
25  histogram->list = NULL;
26 }
27 
28 /*!
29  * \brief read the histogram information
30  *
31  * Reads the histogram information associated with map layer "map"
32  * in mapset "mapset" into the structure "histogram".
33  *
34  * note: a warning message is printed if the file is missing or incorrect
35  * \param name: name of map
36  * \param mapset: mapset that map belongs to
37  * \param histogram: struct for histogram
38  * \return 1 if successful,
39  * 0 if no histogram file,
40  */
41 
42 int Rast_read_histogram(const char *name, const char *mapset,
43  struct Histogram *histogram)
44 {
45  FILE *fd = NULL;
46  long cat;
47  long count;
48  char buf[200];
49 
50  Rast_init_histogram(histogram);
51 
52  if (!G_find_file2_misc("cell_misc", "histogram", name, mapset)) {
53  G_warning(_("Histogram for [%s in %s] missing (run r.support)"), name,
54  mapset);
55  return 0;
56  }
57 
58  fd = G_fopen_old_misc("cell_misc", "histogram", name, mapset);
59  if (!fd)
60  G_fatal_error(_("Can't read histogram for [%s in %s]"), name, mapset);
61 
62  while (fgets(buf, sizeof buf, fd)) {
63  if (sscanf(buf, "%ld:%ld", &cat, &count) != 2)
64  G_fatal_error(_("Invalid histogram file for [%s in %s]"), name,
65  mapset);
66  Rast_extend_histogram((CELL)cat, count, histogram);
67  }
68  fclose(fd);
69 
70  if (histogram->num == 0)
71  G_fatal_error(_("Invalid histogram file for [%s in %s]"), name, mapset);
72 
73  Rast_sort_histogram(histogram);
74 
75  return 1;
76 }
77 
78 /*!
79  * \brief Writes the histogram information
80  *
81  * Writes the histogram information associated with map layer "name"
82  * \param name: name of map
83  * \param histogram: struct for histogram
84  * \return void
85  */
86 
87 void Rast_write_histogram(const char *name, const struct Histogram *histogram)
88 {
89  FILE *fp;
90  int n;
91  LIST *list;
92 
93  fp = fopen_histogram_new(name);
94 
95  list = histogram->list;
96  for (n = 0; n < histogram->num; n++) {
97  if (list[n].count)
98  fprintf(fp, "%ld:%ld\n", (long)list[n].cat, list[n].count);
99  }
100 
101  fclose(fp);
102 }
103 
104 /*!
105  * \brief Writes the histogram based on cell statistics to file
106  *
107  * \param name: name of map
108  * \param statf: cell statistics
109  * \return void
110  */
111 
112 void Rast_write_histogram_cs(const char *name, struct Cell_stats *statf)
113 {
114  FILE *fp;
115  CELL cat;
116  long count;
117 
118  fp = fopen_histogram_new(name);
119 
120  Rast_rewind_cell_stats(statf);
121  while (Rast_next_cell_stat(&cat, &count, statf)) {
122  if (count > 0)
123  fprintf(fp, "%ld:%ld\n", (long)cat, count);
124  }
125 
126  fclose(fp);
127 }
128 
129 /*!
130  * \brief Creates histogram based on cell statistics
131  *
132  * \param statf: cell statistics
133  * \param histogram: raster histogram
134  * \return
135  */
137  struct Histogram *histogram)
138 {
139  CELL cat;
140  long count;
141 
142  Rast_init_histogram(histogram);
143  Rast_rewind_cell_stats(statf);
144  while (Rast_next_cell_stat(&cat, &count, statf))
145  Rast_add_histogram(cat, count, histogram);
146 
147  Rast_sort_histogram(histogram);
148 }
149 
150 /*!
151  * \brief Sorts the histogram in ascending order by counts then category
152  *
153  * Sorts the histogram in ascending order by counts then category.
154  * No combining is done.
155  * \param histogram: struct for histogram
156  * \return 1 if successful,
157  * -1 on fail
158  */
159 int Rast_get_histogram_num(const struct Histogram *histogram)
160 {
161  return histogram->num;
162 }
163 
164 /*!
165  * \brief Returns cat for the nth element in the histogram
166  *
167  * Returns cat for the nth element in the histogram
168  * \param histogram: struct for histogram
169  * \return CELL
170  */
171 CELL Rast_get_histogram_cat(int n, const struct Histogram *histogram)
172 {
173  if (n < 0 || n >= histogram->num)
174  return 0;
175 
176  return histogram->list[n].cat;
177 }
178 
179 /*!
180  * \brief Returns count for the nth element in the histogram
181  *
182  * Returns count for the nth element in the histogram
183  * \param n: nth element
184  * \param histogram: struct for histogram
185  * \return count
186  */
187 long Rast_get_histogram_count(int n, const struct Histogram *histogram)
188 {
189  if (n < 0 || n >= histogram->num)
190  return 0;
191 
192  return histogram->list[n].count;
193 }
194 
195 /*!
196  * \brief Frees memory allocated for the histogram
197  *
198  * frees the memory allocated for the histogram
199  * \param histogram: struct for histogram
200  * \return
201  */
202 void Rast_free_histogram(struct Histogram *histogram)
203 {
204  if (histogram->num > 0)
205  G_free(histogram->list);
206  histogram->num = 0;
207  histogram->list = NULL;
208 }
209 
210 /*!
211  * \brief Sorts the histogram
212  *
213  * Sorts the histogram in ascending order by category,
214  * combining (by adding) elements that have the same category.
215  * \param histogram: struct for histogram
216  * \return 0 if successful,
217  * 1 on fail
218  */
219 int Rast_sort_histogram(struct Histogram *histogram)
220 {
221  int a, b, n;
222  LIST *list;
223 
224  /* if histogram only has 1 entry, nothing to do */
225  if ((n = histogram->num) <= 1)
226  return 1;
227 
228  list = histogram->list;
229 
230  /* quick check to see if sorting needed */
231  for (a = 1; a < n; a++)
232  if (list[a - 1].cat >= list[a].cat)
233  break;
234  if (a >= n)
235  return 1;
236 
237  /* sort */
238  qsort(list, n, sizeof(LIST), &cmp);
239 
240  /* sum duplicate entries */
241  for (a = 0, b = 1; b < n; b++) {
242  if (list[a].cat != list[b].cat) {
243  a++;
244  list[a].count = list[b].count;
245  list[a].cat = list[b].cat;
246  }
247  else {
248  list[a].count += list[b].count;
249  }
250  }
251  histogram->num = a + 1;
252 
253  return 0;
254 }
255 
256 static int cmp(const void *aa, const void *bb)
257 {
258  const LIST *a = aa, *b = bb;
259 
260  if (a->cat < b->cat)
261  return -1;
262 
263  if (a->cat > b->cat)
264  return 1;
265 
266  return 0;
267 }
268 
269 /*!
270  * \brief Sorts the histogram by counts
271  *
272  * Sorts the histogram in ascending order by counts then category.
273  * No combining is done.
274  * \param histogram: struct for histogram
275  * \return 0 if successful,
276  * 1 on fail
277  */
279 {
280  int n;
281  LIST *list;
282 
283  /* if histogram only has 1 entry, nothing to do */
284  if ((n = histogram->num) <= 1)
285  return 1;
286 
287  list = histogram->list;
288 
289  /* sort */
290  qsort(list, n, sizeof(LIST), &cmp_count);
291 
292  return 0;
293 }
294 
295 static int cmp_count(const void *aa, const void *bb)
296 {
297  const LIST *a = aa, *b = bb;
298 
299  if (a->count < b->count)
300  return -1;
301 
302  if (a->count > b->count)
303  return 1;
304 
305  if (a->cat < b->cat)
306  return -1;
307 
308  if (a->cat > b->cat)
309  return 1;
310 
311  return 0;
312 }
313 
314 static FILE *fopen_histogram_new(const char *name)
315 {
316  FILE *fp;
317 
318  fp = G_fopen_new_misc("cell_misc", "histogram", name);
319  if (!fp)
320  G_fatal_error(_("Unable to create histogram file for <%s>"), name);
321 
322  return fp;
323 }
324 
325 /*!
326  * \brief Removes the histogram
327  *
328  * Removes the histogram information associated with map layer "name"
329  * \param name: name of map
330  * \return
331  */
332 
333 void Rast_remove_histogram(const char *name)
334 {
335  G_remove_misc("cell_misc", "histogram", name);
336 }
337 
338 /*!
339  * \brief adds count to the histogram value for cat
340  *
341  * adds count to the histogram value for cat
342  * \param cat: category
343  * \param count
344  * \param histogram: struct for histogram
345  * \return 0 if successful,
346  * 1 on fail
347  */
348 int Rast_add_histogram(CELL cat, long count, struct Histogram *histogram)
349 {
350  int i;
351 
352  for (i = 0; i < histogram->num; i++) {
353  if (histogram->list[i].cat == cat) {
354  histogram->list[i].count += count;
355  return 1;
356  }
357  }
358  Rast_extend_histogram(cat, count, histogram);
359 
360  return 0;
361 }
362 
363 /*!
364  * \brief sets the histogram value for cat to count
365  *
366  * sets the histogram value for cat to count
367  * \param cat: category
368  * \param count
369  * \param histogram: struct for histogram
370  * \return 0 if successful,
371  * 1 on fail
372  */
373 int Rast_set_histogram(CELL cat, long count, struct Histogram *histogram)
374 {
375  int i;
376 
377  for (i = 0; i < histogram->num; i++) {
378  if (histogram->list[i].cat == cat) {
379  histogram->list[i].count = count;
380  return 1;
381  }
382  }
383  Rast_extend_histogram(cat, count, histogram);
384 
385  return 0;
386 }
387 
388 /*!
389  * \brief Extends histogram struct to accommodate a new value
390  *
391  * \param cat: category
392  * \param count
393  * \param histogram: struct for histogram
394  * \return
395  */
396 void Rast_extend_histogram(CELL cat, long count, struct Histogram *histogram)
397 {
398  histogram->num++;
399  histogram->list =
400  (LIST *)G_realloc(histogram->list, histogram->num * sizeof(LIST));
401  histogram->list[histogram->num - 1].cat = cat;
402  histogram->list[histogram->num - 1].count = count;
403 }
404 
405 /*!
406  * \brief Zero out histogram struct
407  *
408  * \param histogram: struct for histogram
409  * \return
410  */
411 void Rast_zero_histogram(struct Histogram *histogram)
412 {
413  int i;
414 
415  for (i = 0; i < histogram->num; i++)
416  histogram->list[i].count = 0;
417 }
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_realloc(p, n)
Definition: defs/gis.h:96
FILE * G_fopen_old_misc(const char *, const char *, const char *, const char *)
open a database misc file for reading
Definition: open_misc.c:205
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
FILE * G_fopen_new_misc(const char *, const char *, const char *)
open a new database misc file
Definition: open_misc.c:178
const char * G_find_file2_misc(const char *, const char *, const char *, const char *)
Searches for a misc file from the mapset search list or in a specified mapset. (look but don't touch)
Definition: find_file.c:257
int G_remove_misc(const char *, const char *, const char *)
Remove a database misc file.
Definition: remove.c:65
int Rast_rewind_cell_stats(struct Cell_stats *)
Reset/rewind cell stats.
Definition: cell_stats.c:248
int Rast_next_cell_stat(CELL *, long *, struct Cell_stats *)
Retrieve sorted cell stats.
Definition: cell_stats.c:312
int CELL
Definition: gis.h:625
#define _(str)
Definition: glocale.h:10
int Rast_get_histogram_num(const struct Histogram *histogram)
Sorts the histogram in ascending order by counts then category.
Definition: histogram.c:159
void Rast_write_histogram(const char *name, const struct Histogram *histogram)
Writes the histogram information.
Definition: histogram.c:87
int Rast_read_histogram(const char *name, const char *mapset, struct Histogram *histogram)
read the histogram information
Definition: histogram.c:42
void Rast_free_histogram(struct Histogram *histogram)
Frees memory allocated for the histogram.
Definition: histogram.c:202
int Rast_add_histogram(CELL cat, long count, struct Histogram *histogram)
adds count to the histogram value for cat
Definition: histogram.c:348
int Rast_sort_histogram(struct Histogram *histogram)
Sorts the histogram.
Definition: histogram.c:219
void Rast_extend_histogram(CELL cat, long count, struct Histogram *histogram)
Extends histogram struct to accommodate a new value.
Definition: histogram.c:396
void Rast_write_histogram_cs(const char *name, struct Cell_stats *statf)
Writes the histogram based on cell statistics to file.
Definition: histogram.c:112
long Rast_get_histogram_count(int n, const struct Histogram *histogram)
Returns count for the nth element in the histogram.
Definition: histogram.c:187
int Rast_sort_histogram_by_count(struct Histogram *histogram)
Sorts the histogram by counts.
Definition: histogram.c:278
void Rast_make_histogram_cs(struct Cell_stats *statf, struct Histogram *histogram)
Creates histogram based on cell statistics.
Definition: histogram.c:136
int Rast_set_histogram(CELL cat, long count, struct Histogram *histogram)
sets the histogram value for cat to count
Definition: histogram.c:373
CELL Rast_get_histogram_cat(int n, const struct Histogram *histogram)
Returns cat for the nth element in the histogram.
Definition: histogram.c:171
void Rast_zero_histogram(struct Histogram *histogram)
Zero out histogram struct.
Definition: histogram.c:411
void Rast_init_histogram(struct Histogram *histogram)
initializes the histogram structure
Definition: histogram.c:22
void Rast_remove_histogram(const char *name)
Removes the histogram.
Definition: histogram.c:333
#define LIST
Definition: histogram.c:7
int count
const char * name
Definition: named_colr.c:6
double b
Definition: r_raster.c:39
struct list * list
Definition: read_list.c:24
int num
Definition: raster.h:197
struct Histogram::Histogram_list * list
Definition: manage.h:4