/
tupper.jl
158 lines (134 loc) · 4.41 KB
/
tupper.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
## This kinda follows the algorithm laid out in
## http://www.dgp.toronto.edu/people/mooncake/papers/SIGGRAPH2001_Tupper.pdf
## the paper is much more thorough
## Helper function to find initial partition into squares
function fill_bottom(W,H)
k = min(floor(Integer,log2(W)), floor(Integer, log2(H)))
rects = Any[] # Array{Int,1}[] #
## fill in
w,h = 0, 2^k
while (W - w) >= 2^k
push!(rects, [w+0, w+2^k, 0, 2^k])
w = w + 2^k
end
j= k - 1
while j > 0
if (W - w) >= 2^j
for i in 1:2^(k-j)
push!(rects, [w+0, w+2^j, (i-1)*2^j, i*2^j])
end
w = w + 2^j
end
j = j - 1
end
rects, h
end
## Helper function to break a rectangle into squares of size 2^j x 2^j
function break_into_squares(W, H)
rects = Any[] # Array{Int,1}[] #
offset = 0
while H - offset > 0
nrects, h = fill_bottom(W, H-offset)
nrects = map(u -> [0,0,offset, offset] + u, nrects)
append!(rects, nrects)
offset = offset + h
end
rects
end
"""
Main algorithm of Tupper.
Break region into square regions
for each square region, subdivide into 4 regions. For each check if there is no solution, if so add to white. Otherwise, refine the region by repeating until we can't subdivide
At that point, check each pixel-by-pixel region for possible values.
Return red, black, and white vectors of Regions.
"""
function GRAPH(r, L, R, B, T, W, H)
rects = break_into_squares(W, H)
k = min(floor(Integer,log2(W)), floor(Integer,log2(H))) # largest square is size 2^k x 2^k
reds = [Region(OInterval(u[1], u[2]), OInterval(u[3], u[4])) for u in rects]
sizehint!(reds, W)
red = Region[] # 1-pixel red, can't decide via check_continuity
black = Region[]
white = Region[]
while (k >= 0) & (length(reds) > 0)
reds = RefinePixels(r, reds, L, R, B, T, W, H, black, white, red)
k = k - 1
end
red, black, white
end
## Refine the region
function RefinePixels(r, U_k, L, R, B, T, W, H, black, white, red)
## Uk_1 a refinement of U_k which hold red regions
Uk_1 = Region[]
for u in U_k
out = compute(r, u, L, R, B, T, W, H)
if out == TRUE
push!(black, u)
elseif out == FALSE
push!(white, u)
else
## subdivide and call again if possible,
x = u.x.val; y = u.y.val
dx, dy = diam(x), diam(y)
if (dx > 1) & (dy > 1)
hx = div(dx,2); hy = div(dy,2)
for i in 0:1, j in 0:1
uij = Region(OInterval(x.lo + i*hx, x.lo + (i+1)*hx),
OInterval(y.lo + j*hy, y.lo + (j+1)*hy))
push!(Uk_1, uij)
end
else
## these are red with diameter 1, could be white or black
val = check_continuity(r, u, L, R, B, T, W, H)
if val == TRUE
push!(black, u)
elseif val == FALSE
push!(white, u)
else
push!(red, u)
end
end
end
end
Uk_1
end
## for 1-pixel squares, check NaN and continuity
## Return TRUE (Black), FALSE (white) or MAYBE (red)
function check_continuity(r::Pred, u, L, R, B, T, W, H)
fxy = compute_fxy(r, u, L, R, B, T, W, H)
## check for NaN
if isempty(fxy.val)
return(FALSE)
end
if (fxy.def == FALSE) || (fxy.def == MAYBE)
return(FALSE)
end
## now check continuity,
val = FALSE
if (fxy.cont == TRUE) && ((r.op === ==) || (r.op === <=) || (r.op === >=))
## use intermediate value theorem here
val = val | cross_zero(r, u, L, R, B, T, W, H)
end
## Now check for inequalities
ineqs = [<, <= , ≤, ≶, ≷, ≥, >=, >]
if (fxy.def == TRUE) && any([r.op === op for op in ineqs])
## just check points
val = val | check_inequality(r, u, L, R, B, T, W, H)
end
## What to do if fxy.cont !== TRUE...
default = MAYBE
if val == MAYBE
return(default)
else
return(val)
end
end
## Return TRUE, FALSE or MAYBE for predicates
function check_continuity(rs::Preds, u, L, R, B, T, W, H)
vals = map(r -> check_continuity(r, u, L, R, B, T, W, H), rs.ps)
val = popfirst!(vals)
for i in 1:length(rs.ops)
val = rs.ops[i](val, vals[i])
end
val
end