A Mandelbrot set renderer implemented in Haskell, outputs a farbfeld image.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mandel.hs 2.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. {-# LANGUAGE CPP #-}
  2. #define IN_COLOUR [0x2000, 0x1c00, 0x1800, 0xffff]
  3. #define ITER_N 200
  4. import Data.Complex
  5. import Data.Word
  6. import Data.ByteString.Builder
  7. import System.Environment
  8. import qualified Data.ByteString.Lazy as B
  9. colours :: [[Word16]]
  10. colours = [ [0xb300, 0x4800, 0x4800, 0xffff]
  11. , [0xb300, 0x7d00, 0x4800, 0xffff]
  12. , [0xb300, 0xb300, 0x4800, 0xffff]
  13. , [0x7d00, 0xb300, 0x4800, 0xffff]
  14. , [0x4800, 0xb300, 0x4800, 0xffff]
  15. , [0x4800, 0xb300, 0x7d00, 0xffff]
  16. , [0x4800, 0xb300, 0xb300, 0xffff]
  17. , [0x4800, 0x7d00, 0xb300, 0xffff]
  18. , [0x4800, 0x4800, 0xb300, 0xffff]
  19. , [0x7d00, 0x4800, 0xb300, 0xffff]
  20. , [0xb300, 0x4800, 0xb300, 0xffff]
  21. , [0xb300, 0x4800, 0x7d00, 0xffff]
  22. ]
  23. bounded :: RealFloat a => Complex a -> Bool
  24. bounded z = magnitude z < 2
  25. iterFs :: (a -> a) -> [(a -> a)]
  26. iterFs = scanl (.) id . repeat
  27. iters :: Num a => a -> (a -> a) -> [a]
  28. iters z = map ($ z) . iterFs
  29. mandelIter :: Num a => a -> a -> a
  30. mandelIter c z = z^2 + c
  31. mandel :: RealFloat a => Complex a -> Int
  32. mandel z = length
  33. . takeWhile id
  34. . map bounded
  35. . take ITER_N
  36. . iters 0
  37. $ mandelIter z
  38. prod :: [a] -> [a] -> [Complex a]
  39. prod rs is = [r :+ i | i <- reverse is, r <- rs]
  40. ffHeader :: Int -> Int -> B.ByteString
  41. ffHeader w h = B.concat
  42. . map toLazyByteString
  43. $ [stringUtf8 "farbfeld", bs w, bs h]
  44. where bs = word32BE . fromIntegral
  45. pixel :: Int -> B.ByteString
  46. pixel x = B.concat
  47. . map (toLazyByteString . word16BE)
  48. . colour
  49. $ x
  50. colour :: Int -> [Word16]
  51. colour x | x == ITER_N = IN_COLOUR
  52. | otherwise = (!!) colours
  53. . mod x
  54. . length
  55. $ colours
  56. range :: Fractional t => t -> t -> Int -> [t]
  57. range _ _ 0 = []
  58. range min max n = take n
  59. . scanl (+) min
  60. . repeat
  61. $ (max - min) / fromIntegral n
  62. mandelRender :: RealFloat a => (a, a) -> (a, a) -> (Int, Int) -> B.ByteString
  63. mandelRender (r0, r1) (i0, i1) (w, h) = ffHeader w h `B.append` pixels
  64. where pixels = B.concat
  65. . map pixel
  66. . map mandel
  67. . prod xs
  68. $ ys
  69. xs = range r0 r1 w
  70. ys = range i0 i1 h
  71. main = do
  72. args <- getArgs
  73. let (r0, r1) = read $ args !! 0
  74. let (i0, i1) = read $ args !! 1
  75. let (w, h) = read $ args !! 2
  76. let img = mandelRender (r0, r1) (i0, i1) (w, h)
  77. B.putStr img