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