Guest User

Untitled

a guest
Jul 17th, 2018
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.40 KB | None | 0 0
  1. {-
  2. fractal : A fractal generator in hasell
  3.  
  4. Author : Mriganka Basu Roy Chowdhury
  5.  
  6. Install : Preferably (if you don't want cabal hell),
  7. form a cabal sandbox and install JuicyPixels
  8. and optparse-applicative. Then just
  9. cabal exec -- ghc fractal.hs -O3
  10. Please use -O3, as otherwise, the generation
  11. may take a lot of time.
  12.  
  13. Modifications :
  14. Look into the source below, and change
  15. stuff if you need to. Most of the code is
  16. segmented, and documented, so that part
  17. should be pretty obvious.
  18. -}
  19.  
  20.  
  21. import Codec.Picture -- needs JuicyPixels
  22. import Data.Complex -- in base, so chill.
  23. import Data.List -- again in base.
  24. import Options.Applicative -- need optparse-applicative
  25. import Data.Semigroup hiding (option) -- in base
  26. import Text.Read (readMaybe) -- in base as well.
  27. import Data.Maybe -- in base.
  28. import Control.Monad -- in base.
  29.  
  30.  
  31. type R = Float -- The real used, change to Double for precision
  32. type C = Complex R
  33. type IterF = C -> C -- Iteration function
  34.  
  35. type Pix = PixelRGB8 -- The pixel type used.
  36. type View = (C, C) -- Upper left, lower right complex numbers
  37. type Dimensions = (Int, Int) -- Width, Height
  38.  
  39. inf :: R
  40. inf = 1e20
  41.  
  42. -------------------- For general uses, just modify this part -------
  43.  
  44. baseFunction :: C -> IterF -- Change this function to your wishes, but
  45. -- keep the signature intact. :)
  46. -- This function currently generates mandelbrot sets.
  47. baseFunction c z = z**2 + c
  48.  
  49. -------------- ************************************ ----------------
  50.  
  51. characteristic :: (C -> IterF) -- Iteration function
  52. -> R -- Escape Radius
  53. -> Int -- Iterations
  54. -> C -- Parameter
  55. -> Pix -- A double indicating color.
  56. characteristic f r n c =
  57. let g = f c
  58. l = map snd $
  59. takeWhile (\(i, z) -> i <= n && realPart (abs z) < r) $
  60. zip [1..] $ iterate g (0.0 :+ 0.0)
  61. in colorFunc n (length l) c (last l)
  62.  
  63. -------------------------------------------------------------------
  64.  
  65. data FractalOptions
  66. = FractalOptions
  67. { iterations :: Int
  68. , escapeRad :: R
  69. , upperLeftX :: R
  70. , upperLeftY :: R
  71. , lowerRightX :: R
  72. , lowerRightY :: R
  73. , width :: Int
  74. , height :: Int
  75. , output :: FilePath
  76. }
  77.  
  78.  
  79. main :: IO ()
  80. main = do
  81. results <- execParser $ info (parser <**> helper)
  82. ( header "--- fractal : A fractal generator ---"
  83. <> progDesc "Generates a PNG image of a fractal generated by iteration"
  84. <> fullDesc
  85. )
  86. let (FractalOptions n r ulx uly lrx lry w h out) = results
  87. image = produceFractal baseFunction n r
  88. ((ulx :+ uly), (lrx :+ lry))
  89. (w, h)
  90.  
  91. putStrLn "Generating and writing the image... Hang tight."
  92.  
  93. writePng out image
  94.  
  95. putStrLn "Done. Enjoy!"
  96.  
  97. ---------------- The parser for optparse ------------
  98.  
  99. parser :: Parser FractalOptions
  100. parser = FractalOptions <$>
  101. option auto
  102. ( long "iterations"
  103. <> short 'n'
  104. <> help "The number of times the iteration happens."
  105. <> metavar "INTEGER"
  106. <> value 30
  107. )
  108. <*>
  109. option auto
  110. ( long "escape"
  111. <> short 'r'
  112. <> help "Escape radius"
  113. <> metavar "REAL"
  114. <> value 10.0
  115. )
  116. <*>
  117. option auto
  118. ( long "upper-left-x"
  119. <> short 'X'
  120. <> help "The upper left x in the frame of the image generated."
  121. <> metavar "REAL"
  122. <> value (-1.8)
  123. )
  124. <*>
  125. option auto
  126. ( long "upper-left-y"
  127. <> short 'Y'
  128. <> help "The upper left y in the frame of the image generated."
  129. <> metavar "REAL"
  130. <> value (1.3)
  131. )
  132. <*>
  133. option auto
  134. ( long "lower-right-x"
  135. <> short 'x'
  136. <> help "The upper left x in the frame of the image generated."
  137. <> metavar "REAL"
  138. <> value (0.8)
  139. )
  140. <*>
  141. option auto
  142. ( long "lower-right-y"
  143. <> short 'y'
  144. <> help "The upper left x in the frame of the image generated."
  145. <> metavar "REAL"
  146. <> value (-1.3)
  147. )
  148. <*>
  149. option auto
  150. ( long "width"
  151. <> short 'w'
  152. <> help "Width of the image generated."
  153. <> metavar "INTEGER"
  154. <> value 600
  155. )
  156. <*>
  157. option auto
  158. ( long "height"
  159. <> short 'h'
  160. <> help "Height of the image generated."
  161. <> metavar "INTEGER"
  162. <> value 600
  163. )
  164. <*>
  165. strOption
  166. ( long "output"
  167. <> short 'o'
  168. <> help "Output file name of the png image"
  169. <> metavar "FILENAME"
  170. <> value "output.png"
  171. )
  172.  
  173.  
  174. ------------- A few math functions ---------------------
  175.  
  176. clamp :: R -> R -> R -> R
  177. clamp l r x = min r (max x l)
  178.  
  179. --
  180.  
  181. normal :: R -- center
  182. -> R -- spread
  183. -> R -- value
  184. -> R
  185. normal c spread x = exp (- (abs (x - c))**2 / spread)
  186.  
  187. --
  188.  
  189. sigmoidCut :: R -> R -> R -> R
  190. sigmoidCut c s x = if x < c then 0.0 else -0.5 + 1.0 / (1 + exp (-(x - c)/s))
  191.  
  192. --------------------------------------------------------
  193.  
  194.  
  195. -- The function that generates the color.
  196. -- The current configuration was obtained after many trials.
  197. -- So perfecting it may require trial and error / theory.
  198.  
  199. colorFunc :: Int -- Number of iterations max
  200. -> Int -- Number of iterations taken
  201. -> C -- Current complex number
  202. -> C -- Final complex number after iteration
  203. -> Pix -- Generated color
  204. colorFunc n m z z' =
  205. let w = 1 + (realPart $ abs z)
  206. w'= 1 + (realPart $ abs z')
  207. x = fromIntegral (n - m) / (fromIntegral n)
  208. r = normal (0.8) 0.05 x
  209. g = normal (0.8) 0.1 x
  210. b = sigmoidCut (0.8) 0.05 x
  211.  
  212. r'= floor $ r * 255
  213. g'= floor $ g * 255
  214. b'= floor $ b * 255
  215. in PixelRGB8 r' g' b'
  216.  
  217.  
  218. --------------- The function that produces the fractal ------
  219.  
  220. produceFractal :: (C -> IterF) -- Iteration function
  221. -> Int -- Iterations
  222. -> R -- Escape radius
  223. -> View -- Region being viewed for the fractal
  224. -> Dimensions -- Image dimensions
  225. -> Image Pix -- Output image
  226.  
  227. produceFractal f n r (upperLeft, lowerRight) (w, h) =
  228. let viewWidth = realPart (lowerRight - upperLeft)
  229. viewHeight= imagPart (upperLeft - lowerRight)
  230.  
  231. charProducer = characteristic f r n
  232.  
  233. pixelSpace = [(x, y) | x <- [0..w], y <- [0..h]]
  234.  
  235. genFunction :: Int -> Int -> Pix
  236. genFunction x y =
  237. let dx = (fromIntegral x * viewWidth) / (fromIntegral w)
  238. dy = -(fromIntegral y * viewHeight) / (fromIntegral h)
  239. z = upperLeft + (dx :+ dy)
  240. in charProducer z
  241.  
  242. in generateImage genFunction w h
  243.  
  244. -------------------------------------------------------------
Add Comment
Please, Sign In to add comment