Tuesday, December 15, 2015

the mandelbrot set

What programmer hasn't at some point written an implementation of Benoit Mandelbrot's great discovery, the most famous fractal in the world? Here's my own minimal version, with the simplest possible coloring scheme. To interact with it, just click any two points: the window will zoom in on the rectangle they define.
import Data.Complex (magnitude, Complex((:+)))
import Graphics.UI.SDL as SDL
(xres, yres) = (900, 750)
main = withInit [InitVideo] $ do
w <- setVideoMode xres yres 32 [NoFrame]
enableEvent SDLMouseMotion False
setCaption "Mandelbrot" "Mandelbrot"
zoom w 1 (-2, 1) (0.5, -1)
zoom w i (x,y) (s,t) = do
let r = area x s y t
render w r i
run w (i + 1) r (0,0)
render w r i = draw w . concat . f $ set i r
where
f = zipWith zip $ map (zip [0..] . repeat) [0..]
draw w cs = do
s <- createRGBSurface [] 1 1 32 0 0 0 0
mapM_ (draw s) cs
SDL.flip w
where
rgb n = div (floor $ min n 2 * 512) 2
rect (x,y) = Just $ Rect x y 1 1
draw s (p,n) = do fillRect s Nothing $ Pixel $ rgb n
blitSurface s Nothing w $ rect p
run w i (xs,ys) p@(x,y) = do
e <- pollEvent
case e of
KeyUp (Keysym SDLK_ESCAPE _ _) -> return ()
MouseButtonUp i j _ -> click $ f i j
_ -> run w i (xs,ys) p
where
f i j = (xs !! fromIntegral i, ys !! fromIntegral j)
click q
| p == (0,0) = run w i (xs,ys) q
| otherwise = zoom w i p q
------------------------------------------------------
area x x' y y' = ([t, t+a.. s], [u, u-b.. v])
where
(a,b) = ((s - t) / dx, (u - v) / dy)
(s,t) = (max x x', min x x')
(u,v) = (max y y', min y y')
(dx, dy) = (fromIntegral xres, fromIntegral yres)
set i (xs, ys) = [[f x y | x <- xs] | y <- ys]
where
f x = magnitude . g . (x :+)
g a = iterate ((+ a) . (^2)) 0 !! (i * 20)

No comments:

Post a Comment