-- |
-- Functions for working with 2-dimensional homogeneous coordinates.
module Nonlinear.Projective.Hom2 where

import Nonlinear.Matrix
import Nonlinear.V2
import Nonlinear.V3
import Nonlinear.Vector ((*^))

-- | Convert a 2-dimensional affine vector into a 3-dimensional homogeneous vector,
-- i.e. sets the @w@ coordinate to 0.
vector :: Num a => V2 a -> V3 a
vector :: V2 a -> V3 a
vector (V2 a
a a
b) = a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
a a
b a
0
{-# INLINE vector #-}

-- | Convert a 2-dimensional affine point into a 3-dimensional homogeneous vector,
-- i.e. sets the @w@ coordinate to 1.
point :: Num a => V2 a -> V3 a
point :: V2 a -> V3 a
point (V2 a
a a
b) = a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
a a
b a
1
{-# INLINE point #-}

-- | Convert 3-dimensional projective coordinates to a 2-dimensional
-- point. This operation may be denoted, @euclidean [x:y:w] = (x\/w,
-- y\/w)@ where the projective, homogeneous, coordinate
-- @[x:y:z]@ is one of many associated with a single point @(x\/w,
-- y\/w)@.
normalizePoint :: Fractional a => V3 a -> V2 a
normalizePoint :: V3 a -> V2 a
normalizePoint (V3 a
a a
b a
w) = (a
1 a -> a -> a
forall a. Fractional a => a -> a -> a
/ a
w) a -> V2 a -> V2 a
forall (f :: * -> *) a. (Vec f, Num a) => a -> f a -> f a
*^ a -> a -> V2 a
forall a. a -> a -> V2 a
V2 a
a a
b
{-# INLINE normalizePoint #-}

mkTransformation :: Num a => M22 a -> V2 a -> M33 a
mkTransformation :: M22 a -> V2 a -> M33 a
mkTransformation (V2 V2 a
r1 V2 a
r2) (V2 a
tx a
ty) =
  V3 a -> V3 a -> V3 a -> M33 a
forall a. a -> a -> a -> V3 a
V3 (V2 a -> a -> V3 a
forall a. V2 a -> a -> V3 a
snoc2 V2 a
r1 a
tx) (V2 a -> a -> V3 a
forall a. V2 a -> a -> V3 a
snoc2 V2 a
r2 a
ty) (a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
0 a
0 a
1)
  where
    snoc2 :: V2 a -> a -> V3 a
snoc2 (V2 a
x a
y) = a -> a -> a -> V3 a
forall a. a -> a -> a -> V3 a
V3 a
x a
y
{-# INLINE mkTransformation #-}

-- | translate along two axes
translation :: Num a => V2 a -> M33 a
translation :: V2 a -> M33 a
translation = M22 a -> V2 a -> M33 a
forall a. Num a => M22 a -> V2 a -> M33 a
mkTransformation M22 a
forall (v :: * -> *) a. (Vec v, Num a) => v (v a)
identity

-- | rotate a radiant angle
rotateRad :: Floating a => a -> M33 a
rotateRad :: a -> M33 a
rotateRad a
rad = M22 a -> V2 a -> M33 a
forall a. Num a => M22 a -> V2 a -> M33 a
mkTransformation M22 a
rot V2 a
0
  where
    cosR :: a
cosR = a -> a
forall a. Floating a => a -> a
cos a
rad
    sinR :: a
sinR = a -> a
forall a. Floating a => a -> a
sin a
rad
    rot :: M22 a
rot =
      V2 a -> V2 a -> M22 a
forall a. a -> a -> V2 a
V2
        (a -> a -> V2 a
forall a. a -> a -> V2 a
V2 a
cosR (a -> a
forall a. Num a => a -> a
negate a
sinR))
        (a -> a -> V2 a
forall a. a -> a -> V2 a
V2 a
sinR a
cosR)

-- | Convert a 2x2 matrix to a 3x3 matrix extending it with 0's in the new row and column.
m22_to_m33 :: Num a => M22 a -> M33 a
m22_to_m33 :: M22 a -> M33 a
m22_to_m33 (V2 V2 a
r1 V2 a
r2) = V3 a -> V3 a -> V3 a -> M33 a
forall a. a -> a -> a -> V3 a
V3 (V2 a -> V3 a
forall a. Num a => V2 a -> V3 a
vector V2 a
r1) (V2 a -> V3 a
forall a. Num a => V2 a -> V3 a
vector V2 a
r2) (V2 a -> V3 a
forall a. Num a => V2 a -> V3 a
point V2 a
0)