{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts , UndecidableInstances, TypeOperators , TypeFamilies, TypeSynonymInstances #-} {-# OPTIONS_GHC -Wall -fno-warn-orphans #-} ---------------------------------------------------------------------- -- | -- Module : Vector3 -- Copyright : (c) Conal Elliott and Andy J Gill 2008 -- License : BSD3 -- -- Maintainer : conal@conal.net, andygill@ku.edu -- Stability : experimental -- -- Vectors in 3D. Uses the OpenGL 'Vector3' type, for convenience and -- efficiency. ---------------------------------------------------------------------- module Graphics.FieldTrip.Vector3 ( Vector3(..), vector3 , xVector3, yVector3, zVector3 , vector3x, vector3y, vector3z , vector3Spherical , vector3SphericalCoords , vector3D, unvector3D, cross3 ) where import Graphics.Rendering.OpenGL (Vector3(..)) import Data.VectorSpace import Data.MemoTrie import Data.Basis import Data.Derivative import Data.Cross import Graphics.FieldTrip.Vector2 -- type V3 = Vector3 Double -- | Construct a 3D vector in rectangular coordinates. vector3 :: s -> s -> s -> Vector3 s vector3 = Vector3 -- | The unit vector in the positive X direction. xVector3 :: Num s => Vector3 s xVector3 = Vector3 1 0 0 -- | The unit vector in the positive Y direction. yVector3 :: Num s => Vector3 s yVector3 = Vector3 0 1 0 -- | The unit vector in the positive Z direction. zVector3 :: Num s => Vector3 s zVector3 = Vector3 0 0 1 vector3x, vector3y, vector3z :: Vector3 s -> s vector3x (Vector3 x _ _) = x vector3y (Vector3 _ y _) = y vector3z (Vector3 _ _ z) = z -- vector3RectCoords :: Vector3 -> (R,R,R) -- vector3RectCoords (Vector3 x y z) = (x,y,z) -- | Vector from spherical coordinates. See also 'vector2SphericalCoords'. vector3Spherical :: Floating s => s -> s -> s -> Vector3 s vector3Spherical rho theta phi = Vector3 (rho * sinPhi * cosTheta) (rho * sinPhi * sinTheta) (rho * cosPhi) where cosTheta = cos theta; cosPhi = cos phi sinTheta = sin theta; sinPhi = sin phi -- | Spherical coordinates of a vector. See also 'vector2Spherical'. vector3SphericalCoords :: (InnerSpace s, Floating s, Scalar s ~ s) => Vector3 s -> (s,s,s) vector3SphericalCoords v@(Vector3 x y z) = (rho, theta, phi) where rho = magnitude v theta = atan (y/x) -- in case (==) is not defined, as in (a:>b) -- if x == 0 then 0 else atan (y/x) phi = acos (z / rho) instance AdditiveGroup u => AdditiveGroup (Vector3 u) where zeroV = Vector3 zeroV zeroV zeroV Vector3 u v w ^+^ Vector3 u' v' w' = Vector3 (u^+^u') (v^+^v') (w^+^w') negateV (Vector3 u v w) = Vector3 (negateV u) (negateV v) (negateV w) instance VectorSpace u => VectorSpace (Vector3 u) where type Scalar (Vector3 u) = Scalar u s *^ Vector3 u v w = Vector3 (s*^u) (s*^v) (s*^w) instance (InnerSpace u, AdditiveGroup (Scalar u)) => InnerSpace (Vector3 u) where Vector3 u v w <.> Vector3 u' v' w' = u<.>u' ^+^ v<.>v' ^+^ w<.>w' instance HasBasis u => HasBasis (Vector3 u) where type Basis (Vector3 u) = Basis (u,u,u) basisValue = toV3 . basisValue decompose = decompose . fromV3 decompose' = decompose' . fromV3 toV3 :: (u,u,u) -> Vector3 u toV3 (u,v,w) = Vector3 u v w fromV3 :: Vector3 u -> (u,u,u) fromV3 (Vector3 u v w) = (u,v,w) instance ( Num s, VectorSpace s , HasBasis s, HasTrie (Basis s), Basis s ~ () ) => HasNormal (Vector2 s :> Vector3 s) where normalVec v = d (Left ()) `cross3` d (Right ()) where d = derivAtBasis v -- Above doesn't seem to work in ghc 6.8. So use explicit instances for -- 'Float' & 'Double'. Revisit. -- instance HasNormal (Vector2 Float :> Vector3 Float) where -- normalVec v = d (Left ()) `cross3` d (Right ()) -- where -- d = untrie (derivative v) -- instance HasNormal (Vector2 Double :> Vector3 Double) where -- normalVec v = d (Left ()) `cross3` d (Right ()) -- where -- d = untrie (derivative v) instance Num s => HasCross3 (Vector3 s) where Vector3 ax ay az `cross3` Vector3 bx by bz = Vector3 (ay * bz - az * by) (az * bx - ax * bz) (ax * by - ay * bx) -- instance (Num s, VectorSpace s s) => HasCross (Vector3 (Vector2 s :> s)) where -- cross = unvector3F . cross . vector3F -- vector3F :: (Applicative f) => Vector3 (f s) -> f (Vector3 s) -- vector3F (Vector3 u v w) = liftA3 Vector3 u v w -- unvector3F :: (Functor f) => f (Vector3 s) -> Vector3 (f s) -- unvector3F d = Vector3 (vector3x <$> d) (vector3y <$> d) (vector3z <$> d) -- instance (Num s, LMapDom s s) => HasNormal (Three (Vector2 s :> s)) where -- normalVec = unvector3D . normalVec . vector3D -- instance ( Num s, VectorSpace s s, HasBasis s s, HasTrie (Basis s) -- , HasNormal (Vector2 s :> Vector3 s) -- , HasBasis (Vector2 s) s, HasTrie (Basis (Vector2 s))) -- => HasNormal (Vector3 (Vector2 s :> s)) where -- normalVec v = d (Left ()) `cross3` d (Right ()) -- where -- d = untrie (derivative v) -- instance (Num s, VectorSpace s s, HasBasis s s, HasTrie (Basis s)) => -- HasNormal (Three (Vector2 s :> s)) where -- normalVec = unvector3D . normalVec . vector3D -- sigh. try the instance above when we're on ghc-6.9 instance HasNormal (Three (Vector2 Float :> Float)) where normalVec = unvector3D . normalVec . vector3D instance HasNormal (Three (Vector2 Double :> Double)) where normalVec = unvector3D . normalVec . vector3D vector3D :: (VectorSpace s, HasBasis a, HasTrie (Basis a)) => Three (a :> s) -> a :> (Vector3 s) vector3D (u,v,w) = liftD3 Vector3 u v w unvector3D :: (VectorSpace s, HasBasis a, HasTrie (Basis a)) => a :> (Vector3 s) -> Three (a :> s) unvector3D d = (vector3x <$>> d, vector3y <$>> d, vector3z <$>> d)