{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}

module Geom2d.Intersect

where

import Geom2d.Point
import Geom2d.Line
import Geom2d.Line.Internal

class Intersect a b where
  intersect :: a -> b -> Bool

instance (Eq a) => Intersect (Point' a) (Point' a) where
  intersect p q = p == q

instance (Eq (p a), Num (p a), Num a, RealFloat a, Point p) =>
         Intersect (InfLine p a) (InfLine p a) where
  intersect a b | a == b = True
                | a `parallel` b = False
                | otherwise = True

instance (Point p, Eq a, Fractional a) =>
         Intersect (InfLine p a) (p a) where
  intersect line@(InfLine a _) q =
    maybe
    ( x a == x q )
    ( \f -> f (x q) == y q )
    ( lineF line )

instance (Point p, Eq a, Fractional a) =>
         Intersect (p a) (InfLine p a) where
  intersect = flip intersect

instance (Eq (p a), Point p, Num (p a), RealFloat a) =>
         Intersect (FinLine p a) (FinLine p a) where
  intersect (FinLine a1 b1) (FinLine a2 b2) =
    case intersection (InfLine a1 b1) (InfLine a2 b2) of
      Nothing -> False
      Just p ->
        let minx = max (min (x a1) (x b1)) (min (x a2) (x b2))
            maxx = min (max (x a1) (x b1)) (max (x a2) (x b2))
            miny = max (min (y a1) (y b1)) (min (y a2) (y b2))
            maxy = min (max (y a1) (y b1)) (max (y a2) (y b2))
        in and [ x p <= maxx
               , x p >= minx
               , y p <= maxy
               , y p >= miny
               ]

instance (Eq (p a), Point p, Num (p a), RealFloat a) =>
         Intersect (InfLine p a) (FinLine p a) where
  intersect infLine (FinLine f1 f2) =
    case intersection infLine (InfLine f1 f2) of
      Nothing -> False
      Just p ->
        let minx = min (x f1) (x f2)
            maxx = max (x f1) (x f2)
            miny = min (y f1) (y f2)
            maxy = max (y f1) (y f2)
        in and [ x p <= maxx
               , x p >= minx
               , y p <= maxy
               , y p >= miny
               ]

instance (Eq (p a), Point p, Num (p a), RealFloat a) =>
         Intersect (FinLine p a) (InfLine p a) where
  intersect = flip intersect