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_v2(IImageRegion region) extends AbstractSteppable { |
7 | event newTrace(bool isHole); |
8 | event foundPoint(Pt p); |
9 | event traceDone; |
10 | |
11 | settable bool includeHoles = true; |
12 | |
13 | int w, x, y, dir; |
14 | Iterator<Pt> it; |
15 | byte[] reachedInDirections; // bits 0 to 3 |
16 | bool tracing; |
17 | int nTrace; // 1 for outline, 2+ for hole |
18 | |
19 | // directions (0 = right, 1 = down, 2 = left, 3 = up) |
20 | static Pt[] directions = { |
21 | pt(1, 0), pt(0, 1), pt(-1, 0), pt(0, -1) // r, d, l, u |
22 | }; |
23 | |
24 | void init { |
25 | var image = region.image(); |
26 | w = image.w(); |
27 | reachedInDirections = new byte[w*image.h()]; |
28 | it = region.pixelIterator(); |
29 | } |
30 | |
31 | public bool step() { |
32 | if (reachedInDirections == null) init(); |
33 | |
34 | if (tracing) |
35 | ret walkOnePixel(); |
36 | else |
37 | ret findFirstPixel(); |
38 | } |
39 | |
40 | bool walkOnePixel() { |
41 | int pos = y*w+x; |
42 | if ((reachedInDirections[pos] & (1 << dir)) != 0) { |
43 | traceDone(); |
44 | tracing = false; |
45 | ret includeHoles; |
46 | } |
47 | |
48 | reachedInDirections[pos] |= (byte) 1 << dir; |
49 | foundPoint(x, y); |
50 | |
51 | for (int turn = 3; turn <= 6; turn++) { // try left, straight, right, back |
52 | int newDir = (dir+turn) & 3; |
53 | Pt d = directions[newDir]; |
54 | int x2 = x+d.x, y2 = y+d.y; |
55 | bool b = region.contains(x2, y2); |
56 | ifdef RegionBorder_innerPoints_debug |
57 | printVars(+x, +y, +dir, +turn, +newDir, +x2, +y2, +b); |
58 | endifdef |
59 | if (b) { |
60 | x = x2; y = y2; dir = newDir; |
61 | true; |
62 | } |
63 | } |
64 | |
65 | true; // no black pixels found in any direction - region must be a single pixel |
66 | } |
67 | |
68 | bool findFirstPixel() { |
69 | // search for first border pixel |
70 | |
71 | if (!it.hasNext()) false; // done |
72 | Pt p = it.next(); |
73 | x = p.x; y = p.y; |
74 | |
75 | if (reachedInDirections[y*w+x] != 0) true; // seen pixel before |
76 | |
77 | // if pixel above is empty, walk to the right |
78 | if (!region.contains(x, y-1)) |
79 | ret true with startTrace(0); |
80 | |
81 | // if pixel on the left is empty, walk upwards |
82 | if (!region.contains(x-1, y)) |
83 | ret true with startTrace(3); |
84 | |
85 | // if pixel on the right is empty, walk downwards |
86 | if (!region.contains(x+1, y)) |
87 | ret true with startTrace(1); |
88 | |
89 | // if pixel below is empty, walk left |
90 | if (!region.contains(x, y+1)) |
91 | ret true with startTrace(2); |
92 | |
93 | // not a border pixel, continue search |
94 | true; |
95 | } |
96 | |
97 | void startTrace(int dir) { |
98 | this.dir = dir; |
99 | |
100 | // mark point reached from all directions in next step |
101 | reachedInDirections[y*w+x] = (byte) (15 & ~(1 << dir)); |
102 | |
103 | set tracing; |
104 | newTrace(++nTrace > 1); |
105 | } |
106 | |
107 | void foundPoint(int x, int y) { foundPoint(pt(x, y)); } |
108 | |
109 | // get all points as list |
110 | |
111 | simplyCached L<Pt> allPoints() { |
112 | new PtBuffer l; |
113 | onFoundPoint(p -> l.add(p)); |
114 | run(); |
115 | ret l; |
116 | } |
117 | |
118 | // get outline as OnePath |
119 | |
120 | simplyCached OnePath onePath() { |
121 | includeHoles(false); |
122 | ret new OnePath(allPoints(), true); |
123 | } |
124 | |
125 | // or as OnePathWithOrigin |
126 | |
127 | simplyCached OnePathWithOrigin onePathWithOrigin() { |
128 | includeHoles(false); |
129 | ret new OnePathWithOrigin(allPoints(), true); |
130 | } |
131 | |
132 | // for debugging |
133 | void runAndPrint { |
134 | onNewTrace(hole -> print(!hole ? "new outline" : "new hole")); |
135 | onTraceDone(-> print("traceDone")); |
136 | onFoundPoint(p -> print("foundPoint " + p)); |
137 | stepMaxWithStats(this, 10000); |
138 | } |
139 | |
140 | bool tracingHole() { ret nTrace > 1; } |
141 | } |
Began life as a copy of #1034656
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj
No comments. add comment
Snippet ID: | #1034966 |
Snippet name: | RegionBorder_innerPoints_v2 backup |
Eternal ID of this version: | #1034966/1 |
Text MD5: | 9bfd6f2269893dc5a1501dd1c370646f |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2022-03-18 22:15:10 |
Source code size: | 3741 bytes / 141 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 130 / 138 |
Referenced in: | [show references] |