Skip to content

Instantly share code, notes, and snippets.

@sordina
Created July 1, 2011 09:49
Show Gist options
  • Save sordina/1058190 to your computer and use it in GitHub Desktop.
Save sordina/1058190 to your computer and use it in GitHub Desktop.
Dragon Curve Image
{-
Plotting the dragon curve
=========================
Image Version
http://en.wikipedia.org/wiki/Lindenmayer_system
-}
import Control.Arrow
import Diagrams.AST hiding (X,Y)
import Data.List
import Control.Monad
-- Should be 90 degrees, but just playing with it to see what happenes
angle = pi/2.5
data Direction = X | Y | F | P | N deriving (Show, Eq)
dims = (270,140)
-- Magic number: Itteration of the Lindenmayer transform
main = forM_ [1..16] draw
draw :: Int -> IO ()
draw n = render ("dragon_" ++ show n ++ ".png") $ normalise ((fromIntegral *** fromIntegral) dims) $ points $ dragon n
render :: String -> [(Double,Double)] -> IO ()
render fn = outputImage fn 800 400 . Modifier (Changes [LineColor (RGBA 0.1 0.2 0.3 1), LineWidth 0.8, Align C, Pad 1.1]) . Shape . Path Open . Points
normalise :: (Double,Double) -> [(Double,Double)] -> [(Double,Double)]
normalise (w,h) l = map ((\x -> x * w / maxx) *** (\y -> y * h / maxy)) l'
where
minx = minimum $ map fst l
miny = minimum $ map snd l
l' = map (subtract minx *** subtract miny) l
maxx = maximum $ map fst l'
maxy = maximum $ map snd l'
points :: [Direction] -> [(Double,Double)]
points l = snd $ foldl' foo (0,[(0,0)]) l
where
foo :: (Double,[(Double,Double)]) -> Direction -> (Double,[(Double,Double)])
foo (a, xs) P = (a + angle, xs)
foo (a, xs) N = (a - angle, xs)
foo (a, xs@((x,y):_)) F = (a, (x + cos a, y + sin a):xs)
foo i _ = i
dragon :: Int -> [Direction]
dragon n = filter (`elem` [F,P,N]) (dragons !! n)
dragons = iterate (concatMap substitute) [F,X]
substitute X = [X,P,Y,F,P]
substitute Y = [N,F,X,N,Y]
substitute x = [x]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment