import Data.Complex import Data.Ratio import System.Environment (getArgs) origin :: Complex Double origin = 0 one :: Complex Double one = 1 type Diagram = (Complex Double, Complex Double, String) diagram :: [Rational] -> Diagram diagram [] = (-one, origin, circle origin 0.1 "white") diagram (q:qs) = let (dir, point, l) = diagram qs m = numerator q n = denominator q center = point + dir point' = center + dir' dir' = -dir * mkPolar (0.5 ** (1 / fromIntegral n)) (2 * pi * fromRational q) in (dir', point', circle center 0.05 "black" `atop` circle point 0.1 "white" `atop` l `atop` line point center `atop` line center point' `atop` atops [ line center point'' | i <- [2 .. n - 1] , let r = fromIntegral (n - (i - 1)) / fromIntegral n , let t = fromIntegral (i * m) / fromIntegral n , let point'' = center + dir' * mkPolar (0.5 ** r) (-2 * pi * t) ]) atop :: String -> String -> String a `atop` b = b ++ a atops :: [String] -> String atops = foldr atop "" sim :: Complex Double -> Complex Double -> Double -> Diagram -> String sim o0 o1 s (_, i0, a) = translate o1 . scale (if s == 0 then o1 - o0 else (o1 - o0) / mkPolar s (phase i0)) $ a sim2 :: Double -> Double -> Diagram -> String sim2 d s a = sim (d*1/2:+d) (d:+d) s a ++ sim (d*3/2:+d) (d:+d) s a translate :: Complex Double -> String -> String translate (x :+ y) a = "" ++ a ++ "" scale z a = "" ++ a ++ "" circle :: Complex Double -> Double -> String -> String circle (cx:+cy) r fill = "" line :: Complex Double -> Complex Double -> String line (x1:+y1) (x2:+y2) = "" svg :: Double -> Diagram -> String svg s a = "" ++ "" ++ "" ++ sim2 512 s a ++ "" ++ "" mandelbrot :: String mandelbrot = "" ++ "" ++ "" ++ js size0 center0 [] ++ "" ++ "" where minSize = 4 size0 = 2048 center0 = 4096 :+ 4096 -- draw a Julia set j r (x:+y) qs = sim ((x-r'):+y) (x:+y) s a ++ sim ((x+r'):+y) (x:+y) s a where a = diagram qs s = fromIntegral (length qs) r' = r / 2 -- draw tree of Julia sets js size1 center1 qs = circle center1 size1 "silver" ++ j size1 center1 qs ++ concat [ js size2 center2 qs' | d <- [1..floor (sqrt (size1 / minSize))] , let size2 = (size1 / fromIntegral d^2) , n <- [1 .. d - 1] , let q = n % d , denominator q == d , let qs' = qs ++ [if null qs then 1 - q else q] , let center2 = center1 + (-1)^length qs' * mkPolar (size1 + size2) (pi - 2 * pi * fromRational (sum qs')) ] replaceSlash :: Char -> Char replaceSlash '/' = '%' replaceSlash c = c main :: IO () main = do args <- getArgs if args == ["M"] then putStrLn mandelbrot else putStrLn $ svg (fromIntegral (length args)) $ diagram $ map (read . map replaceSlash) $ args