vect 0.4.0 → 0.4.5
raw patch · 23 files changed
+1916/−518 lines, 23 files
Files
- Data/Vect/Double/Base.hs +327/−70
- Data/Vect/Double/GramSchmidt.hs +3/−3
- Data/Vect/Double/OpenGL.hs +144/−27
- Data/Vect/Double/Util/Dim2.hs +8/−2
- Data/Vect/Double/Util/Dim3.hs +89/−12
- Data/Vect/Double/Util/Dim4.hs +3/−2
- Data/Vect/Double/Util/Projective.hs +61/−53
- Data/Vect/Float/Base.hs +327/−70
- Data/Vect/Float/GramSchmidt.hs +3/−3
- Data/Vect/Float/OpenGL.hs +144/−27
- Data/Vect/Float/Util/Dim2.hs +8/−2
- Data/Vect/Float/Util/Dim3.hs +89/−12
- Data/Vect/Float/Util/Dim4.hs +3/−2
- Data/Vect/Float/Util/Projective.hs +61/−53
- LICENSE +10/−10
- src/flt/Base.hs +327/−70
- src/flt/GramSchmidt.hs +3/−3
- src/flt/OpenGL.hs +144/−27
- src/flt/Util/Dim2.hs +8/−2
- src/flt/Util/Dim3.hs +89/−12
- src/flt/Util/Dim4.hs +3/−2
- src/flt/Util/Projective.hs +61/−53
- vect.cabal +1/−1
Data/Vect/Double/Base.hs view
@@ -1,11 +1,34 @@ {-# OPTIONS_GHC -DFlt=Double -DVECT_Double #-} -module Data.Vect.Flt.Base where+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving #-} +module Data.Vect.Flt.Base+ ( AbelianGroup(..) , vecSum+ , MultSemiGroup(..) , Ring , semigroupProduct+ , LeftModule(..) , RightModule(..)+ , Vector(..) , DotProd(..) , CrossProd(..)+ , normalize , distance , angle , angle'+ , UnitVector(..)+ , Pointwise(..)+ , Extend(..) , HasCoordinates(..) , Dimension(..)+ , Matrix(..) , Tensor(..) , Diagonal (..) , Determinant(..)+ , Orthogonal(..) , Projective(..) , MatrixNorms(..)+ , Vec2(..) , Vec3(..) , Vec4(..)+ , Mat2(..) , Mat3(..) , Mat4(..)+ , Ortho2 , Ortho3 , Ortho4+ , Normal2 , Normal3 , Normal4+ , Proj3 , Proj4+ , mkVec2 , mkVec3 , mkVec4+ , project , project' , projectUnsafe , flipNormal+ , householder, householderOrtho+ )+ where+ import Control.Monad import System.Random import Foreign +-------------------------------------------------------------------------------- -- class declarations class AbelianGroup g where@@ -20,15 +43,17 @@ vecSum :: AbelianGroup g => [g] -> g vecSum l = foldl (&+) zero l -class (AbelianGroup r) => - Ring r where+class MultSemiGroup r where (.*.) :: r -> r -> r one :: r +class (AbelianGroup r, MultSemiGroup r) => Ring r + infixl 7 .*. -ringProduct :: Ring r => [r] -> r-ringProduct l = foldl (.*.) one l+-- was: ringProduct :: Ring r => [r] -> r+semigroupProduct :: MultSemiGroup r => [r] -> r +semigroupProduct l = foldl (.*.) one l class LeftModule r m where lmul :: r -> m -> m@@ -75,7 +100,7 @@ lensqr = normsqr dotprod :: v -> v -> Flt normsqr v = (v &. v) - norm = sqrt.lensqr+ norm = sqrt . lensqr dotprod = (&.) infix 7 &.@@ -112,26 +137,28 @@ fromNormalRadius :: Flt -> u -> v fromNormalRadius t n = t *& fromNormal n --- | projects the first vector onto the direction of the second (unit) vector+-- | Projects the first vector onto the direction of the second (unit) vector project' :: (Vector v, UnitVector v u, DotProd v) => v -> u -> v project' what dir = projectUnsafe what (fromNormal dir) --- | direction (second argument) is assumed to be a /unit/ vector!+-- | Direction (second argument) is assumed to be a /unit/ vector! projectUnsafe :: (Vector v, DotProd v) => v -> v -> v projectUnsafe what dir = what &- dir &* (what &. dir) project :: (Vector v, DotProd v) => v -> v -> v project what dir = what &- dir &* ((what &. dir) / (dir &. dir)) --- | since unit vectors are not a group, we need a separate function.+-- | Since unit vectors are not a group, we need a separate function. flipNormal :: UnitVector v n => n -> n flipNormal = toNormalUnsafe . neg . fromNormal +-- | Cross product class CrossProd v where crossprod :: v -> v -> v (&^) :: v -> v -> v (&^) = crossprod- + +-- | Pointwise multiplication class Pointwise v where pointwise :: v -> v -> v (&!) :: v -> v -> v@@ -166,13 +193,50 @@ "inverse is an involution" forall m. inverse (inverse m) = m #-} +class Matrix m => Orthogonal m o | m->o, o->m where + fromOrtho :: o -> m + toOrthoUnsafe :: m -> o+ +class (AbelianGroup m, Matrix m) => MatrixNorms m where+ frobeniusNorm :: m -> Flt -- ^ the frobenius norm (= euclidean norm in the space of matrices)+ matrixDistance :: m -> m -> Flt -- ^ euclidean distance in the space of matrices+ operatorNorm :: m -> Flt -- ^ (euclidean) operator norm (not implemented yet)+ matrixDistance m n = frobeniusNorm (n &- m)+ operatorNorm = error "operatorNorm: not implemented yet"+ -- | Outer product (could be unified with Diagonal?) class Tensor t v | t->v where outer :: v -> v -> t class Determinant m where det :: m -> Flt - ++class Dimension a where+ dim :: a -> Int+ +-- | Householder matrix, see <http://en.wikipedia.org/wiki/Householder_transformation>. +-- In plain words, it is the reflection to the hyperplane orthogonal to the input vector.+householder :: (Vector v, UnitVector v u, Matrix m, Vector m, Tensor m v) => u -> m+householder u = idmtx &- (2 *& outer v v) + where v = fromNormal u++householderOrtho :: (Vector v, UnitVector v u, Matrix m, Vector m, Tensor m v, Orthogonal m o) => u -> o+householderOrtho = toOrthoUnsafe . householder++-- | \"Projective\" matrices have the following form: the top left corner+-- is an any matrix, the bottom right corner is 1, and the top-right+-- column is zero. These describe the affine orthogonal transformation of+-- the space one dimension less.+class (Vector v, Orthogonal n o, Diagonal v n) => Projective v n o m p + | m->p, p->m, p->o, o->p, p->n, n->p, p->v, v->p, n->o, n->v, v->n where+ fromProjective :: p -> m+ toProjectiveUnsafe :: m -> p+ orthogonal :: o -> p+ linear :: n -> p+ translation :: v -> p+ scaling :: v -> p++-------------------------------------------------------------------------------- -- Vec / Mat datatypes data Vec2 = Vec2 {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt @@ -182,16 +246,16 @@ data Vec4 = Vec4 {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt deriving (Read,Show) --- | these are /row/ vectors +-- | The components are /row/ vectors data Mat2 = Mat2 !Vec2 !Vec2 deriving (Read,Show) data Mat3 = Mat3 !Vec3 !Vec3 !Vec3 deriving (Read,Show) data Mat4 = Mat4 !Vec4 !Vec4 !Vec4 !Vec4 deriving (Read,Show) -- | The assumption when dealing with these is always that they are of unit length. -- Also, interpolation works differently.-newtype Normal2 = Normal2 Vec2 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable) -newtype Normal3 = Normal3 Vec3 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable,CrossProd) -newtype Normal4 = Normal4 Vec4 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable) +newtype Normal2 = Normal2 Vec2 deriving (Read,Show,Storable,DotProd,Dimension) +newtype Normal3 = Normal3 Vec3 deriving (Read,Show,Storable,DotProd,Dimension) +newtype Normal4 = Normal4 Vec4 deriving (Read,Show,Storable,DotProd,Dimension) mkVec2 :: (Flt,Flt) -> Vec2 mkVec3 :: (Flt,Flt,Flt) -> Vec3@@ -201,6 +265,19 @@ mkVec3 (x,y,z) = Vec3 x y z mkVec4 (x,y,z,w) = Vec4 x y z w +-- | Orthogonal matrices.+--+-- Note: the "Random" instances generates orthogonal matrices with determinant 1+-- (that is, orientation-preserving orthogonal transformations)!+newtype Ortho2 = Ortho2 Mat2 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)+newtype Ortho3 = Ortho3 Mat3 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)+newtype Ortho4 = Ortho4 Mat4 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)++-- | Projective matrices, encoding affine transformations in dimension one less.+newtype Proj3 = Proj3 Mat3 deriving (Read,Show,Storable,MultSemiGroup)+newtype Proj4 = Proj4 Mat4 deriving (Read,Show,Storable,MultSemiGroup)++-------------------------------------------------------------------------------- -- Unit vectors instance UnitVector Vec2 Normal2 where@@ -218,47 +295,163 @@ fromNormal (Normal4 v) = v toNormalUnsafe = Normal4 -rndUnit :: (RandomGen g, Random v, Vector v, DotProd v) => g -> (v,g)-rndUnit g = +_rndUnit :: (RandomGen g, Random v, Vector v, DotProd v) => g -> (v,g)+_rndUnit g = if d > 0.01 then ( v &* (1.0/d) , h )- else rndUnit h+ else _rndUnit h where (v,h) = random g d = norm v instance Random Normal2 where- random g = let (v,h) = rndUnit g in (Normal2 v, h) + random g = let (v,h) = _rndUnit g in (Normal2 v, h) randomR _ = random instance Random Normal3 where- random g = let (v,h) = rndUnit g in (Normal3 v, h) + random g = let (v,h) = _rndUnit g in (Normal3 v, h) randomR _ = random instance Random Normal4 where- random g = let (v,h) = rndUnit g in (Normal4 v, h) + random g = let (v,h) = _rndUnit g in (Normal4 v, h) randomR _ = random -{--instance Storable Normal2 where- alignment _ = alignment (undefined::Vec2)- sizeOf _ = sizeOf (undefined::Vec2)- peek p = liftM (\v -> Normal2 v) (peek $ castPtr p)- poke p (Normal2 v) = poke (castPtr p) v - -instance Storable Normal3 where- alignment _ = alignment (undefined::Vec3)- sizeOf _ = sizeOf (undefined::Vec3)- peek p = liftM (\v -> Normal3 v) (peek $ castPtr p)- poke p (Normal3 v) = poke (castPtr p) v +instance CrossProd Normal3 where+ crossprod (Normal3 v) (Normal3 w) = mkNormal (crossprod v w) -instance Storable Normal4 where- alignment _ = alignment (undefined::Vec4)- sizeOf _ = sizeOf (undefined::Vec4)- peek p = liftM (\v -> Normal4 v) (peek $ castPtr p)- poke p (Normal4 v) = poke (castPtr p) v --}+--------------------------------------------------------------------------------+-- Orthogonal matrices +instance Orthogonal Mat2 Ortho2 where+ fromOrtho (Ortho2 o) = o+ toOrthoUnsafe = Ortho2++instance Orthogonal Mat3 Ortho3 where+ fromOrtho (Ortho3 o) = o+ toOrthoUnsafe = Ortho3 ++instance Orthogonal Mat4 Ortho4 where+ fromOrtho (Ortho4 o) = o+ toOrthoUnsafe = Ortho4++------++instance Matrix Ortho2 where+ transpose (Ortho2 o) = Ortho2 (transpose o)+ idmtx = Ortho2 idmtx+ inverse = transpose++instance Matrix Ortho3 where+ transpose (Ortho3 o) = Ortho3 (transpose o)+ idmtx = Ortho3 idmtx+ inverse = transpose++instance Matrix Ortho4 where+ transpose (Ortho4 o) = Ortho4 (transpose o)+ idmtx = Ortho4 idmtx+ inverse = transpose++------++instance Random Ortho2 where+ random g = let (o,h) = _rndOrtho2 g in (toOrthoUnsafe (_flip1stRow2 o), h)+ randomR _ = random++instance Random Ortho3 where+ random g = let (o,h) = _rndOrtho3 g in (toOrthoUnsafe ( o), h)+ randomR _ = random++instance Random Ortho4 where+ random g = let (o,h) = _rndOrtho4 g in (toOrthoUnsafe (_flip1stRow4 o), h)+ randomR _ = random++------++-- determinant will be -1+_rndOrtho2 :: RandomGen g => g -> (Mat2, g)+_rndOrtho2 g = (h2, g1) where+ h2 = householder u2 :: Mat2 + (u2,g1) = random g ++-- generates a uniformly random orthogonal 3x3 matrix +-- /with determinant +1/, with respect to the Haar measure of SO3.+--+-- see Theorem 4 in:+-- Francesco Mezzadri: How to Generate Random Matrices from the Classical Compact Groups +-- Notices of the AMS, May 2007 issue+-- <http://www.ams.org/notices/200705/fea-mezzadri-web.ps>+_rndOrtho3 :: RandomGen g => g -> (Mat3, g) +_rndOrtho3 g = ( (h3 .*. m3), g2) where+ m3 = (extendWith :: Flt -> Mat2 -> Mat3) 1 o2 + h3 = householder u3 :: Mat3+ (u3,g1) = random g+ (o2,g2) = _rndOrtho2 g1++-- determinant will be -1+_rndOrtho4 :: RandomGen g => g -> (Mat4, g) +_rndOrtho4 g = ( (h4 .*. m4), g2) where+ m4 = (extendWith :: Flt -> Mat3 -> Mat4) 1 o3 + h4 = householder u4 :: Mat4+ (u4,g1) = random g+ (o3,g2) = _rndOrtho3 g1++------++_flip1stRow2 :: Mat2 -> Mat2+_flip1stRow2 (Mat2 a b) = Mat2 (neg a) b++_flip1stRow3 :: Mat3 -> Mat3+_flip1stRow3 (Mat3 a b c) = Mat3 (neg a) b c++_flip1stRow4 :: Mat4 -> Mat4+_flip1stRow4 (Mat4 a b c d) = Mat4 (neg a) b c d++--------------------------------------------------------------------------------+-- projective matrices+ +instance Projective Vec2 Mat2 Ortho2 Mat3 Proj3 where+ fromProjective (Proj3 m) = m+ toProjectiveUnsafe = Proj3+ orthogonal = Proj3 . extendWith 1 . fromOrtho+ linear = Proj3 . extendWith 1+ translation v = Proj3 $ Mat3 (Vec3 1 0 0) (Vec3 0 1 0) (extendWith 1 v)+ scaling v = Proj3 $ diag (extendWith 1 v)+ +instance Projective Vec3 Mat3 Ortho3 Mat4 Proj4 where+ fromProjective (Proj4 m) = m+ toProjectiveUnsafe = Proj4+ orthogonal = Proj4 . extendWith 1 . fromOrtho + linear = Proj4 . extendWith 1+ translation v = Proj4 $ Mat4 (Vec4 1 0 0 0) (Vec4 0 1 0 0) (Vec4 0 0 1 0) (extendWith 1 v)+ scaling v = Proj4 $ diag (extendWith 1 v)++instance Matrix Proj3 where+ idmtx = Proj3 idmtx+ transpose (Proj3 m) = Proj3 (transpose m)+ inverse = _invertProj3++instance Matrix Proj4 where+ idmtx = Proj4 idmtx+ transpose (Proj4 m) = Proj4 (transpose m)+ inverse = _invertProj4++_invertProj3 :: Proj3 -> Proj3+_invertProj3 (Proj3 mat@(Mat3 _ _ t)) = + Proj3 $ Mat3 (extendZero a) (extendZero b) (extendWith 1 t') + where+ t' = neg $ (trim t :: Vec2) .* invm2 + invm2@(Mat2 a b) = inverse $ (trim mat :: Mat2)++-- Inverts a projective 4x4 matrix. But you can simply use "inverse" instead.+-- We assume that the bottom-right corner is 1.+_invertProj4 :: Proj4 -> Proj4+_invertProj4 (Proj4 mat@(Mat4 _ _ _ t)) = + Proj4 $ Mat4 (extendZero a) (extendZero b) (extendZero c) (extendWith 1 t') + where+ t' = neg $ (trim t :: Vec3) .* invm3 + invm3@(Mat3 a b c) = inverse $ (trim mat :: Mat3)++-------------------------------------------------------------------------------- -- Vec2 instances instance HasCoordinates Vec2 Flt where@@ -314,7 +507,10 @@ k = sizeOf (undefined::Flt) poke p x pokeByteOff p k y- ++instance Dimension Vec2 where dim _ = 2++-------------------------------------------------------------------------------- -- Mat2 instances instance HasCoordinates Mat2 Vec2 where@@ -336,19 +532,21 @@ (&+) (Mat2 r1 r2) (Mat2 s1 s2) = Mat2 (r1 &+ s1) (r2 &+ s2) (&-) (Mat2 r1 r2) (Mat2 s1 s2) = Mat2 (r1 &- s1) (r2 &- s2) neg (Mat2 r1 r2) = Mat2 (neg r1) (neg r2) - zero = Mat2 zero zero -- (zero::Vec2) (zero::Vec2)-+ zero = Mat2 zero zero + instance Vector Mat2 where scalarMul s (Mat2 r1 r2) = Mat2 (g r1) (g r2) where g = scalarMul s mapVec f (Mat2 r1 r2) = Mat2 (g r1) (g r2) where g = mapVec f -instance Ring Mat2 where+instance MultSemiGroup Mat2 where (.*.) (Mat2 r1 r2) n = let (Mat2 c1 c2) = transpose n in Mat2 (Vec2 (r1 &. c1) (r1 &. c2)) (Vec2 (r2 &. c1) (r2 &. c2)) one = idmtx +instance Ring Mat2+ instance LeftModule Mat2 Vec2 where lmul (Mat2 row1 row2) v = Vec2 (row1 &. v) (row2 &. v) @@ -362,11 +560,6 @@ outer (Vec2 a b) (Vec2 x y) = Mat2 (Vec2 (a*x) (a*y)) (Vec2 (b*x) (b*y))-{-- outer v w = - let full = Mat2 (Vec2 1 1) (Vec2 1 1)- in (diag v) .*. full .*. (diag w)--} instance Determinant Mat2 where det (Mat2 (Vec2 a b) (Vec2 c d)) = a*d - b*c @@ -393,6 +586,24 @@ poke p r1 pokeByteOff p k r2 +instance Random Mat2 where+ random = randomR (Mat2 v1 v1 , Mat2 v2 v2) where + v1 = Vec2 (-1) (-1) + v2 = Vec2 1 1+ randomR (Mat2 a b, Mat2 c d) gen = + let (x,gen1) = randomR (a,c) gen+ (y,gen2) = randomR (b,d) gen1+ in (Mat2 x y, gen2)+ +instance Dimension Mat2 where dim _ = 2+ +instance MatrixNorms Mat2 where + frobeniusNorm (Mat2 r1 r2) = + sqrt $+ normsqr r1 + + normsqr r2+ +-------------------------------------------------------------------------------- -- Vec3 instances instance HasCoordinates Vec3 Flt where@@ -454,7 +665,10 @@ poke p x pokeByteOff p (k ) y pokeByteOff p (k+k) z- ++instance Dimension Vec3 where dim _ = 3++-------------------------------------------------------------------------------- -- Mat3 instances instance HasCoordinates Mat3 Vec3 where@@ -495,13 +709,13 @@ (&+) (Mat3 r1 r2 r3) (Mat3 s1 s2 s3) = Mat3 (r1 &+ s1) (r2 &+ s2) (r3 &+ s3) (&-) (Mat3 r1 r2 r3) (Mat3 s1 s2 s3) = Mat3 (r1 &- s1) (r2 &- s2) (r3 &- s3) neg (Mat3 r1 r2 r3) = Mat3 (neg r1) (neg r2) (neg r3) - zero = Mat3 zero zero zero -- (zero::Vec3) (zero::Vec3) (zero::Vec3)+ zero = Mat3 zero zero zero instance Vector Mat3 where scalarMul s (Mat3 r1 r2 r3) = Mat3 (g r1) (g r2) (g r3) where g = scalarMul s mapVec f (Mat3 r1 r2 r3) = Mat3 (g r1) (g r2) (g r3) where g = mapVec f -instance Ring Mat3 where+instance MultSemiGroup Mat3 where (.*.) (Mat3 r1 r2 r3) n = let (Mat3 c1 c2 c3) = transpose n in Mat3 (Vec3 (r1 &. c1) (r1 &. c2) (r1 &. c3))@@ -509,6 +723,8 @@ (Vec3 (r3 &. c1) (r3 &. c2) (r3 &. c3)) one = idmtx +instance Ring Mat3+ instance LeftModule Mat3 Vec3 where lmul (Mat3 row1 row2 row3) v = Vec3 (row1 &. v) (row2 &. v) (row3 &. v) @@ -523,11 +739,6 @@ (Vec3 (a*x) (a*y) (a*z)) (Vec3 (b*x) (b*y) (b*z)) (Vec3 (c*x) (c*y) (c*z))-{-- outer v w = - let full = Mat3 (Vec3 1 1 1) (Vec3 1 1 1) (Vec3 1 1 1)- in (diag v) .*. full .*. (diag w)--} instance Determinant Mat3 where det (Mat3 r1 r2 r3) = det (r1,r2,r3)@@ -556,6 +767,26 @@ pokeByteOff p (k ) r2 pokeByteOff p (k+k) r3 +instance Random Mat3 where+ random = randomR (Mat3 v1 v1 v1 , Mat3 v2 v2 v2) where+ v1 = Vec3 (-1) (-1) (-1)+ v2 = Vec3 1 1 1+ randomR (Mat3 a b c, Mat3 d e f) gen = + let (x,gen1) = randomR (a,d) gen+ (y,gen2) = randomR (b,e) gen1+ (z,gen3) = randomR (c,f) gen2 + in (Mat3 x y z, gen3)+ +instance Dimension Mat3 where dim _ = 3+ +instance MatrixNorms Mat3 where + frobeniusNorm (Mat3 r1 r2 r3) = + sqrt $+ normsqr r1 + + normsqr r2 + + normsqr r3 + +-------------------------------------------------------------------------------- -- Vec4 instances instance HasCoordinates Vec4 Flt where@@ -615,6 +846,9 @@ pokeByteOff p (k+k) z pokeByteOff p (3*k) w +instance Dimension Vec4 where dim _ = 4++-------------------------------------------------------------------------------- -- Mat4 instances instance HasCoordinates Mat4 Vec4 where@@ -642,7 +876,7 @@ scalarMul s (Mat4 r1 r2 r3 r4) = Mat4 (g r1) (g r2) (g r3) (g r4) where g = scalarMul s mapVec f (Mat4 r1 r2 r3 r4) = Mat4 (g r1) (g r2) (g r3) (g r4) where g = mapVec f -instance Ring Mat4 where+instance MultSemiGroup Mat4 where (.*.) (Mat4 r1 r2 r3 r4) n = let (Mat4 c1 c2 c3 c4) = transpose n in Mat4 (Vec4 (r1 &. c1) (r1 &. c2) (r1 &. c3) (r1 &. c4))@@ -651,6 +885,8 @@ (Vec4 (r4 &. c1) (r4 &. c2) (r4 &. c3) (r4 &. c4)) one = idmtx +instance Ring Mat4+ instance LeftModule Mat4 Vec4 where lmul (Mat4 row1 row2 row3 row4) v = Vec4 (row1 &. v) (row2 &. v) (row3 &. v) (row4 &. v) @@ -666,14 +902,10 @@ (Vec4 (b*x) (b*y) (b*z) (b*w)) (Vec4 (c*x) (c*y) (c*z) (c*w)) (Vec4 (d*x) (d*y) (d*z) (d*w))-{-- outer v w = - let full = Mat4 (Vec4 1 1 1 1) (Vec4 1 1 1 1) (Vec4 1 1 1 1) (Vec4 1 1 1 1)- in (diag v) .*. full .*. (diag w)--} ---instance Determinant Mat4 where--- det (Mat4 r1 r2 r3 r4)+instance Determinant Mat4 where+ det = error "det/Mat4: not implemented yet" + -- det (Mat4 r1 r2 r3 r4) = {- instance Show Mat4 where@@ -701,6 +933,28 @@ pokeByteOff p (k+k) r3 pokeByteOff p (3*k) r4 +instance Random Mat4 where+ random = randomR (Mat4 v1 v1 v1 v1, Mat4 v2 v2 v2 v2) where+ v1 = Vec4 (-1) (-1) (-1) (-1)+ v2 = Vec4 1 1 1 1+ randomR (Mat4 a b c d, Mat4 e f g h) gen = + let (x,gen1) = randomR (a,e) gen+ (y,gen2) = randomR (b,f) gen1+ (z,gen3) = randomR (c,g) gen2 + (w,gen4) = randomR (d,h) gen3 + in (Mat4 x y z w, gen4)+ +instance Dimension Mat4 where dim _ = 4+ +instance MatrixNorms Mat4 where + frobeniusNorm (Mat4 r1 r2 r3 r4) = + sqrt $+ normsqr r1 + + normsqr r2 + + normsqr r3 + + normsqr r4 + +-------------------------------------------------------------------------------- -- Extend instances instance Extend Vec2 Vec3 where@@ -719,17 +973,20 @@ trim (Vec4 x y z _) = Vec3 x y z instance Extend Mat2 Mat3 where- extendZero (Mat2 p q) = Mat3 (extendZero p) (extendZero q) zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat2 p q) = Mat3 (extendZero p) (extendZero q) zero+ extendWith w (Mat2 p q) = Mat3 (extendZero p) (extendZero q) (Vec3 0 0 w) trim (Mat3 p q _) = Mat2 (trim p) (trim q) instance Extend Mat2 Mat4 where- extendZero (Mat2 p q) = Mat4 (extendZero p) (extendZero q) zero zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat2 p q) = Mat4 (extendZero p) (extendZero q) zero zero+ extendWith w (Mat2 p q) = Mat4 (extendZero p) (extendZero q) (Vec4 0 0 w 0) (Vec4 0 0 0 w) trim (Mat4 p q _ _) = Mat2 (trim p) (trim q) instance Extend Mat3 Mat4 where- extendZero (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) zero+ extendWith w (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) (Vec4 0 0 0 w) trim (Mat4 p q r _) = Mat3 (trim p) (trim q) (trim r)+ +--------------------------------------------------------------------------------+
Data/Vect/Double/GramSchmidt.hs view
@@ -10,7 +10,7 @@ import Data.Vect.Flt.Base --------------------------------------------------------+-------------------------------------------------------------------------------- liftPair :: (a -> b) -> (a,a) -> (b,b) liftPair f (x,y) = (f x, f y)@@ -21,7 +21,7 @@ liftQuadruple :: (a -> b) -> (a,a,a,a) -> (b,b,b,b) liftQuadruple f (x,y,z,w) = (f x, f y, f z, f w) --------------------------------------------------------+-------------------------------------------------------------------------------- -- | produces orthogonal\/orthonormal vectors from a set of vectors class GramSchmidt a where@@ -33,7 +33,7 @@ "gramSchmidtNormalize is idempotent" forall a. gramSchmidtNormalize (gramSchmidtNormalize a) = gramSchmidtNormalize a #-} --------------------------------------------------------+-------------------------------------------------------------------------------- instance GramSchmidt (Vec2,Vec2) where gramSchmidt = gramSchmidtPair
Data/Vect/Double/OpenGL.hs view
@@ -3,21 +3,92 @@ -- TODO: the pointer versions of these functions should be really implemented -- via the pointer versions of the original opengl functions... --- | OpenGL support, inclduing 'vertex', 'texCoord', etc instances for 'Vec2', 'Vec3' and 'Vec4'.+-- | OpenGL support, including 'Vertex', 'TexCoord', etc instances for 'Vec2', 'Vec3' and 'Vec4'. module Data.Vect.Flt.OpenGL where import Control.Monad import Data.Vect.Flt.Base+import Data.Vect.Flt.Util.Projective import qualified Graphics.Rendering.OpenGL as GL import Foreign -import Graphics.Rendering.OpenGL hiding (Normal3,rotate,translate,scale)+import Graphics.Rendering.OpenGL hiding + ( Normal3 , rotate , translate , scale+ , matrix , currentMatrix , withMatrix , multMatrix + ) --------------------------------------------------------+-------------------------------------------------------------------------------- -{-# SPECIALISE radianToDegrees :: Float -> Float #-}+-- | There should be a big warning here about the different conventions, +-- hidden transpositions, and all the confusion this will inevitably cause...+--+-- As it stands, +--+-- > glRotate t1 axis1 >> glRotate t2 axis2 >> glRotate t3 axis3+-- +-- has the same result as+--+-- > multMatrix (rotMatrixProj4 t3 axis3 .*. rotMatrixProj4 t2 axis2 .*. rotMatrixProj4 t1 axis1)+--+-- because at the interface of OpenGL and this library there is a transposition+-- to compensate for the different conventions. (This transposition is implicit+-- in the code, because the way the matrices are stored in the memory is also+-- different: OpenGL stores them column-major, and we store them row-major).++class ToOpenGLMatrix m where+ makeGLMatrix :: m -> IO (GLmatrix Flt)++class FromOpenGLMatrix m where+ peekGLMatrix :: GLmatrix Flt -> IO m+ +setMatrix :: ToOpenGLMatrix m => Maybe MatrixMode -> m -> IO ()+setMatrix mode m = makeGLMatrix m >>= \x -> GL.matrix mode $= x+ +getMatrix :: FromOpenGLMatrix m => Maybe MatrixMode -> IO m+getMatrix mode = get (GL.matrix mode) >>= peekGLMatrix++matrix :: (ToOpenGLMatrix m, FromOpenGLMatrix m) => Maybe MatrixMode -> StateVar m+matrix mode = makeStateVar (getMatrix mode) (setMatrix mode)++currentMatrix :: (ToOpenGLMatrix m, FromOpenGLMatrix m) => StateVar m+currentMatrix = matrix Nothing++multMatrix :: ToOpenGLMatrix m => m -> IO ()+multMatrix m = makeGLMatrix m >>= GL.multMatrix++instance ToOpenGLMatrix Mat4 where+ makeGLMatrix m = GL.withNewMatrix GL.ColumnMajor (flip poke m . castPtr) + +instance FromOpenGLMatrix Mat4 where+ -- huh? GL.withMatrix is strange+ peekGLMatrix x = GL.withMatrix x $ \_ p -> peek (castPtr p)+ +instance ToOpenGLMatrix Mat3 where+ makeGLMatrix m = makeGLMatrix (extendWith 1 m :: Mat4)+ +instance ToOpenGLMatrix Mat2 where+ makeGLMatrix m = makeGLMatrix (extendWith 1 m :: Mat4)++instance ToOpenGLMatrix Ortho4 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat4)++instance ToOpenGLMatrix Ortho3 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat3)++instance ToOpenGLMatrix Ortho2 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat2)++instance ToOpenGLMatrix Proj4 where+ makeGLMatrix m = makeGLMatrix (fromProjective m :: Mat4)++instance ToOpenGLMatrix Proj3 where+ makeGLMatrix m = makeGLMatrix (fromProjective m :: Mat3)+ +--------------------------------------------------------------------------------++{-# SPECIALISE radianToDegrees :: Float -> Float #-} {-# SPECIALISE radianToDegrees :: Double -> Double #-} radianToDegrees :: RealFrac a => a -> a radianToDegrees x = x * 57.295779513082322@@ -28,20 +99,61 @@ degreesToRadian x = x * 1.7453292519943295e-2 -- | The angle is in radians. (WARNING: OpenGL uses degrees!)-rotate :: Flt -> Vec3 -> IO ()-rotate angle (Vec3 x y z) = GL.rotate (radianToDegrees angle) (Vector3 x y z)+glRotate :: Flt -> Vec3 -> IO ()+glRotate angle (Vec3 x y z) = GL.rotate (radianToDegrees angle) (Vector3 x y z) -translate :: Vec3 -> IO ()-translate (Vec3 x y z) = GL.translate (Vector3 x y z)+glTranslate :: Vec3 -> IO ()+glTranslate (Vec3 x y z) = GL.translate (Vector3 x y z) -scale3 :: Vec3 -> IO ()-scale3 (Vec3 x y z) = GL.scale x y z+glScale3 :: Vec3 -> IO ()+glScale3 (Vec3 x y z) = GL.scale x y z -scale :: Flt -> IO ()-scale x = GL.scale x x x+glScale :: Flt -> IO ()+glScale x = GL.scale x x x --------------------------------------------------------+--------------------------------------------------------------------------------+ +-- | \"Orthogonal projecton\" matrix, a la OpenGL +-- (the corresponding functionality is removed in OpenGL 3.1)+orthoMatrix + :: (Flt,Flt) -- ^ (left,right)+ -> (Flt,Flt) -- ^ (bottom,top)+ -> (Flt,Flt) -- ^ (near,far)+ -> Mat4 +orthoMatrix (l,r) (b,t) (n,f) = Mat4+ (Vec4 (2/(r-l)) 0 0 0)+ (Vec4 0 (2/(t-b)) 0 0)+ (Vec4 0 0 (-2/(f-n)) 0)+ (Vec4 (-(r+l)/(r-l)) (-(t+b)/(t-b)) (-(f+n)/(f-n)) 1)+ +-- | The same as "orthoMatrix", but with a different parametrization.+orthoMatrix2 {- ' CPP is sensitive to primes -}+ :: Vec3 -- ^ (left,top,near)+ -> Vec3 -- ^ (right,bottom,far)+ -> Mat4 +orthoMatrix2 (Vec3 l t n) (Vec3 r b f) = orthoMatrix (l,r) (b,t) (n,f) +-- | \"Perspective projecton\" matrix, a la OpenGL +-- (the corresponding functionality is removed in OpenGL 3.1).+frustumMatrix+ :: (Flt,Flt) -- ^ (left,right)+ -> (Flt,Flt) -- ^ (bottom,top)+ -> (Flt,Flt) -- ^ (near,far)+ -> Mat4 +frustumMatrix (l,r) (b,t) (n,f) = Mat4+ (Vec4 (2*n/(r-l)) 0 0 0)+ (Vec4 0 (2*n/(t-b)) 0 0)+ (Vec4 ((r+l)/(r-l)) ((t+b)/(t-b)) (-(f+n)/(f-n)) (-1))+ (Vec4 0 0 (-2*f*n*(f-n)) 0)+ +-- | The same as "frustumMatrix", but with a different parametrization.+frustumMatrix2 {- ' CPP is sensitive to primes -}+ :: Vec3 -- ^ (left,top,near)+ -> Vec3 -- ^ (right,bottom,far)+ -> Mat4 +frustumMatrix2 (Vec3 l t n) (Vec3 r b f) = frustumMatrix (l,r) (b,t) (n,f)++-------------------------------------------------------------------------------- -- Vertex instances instance GL.Vertex Vec2 where@@ -56,17 +168,20 @@ vertex (Vec4 x y z w) = GL.vertex (GL.Vertex4 x y z w) vertexv p = peek p >>= vertex ---------------------------------------------------------+-------------------------------------------------------------------------------- -- the Normal instance -- note that there is no Normal2\/Normal4 in the OpenGL binding instance GL.Normal Normal3 where- normal (Normal3 (Vec3 x y z)) = GL.normal (GL.Normal3 x y z)+ normal u = GL.normal (GL.Normal3 x y z) + where Vec3 x y z = fromNormal u normalv p = peek p >>= normal --------------------------------------------------------+instance GL.Normal Vec3 where+ normal (Vec3 x y z) = GL.normal (GL.Normal3 x y z) + normalv p = peek p >>= normal +-------------------------------------------------------------------------------- -- Color instances instance GL.Color Vec3 where@@ -88,8 +203,7 @@ secondaryColorv p = peek p >>= secondaryColor -} ---------------------------------------------------------+-------------------------------------------------------------------------------- -- TexCoord instances instance GL.TexCoord Vec2 where@@ -110,8 +224,7 @@ multiTexCoord unit (Vec4 u v w z) = GL.multiTexCoord unit (GL.TexCoord4 u v w z) multiTexCoordv unit p = peek p >>= multiTexCoord unit --------------------------------------------------------- +-------------------------------------------------------------------------------- -- Vertex Attributes (experimental) class VertexAttrib' a where@@ -130,16 +243,18 @@ vertexAttrib loc (Vec4 x y z w) = GL.vertexAttrib4 loc x y z w instance VertexAttrib' Normal2 where- vertexAttrib loc (Normal2 (Vec2 x y)) = GL.vertexAttrib2 loc x y+ vertexAttrib loc u = GL.vertexAttrib2 loc x y+ where Vec2 x y = fromNormal u instance VertexAttrib' Normal3 where- vertexAttrib loc (Normal3 (Vec3 x y z)) = GL.vertexAttrib3 loc x y z+ vertexAttrib loc u = GL.vertexAttrib3 loc x y z+ where Vec3 x y z = fromNormal u instance VertexAttrib' Normal4 where- vertexAttrib loc (Normal4 (Vec4 x y z w)) = GL.vertexAttrib4 loc x y z w----------------------------------------------------------+ vertexAttrib loc u = GL.vertexAttrib4 loc x y z w+ where Vec4 x y z w = fromNormal u + +-------------------------------------------------------------------------------- -- Uniform (again, experimental) -- (note that the uniform location code in the OpenGL 2.2.1.1 is broken; @@ -181,3 +296,5 @@ uniformv loc cnt ptr = uniformv loc (4*cnt) (castPtr ptr :: Ptr Flt) #endif++
Data/Vect/Double/Util/Dim2.hs view
@@ -4,12 +4,13 @@ import Data.Vect.Flt.Base --- |example: @structVec2 [1,2,3,4] = [ Vec2 1 2 , Vec2 3 4 ]@.+-- | Example: @structVec2 [1,2,3,4] = [ Vec2 1 2 , Vec2 3 4 ]@. structVec2 :: [Flt] -> [Vec2] structVec2 [] = [] structVec2 (x:y:ls) = (Vec2 x y):(structVec2 ls) structVec2 _ = error "structVec2" +-- | The opposite of "structVec2". destructVec2 :: [Vec2] -> [Flt] destructVec2 [] = [] destructVec2 ((Vec2 x y):ls) = x:y:(destructVec2 ls) @@ -49,10 +50,13 @@ angle2' {- ' CPP is sensitive to primes -} :: Normal2 -> Flt angle2' = angle2 . fromNormal --- |Rotation matrix by a given angle (in radians), counterclockwise.+-- | Rotation matrix by a given angle (in radians), counterclockwise. rotMatrix2 :: Flt -> Mat2 rotMatrix2 a = Mat2 (Vec2 c s) (Vec2 (-s) c) where c = cos a; s = sin a +rotMatrixOrtho2 :: Flt -> Ortho2+rotMatrixOrtho2 = toOrthoUnsafe . rotMatrix2+ rotate2 :: Flt -> Vec2 -> Vec2 rotate2 a v = v .* (rotMatrix2 a) @@ -63,3 +67,5 @@ -- |Rotates clockwise by 90 degrees. rotateCW :: Vec2 -> Vec2 rotateCW (Vec2 x y) = Vec2 y (-x)++
Data/Vect/Double/Util/Dim3.hs view
@@ -4,18 +4,26 @@ import Data.Vect.Flt.Base +--------------------------------------------------------------------------------++-- | Example: @structVec3 [1,2,3,4,5,6] = [ Vec3 1 2 3 , Vec3 4 5 6]@. structVec3 :: [Flt] -> [Vec3] structVec3 [] = [] structVec3 (x:y:z:ls) = (Vec3 x y z):(structVec3 ls) structVec3 _ = error "structVec3" +-- | The opposite of "structVec3". destructVec3 :: [Vec3] -> [Flt] destructVec3 [] = [] destructVec3 ((Vec3 x y z):ls) = x:y:z:(destructVec3 ls) +--------------------------------------------------------------------------------+ det3 :: Vec3 -> Vec3 -> Vec3 -> Flt det3 u v w = det (u,v,w) +--------------------------------------------------------------------------------+ translate3X :: Flt -> Vec3 -> Vec3 translate3Y :: Flt -> Vec3 -> Vec3 translate3Z :: Flt -> Vec3 -> Vec3@@ -43,26 +51,34 @@ rotMatrixY a = Mat3 (Vec3 c 0 (-s)) (Vec3 0 1 0) (Vec3 s 0 c) where c = cos a; s = sin a rotMatrixX a = Mat3 (Vec3 1 0 0) (Vec3 0 c s) (Vec3 0 (-s) c) where c = cos a; s = sin a -rotate3' :: {- ' CPP is sensitive to primes -} Flt -- ^ angle (in radians)- -> Normal3 -- ^ axis (should be a /unit/ vector!) - -> Vec3 -- ^ vector- -> Vec3 -- ^ result+--------------------------------------------------------------------------------++rotate3' {- ' CPP is sensitive to primes -} + :: Flt -- ^ angle (in radians)+ -> Normal3 -- ^ axis (should be a /unit/ vector!) + -> Vec3 -- ^ vector+ -> Vec3 -- ^ result rotate3' angle axis v = v .* (rotMatrix3' axis angle) -rotate3 :: Flt -- ^ angle (in radians)- -> Vec3 -- ^ axis (arbitrary nonzero vector)- -> Vec3 -- ^ vector- -> Vec3 -- ^ result+rotate3 + :: Flt -- ^ angle (in radians)+ -> Vec3 -- ^ axis (arbitrary nonzero vector)+ -> Vec3 -- ^ vector+ -> Vec3 -- ^ result rotate3 angle axis v = v .* (rotMatrix3 axis angle) --- |Rotation around an arbitrary 3D vector. The resulting 3x3 matrix is intended for multiplication on the /right/. +-- | Rotation around an arbitrary 3D vector. The resulting 3x3 matrix is intended for multiplication on the /right/. rotMatrix3 :: Vec3 -> Flt -> Mat3 rotMatrix3 v a = rotMatrix3' (mkNormal v) a --- |Rotation around an arbitrary 3D /unit/ vector. The resulting 3x3 matrix is intended for multiplication on the /right/. +rotMatrixOrtho3 :: Vec3 -> Flt -> Ortho3+rotMatrixOrtho3 v a = toOrthoUnsafe $ rotMatrix3 v a++-- | Rotation around an arbitrary 3D /unit/ vector. The resulting 3x3 matrix is intended for multiplication on the /right/. rotMatrix3' :: {- ' CPP is sensitive to primes -} Normal3 -> Flt -> Mat3-rotMatrix3' (Normal3 v) a = - let c = cos a+rotMatrix3' u a = + let v = fromNormal u+ c = cos a s = sin a m1 = scalarMul (1-c) (outer v v) x = _1 v@@ -73,4 +89,65 @@ (Vec3 ( s*y) (-s*x) c ) in (m1 &+ m2) +rotMatrixOrtho3' :: {- ' CPP is sensitive to primes -} Normal3 -> Flt -> Ortho3+rotMatrixOrtho3' u a = toOrthoUnsafe $ rotMatrix3' u a +--------------------------------------------------------------------------------++-- | Reflects a vector to an axis: that is, the result of @reflect n v@ is+-- 2\<n,v\>n - v+reflect :: Normal3 -> Vec3 -> Vec3+reflect u v = (s *& n) &- v where + n = fromNormal u+ s = 2 * (n &. v)++reflect' :: Normal3 -> Normal3 -> Normal3+reflect' u x = toNormalUnsafe $ reflect u (fromNormal x)+ +refract :: Flt -> Normal3 -> Vec3 -> Vec3+refract eta u v = s *& fromNormal w where+ s = norm v + w = refract' eta u (toNormalUnsafe $ v &* (1.0/s))+ +-- | Refraction.+-- First parameter (@eta@) is the relative refraction index +--+-- > refl_inside+-- > eta = --------------+-- > refl_outside+--+-- where \"inside\" is the direction of the second argument +-- (to vector normal to plane which models the boundary +-- between the two materials). That is, total internal reflection+-- can occur when @eta>1@.+--+-- The convention is that the origin is the point of intersection+-- of the ray and the surface, and all the vectors \"point away\"+-- from here (unlike, say, GLSL's @refract@, where the incident+-- vector \"points towards\" the material)+refract' {- ' CPP is sensitive to primes -} + :: Flt -> Normal3 -> Normal3 -> Normal3+refract' eta u i = + if k<0+ then reflect' u i + else toNormalUnsafe $ ((-eta) *& v) &- (- eta*c + sqrt k) *& n + where+ n = fromNormal u+ v = fromNormal i+ c = n &. v+ k = 1 - eta*eta*(1-c*c)++-- | When total internal reflection would occur, we return "Nothing".+refractOnly' {- ' CPP is sensitive to primes -} + :: Flt -> Normal3 -> Normal3 -> Maybe Normal3+refractOnly' eta u i = + if k<0+ then Nothing + else Just $ toNormalUnsafe $ ((-eta) *& v) &- (- eta*c + sqrt k) *& n + where+ n = fromNormal u+ v = fromNormal i+ c = n &. v+ k = 1 - eta*eta*(1-c*c)++--------------------------------------------------------------------------------
Data/Vect/Double/Util/Dim4.hs view
@@ -40,7 +40,7 @@ vec4Z = Vec4 0 0 1 0 vec4W = Vec4 0 0 0 1 ----------------------------------------------------------------------------+-------------------------------------------------------------------------------- -- |If @(x,y,u,v)@ is an orthonormal system, then (written in pseudo-code) -- @biVector4 (x,y) = plusMinus (reverse $ biVector4 (u,v))@.@@ -76,8 +76,9 @@ -- | Rotation matrix around a plane specified by two normalized and /orthogonal/ vectors. -- Intended for multiplication on the /right/! rotMatrix4' :: {- ' CPP is sensitive to primes -} Flt -> (Normal4,Normal4) -> Mat4-rotMatrix4' angle (Normal4 v, Normal4 w) = m1 &+ (s *& m2) &+ m3 +rotMatrix4' angle (u1,u2) = m1 &+ (s *& m2) &+ m3 where+ v = fromNormal u1 ; w = fromNormal u2 c = cos angle ; s = sin angle m1 = scalarMul (1-c) ( outer v v &+ outer w w ) m2 = biVector4AsTensor v w
Data/Vect/Double/Util/Projective.hs view
@@ -1,6 +1,7 @@ {-# OPTIONS_GHC -DFlt=Double -DVECT_Double #-} --- | Classic 4x4 projective matrices. Our convention is that they are intended for multiplication on+-- | Classic 4x4 projective matrices, encoding the affine transformations of R^3.+-- Our convention is that they are intended for multiplication on -- the /right/, that is, they are of the form -- -- > _____@@ -13,6 +14,8 @@ -- store them by rows; but OpenGL also use the opposite convention (so the OpenGL projective matrices -- are intended for multiplication on the /left/). So in effect, they are the same when stored in the memory, -- say with @poke :: Ptr Mat4 -> Mat4 -> IO ()@.+--+-- Warning: The naming conventions will probably change in the future. module Data.Vect.Flt.Util.Projective where @@ -21,68 +24,73 @@ import qualified Data.Vect.Flt.Util.Dim4 as Dim4 -class ExtendProjective v e | v->e where- extendProj :: v -> e- extendProjWith :: Flt -> v -> e- extendProj = extendProjWith 1- -instance ExtendProjective Vec2 Vec4 where- extendProj (Vec2 x y) = Vec4 x y 0 1- extendProjWith w (Vec2 x y) = Vec4 x y 0 w- -instance ExtendProjective Vec3 Vec4 where- extendProj (Vec3 x y z) = Vec4 x y z 1- extendProjWith w (Vec3 x y z) = Vec4 x y z w--instance ExtendProjective Vec4 Vec4 where- extendProj = id- extendProjWith w (Vec4 x y z w') = let s = w/w' in Vec4 (s*x) (s*y) (s*z) w+-------------------------------------------------------------------------------- -instance ExtendProjective Mat2 Mat4 where- extendProj (Mat2 r1 r2) = Mat4 (extendZero r1) (extendZero r2) (Dim4.vec4Z) (Vec4 0 0 0 1)- extendProjWith w (Mat2 r1 r2) = Mat4 (extendZero r1) (extendZero r2) (Dim4.vec4Z) (Vec4 0 0 0 w)+rotMatrixProj4' :: {- ' CPP is sensitive to primes -} Flt -> Normal3 -> Proj4+rotMatrixProj4' angle axis = linear $ rotMatrix3' axis angle -instance ExtendProjective Mat3 Mat4 where- extendProj (Mat3 r1 r2 r3) = Mat4 (extendZero r1) (extendZero r2) (extendZero r3) (Vec4 0 0 0 1)- extendProjWith w (Mat3 r1 r2 r3) = Mat4 (extendZero r1) (extendZero r2) (extendZero r3) (Vec4 0 0 0 w)+rotMatrixProj4 :: Flt -> Vec3 -> Proj4+rotMatrixProj4 angle axis = linear $ rotMatrix3 axis angle -rotMatrixProj :: Flt -> Normal3 -> Mat4-rotMatrixProj angle axis = extendProj $ rotMatrix3' axis angle+-- | synonym for "rotateAfterProj4"+rotateProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateProj4 = rotateAfterProj4 -rotMatrixProj' :: {- ' CPP is sensitive to primes -} Flt -> Vec3 -> Mat4-rotMatrixProj' angle axis = extendProj $ rotMatrix3 axis angle+-- | Synonym for @\m -> m .*. rotMatrixProj4 angle axis@.+rotateAfterProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateAfterProj4 angle axis m = m .*. (rotMatrixProj4' angle axis) -translMatrixProj :: Vec3 -> Mat4-translMatrixProj v = Mat4 Dim4.vec4X Dim4.vec4Y Dim4.vec4Z (extendProj v)+-- | Synonym for @\m -> rotMatrixProj4 angle axis .*. m@.+rotateBeforeProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateBeforeProj4 angle axis m = (rotMatrixProj4' angle axis) .*. m --- | we assume that the bottom-right corner is 1.-translWithProj :: Vec3 -> Mat4 -> Mat4-translWithProj v mat@(Mat4 r1 r2 r3 r4) = Mat4 r1 r2 r3 (extendProjWith 0 v &+ r4)+--------------- -scaleMatrixProj :: Vec3 -> Mat4-scaleMatrixProj v = diag $ extendProj v+--scalingUniformProj3 :: Flt -> Proj3+--scalingUniformProj3 x = scaling (Vec2 x x) -scaleMatrixUniformProj :: Flt -> Mat4-scaleMatrixUniformProj s = diag (Vec4 s s s 1)+scalingUniformProj4 :: Flt -> Proj4+scalingUniformProj4 x = scaling (Vec3 x x x) -class ProjectiveAction v where- actProj :: v -> Mat4 -> v- -instance ProjectiveAction Vec3 where- actProj v m = trim $ (extendProj v) .* m +-- | Equivalent to @\m -> scaling v .*. m@.+scaleBeforeProj4 :: Vec3 -> Proj4 -> Proj4+scaleBeforeProj4 (Vec3 u v w) p4 = + toProjectiveUnsafe $ + Mat4 (u*&a) (v*&b) (w*&c) t+ where+ Mat4 a b c t = fromProjective p4 -instance ProjectiveAction Vec4 where- actProj v m = v .* m +-- | Equivalent to @\m -> m .*. scaling v@.+scaleAfterProj4 :: Vec3 -> Proj4 -> Proj4+scaleAfterProj4 v p4 =+ toProjectiveUnsafe $ + Mat4 (a&!w) (b&!w) (c&!w) (t&!w)+ where+ w = extendWith 1 v+ Mat4 a b c t = fromProjective p4+ +--------------- --- | When acting on unit vectors, we ignore the translation part.-instance ProjectiveAction Normal3 where- actProj (Normal3 v) m = Normal3 (v .* (trim m :: Mat3))+-- | Synonym for "translateAfter4"+translate4 :: Vec3 -> Proj4 -> Proj4+translate4 = translateAfter4 --- | Inverts a projective 4x4 matrix, assuming that the top-left 3x3 part is /orthogonal/,--- and the bottom-right corner is 1.-invertProj :: Mat4 -> Mat4-invertProj mat@(Mat4 u v w t) = - translWithProj t' $ extendProj $ transpose $ (trim mat :: Mat3)+-- | Equivalent to @\m -> m .*. translation v@.+translateAfter4 :: Vec3 -> Proj4 -> Proj4+translateAfter4 v p4 = + toProjectiveUnsafe $+ Mat4 r1 r2 r3 (extendWith 0 v &+ r4) where- t' = Vec3 (- u &. t) (- v &. t) (- w &. t)- + Mat4 r1 r2 r3 r4 = fromProjective p4 ++-- | Equivalent to @\m -> translation v .*. m@.+translateBefore4 :: Vec3 -> Proj4 -> Proj4+translateBefore4 v p4 = + toProjectiveUnsafe $ + Mat4 r1 r2 r3 (extendWith 0 u &+ r4) + where + u = v .* (trim mat :: Mat3) + mat@(Mat4 r1 r2 r3 r4) = fromProjective p4+ +---------------+
Data/Vect/Float/Base.hs view
@@ -1,11 +1,34 @@ {-# OPTIONS_GHC -DFlt=Float -DVECT_Float #-} -module Data.Vect.Flt.Base where+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving #-} +module Data.Vect.Flt.Base+ ( AbelianGroup(..) , vecSum+ , MultSemiGroup(..) , Ring , semigroupProduct+ , LeftModule(..) , RightModule(..)+ , Vector(..) , DotProd(..) , CrossProd(..)+ , normalize , distance , angle , angle'+ , UnitVector(..)+ , Pointwise(..)+ , Extend(..) , HasCoordinates(..) , Dimension(..)+ , Matrix(..) , Tensor(..) , Diagonal (..) , Determinant(..)+ , Orthogonal(..) , Projective(..) , MatrixNorms(..)+ , Vec2(..) , Vec3(..) , Vec4(..)+ , Mat2(..) , Mat3(..) , Mat4(..)+ , Ortho2 , Ortho3 , Ortho4+ , Normal2 , Normal3 , Normal4+ , Proj3 , Proj4+ , mkVec2 , mkVec3 , mkVec4+ , project , project' , projectUnsafe , flipNormal+ , householder, householderOrtho+ )+ where+ import Control.Monad import System.Random import Foreign +-------------------------------------------------------------------------------- -- class declarations class AbelianGroup g where@@ -20,15 +43,17 @@ vecSum :: AbelianGroup g => [g] -> g vecSum l = foldl (&+) zero l -class (AbelianGroup r) => - Ring r where+class MultSemiGroup r where (.*.) :: r -> r -> r one :: r +class (AbelianGroup r, MultSemiGroup r) => Ring r + infixl 7 .*. -ringProduct :: Ring r => [r] -> r-ringProduct l = foldl (.*.) one l+-- was: ringProduct :: Ring r => [r] -> r+semigroupProduct :: MultSemiGroup r => [r] -> r +semigroupProduct l = foldl (.*.) one l class LeftModule r m where lmul :: r -> m -> m@@ -75,7 +100,7 @@ lensqr = normsqr dotprod :: v -> v -> Flt normsqr v = (v &. v) - norm = sqrt.lensqr+ norm = sqrt . lensqr dotprod = (&.) infix 7 &.@@ -112,26 +137,28 @@ fromNormalRadius :: Flt -> u -> v fromNormalRadius t n = t *& fromNormal n --- | projects the first vector onto the direction of the second (unit) vector+-- | Projects the first vector onto the direction of the second (unit) vector project' :: (Vector v, UnitVector v u, DotProd v) => v -> u -> v project' what dir = projectUnsafe what (fromNormal dir) --- | direction (second argument) is assumed to be a /unit/ vector!+-- | Direction (second argument) is assumed to be a /unit/ vector! projectUnsafe :: (Vector v, DotProd v) => v -> v -> v projectUnsafe what dir = what &- dir &* (what &. dir) project :: (Vector v, DotProd v) => v -> v -> v project what dir = what &- dir &* ((what &. dir) / (dir &. dir)) --- | since unit vectors are not a group, we need a separate function.+-- | Since unit vectors are not a group, we need a separate function. flipNormal :: UnitVector v n => n -> n flipNormal = toNormalUnsafe . neg . fromNormal +-- | Cross product class CrossProd v where crossprod :: v -> v -> v (&^) :: v -> v -> v (&^) = crossprod- + +-- | Pointwise multiplication class Pointwise v where pointwise :: v -> v -> v (&!) :: v -> v -> v@@ -166,13 +193,50 @@ "inverse is an involution" forall m. inverse (inverse m) = m #-} +class Matrix m => Orthogonal m o | m->o, o->m where + fromOrtho :: o -> m + toOrthoUnsafe :: m -> o+ +class (AbelianGroup m, Matrix m) => MatrixNorms m where+ frobeniusNorm :: m -> Flt -- ^ the frobenius norm (= euclidean norm in the space of matrices)+ matrixDistance :: m -> m -> Flt -- ^ euclidean distance in the space of matrices+ operatorNorm :: m -> Flt -- ^ (euclidean) operator norm (not implemented yet)+ matrixDistance m n = frobeniusNorm (n &- m)+ operatorNorm = error "operatorNorm: not implemented yet"+ -- | Outer product (could be unified with Diagonal?) class Tensor t v | t->v where outer :: v -> v -> t class Determinant m where det :: m -> Flt - ++class Dimension a where+ dim :: a -> Int+ +-- | Householder matrix, see <http://en.wikipedia.org/wiki/Householder_transformation>. +-- In plain words, it is the reflection to the hyperplane orthogonal to the input vector.+householder :: (Vector v, UnitVector v u, Matrix m, Vector m, Tensor m v) => u -> m+householder u = idmtx &- (2 *& outer v v) + where v = fromNormal u++householderOrtho :: (Vector v, UnitVector v u, Matrix m, Vector m, Tensor m v, Orthogonal m o) => u -> o+householderOrtho = toOrthoUnsafe . householder++-- | \"Projective\" matrices have the following form: the top left corner+-- is an any matrix, the bottom right corner is 1, and the top-right+-- column is zero. These describe the affine orthogonal transformation of+-- the space one dimension less.+class (Vector v, Orthogonal n o, Diagonal v n) => Projective v n o m p + | m->p, p->m, p->o, o->p, p->n, n->p, p->v, v->p, n->o, n->v, v->n where+ fromProjective :: p -> m+ toProjectiveUnsafe :: m -> p+ orthogonal :: o -> p+ linear :: n -> p+ translation :: v -> p+ scaling :: v -> p++-------------------------------------------------------------------------------- -- Vec / Mat datatypes data Vec2 = Vec2 {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt @@ -182,16 +246,16 @@ data Vec4 = Vec4 {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt deriving (Read,Show) --- | these are /row/ vectors +-- | The components are /row/ vectors data Mat2 = Mat2 !Vec2 !Vec2 deriving (Read,Show) data Mat3 = Mat3 !Vec3 !Vec3 !Vec3 deriving (Read,Show) data Mat4 = Mat4 !Vec4 !Vec4 !Vec4 !Vec4 deriving (Read,Show) -- | The assumption when dealing with these is always that they are of unit length. -- Also, interpolation works differently.-newtype Normal2 = Normal2 Vec2 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable) -newtype Normal3 = Normal3 Vec3 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable,CrossProd) -newtype Normal4 = Normal4 Vec4 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable) +newtype Normal2 = Normal2 Vec2 deriving (Read,Show,Storable,DotProd,Dimension) +newtype Normal3 = Normal3 Vec3 deriving (Read,Show,Storable,DotProd,Dimension) +newtype Normal4 = Normal4 Vec4 deriving (Read,Show,Storable,DotProd,Dimension) mkVec2 :: (Flt,Flt) -> Vec2 mkVec3 :: (Flt,Flt,Flt) -> Vec3@@ -201,6 +265,19 @@ mkVec3 (x,y,z) = Vec3 x y z mkVec4 (x,y,z,w) = Vec4 x y z w +-- | Orthogonal matrices.+--+-- Note: the "Random" instances generates orthogonal matrices with determinant 1+-- (that is, orientation-preserving orthogonal transformations)!+newtype Ortho2 = Ortho2 Mat2 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)+newtype Ortho3 = Ortho3 Mat3 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)+newtype Ortho4 = Ortho4 Mat4 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)++-- | Projective matrices, encoding affine transformations in dimension one less.+newtype Proj3 = Proj3 Mat3 deriving (Read,Show,Storable,MultSemiGroup)+newtype Proj4 = Proj4 Mat4 deriving (Read,Show,Storable,MultSemiGroup)++-------------------------------------------------------------------------------- -- Unit vectors instance UnitVector Vec2 Normal2 where@@ -218,47 +295,163 @@ fromNormal (Normal4 v) = v toNormalUnsafe = Normal4 -rndUnit :: (RandomGen g, Random v, Vector v, DotProd v) => g -> (v,g)-rndUnit g = +_rndUnit :: (RandomGen g, Random v, Vector v, DotProd v) => g -> (v,g)+_rndUnit g = if d > 0.01 then ( v &* (1.0/d) , h )- else rndUnit h+ else _rndUnit h where (v,h) = random g d = norm v instance Random Normal2 where- random g = let (v,h) = rndUnit g in (Normal2 v, h) + random g = let (v,h) = _rndUnit g in (Normal2 v, h) randomR _ = random instance Random Normal3 where- random g = let (v,h) = rndUnit g in (Normal3 v, h) + random g = let (v,h) = _rndUnit g in (Normal3 v, h) randomR _ = random instance Random Normal4 where- random g = let (v,h) = rndUnit g in (Normal4 v, h) + random g = let (v,h) = _rndUnit g in (Normal4 v, h) randomR _ = random -{--instance Storable Normal2 where- alignment _ = alignment (undefined::Vec2)- sizeOf _ = sizeOf (undefined::Vec2)- peek p = liftM (\v -> Normal2 v) (peek $ castPtr p)- poke p (Normal2 v) = poke (castPtr p) v - -instance Storable Normal3 where- alignment _ = alignment (undefined::Vec3)- sizeOf _ = sizeOf (undefined::Vec3)- peek p = liftM (\v -> Normal3 v) (peek $ castPtr p)- poke p (Normal3 v) = poke (castPtr p) v +instance CrossProd Normal3 where+ crossprod (Normal3 v) (Normal3 w) = mkNormal (crossprod v w) -instance Storable Normal4 where- alignment _ = alignment (undefined::Vec4)- sizeOf _ = sizeOf (undefined::Vec4)- peek p = liftM (\v -> Normal4 v) (peek $ castPtr p)- poke p (Normal4 v) = poke (castPtr p) v --}+--------------------------------------------------------------------------------+-- Orthogonal matrices +instance Orthogonal Mat2 Ortho2 where+ fromOrtho (Ortho2 o) = o+ toOrthoUnsafe = Ortho2++instance Orthogonal Mat3 Ortho3 where+ fromOrtho (Ortho3 o) = o+ toOrthoUnsafe = Ortho3 ++instance Orthogonal Mat4 Ortho4 where+ fromOrtho (Ortho4 o) = o+ toOrthoUnsafe = Ortho4++------++instance Matrix Ortho2 where+ transpose (Ortho2 o) = Ortho2 (transpose o)+ idmtx = Ortho2 idmtx+ inverse = transpose++instance Matrix Ortho3 where+ transpose (Ortho3 o) = Ortho3 (transpose o)+ idmtx = Ortho3 idmtx+ inverse = transpose++instance Matrix Ortho4 where+ transpose (Ortho4 o) = Ortho4 (transpose o)+ idmtx = Ortho4 idmtx+ inverse = transpose++------++instance Random Ortho2 where+ random g = let (o,h) = _rndOrtho2 g in (toOrthoUnsafe (_flip1stRow2 o), h)+ randomR _ = random++instance Random Ortho3 where+ random g = let (o,h) = _rndOrtho3 g in (toOrthoUnsafe ( o), h)+ randomR _ = random++instance Random Ortho4 where+ random g = let (o,h) = _rndOrtho4 g in (toOrthoUnsafe (_flip1stRow4 o), h)+ randomR _ = random++------++-- determinant will be -1+_rndOrtho2 :: RandomGen g => g -> (Mat2, g)+_rndOrtho2 g = (h2, g1) where+ h2 = householder u2 :: Mat2 + (u2,g1) = random g ++-- generates a uniformly random orthogonal 3x3 matrix +-- /with determinant +1/, with respect to the Haar measure of SO3.+--+-- see Theorem 4 in:+-- Francesco Mezzadri: How to Generate Random Matrices from the Classical Compact Groups +-- Notices of the AMS, May 2007 issue+-- <http://www.ams.org/notices/200705/fea-mezzadri-web.ps>+_rndOrtho3 :: RandomGen g => g -> (Mat3, g) +_rndOrtho3 g = ( (h3 .*. m3), g2) where+ m3 = (extendWith :: Flt -> Mat2 -> Mat3) 1 o2 + h3 = householder u3 :: Mat3+ (u3,g1) = random g+ (o2,g2) = _rndOrtho2 g1++-- determinant will be -1+_rndOrtho4 :: RandomGen g => g -> (Mat4, g) +_rndOrtho4 g = ( (h4 .*. m4), g2) where+ m4 = (extendWith :: Flt -> Mat3 -> Mat4) 1 o3 + h4 = householder u4 :: Mat4+ (u4,g1) = random g+ (o3,g2) = _rndOrtho3 g1++------++_flip1stRow2 :: Mat2 -> Mat2+_flip1stRow2 (Mat2 a b) = Mat2 (neg a) b++_flip1stRow3 :: Mat3 -> Mat3+_flip1stRow3 (Mat3 a b c) = Mat3 (neg a) b c++_flip1stRow4 :: Mat4 -> Mat4+_flip1stRow4 (Mat4 a b c d) = Mat4 (neg a) b c d++--------------------------------------------------------------------------------+-- projective matrices+ +instance Projective Vec2 Mat2 Ortho2 Mat3 Proj3 where+ fromProjective (Proj3 m) = m+ toProjectiveUnsafe = Proj3+ orthogonal = Proj3 . extendWith 1 . fromOrtho+ linear = Proj3 . extendWith 1+ translation v = Proj3 $ Mat3 (Vec3 1 0 0) (Vec3 0 1 0) (extendWith 1 v)+ scaling v = Proj3 $ diag (extendWith 1 v)+ +instance Projective Vec3 Mat3 Ortho3 Mat4 Proj4 where+ fromProjective (Proj4 m) = m+ toProjectiveUnsafe = Proj4+ orthogonal = Proj4 . extendWith 1 . fromOrtho + linear = Proj4 . extendWith 1+ translation v = Proj4 $ Mat4 (Vec4 1 0 0 0) (Vec4 0 1 0 0) (Vec4 0 0 1 0) (extendWith 1 v)+ scaling v = Proj4 $ diag (extendWith 1 v)++instance Matrix Proj3 where+ idmtx = Proj3 idmtx+ transpose (Proj3 m) = Proj3 (transpose m)+ inverse = _invertProj3++instance Matrix Proj4 where+ idmtx = Proj4 idmtx+ transpose (Proj4 m) = Proj4 (transpose m)+ inverse = _invertProj4++_invertProj3 :: Proj3 -> Proj3+_invertProj3 (Proj3 mat@(Mat3 _ _ t)) = + Proj3 $ Mat3 (extendZero a) (extendZero b) (extendWith 1 t') + where+ t' = neg $ (trim t :: Vec2) .* invm2 + invm2@(Mat2 a b) = inverse $ (trim mat :: Mat2)++-- Inverts a projective 4x4 matrix. But you can simply use "inverse" instead.+-- We assume that the bottom-right corner is 1.+_invertProj4 :: Proj4 -> Proj4+_invertProj4 (Proj4 mat@(Mat4 _ _ _ t)) = + Proj4 $ Mat4 (extendZero a) (extendZero b) (extendZero c) (extendWith 1 t') + where+ t' = neg $ (trim t :: Vec3) .* invm3 + invm3@(Mat3 a b c) = inverse $ (trim mat :: Mat3)++-------------------------------------------------------------------------------- -- Vec2 instances instance HasCoordinates Vec2 Flt where@@ -314,7 +507,10 @@ k = sizeOf (undefined::Flt) poke p x pokeByteOff p k y- ++instance Dimension Vec2 where dim _ = 2++-------------------------------------------------------------------------------- -- Mat2 instances instance HasCoordinates Mat2 Vec2 where@@ -336,19 +532,21 @@ (&+) (Mat2 r1 r2) (Mat2 s1 s2) = Mat2 (r1 &+ s1) (r2 &+ s2) (&-) (Mat2 r1 r2) (Mat2 s1 s2) = Mat2 (r1 &- s1) (r2 &- s2) neg (Mat2 r1 r2) = Mat2 (neg r1) (neg r2) - zero = Mat2 zero zero -- (zero::Vec2) (zero::Vec2)-+ zero = Mat2 zero zero + instance Vector Mat2 where scalarMul s (Mat2 r1 r2) = Mat2 (g r1) (g r2) where g = scalarMul s mapVec f (Mat2 r1 r2) = Mat2 (g r1) (g r2) where g = mapVec f -instance Ring Mat2 where+instance MultSemiGroup Mat2 where (.*.) (Mat2 r1 r2) n = let (Mat2 c1 c2) = transpose n in Mat2 (Vec2 (r1 &. c1) (r1 &. c2)) (Vec2 (r2 &. c1) (r2 &. c2)) one = idmtx +instance Ring Mat2+ instance LeftModule Mat2 Vec2 where lmul (Mat2 row1 row2) v = Vec2 (row1 &. v) (row2 &. v) @@ -362,11 +560,6 @@ outer (Vec2 a b) (Vec2 x y) = Mat2 (Vec2 (a*x) (a*y)) (Vec2 (b*x) (b*y))-{-- outer v w = - let full = Mat2 (Vec2 1 1) (Vec2 1 1)- in (diag v) .*. full .*. (diag w)--} instance Determinant Mat2 where det (Mat2 (Vec2 a b) (Vec2 c d)) = a*d - b*c @@ -393,6 +586,24 @@ poke p r1 pokeByteOff p k r2 +instance Random Mat2 where+ random = randomR (Mat2 v1 v1 , Mat2 v2 v2) where + v1 = Vec2 (-1) (-1) + v2 = Vec2 1 1+ randomR (Mat2 a b, Mat2 c d) gen = + let (x,gen1) = randomR (a,c) gen+ (y,gen2) = randomR (b,d) gen1+ in (Mat2 x y, gen2)+ +instance Dimension Mat2 where dim _ = 2+ +instance MatrixNorms Mat2 where + frobeniusNorm (Mat2 r1 r2) = + sqrt $+ normsqr r1 + + normsqr r2+ +-------------------------------------------------------------------------------- -- Vec3 instances instance HasCoordinates Vec3 Flt where@@ -454,7 +665,10 @@ poke p x pokeByteOff p (k ) y pokeByteOff p (k+k) z- ++instance Dimension Vec3 where dim _ = 3++-------------------------------------------------------------------------------- -- Mat3 instances instance HasCoordinates Mat3 Vec3 where@@ -495,13 +709,13 @@ (&+) (Mat3 r1 r2 r3) (Mat3 s1 s2 s3) = Mat3 (r1 &+ s1) (r2 &+ s2) (r3 &+ s3) (&-) (Mat3 r1 r2 r3) (Mat3 s1 s2 s3) = Mat3 (r1 &- s1) (r2 &- s2) (r3 &- s3) neg (Mat3 r1 r2 r3) = Mat3 (neg r1) (neg r2) (neg r3) - zero = Mat3 zero zero zero -- (zero::Vec3) (zero::Vec3) (zero::Vec3)+ zero = Mat3 zero zero zero instance Vector Mat3 where scalarMul s (Mat3 r1 r2 r3) = Mat3 (g r1) (g r2) (g r3) where g = scalarMul s mapVec f (Mat3 r1 r2 r3) = Mat3 (g r1) (g r2) (g r3) where g = mapVec f -instance Ring Mat3 where+instance MultSemiGroup Mat3 where (.*.) (Mat3 r1 r2 r3) n = let (Mat3 c1 c2 c3) = transpose n in Mat3 (Vec3 (r1 &. c1) (r1 &. c2) (r1 &. c3))@@ -509,6 +723,8 @@ (Vec3 (r3 &. c1) (r3 &. c2) (r3 &. c3)) one = idmtx +instance Ring Mat3+ instance LeftModule Mat3 Vec3 where lmul (Mat3 row1 row2 row3) v = Vec3 (row1 &. v) (row2 &. v) (row3 &. v) @@ -523,11 +739,6 @@ (Vec3 (a*x) (a*y) (a*z)) (Vec3 (b*x) (b*y) (b*z)) (Vec3 (c*x) (c*y) (c*z))-{-- outer v w = - let full = Mat3 (Vec3 1 1 1) (Vec3 1 1 1) (Vec3 1 1 1)- in (diag v) .*. full .*. (diag w)--} instance Determinant Mat3 where det (Mat3 r1 r2 r3) = det (r1,r2,r3)@@ -556,6 +767,26 @@ pokeByteOff p (k ) r2 pokeByteOff p (k+k) r3 +instance Random Mat3 where+ random = randomR (Mat3 v1 v1 v1 , Mat3 v2 v2 v2) where+ v1 = Vec3 (-1) (-1) (-1)+ v2 = Vec3 1 1 1+ randomR (Mat3 a b c, Mat3 d e f) gen = + let (x,gen1) = randomR (a,d) gen+ (y,gen2) = randomR (b,e) gen1+ (z,gen3) = randomR (c,f) gen2 + in (Mat3 x y z, gen3)+ +instance Dimension Mat3 where dim _ = 3+ +instance MatrixNorms Mat3 where + frobeniusNorm (Mat3 r1 r2 r3) = + sqrt $+ normsqr r1 + + normsqr r2 + + normsqr r3 + +-------------------------------------------------------------------------------- -- Vec4 instances instance HasCoordinates Vec4 Flt where@@ -615,6 +846,9 @@ pokeByteOff p (k+k) z pokeByteOff p (3*k) w +instance Dimension Vec4 where dim _ = 4++-------------------------------------------------------------------------------- -- Mat4 instances instance HasCoordinates Mat4 Vec4 where@@ -642,7 +876,7 @@ scalarMul s (Mat4 r1 r2 r3 r4) = Mat4 (g r1) (g r2) (g r3) (g r4) where g = scalarMul s mapVec f (Mat4 r1 r2 r3 r4) = Mat4 (g r1) (g r2) (g r3) (g r4) where g = mapVec f -instance Ring Mat4 where+instance MultSemiGroup Mat4 where (.*.) (Mat4 r1 r2 r3 r4) n = let (Mat4 c1 c2 c3 c4) = transpose n in Mat4 (Vec4 (r1 &. c1) (r1 &. c2) (r1 &. c3) (r1 &. c4))@@ -651,6 +885,8 @@ (Vec4 (r4 &. c1) (r4 &. c2) (r4 &. c3) (r4 &. c4)) one = idmtx +instance Ring Mat4+ instance LeftModule Mat4 Vec4 where lmul (Mat4 row1 row2 row3 row4) v = Vec4 (row1 &. v) (row2 &. v) (row3 &. v) (row4 &. v) @@ -666,14 +902,10 @@ (Vec4 (b*x) (b*y) (b*z) (b*w)) (Vec4 (c*x) (c*y) (c*z) (c*w)) (Vec4 (d*x) (d*y) (d*z) (d*w))-{-- outer v w = - let full = Mat4 (Vec4 1 1 1 1) (Vec4 1 1 1 1) (Vec4 1 1 1 1) (Vec4 1 1 1 1)- in (diag v) .*. full .*. (diag w)--} ---instance Determinant Mat4 where--- det (Mat4 r1 r2 r3 r4)+instance Determinant Mat4 where+ det = error "det/Mat4: not implemented yet" + -- det (Mat4 r1 r2 r3 r4) = {- instance Show Mat4 where@@ -701,6 +933,28 @@ pokeByteOff p (k+k) r3 pokeByteOff p (3*k) r4 +instance Random Mat4 where+ random = randomR (Mat4 v1 v1 v1 v1, Mat4 v2 v2 v2 v2) where+ v1 = Vec4 (-1) (-1) (-1) (-1)+ v2 = Vec4 1 1 1 1+ randomR (Mat4 a b c d, Mat4 e f g h) gen = + let (x,gen1) = randomR (a,e) gen+ (y,gen2) = randomR (b,f) gen1+ (z,gen3) = randomR (c,g) gen2 + (w,gen4) = randomR (d,h) gen3 + in (Mat4 x y z w, gen4)+ +instance Dimension Mat4 where dim _ = 4+ +instance MatrixNorms Mat4 where + frobeniusNorm (Mat4 r1 r2 r3 r4) = + sqrt $+ normsqr r1 + + normsqr r2 + + normsqr r3 + + normsqr r4 + +-------------------------------------------------------------------------------- -- Extend instances instance Extend Vec2 Vec3 where@@ -719,17 +973,20 @@ trim (Vec4 x y z _) = Vec3 x y z instance Extend Mat2 Mat3 where- extendZero (Mat2 p q) = Mat3 (extendZero p) (extendZero q) zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat2 p q) = Mat3 (extendZero p) (extendZero q) zero+ extendWith w (Mat2 p q) = Mat3 (extendZero p) (extendZero q) (Vec3 0 0 w) trim (Mat3 p q _) = Mat2 (trim p) (trim q) instance Extend Mat2 Mat4 where- extendZero (Mat2 p q) = Mat4 (extendZero p) (extendZero q) zero zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat2 p q) = Mat4 (extendZero p) (extendZero q) zero zero+ extendWith w (Mat2 p q) = Mat4 (extendZero p) (extendZero q) (Vec4 0 0 w 0) (Vec4 0 0 0 w) trim (Mat4 p q _ _) = Mat2 (trim p) (trim q) instance Extend Mat3 Mat4 where- extendZero (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) zero+ extendWith w (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) (Vec4 0 0 0 w) trim (Mat4 p q r _) = Mat3 (trim p) (trim q) (trim r)+ +--------------------------------------------------------------------------------+
Data/Vect/Float/GramSchmidt.hs view
@@ -10,7 +10,7 @@ import Data.Vect.Flt.Base --------------------------------------------------------+-------------------------------------------------------------------------------- liftPair :: (a -> b) -> (a,a) -> (b,b) liftPair f (x,y) = (f x, f y)@@ -21,7 +21,7 @@ liftQuadruple :: (a -> b) -> (a,a,a,a) -> (b,b,b,b) liftQuadruple f (x,y,z,w) = (f x, f y, f z, f w) --------------------------------------------------------+-------------------------------------------------------------------------------- -- | produces orthogonal\/orthonormal vectors from a set of vectors class GramSchmidt a where@@ -33,7 +33,7 @@ "gramSchmidtNormalize is idempotent" forall a. gramSchmidtNormalize (gramSchmidtNormalize a) = gramSchmidtNormalize a #-} --------------------------------------------------------+-------------------------------------------------------------------------------- instance GramSchmidt (Vec2,Vec2) where gramSchmidt = gramSchmidtPair
Data/Vect/Float/OpenGL.hs view
@@ -3,21 +3,92 @@ -- TODO: the pointer versions of these functions should be really implemented -- via the pointer versions of the original opengl functions... --- | OpenGL support, inclduing 'vertex', 'texCoord', etc instances for 'Vec2', 'Vec3' and 'Vec4'.+-- | OpenGL support, including 'Vertex', 'TexCoord', etc instances for 'Vec2', 'Vec3' and 'Vec4'. module Data.Vect.Flt.OpenGL where import Control.Monad import Data.Vect.Flt.Base+import Data.Vect.Flt.Util.Projective import qualified Graphics.Rendering.OpenGL as GL import Foreign -import Graphics.Rendering.OpenGL hiding (Normal3,rotate,translate,scale)+import Graphics.Rendering.OpenGL hiding + ( Normal3 , rotate , translate , scale+ , matrix , currentMatrix , withMatrix , multMatrix + ) --------------------------------------------------------+-------------------------------------------------------------------------------- -{-# SPECIALISE radianToDegrees :: Float -> Float #-}+-- | There should be a big warning here about the different conventions, +-- hidden transpositions, and all the confusion this will inevitably cause...+--+-- As it stands, +--+-- > glRotate t1 axis1 >> glRotate t2 axis2 >> glRotate t3 axis3+-- +-- has the same result as+--+-- > multMatrix (rotMatrixProj4 t3 axis3 .*. rotMatrixProj4 t2 axis2 .*. rotMatrixProj4 t1 axis1)+--+-- because at the interface of OpenGL and this library there is a transposition+-- to compensate for the different conventions. (This transposition is implicit+-- in the code, because the way the matrices are stored in the memory is also+-- different: OpenGL stores them column-major, and we store them row-major).++class ToOpenGLMatrix m where+ makeGLMatrix :: m -> IO (GLmatrix Flt)++class FromOpenGLMatrix m where+ peekGLMatrix :: GLmatrix Flt -> IO m+ +setMatrix :: ToOpenGLMatrix m => Maybe MatrixMode -> m -> IO ()+setMatrix mode m = makeGLMatrix m >>= \x -> GL.matrix mode $= x+ +getMatrix :: FromOpenGLMatrix m => Maybe MatrixMode -> IO m+getMatrix mode = get (GL.matrix mode) >>= peekGLMatrix++matrix :: (ToOpenGLMatrix m, FromOpenGLMatrix m) => Maybe MatrixMode -> StateVar m+matrix mode = makeStateVar (getMatrix mode) (setMatrix mode)++currentMatrix :: (ToOpenGLMatrix m, FromOpenGLMatrix m) => StateVar m+currentMatrix = matrix Nothing++multMatrix :: ToOpenGLMatrix m => m -> IO ()+multMatrix m = makeGLMatrix m >>= GL.multMatrix++instance ToOpenGLMatrix Mat4 where+ makeGLMatrix m = GL.withNewMatrix GL.ColumnMajor (flip poke m . castPtr) + +instance FromOpenGLMatrix Mat4 where+ -- huh? GL.withMatrix is strange+ peekGLMatrix x = GL.withMatrix x $ \_ p -> peek (castPtr p)+ +instance ToOpenGLMatrix Mat3 where+ makeGLMatrix m = makeGLMatrix (extendWith 1 m :: Mat4)+ +instance ToOpenGLMatrix Mat2 where+ makeGLMatrix m = makeGLMatrix (extendWith 1 m :: Mat4)++instance ToOpenGLMatrix Ortho4 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat4)++instance ToOpenGLMatrix Ortho3 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat3)++instance ToOpenGLMatrix Ortho2 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat2)++instance ToOpenGLMatrix Proj4 where+ makeGLMatrix m = makeGLMatrix (fromProjective m :: Mat4)++instance ToOpenGLMatrix Proj3 where+ makeGLMatrix m = makeGLMatrix (fromProjective m :: Mat3)+ +--------------------------------------------------------------------------------++{-# SPECIALISE radianToDegrees :: Float -> Float #-} {-# SPECIALISE radianToDegrees :: Double -> Double #-} radianToDegrees :: RealFrac a => a -> a radianToDegrees x = x * 57.295779513082322@@ -28,20 +99,61 @@ degreesToRadian x = x * 1.7453292519943295e-2 -- | The angle is in radians. (WARNING: OpenGL uses degrees!)-rotate :: Flt -> Vec3 -> IO ()-rotate angle (Vec3 x y z) = GL.rotate (radianToDegrees angle) (Vector3 x y z)+glRotate :: Flt -> Vec3 -> IO ()+glRotate angle (Vec3 x y z) = GL.rotate (radianToDegrees angle) (Vector3 x y z) -translate :: Vec3 -> IO ()-translate (Vec3 x y z) = GL.translate (Vector3 x y z)+glTranslate :: Vec3 -> IO ()+glTranslate (Vec3 x y z) = GL.translate (Vector3 x y z) -scale3 :: Vec3 -> IO ()-scale3 (Vec3 x y z) = GL.scale x y z+glScale3 :: Vec3 -> IO ()+glScale3 (Vec3 x y z) = GL.scale x y z -scale :: Flt -> IO ()-scale x = GL.scale x x x+glScale :: Flt -> IO ()+glScale x = GL.scale x x x --------------------------------------------------------+--------------------------------------------------------------------------------+ +-- | \"Orthogonal projecton\" matrix, a la OpenGL +-- (the corresponding functionality is removed in OpenGL 3.1)+orthoMatrix + :: (Flt,Flt) -- ^ (left,right)+ -> (Flt,Flt) -- ^ (bottom,top)+ -> (Flt,Flt) -- ^ (near,far)+ -> Mat4 +orthoMatrix (l,r) (b,t) (n,f) = Mat4+ (Vec4 (2/(r-l)) 0 0 0)+ (Vec4 0 (2/(t-b)) 0 0)+ (Vec4 0 0 (-2/(f-n)) 0)+ (Vec4 (-(r+l)/(r-l)) (-(t+b)/(t-b)) (-(f+n)/(f-n)) 1)+ +-- | The same as "orthoMatrix", but with a different parametrization.+orthoMatrix2 {- ' CPP is sensitive to primes -}+ :: Vec3 -- ^ (left,top,near)+ -> Vec3 -- ^ (right,bottom,far)+ -> Mat4 +orthoMatrix2 (Vec3 l t n) (Vec3 r b f) = orthoMatrix (l,r) (b,t) (n,f) +-- | \"Perspective projecton\" matrix, a la OpenGL +-- (the corresponding functionality is removed in OpenGL 3.1).+frustumMatrix+ :: (Flt,Flt) -- ^ (left,right)+ -> (Flt,Flt) -- ^ (bottom,top)+ -> (Flt,Flt) -- ^ (near,far)+ -> Mat4 +frustumMatrix (l,r) (b,t) (n,f) = Mat4+ (Vec4 (2*n/(r-l)) 0 0 0)+ (Vec4 0 (2*n/(t-b)) 0 0)+ (Vec4 ((r+l)/(r-l)) ((t+b)/(t-b)) (-(f+n)/(f-n)) (-1))+ (Vec4 0 0 (-2*f*n*(f-n)) 0)+ +-- | The same as "frustumMatrix", but with a different parametrization.+frustumMatrix2 {- ' CPP is sensitive to primes -}+ :: Vec3 -- ^ (left,top,near)+ -> Vec3 -- ^ (right,bottom,far)+ -> Mat4 +frustumMatrix2 (Vec3 l t n) (Vec3 r b f) = frustumMatrix (l,r) (b,t) (n,f)++-------------------------------------------------------------------------------- -- Vertex instances instance GL.Vertex Vec2 where@@ -56,17 +168,20 @@ vertex (Vec4 x y z w) = GL.vertex (GL.Vertex4 x y z w) vertexv p = peek p >>= vertex ---------------------------------------------------------+-------------------------------------------------------------------------------- -- the Normal instance -- note that there is no Normal2\/Normal4 in the OpenGL binding instance GL.Normal Normal3 where- normal (Normal3 (Vec3 x y z)) = GL.normal (GL.Normal3 x y z)+ normal u = GL.normal (GL.Normal3 x y z) + where Vec3 x y z = fromNormal u normalv p = peek p >>= normal --------------------------------------------------------+instance GL.Normal Vec3 where+ normal (Vec3 x y z) = GL.normal (GL.Normal3 x y z) + normalv p = peek p >>= normal +-------------------------------------------------------------------------------- -- Color instances instance GL.Color Vec3 where@@ -88,8 +203,7 @@ secondaryColorv p = peek p >>= secondaryColor -} ---------------------------------------------------------+-------------------------------------------------------------------------------- -- TexCoord instances instance GL.TexCoord Vec2 where@@ -110,8 +224,7 @@ multiTexCoord unit (Vec4 u v w z) = GL.multiTexCoord unit (GL.TexCoord4 u v w z) multiTexCoordv unit p = peek p >>= multiTexCoord unit --------------------------------------------------------- +-------------------------------------------------------------------------------- -- Vertex Attributes (experimental) class VertexAttrib' a where@@ -130,16 +243,18 @@ vertexAttrib loc (Vec4 x y z w) = GL.vertexAttrib4 loc x y z w instance VertexAttrib' Normal2 where- vertexAttrib loc (Normal2 (Vec2 x y)) = GL.vertexAttrib2 loc x y+ vertexAttrib loc u = GL.vertexAttrib2 loc x y+ where Vec2 x y = fromNormal u instance VertexAttrib' Normal3 where- vertexAttrib loc (Normal3 (Vec3 x y z)) = GL.vertexAttrib3 loc x y z+ vertexAttrib loc u = GL.vertexAttrib3 loc x y z+ where Vec3 x y z = fromNormal u instance VertexAttrib' Normal4 where- vertexAttrib loc (Normal4 (Vec4 x y z w)) = GL.vertexAttrib4 loc x y z w----------------------------------------------------------+ vertexAttrib loc u = GL.vertexAttrib4 loc x y z w+ where Vec4 x y z w = fromNormal u + +-------------------------------------------------------------------------------- -- Uniform (again, experimental) -- (note that the uniform location code in the OpenGL 2.2.1.1 is broken; @@ -181,3 +296,5 @@ uniformv loc cnt ptr = uniformv loc (4*cnt) (castPtr ptr :: Ptr Flt) #endif++
Data/Vect/Float/Util/Dim2.hs view
@@ -4,12 +4,13 @@ import Data.Vect.Flt.Base --- |example: @structVec2 [1,2,3,4] = [ Vec2 1 2 , Vec2 3 4 ]@.+-- | Example: @structVec2 [1,2,3,4] = [ Vec2 1 2 , Vec2 3 4 ]@. structVec2 :: [Flt] -> [Vec2] structVec2 [] = [] structVec2 (x:y:ls) = (Vec2 x y):(structVec2 ls) structVec2 _ = error "structVec2" +-- | The opposite of "structVec2". destructVec2 :: [Vec2] -> [Flt] destructVec2 [] = [] destructVec2 ((Vec2 x y):ls) = x:y:(destructVec2 ls) @@ -49,10 +50,13 @@ angle2' {- ' CPP is sensitive to primes -} :: Normal2 -> Flt angle2' = angle2 . fromNormal --- |Rotation matrix by a given angle (in radians), counterclockwise.+-- | Rotation matrix by a given angle (in radians), counterclockwise. rotMatrix2 :: Flt -> Mat2 rotMatrix2 a = Mat2 (Vec2 c s) (Vec2 (-s) c) where c = cos a; s = sin a +rotMatrixOrtho2 :: Flt -> Ortho2+rotMatrixOrtho2 = toOrthoUnsafe . rotMatrix2+ rotate2 :: Flt -> Vec2 -> Vec2 rotate2 a v = v .* (rotMatrix2 a) @@ -63,3 +67,5 @@ -- |Rotates clockwise by 90 degrees. rotateCW :: Vec2 -> Vec2 rotateCW (Vec2 x y) = Vec2 y (-x)++
Data/Vect/Float/Util/Dim3.hs view
@@ -4,18 +4,26 @@ import Data.Vect.Flt.Base +--------------------------------------------------------------------------------++-- | Example: @structVec3 [1,2,3,4,5,6] = [ Vec3 1 2 3 , Vec3 4 5 6]@. structVec3 :: [Flt] -> [Vec3] structVec3 [] = [] structVec3 (x:y:z:ls) = (Vec3 x y z):(structVec3 ls) structVec3 _ = error "structVec3" +-- | The opposite of "structVec3". destructVec3 :: [Vec3] -> [Flt] destructVec3 [] = [] destructVec3 ((Vec3 x y z):ls) = x:y:z:(destructVec3 ls) +--------------------------------------------------------------------------------+ det3 :: Vec3 -> Vec3 -> Vec3 -> Flt det3 u v w = det (u,v,w) +--------------------------------------------------------------------------------+ translate3X :: Flt -> Vec3 -> Vec3 translate3Y :: Flt -> Vec3 -> Vec3 translate3Z :: Flt -> Vec3 -> Vec3@@ -43,26 +51,34 @@ rotMatrixY a = Mat3 (Vec3 c 0 (-s)) (Vec3 0 1 0) (Vec3 s 0 c) where c = cos a; s = sin a rotMatrixX a = Mat3 (Vec3 1 0 0) (Vec3 0 c s) (Vec3 0 (-s) c) where c = cos a; s = sin a -rotate3' :: {- ' CPP is sensitive to primes -} Flt -- ^ angle (in radians)- -> Normal3 -- ^ axis (should be a /unit/ vector!) - -> Vec3 -- ^ vector- -> Vec3 -- ^ result+--------------------------------------------------------------------------------++rotate3' {- ' CPP is sensitive to primes -} + :: Flt -- ^ angle (in radians)+ -> Normal3 -- ^ axis (should be a /unit/ vector!) + -> Vec3 -- ^ vector+ -> Vec3 -- ^ result rotate3' angle axis v = v .* (rotMatrix3' axis angle) -rotate3 :: Flt -- ^ angle (in radians)- -> Vec3 -- ^ axis (arbitrary nonzero vector)- -> Vec3 -- ^ vector- -> Vec3 -- ^ result+rotate3 + :: Flt -- ^ angle (in radians)+ -> Vec3 -- ^ axis (arbitrary nonzero vector)+ -> Vec3 -- ^ vector+ -> Vec3 -- ^ result rotate3 angle axis v = v .* (rotMatrix3 axis angle) --- |Rotation around an arbitrary 3D vector. The resulting 3x3 matrix is intended for multiplication on the /right/. +-- | Rotation around an arbitrary 3D vector. The resulting 3x3 matrix is intended for multiplication on the /right/. rotMatrix3 :: Vec3 -> Flt -> Mat3 rotMatrix3 v a = rotMatrix3' (mkNormal v) a --- |Rotation around an arbitrary 3D /unit/ vector. The resulting 3x3 matrix is intended for multiplication on the /right/. +rotMatrixOrtho3 :: Vec3 -> Flt -> Ortho3+rotMatrixOrtho3 v a = toOrthoUnsafe $ rotMatrix3 v a++-- | Rotation around an arbitrary 3D /unit/ vector. The resulting 3x3 matrix is intended for multiplication on the /right/. rotMatrix3' :: {- ' CPP is sensitive to primes -} Normal3 -> Flt -> Mat3-rotMatrix3' (Normal3 v) a = - let c = cos a+rotMatrix3' u a = + let v = fromNormal u+ c = cos a s = sin a m1 = scalarMul (1-c) (outer v v) x = _1 v@@ -73,4 +89,65 @@ (Vec3 ( s*y) (-s*x) c ) in (m1 &+ m2) +rotMatrixOrtho3' :: {- ' CPP is sensitive to primes -} Normal3 -> Flt -> Ortho3+rotMatrixOrtho3' u a = toOrthoUnsafe $ rotMatrix3' u a +--------------------------------------------------------------------------------++-- | Reflects a vector to an axis: that is, the result of @reflect n v@ is+-- 2\<n,v\>n - v+reflect :: Normal3 -> Vec3 -> Vec3+reflect u v = (s *& n) &- v where + n = fromNormal u+ s = 2 * (n &. v)++reflect' :: Normal3 -> Normal3 -> Normal3+reflect' u x = toNormalUnsafe $ reflect u (fromNormal x)+ +refract :: Flt -> Normal3 -> Vec3 -> Vec3+refract eta u v = s *& fromNormal w where+ s = norm v + w = refract' eta u (toNormalUnsafe $ v &* (1.0/s))+ +-- | Refraction.+-- First parameter (@eta@) is the relative refraction index +--+-- > refl_inside+-- > eta = --------------+-- > refl_outside+--+-- where \"inside\" is the direction of the second argument +-- (to vector normal to plane which models the boundary +-- between the two materials). That is, total internal reflection+-- can occur when @eta>1@.+--+-- The convention is that the origin is the point of intersection+-- of the ray and the surface, and all the vectors \"point away\"+-- from here (unlike, say, GLSL's @refract@, where the incident+-- vector \"points towards\" the material)+refract' {- ' CPP is sensitive to primes -} + :: Flt -> Normal3 -> Normal3 -> Normal3+refract' eta u i = + if k<0+ then reflect' u i + else toNormalUnsafe $ ((-eta) *& v) &- (- eta*c + sqrt k) *& n + where+ n = fromNormal u+ v = fromNormal i+ c = n &. v+ k = 1 - eta*eta*(1-c*c)++-- | When total internal reflection would occur, we return "Nothing".+refractOnly' {- ' CPP is sensitive to primes -} + :: Flt -> Normal3 -> Normal3 -> Maybe Normal3+refractOnly' eta u i = + if k<0+ then Nothing + else Just $ toNormalUnsafe $ ((-eta) *& v) &- (- eta*c + sqrt k) *& n + where+ n = fromNormal u+ v = fromNormal i+ c = n &. v+ k = 1 - eta*eta*(1-c*c)++--------------------------------------------------------------------------------
Data/Vect/Float/Util/Dim4.hs view
@@ -40,7 +40,7 @@ vec4Z = Vec4 0 0 1 0 vec4W = Vec4 0 0 0 1 ----------------------------------------------------------------------------+-------------------------------------------------------------------------------- -- |If @(x,y,u,v)@ is an orthonormal system, then (written in pseudo-code) -- @biVector4 (x,y) = plusMinus (reverse $ biVector4 (u,v))@.@@ -76,8 +76,9 @@ -- | Rotation matrix around a plane specified by two normalized and /orthogonal/ vectors. -- Intended for multiplication on the /right/! rotMatrix4' :: {- ' CPP is sensitive to primes -} Flt -> (Normal4,Normal4) -> Mat4-rotMatrix4' angle (Normal4 v, Normal4 w) = m1 &+ (s *& m2) &+ m3 +rotMatrix4' angle (u1,u2) = m1 &+ (s *& m2) &+ m3 where+ v = fromNormal u1 ; w = fromNormal u2 c = cos angle ; s = sin angle m1 = scalarMul (1-c) ( outer v v &+ outer w w ) m2 = biVector4AsTensor v w
Data/Vect/Float/Util/Projective.hs view
@@ -1,6 +1,7 @@ {-# OPTIONS_GHC -DFlt=Float -DVECT_Float #-} --- | Classic 4x4 projective matrices. Our convention is that they are intended for multiplication on+-- | Classic 4x4 projective matrices, encoding the affine transformations of R^3.+-- Our convention is that they are intended for multiplication on -- the /right/, that is, they are of the form -- -- > _____@@ -13,6 +14,8 @@ -- store them by rows; but OpenGL also use the opposite convention (so the OpenGL projective matrices -- are intended for multiplication on the /left/). So in effect, they are the same when stored in the memory, -- say with @poke :: Ptr Mat4 -> Mat4 -> IO ()@.+--+-- Warning: The naming conventions will probably change in the future. module Data.Vect.Flt.Util.Projective where @@ -21,68 +24,73 @@ import qualified Data.Vect.Flt.Util.Dim4 as Dim4 -class ExtendProjective v e | v->e where- extendProj :: v -> e- extendProjWith :: Flt -> v -> e- extendProj = extendProjWith 1- -instance ExtendProjective Vec2 Vec4 where- extendProj (Vec2 x y) = Vec4 x y 0 1- extendProjWith w (Vec2 x y) = Vec4 x y 0 w- -instance ExtendProjective Vec3 Vec4 where- extendProj (Vec3 x y z) = Vec4 x y z 1- extendProjWith w (Vec3 x y z) = Vec4 x y z w--instance ExtendProjective Vec4 Vec4 where- extendProj = id- extendProjWith w (Vec4 x y z w') = let s = w/w' in Vec4 (s*x) (s*y) (s*z) w+-------------------------------------------------------------------------------- -instance ExtendProjective Mat2 Mat4 where- extendProj (Mat2 r1 r2) = Mat4 (extendZero r1) (extendZero r2) (Dim4.vec4Z) (Vec4 0 0 0 1)- extendProjWith w (Mat2 r1 r2) = Mat4 (extendZero r1) (extendZero r2) (Dim4.vec4Z) (Vec4 0 0 0 w)+rotMatrixProj4' :: {- ' CPP is sensitive to primes -} Flt -> Normal3 -> Proj4+rotMatrixProj4' angle axis = linear $ rotMatrix3' axis angle -instance ExtendProjective Mat3 Mat4 where- extendProj (Mat3 r1 r2 r3) = Mat4 (extendZero r1) (extendZero r2) (extendZero r3) (Vec4 0 0 0 1)- extendProjWith w (Mat3 r1 r2 r3) = Mat4 (extendZero r1) (extendZero r2) (extendZero r3) (Vec4 0 0 0 w)+rotMatrixProj4 :: Flt -> Vec3 -> Proj4+rotMatrixProj4 angle axis = linear $ rotMatrix3 axis angle -rotMatrixProj :: Flt -> Normal3 -> Mat4-rotMatrixProj angle axis = extendProj $ rotMatrix3' axis angle+-- | synonym for "rotateAfterProj4"+rotateProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateProj4 = rotateAfterProj4 -rotMatrixProj' :: {- ' CPP is sensitive to primes -} Flt -> Vec3 -> Mat4-rotMatrixProj' angle axis = extendProj $ rotMatrix3 axis angle+-- | Synonym for @\m -> m .*. rotMatrixProj4 angle axis@.+rotateAfterProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateAfterProj4 angle axis m = m .*. (rotMatrixProj4' angle axis) -translMatrixProj :: Vec3 -> Mat4-translMatrixProj v = Mat4 Dim4.vec4X Dim4.vec4Y Dim4.vec4Z (extendProj v)+-- | Synonym for @\m -> rotMatrixProj4 angle axis .*. m@.+rotateBeforeProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateBeforeProj4 angle axis m = (rotMatrixProj4' angle axis) .*. m --- | we assume that the bottom-right corner is 1.-translWithProj :: Vec3 -> Mat4 -> Mat4-translWithProj v mat@(Mat4 r1 r2 r3 r4) = Mat4 r1 r2 r3 (extendProjWith 0 v &+ r4)+--------------- -scaleMatrixProj :: Vec3 -> Mat4-scaleMatrixProj v = diag $ extendProj v+--scalingUniformProj3 :: Flt -> Proj3+--scalingUniformProj3 x = scaling (Vec2 x x) -scaleMatrixUniformProj :: Flt -> Mat4-scaleMatrixUniformProj s = diag (Vec4 s s s 1)+scalingUniformProj4 :: Flt -> Proj4+scalingUniformProj4 x = scaling (Vec3 x x x) -class ProjectiveAction v where- actProj :: v -> Mat4 -> v- -instance ProjectiveAction Vec3 where- actProj v m = trim $ (extendProj v) .* m +-- | Equivalent to @\m -> scaling v .*. m@.+scaleBeforeProj4 :: Vec3 -> Proj4 -> Proj4+scaleBeforeProj4 (Vec3 u v w) p4 = + toProjectiveUnsafe $ + Mat4 (u*&a) (v*&b) (w*&c) t+ where+ Mat4 a b c t = fromProjective p4 -instance ProjectiveAction Vec4 where- actProj v m = v .* m +-- | Equivalent to @\m -> m .*. scaling v@.+scaleAfterProj4 :: Vec3 -> Proj4 -> Proj4+scaleAfterProj4 v p4 =+ toProjectiveUnsafe $ + Mat4 (a&!w) (b&!w) (c&!w) (t&!w)+ where+ w = extendWith 1 v+ Mat4 a b c t = fromProjective p4+ +--------------- --- | When acting on unit vectors, we ignore the translation part.-instance ProjectiveAction Normal3 where- actProj (Normal3 v) m = Normal3 (v .* (trim m :: Mat3))+-- | Synonym for "translateAfter4"+translate4 :: Vec3 -> Proj4 -> Proj4+translate4 = translateAfter4 --- | Inverts a projective 4x4 matrix, assuming that the top-left 3x3 part is /orthogonal/,--- and the bottom-right corner is 1.-invertProj :: Mat4 -> Mat4-invertProj mat@(Mat4 u v w t) = - translWithProj t' $ extendProj $ transpose $ (trim mat :: Mat3)+-- | Equivalent to @\m -> m .*. translation v@.+translateAfter4 :: Vec3 -> Proj4 -> Proj4+translateAfter4 v p4 = + toProjectiveUnsafe $+ Mat4 r1 r2 r3 (extendWith 0 v &+ r4) where- t' = Vec3 (- u &. t) (- v &. t) (- w &. t)- + Mat4 r1 r2 r3 r4 = fromProjective p4 ++-- | Equivalent to @\m -> translation v .*. m@.+translateBefore4 :: Vec3 -> Proj4 -> Proj4+translateBefore4 v p4 = + toProjectiveUnsafe $ + Mat4 r1 r2 r3 (extendWith 0 u &+ r4) + where + u = v .* (trim mat :: Mat3) + mat@(Mat4 r1 r2 r3 r4) = fromProjective p4+ +---------------+
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2008, Balazs Komuves+Copyright (c) 2008-2009, Balazs Komuves All rights reserved. Redistribution and use in source and binary forms, with or without@@ -15,15 +15,15 @@ may be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
src/flt/Base.hs view
@@ -1,10 +1,33 @@ -module Data.Vect.Flt.Base where+{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, GeneralizedNewtypeDeriving #-} +module Data.Vect.Flt.Base+ ( AbelianGroup(..) , vecSum+ , MultSemiGroup(..) , Ring , semigroupProduct+ , LeftModule(..) , RightModule(..)+ , Vector(..) , DotProd(..) , CrossProd(..)+ , normalize , distance , angle , angle'+ , UnitVector(..)+ , Pointwise(..)+ , Extend(..) , HasCoordinates(..) , Dimension(..)+ , Matrix(..) , Tensor(..) , Diagonal (..) , Determinant(..)+ , Orthogonal(..) , Projective(..) , MatrixNorms(..)+ , Vec2(..) , Vec3(..) , Vec4(..)+ , Mat2(..) , Mat3(..) , Mat4(..)+ , Ortho2 , Ortho3 , Ortho4+ , Normal2 , Normal3 , Normal4+ , Proj3 , Proj4+ , mkVec2 , mkVec3 , mkVec4+ , project , project' , projectUnsafe , flipNormal+ , householder, householderOrtho+ )+ where+ import Control.Monad import System.Random import Foreign +-------------------------------------------------------------------------------- -- class declarations class AbelianGroup g where@@ -19,15 +42,17 @@ vecSum :: AbelianGroup g => [g] -> g vecSum l = foldl (&+) zero l -class (AbelianGroup r) => - Ring r where+class MultSemiGroup r where (.*.) :: r -> r -> r one :: r +class (AbelianGroup r, MultSemiGroup r) => Ring r + infixl 7 .*. -ringProduct :: Ring r => [r] -> r-ringProduct l = foldl (.*.) one l+-- was: ringProduct :: Ring r => [r] -> r+semigroupProduct :: MultSemiGroup r => [r] -> r +semigroupProduct l = foldl (.*.) one l class LeftModule r m where lmul :: r -> m -> m@@ -74,7 +99,7 @@ lensqr = normsqr dotprod :: v -> v -> Flt normsqr v = (v &. v) - norm = sqrt.lensqr+ norm = sqrt . lensqr dotprod = (&.) infix 7 &.@@ -111,26 +136,28 @@ fromNormalRadius :: Flt -> u -> v fromNormalRadius t n = t *& fromNormal n --- | projects the first vector onto the direction of the second (unit) vector+-- | Projects the first vector onto the direction of the second (unit) vector project' :: (Vector v, UnitVector v u, DotProd v) => v -> u -> v project' what dir = projectUnsafe what (fromNormal dir) --- | direction (second argument) is assumed to be a /unit/ vector!+-- | Direction (second argument) is assumed to be a /unit/ vector! projectUnsafe :: (Vector v, DotProd v) => v -> v -> v projectUnsafe what dir = what &- dir &* (what &. dir) project :: (Vector v, DotProd v) => v -> v -> v project what dir = what &- dir &* ((what &. dir) / (dir &. dir)) --- | since unit vectors are not a group, we need a separate function.+-- | Since unit vectors are not a group, we need a separate function. flipNormal :: UnitVector v n => n -> n flipNormal = toNormalUnsafe . neg . fromNormal +-- | Cross product class CrossProd v where crossprod :: v -> v -> v (&^) :: v -> v -> v (&^) = crossprod- + +-- | Pointwise multiplication class Pointwise v where pointwise :: v -> v -> v (&!) :: v -> v -> v@@ -165,13 +192,50 @@ "inverse is an involution" forall m. inverse (inverse m) = m #-} +class Matrix m => Orthogonal m o | m->o, o->m where + fromOrtho :: o -> m + toOrthoUnsafe :: m -> o+ +class (AbelianGroup m, Matrix m) => MatrixNorms m where+ frobeniusNorm :: m -> Flt -- ^ the frobenius norm (= euclidean norm in the space of matrices)+ matrixDistance :: m -> m -> Flt -- ^ euclidean distance in the space of matrices+ operatorNorm :: m -> Flt -- ^ (euclidean) operator norm (not implemented yet)+ matrixDistance m n = frobeniusNorm (n &- m)+ operatorNorm = error "operatorNorm: not implemented yet"+ -- | Outer product (could be unified with Diagonal?) class Tensor t v | t->v where outer :: v -> v -> t class Determinant m where det :: m -> Flt - ++class Dimension a where+ dim :: a -> Int+ +-- | Householder matrix, see <http://en.wikipedia.org/wiki/Householder_transformation>. +-- In plain words, it is the reflection to the hyperplane orthogonal to the input vector.+householder :: (Vector v, UnitVector v u, Matrix m, Vector m, Tensor m v) => u -> m+householder u = idmtx &- (2 *& outer v v) + where v = fromNormal u++householderOrtho :: (Vector v, UnitVector v u, Matrix m, Vector m, Tensor m v, Orthogonal m o) => u -> o+householderOrtho = toOrthoUnsafe . householder++-- | \"Projective\" matrices have the following form: the top left corner+-- is an any matrix, the bottom right corner is 1, and the top-right+-- column is zero. These describe the affine orthogonal transformation of+-- the space one dimension less.+class (Vector v, Orthogonal n o, Diagonal v n) => Projective v n o m p + | m->p, p->m, p->o, o->p, p->n, n->p, p->v, v->p, n->o, n->v, v->n where+ fromProjective :: p -> m+ toProjectiveUnsafe :: m -> p+ orthogonal :: o -> p+ linear :: n -> p+ translation :: v -> p+ scaling :: v -> p++-------------------------------------------------------------------------------- -- Vec / Mat datatypes data Vec2 = Vec2 {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt @@ -181,16 +245,16 @@ data Vec4 = Vec4 {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt {-# UNPACK #-} !Flt deriving (Read,Show) --- | these are /row/ vectors +-- | The components are /row/ vectors data Mat2 = Mat2 !Vec2 !Vec2 deriving (Read,Show) data Mat3 = Mat3 !Vec3 !Vec3 !Vec3 deriving (Read,Show) data Mat4 = Mat4 !Vec4 !Vec4 !Vec4 !Vec4 deriving (Read,Show) -- | The assumption when dealing with these is always that they are of unit length. -- Also, interpolation works differently.-newtype Normal2 = Normal2 Vec2 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable) -newtype Normal3 = Normal3 Vec3 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable,CrossProd) -newtype Normal4 = Normal4 Vec4 deriving ({-AbelianGroup,Vector,-}Read,Show,DotProd,Storable) +newtype Normal2 = Normal2 Vec2 deriving (Read,Show,Storable,DotProd,Dimension) +newtype Normal3 = Normal3 Vec3 deriving (Read,Show,Storable,DotProd,Dimension) +newtype Normal4 = Normal4 Vec4 deriving (Read,Show,Storable,DotProd,Dimension) mkVec2 :: (Flt,Flt) -> Vec2 mkVec3 :: (Flt,Flt,Flt) -> Vec3@@ -200,6 +264,19 @@ mkVec3 (x,y,z) = Vec3 x y z mkVec4 (x,y,z,w) = Vec4 x y z w +-- | Orthogonal matrices.+--+-- Note: the "Random" instances generates orthogonal matrices with determinant 1+-- (that is, orientation-preserving orthogonal transformations)!+newtype Ortho2 = Ortho2 Mat2 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)+newtype Ortho3 = Ortho3 Mat3 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)+newtype Ortho4 = Ortho4 Mat4 deriving (Read,Show,Storable,MultSemiGroup,Determinant,Dimension)++-- | Projective matrices, encoding affine transformations in dimension one less.+newtype Proj3 = Proj3 Mat3 deriving (Read,Show,Storable,MultSemiGroup)+newtype Proj4 = Proj4 Mat4 deriving (Read,Show,Storable,MultSemiGroup)++-------------------------------------------------------------------------------- -- Unit vectors instance UnitVector Vec2 Normal2 where@@ -217,47 +294,163 @@ fromNormal (Normal4 v) = v toNormalUnsafe = Normal4 -rndUnit :: (RandomGen g, Random v, Vector v, DotProd v) => g -> (v,g)-rndUnit g = +_rndUnit :: (RandomGen g, Random v, Vector v, DotProd v) => g -> (v,g)+_rndUnit g = if d > 0.01 then ( v &* (1.0/d) , h )- else rndUnit h+ else _rndUnit h where (v,h) = random g d = norm v instance Random Normal2 where- random g = let (v,h) = rndUnit g in (Normal2 v, h) + random g = let (v,h) = _rndUnit g in (Normal2 v, h) randomR _ = random instance Random Normal3 where- random g = let (v,h) = rndUnit g in (Normal3 v, h) + random g = let (v,h) = _rndUnit g in (Normal3 v, h) randomR _ = random instance Random Normal4 where- random g = let (v,h) = rndUnit g in (Normal4 v, h) + random g = let (v,h) = _rndUnit g in (Normal4 v, h) randomR _ = random -{--instance Storable Normal2 where- alignment _ = alignment (undefined::Vec2)- sizeOf _ = sizeOf (undefined::Vec2)- peek p = liftM (\v -> Normal2 v) (peek $ castPtr p)- poke p (Normal2 v) = poke (castPtr p) v - -instance Storable Normal3 where- alignment _ = alignment (undefined::Vec3)- sizeOf _ = sizeOf (undefined::Vec3)- peek p = liftM (\v -> Normal3 v) (peek $ castPtr p)- poke p (Normal3 v) = poke (castPtr p) v +instance CrossProd Normal3 where+ crossprod (Normal3 v) (Normal3 w) = mkNormal (crossprod v w) -instance Storable Normal4 where- alignment _ = alignment (undefined::Vec4)- sizeOf _ = sizeOf (undefined::Vec4)- peek p = liftM (\v -> Normal4 v) (peek $ castPtr p)- poke p (Normal4 v) = poke (castPtr p) v --}+--------------------------------------------------------------------------------+-- Orthogonal matrices +instance Orthogonal Mat2 Ortho2 where+ fromOrtho (Ortho2 o) = o+ toOrthoUnsafe = Ortho2++instance Orthogonal Mat3 Ortho3 where+ fromOrtho (Ortho3 o) = o+ toOrthoUnsafe = Ortho3 ++instance Orthogonal Mat4 Ortho4 where+ fromOrtho (Ortho4 o) = o+ toOrthoUnsafe = Ortho4++------++instance Matrix Ortho2 where+ transpose (Ortho2 o) = Ortho2 (transpose o)+ idmtx = Ortho2 idmtx+ inverse = transpose++instance Matrix Ortho3 where+ transpose (Ortho3 o) = Ortho3 (transpose o)+ idmtx = Ortho3 idmtx+ inverse = transpose++instance Matrix Ortho4 where+ transpose (Ortho4 o) = Ortho4 (transpose o)+ idmtx = Ortho4 idmtx+ inverse = transpose++------++instance Random Ortho2 where+ random g = let (o,h) = _rndOrtho2 g in (toOrthoUnsafe (_flip1stRow2 o), h)+ randomR _ = random++instance Random Ortho3 where+ random g = let (o,h) = _rndOrtho3 g in (toOrthoUnsafe ( o), h)+ randomR _ = random++instance Random Ortho4 where+ random g = let (o,h) = _rndOrtho4 g in (toOrthoUnsafe (_flip1stRow4 o), h)+ randomR _ = random++------++-- determinant will be -1+_rndOrtho2 :: RandomGen g => g -> (Mat2, g)+_rndOrtho2 g = (h2, g1) where+ h2 = householder u2 :: Mat2 + (u2,g1) = random g ++-- generates a uniformly random orthogonal 3x3 matrix +-- /with determinant +1/, with respect to the Haar measure of SO3.+--+-- see Theorem 4 in:+-- Francesco Mezzadri: How to Generate Random Matrices from the Classical Compact Groups +-- Notices of the AMS, May 2007 issue+-- <http://www.ams.org/notices/200705/fea-mezzadri-web.ps>+_rndOrtho3 :: RandomGen g => g -> (Mat3, g) +_rndOrtho3 g = ( (h3 .*. m3), g2) where+ m3 = (extendWith :: Flt -> Mat2 -> Mat3) 1 o2 + h3 = householder u3 :: Mat3+ (u3,g1) = random g+ (o2,g2) = _rndOrtho2 g1++-- determinant will be -1+_rndOrtho4 :: RandomGen g => g -> (Mat4, g) +_rndOrtho4 g = ( (h4 .*. m4), g2) where+ m4 = (extendWith :: Flt -> Mat3 -> Mat4) 1 o3 + h4 = householder u4 :: Mat4+ (u4,g1) = random g+ (o3,g2) = _rndOrtho3 g1++------++_flip1stRow2 :: Mat2 -> Mat2+_flip1stRow2 (Mat2 a b) = Mat2 (neg a) b++_flip1stRow3 :: Mat3 -> Mat3+_flip1stRow3 (Mat3 a b c) = Mat3 (neg a) b c++_flip1stRow4 :: Mat4 -> Mat4+_flip1stRow4 (Mat4 a b c d) = Mat4 (neg a) b c d++--------------------------------------------------------------------------------+-- projective matrices+ +instance Projective Vec2 Mat2 Ortho2 Mat3 Proj3 where+ fromProjective (Proj3 m) = m+ toProjectiveUnsafe = Proj3+ orthogonal = Proj3 . extendWith 1 . fromOrtho+ linear = Proj3 . extendWith 1+ translation v = Proj3 $ Mat3 (Vec3 1 0 0) (Vec3 0 1 0) (extendWith 1 v)+ scaling v = Proj3 $ diag (extendWith 1 v)+ +instance Projective Vec3 Mat3 Ortho3 Mat4 Proj4 where+ fromProjective (Proj4 m) = m+ toProjectiveUnsafe = Proj4+ orthogonal = Proj4 . extendWith 1 . fromOrtho + linear = Proj4 . extendWith 1+ translation v = Proj4 $ Mat4 (Vec4 1 0 0 0) (Vec4 0 1 0 0) (Vec4 0 0 1 0) (extendWith 1 v)+ scaling v = Proj4 $ diag (extendWith 1 v)++instance Matrix Proj3 where+ idmtx = Proj3 idmtx+ transpose (Proj3 m) = Proj3 (transpose m)+ inverse = _invertProj3++instance Matrix Proj4 where+ idmtx = Proj4 idmtx+ transpose (Proj4 m) = Proj4 (transpose m)+ inverse = _invertProj4++_invertProj3 :: Proj3 -> Proj3+_invertProj3 (Proj3 mat@(Mat3 _ _ t)) = + Proj3 $ Mat3 (extendZero a) (extendZero b) (extendWith 1 t') + where+ t' = neg $ (trim t :: Vec2) .* invm2 + invm2@(Mat2 a b) = inverse $ (trim mat :: Mat2)++-- Inverts a projective 4x4 matrix. But you can simply use "inverse" instead.+-- We assume that the bottom-right corner is 1.+_invertProj4 :: Proj4 -> Proj4+_invertProj4 (Proj4 mat@(Mat4 _ _ _ t)) = + Proj4 $ Mat4 (extendZero a) (extendZero b) (extendZero c) (extendWith 1 t') + where+ t' = neg $ (trim t :: Vec3) .* invm3 + invm3@(Mat3 a b c) = inverse $ (trim mat :: Mat3)++-------------------------------------------------------------------------------- -- Vec2 instances instance HasCoordinates Vec2 Flt where@@ -313,7 +506,10 @@ k = sizeOf (undefined::Flt) poke p x pokeByteOff p k y- ++instance Dimension Vec2 where dim _ = 2++-------------------------------------------------------------------------------- -- Mat2 instances instance HasCoordinates Mat2 Vec2 where@@ -335,19 +531,21 @@ (&+) (Mat2 r1 r2) (Mat2 s1 s2) = Mat2 (r1 &+ s1) (r2 &+ s2) (&-) (Mat2 r1 r2) (Mat2 s1 s2) = Mat2 (r1 &- s1) (r2 &- s2) neg (Mat2 r1 r2) = Mat2 (neg r1) (neg r2) - zero = Mat2 zero zero -- (zero::Vec2) (zero::Vec2)-+ zero = Mat2 zero zero + instance Vector Mat2 where scalarMul s (Mat2 r1 r2) = Mat2 (g r1) (g r2) where g = scalarMul s mapVec f (Mat2 r1 r2) = Mat2 (g r1) (g r2) where g = mapVec f -instance Ring Mat2 where+instance MultSemiGroup Mat2 where (.*.) (Mat2 r1 r2) n = let (Mat2 c1 c2) = transpose n in Mat2 (Vec2 (r1 &. c1) (r1 &. c2)) (Vec2 (r2 &. c1) (r2 &. c2)) one = idmtx +instance Ring Mat2+ instance LeftModule Mat2 Vec2 where lmul (Mat2 row1 row2) v = Vec2 (row1 &. v) (row2 &. v) @@ -361,11 +559,6 @@ outer (Vec2 a b) (Vec2 x y) = Mat2 (Vec2 (a*x) (a*y)) (Vec2 (b*x) (b*y))-{-- outer v w = - let full = Mat2 (Vec2 1 1) (Vec2 1 1)- in (diag v) .*. full .*. (diag w)--} instance Determinant Mat2 where det (Mat2 (Vec2 a b) (Vec2 c d)) = a*d - b*c @@ -392,6 +585,24 @@ poke p r1 pokeByteOff p k r2 +instance Random Mat2 where+ random = randomR (Mat2 v1 v1 , Mat2 v2 v2) where + v1 = Vec2 (-1) (-1) + v2 = Vec2 1 1+ randomR (Mat2 a b, Mat2 c d) gen = + let (x,gen1) = randomR (a,c) gen+ (y,gen2) = randomR (b,d) gen1+ in (Mat2 x y, gen2)+ +instance Dimension Mat2 where dim _ = 2+ +instance MatrixNorms Mat2 where + frobeniusNorm (Mat2 r1 r2) = + sqrt $+ normsqr r1 + + normsqr r2+ +-------------------------------------------------------------------------------- -- Vec3 instances instance HasCoordinates Vec3 Flt where@@ -453,7 +664,10 @@ poke p x pokeByteOff p (k ) y pokeByteOff p (k+k) z- ++instance Dimension Vec3 where dim _ = 3++-------------------------------------------------------------------------------- -- Mat3 instances instance HasCoordinates Mat3 Vec3 where@@ -494,13 +708,13 @@ (&+) (Mat3 r1 r2 r3) (Mat3 s1 s2 s3) = Mat3 (r1 &+ s1) (r2 &+ s2) (r3 &+ s3) (&-) (Mat3 r1 r2 r3) (Mat3 s1 s2 s3) = Mat3 (r1 &- s1) (r2 &- s2) (r3 &- s3) neg (Mat3 r1 r2 r3) = Mat3 (neg r1) (neg r2) (neg r3) - zero = Mat3 zero zero zero -- (zero::Vec3) (zero::Vec3) (zero::Vec3)+ zero = Mat3 zero zero zero instance Vector Mat3 where scalarMul s (Mat3 r1 r2 r3) = Mat3 (g r1) (g r2) (g r3) where g = scalarMul s mapVec f (Mat3 r1 r2 r3) = Mat3 (g r1) (g r2) (g r3) where g = mapVec f -instance Ring Mat3 where+instance MultSemiGroup Mat3 where (.*.) (Mat3 r1 r2 r3) n = let (Mat3 c1 c2 c3) = transpose n in Mat3 (Vec3 (r1 &. c1) (r1 &. c2) (r1 &. c3))@@ -508,6 +722,8 @@ (Vec3 (r3 &. c1) (r3 &. c2) (r3 &. c3)) one = idmtx +instance Ring Mat3+ instance LeftModule Mat3 Vec3 where lmul (Mat3 row1 row2 row3) v = Vec3 (row1 &. v) (row2 &. v) (row3 &. v) @@ -522,11 +738,6 @@ (Vec3 (a*x) (a*y) (a*z)) (Vec3 (b*x) (b*y) (b*z)) (Vec3 (c*x) (c*y) (c*z))-{-- outer v w = - let full = Mat3 (Vec3 1 1 1) (Vec3 1 1 1) (Vec3 1 1 1)- in (diag v) .*. full .*. (diag w)--} instance Determinant Mat3 where det (Mat3 r1 r2 r3) = det (r1,r2,r3)@@ -555,6 +766,26 @@ pokeByteOff p (k ) r2 pokeByteOff p (k+k) r3 +instance Random Mat3 where+ random = randomR (Mat3 v1 v1 v1 , Mat3 v2 v2 v2) where+ v1 = Vec3 (-1) (-1) (-1)+ v2 = Vec3 1 1 1+ randomR (Mat3 a b c, Mat3 d e f) gen = + let (x,gen1) = randomR (a,d) gen+ (y,gen2) = randomR (b,e) gen1+ (z,gen3) = randomR (c,f) gen2 + in (Mat3 x y z, gen3)+ +instance Dimension Mat3 where dim _ = 3+ +instance MatrixNorms Mat3 where + frobeniusNorm (Mat3 r1 r2 r3) = + sqrt $+ normsqr r1 + + normsqr r2 + + normsqr r3 + +-------------------------------------------------------------------------------- -- Vec4 instances instance HasCoordinates Vec4 Flt where@@ -614,6 +845,9 @@ pokeByteOff p (k+k) z pokeByteOff p (3*k) w +instance Dimension Vec4 where dim _ = 4++-------------------------------------------------------------------------------- -- Mat4 instances instance HasCoordinates Mat4 Vec4 where@@ -641,7 +875,7 @@ scalarMul s (Mat4 r1 r2 r3 r4) = Mat4 (g r1) (g r2) (g r3) (g r4) where g = scalarMul s mapVec f (Mat4 r1 r2 r3 r4) = Mat4 (g r1) (g r2) (g r3) (g r4) where g = mapVec f -instance Ring Mat4 where+instance MultSemiGroup Mat4 where (.*.) (Mat4 r1 r2 r3 r4) n = let (Mat4 c1 c2 c3 c4) = transpose n in Mat4 (Vec4 (r1 &. c1) (r1 &. c2) (r1 &. c3) (r1 &. c4))@@ -650,6 +884,8 @@ (Vec4 (r4 &. c1) (r4 &. c2) (r4 &. c3) (r4 &. c4)) one = idmtx +instance Ring Mat4+ instance LeftModule Mat4 Vec4 where lmul (Mat4 row1 row2 row3 row4) v = Vec4 (row1 &. v) (row2 &. v) (row3 &. v) (row4 &. v) @@ -665,14 +901,10 @@ (Vec4 (b*x) (b*y) (b*z) (b*w)) (Vec4 (c*x) (c*y) (c*z) (c*w)) (Vec4 (d*x) (d*y) (d*z) (d*w))-{-- outer v w = - let full = Mat4 (Vec4 1 1 1 1) (Vec4 1 1 1 1) (Vec4 1 1 1 1) (Vec4 1 1 1 1)- in (diag v) .*. full .*. (diag w)--} ---instance Determinant Mat4 where--- det (Mat4 r1 r2 r3 r4)+instance Determinant Mat4 where+ det = error "det/Mat4: not implemented yet" + -- det (Mat4 r1 r2 r3 r4) = {- instance Show Mat4 where@@ -700,6 +932,28 @@ pokeByteOff p (k+k) r3 pokeByteOff p (3*k) r4 +instance Random Mat4 where+ random = randomR (Mat4 v1 v1 v1 v1, Mat4 v2 v2 v2 v2) where+ v1 = Vec4 (-1) (-1) (-1) (-1)+ v2 = Vec4 1 1 1 1+ randomR (Mat4 a b c d, Mat4 e f g h) gen = + let (x,gen1) = randomR (a,e) gen+ (y,gen2) = randomR (b,f) gen1+ (z,gen3) = randomR (c,g) gen2 + (w,gen4) = randomR (d,h) gen3 + in (Mat4 x y z w, gen4)+ +instance Dimension Mat4 where dim _ = 4+ +instance MatrixNorms Mat4 where + frobeniusNorm (Mat4 r1 r2 r3 r4) = + sqrt $+ normsqr r1 + + normsqr r2 + + normsqr r3 + + normsqr r4 + +-------------------------------------------------------------------------------- -- Extend instances instance Extend Vec2 Vec3 where@@ -718,17 +972,20 @@ trim (Vec4 x y z _) = Vec3 x y z instance Extend Mat2 Mat3 where- extendZero (Mat2 p q) = Mat3 (extendZero p) (extendZero q) zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat2 p q) = Mat3 (extendZero p) (extendZero q) zero+ extendWith w (Mat2 p q) = Mat3 (extendZero p) (extendZero q) (Vec3 0 0 w) trim (Mat3 p q _) = Mat2 (trim p) (trim q) instance Extend Mat2 Mat4 where- extendZero (Mat2 p q) = Mat4 (extendZero p) (extendZero q) zero zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat2 p q) = Mat4 (extendZero p) (extendZero q) zero zero+ extendWith w (Mat2 p q) = Mat4 (extendZero p) (extendZero q) (Vec4 0 0 w 0) (Vec4 0 0 0 w) trim (Mat4 p q _ _) = Mat2 (trim p) (trim q) instance Extend Mat3 Mat4 where- extendZero (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) zero- extendWith _ _ = error "extendWith is meaningless for matrices"+ extendZero (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) zero+ extendWith w (Mat3 p q r) = Mat4 (extendZero p) (extendZero q) (extendZero r) (Vec4 0 0 0 w) trim (Mat4 p q r _) = Mat3 (trim p) (trim q) (trim r)+ +--------------------------------------------------------------------------------+
src/flt/GramSchmidt.hs view
@@ -9,7 +9,7 @@ import Data.Vect.Flt.Base --------------------------------------------------------+-------------------------------------------------------------------------------- liftPair :: (a -> b) -> (a,a) -> (b,b) liftPair f (x,y) = (f x, f y)@@ -20,7 +20,7 @@ liftQuadruple :: (a -> b) -> (a,a,a,a) -> (b,b,b,b) liftQuadruple f (x,y,z,w) = (f x, f y, f z, f w) --------------------------------------------------------+-------------------------------------------------------------------------------- -- | produces orthogonal\/orthonormal vectors from a set of vectors class GramSchmidt a where@@ -32,7 +32,7 @@ "gramSchmidtNormalize is idempotent" forall a. gramSchmidtNormalize (gramSchmidtNormalize a) = gramSchmidtNormalize a #-} --------------------------------------------------------+-------------------------------------------------------------------------------- instance GramSchmidt (Vec2,Vec2) where gramSchmidt = gramSchmidtPair
src/flt/OpenGL.hs view
@@ -2,21 +2,92 @@ -- TODO: the pointer versions of these functions should be really implemented -- via the pointer versions of the original opengl functions... --- | OpenGL support, inclduing 'vertex', 'texCoord', etc instances for 'Vec2', 'Vec3' and 'Vec4'.+-- | OpenGL support, including 'Vertex', 'TexCoord', etc instances for 'Vec2', 'Vec3' and 'Vec4'. module Data.Vect.Flt.OpenGL where import Control.Monad import Data.Vect.Flt.Base+import Data.Vect.Flt.Util.Projective import qualified Graphics.Rendering.OpenGL as GL import Foreign -import Graphics.Rendering.OpenGL hiding (Normal3,rotate,translate,scale)+import Graphics.Rendering.OpenGL hiding + ( Normal3 , rotate , translate , scale+ , matrix , currentMatrix , withMatrix , multMatrix + ) --------------------------------------------------------+-------------------------------------------------------------------------------- -{-# SPECIALISE radianToDegrees :: Float -> Float #-}+-- | There should be a big warning here about the different conventions, +-- hidden transpositions, and all the confusion this will inevitably cause...+--+-- As it stands, +--+-- > glRotate t1 axis1 >> glRotate t2 axis2 >> glRotate t3 axis3+-- +-- has the same result as+--+-- > multMatrix (rotMatrixProj4 t3 axis3 .*. rotMatrixProj4 t2 axis2 .*. rotMatrixProj4 t1 axis1)+--+-- because at the interface of OpenGL and this library there is a transposition+-- to compensate for the different conventions. (This transposition is implicit+-- in the code, because the way the matrices are stored in the memory is also+-- different: OpenGL stores them column-major, and we store them row-major).++class ToOpenGLMatrix m where+ makeGLMatrix :: m -> IO (GLmatrix Flt)++class FromOpenGLMatrix m where+ peekGLMatrix :: GLmatrix Flt -> IO m+ +setMatrix :: ToOpenGLMatrix m => Maybe MatrixMode -> m -> IO ()+setMatrix mode m = makeGLMatrix m >>= \x -> GL.matrix mode $= x+ +getMatrix :: FromOpenGLMatrix m => Maybe MatrixMode -> IO m+getMatrix mode = get (GL.matrix mode) >>= peekGLMatrix++matrix :: (ToOpenGLMatrix m, FromOpenGLMatrix m) => Maybe MatrixMode -> StateVar m+matrix mode = makeStateVar (getMatrix mode) (setMatrix mode)++currentMatrix :: (ToOpenGLMatrix m, FromOpenGLMatrix m) => StateVar m+currentMatrix = matrix Nothing++multMatrix :: ToOpenGLMatrix m => m -> IO ()+multMatrix m = makeGLMatrix m >>= GL.multMatrix++instance ToOpenGLMatrix Mat4 where+ makeGLMatrix m = GL.withNewMatrix GL.ColumnMajor (flip poke m . castPtr) + +instance FromOpenGLMatrix Mat4 where+ -- huh? GL.withMatrix is strange+ peekGLMatrix x = GL.withMatrix x $ \_ p -> peek (castPtr p)+ +instance ToOpenGLMatrix Mat3 where+ makeGLMatrix m = makeGLMatrix (extendWith 1 m :: Mat4)+ +instance ToOpenGLMatrix Mat2 where+ makeGLMatrix m = makeGLMatrix (extendWith 1 m :: Mat4)++instance ToOpenGLMatrix Ortho4 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat4)++instance ToOpenGLMatrix Ortho3 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat3)++instance ToOpenGLMatrix Ortho2 where+ makeGLMatrix m = makeGLMatrix (fromOrtho m :: Mat2)++instance ToOpenGLMatrix Proj4 where+ makeGLMatrix m = makeGLMatrix (fromProjective m :: Mat4)++instance ToOpenGLMatrix Proj3 where+ makeGLMatrix m = makeGLMatrix (fromProjective m :: Mat3)+ +--------------------------------------------------------------------------------++{-# SPECIALISE radianToDegrees :: Float -> Float #-} {-# SPECIALISE radianToDegrees :: Double -> Double #-} radianToDegrees :: RealFrac a => a -> a radianToDegrees x = x * 57.295779513082322@@ -27,20 +98,61 @@ degreesToRadian x = x * 1.7453292519943295e-2 -- | The angle is in radians. (WARNING: OpenGL uses degrees!)-rotate :: Flt -> Vec3 -> IO ()-rotate angle (Vec3 x y z) = GL.rotate (radianToDegrees angle) (Vector3 x y z)+glRotate :: Flt -> Vec3 -> IO ()+glRotate angle (Vec3 x y z) = GL.rotate (radianToDegrees angle) (Vector3 x y z) -translate :: Vec3 -> IO ()-translate (Vec3 x y z) = GL.translate (Vector3 x y z)+glTranslate :: Vec3 -> IO ()+glTranslate (Vec3 x y z) = GL.translate (Vector3 x y z) -scale3 :: Vec3 -> IO ()-scale3 (Vec3 x y z) = GL.scale x y z+glScale3 :: Vec3 -> IO ()+glScale3 (Vec3 x y z) = GL.scale x y z -scale :: Flt -> IO ()-scale x = GL.scale x x x+glScale :: Flt -> IO ()+glScale x = GL.scale x x x --------------------------------------------------------+--------------------------------------------------------------------------------+ +-- | \"Orthogonal projecton\" matrix, a la OpenGL +-- (the corresponding functionality is removed in OpenGL 3.1)+orthoMatrix + :: (Flt,Flt) -- ^ (left,right)+ -> (Flt,Flt) -- ^ (bottom,top)+ -> (Flt,Flt) -- ^ (near,far)+ -> Mat4 +orthoMatrix (l,r) (b,t) (n,f) = Mat4+ (Vec4 (2/(r-l)) 0 0 0)+ (Vec4 0 (2/(t-b)) 0 0)+ (Vec4 0 0 (-2/(f-n)) 0)+ (Vec4 (-(r+l)/(r-l)) (-(t+b)/(t-b)) (-(f+n)/(f-n)) 1)+ +-- | The same as "orthoMatrix", but with a different parametrization.+orthoMatrix2 {- ' CPP is sensitive to primes -}+ :: Vec3 -- ^ (left,top,near)+ -> Vec3 -- ^ (right,bottom,far)+ -> Mat4 +orthoMatrix2 (Vec3 l t n) (Vec3 r b f) = orthoMatrix (l,r) (b,t) (n,f) +-- | \"Perspective projecton\" matrix, a la OpenGL +-- (the corresponding functionality is removed in OpenGL 3.1).+frustumMatrix+ :: (Flt,Flt) -- ^ (left,right)+ -> (Flt,Flt) -- ^ (bottom,top)+ -> (Flt,Flt) -- ^ (near,far)+ -> Mat4 +frustumMatrix (l,r) (b,t) (n,f) = Mat4+ (Vec4 (2*n/(r-l)) 0 0 0)+ (Vec4 0 (2*n/(t-b)) 0 0)+ (Vec4 ((r+l)/(r-l)) ((t+b)/(t-b)) (-(f+n)/(f-n)) (-1))+ (Vec4 0 0 (-2*f*n*(f-n)) 0)+ +-- | The same as "frustumMatrix", but with a different parametrization.+frustumMatrix2 {- ' CPP is sensitive to primes -}+ :: Vec3 -- ^ (left,top,near)+ -> Vec3 -- ^ (right,bottom,far)+ -> Mat4 +frustumMatrix2 (Vec3 l t n) (Vec3 r b f) = frustumMatrix (l,r) (b,t) (n,f)++-------------------------------------------------------------------------------- -- Vertex instances instance GL.Vertex Vec2 where@@ -55,17 +167,20 @@ vertex (Vec4 x y z w) = GL.vertex (GL.Vertex4 x y z w) vertexv p = peek p >>= vertex ---------------------------------------------------------+-------------------------------------------------------------------------------- -- the Normal instance -- note that there is no Normal2\/Normal4 in the OpenGL binding instance GL.Normal Normal3 where- normal (Normal3 (Vec3 x y z)) = GL.normal (GL.Normal3 x y z)+ normal u = GL.normal (GL.Normal3 x y z) + where Vec3 x y z = fromNormal u normalv p = peek p >>= normal --------------------------------------------------------+instance GL.Normal Vec3 where+ normal (Vec3 x y z) = GL.normal (GL.Normal3 x y z) + normalv p = peek p >>= normal +-------------------------------------------------------------------------------- -- Color instances instance GL.Color Vec3 where@@ -87,8 +202,7 @@ secondaryColorv p = peek p >>= secondaryColor -} ---------------------------------------------------------+-------------------------------------------------------------------------------- -- TexCoord instances instance GL.TexCoord Vec2 where@@ -109,8 +223,7 @@ multiTexCoord unit (Vec4 u v w z) = GL.multiTexCoord unit (GL.TexCoord4 u v w z) multiTexCoordv unit p = peek p >>= multiTexCoord unit --------------------------------------------------------- +-------------------------------------------------------------------------------- -- Vertex Attributes (experimental) class VertexAttrib' a where@@ -129,16 +242,18 @@ vertexAttrib loc (Vec4 x y z w) = GL.vertexAttrib4 loc x y z w instance VertexAttrib' Normal2 where- vertexAttrib loc (Normal2 (Vec2 x y)) = GL.vertexAttrib2 loc x y+ vertexAttrib loc u = GL.vertexAttrib2 loc x y+ where Vec2 x y = fromNormal u instance VertexAttrib' Normal3 where- vertexAttrib loc (Normal3 (Vec3 x y z)) = GL.vertexAttrib3 loc x y z+ vertexAttrib loc u = GL.vertexAttrib3 loc x y z+ where Vec3 x y z = fromNormal u instance VertexAttrib' Normal4 where- vertexAttrib loc (Normal4 (Vec4 x y z w)) = GL.vertexAttrib4 loc x y z w----------------------------------------------------------+ vertexAttrib loc u = GL.vertexAttrib4 loc x y z w+ where Vec4 x y z w = fromNormal u + +-------------------------------------------------------------------------------- -- Uniform (again, experimental) -- (note that the uniform location code in the OpenGL 2.2.1.1 is broken; @@ -180,3 +295,5 @@ uniformv loc cnt ptr = uniformv loc (4*cnt) (castPtr ptr :: Ptr Flt) #endif++
src/flt/Util/Dim2.hs view
@@ -3,12 +3,13 @@ import Data.Vect.Flt.Base --- |example: @structVec2 [1,2,3,4] = [ Vec2 1 2 , Vec2 3 4 ]@.+-- | Example: @structVec2 [1,2,3,4] = [ Vec2 1 2 , Vec2 3 4 ]@. structVec2 :: [Flt] -> [Vec2] structVec2 [] = [] structVec2 (x:y:ls) = (Vec2 x y):(structVec2 ls) structVec2 _ = error "structVec2" +-- | The opposite of "structVec2". destructVec2 :: [Vec2] -> [Flt] destructVec2 [] = [] destructVec2 ((Vec2 x y):ls) = x:y:(destructVec2 ls) @@ -48,10 +49,13 @@ angle2' {- ' CPP is sensitive to primes -} :: Normal2 -> Flt angle2' = angle2 . fromNormal --- |Rotation matrix by a given angle (in radians), counterclockwise.+-- | Rotation matrix by a given angle (in radians), counterclockwise. rotMatrix2 :: Flt -> Mat2 rotMatrix2 a = Mat2 (Vec2 c s) (Vec2 (-s) c) where c = cos a; s = sin a +rotMatrixOrtho2 :: Flt -> Ortho2+rotMatrixOrtho2 = toOrthoUnsafe . rotMatrix2+ rotate2 :: Flt -> Vec2 -> Vec2 rotate2 a v = v .* (rotMatrix2 a) @@ -62,3 +66,5 @@ -- |Rotates clockwise by 90 degrees. rotateCW :: Vec2 -> Vec2 rotateCW (Vec2 x y) = Vec2 y (-x)++
src/flt/Util/Dim3.hs view
@@ -3,18 +3,26 @@ import Data.Vect.Flt.Base +--------------------------------------------------------------------------------++-- | Example: @structVec3 [1,2,3,4,5,6] = [ Vec3 1 2 3 , Vec3 4 5 6]@. structVec3 :: [Flt] -> [Vec3] structVec3 [] = [] structVec3 (x:y:z:ls) = (Vec3 x y z):(structVec3 ls) structVec3 _ = error "structVec3" +-- | The opposite of "structVec3". destructVec3 :: [Vec3] -> [Flt] destructVec3 [] = [] destructVec3 ((Vec3 x y z):ls) = x:y:z:(destructVec3 ls) +--------------------------------------------------------------------------------+ det3 :: Vec3 -> Vec3 -> Vec3 -> Flt det3 u v w = det (u,v,w) +--------------------------------------------------------------------------------+ translate3X :: Flt -> Vec3 -> Vec3 translate3Y :: Flt -> Vec3 -> Vec3 translate3Z :: Flt -> Vec3 -> Vec3@@ -42,26 +50,34 @@ rotMatrixY a = Mat3 (Vec3 c 0 (-s)) (Vec3 0 1 0) (Vec3 s 0 c) where c = cos a; s = sin a rotMatrixX a = Mat3 (Vec3 1 0 0) (Vec3 0 c s) (Vec3 0 (-s) c) where c = cos a; s = sin a -rotate3' :: {- ' CPP is sensitive to primes -} Flt -- ^ angle (in radians)- -> Normal3 -- ^ axis (should be a /unit/ vector!) - -> Vec3 -- ^ vector- -> Vec3 -- ^ result+--------------------------------------------------------------------------------++rotate3' {- ' CPP is sensitive to primes -} + :: Flt -- ^ angle (in radians)+ -> Normal3 -- ^ axis (should be a /unit/ vector!) + -> Vec3 -- ^ vector+ -> Vec3 -- ^ result rotate3' angle axis v = v .* (rotMatrix3' axis angle) -rotate3 :: Flt -- ^ angle (in radians)- -> Vec3 -- ^ axis (arbitrary nonzero vector)- -> Vec3 -- ^ vector- -> Vec3 -- ^ result+rotate3 + :: Flt -- ^ angle (in radians)+ -> Vec3 -- ^ axis (arbitrary nonzero vector)+ -> Vec3 -- ^ vector+ -> Vec3 -- ^ result rotate3 angle axis v = v .* (rotMatrix3 axis angle) --- |Rotation around an arbitrary 3D vector. The resulting 3x3 matrix is intended for multiplication on the /right/. +-- | Rotation around an arbitrary 3D vector. The resulting 3x3 matrix is intended for multiplication on the /right/. rotMatrix3 :: Vec3 -> Flt -> Mat3 rotMatrix3 v a = rotMatrix3' (mkNormal v) a --- |Rotation around an arbitrary 3D /unit/ vector. The resulting 3x3 matrix is intended for multiplication on the /right/. +rotMatrixOrtho3 :: Vec3 -> Flt -> Ortho3+rotMatrixOrtho3 v a = toOrthoUnsafe $ rotMatrix3 v a++-- | Rotation around an arbitrary 3D /unit/ vector. The resulting 3x3 matrix is intended for multiplication on the /right/. rotMatrix3' :: {- ' CPP is sensitive to primes -} Normal3 -> Flt -> Mat3-rotMatrix3' (Normal3 v) a = - let c = cos a+rotMatrix3' u a = + let v = fromNormal u+ c = cos a s = sin a m1 = scalarMul (1-c) (outer v v) x = _1 v@@ -72,4 +88,65 @@ (Vec3 ( s*y) (-s*x) c ) in (m1 &+ m2) +rotMatrixOrtho3' :: {- ' CPP is sensitive to primes -} Normal3 -> Flt -> Ortho3+rotMatrixOrtho3' u a = toOrthoUnsafe $ rotMatrix3' u a +--------------------------------------------------------------------------------++-- | Reflects a vector to an axis: that is, the result of @reflect n v@ is+-- 2\<n,v\>n - v+reflect :: Normal3 -> Vec3 -> Vec3+reflect u v = (s *& n) &- v where + n = fromNormal u+ s = 2 * (n &. v)++reflect' :: Normal3 -> Normal3 -> Normal3+reflect' u x = toNormalUnsafe $ reflect u (fromNormal x)+ +refract :: Flt -> Normal3 -> Vec3 -> Vec3+refract eta u v = s *& fromNormal w where+ s = norm v + w = refract' eta u (toNormalUnsafe $ v &* (1.0/s))+ +-- | Refraction.+-- First parameter (@eta@) is the relative refraction index +--+-- > refl_inside+-- > eta = --------------+-- > refl_outside+--+-- where \"inside\" is the direction of the second argument +-- (to vector normal to plane which models the boundary +-- between the two materials). That is, total internal reflection+-- can occur when @eta>1@.+--+-- The convention is that the origin is the point of intersection+-- of the ray and the surface, and all the vectors \"point away\"+-- from here (unlike, say, GLSL's @refract@, where the incident+-- vector \"points towards\" the material)+refract' {- ' CPP is sensitive to primes -} + :: Flt -> Normal3 -> Normal3 -> Normal3+refract' eta u i = + if k<0+ then reflect' u i + else toNormalUnsafe $ ((-eta) *& v) &- (- eta*c + sqrt k) *& n + where+ n = fromNormal u+ v = fromNormal i+ c = n &. v+ k = 1 - eta*eta*(1-c*c)++-- | When total internal reflection would occur, we return "Nothing".+refractOnly' {- ' CPP is sensitive to primes -} + :: Flt -> Normal3 -> Normal3 -> Maybe Normal3+refractOnly' eta u i = + if k<0+ then Nothing + else Just $ toNormalUnsafe $ ((-eta) *& v) &- (- eta*c + sqrt k) *& n + where+ n = fromNormal u+ v = fromNormal i+ c = n &. v+ k = 1 - eta*eta*(1-c*c)++--------------------------------------------------------------------------------
src/flt/Util/Dim4.hs view
@@ -39,7 +39,7 @@ vec4Z = Vec4 0 0 1 0 vec4W = Vec4 0 0 0 1 ----------------------------------------------------------------------------+-------------------------------------------------------------------------------- -- |If @(x,y,u,v)@ is an orthonormal system, then (written in pseudo-code) -- @biVector4 (x,y) = plusMinus (reverse $ biVector4 (u,v))@.@@ -75,8 +75,9 @@ -- | Rotation matrix around a plane specified by two normalized and /orthogonal/ vectors. -- Intended for multiplication on the /right/! rotMatrix4' :: {- ' CPP is sensitive to primes -} Flt -> (Normal4,Normal4) -> Mat4-rotMatrix4' angle (Normal4 v, Normal4 w) = m1 &+ (s *& m2) &+ m3 +rotMatrix4' angle (u1,u2) = m1 &+ (s *& m2) &+ m3 where+ v = fromNormal u1 ; w = fromNormal u2 c = cos angle ; s = sin angle m1 = scalarMul (1-c) ( outer v v &+ outer w w ) m2 = biVector4AsTensor v w
src/flt/Util/Projective.hs view
@@ -1,5 +1,6 @@ --- | Classic 4x4 projective matrices. Our convention is that they are intended for multiplication on+-- | Classic 4x4 projective matrices, encoding the affine transformations of R^3.+-- Our convention is that they are intended for multiplication on -- the /right/, that is, they are of the form -- -- > _____@@ -12,6 +13,8 @@ -- store them by rows; but OpenGL also use the opposite convention (so the OpenGL projective matrices -- are intended for multiplication on the /left/). So in effect, they are the same when stored in the memory, -- say with @poke :: Ptr Mat4 -> Mat4 -> IO ()@.+--+-- Warning: The naming conventions will probably change in the future. module Data.Vect.Flt.Util.Projective where @@ -20,68 +23,73 @@ import qualified Data.Vect.Flt.Util.Dim4 as Dim4 -class ExtendProjective v e | v->e where- extendProj :: v -> e- extendProjWith :: Flt -> v -> e- extendProj = extendProjWith 1- -instance ExtendProjective Vec2 Vec4 where- extendProj (Vec2 x y) = Vec4 x y 0 1- extendProjWith w (Vec2 x y) = Vec4 x y 0 w- -instance ExtendProjective Vec3 Vec4 where- extendProj (Vec3 x y z) = Vec4 x y z 1- extendProjWith w (Vec3 x y z) = Vec4 x y z w--instance ExtendProjective Vec4 Vec4 where- extendProj = id- extendProjWith w (Vec4 x y z w') = let s = w/w' in Vec4 (s*x) (s*y) (s*z) w+-------------------------------------------------------------------------------- -instance ExtendProjective Mat2 Mat4 where- extendProj (Mat2 r1 r2) = Mat4 (extendZero r1) (extendZero r2) (Dim4.vec4Z) (Vec4 0 0 0 1)- extendProjWith w (Mat2 r1 r2) = Mat4 (extendZero r1) (extendZero r2) (Dim4.vec4Z) (Vec4 0 0 0 w)+rotMatrixProj4' :: {- ' CPP is sensitive to primes -} Flt -> Normal3 -> Proj4+rotMatrixProj4' angle axis = linear $ rotMatrix3' axis angle -instance ExtendProjective Mat3 Mat4 where- extendProj (Mat3 r1 r2 r3) = Mat4 (extendZero r1) (extendZero r2) (extendZero r3) (Vec4 0 0 0 1)- extendProjWith w (Mat3 r1 r2 r3) = Mat4 (extendZero r1) (extendZero r2) (extendZero r3) (Vec4 0 0 0 w)+rotMatrixProj4 :: Flt -> Vec3 -> Proj4+rotMatrixProj4 angle axis = linear $ rotMatrix3 axis angle -rotMatrixProj :: Flt -> Normal3 -> Mat4-rotMatrixProj angle axis = extendProj $ rotMatrix3' axis angle+-- | synonym for "rotateAfterProj4"+rotateProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateProj4 = rotateAfterProj4 -rotMatrixProj' :: {- ' CPP is sensitive to primes -} Flt -> Vec3 -> Mat4-rotMatrixProj' angle axis = extendProj $ rotMatrix3 axis angle+-- | Synonym for @\m -> m .*. rotMatrixProj4 angle axis@.+rotateAfterProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateAfterProj4 angle axis m = m .*. (rotMatrixProj4' angle axis) -translMatrixProj :: Vec3 -> Mat4-translMatrixProj v = Mat4 Dim4.vec4X Dim4.vec4Y Dim4.vec4Z (extendProj v)+-- | Synonym for @\m -> rotMatrixProj4 angle axis .*. m@.+rotateBeforeProj4 :: Flt -> Normal3 -> Proj4 -> Proj4+rotateBeforeProj4 angle axis m = (rotMatrixProj4' angle axis) .*. m --- | we assume that the bottom-right corner is 1.-translWithProj :: Vec3 -> Mat4 -> Mat4-translWithProj v mat@(Mat4 r1 r2 r3 r4) = Mat4 r1 r2 r3 (extendProjWith 0 v &+ r4)+--------------- -scaleMatrixProj :: Vec3 -> Mat4-scaleMatrixProj v = diag $ extendProj v+--scalingUniformProj3 :: Flt -> Proj3+--scalingUniformProj3 x = scaling (Vec2 x x) -scaleMatrixUniformProj :: Flt -> Mat4-scaleMatrixUniformProj s = diag (Vec4 s s s 1)+scalingUniformProj4 :: Flt -> Proj4+scalingUniformProj4 x = scaling (Vec3 x x x) -class ProjectiveAction v where- actProj :: v -> Mat4 -> v- -instance ProjectiveAction Vec3 where- actProj v m = trim $ (extendProj v) .* m +-- | Equivalent to @\m -> scaling v .*. m@.+scaleBeforeProj4 :: Vec3 -> Proj4 -> Proj4+scaleBeforeProj4 (Vec3 u v w) p4 = + toProjectiveUnsafe $ + Mat4 (u*&a) (v*&b) (w*&c) t+ where+ Mat4 a b c t = fromProjective p4 -instance ProjectiveAction Vec4 where- actProj v m = v .* m +-- | Equivalent to @\m -> m .*. scaling v@.+scaleAfterProj4 :: Vec3 -> Proj4 -> Proj4+scaleAfterProj4 v p4 =+ toProjectiveUnsafe $ + Mat4 (a&!w) (b&!w) (c&!w) (t&!w)+ where+ w = extendWith 1 v+ Mat4 a b c t = fromProjective p4+ +--------------- --- | When acting on unit vectors, we ignore the translation part.-instance ProjectiveAction Normal3 where- actProj (Normal3 v) m = Normal3 (v .* (trim m :: Mat3))+-- | Synonym for "translateAfter4"+translate4 :: Vec3 -> Proj4 -> Proj4+translate4 = translateAfter4 --- | Inverts a projective 4x4 matrix, assuming that the top-left 3x3 part is /orthogonal/,--- and the bottom-right corner is 1.-invertProj :: Mat4 -> Mat4-invertProj mat@(Mat4 u v w t) = - translWithProj t' $ extendProj $ transpose $ (trim mat :: Mat3)+-- | Equivalent to @\m -> m .*. translation v@.+translateAfter4 :: Vec3 -> Proj4 -> Proj4+translateAfter4 v p4 = + toProjectiveUnsafe $+ Mat4 r1 r2 r3 (extendWith 0 v &+ r4) where- t' = Vec3 (- u &. t) (- v &. t) (- w &. t)- + Mat4 r1 r2 r3 r4 = fromProjective p4 ++-- | Equivalent to @\m -> translation v .*. m@.+translateBefore4 :: Vec3 -> Proj4 -> Proj4+translateBefore4 v p4 = + toProjectiveUnsafe $ + Mat4 r1 r2 r3 (extendWith 0 u &+ r4) + where + u = v .* (trim mat :: Mat3) + mat@(Mat4 r1 r2 r3 r4) = fromProjective p4+ +---------------+
vect.cabal view
@@ -1,5 +1,5 @@ Name: vect-Version: 0.4.0+Version: 0.4.5 Synopsis: A low-dimensional linear algebra library, tailored to computer graphics. Description: A low-dimensional (2, 3 and 4) linear algebra library, with lots of useful functions. Intended usage is primarily