Libraryless. Click here for Pure Java version (10649L/59K).
1 | // both the outer outline and the outline of a hole are called a "trace" |
2 | // should return outer outline first and then outline of holes |
3 | |
4 | // seems to return first point again at the end sometimes |
5 | |
6 | srecord noeq RegionBorder_innerPoints_withDiagonals(IImageRegion region) extends AbstractBorderTracer { |
7 | Rect bounds; // region bounds |
8 | int x, y; |
9 | int dir; // current direction (1 to 8) |
10 | Iterator<Pt> it; |
11 | byte[] reachedInDirections; // bits 0 to 7 |
12 | bool tracing; |
13 | int nTrace; // 1 for outline, 2+ for hole |
14 | |
15 | void init { |
16 | bounds = region.bounds(); |
17 | reachedInDirections = new byte[area(bounds)]; |
18 | it = region.pixelIterator(); |
19 | } |
20 | |
21 | public bool step() { |
22 | if (reachedInDirections == null) init(); |
23 | |
24 | if (tracing) |
25 | ret walkOnePixel(); |
26 | else |
27 | ret findFirstPixel(); |
28 | } |
29 | |
30 | bool walkOnePixel() { |
31 | int posInBounds = (y-bounds.y)*bounds.w+x-bounds.x; |
32 | if ((reachedInDirections[posInBounds] & (1 << (dir-1))) != 0) { |
33 | traceDone(); |
34 | tracing = false; |
35 | ret includeHoles; |
36 | } |
37 | |
38 | reachedInDirections[posInBounds] |= (byte) 1 << (dir-1); |
39 | printVars ifdef RegionBorder_innerPoints_debug("foundPoint", +x, +y); |
40 | foundPoint(x, y); |
41 | |
42 | // try left, half left, straight, half right, right, back |
43 | for (int turn = -2; turn <= 4; turn++) { |
44 | int newDir = modRange_incl(dir+turn, 1, 8); |
45 | Pt d = onePathDirection(newDir); |
46 | int x2 = x+d.x, y2 = y+d.y; |
47 | bool b = region.contains(x2, y2); |
48 | if (b) { |
49 | printVars ifdef RegionBorder_innerPoints_debug(+x, +y, +dir, +turn, +newDir, +d, +x2, +y2, +b); |
50 | x = x2; y = y2; dir = newDir; |
51 | true; |
52 | } |
53 | } |
54 | |
55 | print ifdef RegionBorder_innerPoints_debug("fall through"); |
56 | true; // no black pixels found in any direction - region must be a single pixel |
57 | } |
58 | |
59 | bool findFirstPixel() { |
60 | // search for first border pixel |
61 | |
62 | if (!it.hasNext()) false; // done |
63 | Pt p = it.next(); |
64 | x = p.x; y = p.y; |
65 | |
66 | int posInBounds = (y-bounds.y)*bounds.w+x-bounds.x; |
67 | if (reachedInDirections[posInBounds] != 0) true; // seen pixel before |
68 | |
69 | // if pixel above is empty, walk to the right |
70 | if (!region.contains(x, y-1)) |
71 | ret true with startTrace(4); |
72 | |
73 | // if pixel on the left is empty, walk upwards |
74 | if (!region.contains(x-1, y)) |
75 | ret true with startTrace(2); |
76 | |
77 | // if pixel on the right is empty, walk downwards |
78 | if (!region.contains(x+1, y)) |
79 | ret true with startTrace(6); |
80 | |
81 | // if pixel below is empty, walk left |
82 | if (!region.contains(x, y+1)) |
83 | ret true with startTrace(8); |
84 | |
85 | // not a border pixel, continue search |
86 | true; |
87 | } |
88 | |
89 | void startTrace(int dir) { |
90 | this.dir = dir; |
91 | |
92 | // mark point reached from all directions in next step |
93 | int posInBounds = (y-bounds.y)*bounds.w+x-bounds.x; |
94 | reachedInDirections[posInBounds] = (byte) ~(1 << (dir-1)); |
95 | |
96 | set tracing; |
97 | printVars ifdef RegionBorder_innerPoints_debug("startTrace", +dir, +x, +y); |
98 | newTrace(++nTrace > 1); |
99 | } |
100 | |
101 | void foundPoint(int x, int y) { foundPoint(pt(x, y)); } |
102 | |
103 | // get all points as list |
104 | |
105 | simplyCached L<Pt> allPoints() { |
106 | new PtBuffer l; |
107 | onFoundPoint(p -> l.add(p)); |
108 | run(); |
109 | ret l; |
110 | } |
111 | |
112 | // get outline as OnePath |
113 | |
114 | simplyCached OnePath onePath() { |
115 | includeHoles(false); |
116 | ret new OnePath(allPoints(), true); |
117 | } |
118 | |
119 | // or as OnePathWithOrigin |
120 | |
121 | simplyCached OnePathWithOrigin onePathWithOrigin() { |
122 | includeHoles(false); |
123 | ret new OnePathWithOrigin(allPoints(), true); |
124 | } |
125 | |
126 | // for debugging |
127 | void runAndPrint { |
128 | onNewTrace(hole -> print(!hole ? "new outline" : "new hole")); |
129 | onTraceDone(-> print("traceDone")); |
130 | onFoundPoint(p -> print("foundPoint " + p)); |
131 | stepMaxWithStats(this, 10000); |
132 | } |
133 | |
134 | bool tracingHole() { ret nTrace > 1; } |
135 | } |
Began life as a copy of #1034656
download show line numbers debug dex old transpilations
Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1034976 |
Snippet name: | RegionBorder_innerPoints_withDiagonals - find region outline, also allowing diagonal steps |
Eternal ID of this version: | #1034976/11 |
Text MD5: | 2d7fe2822d9d9b5ff229f646f3ef860a |
Transpilation MD5: | 95b952eb4cb32fc7f3613e6d2377646e |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-04-28 16:52:53 |
Source code size: | 3953 bytes / 135 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 189 / 276 |
Version history: | 10 change(s) |
Referenced in: | [show references] |