module Point
( Point
, pattern Point
, xVal
, yVal
, fromFloat
, pointMap
, pointAsTuple
, (|+|)
, (|*|)
, (|/|)
, cross
, dot
, angleBetween
, mag
, magSquared
, mirrorP
, rotateP
, cartesianProduct
) where
import ApproxEq
data Point = Point !Float !Float deriving (Eq, Show)
instance Num Point where
Point x1 y1 + Point x2 y2 = Point (x1 + x2) (y1 + y2)
Point x1 y1 * Point x2 y2 = Point (x1 * x2) (y1 * y2)
Point x1 y1 - Point x2 y2 = Point (x1 - x2) (y1 - y2)
abs (Point x y) = Point (abs x) (abs y)
signum (Point x y) = Point (signum x) (signum y)
negate (Point x y) = Point (x * (-1)) (y * (-1))
fromInteger i = Point (fromInteger i) (fromInteger i)
instance Fractional Point where
Point x1 y1 / Point x2 y2 = Point (x1 / x2) (y1 / y2)
recip (Point x y) = Point y x
fromRational r = Point (fromRational r) (fromRational r)
instance Floating Point where
pi = Point pi pi
exp (Point x y) = Point (exp x) (exp y)
log (Point x y) = Point (log x) (log y)
sin (Point x y) = Point (sin x) (sin y)
cos (Point x y) = Point (cos x) (cos y)
asin (Point x y) = Point (asin x) (asin y)
acos (Point x y) = Point (acos x) (acos y)
atan (Point x y) = Point (atan x) (atan y)
sinh (Point x y) = Point (sinh x) (sinh y)
cosh (Point x y) = Point (cosh x) (cosh y)
asinh (Point x y) = Point (asinh x) (asinh y)
acosh (Point x y) = Point (acosh x) (acosh y)
atanh (Point x y) = Point (atanh x) (atanh y)
instance ApproxEq Point where
approxEqual a b epsilon = let Point dx dy = abs (a - b) in
dx < epsilon && dy < epsilon
instance Ord Point where
compare a b = pointAsTuple a `compare` pointAsTuple b
(<=) a b = pointAsTuple a <= pointAsTuple b
xVal :: Point -> Float
xVal (Point coord _) = coord
yVal :: Point -> Float
yVal (Point _ coord) = coord
fromFloat :: Float -> Point
fromFloat f = Point f f
pointMap :: (Float -> Float) -> Point -> Point
pointMap f (Point x y) = Point (f x) (f y)
pointAsTuple :: Point -> (Float, Float)
pointAsTuple (Point x y) = (x, y)
(|+|) :: Point -> Float -> Point
(|+|) p v = p + fromFloat v
(|*|) :: Point -> Float -> Point
(|*|) p v = p * fromFloat v
(|/|) :: Point -> Float -> Point
(|/|) p v = p / fromFloat v
cross :: Point -> Point -> Float
cross (Point x1 y1) (Point x2 y2) = x1 * y2 - y1 * x2
dot :: Point -> Point -> Float
dot (Point x1 y1) (Point x2 y2) = x1 * x2 + y1 * y2
angleBetween :: Point -> Point -> Float
angleBetween p1 p2 = atan2 (cross p1 p2) (dot p1 p2)
mag :: Point -> Float
mag p = sqrt (dot p p)
magSquared :: Point -> Float
magSquared p = dot p p
mirrorP :: Point -> Point -> Point -> Point
mirrorP a p v = (-a) + 2 * p + 2 * w |*| dot (a - p) w
where w = v |/| mag v
rotateP :: Point -> Point -> Float -> Point
rotateP a p t = p + Point (ax * cos t - ay * sin t) (ax * sin t + ay * cos t)
where
Point ax ay = a - p
cartesianProduct :: [Float] -> [Float] -> [Point]
cartesianProduct xs ys = Point <$> xs <*> ys