Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
AEC Mandelbrot - Main.hs

Main.hs

Caricato da: ZioCrocifisso
Scarica il programma completo

  1. {-# LANGUAGE BangPatterns #-}
  2. module Main where
  3.  
  4. import Control.Applicative
  5. import Control.Monad ()
  6. import Data.Complex
  7. import Data.List as L
  8. import System.Environment
  9.  
  10. sa :: Show a => a -> ShowS
  11. sa = shows
  12.  
  13. sc :: Char -> ShowS
  14. sc = showChar
  15.  
  16. ss :: String -> ShowS
  17. ss = showString
  18.  
  19. hsvToRgb :: (Double, Double, Double) -> (Double, Double, Double)
  20. hsvToRgb (h, s, v)
  21.         | s == 0 = (v, v, v)
  22.         | v > 1 = hsvToRgb (h, s, 1)
  23.         | h < 1 = (v, t, p)
  24.         | h < 2 = (q, v, p)
  25.         | h < 3 = (p, v, t)
  26.         | h < 4 = (p, q, v)
  27.         | h < 5 = (t, p, v)
  28.         | otherwise = (v, p, q)
  29.         where
  30.                 f = h - fromIntegral (floor h)
  31.                 p = v * (1 - s)
  32.                 q = v * (1 - s * f)
  33.                 t = v * (1 - s * (1 - f))
  34.  
  35. rgbToXTerm :: (Double, Double, Double) -> Integer
  36. rgbToXTerm (r, g, b) = round $ 16 + r * 216 + g * 36 + b * 6
  37.  
  38. rgb255 :: (Double, Double, Double) -> (Integer, Integer, Integer)
  39. rgb255 (r, g, b) = (c r, c g, c b)
  40.         where c = floor . (* 255)
  41.  
  42. hsvToXTerm :: (Double, Double, Double) -> Integer
  43. hsvToXTerm = rgbToXTerm . hsvToRgb
  44.  
  45. mandelbrot :: Integer -> Double -> Double -> Double -> [Integer]
  46. mandelbrot w yOff xOff zoom = getIntensity <$> xCoords <*> yCoords
  47.         where
  48.                 wOff = 2 / fromIntegral (w - 1)
  49.  
  50.                 xCoords = L.genericTake w $ iterate (+ wOff * zoom) (- zoom + xOff)
  51.                 yCoords = L.genericTake w $ iterate (+ wOff * 0.5 * zoom) (-zoom + yOff)
  52.  
  53.                 getIntensity x y = fst . iterations p . (,) 0 $ p
  54.                                 where p = y :+ x
  55.  
  56.                 iterations _ (500, _) = (0, 0 :+ 0)
  57.                 iterations c (count, z) = if isIn then next else (count, z)
  58.                         where
  59.                                 z' = z ^ 2 + c
  60.                                 isIn = magnitude z' < 2
  61.                                 next = iterations c (count + 1, z')
  62.  
  63. gen :: (Bool -> Integer -> ShowS) -> Integer -> [Integer] -> ShowS
  64. gen f w = fst . foldl' put (ss "", 0)
  65.         where
  66.                 put (!s, x) !i = let last = x >= w - 1 in (s . f last i, if last then 0 else x + 1)
  67.  
  68. genHsv :: Double -> Integer -> (Double, Double, Double)
  69. genHsv fac i = (fromIntegral i / 83, 1, sqrt (fromIntegral i / 5) * fac)
  70.  
  71. genAEC :: Integer -> [Integer] -> String
  72. genAEC w = ($ "\ESC[0m") . gen put w
  73.         where
  74.                 col 0 _ = col 1 ' '
  75.                 col i c = ss "\ESC[48;5;" . cl . ss "m\ESC[38;5;" . cl . sc 'm' . sc c . ss "\ESC[0m"
  76.                         where
  77.                                 cl = sa . hsvToXTerm . genHsv 0.04 $ i
  78.  
  79.                 put False i = col i '*'
  80.                 put True i = put False i . sc '\n'
  81.  
  82. genPPM :: Integer -> [Integer] -> String
  83. genPPM w c = ss "P3\n" . sa w . sc ' ' . sa len . ss "\n255\n" . gen put w c $ ""
  84.         where
  85.                 --len = L.genericLength c `quot` w
  86.                 len = w
  87.                 endChar True = '\n'
  88.                 endChar False = '\t'
  89.                 put last i = case rgb255 . hsvToRgb . genHsv 0.5 $ i of
  90.                                 (b, g, r) -> sa r . sc ' ' . sa g . sc ' ' . sa b . sc (endChar last)
  91.  
  92. main :: IO ()
  93. main = getArgs >>= \as -> case as of
  94.         (w : x : y : z : (f : []) : _) -> ma w x y z f
  95.         (w : x : y : z : _) -> ma w x y z 'a'
  96.         (w : x : y : []) -> ma w x y "0.5" 'a'
  97.         (w : x : []) -> ma w x "0" "0.5" 'a'
  98.         (w : [] ) -> ma w "0.5" "0" "0.5" 'a'
  99.         [] -> ma "80" "0.5" "0" "0.5" 'a'
  100.         where ma ws xs ys zs fs =
  101.                 let
  102.                         w = read ws :: Integer
  103.                         x = read xs :: Double
  104.                         y = read ys :: Double
  105.                         z = 1 / read zs :: Double
  106.                         f = case fs of
  107.                                 'a' -> genAEC
  108.                                 'p' -> genPPM
  109.                                 _ -> error "Invalid format."
  110.                 in putStrLn . f w . mandelbrot w x y $ z