histogram.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. #include <grass/gis.h>
  2. #include <grass/glocale.h>
  3. #include <stdlib.h>
  4. #define LIST struct Histogram_list
  5. static FILE *fopen_histogram_new(const char *);
  6. static int cmp(const void *, const void *);
  7. static int cmp_count(const void *, const void *);
  8. /*!
  9. * \brief initializes the histogram structure
  10. *
  11. * initializes the histogram structure for calls to G_set_histogram()
  12. * and G_add_histogram()
  13. * \param histogram
  14. * \return
  15. */
  16. void G_init_histogram(struct Histogram *histogram)
  17. {
  18. histogram->num = 0;
  19. histogram->list = NULL;
  20. }
  21. /*!
  22. * \brief read the histogram information
  23. *
  24. * Reads the histogram information associated with map layer "map"
  25. * in mapset "mapset" into the structure "histogram".
  26. *
  27. * note: a warning message is printed if the file is missing or incorrect
  28. * \param name: name of map
  29. * \param mapset: mapset that map belongs to
  30. * \param histogram: struct for histogram
  31. * \return 1 if successful,
  32. * 0 if no histogram file,
  33. * -1 on fail
  34. */
  35. int G_read_histogram(const char *name, const char *mapset,
  36. struct Histogram *histogram)
  37. {
  38. FILE *fd = NULL;
  39. long cat;
  40. long count;
  41. char buf[200];
  42. G_init_histogram(histogram);
  43. if (G_find_file2_misc("cell_misc", "histogram", name, mapset) == NULL) {
  44. G_warning(_("Histogram for [%s in %s] missing (run r.support)"), name,
  45. mapset);
  46. return 0;
  47. }
  48. fd = G_fopen_old_misc("cell_misc", "histogram", name, mapset);
  49. if (!fd) {
  50. G_warning(_("Can't read histogram for [%s in %s]"), name, mapset);
  51. return -1;
  52. }
  53. while (fgets(buf, sizeof buf, fd)) {
  54. if (sscanf(buf, "%ld:%ld", &cat, &count) != 2) {
  55. G_free_histogram(histogram);
  56. fclose(fd);
  57. G_warning(_("Invalid histogram file for [%s in %s]"), name,
  58. mapset);
  59. return -1;
  60. }
  61. G_extend_histogram((CELL) cat, count, histogram);
  62. }
  63. fclose(fd);
  64. if (histogram->num == 0) {
  65. G_warning(_("Invalid histogram file for [%s in %s]"), name, mapset);
  66. return -1;
  67. }
  68. G_sort_histogram(histogram);
  69. return 1;
  70. }
  71. /*!
  72. * \brief Writes the histogram information
  73. *
  74. * Writes the histogram information associated with map layer "name"
  75. * \param name: name of map
  76. * \param histogram: struct for histogram
  77. * \return 1 if successful,
  78. * -1 on fail
  79. */
  80. int G_write_histogram(const char *name, const struct Histogram *histogram)
  81. {
  82. FILE *fd;
  83. int n;
  84. LIST *list;
  85. fd = fopen_histogram_new(name);
  86. if (fd == NULL)
  87. return -1;
  88. list = histogram->list;
  89. for (n = 0; n < histogram->num; n++) {
  90. if (list[n].count)
  91. fprintf(fd, "%ld:%ld\n", (long)list[n].cat, list[n].count);
  92. }
  93. fclose(fd);
  94. return 1;
  95. }
  96. /*!
  97. * \brief Writes the histogram based on cell statistics to file
  98. *
  99. * \param name: name of map
  100. * \param statf: cell statistics
  101. * \return 1 on success
  102. * -1 on failure
  103. */
  104. int G_write_histogram_cs(const char *name, struct Cell_stats *statf)
  105. {
  106. FILE *fd;
  107. CELL cat;
  108. long count;
  109. fd = fopen_histogram_new(name);
  110. if (fd == NULL)
  111. return -1;
  112. G_rewind_cell_stats(statf);
  113. while (G_next_cell_stat(&cat, &count, statf)) {
  114. if (count > 0)
  115. fprintf(fd, "%ld:%ld\n", (long)cat, count);
  116. }
  117. fclose(fd);
  118. return 1;
  119. }
  120. /*!
  121. * \brief Creates histogram based on cell statistics
  122. *
  123. * \param statf: cell statistics
  124. * \param histogram: raster histogram
  125. * \return
  126. */
  127. void G_make_histogram_cs(struct Cell_stats *statf, struct Histogram *histogram)
  128. {
  129. CELL cat;
  130. long count;
  131. G_init_histogram(histogram);
  132. G_rewind_cell_stats(statf);
  133. while (G_next_cell_stat(&cat, &count, statf))
  134. G_add_histogram(cat, count, histogram);
  135. G_sort_histogram(histogram);
  136. }
  137. /*!
  138. * \brief Sorts the histogram in ascending order by counts then category
  139. *
  140. * Sorts the histogram in ascending order by counts then category.
  141. * No combining is done.
  142. * \param histogram: struct for histogram
  143. * \return 1 if successful,
  144. * -1 on fail
  145. */
  146. int G_get_histogram_num(const struct Histogram *histogram)
  147. {
  148. return histogram->num;
  149. }
  150. /*!
  151. * \brief Returns cat for the nth element in the histogram
  152. *
  153. * Returns cat for the nth element in the histogram
  154. * \param histogram: struct for histogram
  155. * \return CELL
  156. */
  157. CELL G_get_histogram_cat(int n, const struct Histogram * histogram)
  158. {
  159. if (n < 0 || n >= histogram->num)
  160. return 0;
  161. return histogram->list[n].cat;
  162. }
  163. /*!
  164. * \brief Returns count for the nth element in the histogram
  165. *
  166. * Returns count for the nth element in the histogram
  167. * \param n: nth element
  168. * \param histogram: struct for histogram
  169. * \return count
  170. */
  171. long G_get_histogram_count(int n, const struct Histogram *histogram)
  172. {
  173. if (n < 0 || n >= histogram->num)
  174. return 0;
  175. return histogram->list[n].count;
  176. }
  177. /*!
  178. * \brief Frees memory allocated for the histogram
  179. *
  180. * frees the memory allocated for the histogram
  181. * \param histogram: struct for histogram
  182. * \return
  183. */
  184. void G_free_histogram(struct Histogram *histogram)
  185. {
  186. if (histogram->num > 0)
  187. G_free(histogram->list);
  188. histogram->num = 0;
  189. histogram->list = NULL;
  190. }
  191. /*!
  192. * \brief Sorts the histogram
  193. *
  194. * Sorts the histogram in ascending order by category,
  195. * combining (by adding) elements that have the same category.
  196. * \param histogram: struct for histogram
  197. * \return 0 if successful,
  198. * 1 on fail
  199. */
  200. int G_sort_histogram(struct Histogram *histogram)
  201. {
  202. int a, b, n;
  203. LIST *list;
  204. /* if histogram only has 1 entry, nothing to do */
  205. if ((n = histogram->num) <= 1)
  206. return 1;
  207. list = histogram->list;
  208. /* quick check to see if sorting needed */
  209. for (a = 1; a < n; a++)
  210. if (list[a - 1].cat >= list[a].cat)
  211. break;
  212. if (a >= n)
  213. return 1;
  214. /* sort */
  215. qsort(list, n, sizeof(LIST), &cmp);
  216. /* sum duplicate entries */
  217. for (a = 0, b = 1; b < n; b++) {
  218. if (list[a].cat != list[b].cat) {
  219. a++;
  220. list[a].count = list[b].count;
  221. list[a].cat = list[b].cat;
  222. }
  223. else {
  224. list[a].count += list[b].count;
  225. }
  226. }
  227. histogram->num = a + 1;
  228. return 0;
  229. }
  230. static int cmp(const void *aa, const void *bb)
  231. {
  232. const LIST *a = aa, *b = bb;
  233. if (a->cat < b->cat)
  234. return -1;
  235. if (a->cat > b->cat)
  236. return 1;
  237. return 0;
  238. }
  239. /*!
  240. * \brief Sorts the histogram by counts
  241. *
  242. * Sorts the histogram in ascending order by counts then category.
  243. * No combining is done.
  244. * \param histogram: struct for histogram
  245. * \return 0 if successful,
  246. * 1 on fail
  247. */
  248. int G_sort_histogram_by_count(struct Histogram *histogram)
  249. {
  250. int n;
  251. LIST *list;
  252. /* if histogram only has 1 entry, nothing to do */
  253. if ((n = histogram->num) <= 1)
  254. return 1;
  255. list = histogram->list;
  256. /* sort */
  257. qsort(list, n, sizeof(LIST), &cmp_count);
  258. return 0;
  259. }
  260. static int cmp_count(const void *aa, const void *bb)
  261. {
  262. const LIST *a = aa, *b = bb;
  263. if (a->count < b->count)
  264. return -1;
  265. if (a->count > b->count)
  266. return 1;
  267. if (a->cat < b->cat)
  268. return -1;
  269. if (a->cat > b->cat)
  270. return 1;
  271. return 0;
  272. }
  273. static FILE *fopen_histogram_new(const char *name)
  274. {
  275. FILE *fd;
  276. fd = G_fopen_new_misc("cell_misc", "histogram", name);
  277. if (fd == NULL)
  278. G_warning(_("can't create histogram for [%s in %s]"), name,
  279. G_mapset());
  280. return fd;
  281. }
  282. /*!
  283. * \brief Removes the histogram
  284. *
  285. * Removes the histogram information associated with map layer "name"
  286. * \param name: name of map
  287. * \return
  288. */
  289. void G_remove_histogram(const char *name)
  290. {
  291. G_remove_misc("cell_misc", "histogram", name);
  292. }
  293. /*!
  294. * \brief adds count to the histogram value for cat
  295. *
  296. * adds count to the histogram value for cat
  297. * \param cat: category
  298. * \param count
  299. * \param histogram: struct for histogram
  300. * \return 0 if successful,
  301. * 1 on fail
  302. */
  303. int G_add_histogram(CELL cat, long count, struct Histogram *histogram)
  304. {
  305. int i;
  306. for (i = 0; i < histogram->num; i++) {
  307. if (histogram->list[i].cat == cat) {
  308. histogram->list[i].count += count;
  309. return 1;
  310. }
  311. }
  312. G_extend_histogram(cat, count, histogram);
  313. return 0;
  314. }
  315. /*!
  316. * \brief sets the histogram value for cat to count
  317. *
  318. * sets the histogram value for cat to count
  319. * \param cat: category
  320. * \param count
  321. * \param histogram: struct for histogram
  322. * \return 0 if successful,
  323. * 1 on fail
  324. */
  325. int G_set_histogram(CELL cat, long count, struct Histogram *histogram)
  326. {
  327. int i;
  328. for (i = 0; i < histogram->num; i++) {
  329. if (histogram->list[i].cat == cat) {
  330. histogram->list[i].count = count;
  331. return 1;
  332. }
  333. }
  334. G_extend_histogram(cat, count, histogram);
  335. return 0;
  336. }
  337. /*!
  338. * \brief Extends histogram struct to accomodate a new value
  339. *
  340. * \param cat: category
  341. * \param count
  342. * \param histogram: struct for histogram
  343. * \return
  344. */
  345. void G_extend_histogram(CELL cat, long count, struct Histogram *histogram)
  346. {
  347. histogram->num++;
  348. histogram->list =
  349. (LIST *) G_realloc(histogram->list,
  350. histogram->num * sizeof(LIST));
  351. histogram->list[histogram->num - 1].cat = cat;
  352. histogram->list[histogram->num - 1].count = count;
  353. }
  354. /*!
  355. * \brief Zero out histogram struct
  356. *
  357. * \param histogram: struct for histogram
  358. * \return
  359. */
  360. void G_zero_histogram(struct Histogram *histogram)
  361. {
  362. int i;
  363. for (i = 0; i < histogram->num; i++)
  364. histogram->list[i].count = 0;
  365. }