Document everything

This commit is contained in:
Kiana Sheibani 2022-10-21 17:12:43 -04:00
parent 1ad4c1f13c
commit 077b393bd1
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
17 changed files with 258 additions and 26 deletions

View file

@ -11,6 +11,7 @@ readme = "README.md"
modules = Data.NP, modules = Data.NP,
Data.Permutation, Data.Permutation,
Data.NumIdr,
Data.NumIdr.Array, Data.NumIdr.Array,
Data.NumIdr.Array.Array, Data.NumIdr.Array.Array,
Data.NumIdr.Array.Coords, Data.NumIdr.Array.Coords,
@ -20,4 +21,15 @@ modules = Data.NP,
Data.NumIdr.Interfaces, Data.NumIdr.Interfaces,
Data.NumIdr.PrimArray, Data.NumIdr.PrimArray,
Data.NumIdr.Scalar, Data.NumIdr.Scalar,
Data.NumIdr.Vector Data.NumIdr.Vector,
Data.NumIdr.Transform,
Data.NumIdr.Transform.Affine,
Data.NumIdr.Transform.Isometry,
Data.NumIdr.Transform.Linear,
Data.NumIdr.Transform.Orthonormal,
Data.NumIdr.Transform.Point,
Data.NumIdr.Transform.Rigid,
Data.NumIdr.Transform.Rotation,
Data.NumIdr.Transform.Transform,
Data.NumIdr.Transform.Translation,
Data.NumIdr.Transform.Trivial

12
src/Data/NumIdr.idr Normal file
View file

@ -0,0 +1,12 @@
module Data.NumIdr
import public Data.NP
import public Data.Permutation
import public Data.NumIdr.Interfaces
import public Data.NumIdr.Array
import public Data.NumIdr.Scalar
import public Data.NumIdr.Vector
import public Data.NumIdr.Matrix
import public Data.NumIdr.Homogeneous
import public Data.NumIdr.Transform

View file

