{-|
== Simple utilities for 2D geometry

-}

module Geometry
    ( V2(..)
    , mag2
    , dist2
    , dot
    , cross
    , turn
    ) where

import Control.DeepSeq

data V2 = V2 !Int !Int deriving (V2 -> V2 -> Bool
(V2 -> V2 -> Bool) -> (V2 -> V2 -> Bool) -> Eq V2
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: V2 -> V2 -> Bool
$c/= :: V2 -> V2 -> Bool
== :: V2 -> V2 -> Bool
$c== :: V2 -> V2 -> Bool
Eq, Eq V2
Eq V2
-> (V2 -> V2 -> Ordering)
-> (V2 -> V2 -> Bool)
-> (V2 -> V2 -> Bool)
-> (V2 -> V2 -> Bool)
-> (V2 -> V2 -> Bool)
-> (V2 -> V2 -> V2)
-> (V2 -> V2 -> V2)
-> Ord V2
V2 -> V2 -> Bool
V2 -> V2 -> Ordering
V2 -> V2 -> V2
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: V2 -> V2 -> V2
$cmin :: V2 -> V2 -> V2
max :: V2 -> V2 -> V2
$cmax :: V2 -> V2 -> V2
>= :: V2 -> V2 -> Bool
$c>= :: V2 -> V2 -> Bool
> :: V2 -> V2 -> Bool
$c> :: V2 -> V2 -> Bool
<= :: V2 -> V2 -> Bool
$c<= :: V2 -> V2 -> Bool
< :: V2 -> V2 -> Bool
$c< :: V2 -> V2 -> Bool
compare :: V2 -> V2 -> Ordering
$ccompare :: V2 -> V2 -> Ordering
$cp1Ord :: Eq V2
Ord, Int -> V2 -> ShowS
[V2] -> ShowS
V2 -> String
(Int -> V2 -> ShowS)
-> (V2 -> String) -> ([V2] -> ShowS) -> Show V2
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [V2] -> ShowS
$cshowList :: [V2] -> ShowS
show :: V2 -> String
$cshow :: V2 -> String
showsPrec :: Int -> V2 -> ShowS
$cshowsPrec :: Int -> V2 -> ShowS
Show)

instance Num V2 where
    V2 Int
x1 Int
y1 + :: V2 -> V2 -> V2
+ V2 Int
x2 Int
y2 = Int -> Int -> V2
V2 (Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
x2) (Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
y2)
    V2 Int
x1 Int
y1 - :: V2 -> V2 -> V2
- V2 Int
x2 Int
y2 = Int -> Int -> V2
V2 (Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
x2) (Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
y2)
    * :: V2 -> V2 -> V2
(*)         = String -> V2 -> V2 -> V2
forall a. HasCallStack => String -> a
error String
"(*) @V2: unsupported"
    abs :: V2 -> V2
abs         = String -> V2 -> V2
forall a. HasCallStack => String -> a
error String
"abs @V2: unsupported"
    signum :: V2 -> V2
signum      = String -> V2 -> V2
forall a. HasCallStack => String -> a
error String
"signum @V2: unsupported"
    fromInteger :: Integer -> V2
fromInteger = String -> Integer -> V2
forall a. HasCallStack => String -> a
error String
"fromInteger @V2: unsupported"

-- | The square of the magnitude of the vector.
mag2 :: V2 -> Int
mag2 :: V2 -> Int
mag2 (V2 Int
x Int
y) = Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
y Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
y

-- | The square of the distance between two vectors.
dist2 :: V2 -> V2 -> Int
dist2 :: V2 -> V2 -> Int
dist2 V2
p1 V2
p2 = V2 -> Int
mag2 (V2
p1 V2 -> V2 -> V2
forall a. Num a => a -> a -> a
- V2
p2)

-- | Dot product of two vectors.
dot :: V2 -> V2 -> Int
dot :: V2 -> V2 -> Int
dot (V2 Int
x1 Int
y1) (V2 Int
x2 Int
y2) = Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
x2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
y1 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
y2

-- | Cross product of two vectors.
cross :: V2 -> V2 -> Int
cross :: V2 -> V2 -> Int
cross (V2 Int
x1 Int
y1) (V2 Int
x2 Int
y2) = Int
x1 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
y2 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
x2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
y1

-- | The turn going from p1 to p2 to p3. Returns an Ordering representing left, no turn, or right.
-- Mnemonic: LT stands for "left turn".
turn :: V2 -> V2 -> V2 -> Ordering
turn :: V2 -> V2 -> V2 -> Ordering
turn V2
p1 V2
p2 V2
p3 = Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
0 (V2 -> V2 -> Int
cross (V2
p2 V2 -> V2 -> V2
forall a. Num a => a -> a -> a
- V2
p1) (V2
p3 V2 -> V2 -> V2
forall a. Num a => a -> a -> a
- V2
p1))

{-# INLINABLE mag2 #-}
{-# INLINABLE dist2 #-}
{-# INLINABLE dot #-}
{-# INLINABLE cross #-}
{-# INLINABLE turn #-}

instance NFData V2 where
    rnf :: V2 -> ()
rnf = V2 -> ()
forall a. a -> ()
rwhnf