| 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 |
|
|---|
| 22 | int centroids(int fd, /* File descriptor of map layer to process */
|
|---|
| 23 | /* This file is assumed to be opened before calling */
|
|---|
| 24 | /* centroids. */
|
|---|
| 25 | unsigned long *e, unsigned long *n, /* Pointers to arrays at least max+1 long */
|
|---|
| 26 | int method, /* 0, 1, or 2; see above. */
|
|---|
| 27 | int max)
|
|---|
| 28 | { /* Highest positive cat number in map layer */
|
|---|
| 29 | CELL *cell_buf, v;
|
|---|
| 30 | int i, adjusted, numb, left, right;
|
|---|
| 31 | long int *count;
|
|---|
| 32 | int row, col, rows, cols;
|
|---|
| 33 |
|
|---|
| 34 | adjusted = 0;
|
|---|
| 35 |
|
|---|
| 36 | cell_buf = Rast_allocate_c_buf();
|
|---|
| 37 | /* space to accumulate counts */
|
|---|
| 38 | count = (long int *)G_malloc((max + 1) * sizeof(long int));
|
|---|
| 39 |
|
|---|
| 40 | /* zero the count totals */
|
|---|
| 41 | for (i = 1; i <= max; i++) {
|
|---|
| 42 | count[i] = 0;
|
|---|
| 43 | e[i] = 0;
|
|---|
| 44 | n[i] = 0;
|
|---|
| 45 | }
|
|---|
| 46 |
|
|---|
| 47 | /* do rows and columns through window and mask */
|
|---|
| 48 | /* to do counting */
|
|---|
| 49 | rows = Rast_window_rows();
|
|---|
| 50 | cols = Rast_window_cols();
|
|---|
| 51 | for (row = 0; row < rows; row++) {
|
|---|
| 52 | Rast_get_c_row(fd, cell_buf, row); /* get a row */
|
|---|
| 53 | for (col = 0; col < cols; col++) {
|
|---|
| 54 | v = cell_buf[col]; /* next cell value in row */
|
|---|
| 55 | if (v < 1)
|
|---|
| 56 | continue; /* can't handle 0 or - values */
|
|---|
| 57 | count[v]++;
|
|---|
| 58 | if (method > 0) { /* acccumulate row, col weights */
|
|---|
| 59 | e[v] += col;
|
|---|
| 60 | n[v] += row;
|
|---|
| 61 | }
|
|---|
| 62 | }
|
|---|
| 63 | }
|
|---|
| 64 |
|
|---|
| 65 | /* compute averages */
|
|---|
| 66 | if (method > 0)
|
|---|
| 67 | for (i = 1; i <= max; i++) {
|
|---|
| 68 | if (count[i]) {
|
|---|
| 69 | numb = count[i];
|
|---|
| 70 | e[i] /= numb;
|
|---|
| 71 | n[i] /= numb;
|
|---|
| 72 | }
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | /* substitute 'count' centroids for 'weighted' ones, if necessary */
|
|---|
| 76 | if (method == 1) {
|
|---|
| 77 | for (i = 1; i <= max; i++) {
|
|---|
| 78 | if (count[i]) {
|
|---|
| 79 | row = n[i];
|
|---|
| 80 | col = e[i];
|
|---|
| 81 | /* get cell at row,col */
|
|---|
| 82 | Rast_get_c_row(fd, cell_buf, row);
|
|---|
| 83 | v = cell_buf[col];
|
|---|
| 84 | if (v > 0) {
|
|---|
| 85 | if (v == i)
|
|---|
| 86 | count[i] = 0; /* weighted is acceptable */
|
|---|
| 87 | else
|
|---|
| 88 | adjusted++;
|
|---|
| 89 | }
|
|---|
| 90 | }
|
|---|
| 91 | }
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | /* compute middle cell; zeros will remain zeros */
|
|---|
| 95 | for (i = 1; i <= max; i++)
|
|---|
| 96 | count[i] = (count[i] + 1) / 2;
|
|---|
| 97 |
|
|---|
| 98 | /* go through map again */
|
|---|
| 99 | for (row = 0; row < rows; row++) {
|
|---|
| 100 | Rast_get_c_row(fd, cell_buf, row);
|
|---|
| 101 | for (col = 0; col < cols; col++) {
|
|---|
| 102 | v = cell_buf[col];
|
|---|
| 103 | if (v < 1)
|
|---|
| 104 | continue;
|
|---|
| 105 | if (count[v] == 0)
|
|---|
| 106 | continue;
|
|---|
| 107 | if ((--count[v]) == 0) { /* then this is middle cell */
|
|---|
| 108 | n[v] = row;
|
|---|
| 109 | /* find row-center in this clump */
|
|---|
| 110 | left = right = col;
|
|---|
| 111 | /* left edge first */
|
|---|
| 112 | while (left > 0)
|
|---|
| 113 | if (cell_buf[--left] != v) {
|
|---|
| 114 | left++;
|
|---|
| 115 | break;
|
|---|
| 116 | }
|
|---|
| 117 | /* then right edge */
|
|---|
| 118 | while (right < cols)
|
|---|
| 119 | if (cell_buf[++right] != v) {
|
|---|
| 120 | right--;
|
|---|
| 121 | break;
|
|---|
| 122 | }
|
|---|
| 123 | e[v] = (left + right) / 2;
|
|---|
| 124 | }
|
|---|
| 125 | }
|
|---|
| 126 | }
|
|---|
| 127 | G_free(cell_buf);
|
|---|
| 128 | G_free(count);
|
|---|
| 129 | return (adjusted);
|
|---|
| 130 | } /* end of centroids() */
|
|---|