module Line ( Line (..)
, throughPoint
, fromPoints
, createPerpendicularAt
, slope
, intersection
, isOnLine
) where
import Linear
import Control.Lens
-- TODO: letting _p to be NaN is actually a really bad idea
data Line = Line { _m :: Double
, _p :: V2 Double
} deriving Show
throughPoint :: V2 Double -> Double -> Line
throughPoint p m = Line m p
fromPoints :: V2 Double -> V2 Double -> Line
fromPoints p1 p2 = throughPoint p1 (slope p1 p2)
-- Creates a a line which is perpendicular to the line defined by P and P1 and goes through P
createPerpendicularAt :: V2 Double -> V2 Double -> Line
createPerpendicularAt p p1
| m == 0
= throughPoint p nan
| isNaN m
= throughPoint p 0
| otherwise
= throughPoint p (-1 / m)
where
m = slope p p1
slope :: V2 Double -> V2 Double -> Double
slope p1 p2
| p2 ^. _x == p1 ^. _x
= nan
| otherwise
= (p2 ^. _y - p1 ^. _y) / (p2 ^. _x - p1 ^. _x)
nan :: Double
nan = 0/0
-- If the solution is not found it actually returns +/-infinity
intersection :: Line -> Line -> V2 Double
intersection line1 line2
| isNaN (_m line1)
= verticalIntersection line1 line2
| isNaN (_m line2)
= verticalIntersection line2 line1
| otherwise
= V2 x y
where
x = (_m line1 * _p line1 ^. _x - _m line2 * _p line2 ^. _x - _p line1 ^. _y + _p line2 ^. _y) / (_m line1 - _m line2)
y = _m line1 * x - _m line1 * _p line1 ^. _x + _p line1 ^. _y
-- First line is vertical
verticalIntersection :: Line -> Line -> V2 Double
verticalIntersection vline line = V2 x y
where
x = _p vline ^. _x
y = _m line * (x - _p line ^. _x) + _p line ^. _y
isOnLine :: Line -> V2 Double -> Bool
isOnLine l p2
| isNaN (_m l)
= p1 ^. _x == p2 ^. _x
| otherwise
= (p2 ^. _x - p1 ^. _x) * (_m l) == (p2 ^. _y - p1 ^. _y)
where
p1 = _p l