{-# LANGUAGE GADTs #-} -- only for presentation -- | Simple library for 2D shapes. Deep embedding. module Shape.Deep ( -- * Types Shape -- abstract -- * Constructor functions , empty, disc, square -- * Primitive combinators , transform, translate , union, intersect, invert -- * Run functions , inside ) where import Matrix -- | In a deep embedding our objects are represented by a datatype -- with constructors for each primitive operation. {- From the lecture slides: type Shape -- Constructor functions empty :: Shape disc :: Shape square :: Shape -- Combinators translate :: Vec -> Shape -> Shape scale :: Vec -> Shape -> Shape rotate :: Angle -> Shape -> Shape union :: Shape -> Shape -> Shape intersect :: Shape -> Shape -> Shape difference:: Shape -> Shape -> Shape Later scale, rotate, difference are derived from invert and transform: invert :: Shape -> Shape transform :: Matrix -> Shape -> Shape -} data Shape where -- Constructor functions Empty :: Shape Disc :: Shape Square :: Shape -- Combinators Translate :: Vec -> Shape -> Shape Transform :: Matrix-> Shape -> Shape Union :: Shape -> Shape -> Shape Intersect :: Shape -> Shape -> Shape Invert :: Shape -> Shape {- -- Shape without GADT syntax data Shape = Empty | Disc | Square | Translate Vec Shape | Transform Matrix Shape | Union Shape Shape | Intersect Shape Shape | Invert Shape -} -- * Creation functions empty :: Shape empty = Empty disc :: Shape disc = Disc square :: Shape square = Square -- * Primitive combinators transform :: Matrix -> Shape -> Shape transform = Transform translate :: Vec -> Shape -> Shape translate = Translate union :: Shape -> Shape -> Shape union = Union intersect :: Shape -> Shape -> Shape intersect = Intersect invert :: Shape -> Shape invert = Invert -- * Run function inside :: Point -> Shape -> Bool _p `inside` Empty = False p `inside` Disc = sqDistance p <= 1 p `inside` Square = maxnorm p <= 1 p `inside` Translate v sh = (p `sub` v) `inside` sh p `inside` Transform m sh = (inv m `mul` p) `inside` sh p `inside` Union sh1 sh2 = p `inside` sh1 || p `inside` sh2 p `inside` Intersect sh1 sh2 = p `inside` sh1 && p `inside` sh2 p `inside` Invert sh = not (p `inside` sh) -- * Helper functions sqDistance :: Point -> Double sqDistance p = x*x+y*y -- proper distance would use sqrt where x = ptX p y = ptY p maxnorm :: Point -> Double maxnorm p = max (abs x) (abs y) where x = ptX p y = ptY p -- | More reading: http://en.wikipedia.org/wiki/Norm_%28mathematics%29#Properties