-- GENERATED by C->Haskell Compiler, version 0.28.1 Switcheroo, 1 April 2016 (Haskell)
-- Edit the ORIGNAL .chs file instead!


{-# LINE 1 "src/Chiphunk/Low/Helper.chs" #-}
-- | Description: Helpers functions mostly for estimating certain measures.
-- Module provides helper function mostly for estimating certain measures.
module Chiphunk.Low.Helper
  ( momentForCircle
  , momentForSegment
  , momentForPoly
  , momentForBox
  , areaForCircle
  , areaForSegment
  , areaForPoly
  , centroidForPoly
  , convexHull
  ) where
import qualified Foreign.C.Types as C2HSImp
import qualified Foreign.Ptr as C2HSImp
import qualified System.IO.Unsafe as C2HSImp



import Data.VectorSpace
import Foreign
import System.IO.Unsafe

import Chiphunk.Low.Internal

import Chiphunk.Low.Types
{-# LINE 21 "src/Chiphunk/Low/Helper.chs" #-}





-- | Calculate the moment of inertia for a hollow circle, @r1@ and @r2@ are the inner and outer diameters
-- in no particular order. (A solid circle has an inner diameter of 0)
momentForCircle
  :: Double -- ^ Mass
  -> Double -- ^ r1
  -> Double -- ^ r2
  -> Vect   -- ^ Offset
  -> Double
momentForCircle m r1 r2 offs = m * (0.5 * (r1 * r1 + r2 * r2) + magnitudeSq offs)

-- | Calculate the moment of inertia for a line segment. The endpoints @a@ and @b@ are relative to the body.
momentForSegment
  :: Double -- ^ Mass
  -> Vect   -- ^ a
  -> Vect   -- ^ b
  -> Double -- ^ Thickness
  -> Double
momentForSegment m a b r = m * ((len * len + 4 * r * r) / 12 + magnitudeSq offs)
  where
    offs = lerp a b 0.5
    len  = magnitude (b ^-^ a) + 2 * r

-- | Calculate the moment of inertia for a solid polygon shape assuming its center of gravity is at its centroid.
-- The offset is added to each vertex.
momentForPoly :: (Double) -- ^ Mass
 -> ([Vect]) -- ^ Vertexes
 -> (Vect) -- ^ Offset
 -> (Double) -- ^ Thickness
 -> (Double)
momentForPoly a1 a2 a3 a4 =
  C2HSImp.unsafePerformIO $
  let {a1' = realToFrac a1} in
  withList a2 $ \(a2'1, a2'2) ->
  with a3 $ \a3' ->
  let {a4' = realToFrac a4} in
  momentForPoly'_ a1' a2'1  a2'2 a3' a4' >>= \res ->
  let {res' = realToFrac res} in
  return (res')

{-# LINE 55 "src/Chiphunk/Low/Helper.chs" #-}


-- | Calculate the moment of inertia for a solid box centered on the body.
momentForBox
  :: Double -- ^ Mass
  -> Double -- ^ Width
  -> Double -- ^ Height
  -> Double
momentForBox m w h = m * (w * w + h * h) / 12

-- | Area of a hollow circle.
areaForCircle
  :: Double -- ^ r1
  -> Double -- ^ r2
  -> Double
areaForCircle r1 r2 = pi * abs (r1 * r1 - r2 * r2)

-- | Area of a beveled segment. (Will always be zero if radius is zero)
areaForSegment
  :: Vect   -- ^ One end
  -> Vect   -- ^ Other end
  -> Double -- ^ Thickness
  -> Double
areaForSegment v1 v2 r = magnitude (v1 ^-^ v2) * 2 * r + pi * r * r

-- | Signed area of a polygon shape. Returns a negative number for polygons with a clockwise winding.
areaForPoly :: ([Vect]) -- ^ Vertexes
 -> (Double) -- ^ Thickness
 -> (Double)
areaForPoly a1 a2 =
  C2HSImp.unsafePerformIO $
  withList a1 $ \(a1'1, a1'2) ->
  let {a2' = realToFrac a2} in
  areaForPoly'_ a1'1  a1'2 a2' >>= \res ->
  let {res' = realToFrac res} in
  return (res')

{-# LINE 84 "src/Chiphunk/Low/Helper.chs" #-}


-- | Calculate the centroid for a polygon.
centroidForPoly :: ([Vect]) -> (Vect)
centroidForPoly a1 =
  C2HSImp.unsafePerformIO $
  withList a1 $ \(a1'1, a1'2) ->
  alloca $ \a2' ->
  centroidForPoly'_ a1'1  a1'2 a2' >>
  peek  a2'>>= \a2'' ->
  return (a2'')

{-# LINE 87 "src/Chiphunk/Low/Helper.chs" #-}


-- | Calculate the convex hull of a given set of points.
convexHull
  :: [Vect]        -- ^ Set of vertexes
  -> Double        -- ^ Allowed amount to shrink the hull when simplifying it. A tolerance of 0 creates an exact hull.
  -> ([Vect], Int) -- ^ Second element is index of first output vertex in input list.
convexHull vs tol = unsafePerformIO $
  withArray vs $ \pVs ->
  allocaArray (length vs) $ \pRes ->
  alloca $ \pFst -> do
    n <- c_convexHull (fromIntegral $ length vs) pVs pRes pFst (realToFrac tol)
    (,) <$> peekArray (fromIntegral n) pRes <*> (fromIntegral <$> peek pFst)

foreign import ccall unsafe "Chiphunk/Low/Helper.chs.h __c2hs_wrapped__cpMomentForPoly"
  momentForPoly'_ :: (C2HSImp.CDouble -> (C2HSImp.CInt -> ((VectPtr) -> ((VectPtr) -> (C2HSImp.CDouble -> (IO C2HSImp.CDouble))))))

foreign import ccall unsafe "Chiphunk/Low/Helper.chs.h cpAreaForPoly"
  areaForPoly'_ :: (C2HSImp.CInt -> ((VectPtr) -> (C2HSImp.CDouble -> (IO C2HSImp.CDouble))))

foreign import ccall unsafe "Chiphunk/Low/Helper.chs.h w_cpCentroidForPoly"
  centroidForPoly'_ :: (C2HSImp.CInt -> ((VectPtr) -> ((VectPtr) -> (IO ()))))

foreign import ccall safe "Chiphunk/Low/Helper.chs.h cpConvexHull"
  c_convexHull :: (C2HSImp.CInt -> ((VectPtr) -> ((VectPtr) -> ((C2HSImp.Ptr C2HSImp.CInt) -> (C2HSImp.CDouble -> (IO C2HSImp.CInt))))))