import Numeric type Vect = (Float, Float) -- ベクタ型 type LineSegment = [Vect] -- 線分 type Figure = [LineSegment] -- 図形データは線分のリスト type Frame = (Vect,Vect,Vect) -- 最後の絵を描くフレーム type Painter = (Frame -> IO ()) -- ぺインタはフレームを貰い出力する blan,wave :: Painter blank = \ frame -> putStr "" -- 何も描かないぺインタ wave = segmentsToPainter 20 20 -- 図-3 Gの人がた [[(0,13),(3,8),(6,12),(7,11),(5,0)],[(8,0),(10,6),(12,0)], [(15,0),(12,10),(20,3)],[(20,7),(15,13),(12,13),(13,17),(12,20)], [(8,20),(7,17),(8,13),(6,13),(3,12),(0,17)]] infixr 7 +~, -~ -- 2項演算子 +~,-~ infixr 8 *~ -- 2項演算子 *~ (+~), (-~) :: Vect -> Vect -> Vect (x0,y0) +~ (x1,y1) = (x0+x1, y0+y1) -- ベクタ(x0,y0)に(x1,y1)を足す (x0,y0) -~ (x1,y1) = (x0-x1, y0-y1) -- ベクタ(x0,y0)から(x1,y1)を引く (*~) :: Float -> Vect ->Vect a *~ (x,y) = (a*x, a*y) -- ベクタ(x0,y0)をa倍する drawLine,drawLine' :: [Vect] -> String --[(x,y),...]を結ぶ線を引く文字列を作る drawLine ((x,y):xys) = show x ++ " " ++ show y ++ " moveto\n" ++ drawLine' xys drawLine' [] = "" drawLine' ((x,y):xys) = show x ++ " " ++ show y ++ " lineto\n" ++ drawLine' xys segmentsToPainter :: Float -> Float -> Figure -> Painter segmentsToPainter scale0 scale1 segs = -- 線分の位置を正規化しぺインタに \ frame -> putStr \$ let toFrame (x,y) = frameCoodMap frame (x/scale0, y/scale1) drawSeg seg = drawLine (map toFrame seg) in concat (map drawSeg segs) ++ "stroke\n" frameCoodMap :: Frame -> (Vect -> Vect) frameCoodMap (org,edge0,edge1) = -- フレームの枠内へ座標変換 \ (x,y) -> org +~ x *~ edge0 +~ y *~ edge1 transformPainter :: Painter -> Vect -> Vect -> Vect -> Painter transformPainter painter org edge0 edge1 = \ frame -> let m = frameCoodMap frame newOrg = m org newEdge0 = m edge0 -~ newOrg newEdge1 = m edge1 -~ newOrg in painter (newOrg, newEdge0, newEdge1) rot,flipHoriz,flipVert :: Painter -> Painter rot p = transformPainter p (1,0) (1,1) (0,0) -- 左回転 flipHoriz p = transformPainter p (1,0) (0,0) (1,1) -- 左右反転 flipVert p = transformPainter p (0,1) (1,1) (0,0) -- 上下反転 above,beside :: Float -> Float -> Painter -> Painter -> Painter above m n p q = -- pをqの上にm:nの高さで積む \ frame -> do transformPainter p (0,r) (1,r) (0,1) frame transformPainter q (0,0) (1,0) (0,r) frame where r = n/(m+n) beside m n p q = -- pとqをm:nの幅で並べる \ frame -> do transformPainter p (0,0) (r,0) (0,1) frame transformPainter q (r,0) (1,0) (r,1) frame where r = m/(m+n) infixr 3 -- 2項演算子 infixr 4 <-> -- 2項演算子 <-> (), (<->) :: Painter -> Painter -> Painter () = above 1 1 -- p q pをqの上に積む (<->) = beside 1 1 -- p <-> q pとqを並べる unitSquare :: Frame unitSquare = ((128,16),(256,0),(0,256)) -- 絵を描くフレーム