{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
{-# LANGUAGE ExistentialQuantification, MultiParamTypeClasses, FlexibleInstances, StandaloneDeriving #-}
-----------------------------------------------------------------------------------------
-- |
-- Module : Data.Vector3
-- Copyright : (c) Antony Courtney and Henrik Nilsson, Yale University, 2003
-- License : BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer : ivan.perez@keera.co.uk
-- Stability : provisional
-- Portability : non-portable (GHC extensions)
--
-- 3D vector abstraction (R^3).
--
-----------------------------------------------------------------------------------------
module Data.Vector3 (
Vector3, -- Abstract, instance of VectorSpace
vector3, -- :: RealFloat a => a -> a -> a -> Vector3 a
vector3X, -- :: RealFloat a => Vector3 a -> a
vector3Y, -- :: RealFloat a => Vector3 a -> a
vector3Z, -- :: RealFloat a => Vector3 a -> a
vector3XYZ, -- :: RealFloat a => Vector3 a -> (a, a, a)
vector3Spherical, -- :: RealFloat a => a -> a -> a -> Vector3 a
vector3Rho, -- :: RealFloat a => Vector3 a -> a
vector3Theta, -- :: RealFloat a => Vector3 a -> a
vector3Phi, -- :: RealFloat a => Vector3 a -> a
vector3RhoThetaPhi, -- :: RealFloat a => Vector3 a -> (a, a, a)
vector3Rotate -- :: RealFloat a => a -> a -> Vector3 a -> Vector3 a
) where
import Control.DeepSeq (NFData(..))
import Data.VectorSpace
-- * 3D vector, constructors and selectors
-- | 3D Vector.
-- Restrict coefficient space to RealFloat (rather than Floating) for now.
-- While unclear if a complex coefficient space would be useful (and if the
-- result really would be a 3d vector), the only thing causing trouble is the
-- use of atan2 in vector3Theta and vector3Phi. Maybe atan2 can be generalized?
data Vector3 a = RealFloat a => Vector3 !a !a !a
deriving instance Eq a => Eq (Vector3 a)
deriving instance Show a => Show (Vector3 a)
instance NFData a => NFData (Vector3 a) where
rnf (Vector3 x y z) = rnf x `seq` rnf y `seq` rnf z `seq` ()
-- | Creates a 3D vector from the cartesian coordinates.
vector3 :: RealFloat a => a -> a -> a -> Vector3 a
vector3 = Vector3
-- | X cartesian coordinate.
vector3X :: RealFloat a => Vector3 a -> a
vector3X (Vector3 x _ _) = x
-- | Y cartesian coordinate.
vector3Y :: RealFloat a => Vector3 a -> a
vector3Y (Vector3 _ y _) = y
-- | Z cartesian coordinate.
vector3Z :: RealFloat a => Vector3 a -> a
vector3Z (Vector3 _ _ z) = z
-- | Returns a vector's cartesian coordinates.
vector3XYZ :: RealFloat a => Vector3 a -> (a, a, a)
vector3XYZ (Vector3 x y z) = (x, y, z)
-- | Creates a 3D vector from the spherical coordinates.
vector3Spherical :: RealFloat a => a -> a -> a -> Vector3 a
vector3Spherical rho theta phi =
Vector3 (rhoSinPhi * cos theta) (rhoSinPhi * sin theta) (rho * cos phi)
where
rhoSinPhi = rho * sin phi
-- | Calculates the vector's radial distance.
vector3Rho :: RealFloat a => Vector3 a -> a
vector3Rho (Vector3 x y z) = sqrt (x * x + y * y + z * z)
-- | Calculates the vector's azimuth.
vector3Theta :: RealFloat a => Vector3 a -> a
vector3Theta (Vector3 x y _) = atan2 y x
-- | Calculates the vector's inclination.
vector3Phi :: RealFloat a => Vector3 a -> a
vector3Phi v@(Vector3 _ _ z) = acos (z / vector3Rho v)
-- | Spherical coordinate representation of a 3D vector.
vector3RhoThetaPhi :: RealFloat a => Vector3 a -> (a, a, a)
vector3RhoThetaPhi (Vector3 x y z) = (rho, theta, phi)
where
rho = sqrt (x * x + y * y + z * z)
theta = atan2 y x
phi = acos (z / rho)
-- * Vector space instance
instance RealFloat a => VectorSpace (Vector3 a) a where
zeroVector = Vector3 0 0 0
a *^ (Vector3 x y z) = Vector3 (a * x) (a * y) (a * z)
(Vector3 x y z) ^/ a = Vector3 (x / a) (y / a) (z / a)
negateVector (Vector3 x y z) = (Vector3 (-x) (-y) (-z))
(Vector3 x1 y1 z1) ^+^ (Vector3 x2 y2 z2) = Vector3 (x1+x2) (y1+y2) (z1+z2)
(Vector3 x1 y1 z1) ^-^ (Vector3 x2 y2 z2) = Vector3 (x1-x2) (y1-y2) (z1-z2)
(Vector3 x1 y1 z1) `dot` (Vector3 x2 y2 z2) = x1 * x2 + y1 * y2 + z1 * z2
-- * Additional operations
-- | Rotates a vector with a given polar and azimuthal angles.
vector3Rotate :: RealFloat a => a -> a -> Vector3 a -> Vector3 a
vector3Rotate theta' phi' v =
vector3Spherical (vector3Rho v)
(vector3Theta v + theta')
(vector3Phi v + phi')