{-# LANGUAGE BangPatterns #-}
module Geometry.Vector3D
    where
import Geometry.Vector
import Geometry.Data

import Data.List

infixl 6 +.+.+, -.-.-
infixl 7 *.*.*

{- | 3D coordinate-wise addition.  -}
(+.+.+) :: Point3 -> Point3 -> Point3
{-# INLINE (+.+.+) #-}
V3 x1 y1 z1 +.+.+ V3 x2 y2 z2 =
  let
    !x = x1 + x2
    !y = y1 + y2
    !z = z1 + z2
  in V3 x y z
{- | 3D coordinate-wise subtraction.  -}
(-.-.-) :: Point3 -> Point3 -> Point3
{-# INLINE (-.-.-) #-}
V3 x1 y1 z1 -.-.- V3 x2 y2 z2 =
  let
    !x = x1 - x2
    !y = y1 - y2
    !z = z1 - z2
  in V3 x y z
{- | 3D scalar multiplication.  -}
(*.*.*) :: Float -> Point3 -> Point3
{-# INLINE (*.*.*) #-}
a *.*.* (V3 x2 y2 z2) =
  let
    !x = a * x2
    !y = a * y2
    !z = a * z2
  in V3 x y z

crossProd :: Point3 -> Point3 -> Point3
crossProd (V3 x y z) (V3 a b c) = V3
    ( y * c - z * b)
    ( z * a - x * c)
    ( x * b - y * a)

rotate3 :: Float -> Point3 -> Point3
{-# INLINE rotate3 #-}
rotate3 a (V3 x y z) = V3 x' y' z
  where 
    (V2 x' y') = rotateV a (V2 x y)

magV3 :: Point3 -> Float
{-# INLINE magV3 #-}
magV3 (V3 x y z) = sqrt $ x^i + y^i + z^i
  where
    i = 2 :: Int

normalizeV3 :: Point3 -> Point3
{-# INLINE normalizeV3 #-}
normalizeV3 (V3 0 0 0) = V3 0 0 0
normalizeV3 p = (1 / magV3 p) *.*.* p

addZ :: Float -> Point2 -> Point3
{-# INLINE addZ #-}
addZ z (V2 x y) = V3 x y z

stripZ :: Point3 -> Point2
{-# INLINE stripZ #-}
stripZ (V3 x y _) = V2 x y

dist3 :: Point3 -> Point3 -> Float
{-# INLINE dist3 #-}
dist3 !p1 !p2 = magV3 (p2 -.-.- p1)

orderAround3
    :: Point3 -- ^ Vector to order around
    -> [Point3]
    -> [Point3]
orderAround3 v ps = sortOn (argV . prj) ps
  where
    xdir = crossProd v (head ps)
    ydir = crossProd v xdir
    prj p = V2 (dotV3 xdir p) (dotV3 ydir p)

vCen3 :: [Point3] -> Point3
vCen3 ps = (1 / fromIntegral (length ps)) *.*.* foldr (+.+.+) (V3 0 0 0) ps 

dotV3
    :: Point3
    -> Point3
    -> Float
dotV3 (V3 x y z) (V3 a b c) = x*a + y*b + z*c

projV3
    :: Point3
    -> Point3
    -> Point3
projV3 = undefined


