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
|
using Tk
using Images
using ImageView
using Color
type FractalCanvas
c::Canvas
f::FractalExplorer.Fractal
image::Array{HSV{Float64}, 2}
function FractalCanvas(c::Canvas, bb::Base.Graphics.BoundingBox, make_c::Function, step::Function; rref=RemoteRef())
winsize = tuple((get_size(c) * 2)...)
f = FractalExplorer.Fractal{Float64}(winsize, bb, make_c, step)
image = [ HSV(0, 0, 0) for y=1:winsize[2], x=1:winsize[1] ]
fc = new(c, f, image)
c.draw = function(x)
props = Dict()
img2 = ImageView.ImageSlice2d(fc.image, props)
imgc = ImageView.ImageCanvas(ImageView.cairo_format(fc.image), props)
imgc.c = fc.c
ImageView.allocate_surface!(imgc, winsize[1], winsize[2])
ImageView.rerender(imgc, img2)
ImageView.resize(imgc, img2)
end
bind(c, "<Double-Button-1>", function(path,x,y)
put!(rref, true)
fractal(c, make_c, step, false)
end)
c.mouse.button1press = function(c, x, y)
function rubberband_end(c, bb)
(size_x, size_y) = tuple((get_size(c) * 2)...)
win_aspect_ratio = size_x / size_y
box_aspect_ratio = (bb.xmax - bb.xmin) / (bb.ymax - bb.ymin)
line_x = linspace(fc.f.bb.xmin, fc.f.bb.xmax, size_x)
line_y = linspace(fc.f.bb.ymin, fc.f.bb.ymax, size_y)
plane = [ (x, y) for x=line_x, y=line_y ]
if box_aspect_ratio > win_aspect_ratio
xmin = plane[bb.xmin, bb.ymin][1]
xmax = plane[bb.xmax, bb.ymax][1]
ymin = plane[bb.xmin, bb.ymin][2]
ymax = ymin + (xmax - xmin)
else
xmin = plane[bb.xmin, bb.ymin][1]
ymin = plane[bb.xmin, bb.ymin][2]
ymax = plane[bb.xmax, bb.ymax][2]
xmax = xmin + (ymax - ymin)
end
bb = Base.Graphics.BoundingBox(xmin, xmax, ymin, ymax)
put!(rref, true)
fractal(c, make_c, step, false, bb)
end
ImageView.rubberband_start(c, x, y, rubberband_end)
end
return fc
end
end
mandelbrot(fc::FractalCanvas) = mandelbrot(fc.c)
function mandelbrot(canvas::Canvas = createwindow())
return fractal(canvas, z -> z, (z, c) -> z.^2 + c)
end
julia(fc::FractalCanvas, c = 0) = julia(fc.c, c)
function julia(canvas::Canvas = createwindow(), c::Union(Number, Array{Number, 2}) = 0)
return fractal(canvas, z -> c, (z, c) -> z.^2 + c)
end
fractal(make_c, step) = fractal(createwindow(), make_c, step)
fractal(fc::FractalCanvas, make_c, step) = fractal(fc.c, make_c, step)
function fractal(canvas::Canvas, make_c::Function, step::Function, should_wait=!isinteractive(), bb=Base.Graphics.BoundingBox(-2.0, 2.0, -2.0, 2.0))
rref = RemoteRef()
fc = FractalCanvas(canvas, bb, make_c, step, rref=rref)
saw_some_pixels = false
for i in 1:1000
FractalExplorer.step(fc.f)
diverging_pixels = (abs(fc.f.z) .> 2)
new_pixels = diverging_pixels & (fc.image .== HSV(0, 0, 0))
fc.image[new_pixels] = HSV(i * 4, 1, 1)
redraw(fc)
if isready(rref)
break
end
if saw_some_pixels && length(find(new_pixels)) <= 1
break
end
if length(find(diverging_pixels)) > 0
saw_some_pixels = true
end
end
if should_wait
cv = Condition()
win = Tk.toplevel(fc.c)
bind(win, "<Destroy>", e->notify(cv))
wait(cv)
end
return fc
end
function createwindow(winsize::(Integer, Integer) = (640, 480))
win = Toplevel("FractalExplorer", winsize[1], winsize[2], false)
frame = Frame(win)
pack(frame, expand=true, fill="both")
canvas = Canvas(frame, winsize[1], winsize[2])
pack(canvas, expand=true, fill="both")
set_visible(win, true)
# XXX this is needed because not calling view before get_size causes things
# to fail for some reason? it shouldn't be necessary otherwise
view(canvas, [ HSV(0, 0, 0) for y=1:winsize[2], x=1:winsize[1] ], interactive=false)
return canvas
end
function redraw(fc::FractalCanvas)
return view(fc.c, fc.image, interactive=false)
end
|