@ -42,29 +42,37 @@ HVector n = Vector (S n)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
||| Convert a vector to a homogeneous vector.
export export
vectorToH : Num a => Vector n a -> HVector n a vectorToH : Num a => Vector n a -> HVector n a
vectorToH v = rewrite plusCommutative 1 n in v ++ vector [1] vectorToH v = rewrite plusCommutative 1 n in v ++ vector [1]
||| Convert a vector to a homogeneous vector that ignores the translation
||| component of homogeneous matrices.
export export
vectorToHLinear : Num a => Vector n a -> HVector n a vectorToHLinear : Num a => Vector n a -> HVector n a
vectorToHLinear v = rewrite plusCommutative 1 n in v ++ vector [0] vectorToHLinear v = rewrite plusCommutative 1 n in v ++ vector [0]
||| Construct a homogeneous vector given its coordinates.
export export
hvector : Num a => Vect n a -> HVector n a hvector : Num a => Vect n a -> HVector n a
hvector v = rewrite plusCommutative 1 n in vector (v ++ [1]) hvector v = rewrite plusCommutative 1 n in vector (v ++ [1])
||| Construct a homogeneous vector that ignores translations given its
||| coordinates.
export export
hvectorLinear : Num a => Vect n a -> HVector n a hvectorLinear : Num a => Vect n a -> HVector n a
hvectorLinear v = rewrite plusCommutative 1 n in vector (v ++ [0]) hvectorLinear v = rewrite plusCommutative 1 n in vector (v ++ [0])
||| Extract a normal vector from a homogeneous vector.
export export
fromHomogeneous : HVector n a -> Vector n a fromHomogeneous : HVector n a -> Vector n a
fromHomogeneous = vector . init . toVect fromHomogeneous {n} v with (viewShape v)
-- HACK: Find an implementation for `fromHomogeneous` that doesn't suck _ | Shape [S n] = resizeLTE [n] v {ok = [lteSuccRight reflexive]}
||| Construct a homogeneous matrix given a matrix and a translation vector.
export export
hmatrix : Num a => Matrix m n a -> Vector m a -> HMatrix m n a hmatrix : Num a => Matrix m n a -> Vector m a -> HMatrix m n a
hmatrix {m,n} mat tr with (viewShape mat) hmatrix {m,n} mat tr with (viewShape mat)
@ -73,14 +81,16 @@ hmatrix {m,n} mat tr with (viewShape mat)
mat `hconcat` reshape mat `hconcat` reshape
{ok = sym $ multOneRightNeutral _} [m,1] tr {ok = sym $ multOneRightNeutral _} [m,1] tr
||| Convert a regular matrix to a homogeneous matrix.
export export
matrixToH : Num a => Matrix m n a -> HMatrix m n a matrixToH : Num a => Matrix m n a -> HMatrix m n a
matrixToH {m,n} mat with (viewShape mat) matrixToH {m,n} mat with (viewShape mat)
_ | Shape [m,n] = indexSet [last,last] 1 $ resize [S m, S n] 0 mat _ | Shape [m,n] = indexSet [last,last] 1 $ resize [S m, S n] 0 mat
||| Determine if a matrix fits the pattern of a homogeneous matrix.
export export
isHMatrix : (Eq a, Num a) => Matrix m n a -> Bool isHMatrix : Eq a => Num a => Matrix m n a -> Bool
isHMatrix {m,n} mat with (viewShape mat) isHMatrix {m,n} mat with (viewShape mat)
isHMatrix {m=Z,n} mat | Shape [Z,n] = False isHMatrix {m=Z,n} mat | Shape [Z,n] = False
isHMatrix {m=S m,n=Z} mat | Shape [S m,Z] = False isHMatrix {m=S m,n=Z} mat | Shape [S m,Z] = False
@ -88,12 +98,14 @@ isHMatrix {m,n} mat with (viewShape mat)
getRow last mat == resize _ 1 (zeros [n]) getRow last mat == resize _ 1 (zeros [n])
||| Get the regular matrix component of a homogeneous matrix.
export export
getMatrix : HMatrix m n a -> Matrix m n a getMatrix : HMatrix m n a -> Matrix m n a
getMatrix {m,n} mat with (viewShape mat) getMatrix {m,n} mat with (viewShape mat)
_ | Shape [S m, S n] = resizeLTE [m,n] mat _ | Shape [S m, S n] = resizeLTE [m,n] mat
{ok = [lteSuccRight reflexive,lteSuccRight reflexive]} {ok = [lteSuccRight reflexive,lteSuccRight reflexive]}
||| Get the translation vector from a homogeneous matrix.
export export
getTranslationVector : HMatrix m n a -> Vector m a getTranslationVector : HMatrix m n a -> Vector m a
getTranslationVector {m,n} mat with (viewShape mat) getTranslationVector {m,n} mat with (viewShape mat)
@ -106,27 +118,33 @@ getTranslationVector {m,n} mat with (viewShape mat)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
||| Construct a homogeneous matrix that scales a vector by the input.
export export
scalingH : {n : _} -> Num a => a -> HMatrix' n a scalingH : {n : _} -> Num a => a -> HMatrix' n a
scalingH x = indexSet [last,last] 1 $ repeatDiag x 0 scalingH x = indexSet [last,last] 1 $ repeatDiag x 0
||| Construct a homogeneous matrix that translates by the given vector.
export export
translationH : Num a => Vector n a -> HMatrix' n a translationH : Num a => Vector n a -> HMatrix' n a
translationH {n} v with (viewShape v) translationH {n} v with (viewShape v)
_ | Shape [n] = hmatrix identity v _ | Shape [n] = hmatrix identity v
||| Construct a 2D homogeneous matrix that rotates by the given angle (in radians).
export export
rotate2DH : Double -> HMatrix' 2 Double rotate2DH : Double -> HMatrix' 2 Double
rotate2DH = matrixToH . rotate2D rotate2DH = matrixToH . rotate2D
||| Construct a 3D homogeneous matrix that rotates around the x-axis.
export export
rotate3DXH : Double -> HMatrix' 3 Double rotate3DXH : Double -> HMatrix' 3 Double
rotate3DXH = matrixToH . rotate3DX rotate3DXH = matrixToH . rotate3DX
||| Construct a 3D homogeneous matrix that rotates around the y-axis.
export export
rotate3DYH : Double -> HMatrix' 3 Double rotate3DYH : Double -> HMatrix' 3 Double
rotate3DYH = matrixToH . rotate3DY rotate3DYH = matrixToH . rotate3DY
||| Construct a 3D homogeneous matrix that rotates around the z-axis.
export export
rotate3DZH : Double -> HMatrix' 3 Double rotate3DZH : Double -> HMatrix' 3 Double
rotate3DZH = matrixToH . rotate3DZ rotate3DZH = matrixToH . rotate3DZ

View file

@ -36,7 +36,7 @@ export
-- Multiplication -- Multiplication
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
infixr 9 *. infixl 9 *.
infixr 10 ^ infixr 10 ^
||| A generalized multiplication/application operator. This interface is ||| A generalized multiplication/application operator. This interface is

View file

