Haskell組み込みDSLでSVGを書く
概要
プログラムで画像を作りたい時に便利そうなのでメモ。
diagrams-svg: SVG backend for diagrams drawing EDSL. | Hackage
これはHaskellでVector画像を描くライブラリである、diagramsライブラリのSVG出力ライブラリとなっている。
diagrams-lib: Embedded domain-specific language for declarative graphics | Hackage
一応githubにチュートリアルっぽいものがあるのだが、
それは型エラーでコンパイルできなかった。
今回は使い方を確認するために有名なフラクタル図形を書いてみた。
シェルピンスキーのギャスケット - Wikipedia
コンパイルと実行
$ ghc --make Sierpinski.hs $ ./Sierpinski -o image.svg 10 5
コマンドライン引数で渡した10と5が図形のパラメータとしてコード中で使用することができて便利だ。
出力される画像はこんな感じになる。
簡単なコード解説
main :: IO () main = mainWith d where d c k = pad 1.1 $ sierpinski c k # lcA transparent # fc (sRGB 0.3 0.3 0.3)
mainWithという関数がdの型から適切にコマンドライン引数をパーズしてdに渡してくれる。
関数dはパラメータcとkをつけとって図形を返す。
ここでcとkはそれぞれ最小の三角形のサイズと再帰の深さを表すパラメータで、
ではsierpinski c kという図形の線の色(lcA)や塗りつぶしの色(fc)を指定して、
1割の余白(pad)を付与する。
sierpinski :: Double -> Int -> Diagram B R2 sierpinski c 0 = triangle c sierpinski c k = let d' = sierpinski c (k-1) l = c * 2^(k-1) z = sqrt 3 / 2 * l / 3 ps = [(0,z*2),(-l/2,-z),(l/2,-z)] in position $ map (\p -> (p2 p,d')) ps
Diagram B R2という型においてBはバックエンドの型(ここではSVG)、R2は2次元画像を意味する。*1
再帰の深さがリミットに達した場合は一辺の長さがcの正三角形(triangle c)を返し、
そうでない場合は、siperpinski図形を生成し(sierpinski c (k-1))、それを3箇所に並べた(position)ものが
siperpinski図形となる。
このようにして図形を代数的にかけるのでとてもイイ感じのライブラリだ。