module Geometry.SetOperations.CrossPoint
( Sign (..)
, toSign
, CrossPoint (..)
, MakeCrossPoint (..)
, toCrossPoint
) where
import Protolude
import Linear
import Linear.Affine (Point)
import qualified Linear.Affine as Point
import Data.EqZero
import Geometry.Plane.General
data Sign = M | Z | P deriving (Show, Eq)
toSign :: (EqZero n, Ord n, Num n) => n -> Sign
toSign x
| eqZero x = Z
| x < 0 = M
| otherwise = P
data CrossPoint v n = CP
{ orientation :: Plane v n -> Sign
, getPoint :: Point v n
}
toCrossPoint :: (EqZero n, Foldable v, Num n, Ord n)
=> Point v n -> CrossPoint v n
toCrossPoint pt = CP orient pt
where
orient p = toSign . ((planeLast p) +) . sum
$ zipWith (*) (toList $ planeVector p) (toList pt)
class MakeCrossPoint v n where
makeCrossPoint :: v (Plane v n) -> Maybe (CrossPoint v n)
instance (Fractional n, Ord n, EqZero n) => MakeCrossPoint V2 n where
makeCrossPoint planes
| eqZero d2 = Nothing
| otherwise = Just $ CP orient solved
where
V2 (Plane (V2 a b) c)
(Plane (V2 d e) f) = planes
orient (Plane (V2 g h) i) = toSign $ g*dd0 + h*dd1 + i
dd0 = d2*d0
dd1 = d2*d1
d0 = b*f c*e
d1 = a*f c*d
d2 = a*e b*d
dd = 1/d2
solved = Point.P $ V2 (dd*d0) (dd*d1)
instance (Fractional n, Ord n, EqZero n) => MakeCrossPoint V3 n where
makeCrossPoint planes
| eqZero d3 = Nothing
| otherwise = Just $ CP orient solved
where
V3 (Plane (V3 a b c) d)
(Plane (V3 e f g) h)
(Plane (V3 i j k) l) = planes
orient (Plane (V3 m n o) p) = toSign $ d3*(m*d0 n*d1 + o*d2 p*d3)
d0 = k*m1 j*m0 + l*m2
d1 = k*m3 i*m0 + l*m4
d2 = j*m3 i*m1 + l*m5
d3 = i*m2 j*m4 + k*m5
m0 = c*h d*g
m1 = b*h d*f
m2 = c*f b*g
m3 = a*h d*e
m4 = c*e a*g
m5 = b*e a*f
dd = 1/d3
solved = Point.P $ V3 (dd*d0) (dd*d1) (dd*d2)