{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Data.AffineSpace.Point -- Copyright : (c) 2011 Brent Yorgey -- License : BSD-style (see LICENSE) -- Maintainer : byorgey@cis.upenn.edu -- -- A type for /points/ (as distinct from vectors), with an appropriate -- AffineSpace instance. -- ----------------------------------------------------------------------------- module Data.AffineSpace.Point ( -- * Points Point(..), unPoint, origin, (*.), mirror, -- * Reflection through a point relative, relative2, relative3, reflectThrough, ) where import Data.AffineSpace import Data.VectorSpace import Data.Data (Data) import Data.Typeable (Typeable) ------------------------------------------------------------ -- Points ------------------------------------------------ ------------------------------------------------------------ -- | @Point@ is a newtype wrapper around vectors used to represent -- points, so we don't get them mixed up. The distinction between -- vectors and points is important: translations affect points, but -- leave vectors unchanged. Points are instances of the -- 'AffineSpace' class from "Data.AffineSpace". newtype Point v = P v deriving (Eq, Ord, Read, Show, Data, Typeable, Functor) -- | Convert a point @p@ into the vector from the origin to @p@. This -- should be considered a \"semantically unsafe\" operation; think -- carefully about whether and why you need to use it. The -- recommended way to do this conversion would be to write @(p -- '.-.' 'origin')@. unPoint :: Point v -> v unPoint (P v) = v -- | The origin of the vector space @v@. origin :: AdditiveGroup v => Point v origin = P zeroV instance AdditiveGroup v => AffineSpace (Point v) where type Diff (Point v) = v P v1 .-. P v2 = v1 ^-^ v2 P v1 .+^ v2 = P (v1 ^+^ v2) -- | Scale a point by a scalar. (*.) :: VectorSpace v => Scalar v -> Point v -> Point v s *. P v = P (s *^ v) -- | Reflect a point through the 'origin'. mirror :: AdditiveGroup v => Point v -> Point v mirror = reflectThrough origin -- | Apply a transformation relative to the given point. relative :: AffineSpace p => p -> (Diff p -> Diff p) -> p -> p relative p f = (p .+^) . f . (.-. p) -- | Apply a transformation relative to the given point. relative2 :: AffineSpace p => p -> (Diff p -> Diff p -> Diff p) -> p -> p -> p relative2 p f x y = (p .+^) $ f (inj x) (inj y) where inj = (.-. p) -- | Apply a transformation relative to the given point. relative3 :: AffineSpace p => p -> (Diff p -> Diff p -> Diff p -> Diff p) -> p -> p -> p -> p relative3 p f x y z = (p .+^) $ f (inj x) (inj y) (inj z) where inj = (.-. p) -- | Mirror a point through a given point. reflectThrough :: AffineSpace p => p -> p -> p reflectThrough o = relative o negateV