{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
{-|
Module      : Reanimate.Math.Common
Copyright   : Written by David Himmelstrup
License     : Unlicense
Maintainer  : lemmih@gmail.com
Stability   : experimental
Portability : POSIX

Low-level primitives related to computational geometry.

-}
module Reanimate.Math.Common
  ( -- * Ring
    Ring(..)
  , ringSize            -- :: Ring a -> Int
  , ringAccess          -- :: Ring a -> Int -> V2 a
  , ringClamp           -- :: Ring a -> Int -> Int
  , ringUnpack          -- :: Ring a -> Vector (V2 a)
  , ringPack            -- :: Vector (V2 a) -> Ring a
  , ringMap             -- :: (V2 a -> V2 b) -> Ring a -> Ring b
  , ringRayIntersect    -- :: Ring Rational -> (Int, Int) -> (Int,Int) -> Maybe (V2 Rational)
    -- * Math
  , area                -- :: Fractional a => V2 a -> V2 a -> V2 a -> a
  , area2X              -- :: Fractional a => V2 a -> V2 a -> V2 a -> a
  , isLeftTurn          -- :: (Num a, Ord a) => V2 a -> V2 a -> V2 a -> Bool
  , isLeftTurnOrLinear  -- :: (Num a, Ord a) => V2 a -> V2 a -> V2 a -> Bool
  , isRightTurn         -- :: (Num a, Ord a) => V2 a -> V2 a -> V2 a -> Bool
  , isRightTurnOrLinear -- :: (Num a, Ord a) => V2 a -> V2 a -> V2 a -> Bool
  , direction           -- :: Num a => V2 a -> V2 a -> V2 a -> a
  , isInside            -- :: (Fractional a, Ord a) => V2 a -> V2 a -> V2 a -> V2 a -> Bool
  , isInsideStrict      -- :: (Fractional a, Ord a) => V2 a -> V2 a -> V2 a -> V2 a -> Bool
  , barycentricCoords   -- :: Fractional a => V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
  , rayIntersect        -- :: (Fractional a, Ord a) => (V2 a,V2 a) -> (V2 a,V2 a) -> Maybe (V2 a)
  , isBetween           -- :: (Ord a, Fractional a) => V2 a -> (V2 a, V2 a) -> Bool
  , lineIntersect       -- :: (Ord a, Fractional a) => (V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
  , distSquared         -- :: (Fractional a) => V2 a -> V2 a -> a
  , approxDist          -- :: (Real a, Fractional a) => V2 a -> V2 a -> a
  , distance'           -- :: (Real a, Fractional a) => V2 a -> V2 a -> Double
  , triangleAngles      -- :: V2 Double -> V2 Double -> V2 Double -> (Double, Double, Double)
  , Epsilon(..)
  ) where

import           Data.Vector    (Vector)
import qualified Data.Vector    as V
import           Linear.Matrix  (det33)
import           Linear.Metric
import           Linear.V2
import           Linear.V3
import           Linear.Vector
import           Linear.Epsilon

instance Epsilon Rational where
  nearZero :: Rational -> Bool
nearZero Rational
r = Rational
rRational -> Rational -> Bool
forall a. Eq a => a -> a -> Bool
==Rational
0

-- | Circular collection of pairs.
newtype Ring a = Ring (Vector (V2 a))

-- | Number of elements in the ring.
ringSize :: Ring a -> Int
ringSize :: Ring a -> Int
ringSize (Ring Vector (V2 a)
v) = Vector (V2 a) -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Vector (V2 a)
v

-- | Safe method for accessing elements in the ring.
ringAccess :: Ring a -> Int -> V2 a
ringAccess :: Ring a -> Int -> V2 a
ringAccess (Ring Vector (V2 a)
v) Int
i = Vector (V2 a)
v Vector (V2 a) -> Int -> V2 a
forall a. Vector a -> Int -> a
V.! Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod Int
i (Vector (V2 a) -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Vector (V2 a)
v)

-- | Clamp index to within the usable range for the ring.
ringClamp :: Ring a -> Int -> Int
ringClamp :: Ring a -> Int -> Int
ringClamp (Ring Vector (V2 a)
v) Int
i = Int -> Int -> Int
forall a. Integral a => a -> a -> a
mod Int
i (Vector (V2 a) -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Vector (V2 a)
v)

-- | Convert ring to a vector.
ringUnpack :: Ring a -> Vector (V2 a)
ringUnpack :: Ring a -> Vector (V2 a)
ringUnpack (Ring Vector (V2 a)
v) = Vector (V2 a)
v

-- | Convert vector to a ring.
ringPack :: Vector (V2 a) -> Ring a
ringPack :: Vector (V2 a) -> Ring a
ringPack = Vector (V2 a) -> Ring a
forall a. Vector (V2 a) -> Ring a
Ring

-- | Map each element of a ring.
ringMap :: (V2 a -> V2 b) -> Ring a -> Ring b
ringMap :: (V2 a -> V2 b) -> Ring a -> Ring b
ringMap V2 a -> V2 b
fn (Ring Vector (V2 a)
v) = Vector (V2 b) -> Ring b
forall a. Vector (V2 a) -> Ring a
Ring ((V2 a -> V2 b) -> Vector (V2 a) -> Vector (V2 b)
forall a b. (a -> b) -> Vector a -> Vector b
V.map V2 a -> V2 b
fn Vector (V2 a)
v)

-- | Compute the intersection of two pairs of nodes in the ring.
ringRayIntersect :: Ring Rational -> (Int, Int) -> (Int,Int) -> Maybe (V2 Rational)
ringRayIntersect :: Ring Rational -> (Int, Int) -> (Int, Int) -> Maybe (V2 Rational)
ringRayIntersect Ring Rational
p (Int
a,Int
b) (Int
c,Int
d) =
  (V2 Rational, V2 Rational)
-> (V2 Rational, V2 Rational) -> Maybe (V2 Rational)
forall a.
(Fractional a, Ord a) =>
(V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
rayIntersect (Ring Rational -> Int -> V2 Rational
forall a. Ring a -> Int -> V2 a
ringAccess Ring Rational
p Int
a, Ring Rational -> Int -> V2 Rational
forall a. Ring a -> Int -> V2 a
ringAccess Ring Rational
p Int
b) (Ring Rational -> Int -> V2 Rational
forall a. Ring a -> Int -> V2 a
ringAccess Ring Rational
p Int
c, Ring Rational -> Int -> V2 Rational
forall a. Ring a -> Int -> V2 a
ringAccess Ring Rational
p Int
d)

-- | Compute area of triangle.
area :: Fractional a => V2 a -> V2 a -> V2 a -> a
area :: V2 a -> V2 a -> V2 a -> a
area V2 a
a V2 a
b V2 a
c = a
1a -> a -> a
forall a. Fractional a => a -> a -> a
/a
2 a -> a -> a
forall a. Num a => a -> a -> a
* V2 a -> V2 a -> V2 a -> a
forall a. Fractional a => V2 a -> V2 a -> V2 a -> a
area2X V2 a
a V2 a
b V2 a
c

-- | Compute 2x area of triangle. This avoids a division.
area2X :: Fractional a => V2 a -> V2 a -> V2 a -> a
area2X :: V2 a -> V2 a -> V2 a -> a
area2X (V2 a
a1 a
a2) (V2 a
b1 a
b2) (V2 a
c1 a
c2) =
  M33 a -> a
forall a. Num a => M33 a -> a
det33 (V3 a -> V3 a -> V3 a -> M33 a
forall a. a -> a -> a -> V3 a
V3 (a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
a1 a
a2 a
1)
            (a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
b1 a
b2 a
1)
            (a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
c1 a
c2 a
1))

compareEpsZero :: (Ord a, Fractional a, Epsilon a) => a -> Ordering
compareEpsZero :: a -> Ordering
compareEpsZero a
val
  | a -> Bool
forall a. Epsilon a => a -> Bool
nearZero a
val  = Ordering
EQ
  | Bool
otherwise     = a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare a
val a
0

{-# INLINE isLeftTurn #-}
-- | Return @True@ iff the line from @p1@ to @p2@ makes a left-turn to @p3@.
isLeftTurn :: (Fractional a, Ord a, Epsilon a) => V2 a -> V2 a -> V2 a -> Bool
isLeftTurn :: V2 a -> V2 a -> V2 a -> Bool
isLeftTurn V2 a
p1 V2 a
p2 V2 a
p3 =
  case a -> Ordering
forall a. (Ord a, Fractional a, Epsilon a) => a -> Ordering
compareEpsZero (V2 a -> V2 a -> V2 a -> a
forall a. Num a => V2 a -> V2 a -> V2 a -> a
direction V2 a
p1 V2 a
p2 V2 a
p3) of
    Ordering
LT -> Bool
True
    Ordering
EQ -> Bool
False -- colinear
    Ordering
GT -> Bool
False

{-# INLINE isLeftTurnOrLinear #-}
-- | Return @True@ iff the line from @p1@ to @p2@ does not make a right-turn to @p3@.
isLeftTurnOrLinear :: (Fractional a, Ord a, Epsilon a) => V2 a -> V2 a -> V2 a -> Bool
isLeftTurnOrLinear :: V2 a -> V2 a -> V2 a -> Bool
isLeftTurnOrLinear V2 a
p1 V2 a
p2 V2 a
p3 =
  case a -> Ordering
forall a. (Ord a, Fractional a, Epsilon a) => a -> Ordering
compareEpsZero (V2 a -> V2 a -> V2 a -> a
forall a. Num a => V2 a -> V2 a -> V2 a -> a
direction V2 a
p1 V2 a
p2 V2 a
p3) of
    Ordering
LT -> Bool
True
    Ordering
EQ -> Bool
True -- colinear
    Ordering
GT -> Bool
False

{-# INLINE isRightTurn #-}
-- | Return @True@ iff the line from @p1@ to @p2@ makes a right-turn to @p3@.
isRightTurn :: (Fractional a, Ord a, Epsilon a) => V2 a -> V2 a -> V2 a -> Bool
isRightTurn :: V2 a -> V2 a -> V2 a -> Bool
isRightTurn V2 a
a V2 a
b V2 a
c = Bool -> Bool
not (V2 a -> V2 a -> V2 a -> Bool
forall a.
(Fractional a, Ord a, Epsilon a) =>
V2 a -> V2 a -> V2 a -> Bool
isLeftTurnOrLinear V2 a
a V2 a
b V2 a
c)

{-# INLINE isRightTurnOrLinear #-}
-- | Return @True@ iff the line from @p1@ to @p2@ does not make a left-turn to @p3@.
isRightTurnOrLinear :: (Fractional a, Ord a, Epsilon a) => V2 a -> V2 a -> V2 a -> Bool
isRightTurnOrLinear :: V2 a -> V2 a -> V2 a -> Bool
isRightTurnOrLinear V2 a
a V2 a
b V2 a
c = Bool -> Bool
not (V2 a -> V2 a -> V2 a -> Bool
forall a.
(Fractional a, Ord a, Epsilon a) =>
V2 a -> V2 a -> V2 a -> Bool
isLeftTurn V2 a
a V2 a
b V2 a
c)

{-# INLINE direction #-}
-- | Compute the change in direction in a line between the three points.
direction :: Num a => V2 a -> V2 a -> V2 a -> a
direction :: V2 a -> V2 a -> V2 a -> a
direction V2 a
p1 V2 a
p2 V2 a
p3 = V2 a -> V2 a -> a
forall a. Num a => V2 a -> V2 a -> a
crossZ (V2 a
p3V2 a -> V2 a -> V2 a
forall a. Num a => a -> a -> a
-V2 a
p1) (V2 a
p2V2 a -> V2 a -> V2 a
forall a. Num a => a -> a -> a
-V2 a
p1)

{-# INLINE isInside #-}
-- | Returns @True@ if the fourth argument is inside the triangle or
--   on the border.
isInside :: (Fractional a, Ord a) => V2 a -> V2 a -> V2 a -> V2 a -> Bool
isInside :: V2 a -> V2 a -> V2 a -> V2 a -> Bool
isInside V2 a
a V2 a
b V2 a
c V2 a
d =
    a
s a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 Bool -> Bool -> Bool
&& a
s a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1 Bool -> Bool -> Bool
&& a
t a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 Bool -> Bool -> Bool
&& a
t a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1 Bool -> Bool -> Bool
&& a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
0 Bool -> Bool -> Bool
&& a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
1
  where
    (a
s, a
t, a
i) = V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
forall a. Fractional a => V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
barycentricCoords V2 a
a V2 a
b V2 a
c V2 a
d

{-# INLINE isInsideStrict #-}
-- | Returns @True@ iff the fourth argument is inside the triangle.
isInsideStrict :: (Fractional a, Ord a) => V2 a -> V2 a -> V2 a -> V2 a -> Bool
isInsideStrict :: V2 a -> V2 a -> V2 a -> V2 a -> Bool
isInsideStrict V2 a
a V2 a
b V2 a
c V2 a
d =
    a
s a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0 Bool -> Bool -> Bool
&& a
s a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1 Bool -> Bool -> Bool
&& a
t a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0 Bool -> Bool -> Bool
&& a
t a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1 Bool -> Bool -> Bool
&& a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
0 Bool -> Bool -> Bool
&& a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
1
  where
    (a
s, a
t, a
i) = V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
forall a. Fractional a => V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
barycentricCoords V2 a
a V2 a
b V2 a
c V2 a
d

{-# INLINE barycentricCoords #-}
-- | Compute relative coordinates inside the triangle. Invariant: @a+b+c=1@
barycentricCoords :: Fractional a => V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
barycentricCoords :: V2 a -> V2 a -> V2 a -> V2 a -> (a, a, a)
barycentricCoords (V2 a
x1 a
y1) (V2 a
x2 a
y2) (V2 a
x3 a
y3) (V2 a
x a
y) =
    (a
lam1, a
lam2, a
lam3)
  where
    lam1 :: a
lam1 = ((a
y2a -> a -> a
forall a. Num a => a -> a -> a
-a
y3)a -> a -> a
forall a. Num a => a -> a -> a
*(a
xa -> a -> a
forall a. Num a => a -> a -> a
-a
x3) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
x3 a -> a -> a
forall a. Num a => a -> a -> a
- a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
ya -> a -> a
forall a. Num a => a -> a -> a
-a
y3)) a -> a -> a
forall a. Fractional a => a -> a -> a
/
           ((a
y2a -> a -> a
forall a. Num a => a -> a -> a
-a
y3)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x1a -> a -> a
forall a. Num a => a -> a -> a
-a
x3) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
x3a -> a -> a
forall a. Num a => a -> a -> a
-a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
y1a -> a -> a
forall a. Num a => a -> a -> a
-a
y3))
    lam2 :: a
lam2 = ((a
y3a -> a -> a
forall a. Num a => a -> a -> a
-a
y1)a -> a -> a
forall a. Num a => a -> a -> a
*(a
xa -> a -> a
forall a. Num a => a -> a -> a
-a
x3) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
x1a -> a -> a
forall a. Num a => a -> a -> a
-a
x3)a -> a -> a
forall a. Num a => a -> a -> a
*(a
ya -> a -> a
forall a. Num a => a -> a -> a
-a
y3)) a -> a -> a
forall a. Fractional a => a -> a -> a
/
           ((a
y2a -> a -> a
forall a. Num a => a -> a -> a
-a
y3)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x1a -> a -> a
forall a. Num a => a -> a -> a
-a
x3) a -> a -> a
forall a. Num a => a -> a -> a
+ (a
x3a -> a -> a
forall a. Num a => a -> a -> a
-a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
y1a -> a -> a
forall a. Num a => a -> a -> a
-a
y3))
    lam3 :: a
lam3 = a
1 a -> a -> a
forall a. Num a => a -> a -> a
- a
lam1 a -> a -> a
forall a. Num a => a -> a -> a
- a
lam2


{-# INLINE rayIntersect #-}
-- | Compute intersection of two infinite lines.
rayIntersect :: (Fractional a, Ord a) => (V2 a,V2 a) -> (V2 a,V2 a) -> Maybe (V2 a)
rayIntersect :: (V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
rayIntersect (V2 a
x1 a
y1,V2 a
x2 a
y2) (V2 a
x3 a
y3, V2 a
x4 a
y4)
  | a
yBot a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = Maybe (V2 a)
forall a. Maybe a
Nothing
  | Bool
otherwise = V2 a -> Maybe (V2 a)
forall a. a -> Maybe a
Just (V2 a -> Maybe (V2 a)) -> V2 a -> Maybe (V2 a)
forall a b. (a -> b) -> a -> b
$
    a -> a -> V2 a
forall a. a -> a -> V2 a
V2 (a
xTopa -> a -> a
forall a. Fractional a => a -> a -> a
/a
xBot) (a
yTopa -> a -> a
forall a. Fractional a => a -> a -> a
/a
yBot)
  where
    xTop :: a
xTop = (a
x1a -> a -> a
forall a. Num a => a -> a -> a
*a
y2 a -> a -> a
forall a. Num a => a -> a -> a
- a
y1a -> a -> a
forall a. Num a => a -> a -> a
*a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x3a -> a -> a
forall a. Num a => a -> a -> a
-a
x4) a -> a -> a
forall a. Num a => a -> a -> a
- (a
x1 a -> a -> a
forall a. Num a => a -> a -> a
- a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x3a -> a -> a
forall a. Num a => a -> a -> a
*a
y4a -> a -> a
forall a. Num a => a -> a -> a
-a
y3a -> a -> a
forall a. Num a => a -> a -> a
*a
x4)
    xBot :: a
xBot = (a
x1a -> a -> a
forall a. Num a => a -> a -> a
-a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
y3a -> a -> a
forall a. Num a => a -> a -> a
-a
y4)a -> a -> a
forall a. Num a => a -> a -> a
-(a
y1a -> a -> a
forall a. Num a => a -> a -> a
-a
y2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x3a -> a -> a
forall a. Num a => a -> a -> a
-a
x4)
    yTop :: a
yTop = (a
x1a -> a -> a
forall a. Num a => a -> a -> a
*a
y2 a -> a -> a
forall a. Num a => a -> a -> a
- a
y1a -> a -> a
forall a. Num a => a -> a -> a
*a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
y3a -> a -> a
forall a. Num a => a -> a -> a
-a
y4) a -> a -> a
forall a. Num a => a -> a -> a
- (a
y1a -> a -> a
forall a. Num a => a -> a -> a
-a
y2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x3a -> a -> a
forall a. Num a => a -> a -> a
*a
y4a -> a -> a
forall a. Num a => a -> a -> a
-a
y3a -> a -> a
forall a. Num a => a -> a -> a
*a
x4)
    yBot :: a
yBot = (a
x1a -> a -> a
forall a. Num a => a -> a -> a
-a
x2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
y3a -> a -> a
forall a. Num a => a -> a -> a
-a
y4) a -> a -> a
forall a. Num a => a -> a -> a
- (a
y1a -> a -> a
forall a. Num a => a -> a -> a
-a
y2)a -> a -> a
forall a. Num a => a -> a -> a
*(a
x3a -> a -> a
forall a. Num a => a -> a -> a
-a
x4)

{-# INLINE isBetween #-}
-- | Returns @True@ iff a point is on a line segment.
isBetween :: (Ord a, Fractional a) => V2 a -> (V2 a, V2 a) -> Bool
isBetween :: V2 a -> (V2 a, V2 a) -> Bool
isBetween (V2 a
x a
y) (V2 a
x1 a
y1, V2 a
x2 a
y2) =
  ((a
y1 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
y) Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= (a
y2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
y) Bool -> Bool -> Bool
|| a
y a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y1 Bool -> Bool -> Bool
|| a
y a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y2) Bool -> Bool -> Bool
&& -- y is between y1 and y2
  ((a
x1 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
x) Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= (a
x2 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
x) Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x1 Bool -> Bool -> Bool
|| a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x2)

{-# INLINE lineIntersect #-}
-- | Compute intersection of two line segments.
lineIntersect :: (Ord a, Fractional a) => (V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
lineIntersect :: (V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
lineIntersect (V2 a, V2 a)
a (V2 a, V2 a)
b =
  case (V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
forall a.
(Fractional a, Ord a) =>
(V2 a, V2 a) -> (V2 a, V2 a) -> Maybe (V2 a)
rayIntersect (V2 a, V2 a)
a (V2 a, V2 a)
b of
    Just V2 a
u
      | V2 a -> (V2 a, V2 a) -> Bool
forall a. (Ord a, Fractional a) => V2 a -> (V2 a, V2 a) -> Bool
isBetween V2 a
u (V2 a, V2 a)
a Bool -> Bool -> Bool
&& V2 a -> (V2 a, V2 a) -> Bool
forall a. (Ord a, Fractional a) => V2 a -> (V2 a, V2 a) -> Bool
isBetween V2 a
u (V2 a, V2 a)
b -> V2 a -> Maybe (V2 a)
forall a. a -> Maybe a
Just V2 a
u
    Maybe (V2 a)
_ -> Maybe (V2 a)
forall a. Maybe a
Nothing

-- circleIntersect :: (Ord a, Fractional a) => (V2 a, V2 a) -> (V2 a, V2 a) -> [V2 a]

-- | Compute the square of the distance between two points.
distSquared :: (Num a) => V2 a -> V2 a -> a
distSquared :: V2 a -> V2 a -> a
distSquared V2 a
a V2 a
b = V2 a -> a
forall (f :: * -> *) a. (Metric f, Num a) => f a -> a
quadrance (V2 a
a V2 a -> V2 a -> V2 a
forall (f :: * -> *) a. (Additive f, Num a) => f a -> f a -> f a
^-^ V2 a
b)

-- | Approximate the distance between two points.
approxDist :: (Real a, Fractional a) => V2 a -> V2 a -> a
approxDist :: V2 a -> V2 a -> a
approxDist V2 a
a V2 a
b = Double -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Double -> Double
forall a. Floating a => a -> a
sqrt (a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac (V2 a -> V2 a -> a
forall a. Num a => V2 a -> V2 a -> a
distSquared V2 a
a V2 a
b) :: Double))

-- | Approximate the distance between two points.
distance' :: (Real a, Fractional a) => V2 a -> V2 a -> Double
distance' :: V2 a -> V2 a -> Double
distance' V2 a
a V2 a
b = Double -> Double
forall a. Floating a => a -> a
sqrt (a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac (V2 a -> V2 a -> a
forall a. Num a => V2 a -> V2 a -> a
distSquared V2 a
a V2 a
b))

-- sum of angles is always pi.
-- | Approximate the angles of a triangle.
triangleAngles :: V2 Double -> V2 Double -> V2 Double -> (Double, Double, Double)
triangleAngles :: V2 Double -> V2 Double -> V2 Double -> (Double, Double, Double)
triangleAngles V2 Double
a V2 Double
b V2 Double
c =
    (V2 Double -> V2 Double -> Double
forall a. RealFloat a => V2 a -> V2 a -> a
findAngle (V2 Double
bV2 Double -> V2 Double -> V2 Double
forall a. Num a => a -> a -> a
-V2 Double
a) (V2 Double
cV2 Double -> V2 Double -> V2 Double
forall a. Num a => a -> a -> a
-V2 Double
a)
    ,V2 Double -> V2 Double -> Double
forall a. RealFloat a => V2 a -> V2 a -> a
findAngle (V2 Double
cV2 Double -> V2 Double -> V2 Double
forall a. Num a => a -> a -> a
-V2 Double
b) (V2 Double
aV2 Double -> V2 Double -> V2 Double
forall a. Num a => a -> a -> a
-V2 Double
b)
    ,V2 Double -> V2 Double -> Double
forall a. RealFloat a => V2 a -> V2 a -> a
findAngle (V2 Double
aV2 Double -> V2 Double -> V2 Double
forall a. Num a => a -> a -> a
-V2 Double
c) (V2 Double
bV2 Double -> V2 Double -> V2 Double
forall a. Num a => a -> a -> a
-V2 Double
c))
  where
    findAngle :: V2 a -> V2 a -> a
findAngle V2 a
v1 V2 a
v2 = a -> a
forall a. Num a => a -> a
abs (a -> a -> a
forall a. RealFloat a => a -> a -> a
atan2 (V2 a -> V2 a -> a
forall a. Num a => V2 a -> V2 a -> a
crossZ V2 a
v1 V2 a
v2) (V2 a -> V2 a -> a
forall (f :: * -> *) a. (Metric f, Num a) => f a -> f a -> a
dot V2 a
v1 V2 a
v2))
    -- findAngle v1 v2 = acos (dot v1 v2 / (norm v1 * norm v2))