diff --git a/src/Data/NumIdr/Homogeneous.idr b/src/Data/NumIdr/Homogeneous.idr index 87f5a39..a40fe7f 100644 --- a/src/Data/NumIdr/Homogeneous.idr +++ b/src/Data/NumIdr/Homogeneous.idr @@ -27,7 +27,7 @@ public export HMatrix' : Nat -> Type -> Type HMatrix' n = HMatrix n n -||| An `n`-dimensional homogeneous vector type. +||| An homogeneous vector type. ||| ||| Homogeneous vectors are vectors intended to be multiplied with homogeneous ||| matrices (see `HMatrix`). They have an extra dimension compared to regular @@ -129,6 +129,7 @@ translationH : Num a => Vector n a -> HMatrix' n a translationH {n} v with (viewShape v) _ | Shape [n] = hmatrix identity v + ||| Construct a 2D homogeneous matrix that rotates by the given angle (in radians). export rotate2DH : Double -> HMatrix' 2 Double @@ -148,3 +149,20 @@ rotate3DYH = matrixToH . rotate3DY export rotate3DZH : Double -> HMatrix' 3 Double rotate3DZH = matrixToH . rotate3DZ + + +export +reflectH : {n : _} -> Neg a => Fin n -> HMatrix' n a +reflectH i = indexSet [weaken i,weaken i] (-1) identity + +export +reflectXH : {n : _} -> Neg a => HMatrix' (1 + n) a +reflectXH = reflectH 0 + +export +reflectYH : {n : _} -> Neg a => HMatrix' (2 + n) a +reflectYH = reflectH 0 + +export +reflectZH : {n : _} -> Neg a => HMatrix' (3 + n) a +reflectZH = reflectH 0 diff --git a/src/Data/NumIdr/Interfaces.idr b/src/Data/NumIdr/Interfaces.idr index f6a3fc1..37c12e8 100644 --- a/src/Data/NumIdr/Interfaces.idr +++ b/src/Data/NumIdr/Interfaces.idr @@ -31,7 +31,6 @@ export FieldCmp Double where abslt = (<) `on` abs - -- Alternative implementations of `Eq` and `FieldCmp` that compare floating -- point numbers approximately, useful when working with transforms namespace Eq diff --git a/src/Data/NumIdr/Matrix.idr b/src/Data/NumIdr/Matrix.idr index 7cace16..1f5753f 100644 --- a/src/Data/NumIdr/Matrix.idr +++ b/src/Data/NumIdr/Matrix.idr @@ -96,6 +96,23 @@ rotate3DZ : Double -> Matrix' 3 Double rotate3DZ a = matrix [[cos a, - sin a, 0], [sin a, cos a, 0], [0,0,1]] +export +reflect : {n : _} -> Neg a => Fin n -> Matrix' n a +reflect i = indexSet [i, i] (-1) (repeatDiag 1 0) + +export +reflectX : {n : _} -> Neg a => Matrix' (1 + n) a +reflectX = reflect 0 + +export +reflectY : {n : _} -> Neg a => Matrix' (2 + n) a +reflectY = reflect 1 + +export +reflectZ : {n : _} -> Neg a => Matrix' (3 + n) a +reflectZ = reflect 2 + + -------------------------------------------------------------------------------- -- Indexing -------------------------------------------------------------------------------- @@ -225,6 +242,14 @@ trace : Num a => Matrix m n a -> a trace = sum . diagonal' +||| Construct a matrix that reflects a vector along a hyperplane of the +||| given normal vector. The input does not have to be a unit vector. +export +reflectNormal : (Neg a, Fractional a) => Vector n a -> Matrix' n a +reflectNormal {n} v with (viewShape v) + _ | Shape [n] = repeatDiag 1 0 - (2 / normSq v) *. outer v v + + -------------------------------------------------------------------------------- -- Matrix multiplication -------------------------------------------------------------------------------- diff --git a/src/Data/NumIdr/Transform/Orthonormal.idr b/src/Data/NumIdr/Transform/Orthonormal.idr index 9209dca..263e04b 100644 --- a/src/Data/NumIdr/Transform/Orthonormal.idr +++ b/src/Data/NumIdr/Transform/Orthonormal.idr @@ -40,7 +40,7 @@ fromMatrix mat = if isOrthonormal' mat then Just (unsafeMkTrans (matrixToH mat)) ||| Construct an orthonormal transform that reflects a particular coordinate. export reflect : {n : _} -> Neg a => Fin n -> Orthonormal n a -reflect i = unsafeMkTrans $ indexSet [weaken i,weaken i] (-1) identity +reflect = unsafeMkTrans . reflectH ||| The orthonormal transform that reflects on the x-coordinate (first coordinate). export diff --git a/src/Data/NumIdr/Transform/Rotation.idr b/src/Data/NumIdr/Transform/Rotation.idr index 7ed18be..34b8fe2 100644 --- a/src/Data/NumIdr/Transform/Rotation.idr +++ b/src/Data/NumIdr/Transform/Rotation.idr @@ -25,6 +25,7 @@ isRotation' : FieldCmp a => Matrix' n a -> Bool isRotation' mat = isOrthonormal' mat && det mat == 1 ||| Try to constuct a rotation from a matrix. +export fromMatrix : FieldCmp a => Matrix' n a -> Maybe (Rotation n a) fromMatrix mat = if isRotation' mat then Just (unsafeMkTrans $ matrixToH mat) else Nothing @@ -35,6 +36,11 @@ isRotation : FieldCmp a => HMatrix' n a -> Bool isRotation {n} mat with (viewShape mat) _ | Shape [S n, S n] = isHMatrix mat && all (==0) (mat !!.. [EndBound last, One last]) +export +fromHMatrix : FieldCmp a => HMatrix' n a -> Maybe (Rotation n a) +fromHMatrix mat = if isRotation mat then Just (unsafeMkTrans mat) + else Nothing + ||| Construct a 2D rotation that rotates by the given angle (in radians). export rotate2D : Num a => Double -> Rotation 2 Double