    {-# LANGUAGE RankNTypes   #-}
    {-# LANGUAGE TypeFamilies #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Diagrams.Core.Points
    -- Copyright   :  (c) 2011 diagrams-core team (see LICENSE)
    -- License     :  BSD-style (see LICENSE)
    -- Maintainer  :  diagrams-discuss@googlegroups.com
    --
    -- A type for /points/ (as distinct from vectors).
    --
    -----------------------------------------------------------------------------

    module Diagrams.Core.Points
           ( -- * Points

             Point(..), origin, (*.), relative, _Point

           , reflectThrough, mirror, relative2, relative3
           ) where

    import           Control.Lens    (over)

    import           Linear.Affine
    import           Linear.Vector

    import           Diagrams.Core.V

    type instance V (Point v n) = v
    type instance N (Point v n) = n

    -- | Reflect a point across the origin.
    mirror :: (Additive v, Num n) => Point v n -> Point v n
    mirror :: forall (v :: * -> *) n.
    (Additive v, Num n) =>
    Point v n -> Point v n
    mirror = Point v n -> Point v n -> Point v n
    forall (v :: * -> *) n.
    (Additive v, Num n) =>
    Point v n -> Point v n -> Point v n
    reflectThrough Point v n
    forall (f :: * -> *) a. (Additive f, Num a) => Point f a
    origin

    -- | Scale a point by a scalar. Specialized version of '(*^)'.
    (*.) :: (Functor v, Num n) => n -> Point v n -> Point v n
    *. :: forall (v :: * -> *) n.
    (Functor v, Num n) =>
    n -> Point v n -> Point v n
    (*.) = n -> Point v n -> Point v n
    forall (f :: * -> *) a. (Functor f, Num a) => a -> f a -> f a
    (*^)

    -- | Apply a transformation relative to the given point.
    relative2 :: (Additive v, Num n)
      => Point v n -> (v n -> v n -> v n)
      -> Point v n -> Point v n -> Point v n
    relative2 :: forall (v :: * -> *) n.
    (Additive v, Num n) =>
    Point v n
    -> (v n -> v n -> v n) -> Point v n -> Point v n -> Point v n
    relative2 Point v n
    p v n -> v n -> v n
    f Point v n
    x Point v n
    y = (Point v n
    p Point v n -> Diff (Point v) n -> Point v n
    forall a. Num a => Point v a -> Diff (Point v) a -> Point v a
    forall (p :: * -> *) a. (Affine p, Num a) => p a -> Diff p a -> p a
    .+^) (Diff (Point v) n -> Point v n) -> Diff (Point v) n -> Point v n
    forall a b. (a -> b) -> a -> b
    $ v n -> v n -> v n
    f (Point v n -> Diff (Point v) n
    inj Point v n
    x) (Point v n -> Diff (Point v) n
    inj Point v n
    y) where inj :: Point v n -> Diff (Point v) n
    inj = (Point v n -> Point v n -> Diff (Point v) n
    forall a. Num a => Point v a -> Point v a -> Diff (Point v) a
    forall (p :: * -> *) a. (Affine p, Num a) => p a -> p a -> Diff p a
    .-. Point v n
    p)

    -- | Apply a transformation relative to the given point.
    relative3 :: (Additive v, Num n)
      => Point v n -> (v n -> v n -> v n -> v n)
      -> Point v n -> Point v n -> Point v n -> Point v n
    relative3 :: forall (v :: * -> *) n.
    (Additive v, Num n) =>
    Point v n
    -> (v n -> v n -> v n -> v n)
    -> Point v n
    -> Point v n
    -> Point v n
    -> Point v n
    relative3 Point v n
    p v n -> v n -> v n -> v n
    f Point v n
    x Point v n
    y Point v n
    z = (Point v n
    p Point v n -> Diff (Point v) n -> Point v n
    forall a. Num a => Point v a -> Diff (Point v) a -> Point v a
    forall (p :: * -> *) a. (Affine p, Num a) => p a -> Diff p a -> p a
    .+^) (Diff (Point v) n -> Point v n) -> Diff (Point v) n -> Point v n
    forall a b. (a -> b) -> a -> b
    $ v n -> v n -> v n -> v n
    f (Point v n -> Diff (Point v) n
    inj Point v n
    x) (Point v n -> Diff (Point v) n
    inj Point v n
    y) (Point v n -> Diff (Point v) n
    inj Point v n
    z) where inj :: Point v n -> Diff (Point v) n
    inj = (Point v n -> Point v n -> Diff (Point v) n
    forall a. Num a => Point v a -> Point v a -> Diff (Point v) a
    forall (p :: * -> *) a. (Affine p, Num a) => p a -> p a -> Diff p a
    .-. Point v n
    p)

    -- | Mirror a point through a given point.
    reflectThrough :: (Additive v, Num n) => Point v n -> Point v n -> Point v n
    reflectThrough :: forall (v :: * -> *) n.
    (Additive v, Num n) =>
    Point v n -> Point v n -> Point v n
    reflectThrough Point v n
    o = ASetter (Point v n) (Point v n) (v n) (v n)
    -> (v n -> v n) -> Point v n -> Point v n
    forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
    over (Point v n -> Iso' (Point v n) (v n)
    forall (f :: * -> *) a.
    (Additive f, Num a) =>
    Point f a -> Iso' (Point f a) (f a)
    relative Point v n
    o) v n -> v n
    forall (f :: * -> *) a. (Functor f, Num a) => f a -> f a
    negated