shapes-demo-0.1.0.0: src/Physics/Draw/Linear.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
module Physics.Draw.Linear where
import GHC.TypeLits (Nat)
import GHC.TypeNats (KnownNat)
import Control.Lens
import qualified Data.Vector as Vec
import Data.Vector ((!))
import Data.Maybe
import Linear.Affine
import Linear.Epsilon
import Linear.V
import Linear.V2
import Linear.V3
import Linear.V4
import Linear.Matrix
import Linear.Metric
type V6 a = V 6 a
type M66 a = V6 (V6 a)
type P2 a = Point V2 a
join22 :: V2 a -> V2 a -> V4 a
join22 (V2 ax ay) (V2 bx by) = V4 ax ay bx by
join33 :: V3 a -> V3 a -> V 6 a
join33 (V3 a b c) (V3 d e f) = listToV [a, b, c, d, e, f]
split33 :: V6 a -> (V3 a, V3 a)
split33 v = Vec.splitAt 3 (toVector v) & both %~ (\v' -> V3 (v' ! 0) (v' ! 1) (v' ! 2))
flip33 :: V6 a -> V6 a
flip33 v = listToV [d, e, f, a, b, c]
where (a, b, c, d, e, f) = extract6 v
extract6 :: V6 a -> (a, a, a, a, a, a)
extract6 v6 = (v ! 0, v ! 1, v ! 2, v ! 3, v ! 4, v ! 5)
where v = toVector v6
join44 :: V4 a -> V4 a -> V 8 a
join44 (V4 a b c d) (V4 e f g h) = listToV [a, b, c, d, e, f, g, h]
cross22 :: Num a => V2 a -> V2 a -> a
cross22 (V2 ax ay) (V2 bx by) = (ax * by) - (ay * bx)
append2 :: V2 a -> a -> V3 a
append2 (V2 a b) = V3 a b
split3 :: V3 a -> (V2 a, a)
split3 (V3 a b c) = (V2 a b, c)
listToV :: KnownNat n => [a] -> V (n :: Nat) a
listToV = fromJust . fromVector . Vec.fromList
rotate22_ :: (Num a) => a -> a -> M22 a
rotate22_ cosv sinv = V2 (V2 cosv (-sinv)) (V2 sinv cosv)
rotate22 :: (Floating a) => a -> M22 a
rotate22 ori = rotate22_ c s
where c = cos ori
s = sin ori
afmat33 :: (Num a) => M22 a -> M33 a
afmat33 (V2 x y) = V3 (append2 x 0) (append2 y 0) (V3 0 0 1)
aftranslate33 :: (Num a) => V2 a -> M33 a
aftranslate33 (V2 x y) = V3 (V3 1 0 x) (V3 0 1 y) (V3 0 0 1)
afrotate33 :: (Floating a) => a -> M33 a
afrotate33 = afmat33 . rotate22
afscale33 :: (Num a) => V2 a -> M33 a
afscale33 (V2 x y) = V3 (V3 x 0 0) (V3 0 y 0) (V3 0 0 1)
dfa :: (Num a) => Diff V2 a -> V3 a
dfa (V2 x y) = V3 x y 0
afd :: V3 a -> Diff V2 a
afd = view _xy
pfa :: (Num a) => P2 a -> V3 a
pfa (P (V2 x y)) = V3 x y 1
afp :: V3 a -> P2 a
afp = P . view _xy
afdot :: (Num a) => P2 a -> Diff V2 a -> a
afdot a b = view _Point a `dot` b
afdot' :: (Num a) => Diff V2 a -> P2 a -> a
afdot' = flip afdot
data Diag6 a = Diag6 (V6 a)
toDiag6 :: [a] -> Diag6 a
toDiag6 = Diag6 . listToV
mulDiag6 :: (Num a) => V6 a -> Diag6 a -> V6 a
mulDiag6 v (Diag6 d) = (*) <$> v <*> d
mulDiag6' :: (Num a) => Diag6 a -> V6 a -> V6 a
mulDiag6' = flip mulDiag6
class AffineTrans t a where
afmul :: M33 a -> t -> t
instance (Num a) => AffineTrans (Point V2 a) a where
afmul m = afp . (m !*) . pfa
instance (Num a) => AffineTrans (V2 a) a where
afmul m = afd . (m !*) . dfa
clockwise22 :: Num a => M22 a
clockwise22 = V2 (V2 0 1) (V2 (-1) 0)
clockwise2 :: Num a => V2 a -> V2 a
clockwise2 (V2 x y) = V2 y (-x)
anticlockwise22 :: Num a => M22 a
anticlockwise22 = V2 (V2 0 1) (V2 (-1) 0)
anticlockwise2 :: Num a => V2 a -> V2 a
anticlockwise2 (V2 x y) = V2 (-y) x
perpendicularTowards :: (Num a, Ord a) => V2 a -> V2 a -> V2 a
a `perpendicularTowards` b = rot b
where rot = if a `cross22` b > 0 then clockwise2
else anticlockwise2
similarDir :: (Metric t, Num a, Ord a) => t a -> t a -> Bool
similarDir a b = a `dot` b > 0
horizontalizer22 :: (Floating a) => V2 a -> M22 a
horizontalizer22 d@(V2 a o) = rotate22_ cosv (-sinv)
where sinv = o / h
cosv = a / h
h = norm d
data Line2 a = Line2 { linePoint :: !(P2 a)
, lineNormal :: !(V2 a) }
toLine2 :: (Num a) => P2 a -> P2 a -> Line2 a
toLine2 a b = Line2 { linePoint = a
, lineNormal = clockwise2 (b .-. a) }
perpLine2 :: (Num a) => P2 a -> P2 a -> Line2 a
perpLine2 a b = Line2 { linePoint = a
, lineNormal = b .-. a }
-- solving some `mx = b` up in here
intersect2 :: (Floating a, Epsilon a) => Line2 a -> Line2 a -> P2 a
intersect2 (Line2 p n) (Line2 p' n') =
P (inv22 m !* b)
where b = V2 (p `afdot` n) (p' `afdot` n')
m = V2 n n'
center2 :: (Fractional a) => P2 a -> P2 a -> P2 a
center2 a b = fmap (/2) (a + b)