-- | -- Module: Data.Geo.Jord.Vector3d -- Copyright: (c) 2018 Cedric Liegeois -- License: BSD3 -- Maintainer: Cedric Liegeois -- Stability: experimental -- Portability: portable -- -- 3-element vectors. -- module Data.Geo.Jord.Vector3d ( Vector3d(..) , IsVector3d(..) , vadd , vsub , vdot , vnorm , vcross , vrotate , vscale , vunit , vzero , transpose , mdot ) where -- | 3-element vector. data Vector3d = Vector3d { vx :: Double , vy :: Double , vz :: Double } deriving (Eq, Show) -- | class for data types assimilated to 'Vector3d'. class IsVector3d a where vec :: a -> Vector3d -- | Adds 2 vectors. vadd :: Vector3d -> Vector3d -> Vector3d vadd v1 v2 = Vector3d x y z where x = vx v1 + vx v2 y = vy v1 + vy v2 z = vz v1 + vz v2 -- | Subtracts 2 vectors. vsub :: Vector3d -> Vector3d -> Vector3d vsub v1 v2 = Vector3d x y z where x = vx v1 - vx v2 y = vy v1 - vy v2 z = vz v1 - vz v2 -- | Computes the cross product of 2 vectors: the vector perpendicular to given vectors. vcross :: Vector3d -> Vector3d -> Vector3d vcross v1 v2 = Vector3d x y z where x = vy v1 * vz v2 - vz v1 * vy v2 y = vz v1 * vx v2 - vx v1 * vz v2 z = vx v1 * vy v2 - vy v1 * vx v2 -- | Computes the dot product of 2 vectors. vdot :: Vector3d -> Vector3d -> Double vdot v1 v2 = vx v1 * vx v2 + vy v1 * vy v2 + vz v1 * vz v2 -- | Computes the norm of a vector. vnorm :: Vector3d -> Double vnorm v = sqrt (x * x + y * y + z * z) where x = vx v y = vy v z = vz v -- | @vrotate v rm@ applies rotation matrix @rm@ to @v@. vrotate :: Vector3d -> [Vector3d] -> Vector3d vrotate v rm | length rm /= 3 = error ("Invalid rotation matrix" ++ show rm) | otherwise = Vector3d x y z where [x, y, z] = map (vdot v) rm -- | @vscale v s@ multiplies each component of @v@ by @s@. vscale :: Vector3d -> Double -> Vector3d vscale v s = Vector3d x y z where x = vx v * s y = vy v * s z = vz v * s -- | Normalises a vector. The 'vnorm' of the produced vector is @1@. vunit :: Vector3d -> Vector3d vunit v | s == 1.0 = v | otherwise = vscale v s where s = 1.0 / vnorm v -- | vector of vnorm 0. vzero :: Vector3d vzero = Vector3d 0 0 0 -- | transpose __square__ matrix made of 'Vector3d'. transpose :: [Vector3d] -> [Vector3d] transpose m = fmap ds2v (transpose' xs) where xs = fmap v2ds m -- | transpose matrix. transpose' :: [[Double]] -> [[Double]] transpose' ([]:_) = [] transpose' x = map head x : transpose' (map tail x) -- | multiplies 2 matrices of 'Vector3d'. mdot :: [Vector3d] -> [Vector3d] -> [Vector3d] mdot a b = fmap ds2v [[vdot ar bc | bc <- transpose b] | ar <- a] -- | 'Vector3d' to list of doubles. v2ds :: Vector3d -> [Double] v2ds (Vector3d x' y' z') = [x', y', z'] -- | list of doubles to 'Vector3d'. ds2v :: [Double] -> Vector3d ds2v [x', y', z'] = Vector3d x' y' z' ds2v xs = error ("Invalid list: " ++ show xs)