```module Numeric.LinearAlgebra.OrthoNormalBasis where

import Numeric.LinearAlgebra.Vector

epsilon :: (Ord a, Floating a) => a
epsilon = 0.01

data ONB a = ONB
{ onbU :: Vec3 a
, onbV :: Vec3 a
, onbW :: Vec3 a
} deriving (Read, Show, Eq, Ord)

mkFromU :: (Ord a, Floating a) => Vec3 a -> ONB a
mkFromU u' = ONB u v w
where
n = Vec3 1 0 0
m = Vec3 0 1 0
u = unitVector u'
v = if len (u <%> n) < epsilon
then u <%> m
else u <%> n
w = u <%> v

mkFromV :: (Ord a, Floating a) => Vec3 a -> ONB a
mkFromV v' = ONB u v w
where
n = Vec3 1 0 0
m = Vec3 0 1 0
v = unitVector v'
u = if lenSquared (v <%> n) < epsilon
then v <%> m
else v <%> n
w = u <%> v

mkFromW :: (Ord a, Floating a) => Vec3 a -> ONB a
mkFromW w' = ONB u v w
where
n = Vec3 1 0 0
m = Vec3 0 1 0
w = unitVector w'
u = if len (w <%> n) < epsilon
then w <%> m
else w <%> n
v = w <%> u

mkFromUV :: Floating a => Vec3 a -> Vec3 a -> ONB a
mkFromUV u' v' = ONB u v w
where
u = unitVector u'
w = unitVector (u' <%> v')
v = w <%> u

mkFromVU :: Floating a => Vec3 a -> Vec3 a -> ONB a
mkFromVU v' u' = ONB u v w
where
v = unitVector v'
w = unitVector (u' <%> v')
u = v <%> w

mkFromUW :: Floating a => Vec3 a -> Vec3 a -> ONB a
mkFromUW u' w' = ONB u v w
where
u = unitVector u'
v = unitVector (w' <%> u')
w = u <%> v

mkFromWU :: Floating a => Vec3 a -> Vec3 a -> ONB a
mkFromWU w' u' = ONB u v w
where
w = unitVector w'
v = unitVector (w' <%> u')
u = v <%> w

mkFromVW :: Floating a => Vec3 a -> Vec3 a -> ONB a
mkFromVW v' w' = ONB u v w
where
v = unitVector v'
u = unitVector (v' <%> w')
w = u <%> v

mkFromWV :: Floating a => Vec3 a -> Vec3 a -> ONB a
mkFromWV w' v' = ONB u v w
where
w = unitVector w'
u = unitVector (v' <%> w')
v = w <%> u
```