centroids.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /* Find 'centroids' of all cats. Most useful with cats which are
  2. * like clumps (contiguous areas), but will work on any file.
  3. * Respects the current window and mask.
  4. * Category zero and negative categories are not done!
  5. * Returned centroids are (row, col) pairs in n, e.
  6. * Returned value is 0 for most cases, > 0 if 'both' method
  7. * selected and some values fell outside 'clumps', and were
  8. * adjusted.
  9. * Two methods can be used: 'distance-weighted' and 'counting'.
  10. *
  11. * Method 0 = 'counting' or 'clump'; centroid point guaranteed
  12. * to be at a cell of the given category.
  13. * 1 = Both 0 and 2 are run; if method 2 centroid is on
  14. * cell of proper cat, it is used, otherwise
  15. * method 1 value is substituted.
  16. * 2 = 'distance-weighted'; row = sigma(row)/n,
  17. * col = sigma(col)/n.
  18. */
  19. #include <grass/gis.h>
  20. #include <grass/raster.h>
  21. int centroids(int fd, /* File descriptor of map layer to process */
  22. /* This file is assumed to be opened before calling */
  23. /* centroids. */
  24. unsigned long *e, unsigned long *n, /* Pointers to arrays at least max+1 long */
  25. int method, /* 0, 1, or 2; see above. */
  26. int max)
  27. { /* Highest positive cat number in map layer */
  28. CELL *cell_buf, v;
  29. int i, adjusted, numb, left, right;
  30. long int *count;
  31. int row, col, rows, cols;
  32. adjusted = 0;
  33. cell_buf = Rast_allocate_c_buf();
  34. /* space to accumulate counts */
  35. count = (long int *)G_malloc((max + 1) * sizeof(long int));
  36. /* zero the count totals */
  37. for (i = 1; i <= max; i++) {
  38. count[i] = 0;
  39. e[i] = 0;
  40. n[i] = 0;
  41. }
  42. /* do rows and columns through window and mask */
  43. /* to do counting */
  44. rows = Rast_window_rows();
  45. cols = Rast_window_cols();
  46. for (row = 0; row < rows; row++) {
  47. Rast_get_c_row(fd, cell_buf, row); /* get a row */
  48. for (col = 0; col < cols; col++) {
  49. v = cell_buf[col]; /* next cell value in row */
  50. if (v < 1)
  51. continue; /* can't handle 0 or - values */
  52. count[v]++;
  53. if (method > 0) { /* acccumulate row, col weights */
  54. e[v] += col;
  55. n[v] += row;
  56. }
  57. }
  58. }
  59. /* compute averages */
  60. if (method > 0)
  61. for (i = 1; i <= max; i++) {
  62. if (count[i]) {
  63. numb = count[i];
  64. e[i] /= numb;
  65. n[i] /= numb;
  66. }
  67. }
  68. /* substitute 'count' centroids for 'weighted' ones, if necessary */
  69. if (method == 1) {
  70. for (i = 1; i <= max; i++) {
  71. if (count[i]) {
  72. row = n[i];
  73. col = e[i];
  74. /* get cell at row,col */
  75. Rast_get_c_row(fd, cell_buf, row);
  76. v = cell_buf[col];
  77. if (v > 0) {
  78. if (v == i)
  79. count[i] = 0; /* weighted is acceptable */
  80. else
  81. adjusted++;
  82. }
  83. }
  84. }
  85. }
  86. /* compute middle cell; zeros will remain zeros */
  87. for (i = 1; i <= max; i++)
  88. count[i] = (count[i] + 1) / 2;
  89. /* go through map again */
  90. for (row = 0; row < rows; row++) {
  91. Rast_get_c_row(fd, cell_buf, row);
  92. for (col = 0; col < cols; col++) {
  93. v = cell_buf[col];
  94. if (v < 1)
  95. continue;
  96. if (count[v] == 0)
  97. continue;
  98. if ((--count[v]) == 0) { /* then this is middle cell */
  99. n[v] = row;
  100. /* find row-center in this clump */
  101. left = right = col;
  102. /* left edge first */
  103. while (left > 0)
  104. if (cell_buf[--left] != v) {
  105. left++;
  106. break;
  107. }
  108. /* then right edge */
  109. while (right < cols)
  110. if (cell_buf[++right] != v) {
  111. right--;
  112. break;
  113. }
  114. e[v] = (left + right) / 2;
  115. }
  116. }
  117. }
  118. G_free(cell_buf);
  119. G_free(count);
  120. return (adjusted);
  121. } /* end of centroids() */