hgeometry-0.14: src/Data/Geometry/Point/Class.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
module Data.Geometry.Point.Class where
import Control.Lens
import Data.Geometry.Point.Internal (Point)
import qualified Data.Geometry.Point.Internal as Internal
import Data.Geometry.Vector
import GHC.TypeNats
--------------------------------------------------------------------------------
-- $setup
-- >>> import Data.Geometry.Point.Internal (pattern Point2, pattern Point3, origin)
class ToAPoint point d r where
toPoint :: Prism' (point d r) (Point d r)
class AsAPoint p where
asAPoint :: Lens (p d r) (p d' r') (Point d r) (Point d' r')
-- | Lens to access the vector corresponding to this point.
--
-- >>> (Point3 1 2 3) ^. vector'
-- Vector3 1 2 3
-- >>> origin & vector' .~ Vector3 1 2 3
-- Point3 1 2 3
vector' :: AsAPoint p => Lens (p d r) (p d r') (Vector d r) (Vector d r')
vector' = asAPoint . lens Internal.toVec (const Internal.Point)
-- | Get the coordinate in a given dimension
--
-- >>> Point3 1 2 3 ^. coord @2
-- 2
-- >>> Point3 1 2 3 & coord @1 .~ 10
-- Point3 10 2 3
-- >>> Point3 1 2 3 & coord @3 %~ (+1)
-- Point3 1 2 4
coord :: forall i p d r. (1 <= i, i <= d, KnownNat i, Arity d, AsAPoint p) => Lens' (p d r) r
coord = asAPoint.Internal.coord @i
-- | Get the coordinate in a given dimension. This operation is unsafe in the
-- sense that no bounds are checked. Consider using `coord` instead.
--
--
-- >>> Point3 1 2 3 ^. unsafeCoord 2
-- 2
unsafeCoord :: (Arity d, AsAPoint p) => Int -> Lens' (p d r) r
unsafeCoord i = asAPoint.Internal.unsafeCoord i
instance ToAPoint Point d r where
toPoint = prism' id Just
instance AsAPoint Point where
asAPoint = id
-- | Shorthand to access the first coordinate C 1
--
-- >>> Point3 1 2 3 ^. xCoord
-- 1
-- >>> Point2 1 2 & xCoord .~ 10
-- Point2 10 2
xCoord :: (1 <= d, Arity d, AsAPoint point) => Lens' (point d r) r
xCoord = coord @1
{-# INLINABLE xCoord #-}
-- | Shorthand to access the second coordinate C 2
--
-- >>> Point2 1 2 ^. yCoord
-- 2
-- >>> Point3 1 2 3 & yCoord %~ (+1)
-- Point3 1 3 3
yCoord :: (2 <= d, Arity d, AsAPoint point) => Lens' (point d r) r
yCoord = coord @2
{-# INLINABLE yCoord #-}
-- | Shorthand to access the third coordinate C 3
--
-- >>> Point3 1 2 3 ^. zCoord
-- 3
-- >>> Point3 1 2 3 & zCoord %~ (+1)
-- Point3 1 2 4
zCoord :: (3 <= d, Arity d, AsAPoint point) => Lens' (point d r) r
zCoord = coord @3
{-# INLINABLE zCoord #-}