module Line ( Line (..)
            , throughPoint
            , fromPoints
            , createPerpendicularAt
            , slope
            , intersection
            ) where
          
import Linear    
import Control.Lens

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 unique it actually return +/-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

