-----------------------------------------------------------------------------
-- |
-- Module      :  Diagrams.TwoD.Vector
-- Copyright   :  (c) 2011 diagrams-lib team (see LICENSE)
-- License     :  BSD-style (see LICENSE)
-- Maintainer  :  diagrams-discuss@googlegroups.com
--
-- Two-dimensional vectors.
--
-----------------------------------------------------------------------------
module Diagrams.TwoD.Vector
       ( -- * Special 2D vectors
         unitX, unitY, unit_X, unit_Y
       , xDir, yDir

         -- * Converting between vectors and angles
       , angleV, angleDir, e, signedAngleBetween, signedAngleBetweenDirs

         -- * 2D vector utilities
       , perp, leftTurn, cross2

       ) where

import           Control.Lens        (view, (&), (.~), (^.))

import           Diagrams.Angle
import           Diagrams.Direction
import           Diagrams.TwoD.Types

import           Linear.Metric
import           Linear.V2
import           Linear.Vector

-- | The unit vector in the positive X direction.
unitX :: (R1 v, Additive v, Num n) => v n
unitX :: forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX = forall (f :: * -> *) a. (Additive f, Num a) => f a
zero forall a b. a -> (a -> b) -> b
& forall (t :: * -> *) a. R1 t => Lens' (t a) a
_x forall s t a b. ASetter s t a b -> b -> s -> t
.~ n
1

-- | The unit vector in the negative X direction.
unit_X :: (R1 v, Additive v, Num n) => v n
unit_X :: forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unit_X = forall (f :: * -> *) a. (Additive f, Num a) => f a
zero forall a b. a -> (a -> b) -> b
& forall (t :: * -> *) a. R1 t => Lens' (t a) a
_x forall s t a b. ASetter s t a b -> b -> s -> t
.~ (-n
1)

-- | The unit vector in the positive Y direction.
unitY :: (R2 v, Additive v, Num n) => v n
unitY :: forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY = forall (f :: * -> *) a. (Additive f, Num a) => f a
zero forall a b. a -> (a -> b) -> b
& forall (t :: * -> *) a. R2 t => Lens' (t a) a
_y forall s t a b. ASetter s t a b -> b -> s -> t
.~ n
1

-- | The unit vector in the negative Y direction.
unit_Y :: (R2 v, Additive v, Num n) => v n
unit_Y :: forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unit_Y = forall (f :: * -> *) a. (Additive f, Num a) => f a
zero forall a b. a -> (a -> b) -> b
& forall (t :: * -> *) a. R2 t => Lens' (t a) a
_y forall s t a b. ASetter s t a b -> b -> s -> t
.~ (-n
1)

-- | A 'Direction' pointing in the X direction.
xDir :: (R1 v, Additive v, Num n) => Direction v n
xDir :: forall (v :: * -> *) n. (R1 v, Additive v, Num n) => Direction v n
xDir = forall (v :: * -> *) n. v n -> Direction v n
dir forall (v :: * -> *) n. (R1 v, Additive v, Num n) => v n
unitX

-- | A 'Direction' pointing in the Y direction.
yDir :: (R2 v, Additive v, Num n) => Direction v n
yDir :: forall (v :: * -> *) n. (R2 v, Additive v, Num n) => Direction v n
yDir = forall (v :: * -> *) n. v n -> Direction v n
dir forall (v :: * -> *) n. (R2 v, Additive v, Num n) => v n
unitY

-- | A direction at a specified angle counter-clockwise from the 'xDir'.
angleDir :: Floating n => Angle n -> Direction V2 n
angleDir :: forall n. Floating n => Angle n -> Direction V2 n
angleDir = forall (v :: * -> *) n. v n -> Direction v n
dir forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall n. Floating n => Angle n -> V2 n
angleV

-- | A unit vector at a specified angle counter-clockwise from the
--   positive x-axis
angleV :: Floating n => Angle n -> V2 n
angleV :: forall n. Floating n => Angle n -> V2 n
angleV = forall a. Floating a => a -> V2 a
angle forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall n. Iso' (Angle n) n
rad

-- | A unit vector at a specified angle counter-clockwise from the
--   positive X axis.
e :: Floating n => Angle n -> V2 n
e :: forall n. Floating n => Angle n -> V2 n
e = forall n. Floating n => Angle n -> V2 n
angleV

-- | @leftTurn v1 v2@ tests whether the direction of @v2@ is a left
--   turn from @v1@ (that is, if the direction of @v2@ can be obtained
--   from that of @v1@ by adding an angle 0 <= theta <= tau/2).
leftTurn :: (Num n, Ord n) => V2 n -> V2 n -> Bool
leftTurn :: forall n. (Num n, Ord n) => V2 n -> V2 n -> Bool
leftTurn V2 n
v1 V2 n
v2 = (V2 n
v1 forall (f :: * -> *) a. (Metric f, Num a) => f a -> f a -> a
`dot` forall a. Num a => V2 a -> V2 a
perp V2 n
v2) forall a. Ord a => a -> a -> Bool
< n
0

-- | Cross product on vectors in R2.
cross2 :: Num n => V2 n -> V2 n -> n
cross2 :: forall n. Num n => V2 n -> V2 n -> n
cross2 (V2 n
x1 n
y1) (V2 n
x2 n
y2) = n
x1 forall a. Num a => a -> a -> a
* n
y2 forall a. Num a => a -> a -> a
- n
y1 forall a. Num a => a -> a -> a
* n
x2

-- | Signed angle between two vectors. Currently defined as
--
-- @
-- signedAngleBetween u v = (u ^. _theta) ^-^ (v ^. _theta)
-- @
signedAngleBetween :: RealFloat n => V2 n -> V2 n -> Angle n
signedAngleBetween :: forall n. RealFloat n => V2 n -> V2 n -> Angle n
signedAngleBetween V2 n
u V2 n
v = (V2 n
u forall s a. s -> Getting a s a -> a
^. forall (t :: * -> *) n.
(HasTheta t, RealFloat n) =>
Lens' (t n) (Angle n)
_theta) forall (f :: * -> *) a. (Additive f, Num a) => f a -> f a -> f a
^-^ (V2 n
v forall s a. s -> Getting a s a -> a
^. forall (t :: * -> *) n.
(HasTheta t, RealFloat n) =>
Lens' (t n) (Angle n)
_theta)

-- | Same as 'signedAngleBetween' but for 'Directions's.
signedAngleBetweenDirs :: RealFloat n => Direction V2 n -> Direction V2 n -> Angle n
signedAngleBetweenDirs :: forall n.
RealFloat n =>
Direction V2 n -> Direction V2 n -> Angle n
signedAngleBetweenDirs Direction V2 n
u Direction V2 n
v = (Direction V2 n
u forall s a. s -> Getting a s a -> a
^. forall (t :: * -> *) n.
(HasTheta t, RealFloat n) =>
Lens' (t n) (Angle n)
_theta) forall (f :: * -> *) a. (Additive f, Num a) => f a -> f a -> f a
^-^ (Direction V2 n
v forall s a. s -> Getting a s a -> a
^. forall (t :: * -> *) n.
(HasTheta t, RealFloat n) =>
Lens' (t n) (Angle n)
_theta)