histogram.c 9.2 KB

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