module Geom2d.Point.Internal
( Point' (..)
, Point (..)
, magnitude
)
where
import Data.AEq
import Data.Fixed
import Geom2d.Rotation
import qualified Prelude ((^))
import Prelude hiding ((^))
import Test.QuickCheck
(^) :: Num a => a -> Int -> a
(^) = (Prelude.^)
newtype Point' a = Point' (a,a) deriving (Show, Read, Eq)
class Point p where
x :: p a -> a
y :: p a -> a
fromCoords :: a -> a -> p a
magnitude :: (Point p, Floating a, Num a) => p a -> a
magnitude p =
sqrt (x p ^ (2::Int) + y p ^ (2::Int))
instance Point Point' where
x (Point' p) = fst p
y (Point' p) = snd p
fromCoords a b = Point' (a, b)
instance (Eq a, Num a, Fractional a, RealFloat a) => Num (Point' a) where
(Point' (p1,p2)) + (Point' (q1,q2)) = Point' (p1+q1, p2+q2)
(Point' (p1,p2)) (Point' (q1,q2)) = Point' (p1q1, p2q2)
(Point' (m,n)) * (Point' (p,q)) = Point' (m*p n*q, m*q + n*p)
abs (Point' (m,n)) = Point' (sqrt (m^2 + n^2), 0)
signum p@(Point' (m,n))
| m == fromIntegral (0::Int) && n == fromIntegral (0::Int) =
Point' (m,n)
| otherwise = Point' (m*l,n*l)
where l = 1 / x (abs p)
fromInteger n = Point' (fromInteger n, 0)
negate (Point' (a,b)) = Point' (negate a, negate b)
instance (Arbitrary a) => Arbitrary (Point' a) where
arbitrary = curry Point' <$> arbitrary <*> arbitrary
instance (Num a, AEq a, RealFloat a) => AEq (Point' a) where
(Point' (m,n)) ~== (Point' (p,q)) =
m^2 + n^2 ~== p^2 + q^2 &&
atan2 n m ~== atan2 q p
instance Functor Point' where
fmap f (Point' (a,b)) = Point' (f a, f b)
instance Rotation Point' where
angle p | magnitude p == 0 = Nothing
| otherwise = Just $ atan2 (y p) (x p)
rotate r (Point' (a,b)) = Point' (a * cos r b * sin r, a * sin r + b * cos r)