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