{- |
  3-dimensional vectors with vector arithmetic.
-}

module Data.Vector.V3 where

import Data.Vector.Class

data Vector3 = Vector3 {v3x, v3y, v3z :: {-# UNPACK #-} !Scalar} deriving (Eq, Show)

instance Vector Vector3 where
  vmap  f (Vector3 x  y  z )                    = Vector3 (f x)     (f y)     (f z)
  vzip  f (Vector3 x1 y1 z1) (Vector3 x2 y2 z2) = Vector3 (f x1 x2) (f y1 y2) (f z1 z2)
  vfold f (Vector3 x  y  z )                    = f x (f y z)

  vpack (x:y:z:_) = Just $ Vector3 x y z
  vpack _         = Nothing

  vunpack (Vector3 x y z) = [x,y,z]

instance Num Vector3 where
  (+) = vzip (+)
  (-) = vzip (-)
  (*) = vzip (*)
  abs = vmap abs
  signum = vmap signum
  fromInteger x = let x' = fromInteger x in Vector3 x' x' x'

instance Fractional Vector3 where
  (/) = vzip (/)
  recip = vmap recip
  fromRational x = let x' = fromRational x in Vector3 x' x' x'

{- |
  Take the /cross product/ of two 3D vectors. This produces a new 3D vector that is perpendicular to the plane of the first two vectors, and who's length is equal to the sine of the angle between those vectors multiplied by their lengths.

  Note that @a \`vcross\` b = negate (b \`vcross\` a)@.
-}
vcross :: Vector3 -> Vector3 -> Vector3
vcross (Vector3 x1 y1 z1) (Vector3 x2 y2 z2) =
  Vector3
  {
    v3x = y1 * z2   -   y2 * z1,
    v3y = z1 * x2   -   z2 * x1,
    v3z = x1 * y2   -   x2 * y1
  }