@ -74,20 +74,23 @@ export
scale : {n : _} -> Num a => a -> Matrix' n a scale : {n : _} -> Num a => a -> Matrix' n a
scale x = repeatDiag x 0 scale x = repeatDiag x 0
||| Calculate the rotation matrix of an angle. ||| Construct a 2D rotation matrix that rotates by the given angle (in radians).
export export
rotate2D : Double -> Matrix' 2 Double rotate2D : Double -> Matrix' 2 Double
rotate2D a = matrix [[cos a, - sin a], [sin a, cos a]] rotate2D a = matrix [[cos a, - sin a], [sin a, cos a]]
||| Construct a 3D rotation matrix around the x-axis.
export export
rotate3DX : Double -> Matrix' 3 Double rotate3DX : Double -> Matrix' 3 Double
rotate3DX a = matrix [[1,0,0], [0, cos a, - sin a], [0, sin a, cos a]] rotate3DX a = matrix [[1,0,0], [0, cos a, - sin a], [0, sin a, cos a]]
||| Construct a 3D rotation matrix around the y-axis.
export export
rotate3DY : Double -> Matrix' 3 Double rotate3DY : Double -> Matrix' 3 Double
rotate3DY a = matrix [[cos a, 0, sin a], [0,1,0], [- sin a, 0, cos a]] rotate3DY a = matrix [[cos a, 0, sin a], [0,1,0], [- sin a, 0, cos a]]
||| Construct a 3D rotation matrix around the z-axis.
export export
rotate3DZ : Double -> Matrix' 3 Double rotate3DZ : Double -> Matrix' 3 Double
rotate3DZ a = matrix [[cos a, - sin a, 0], [sin a, cos a, 0], [0,0,1]] rotate3DZ a = matrix [[cos a, - sin a, 0], [sin a, cos a, 0], [0,0,1]]

View file

@ -12,14 +12,19 @@ import Data.NumIdr.Transform.Transform
%default total %default total
||| An affine transform can contain any invertible affine map.
public export public export
Affine : Nat -> Type -> Type Affine : Nat -> Type -> Type
Affine = Transform TAffine Affine = Transform TAffine
||| Determine if a homogeneous matrix represents an affine transform
||| (i.e. is invertible).
export export
isAffine : FieldCmp a => HMatrix' n a -> Bool isAffine : FieldCmp a => HMatrix' n a -> Bool
isAffine mat = isHMatrix mat && invertible (getMatrix mat) isAffine mat = isHMatrix mat && invertible (getMatrix mat)
||| Try to construct an affine transform from a homogeneous matrix.
export export
fromHMatrix : FieldCmp a => HMatrix' n a -> Maybe (Affine n a) fromHMatrix : FieldCmp a => HMatrix' n a -> Maybe (Affine n a)
fromHMatrix mat = if isAffine mat fromHMatrix mat = if isAffine mat

View file

@ -8,13 +8,23 @@ import Data.NumIdr.Matrix
import Data.NumIdr.Homogeneous import Data.NumIdr.Homogeneous
import Data.NumIdr.Transform.Point import Data.NumIdr.Transform.Point
import Data.NumIdr.Transform.Transform import Data.NumIdr.Transform.Transform
import Data.NumIdr.Transform.Orthonormal
%default total %default total
||| An isometry is an affine transformation that preserves distance between
||| points. It encompasses translations, rotations, and reflections.
public export public export
Isometry : Nat -> Type -> Type Isometry : Nat -> Type -> Type
Isometry = Transform TIsometry Isometry = Transform TIsometry
||| Determine if a matrix represents an isometry.
export
isIsometry : Eq a => Num a => HMatrix' n a -> Bool
isIsometry mat = isHMatrix mat && isOrthonormal' (getMatrix mat)
-- TODO: Add Isometry constructors ||| Try to construct an isometry from a homogeneous matrix.
export
fromHMatrix : Eq a => Num a => HMatrix' n a -> Maybe (Isometry n a)
fromHMatrix mat = if isIsometry mat then Just (unsafeMkTrans mat) else Nothing

View file

@ -12,20 +12,25 @@ import Data.NumIdr.Transform.Transform
%default total %default total
||| A linear transform can contain any invertible linear map.
public export public export
Linear : Nat -> Type -> Type Linear : Nat -> Type -> Type
Linear = Transform TLinear Linear = Transform TLinear
||| Determine if a homogeneous matrix represents a linear transform.
export export
isLinear : FieldCmp a => HMatrix' n a -> Bool isLinear : FieldCmp a => HMatrix' n a -> Bool
isLinear mat = isHMatrix mat && invertible (getMatrix mat) isLinear mat = isHMatrix mat && invertible (getMatrix mat)
&& all (==0) (getTranslationVector mat) && all (==0) (getTranslationVector mat)
||| Try to construct a linear transform from a homogeneous matrix.
export export
fromHMatrix : FieldCmp a => HMatrix' n a -> Maybe (Linear n a) fromHMatrix : FieldCmp a => HMatrix' n a -> Maybe (Linear n a)
fromHMatrix mat = if isLinear mat then Just (unsafeMkTrans mat) else Nothing fromHMatrix mat = if isLinear mat then Just (unsafeMkTrans mat) else Nothing
||| Try to construct a linear transform from a matrix.
||| This will fail if the matrix is not invertible.
export export
fromMatrix : FieldCmp a => Matrix' n a -> Maybe (Linear n a) fromMatrix : FieldCmp a => Matrix' n a -> Maybe (Linear n a)
fromMatrix mat = if invertible mat then Just (unsafeMkTrans (matrixToH mat)) fromMatrix mat = if invertible mat then Just (unsafeMkTrans (matrixToH mat))

View file

