-- MANDELBROT SET GENERATOR -- DAVID HANLEY 11/03/1992 -- BUILDS A MAND-TREE, which contains, at its leaves, a colour. -- Tree is then traversed and points along with their colour are output module Main where a `par` b = b --1.3 a `seq` b = b -- MandTree - either contains a NS node with two subtrees -- contains a EW node with two subtrees -- a leaf holding a colour data MandTree = NS MandTree MandTree |EW MandTree MandTree |Leaf Colour -- Colour - colour of a point or rectangle type Colour = Int -- Point - 2-Tuple of integers, (Int1,Int2), -- where Int1 - x-coord of point, -- Int2 - y-coord of point. type Point = (Int,Int) -- MandTuple type MandTuple = (Int,Int,Int,Int,Colour) -- size: Size of window - Square 400x400 size :: Int size = 200 -- build_tree - Constructs mandtree build_tree :: Point -> Point -> MandTree build_tree p1@(x1,y1) p2@(x2,y2) = if rec_col /= -1 then -- All points in currnet rectangle are same colour Leaf rec_col else if split == "NS" then btns1 `par` (btns2 `seq` (NS btns1 btns2)) else btew1 `par` (btew2 `seq` (EW btew1 btew2)) where rec_col = check_perim p1 p2 split = if (x2-x1) >= (y2-y1) then -- x-axis longer, NS split "NS" else -- y-axis longer, EW split "EW" nsp1 = p1 nsp2 = (split_x, y2) nsp3 = (split_x+1, y1) nsp4 = p2 ewp1 = p1 ewp2 = (x2, split_y) ewp3 = (x1, split_y+1) ewp4 = p2 split_x = (x2+x1) `div` 2 split_y = (y2+y1) `div` 2 btns1 = build_tree nsp1 nsp2 btns2 = build_tree nsp3 nsp4 btew1 = build_tree ewp1 ewp2 btew2 = build_tree ewp3 ewp4 check_perim :: Point -> Point -> Colour check_perim p1@(x1,y1) p2@(x2,y2) = if (equalp p1 p2) then -- single point, just return its colour point_colour p1 else if corners_diff then -- check corners of current rectangle aren't same -1 else check_sides where corners_diff = if col1 == col2 then if col1 == col3 then if col1 == col4 then False else True else True else True col1 = point_colour p1 col2 = point_colour (x2,y1) col3 = point_colour (x2,y2) col4 = point_colour (x1,y2) check_sides = if (check_line (x1+1,y1) right) then if (check_line (x2,y1+1) down) then if (check_line (x2-1,y2) left) then if (check_line (x1,y2-1) up) then col1 else -1 else -1 else -1 else -1 where check_line pc@(xc,yc) pd@(xd,yd) = if finished then True else if (point_colour pc) /= col1 then False else check_line (xc+xd, yc+yd) pd where finished = if (equalp pd right) then (xc >= x2) else if (equalp pd down) then (yc <= y2) else if (equalp pd left) then (xc <= x1) else (yc >= y1) -- Evaluate the color index of a point -- This is the algoritm described on page 121 of "The Beauty of Fractals" -- The code is commented with the step numbers from the algorithm. -- point_colour - Calculates the dwell value of a point. point_colour :: Point -> Colour point_colour (x, y) = check_radius (np x) (nq y) 0 0.0 0.0 -- step1 -- check_radius - Calculates the escape radius of a point check_radius :: Float -> Float -> Int -> Float -> Float -> Colour check_radius p q k x y = if kp == num_cols then 0 -- step 3.ii else if r > (fromIntegral m ) then kp -- step 3.i else check_radius p q (kp) xn yn -- step 3.iii where xn = new_x x y p -- step 2 yn = new_y x y q -- step 2 r = radius xn yn -- step 3 kp = k + 1 -- step 2 -- M Set Properties. pmn :: Float -- Min p value. pmn = -2.25 pmx :: Float -- Max p value. pmx = 0.75 qmn :: Float -- Min q value. qmn = -1.5 qmx :: Float -- Max q value qmx = 1.5 m :: Int -- The escape radius, M. m = 20 --- Misc functions. equalp :: Point -> Point -> Bool equalp (x1, y1) (x2, y2) = ((x1 == x2) && (y1 == y2)) -- Set calculation functions. num_cols :: Int -- The number of colors; num_cols+1 = length (the_colors). num_cols = 26 delta_p :: Float -- The change in p per pixel. delta_p = (pmx - pmn) / fromIntegral (size - 1) delta_q :: Float -- The change in q per pixel. delta_q = (qmx - qmn) / fromIntegral (size - 1) np :: Int -> Float -- Calculate a new value of p. np x = pmn + (fromIntegral x) * delta_p nq :: Int -> Float -- Calculate a new value of q. nq y = qmn + (fromIntegral y) * delta_q radius :: Float -> Float -> Float -- Current radius of apoint (x,y). radius x y = x*x + y*y new_x :: Float -> Float -> Float -> Float -- iterate new x value. new_x x y p = x*x - y*y + p new_y :: Float -> Float -> Float -> Float -- iterate new y value. new_y x y q = 2.0 * x * y + q -- Misc. functions for traversing perimeter of rectangle. up,down,left,right :: Point up = ( 0,-1) down = ( 0, 1) left = (-1, 0) right = ( 1, 0) -- finite: forces evaluation of a tree finite :: MandTree -> Bool finite (Leaf c) = (c == c) finite (NS t1 t2) = (finite t1 && finite t2) finite (EW t1 t2) = (finite t1 && finite t2) main = if finite(build_tree (0,0) (size,size `div` 2)) then print "Success" else print "Fail"