スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【Haskell】マンデルブロ集合

haskellで画像ファイルを作成したいなとふと思い立ったので、マンデルブロ集合を作成するプログラムをしました。
ビットマップを扱うライブラリは公開されてると思ったので調べてcabal を使ってダウンロード&インストール
発散するかどうかのチェックは|z|>2,発散速度は|z|>2になるまでの計算の繰り返し回数です。
とりあえず作ってみたので高速化なんて全然考えてないですが、それなりに1000*1000px程度を
一分程度の速度で描けたのでまあまあかな。
作ってて気になったのがHaskellってワンライナーで書きやすいので、横に長くなっちゃうstyleで
書いてしまって、後で型エラーとかで困ることが多多ありました。

拡張をかんがえると、
1:色の指定を外部ファイルから与えること
2:発散しない場合でも何かしらの色を付ける方法を考える
3:ライブラリ化

といったところですかね。
あ、あと高速化。



{-
-マンデルブロ集合描写プログラム
- 2012/12/22 作成
- author: t.k.
- version: 0.1.0
-}
import Codec.BMP
import Numeric
import qualified Data.ByteString as B
import GHC.Word
import Data.Complex
import Control.Monad.List
import System.IO
import System.Environment



-- 計算範囲 [(x.y) | x <- [x1..x2], y <- [y1..y2]]
--とするとき
--引数 x1 -> x2 -> y1 -> y2 -> width -> outputFilePath -> IO()
--
main :: IO()
main = do arg <- getArgs
let l = read (arg !! 0)
let r = read (arg !! 1)
let b = read (arg !! 2)
let t = read (arg !! 3)
let w = read (arg !! 4)
let f = arg !! 5
drowMandibrot2 (l,t) (r,b) w f


-- [[(R,G,B)]] の配列からビットマップのByteStringに変換する
rgbToByteList:: [[(Word8,Word8,Word8)]] -> B.ByteString
rgbToByteList = B.pack . concat . map rgbToByteList'
where rgbToByteList' = concatMap (\(r,g,b) -> [ r, g,b,0])
----------------------------------------------------------------------
{-
- マンディブロ集合
-}

-- マンデルブロ集合漸化式
mandibrotFunc :: (Num a) => a -> a -> a
mandibrotFunc c z = z*z + c


-- zの計算回数
count :: Int
count = 200

-- マンデルブロ集合の発散速度[1..count]からRGBの値を得る
-- 発散速度 -> RGB
toPixcel :: Int -> (Word8,Word8,Word8)
toPixcel z
| z == 0 = (0,0,0)
| count - z > 60 = (255,241,0)
| count - z > 30 = (00,30,68)
| count - z > 25 = (99,22,60)
| count - z > 20 = (125,100,120)
| count - z > 15 = (80,90,100)
| count - z > 8 = (125,180,120)
| count - z > 3 = (120,220,225)
| otherwise = (255,255,255)
{-
| z == 0 = (0,0,0)
| z < 10 = (30,30,30)
| z < 20 = (60,60,60)
| z < 40 = (120,120,120)
| z < 80 = (150,150,150)
| z < 90 = (180,180,180)
| otherwise = (255,255,255)
-}

-- マンデルブロ集合描写関数(最初に作ったのが使いにくインターフェースだったため改良)
-- (left,top) -> (right,bottom) -> width -> FilePath -> IO()
drowMandibrot2 :: (Double ,Double) -> (Double,Double) -> Int -> FilePath -> IO()
drowMandibrot2 (left,top) (right,bottom) w file = drowMandibrot (left,bottom) (w,h) dt file
where
dt = (right - left ) / (fromIntegral w)
h = truncate $ (top - bottom) / dt

-- マンデルブロ描写関数
-- 引数 (top,left) -> (width,heigth) -> dt -> FilePath -> IO()
drowMandibrot :: (Double ,Double) -> (Int,Int) -> Double -> FilePath -> IO()
drowMandibrot point size@(w,h) dt file = writeBMP file $ packRGBA32ToBMP w h $ rgbToByteList $! mandibrot point size dt


-- 複素平面上のマンデルブロ集合の発散速度を計算しRGBのリストを返す
mandibrot :: (Double ,Double) -> (Int,Int) -> Double -> [[(Word8,Word8,Word8)]]
mandibrot (left,top) (w,h) dt = map (map (toPixcel . calc ) ) $ numberList left top w h dt
where
-- マンデルブロ集合の発散速度を計算する
-- 引数 発散速度を計算する複素平面上の点 -> 発散速度
calc c = count - (length $ takeWhile ( \x -> (magnitude x) <=2) $ take count $ iterate (mandibrotFunc c ) 0 )
-- マンデルブロ集合を計算する複素平面上の点をすべて計算する
-- 引数 left 0 -> top -> width -> height -> dt
numberList left top w h dt = map (\x -> (take w (iterate ( +(dt:+0) ) $ (left:+0) + x))) $ take h $ iterate (+ ((0:+dt))) $ (left:+top)
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

かみさまみならい

Author:かみさまみならい
FC2ブログへようこそ!

最近の記事
最近のコメント
最近のトラックバック
月別アーカイブ
カテゴリー
ブロとも申請フォーム

この人とブロともになる

ブログ内検索
RSSフィード
リンク
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。