@ -12,39 +12,54 @@ import Data.NumIdr.Transform.Transform
%default total %default total
||| An orthonormal transform is one that contains an orthonormal matrix,
||| also known as an improper rotation or rotoreflection.
public export public export
Orthonormal : Nat -> Type -> Type Orthonormal : Nat -> Type -> Type
Orthonormal = Transform TOrthonormal Orthonormal = Transform TOrthonormal
||| Determine if a matrix represents an orthonormal transform.
export export
isOrthonormal' : Eq a => Num a => Matrix' n a -> Bool isOrthonormal' : Eq a => Num a => Matrix' n a -> Bool
isOrthonormal' {n} mat with (viewShape mat) isOrthonormal' {n} mat with (viewShape mat)
_ | Shape [n,n] = identity == fromFunction [n,n] (\[i,j] => getColumn i mat `dot` getColumn j mat) _ | Shape [n,n] = identity == fromFunction [n,n] (\[i,j] => getColumn i mat `dot` getColumn j mat)
||| Try to construct an orthonormal transform from a matrix.
export export
fromMatrix : Eq a => Num a => Matrix' n a -> Maybe (Orthonormal n a) fromMatrix : Eq a => Num a => Matrix' n a -> Maybe (Orthonormal n a)
fromMatrix mat = if isOrthonormal' mat then Just (unsafeMkTrans (matrixToH mat)) fromMatrix mat = if isOrthonormal' mat then Just (unsafeMkTrans (matrixToH mat))
else Nothing else Nothing
--------------------------------------------------------------------------------
-- Reflections
--------------------------------------------------------------------------------
||| Construct an orthonormal transform that reflects a particular coordinate.
export export
reflect : {n : _} -> Neg a => Fin n -> Orthonormal n a reflect : {n : _} -> Neg a => Fin n -> Orthonormal n a
reflect i = unsafeMkTrans $ indexSet [weaken i,weaken i] (-1) identity reflect i = unsafeMkTrans $ indexSet [weaken i,weaken i] (-1) identity
||| The orthonormal transform that reflects on the x-coordinate (first coordinate).
export export
reflectX : {n : _} -> Neg a => Orthonormal (1 + n) a reflectX : {n : _} -> Neg a => Orthonormal (1 + n) a
reflectX = reflect 0 reflectX = reflect 0
||| The orthonormal transform that reflects on the y-coordinate (second coordinate).
export export
reflectY : {n : _} -> Neg a => Orthonormal (2 + n) a reflectY : {n : _} -> Neg a => Orthonormal (2 + n) a
reflectY = reflect 1 reflectY = reflect 1
||| The orthonormal transform that reflects on the z-coordinate (third coordinate).
export export
reflectZ : {n : _} -> Neg a => Orthonormal (3 + n) a reflectZ : {n : _} -> Neg a => Orthonormal (3 + n) a
reflectZ = reflect 2 reflectZ = reflect 2
||| Construct an orthonormal transform that reflects along a hyperplane of the
||| given normal vector. The input does not have to be a unit vector.
export export
reflectNormal : (Neg a, Fractional a) => Vector n a -> Orthonormal n a reflectNormal : (Neg a, Fractional a) => Vector n a -> Orthonormal n a
reflectNormal {n} v with (viewShape v) reflectNormal {n} v with (viewShape v)

View file

