(int startX, int startY, boolean fourConnected)
| 178 | * and not an inner hole. |
| 179 | */ |
| 180 | private boolean traceEdge(int startX, int startY, boolean fourConnected) { |
| 181 | // Let us name the crossings between 4 pixels vertices, then the |
| 182 | // vertex (x,y) marked with '+', is between pixels (x-1, y-1) and (x,y): |
| 183 | // |
| 184 | // pixel x-1 x |
| 185 | // y-1 | |
| 186 | // ----+---- |
| 187 | // y | |
| 188 | // |
| 189 | // The four principal directions are numbered such that the direction |
| 190 | // number * 90 degrees gives the angle in the mathematical sense; and |
| 191 | // the directions to the adjacent pixels (for inside(x,y,direction) are |
| 192 | // at (number * 90 - 45) degrees: |
| 193 | // walking pixel |
| 194 | // directions: 1 directions: 2 | 1 |
| 195 | // 2 + 0 ----+---- |
| 196 | // 3 3 | 0 |
| 197 | // |
| 198 | // Directions, like angles, are cyclic; direction -1 = direction 3, etc. |
| 199 | // |
| 200 | // The algorithm: We walk along the border, from one vertex to the next, |
| 201 | // with the outside pixels always being at the left-hand side. |
| 202 | // For 8-connected tracing, we always trying to turn left as much as |
| 203 | // possible, to encompass an area as large as possible. |
| 204 | // Thus, when walking in direction 1 (up, -y), we start looking |
| 205 | // at the pixel in direction 2; if it is inside, we proceed in this |
| 206 | // direction (left); otherwise we try with direction 1 (up); if pixel 1 |
| 207 | // is not inside, we must proceed in direction 0 (right). |
| 208 | // |
| 209 | // 2 | 1 (i=inside, o=outside) |
| 210 | // direction 2 < ---+---- > direction 0 |
| 211 | // o | i |
| 212 | // ^ direction 1 = up = starting direction |
| 213 | // |
| 214 | // For 4-connected pixels, we try to go right as much as possible: |
| 215 | // First try with pixel 1; if it is outside we go in direction 0 (right). |
| 216 | // Otherwise, we examine pixel 2; if it is outside, we go in |
| 217 | // direction 1 (up); otherwise in direction 2 (left). |
| 218 | // |
| 219 | // When moving a closed loop, 'direction' gets incremented or decremented |
| 220 | // by a total of 360 degrees (i.e., 4) for counterclockwise and clockwise |
| 221 | // loops respectively. As the inside pixels are at the right side, we have |
| 222 | // got an outline of inner pixels after a cw loop (direction decremented |
| 223 | // by 4). |
| 224 | // |
| 225 | npoints = 0; |
| 226 | xmin = width; |
| 227 | final int startDirection; |
| 228 | if (inside(startX,startY)) // inside at left, outside right |
| 229 | startDirection = 1; // starting in direction 1 = up |
| 230 | else { |
| 231 | startDirection = 3; // starting in direction 3 = down |
| 232 | startY++; // continue after the boundary that has direction 3 |
| 233 | } |
| 234 | int x = startX; |
| 235 | int y = startY; |
| 236 | int direction = startDirection; |
| 237 | do { |
no test coverage detected