-- 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 :: Double -> Double -> Vect
cpv = Double -> Double -> Vect
Vect

-- | Constant for the zero vector.
--
-- Alias for 'zeroV'
vZero :: Vect
vZero :: Vect
vZero = Vect
forall v. AdditiveGroup v => v
zeroV

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

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

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

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

-- | Scalar multiplication.
--
-- Alias for '^*'.
vMult :: Vect -> Double -> Vect
vMult :: Vect -> Double -> Vect
vMult = Vect -> Double -> Vect
forall v s. (VectorSpace v, s ~ Scalar v) => v -> s -> v
(^*)

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

-- | 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 Double
x1 Double
y1 vCross :: Vect -> Vect -> Double
`vCross` Vect Double
x2 Double
y2 = Double
x1 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
y2 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
y1 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
x2

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

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

-- | Returns the vector projection of @v1@ onto @v2@.
--
-- Alias for 'project'.
vProject
  :: Vect -- ^ v1
  -> Vect -- ^ v2
  -> Vect
vProject :: Vect -> Vect -> Vect
vProject = Vect -> Vect -> Vect
forall v s.
(InnerSpace v, s ~ Scalar v, Fractional s) =>
v -> v -> v
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 Double
x1 Double
y1 vRotate :: Vect -> Vect -> Vect
`vRotate` Vect Double
x2 Double
y2 = Double -> Double -> Vect
Vect (Double
x1 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
x2 Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
y1 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
y2) (Double
x1 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
y2 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
x2 Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
y1)

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

-- | Returns the length of v.
--
-- Alias for 'magnitude'.
vLength :: Vect -> Double
vLength :: Vect -> Double
vLength = Vect -> Double
forall v s. (InnerSpace v, s ~ Scalar v, Floating s) => v -> s
magnitude

-- | Returns the squared length of @v@. Faster than 'vLength' when you only need to compare lengths.
--
-- Alias for 'magnitudeSq'.
vLengthSq :: Vect -> Double
vLengthSq :: Vect -> Double
vLengthSq = Vect -> Double
forall v s. (InnerSpace v, s ~ Scalar v) => v -> s
magnitudeSq

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

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

-- | Spherical linearly interpolate between v1 and v2.
vSLerp :: (Vect) -- ^ v1
 -> (Vect) -- ^ v2
 -> (Double) -> (Vect)
vSLerp :: Vect -> Vect -> Double -> Vect
vSLerp Vect
a1 Vect
a2 Double
a3 =
  IO Vect -> Vect
forall a. IO a -> a
C2HSImp.unsafePerformIO (IO Vect -> Vect) -> IO Vect -> Vect
forall a b. (a -> b) -> a -> b
$
  Vect -> (Ptr Vect -> IO Vect) -> IO Vect
forall a b. Storable a => a -> (Ptr a -> IO b) -> IO b
with Vect
a1 ((Ptr Vect -> IO Vect) -> IO Vect)
-> (Ptr Vect -> IO Vect) -> IO Vect
forall a b. (a -> b) -> a -> b
$ \Ptr Vect
a1' -> 
  Vect -> (Ptr Vect -> IO Vect) -> IO Vect
forall a b. Storable a => a -> (Ptr a -> IO b) -> IO b
with Vect
a2 ((Ptr Vect -> IO Vect) -> IO Vect)
-> (Ptr Vect -> IO Vect) -> IO Vect
forall a b. (a -> b) -> a -> b
$ \Ptr Vect
a2' -> 
  let {a3' :: CDouble
a3' = Double -> CDouble
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
a3} in 
  (Ptr Vect -> IO Vect) -> IO Vect
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Vect -> IO Vect) -> IO Vect)
-> (Ptr Vect -> IO Vect) -> IO Vect
forall a b. (a -> b) -> a -> b
$ \Ptr Vect
a4' -> 
  Ptr Vect -> Ptr Vect -> CDouble -> Ptr Vect -> IO ()
vSLerp'_ Ptr Vect
a1' Ptr Vect
a2' CDouble
a3' Ptr Vect
a4' IO () -> IO Vect -> IO Vect
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>
  Ptr Vect -> IO Vect
forall a. Storable a => Ptr a -> IO a
peek  Ptr Vect
a4'IO Vect -> (Vect -> IO Vect) -> IO Vect
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Vect
a4'' -> 
  Vect -> IO Vect
forall (m :: * -> *) a. Monad m => a -> m a
return (Vect
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 :: Vect -> Double -> Vect
vClamp Vect
v Double
l
  | Vect -> Double
forall v s. (InnerSpace v, s ~ Scalar v) => v -> s
magnitudeSq Vect
v Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
l Double -> Double -> Double
forall a. Num a => a -> a -> a
* Double
l = Double
Scalar Vect
l Scalar Vect -> Vect -> Vect
forall v. VectorSpace v => Scalar v -> v -> v
*^ Vect -> Vect
forall v s. (InnerSpace v, s ~ Scalar v, Floating s) => v -> v
normalized Vect
v
  | Bool
otherwise             = Vect
v

-- | Returns the distance between @v1@ and @v2@.
vDist
  :: Vect   -- ^ v1
  -> Vect   -- ^ v2
  -> Double
vDist :: Vect -> Vect -> Double
vDist Vect
v1 Vect
v2 = Vect -> Double
forall v s. (InnerSpace v, s ~ Scalar v, Floating s) => v -> s
magnitude (Vect -> Double) -> Vect -> Double
forall a b. (a -> b) -> a -> b
$ Vect
v1 Vect -> Vect -> Vect
forall v. AdditiveGroup v => v -> v -> v
^-^ Vect
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 :: Vect -> Vect -> Double
vDistSq Vect
v1 Vect
v2 = Vect -> Double
forall v s. (InnerSpace v, s ~ Scalar v) => v -> s
magnitudeSq (Vect -> Double) -> Vect -> Double
forall a b. (a -> b) -> a -> b
$ Vect
v1 Vect -> Vect -> Vect
forall v. AdditiveGroup v => v -> v -> v
^-^ Vect
v2

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

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

-- | Returns the angular direction @v@ is pointing in (in radians).
vToAngle
  :: Vect   -- ^ v
  -> Double
vToAngle :: Vect -> Double
vToAngle (Vect Double
x Double
y) = Double -> Double -> Double
forall a. RealFloat a => a -> a -> a
atan2 Double
y Double
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 ())))))