@ -10,6 +10,9 @@ import Data.NumIdr.Interfaces
%default total %default total
||| A point is a wrapper around the basic vector type, intended to be used with
||| `Transform`. These contain the exact same information as a vector, but
||| behave differently when transforms are applied to them.
export export
record Point n a where record Point n a where
constructor MkPoint constructor MkPoint
@ -23,19 +26,23 @@ record Point n a where
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
||| Construct a point from a vector.
export export
fromVector : Vector n a -> Point n a fromVector : Vector n a -> Point n a
fromVector = MkPoint fromVector = MkPoint
||| Convert a point to a vector.
export export
toVector : Point n a -> Vector n a toVector : Point n a -> Vector n a
toVector = vec toVector = vec
||| Construct a point given its coordinates.
export export
point : Vect n a -> Point n a point : Vect n a -> Point n a
point = fromVector . vector point = fromVector . vector
||| The origin point.
export export
origin : Num a => {n : Nat} -> Point n a origin : Num a => {n : Nat} -> Point n a
origin = fromVector $ zeros [n] origin = fromVector $ zeros [n]
@ -49,23 +56,34 @@ origin = fromVector $ zeros [n]
infixl 10 !! infixl 10 !!
infixl 10 !? infixl 10 !?
||| Index the point at the given coordinate.
export export
index : Fin n -> Point n a -> a index : Fin n -> Point n a -> a
index n (MkPoint v) = index n v index i (MkPoint v) = index i v
||| Index the point at the given coordinate.
|||
||| This is the operator form of `index`.
export export
(!!) : Point n a -> Fin n -> a (!!) : Point n a -> Fin n -> a
(!!) = flip index (!!) = flip index
||| Index the point at the given coordinate, returning `Nothing` if the index
||| is out of bounds.
export export
indexNB : Nat -> Point n a -> Maybe a indexNB : Nat -> Point n a -> Maybe a
indexNB n (MkPoint v) = indexNB n v indexNB n (MkPoint v) = indexNB n v
||| Index the point at the given coordinate, returning `Nothing` if the index
||| is out of bounds.
|||
||| This is the operator form of `indexNB`.
export export
(!?) : Point n a -> Nat -> Maybe a (!?) : Point n a -> Nat -> Maybe a
(!?) = flip indexNB (!?) = flip indexNB
||| Return a `Vect` of the coordinates in the point.
export export
toVect : Point n a -> Vect n a toVect : Point n a -> Vect n a
toVect = toVect . vec toVect = toVect . vec
@ -73,14 +91,17 @@ toVect = toVect . vec
-- Named projections -- Named projections
||| Return the x-coordinate (the first value) of the vector.
export export
(.x) : Point (1 + n) a -> a (.x) : Point (1 + n) a -> a
(.x) = index FZ (.x) = index FZ
||| Return the y-coordinate (the second value) of the vector.
export export
(.y) : Point (2 + n) a -> a (.y) : Point (2 + n) a -> a
(.y) = index (FS FZ) (.y) = index (FS FZ)
||| Return the z-coordinate (the third value) of the vector.
export export
(.z) : Point (3 + n) a -> a (.z) : Point (3 + n) a -> a
(.z) = index (FS (FS FZ)) (.z) = index (FS (FS FZ))
@ -98,15 +119,18 @@ infixl 8 -.
-- These would have been named simply (+) and (-), but that caused -- These would have been named simply (+) and (-), but that caused
-- too many issues with interface resolution. -- too many issues with interface resolution.
||| Add a vector to a point.
export export
(+.) : Num a => Vector n a -> Point n a -> Point n a (+.) : Num a => Vector n a -> Point n a -> Point n a
a +. MkPoint b = MkPoint (zipWith (+) a b) a +. MkPoint b = MkPoint (zipWith (+) a b)
||| Add a point to a vector.
export export
(.+) : Num a => Point n a -> Vector n a -> Point n a (.+) : Num a => Point n a -> Vector n a -> Point n a
MkPoint a .+ b = MkPoint (zipWith (+) a b) MkPoint a .+ b = MkPoint (zipWith (+) a b)
||| Subtract two points to get the vector between them.
export export
(-.) : Neg a => Point n a -> Point n a -> Vector n a (-.) : Neg a => Point n a -> Point n a -> Vector n a
MkPoint a -. MkPoint b = zipWith (-) a b MkPoint a -. MkPoint b = zipWith (-) a b

View file

@ -8,12 +8,38 @@ import Data.NumIdr.Matrix
import Data.NumIdr.Homogeneous import Data.NumIdr.Homogeneous
import Data.NumIdr.Transform.Point import Data.NumIdr.Transform.Point
import Data.NumIdr.Transform.Transform import Data.NumIdr.Transform.Transform
import Data.NumIdr.Transform.Rotation
%default total %default total
||| A rigid transform encodes a (proper) rigid transformation, also known as a
||| rototranslation.
public export public export
Rigid : Nat -> Type -> Type Rigid : Nat -> Type -> Type
Rigid = Transform TRigid Rigid = Transform TRigid
-- TODO: Add Rigid constructors -- TODO: Add Rigid constructors
||| Determine if a homogeneous matrix represents a rigid transform.
export
isRigid : FieldCmp a => HMatrix' n a -> Bool
isRigid mat = isHMatrix mat && isRotation' (getMatrix mat)
export
rigid2D : Vector 2 Double -> Double -> Rigid 2 Double
rigid2D v a = setTranslation v (rotate2D a)
||| Construct a 3D rigid transform representing an observer standing at `orig`
||| and facing towards `target`.
|||
||| @ orig The origin point, i.e. the point that the origin is mapped to.
||| @ target The point that the z-axis is directed towards.
||| @ up The vertical direction, the direction that the y-axis faces.
export
faceTowards : (orig, target : Point 3 Double) -> (up : Vector 3 Double)
-> Rigid 3 Double
faceTowards orig target up = setTranslation (toVector orig)
(faceTowards (orig -. target) up)

View file

