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

-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.Core.Points
--
-- 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

mirror :: (Additive v, Num n) => Point v n -> Point v n
mirror = reflectThrough origin

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

-- | 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 p f x y = (p .+^) \$ f (inj x) (inj y) where inj = (.-. 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 p f x y z = (p .+^) \$ f (inj x) (inj y) (inj z) where inj = (.-. p)

-- | Mirror a point through a given point.
reflectThrough :: (Additive v, Num n) => Point v n -> Point v n -> Point v n
reflectThrough o = over (relative o) negated

```