```module Data.Geometry.Circle( Circle2'(..)
, Disc2'(..)
, IsCircleLike(..)
, inCircle
, insideCircle
, onCircle
, inDisc
, insideDisc
) where

import Data.Geometry.Point
import Data.Geometry.Geometry

---------------------------------------------------------------------
-- | A circle in the plane

data Circle2' a = Circle2 (Point2' a) a

instance HasPoints Circle2' where
points (Circle2 p _) = [p]

-- TODO: instance for transformable

---------------------------------------------------------------------
-- | A disc in the plane (i.e. a circle inclusiding its contents)

newtype Disc2' a = Disc2 { border :: Circle2' a }

instance HasPoints Disc2' where
points = points . border

-- TODO: instance for transformable

--------------------------------------------------------------------------------
-- | functions on circles

-- | Class expressing functions that circlelike objects all have. Like a center
-- and a radius. Minimal implementation is either getCircle or center and radius
class IsCircleLike t where
getCircle   :: t a -> Circle2' a
getCircle x = Circle2 (center x) (radius x)

center :: t a -> Point2' a
center = center . getCircle

radius :: t a -> a

distance   :: Floating a => Point2' a -> t a -> a
distance p = distance p . getCircle

distanceToCenter   :: Floating a => Point2' a -> t a -> a
distanceToCenter p = distanceToCenter p . getCircle

instance IsCircleLike Circle2' where
center (Circle2 p _)       = p
radius (Circle2 _ r)       = r
distanceToCenter p (Circle2 q _) = dist p q

distance p c@(Circle2 _ r) = distanceToCenter p c - r

instance IsCircleLike Disc2' where
getCircle = border

--------------------------------------------------------------------------------
-- | Checking if points lie in or on a circle/disc

-- | Squared distance to the center
l22ToCenter :: Num a => Point2' a -> Circle2' a -> a
l22ToCenter p (Circle2 q _) = l22dist p q

-- | whether or not p lies in OR on the circle c
inCircle       :: (Ord a, Num a) => Point2' a -> Circle2' a -> Bool
p `inCircle` c = l22ToCenter p c <= (radius c)^2

-- | whether or not p lies strictly inside the circle c
insideCircle       :: (Num a, Ord a) => Point2' a -> Circle2' a -> Bool
p `insideCircle` c = l22ToCenter p c < (radius c)^2

-- | whether or not p lies on the circle
onCircle                          :: (Eq a, Num a) => Point2' a -> Circle2' a -> Bool
p `onCircle` c = l22ToCenter p c == (radius c)^2

-- | whether or not a point lies in a disc: this includes its border
inDisc               :: (Num a, Ord a) => Point2' a -> Disc2' a -> Bool
p `inDisc` (Disc2 c) = p `inCircle` c

-- | whether or not a point lies strictly inside a disc.
insideDisc :: (Num a, Ord a) => Point2' a -> Disc2' a -> Bool
p `insideDisc` (Disc2 c) = p `insideCircle` c
```