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

    -- | Geometric functions concerning vectors.
    module Graphics.Gloss.Data.Vector
            ( Vector
            , magV
            , argV
            , dotV
            , detV
            , mulSV
            , rotateV
            , angleVV
            , normalizeV
            , unitVectorAtAngle )
    where
    import Graphics.Gloss.Data.Picture
    import Graphics.Gloss.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 #-}