@ -13,32 +13,63 @@ import Data.NumIdr.Transform.Orthonormal
%default total %default total
||| A transform that contains a rotation.
public export public export
Rotation : Nat -> Type -> Type Rotation : Nat -> Type -> Type
Rotation = Transform TRotation Rotation = Transform TRotation
||| Determine if a matrix represents a rotation.
-- HACK: Replace with more efficient method -- HACK: Replace with more efficient method
export export
isRotation' : FieldCmp a => Matrix' n a -> Bool isRotation' : FieldCmp a => Matrix' n a -> Bool
isRotation' mat = isOrthonormal mat && det mat == 1 isRotation' mat = isOrthonormal' mat && det mat == 1
||| Try to constuct a rotation from a matrix.
fromMatrix : FieldCmp a => Matrix' n a -> Maybe (Rotation n a) fromMatrix : FieldCmp a => Matrix' n a -> Maybe (Rotation n a)
fromMatrix mat = if isRotation' mat then Just (unsafeMkTrans $ matrixToH mat) fromMatrix mat = if isRotation' mat then Just (unsafeMkTrans $ matrixToH mat)
else Nothing else Nothing
||| Determine if a homogeneous matrix represents a rotation.
export
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])
||| Construct a 2D rotation that rotates by the given angle (in radians).
export export
rotate2D : Num a => Double -> Rotation 2 Double rotate2D : Num a => Double -> Rotation 2 Double
rotate2D = unsafeMkTrans . rotate2DH rotate2D = unsafeMkTrans . rotate2DH
--------------------------------------------------------------------------------
-- 3D rotations
--------------------------------------------------------------------------------
||| Construct a 3D rotation around the x-axis.
export export
rotate3DX : Num a => Double -> Rotation 3 Double rotate3DX : Double -> Rotation 3 Double
rotate3DX = unsafeMkTrans . rotate3DXH rotate3DX = unsafeMkTrans . rotate3DXH
||| Construct a 3D rotation around the y-axis.
export export
rotate3DY : Num a => Double -> Rotation 3 Double rotate3DY : Double -> Rotation 3 Double
rotate3DY = unsafeMkTrans . rotate3DYH rotate3DY = unsafeMkTrans . rotate3DYH
||| Construct a 3D rotation around the z-axis.
export export
rotate3DZ : Num a => Double -> Rotation 3 Double rotate3DZ : Double -> Rotation 3 Double
rotate3DZ = unsafeMkTrans . rotate3DZH rotate3DZ = unsafeMkTrans . rotate3DZH
||| Construct a rotation representing an observer facing towards `dir`.
|||
||| @ dir The facing direction, aligned with the z-axis.
||| @ up The vertical direction, the direction that the y-axis faces.
export
faceTowards : (dir, up : Vector 3 Double) -> Rotation 3 Double
faceTowards dir up = let z = normalize dir
x = normalize (up `cross` z)
y = normalize (z `cross` x)
in unsafeMkTrans $ matrixToH $ hstack [x,y,z]

View file

