-- GENERATED by C->Haskell Compiler, version 0.28.3 Switcheroo, 25 November 2017 (Haskell)
-- Edit the ORIGNAL .chs file instead!


{-# LINE 1 "src/Chiphunk/Low/Vect.chs" #-}
-- | Description: 2D vector manipulations.
-- Module provides utilities to manipulate 2D vectors. Most of the code is re-implemented in Haskell (mirrorring C)
-- to avoid unnecessary foreign calls/marshalling, but only for simple operations.
--
-- Also note that 'Vect' has 'Eq', 'AdditiveGroup', 'VectorSpace', 'InnerSpace' and 'HasCross2' instances.
-- Large part of functions in this module just provides Chiphunk-compatible aliases for those instances' methods.
module Chiphunk.Low.Vect
  ( Vect (..)
  , cpv
  , vZero
  , vEql
  , vAdd
  , vSub
  , vNeg
  , vMult
  , vDot
  , vCross
  , vPerp
  , vRPerp
  , vProject
  , vRotate
  , vUnRotate
  , vLength
  , vLengthSq
  , vLerp
  , vLerpConst
  , vSLerp
  , vSLerpConst
  , vNormalize
  , vClamp
  , vDist
  , vDistSq
  , vNear
  , vForAngle
  , vToAngle
  ) where
import qualified Foreign.C.Types as C2HSImp
import qualified System.IO.Unsafe as C2HSImp



import Data.Cross
import Data.VectorSpace
import Foreign

import Chiphunk.Low.Types
{-# LINE 42 "src/Chiphunk/Low/Vect.chs" #-}




-- | Convenience constructor for creating new cpVect structs.
-- Alias for 'Vect'
cpv :: Double -> Double -> Vect
cpv = Vect

-- | Constant for the zero vector.
--
-- Alias for 'zeroV'
vZero :: Vect
vZero = zeroV

-- | Check if two vectors are equal. (Be careful when comparing floating point numbers!)
--
-- Alias for '=='.
vEql :: Vect -> Vect -> Bool
vEql = (==)

-- | Add two vectors.
--
-- Alias for '^+^'.
vAdd :: Vect -> Vect -> Vect
vAdd = (^+^)

-- | Subtract two vectors.
--
-- Alias for '^-^'.
vSub :: Vect -> Vect -> Vect
vSub = (^-^)

-- | Negate a vector.
--
-- Alias for 'negateV'.
vNeg :: Vect -> Vect
vNeg = negateV

-- | Scalar multiplication.
--
-- Alias for '^*'.
vMult :: Vect -> Double -> Vect
vMult = (^*)

-- | Vector dot product.
--
-- Alias for '<.>'.
vDot :: Vect -> Vect -> Double
vDot = (<.>)

-- | 2D vector cross product analog. The cross product of 2D vectors results in a 3D vector with only a z component.
-- This function returns the value along the z-axis.
vCross :: Vect -> Vect -> Double
Vect x1 y1 `vCross` Vect x2 y2 = x1 * y2 - y1 * x2

-- | Returns a perpendicular vector. (90 degree rotation)
--
-- Alias for 'cross2'.
vPerp :: Vect -> Vect
vPerp = cross2

-- | Returns a perpendicular vector. (-90 degree rotation)
vRPerp :: Vect -> Vect
vRPerp v = negateV $ cross2 v

-- | Returns the vector projection of @v1@ onto @v2@.
--
-- Alias for 'project'.
vProject
  :: Vect -- ^ v1
  -> Vect -- ^ v2
  -> Vect
vProject = project

-- | Uses complex multiplication to rotate @v1@ by @v2@. Scaling will occur if @v1@ is not a unit vector.
vRotate
  :: Vect -- ^ v1
  -> Vect -- ^ v2
  -> Vect
Vect x1 y1 `vRotate` Vect x2 y2 = Vect (x1 * x2 - y1 * y2) (x1 * y2 + x2 * y1)

-- | Inverse of 'vRotate'.
vUnRotate :: Vect -> Vect -> Vect
Vect x1 y1 `vUnRotate` Vect x2 y2 = Vect (x1 * x2 + y1 * y2) (x2 * y1 - x1 * y2)

-- | Returns the length of v.
--
-- Alias for 'magnitude'.
vLength :: Vect -> Double
vLength = magnitude

-- | Returns the squared length of @v@. Faster than 'vLength' when you only need to compare lengths.
--
-- Alias for 'magnitudeSq'.
vLengthSq :: Vect -> Double
vLengthSq = magnitudeSq

-- | Linearly interpolate between @v1@ and @v2@.
--
-- Alias for 'lerp'.
vLerp
  :: Vect   -- ^ v1
  -> Vect   -- ^ v2
  -> Double
  -> Vect
vLerp = lerp

-- | Linearly interpolate between @v1@ towards @v2@ by distance @d@.
vLerpConst
  :: Vect   -- ^ v1
  -> Vect   -- ^ v2
  -> Double -- ^ d
  -> Vect
vLerpConst a b l = a ^+^ vClamp (b ^-^ a) l

-- | Spherical linearly interpolate between v1 and v2.
vSLerp :: (Vect) -- ^ v1
 -> (Vect) -- ^ v2
 -> (Double) -> (Vect)
vSLerp a1 a2 a3 =
  C2HSImp.unsafePerformIO $
  with a1 $ \a1' ->
  with a2 $ \a2' ->
  let {a3' = realToFrac a3} in
  alloca $ \a4' ->
  vSLerp'_ a1' a2' a3' a4' >>
  peek  a4'>>= \a4'' ->
  return (a4'')

{-# LINE 164 "src/Chiphunk/Low/Vect.chs" #-}


-- | Spherical linearly interpolate between @v1@ towards @v2@ by no more than angle @a@ in radians.
vSLerpConst :: (Vect) -- ^ v1
 -> (Vect) -- ^ v2
 -> (Double) -- ^ a
 -> (Vect)
vSLerpConst a1 a2 a3 =
  C2HSImp.unsafePerformIO $
  with a1 $ \a1' ->
  with a2 $ \a2' ->
  let {a3' = realToFrac a3} in
  alloca $ \a4' ->
  vSLerpConst'_ a1' a2' a3' a4' >>
  peek  a4'>>= \a4'' ->
  return (a4'')

{-# LINE 172 "src/Chiphunk/Low/Vect.chs" #-}


-- | Returns a normalized copy of @v@. As a special case, it returns 'vZero' when called on 'vZero'.
--
-- Alias for 'normalized'.
vNormalize :: Vect -> Vect
vNormalize = normalized

-- | Clamp @v@ to length @len@.
vClamp
  :: Vect   -- ^ v
  -> Double -- ^ len
  -> Vect
vClamp v l
  | magnitudeSq v > l * l = l *^ normalized v
  | otherwise             = v

-- | Returns the distance between @v1@ and @v2@.
vDist
  :: Vect   -- ^ v1
  -> Vect   -- ^ v2
  -> Double
vDist v1 v2 = magnitude $ v1 ^-^ v2

-- | Returns the squared distance between @v1@ and @v2@. Faster than 'vDist' when you only need to compare distances.
vDistSq
  :: Vect   -- ^ v1
  -> Vect   -- ^ v2
  -> Double
vDistSq v1 v2 = magnitudeSq $ v1 ^-^ v2

-- | Returns true if the distance between @v1@ and @v2@ is less than @dist@.
vNear
  :: Vect   -- ^ v1
  -> Vect   -- ^ v2
  -> Double -- ^ dist
  -> Bool
vNear v1 v2 d = vDistSq v1 v2 < d * d

-- | Returns the unit length vector for the given angle (in radians).
vForAngle :: Double -> Vect
vForAngle alpha = Vect (cos alpha) (sin alpha)

-- | Returns the angular direction @v@ is pointing in (in radians).
vToAngle
  :: Vect   -- ^ v
  -> Double
vToAngle (Vect x y) = atan2 y x

foreign import ccall unsafe "Chiphunk/Low/Vect.chs.h __c2hs_wrapped__w_cpvslerp"
  vSLerp'_ :: ((VectPtr) -> ((VectPtr) -> (C2HSImp.CDouble -> ((VectPtr) -> (IO ())))))

foreign import ccall unsafe "Chiphunk/Low/Vect.chs.h __c2hs_wrapped__w_cpvslerpconst"
  vSLerpConst'_ :: ((VectPtr) -> ((VectPtr) -> (C2HSImp.CDouble -> ((VectPtr) -> (IO ())))))