hgeometry-0.1.1.1: src/Data/Geometry/Geometry.hs
{-# Language FlexibleInstances,
UndecidableInstances,
OverlappingInstances
#-}
module Data.Geometry.Geometry(
-- ** Point based geometries
IsPoint2Functor(..)
, IsTransformable(..)
, HasPoints(..)
, Vec3(..)
, Matrix3(..)
, identityMatrix3
, matrix3FromLists
, matrix3FromList
, matrix3ToList
, matrix3ToLists
) where
import Data.Geometry.Point
---------------------------------------------------------------------
-- | Point based geometries
-- | A class that defines a point2 functor. This defines that every operation that
-- we can do on a point we can also do on instances of this class. i.e. by
-- applying the operation on the underlying points.
class IsPoint2Functor g where
p2fmap :: (Point2' a -> Point2' b) -> g a -> g b
class HasPoints g where
points :: g a -> [Point2' a]
instance HasPoints Point2' where
points p = [p]
---------------------------------------------------------------------
-- | Basic linear algebra to support affine transformations in 2D
-- | Type to represent a matrix, form is:
-- [ [ a11, a12, a13 ]
-- [ a21, a22, a23 ]
-- [ a31, a32, a33 ] ]
newtype Vec3 a = Vec3 (a,a,a)
deriving (Show,Eq)
newtype Matrix3 a = Matrix3 (Vec3 (Vec3 a))
deriving (Show,Eq)
instance Functor Vec3 where
fmap f (Vec3 (a,b,c)) = Vec3 (f a, f b, f c)
instance Functor Matrix3 where
fmap f (Matrix3 (Vec3 (a,b,c))) = Matrix3 $ Vec3 (fmap f a, fmap f b, fmap f c)
v3FromList :: [a] -> Vec3 a
v3FromList [a,b,c] = Vec3 (a,b,c)
v3FromList _ = error "v3FromList needs exactly 3 elements."
-- | given a single list of 9 elements, construct a Matrix3
matrix3FromList :: [a] -> Matrix3 a
matrix3FromList = matrix3FromLists . rtake 3
where
rtake k ss = let (xs,ys) = splitAt k ss in
xs : rtake k ys
-- | Given a 3x3 matrix as a list of lists, convert it to a Matrix3
matrix3FromLists :: [[a]] -> Matrix3 a
matrix3FromLists = Matrix3 . v3FromList . map v3FromList
v3ToList :: Vec3 a -> [a]
v3ToList (Vec3 (a,b,c)) = [a,b,c]
-- | Gather the elements of the matrix in one long list (in row by row order)
matrix3ToList :: Matrix3 a -> [a]
matrix3ToList = concat . matrix3ToLists
matrix3ToLists :: Matrix3 a -> [[a]]
matrix3ToLists (Matrix3 (Vec3 (a,b,c))) = map v3ToList [a,b,c]
identityMatrix3 :: Num a => Matrix3 a
identityMatrix3 = matrix3FromLists [ [ 1, 0, 0 ]
, [ 0, 1, 0 ]
, [ 0, 0, 1 ] ]
multiply3 :: Num a => Matrix3 a -> Vec3 a -> Vec3 a
multiply3 (Matrix3 (Vec3 ( Vec3 (a,b,c)
, Vec3 (d,e,f)
, Vec3 (g,h,i)))) (Vec3 (x,y,z)) =
Vec3 ( a*x + b*y + c*z,
d*x + e*y + f*z,
g*x + h*y + i*z)
-- | Class that indicates that something can be transformable using
-- an affine transformation
class IsTransformable g where
transformWith :: Num a => Matrix3 a -> g a -> g a
-- | Points are transformable
instance IsTransformable Point2' where
transformWith = transformPoint
transformPoint :: Num a => Matrix3 a -> Point2' a -> Point2' a
transformPoint m (Point2 (x,y)) = Point2 (x',y')
where
v = Vec3 (x,y,1)
Vec3 (x',y',_) = multiply3 m v
-- | Everything that is built from points is transformable
tranformPointBased :: (Num a, IsPoint2Functor g) => Matrix3 a -> g a -> g a
tranformPointBased m = p2fmap (transformWith m)
instance IsPoint2Functor g => IsTransformable g where
transformWith = tranformPointBased