clump.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /****************************************************************************
  2. *
  3. * MODULE: r.clump
  4. *
  5. * AUTHOR(S): Michael Shapiro - CERL
  6. *
  7. * PURPOSE: Recategorizes data in a raster map layer by grouping cells
  8. * that form physically discrete areas into unique categories.
  9. *
  10. * COPYRIGHT: (C) 2006 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. ***************************************************************************/
  17. #include <time.h>
  18. #include <grass/gis.h>
  19. #include <grass/raster.h>
  20. #include <grass/glocale.h>
  21. #include "local_proto.h"
  22. #define INCR 1024
  23. CELL clump(int in_fd, int out_fd)
  24. {
  25. register int col;
  26. register CELL *prev_clump, *cur_clump;
  27. register CELL *index;
  28. register int n;
  29. CELL *prev_in, *cur_in;
  30. CELL *temp_cell, *temp_clump, *out_cell;
  31. CELL X, UP, LEFT, NEW, OLD;
  32. CELL label;
  33. int nrows, ncols;
  34. int row;
  35. int len;
  36. int pass;
  37. int nalloc;
  38. long cur_time;
  39. int column;
  40. nrows = Rast_window_rows();
  41. ncols = Rast_window_cols();
  42. /* allocate reclump index */
  43. nalloc = INCR;
  44. index = (CELL *) G_malloc(nalloc * sizeof(CELL));
  45. index[0] = 0;
  46. /* allocate CELL buffers one column larger than current window */
  47. len = (ncols + 1) * sizeof(CELL);
  48. prev_in = (CELL *) G_malloc(len);
  49. cur_in = (CELL *) G_malloc(len);
  50. prev_clump = (CELL *) G_malloc(len);
  51. cur_clump = (CELL *) G_malloc(len);
  52. out_cell = (CELL *) G_malloc(len);
  53. /******************************** PASS 1 ************************************
  54. * first pass thru the input simulates the clump to determine
  55. * the reclumping index.
  56. * second pass does the clumping for real
  57. */
  58. time(&cur_time);
  59. for (pass = 1; pass <= 2; pass++) {
  60. /* second pass must generate a renumbering scheme */
  61. if (pass == 2) {
  62. CELL cat, *renumber;
  63. renumber = (CELL *) G_malloc((label + 1) * sizeof(CELL));
  64. cat = 1;
  65. for (n = 1; n <= label; n++)
  66. renumber[n] = 0;
  67. for (n = 1; n <= label; n++)
  68. renumber[index[n]] = 1;
  69. for (n = 1; n <= label; n++)
  70. if (renumber[n])
  71. renumber[n] = cat++;
  72. for (n = 1; n <= label; n++)
  73. index[n] = renumber[index[n]];
  74. G_free(renumber);
  75. }
  76. /* fake a previous row which is all zero */
  77. G_zero(prev_in, len);
  78. G_zero(prev_clump, len);
  79. /* create a left edge of zero */
  80. cur_in[0] = 0;
  81. cur_clump[0] = 0;
  82. /* initialize clump labels */
  83. label = 0;
  84. G_message(_("Pass %d..."), pass);
  85. for (row = 0; row < nrows; row++) {
  86. Rast_get_c_row(in_fd, cur_in + 1, row);
  87. G_percent(row+1, nrows, 2);
  88. X = 0;
  89. for (col = 1; col <= ncols; col++) {
  90. LEFT = X;
  91. X = cur_in[col];
  92. if (X == 0) { /* don't clump zero data */
  93. cur_clump[col] = 0;
  94. continue;
  95. }
  96. UP = prev_in[col];
  97. /*
  98. * if the cell value is different above and to the left
  99. * then we must start a new clump
  100. *
  101. * this new clump may eventually collide with another
  102. * clump and have to be merged
  103. */
  104. if (X != LEFT && X != UP) { /* start a new clump */
  105. label++;
  106. cur_clump[col] = label;
  107. if (pass == 1) {
  108. if (label >= nalloc) {
  109. nalloc += INCR;
  110. index =
  111. (CELL *) G_realloc(index,
  112. nalloc * sizeof(CELL));
  113. }
  114. index[label] = label;
  115. }
  116. continue;
  117. }
  118. if (X == LEFT && X != UP) { /* same clump as to the left */
  119. cur_clump[col] = cur_clump[col - 1];
  120. continue;
  121. }
  122. if (X == UP && X != LEFT) { /* same clump as above */
  123. cur_clump[col] = prev_clump[col];
  124. continue;
  125. }
  126. /*
  127. * at this point the cell value X is the same as LEFT and UP
  128. * so it should go into the same clump. It is possible for
  129. * the clump value on the left to differ from the clump value
  130. * above. If this happens we have a conflict and one of the
  131. * LEFT or UP needs to be reclumped
  132. */
  133. if (cur_clump[col - 1] == prev_clump[col]) { /* ok */
  134. cur_clump[col] = prev_clump[col];
  135. continue;
  136. }
  137. /* conflict! preserve the clump from above and change the left.
  138. * Must also go back to the left in the current row and to the right
  139. * in the previous row to change all the clump values as well.
  140. *
  141. */
  142. NEW = prev_clump[col];
  143. OLD = cur_clump[col - 1];
  144. cur_clump[col] = NEW;
  145. /* to left
  146. for (n = 1; n < col; n++)
  147. if (cur_clump[n] == OLD)
  148. cur_clump[n] = NEW;
  149. */
  150. temp_cell = cur_clump++;
  151. n = col - 1;
  152. while (n-- > 0)
  153. if (*cur_clump == OLD)
  154. *cur_clump++ = NEW;
  155. else
  156. cur_clump++;
  157. cur_clump = temp_cell;
  158. /* to right
  159. for (n = col+1; n <= ncols; n++)
  160. if (prev_clump[n] == OLD)
  161. prev_clump[n] = NEW;
  162. */
  163. temp_cell = prev_clump;
  164. prev_clump += col + 1;
  165. n = ncols - col;
  166. while (n-- > 0)
  167. if (*prev_clump == OLD)
  168. *prev_clump++ = NEW;
  169. else
  170. prev_clump++;
  171. prev_clump = temp_cell;
  172. /* modify the indexes
  173. if (pass == 1)
  174. for (n = 1; n <= label; n++)
  175. if (index[n] == OLD)
  176. index[n] = NEW;
  177. */
  178. if (pass == 1) {
  179. temp_cell = index++;
  180. n = label;
  181. while (n-- > 0)
  182. if (*index == OLD)
  183. *index++ = NEW;
  184. else
  185. index++;
  186. index = temp_cell;
  187. }
  188. }
  189. if (pass == 2) {
  190. /*
  191. for (col = 1; col <= ncols; col++)
  192. out_cell[col] = index[cur_clump[col]];
  193. Rast_put_row (out_fd, out_cell+1, CELL_TYPE);
  194. */
  195. col = ncols;
  196. temp_clump = cur_clump + 1; /* skip left edge */
  197. temp_cell = out_cell;
  198. while (col-- > 0)
  199. *temp_cell++ = index[*temp_clump++];
  200. for (column = 0; column < ncols; column++) {
  201. if (out_cell[column] == 0)
  202. Rast_set_null_value(&out_cell[column], 1, CELL_TYPE);
  203. }
  204. Rast_put_row(out_fd, out_cell, CELL_TYPE);
  205. }
  206. /* switch the buffers so that the current buffer becomes the previous */
  207. temp_cell = cur_in;
  208. cur_in = prev_in;
  209. prev_in = temp_cell;
  210. temp_clump = cur_clump;
  211. cur_clump = prev_clump;
  212. prev_clump = temp_clump;
  213. }
  214. print_time(&cur_time);
  215. }
  216. return 0;
  217. }
  218. int print_time(long *start)
  219. {
  220. int hours, minutes, seconds;
  221. long done;
  222. time(&done);
  223. seconds = done - *start;
  224. *start = done;
  225. hours = seconds / 3600;
  226. minutes = (seconds - hours * 3600) / 60;
  227. seconds = seconds % 60;
  228. if (hours)
  229. G_verbose_message("%2d:%02d:%02d", hours, minutes, seconds);
  230. else if (minutes)
  231. G_verbose_message("%d:%02d", minutes, seconds);
  232. else
  233. G_verbose_message("%d seconds", seconds);
  234. return 0;
  235. }