{-# LANGUAGE UnicodeSyntax #-}

module Numeric.Geometric.Predicates.Rational where
import Numeric.Geometric.Primitives


-- | Counter-clockwise orientation test. Classifies p3 in relation to the line formed by p1 and p2.

ccw  Vector2 Rational  Vector2 Rational  Vector2 Rational 
     Ordering -- ^ LT=Right, GT=Left, EQ=Coincident 

ccw (x1,y1) (x2,y2) (x3,y3) = compare result 0
    where
      result = (x1*y2) + (x2*y3) + (x3*y1) - (x1*y3) - (x2*y1) - (x3*y2)


-- | Test the relation of a point to the circle formed by (p1..p3).

incircle  (Vector2 Rational, Vector2 Rational, Vector2 Rational) -- ^ 3 points on the circle, must be in counterclockwise order. 
          Vector2 Rational                                       -- ^ Query point 
          Ordering                                               -- ^ GT=inside, EQ=border, LT=outside 
incircle (p1,p2,p3) p4 = compare result 0

       where
         result = (d p1) * (ccw' p2 p3 p4) 
                - (d p2) * (ccw' p1 p3 p4) 
                + (d p3) * (ccw' p1 p2 p4) 
                - (d p4) * (ccw' p1 p2 p3)

         d (x,y) = (x*x) + (y*y)

         ccw' (x1,y1) (x2,y2) (x3,y3) = (x1*y2) + (x2*y3) + (x3*y1) - (x1*y3) - (x2*y1) - (x3*y2)

-- | Test if Point is within the closed interval specified

cintt  Rational -- ^ Lo 
       Rational -- ^ Hi
       Rational -- ^ Point 
       Bool      

cintt x1 x2 p | x1 == x2 = p == x1
              | otherwise = t >= 0 && t <= 1

          where
            t = (u - p) / (-v)
            u = x1
            v = x2 - x1



-- | Calculate the point of intersecton. Assumes the input lines are already known to be intersecting,

isctp  LineSegment (Vector2 Rational)  LineSegment (Vector2 Rational)  Vector2 Rational
isctp ((ax,ay),(bx,by)) ((cx,cy),(dx,dy)) = (x,y)

    where

      rtop = (ay-cy)*(dx-cx)-(ax-cx)*(dy-cy)
      rbot = (bx-ax)*(dy-cy)-(by-ay)*(dx-cx)

      r = rtop/rbot

      x = ax + r * (bx - ax)
      y = ay + r * (by - ay)