@ -16,12 +16,14 @@ import Data.NumIdr.Transform.Point
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
||| A transform type encodes the properties of a transform. There are 8 transform
||| types, and together with the coersion relation `(:<)` they form a semilattice.
export export
TransType : Type TransType : Type
TransType = (Fin 4, Bool) TransType = (Fin 4, Bool)
namespace TransType namespace TransType
export public export
TAffine, TIsometry, TRigid, TTranslation, TAffine, TIsometry, TRigid, TTranslation,
TLinear, TOrthonormal, TRotation, TTrivial : TransType TLinear, TOrthonormal, TRotation, TTrivial : TransType
TAffine = (3, True) TAffine = (3, True)
@ -39,26 +41,46 @@ namespace TransType
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
||| Coersion relation for transform types.
||| `a :< b` is `True` if and only if any transform of type `a` can be cast into
||| a transform of type `b`.
public export public export
(:<) : TransType -> TransType -> Bool (:<) : TransType -> TransType -> Bool
(xn, xb) :< (yn, yb) = (xn <= yn) && (xb >= yb) (xn, xb) :< (yn, yb) = (xn <= yn) && (xb <= yb)
||| Return the type of transform resulting from multiplying transforms of
||| the two input types.
public export public export
transMult : TransType -> TransType -> TransType transMult : TransType -> TransType -> TransType
transMult (xn, xb) (yn, yb) = (max xn yn, xb && yb) transMult (xn, xb) (yn, yb) = (max xn yn, xb || yb)
||| Return the linearized transform type, i.e. the transform type resulting
||| from removing the translation component of the original transform.
public export public export
linearizeType : TransType -> TransType linearizeType : TransType -> TransType
linearizeType = mapSnd (const False) linearizeType = mapSnd (const False)
||| Return the delinearized transform type, i.e. the transform type resulting
||| from adding a translation to the original transform.
public export public export
delinearizeType : TransType -> TransType delinearizeType : TransType -> TransType
delinearizeType = mapSnd (const True) delinearizeType = mapSnd (const True)
||| A transform is a wrapper for a homogeneous matrix subject to certain
||| restrictions, such as a rotation, an isometry, or a rigid transform.
||| The restriction on the transform is encoded by the transform's *type*.
|||
||| Transforms have special behavior over matrices when it comes to multiplication.
||| When a transform is applied to a vector, only the linear part of the transform
||| is applied, as if `linearize` were called on the transform before the operation.
|||
||| In order for non-linear transformations to be used, the transform should be
||| applied to the special wrapper type `Point`. This separates the concepts of
||| point and vector, which is often useful when working with affine maps.
export export
data Transform : TransType -> Nat -> Type -> Type where data Transform : TransType -> Nat -> Type -> Type where
MkTrans : (type : TransType) -> HMatrix' n a -> Transform type n a MkTrans : (ty : TransType) -> HMatrix' n a -> Transform ty n a
%name Transform t %name Transform t
@ -67,15 +89,31 @@ export
unsafeMkTrans : {ty : _} -> HMatrix' n a -> Transform ty n a unsafeMkTrans : {ty : _} -> HMatrix' n a -> Transform ty n a
unsafeMkTrans = MkTrans _ unsafeMkTrans = MkTrans _
export
toHMatrix : Transform ty n a -> HMatrix' n a
toHMatrix (MkTrans _ mat) = mat
||| Unwrap the inner homogeneous matrix from a transform.
export
getHMatrix : Transform ty n a -> HMatrix' n a
getHMatrix (MkTrans _ mat) = mat
||| Unwrap the inner matrix from a transform, ignoring the translation component
||| if one exists.
export
getMatrix : Transform ty n a -> Matrix' n a
getMatrix (MkTrans _ mat) = getMatrix mat
||| Linearize a transform by removing its translation component.
||| If the transform is already linear, then this function does nothing.
export export
linearize : Num a => Transform ty n a -> Transform (linearizeType ty) n a linearize : Num a => Transform ty n a -> Transform (linearizeType ty) n a
linearize {n} (MkTrans _ mat) with (viewShape mat) linearize {n} (MkTrans _ mat) with (viewShape mat)
_ | Shape [S n,S n] = MkTrans _ (hmatrix (getMatrix mat) (zeros _)) _ | Shape [S n,S n] = MkTrans _ (hmatrix (getMatrix mat) (zeros _))
||| Set the translation component of a transform.
|||
||| `setTranslation v tr == translate v *. linearize tr`
|||
||| If `tr` is linear:
||| `setTranslation v tr == translate v *. tr`
export export
setTranslation : Num a => Vector n a -> Transform ty n a setTranslation : Num a => Vector n a -> Transform ty n a
-> Transform (delinearizeType ty) n a -> Transform (delinearizeType ty) n a
@ -124,7 +162,3 @@ export
export export
{t2 : _} -> So (t1 :< t2) => Cast a b => Cast (Transform t1 n a) (Transform t2 n b) where {t2 : _} -> So (t1 :< t2) => Cast a b => Cast (Transform t1 n a) (Transform t2 n b) where
cast (MkTrans t1 mat) = MkTrans t2 (cast mat) cast (MkTrans t1 mat) = MkTrans t2 (cast mat)
export
Show a => Show (Transform ty n a) where
showPrec p (MkTrans ty mat) = showCon p "MkTrans" $ showArg ty ++ showArg mat

View file

@ -12,20 +12,25 @@ import Data.NumIdr.Transform.Transform
%default total %default total
||| A translation is a transform that adds a constant vector value
||| to its input point.
public export public export
Translation : Nat -> Type -> Type Translation : Nat -> Type -> Type
Translation = Transform TTranslation Translation = Transform TTranslation
||| Determine if a homogeneous matrix encodes a translation.
export export
isTranslation : Eq a => Num a => HMatrix' n a -> Bool isTranslation : Eq a => Num a => HMatrix' n a -> Bool
isTranslation {n} mat with (viewShape mat) isTranslation {n} mat with (viewShape mat)
_ | Shape [S n,S n] = isHMatrix mat && getMatrix mat == identity _ | Shape [S n,S n] = isHMatrix mat && getMatrix mat == identity
||| Construct a translation given a vector.
export export
translate : Num a => Vector n a -> Translation n a translate : Num a => Vector n a -> Translation n a
translate v = unsafeMkTrans (translationH v) translate v = unsafeMkTrans (translationH v)
||| Try to construct a translation from a homogeneous matrix.
export export
fromHMatrix : (Eq a, Num a) => HMatrix' n a -> Maybe (Translation n a) fromHMatrix : Eq a => Num a => HMatrix' n a -> Maybe (Translation n a)
fromHMatrix mat = if isTranslation mat then Just (unsafeMkTrans mat) else Nothing fromHMatrix mat = if isTranslation mat then Just (unsafeMkTrans mat) else Nothing

View file

@ -12,11 +12,15 @@ import Data.NumIdr.Transform.Transform
%default total %default total
||| A trivial transform is a transform that must leave all points unchanged.
||| This transform type only exists so that `linearize` can take a translation
||| as input.
public export public export
Trivial : Nat -> Type -> Type Trivial : Nat -> Type -> Type
Trivial = Transform TTrivial Trivial = Transform TTrivial
||| Determine if a homogeneous matrix is trivial.
export export
isTrivial : Eq a => Num a => HMatrix' n a -> Bool isTrivial : Eq a => Num a => HMatrix' n a -> Bool
isTrivial {n} mat with (viewShape mat) isTrivial {n} mat with (viewShape mat)

