module Apecs.Physics.Geometry where

import Apecs.Physics.Types
import Linear

vertices :: Convex -> [BVec]
vertices (Convex s _) = s

-- | Map a function over all vertices
mapVertices :: (BVec -> BVec) -> Convex -> Convex
mapVertices f (Convex s r) = Convex (f <$> s) r

-- | Translates all vertices. The name shift is to prevent collisions with gloss
shift :: BVec -> Convex -> Convex
shift = mapVertices . (+)

getRadius :: Convex -> Double
getRadius (Convex _ r) = r

setRadius :: Double -> Convex -> Convex
setRadius r (Convex s _) = Convex s r

cCircle, zCircle :: Double -> Convex
cCircle r = oCircle 0 r
zCircle = cCircle

oCircle :: BVec -> Double -> Convex
oCircle o r = Convex [o] r

hLine, vLine :: Double -> Convex
hLine l = Convex [V2 (-l/2) 0, V2 (l/2) 0] 0
vLine l = Convex [V2 0 (l/2), V2 0 (-l/2)] 0

-- | Centered rectangle with a given size
cRectangle :: BVec -> Convex
cRectangle s = oRectangle (-s*0.5) s

-- | Rectangle with a given origin and size
oRectangle :: BVec -> BVec -> Convex
oRectangle (V2 x y) (V2 w h) = Convex [V2 x y, V2 x (y+h), V2 (x+w) (y+h), V2 (x+w) y] 0

-- | Rectangle with origin 0 and given size
zRectangle :: BVec -> Convex
zRectangle s = oRectangle 0 s

-- | Split a shape into its edges. Will return no edges for points, but returns 2 for a line (in opposite directions)
toEdges :: Convex -> [Convex]
toEdges (Convex [] _) = []
toEdges (Convex [_] _) = []
toEdges (Convex vs r) = zipWith (\h t -> Convex [h,t] r) vs (tail . cycle $ vs)

-- | A set of lines forming a grid. Returns (r + c + 2) segments.
gridLines :: Vec -> Int -> Int -> [Convex]
gridLines size c r =
  [ shift (V2 x 0) (vLine h) | x <- xs ] ++
  [ shift (V2 0 y) (hLine w) | y <- ys ]
  where
    V2 w h = size
    V2 x y = -size*0.5
    dx = w/fromIntegral c
    dy = h/fromIntegral r
    xs = [x + fromIntegral n * dx | n <- [0..c]]
    ys = [y + fromIntegral n * dy | n <- [0..r]]