main.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /****************************************************************************
  2. *
  3. * MODULE: r.li.patchdensity
  4. * AUTHOR(S): Claudio Porta and Lucio Davide Spano (original contributors)
  5. * students of Computer Science University of Pisa (Italy)
  6. * Commission from Faunalia Pontedera (PI) www.faunalia.it
  7. * Fixes: Serena Pallecchi, Markus Neteler <neteler itc.it>
  8. * PURPOSE: calculates patch density index
  9. * COPYRIGHT: (C) 2006-2007 by the GRASS Development Team
  10. *
  11. * This program is free software under the GNU General Public
  12. * License (>=v2). Read the file COPYING that comes with GRASS
  13. * for details.
  14. *
  15. *****************************************************************************/
  16. #include <stdlib.h>
  17. #include <fcntl.h>
  18. #include <grass/gis.h>
  19. #include <grass/raster.h>
  20. #include <grass/glocale.h>
  21. #include "../r.li.daemon/daemon.h"
  22. int main(int argc, char *argv[])
  23. {
  24. struct Option *raster, *conf, *output;
  25. struct GModule *module;
  26. G_gisinit(argv[0]);
  27. module = G_define_module();
  28. module->description =
  29. _("Calculates patch density index on a raster map, using a 4 neighbour algorithm");
  30. G_add_keyword(_("raster"));
  31. G_add_keyword(_("landscape structure analysis"));
  32. G_add_keyword(_("patch index"));
  33. /* define options */
  34. raster = G_define_standard_option(G_OPT_R_INPUT);
  35. conf = G_define_standard_option(G_OPT_F_INPUT);
  36. conf->key = "config";
  37. conf->description = _("Configuration file");
  38. conf->required = YES;
  39. output = G_define_standard_option(G_OPT_R_OUTPUT);
  40. /** add other options for index parameters here */
  41. if (G_parser(argc, argv))
  42. exit(EXIT_FAILURE);
  43. return calculateIndex(conf->answer, patch_density, NULL, raster->answer,
  44. output->answer);
  45. }
  46. int patch_density(int fd, char **par, struct area_entry *ad, double *result)
  47. {
  48. CELL *buf, *sup, *cnull;
  49. CELL pid, old_pid, *pid_curr, *pid_sup, *ctmp;
  50. int count, i, j, k, connected, other_above;
  51. struct Cell_head hd;
  52. int mask_fd, *mask_buf, null_count;
  53. double area;
  54. double EW_DIST1, EW_DIST2, NS_DIST1, NS_DIST2;
  55. Rast_get_cellhd(ad->raster, "", &hd);
  56. cnull = Rast_allocate_c_buf();
  57. Rast_set_c_null_value(cnull, Rast_window_cols());
  58. sup = cnull;
  59. /* initialize patch ids */
  60. pid_curr = Rast_allocate_c_buf();
  61. Rast_set_c_null_value(pid_curr, Rast_window_cols());
  62. pid_sup = Rast_allocate_c_buf();
  63. Rast_set_c_null_value(pid_sup, Rast_window_cols());
  64. /* open mask if needed */
  65. mask_fd = -1;
  66. mask_buf = NULL;
  67. null_count = 0;
  68. if (ad->mask == 1) {
  69. if ((mask_fd = open(ad->mask_name, O_RDONLY, 0755)) < 0)
  70. return 0;
  71. mask_buf = G_malloc(ad->cl * sizeof(int));
  72. }
  73. /* calculate distance */
  74. G_begin_distance_calculations();
  75. /* EW Dist at North edge */
  76. EW_DIST1 = G_distance(hd.east, hd.north, hd.west, hd.north);
  77. /* EW Dist at South Edge */
  78. EW_DIST2 = G_distance(hd.east, hd.south, hd.west, hd.south);
  79. /* NS Dist at East edge */
  80. NS_DIST1 = G_distance(hd.east, hd.north, hd.east, hd.south);
  81. /* NS Dist at West edge */
  82. NS_DIST2 = G_distance(hd.west, hd.north, hd.west, hd.south);
  83. /* calculate number of patches */
  84. count = 0;
  85. connected = 0;
  86. other_above = 0;
  87. pid = 0;
  88. for (i = 0; i < ad->rl; i++) {
  89. buf = RLI_get_cell_raster_row(fd, i + ad->y, ad);
  90. if (i > 0) {
  91. sup = RLI_get_cell_raster_row(fd, i - 1 + ad->y, ad);
  92. }
  93. /* mask values */
  94. if (ad->mask == 1) {
  95. if (read(mask_fd, mask_buf, (ad->cl * sizeof(int))) < 0)
  96. return 0;
  97. for (j = 0; j < ad->cl; j++) {
  98. if (mask_buf[j + ad->x] == 0) {
  99. Rast_set_c_null_value(&buf[j + ad->x], 1);
  100. null_count++;
  101. }
  102. }
  103. }
  104. ctmp = pid_sup;
  105. pid_sup = pid_curr;
  106. pid_curr = ctmp;
  107. Rast_set_c_null_value(pid_curr, Rast_window_cols());
  108. connected = 0;
  109. other_above = 1;
  110. for (j = 0; j < ad->cl; j++) {
  111. if (Rast_is_null_value(&(buf[j + ad->x]), CELL_TYPE)) {
  112. connected = 0;
  113. other_above = 1;
  114. continue;
  115. }
  116. if (sup[j + ad->x] == buf[j + ad->x]) {
  117. if (!connected) {
  118. pid_curr[j + ad->x] = pid_sup[j + ad->x];
  119. }
  120. if (pid_curr[j + ad->x] != pid_sup[j + ad->x]) {
  121. if (connected) {
  122. count--;
  123. }
  124. if (other_above) {
  125. pid_curr[j + ad->x] = pid_sup[j + ad->x];
  126. for (k = j + ad->x - 1; k >= ad->x; k--) {
  127. if (buf[k] != buf[j + ad->x])
  128. break;
  129. pid_curr[k] = pid_sup[j + ad->x];
  130. }
  131. }
  132. else {
  133. old_pid = pid_sup[j + ad->x];
  134. pid_sup[j + ad->x] = pid_curr[j + ad->x];
  135. for (k = j + 1; k < ad->cl; k++) {
  136. if (pid_sup[k + ad->x] == old_pid) {
  137. pid_sup[k + ad->x] = pid_curr[j + ad->x];
  138. }
  139. }
  140. }
  141. }
  142. other_above = 0;
  143. connected = 1;
  144. }
  145. if (!connected) {
  146. count++;
  147. pid++;
  148. pid_curr[j + ad->x] = pid;
  149. }
  150. if (j < ad->cl - 1) {
  151. if (buf[j + ad->x] == buf[j + 1 + ad->x]) {
  152. connected = 1;
  153. pid_curr[j + 1 + ad->x] = pid_curr[j + ad->x];
  154. }
  155. else {
  156. other_above = 1;
  157. connected = 0;
  158. }
  159. }
  160. }
  161. }
  162. area = (((EW_DIST1 + EW_DIST2) / 2) / hd.cols) *
  163. (((NS_DIST1 + NS_DIST2) / 2) / hd.rows) *
  164. (ad->rl *ad->cl - null_count);
  165. if (area != 0)
  166. *result = (count / area) * 1000000;
  167. else
  168. Rast_set_d_null_value(result, 1);
  169. if (ad->mask == 1) {
  170. G_free(mask_buf);
  171. }
  172. G_free(cnull);
  173. G_free(pid_curr);
  174. G_free(pid_sup);
  175. return RLI_OK;
  176. }