\section{Representing objects in homogenous coordinates: RSAGL.Homogenous}

Entities such as points and vectors that can be represented as matrices.  The Homogenous typeclass is
an easy way to implement affine transformations on these types.

toHomogenous always results in a column matrix, while fromHomogenous always expects a row matrix.
This means that (fromHomogenous . toHomogenous) is not an identity function.
Instead, (fromHomogenous . matrixTranspose . toHomogenous) is an identity function.

\begin{code}
module RSAGL.Homogenous
    (Homogenous(..),
     transformHomogenous)
    where

import RSAGL.Vector
import RSAGL.Matrix

class Homogenous a where
    toHomogenous :: a -> Matrix
    fromHomogenous :: Matrix -> a

instance Homogenous Vector3D where
    toHomogenous (Vector3D x y z) = matrix [[x],
                                            [y],
                                            [z],
                                            [0.0]]
    fromHomogenous m = vector3d $ genericFromHomogenous m 

instance Homogenous Point3D where
    toHomogenous (Point3D x y z) = matrix [[x],
                                           [y],
                                           [z],
                                           [1.0]]
    fromHomogenous m = point3d $ genericFromHomogenous m

genericFromHomogenous :: Matrix -> XYZ
genericFromHomogenous m = let x = (rowMajorForm m) !! 0 !! 0
			      y = (rowMajorForm m) !! 1 !! 0
			      z = (rowMajorForm m) !! 2 !! 0
			      in (x,y,z)

transformHomogenous :: (Homogenous a, Homogenous b) => Matrix -> a -> b
transformHomogenous transformation_matrix entity = 
    fromHomogenous $ matrixMultiply transformation_matrix $ toHomogenous entity
\end{code}