/
line.jl
140 lines (130 loc) · 3.92 KB
/
line.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
# Line drawing algorithm
"""
drawline(func::Function, ci1::CartesianIndex{2}, ci2::CartesianIndex{2}, eachstep::Bool=false)
At each step along the line from `ci1` to `ci2` call `func` with a single argument, the row, column coordinates
of the pixel as a `Tuple{Int, Int}`.
If `eachstep=true` then `func` is called once when the row changes and once when the column changes. When
`eachstep=false` then `func` is called less frequently and both row and col may change between calls.
"""
function drawline(
func::Function,
ci1::CartesianIndex{2},
ci2::CartesianIndex{2},
eachstep::Bool = false,
)
r, c = ci1.I
dr, dc = -abs(ci2.I[1] - ci1.I[1]), abs(ci2.I[2] - ci1.I[2])
sr, sc = ci1.I[1] < ci2.I[1] ? 1 : -1, ci1.I[2] < ci2.I[2] ? 1 : -1
err = dc + dr
func(ci1.I)
while !((c == ci2.I[2]) && (r == ci2.I[1]))
e2 = 2 * err
if e2 >= dr
err += dr
c += sc
if eachstep
func((r, c))
end
end
if e2 <= dc
err += dc
r += sr
if eachstep
func((r, c))
end
end
if !eachstep
func((r, c))
end
end
end
"""
drawray(
func::Function, # returns Bool
ci1::CartesianIndex{2}, # starting point
ci2::CartesianIndex{2}, # towards this point
bounds::CartesianIndices{2, Tuple{Base.OneTo{Int64}, Base.OneTo{Int64}}}, # stay within
eachstep::Bool=false
)
function drawray(
func::Function,
ci1::CartesianIndex{2},
ci2::CartesianIndex{2},
eachstep::Bool = false,
)
Draw a ray starting at `ci1` towards `ci2` and call `func` with a single argument, the row, column coordinates
of the pixel as a `Tuple{Int, Int}`. `func` must return a `Bool` - true to continue drawing the ray and false to
stop drawing the ray. The first version checks the bounds each step and the second doesn't.
If `eachstep=true` then `func` is called once when the row changes and once when the column changes. When
`eachstep=false` then `func` is called less frequently and both row and col may change between calls.
"""
function drawray(
func::Function,
ci1::CartesianIndex{2},
ci2::CartesianIndex{2},
bounds::CartesianIndices{2, Tuple{Vararg{OrdinalRange{Int64, Int64}, 2}}},
eachstep::Bool = false,
)
r, c = ci1.I
dr, dc = -abs(ci2.I[1] - ci1.I[1]), abs(ci2.I[2] - ci1.I[2])
sr, sc = ci1.I[1] < ci2.I[1] ? 1 : -1, ci1.I[2] < ci2.I[2] ? 1 : -1
err = dc + dr
inb(r,c) = ((r in bounds.indices[1]) && (c in bounds.indices[2]))
if !(inb(r,c) && func((r,c)))
return nothing
end
while true
e2 = 2 * err
if e2 >= dr
err += dr
c += sc
if eachstep && !(inb(r,c) && func((r, c)))
return nothing
end
end
if e2 <= dc
err += dc
r += sr
if eachstep && !(inb(r,c) && func((r, c)))
return nothing
end
end
if (!eachstep) && !(inb(r,c) && func((r, c)))
return nothing
end
end
end
function drawray(
func::Function,
ci1::CartesianIndex{2},
ci2::CartesianIndex{2},
eachstep::Bool = false,
)
r, c = ci1.I
dr, dc = -abs(ci2.I[1] - ci1.I[1]), abs(ci2.I[2] - ci1.I[2])
sr, sc = ci1.I[1] < ci2.I[1] ? 1 : -1, ci1.I[2] < ci2.I[2] ? 1 : -1
err = dc + dr
if !func((r,c))
return nothing
end
while true
e2 = 2 * err
if e2 >= dr
err += dr
c += sc
if eachstep && !func((r, c))
return nothing
end
end
if e2 <= dc
err += dc
r += sr
if eachstep && !func((r, c))
return nothing
end
end
if (!eachstep) && !func((r, c))
return nothing
end
end
end