packages feed

brillo-1.13.3: Brillo/Data/Vector.hs

{-# OPTIONS -fno-warn-missing-methods #-}
{-# LANGUAGE TypeSynonymInstances #-}

-- | Geometric functions concerning vectors.
module Brillo.Data.Vector (
  Vector,
  magV,
  argV,
  dotV,
  detV,
  mulSV,
  rotateV,
  angleVV,
  normalizeV,
  unitVectorAtAngle,
)
where

import Brillo.Data.Picture
import Brillo.Geometry.Angle


-- | The magnitude of a vector.
magV :: Vector -> Float
magV (x, y) =
  sqrt (x * x + y * y)
{-# INLINE magV #-}


-- | The angle of this vector, relative to the +ve x-axis.
argV :: Vector -> Float
argV (x, y) =
  normalizeAngle $ atan2 y x
{-# INLINE argV #-}


-- | The dot product of two vectors.
dotV :: Vector -> Vector -> Float
dotV (x1, x2) (y1, y2) =
  x1 * y1 + x2 * y2
{-# INLINE dotV #-}


-- | The determinant of two vectors.
detV :: Vector -> Vector -> Float
detV (x1, y1) (x2, y2) =
  x1 * y2 - y1 * x2
{-# INLINE detV #-}


-- | Multiply a vector by a scalar.
mulSV :: Float -> Vector -> Vector
mulSV s (x, y) =
  (s * x, s * y)
{-# INLINE mulSV #-}


-- | Rotate a vector by an angle (in radians). +ve angle is counter-clockwise.
rotateV :: Float -> Vector -> Vector
rotateV r (x, y) =
  ( x * cos r - y * sin r
  , x * sin r + y * cos r
  )
{-# INLINE rotateV #-}


-- | Compute the inner angle (in radians) between two vectors.
angleVV :: Vector -> Vector -> Float
angleVV p1 p2 =
  let m1 = magV p1
      m2 = magV p2
      d = p1 `dotV` p2
      aDiff = acos $ d / (m1 * m2)
  in  aDiff
{-# INLINE angleVV #-}


-- | Normalise a vector, so it has a magnitude of 1.
normalizeV :: Vector -> Vector
normalizeV v = mulSV (1 / magV v) v
{-# INLINE normalizeV #-}


{-| Produce a unit vector at a given angle relative to the +ve x-axis.
     The provided angle is in radians.
-}
unitVectorAtAngle :: Float -> Vector
unitVectorAtAngle r =
  (cos r, sin r)
{-# INLINE unitVectorAtAngle #-}