Skip to content

Instantly share code, notes, and snippets.

@sharpTrick
Created December 6, 2021 23:28
Show Gist options
  • Save sharpTrick/fa9767220e8c73d61e4c192ddc70f6c7 to your computer and use it in GitHub Desktop.
Save sharpTrick/fa9767220e8c73d61e4c192ddc70f6c7 to your computer and use it in GitHub Desktop.
To create a smoothly interpolated Mandelbrot fractal: https://youtu.be/qmXgUyHy42g
module InterpolatedMandelbrot
using GLMakie
# function mandelbrot_func(z::ComplexF64, c::ComplexF64=0.0+0.0im)::ComplexF64
# z^2 + c
# end
const N = 32
function plot_dots!(fig, ax)
c_node = Node(0.0+0im)
ca_node = Node(zeros(ComplexF64, N))
on(c_node) do c
ca_node[][1] = c
z=c
for i = 2:N
ca_node[][i] = z = z^2 + c
end
notify(ca_node)
end
m_node = Node(zeros(Float64, N, 2))
on(ca_node) do ca
m_node[][1:N,1] .= real.(ca)
m_node[][1:N,2] .= imag.(ca)
notify(m_node)
end
on(events(fig).mouseposition) do event
pos = mouseposition(ax.scene)
c_node[] = pos[1] + pos[2] * im
end
lines!(ax, m_node)
scatter!(ax, m_node)
display(fig)
fig, ax
end
# const X=3775
# const Y=2098
function plot_img!(fig, ax)
X = ax.scene.px_area[].widths[1]
Y = ax.scene.px_area[].widths[2]
xs = Node((collect(1:X) ./ Y) .* 2.25 .- 1.5*X/Y)
ys = Node((collect(1:Y) ./ Y) .* 2.25 .- 2.25/2)
cs = [xs[][i] + ys[][j] * im for i=1:X, j=1:Y]
zs = zeros(ComplexF64,X,Y)
vs = zeros(ComplexF64,X,Y)
ifs = isfinite.(zs)
ds = zeros(Float64,X,Y)
ms = zeros(Float64,X,Y)
as = zeros(Float64,X,Y)
rs = zeros(Float64,X,Y)
gs = zeros(Float64,X,Y)
bs = zeros(Float64,X,Y)
img_node = Node(zeros(RGBf0,X,Y))
prev_iteration = 0
iteration_node = Node(0.0)
on(iteration_node) do iteration
while prev_iteration < floor(Int64, iteration)
# ifs .= isfinite.(zs)
# ds[ifs] .= prev_iteration
zs .= zs.^2 .+ cs
prev_iteration = prev_iteration + 1
end
iteration_part = iteration % 1
# iteration_part = sin(iteration_part*pi/2)^4 # smoothly tick like a clock
zp = clamp(iteration_part*2, 0, 1)
ca = clamp(iteration_part*2-1, 0,1)
zp = sin(zp*pi/2)^2 # smoothly tick like a clock
ca = sin(ca*pi/2)^2 # smoothly tick like a clock
vs .= zs.^(1+zp) .+ (cs .* ca)
ifs .= isfinite.(vs)
ds[ifs] .= prev_iteration + zp
ms[ifs] .= exp.(-1 .* abs.(log.(abs.(vs[ifs]))))
as[ifs] .= angle.(vs[ifs])
rs[ifs] .= cos.(as[ifs]./2).^2
gs[ifs] .= cos.(as[ifs]./2 .+ pi/3).^2
bs[ifs] .= cos.(as[ifs]./2 .+ 2*pi/3).^2
img_node[][ifs] .= ms[ifs] .* RGBf0.(rs[ifs], gs[ifs], bs[ifs])
img_node[][.!ifs] .= RGBf0.(1 .- log.(ds[.!ifs]) ./ log(iteration))
notify(img_node)
end
on(ax.finallimits) do fl
xs[] .= (collect(1:X) ./ X) .* fl.widths[1] .+ fl.origin[1]
ys[] .= (collect(1:Y) ./ Y) .* fl.widths[2] .+ fl.origin[2]
for i=1:X, j=1:Y
cs[i,j] = xs[][i] + ys[][j] * im
end
fill!(zs, 0)
fill!(ds, 0)
notify(xs)
notify(ys)
prev_iteration = 0
iteration_node[] = 0
end
image!(xs, ys, img_node)
display(fig)
fig, ax, iteration_node
end
const W=1920
const H=1080
function plot()
set_theme!(theme_dark())
fig = Figure(resolution = (W, H))
ax = fig[1, 1] = Axis(fig)
limits!(ax, -1.5,0.5,-1,W)
fig,ax, iteration_node = plot_img!(fig, ax)
# Uncomment out for dots under cursor
# plot_dots!(fig, ax)
display(fig)
fig, ax, iteration_node
end
# To generate plot:
# fig, ax, itno = FractalFun.plot()
# To run live animation:
# for _=1:256; itno[]=itno[]+1/32; sleep(1/24); end
# To make video:
# record(fig, "fractal.mkv", 0.0:1/64:64.0; framerate=24) do it
# itno[] = it
# end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment