{-# LANGUAGE NamedFieldPuns #-}

-- | Geometric utility functions.
module Geometry
  ( Point(..)
  , Line(..)
  , Angle(..)
  , intersectLineLine
  , distanceFromOrigin
  , distanceLineFromOrigin
  , perpendicularThroughPoint
  , angleFromOrigin
  , normalizeAngle
  , lengthOfRayUntilIntersect
  ) where

import           Data.Fixed (mod')

data Point =
  Point Double
        Double

data Line = Line
  { slope     :: Double
  , intercept :: Double
  }

newtype Angle =
  Radians Double

intersectLineLine :: Line -> Line -> Point
intersectLineLine a b =
  let x = (intercept a - intercept b) / (slope b - slope a)
      y = slope a * x + intercept a
  in Point x y

distanceFromOrigin :: Point -> Double
distanceFromOrigin (Point x y) = sqrt (x * x + y * y)

distanceLineFromOrigin :: Line -> Double
distanceLineFromOrigin Line {slope, intercept} =
  abs intercept / sqrt (slope * slope + 1)

perpendicularThroughPoint :: Line -> Point -> Line
perpendicularThroughPoint Line {slope} (Point x y) =
  let slope' = -1 / slope
      intercept' = y - slope' * x
  in Line {slope = slope', intercept = intercept'}

angleFromOrigin :: Point -> Angle
angleFromOrigin (Point x y) = Radians $ atan2 y x

normalizeAngle :: Angle -> Angle
normalizeAngle (Radians theta) = Radians $ mod' theta (2 * pi)

lengthOfRayUntilIntersect :: Angle -> Line -> Double
lengthOfRayUntilIntersect (Radians theta) Line {slope, intercept} =
  intercept / (sin theta - slope * cos theta)