View file

@ -132,12 +132,12 @@ swizzle p v = rewrite sym (lengthCorrect p)
) )
||| Swap two entries in a vector. ||| Swap two coordinates in a vector.
export export
swapCoords : (i,j : Fin n) -> Vector n a -> Vector n a swapCoords : (i,j : Fin n) -> Vector n a -> Vector n a
swapCoords = swapInAxis 0 swapCoords = swapInAxis 0
||| Permute the entries in a vector. ||| Permute the coordinates in a vector.
export export
permuteCoords : Permutation n -> Vector n a -> Vector n a permuteCoords : Permutation n -> Vector n a -> Vector n a
permuteCoords = permuteInAxis 0 permuteCoords = permuteInAxis 0
@ -166,3 +166,14 @@ perp : Neg a => Vector 2 a -> Vector 2 a -> a
perp a b = a.x * b.y - a.y * b.x perp a b = a.x * b.y - a.y * b.x
||| Calculate the cross product of the two vectors.
export
cross : Neg a => Vector 3 a -> Vector 3 a -> Vector 3 a
cross v1 v2 = let [a, b, c] = elements v1
[x, y, z] = elements v2
in vector [b*z - c*y, c*x - a*z, a*y - b*x]
||| Calculate the triple product of the three vectors.
export
triple : Neg a => Vector 3 a -> Vector 3 a -> Vector 3 a -> a
triple a b c = a `dot` (b `cross` c)

View file

@ -6,24 +6,37 @@ import Data.NumIdr.Interfaces
%default total %default total
||| A permutation in `n` elements.
|||
||| Permutations are internally stored as a list of elements to swap in
||| right-to-left order. This allows for easy composition and inversion of
||| permutation values.
export export
record Permutation n where record Permutation n where
constructor MkPerm constructor MkPerm
swaps : List (Fin n, Fin n) swaps : List (Fin n, Fin n)
||| Construct a permutation that swaps two elements.
export export
swap : (i,j : Fin n) -> Permutation n swap : (i,j : Fin n) -> Permutation n
swap x y = MkPerm [(x,y)] swap x y = MkPerm [(x,y)]
||| Construct a permutation that makes the listed swaps in right-to-left order.
export export
swaps : List (Fin n, Fin n) -> Permutation n swaps : List (Fin n, Fin n) -> Permutation n
swaps = MkPerm swaps = MkPerm
||| Add a swap to the end of a permutation.
|||
||| `appendSwap sw p = swap sw *. p`
export export
appendSwap : (i,j : Fin n) -> Permutation n -> Permutation n appendSwap : (i,j : Fin n) -> Permutation n -> Permutation n
appendSwap i j (MkPerm a) = MkPerm ((i,j)::a) appendSwap i j (MkPerm a) = MkPerm ((i,j)::a)
||| Add a swap to the beginning of a permutation.
|||
||| `prependSwap sw p = p *. swap sw`
export export
prependSwap : (i,j : Fin n) -> Permutation n -> Permutation n prependSwap : (i,j : Fin n) -> Permutation n -> Permutation n
prependSwap i j (MkPerm a) = MkPerm (a `snoc` (i,j)) prependSwap i j (MkPerm a) = MkPerm (a `snoc` (i,j))
@ -33,6 +46,7 @@ mon : Monoid (a -> a)
mon = MkMonoid @{MkSemigroup (.)} id mon = MkMonoid @{MkSemigroup (.)} id
||| Swap two elements of a `Vect`.
export export
swapElems : (i,j : Fin n) -> Vect n a -> Vect n a swapElems : (i,j : Fin n) -> Vect n a -> Vect n a
swapElems i j v = swapElems i j v =
@ -41,17 +55,20 @@ swapElems i j v =
y = index j v y = index j v
in replaceAt j x $ replaceAt i y v in replaceAt j x $ replaceAt i y v
||| Permute the elements of a `Vect`.
export export
permuteVect : Permutation n -> Vect n a -> Vect n a permuteVect : Permutation n -> Vect n a -> Vect n a
permuteVect p = foldMap @{%search} @{mon} (uncurry swapElems) p.swaps permuteVect p = foldMap @{%search} @{mon} (uncurry swapElems) p.swaps
||| Construct a function that swaps two values.
export export
swapValues : (i,j : Fin n) -> Nat -> Nat swapValues : (i,j : Fin n) -> Nat -> Nat
swapValues i j x = if x == cast i then cast j swapValues i j x = if x == cast i then cast j
else if x == cast j then cast i else if x == cast j then cast i
else x else x
||| Construct a function that permutes values.
export export
permuteValues : Permutation n -> Nat -> Nat permuteValues : Permutation n -> Nat -> Nat
permuteValues p = foldMap @{%search} @{mon} (uncurry swapValues) p.swaps permuteValues p = foldMap @{%search} @{mon} (uncurry swapValues) p.swaps