mirror of https://github.com/liamg/aminal.git
371 lines
14 KiB
Cheetah
371 lines
14 KiB
Cheetah
// Copyright 2014 The go-gl/mathgl Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// <<.Comment>>
|
|
// Edit <<.TemplateName>> and run "go generate" to make changes.
|
|
|
|
package mgl32
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"golang.org/x/image/math/f32"
|
|
"text/tabwriter"
|
|
)
|
|
|
|
type Mat2 [4]float32
|
|
type Mat2x3 [6]float32
|
|
type Mat2x4 [8]float32
|
|
type Mat3x2 [6]float32
|
|
type Mat3 f32.Mat3
|
|
type Mat3x4 [12]float32
|
|
type Mat4x2 [8]float32
|
|
type Mat4x3 [12]float32
|
|
type Mat4 f32.Mat4
|
|
|
|
func (m Mat2) Mat3() Mat3 {
|
|
col0, col1 := m.Cols()
|
|
return Mat3FromCols(
|
|
col0.Vec3(0),
|
|
col1.Vec3(0),
|
|
Vec3{0, 0, 1},
|
|
)
|
|
}
|
|
|
|
func (m Mat2) Mat4() Mat4 {
|
|
col0, col1 := m.Cols()
|
|
return Mat4FromCols(
|
|
col0.Vec4(0, 0),
|
|
col1.Vec4(0, 0),
|
|
Vec4{0, 0, 1, 0},
|
|
Vec4{0, 0, 0, 1},
|
|
)
|
|
}
|
|
|
|
func (m Mat3) Mat2() Mat2 {
|
|
col0, col1, _ := m.Cols()
|
|
return Mat2FromCols(
|
|
col0.Vec2(),
|
|
col1.Vec2(),
|
|
)
|
|
}
|
|
|
|
func (m Mat3) Mat4() Mat4 {
|
|
col0, col1, col2 := m.Cols()
|
|
return Mat4FromCols(
|
|
col0.Vec4(0),
|
|
col1.Vec4(0),
|
|
col2.Vec4(0),
|
|
Vec4{0, 0, 0, 1},
|
|
)
|
|
}
|
|
|
|
func (m Mat4) Mat2() Mat2 {
|
|
col0, col1, _, _ := m.Cols()
|
|
return Mat2FromCols(
|
|
col0.Vec2(),
|
|
col1.Vec2(),
|
|
)
|
|
}
|
|
|
|
func (m Mat4) Mat3() Mat3 {
|
|
col0, col1, col2, _ := m.Cols()
|
|
return Mat3FromCols(
|
|
col0.Vec3(),
|
|
col1.Vec3(),
|
|
col2.Vec3(),
|
|
)
|
|
}
|
|
|
|
|
|
<</* Common functions for all matrices */>>
|
|
<<range $m := enum 2 3 4>><<range $n := enum 2 3 4>>
|
|
<<$type := typename $m $n>>
|
|
|
|
// Sets a Column within the Matrix, so it mutates the calling matrix.
|
|
func (m *<<$type>>) SetCol(col int, v <<typename $m 1>>) {
|
|
<<range $i := iter 0 $m>><<sep "," $i>>m[col*<<$m>>+<<$i>>]<<end>> = <<repeat $m "v[%d]" ",">>
|
|
}
|
|
|
|
// Sets a Row within the Matrix, so it mutates the calling matrix.
|
|
func (m *<<$type>>) SetRow(row int, v <<typename $n 1>>) {
|
|
<<range $i := iter 0 $n>><<sep "," $i>>m[row+<<mul $m $i>>]<<end>> = <<repeat $n "v[%d]" ",">>
|
|
}
|
|
|
|
<<if eq $m $n>>
|
|
// Diag is a basic operation on a square matrix that simply
|
|
// returns main diagonal (meaning all elements such that row==col).
|
|
func (m <<$type>>) Diag() <<typename $m 1>> {
|
|
return <<typename $m 1>>{<<range $i := iter 0 $m>>m[<<mul $i $m | add $i>>],<<end>>}
|
|
}
|
|
<<end>>
|
|
|
|
<<if eq $m $n>>
|
|
// Ident<<$m>> returns the <<$m>>x<<$n>> identity matrix.
|
|
// The identity matrix is a square matrix with the value 1 on its
|
|
// diagonals. The characteristic property of the identity matrix is that
|
|
// any matrix multiplied by it is itself. (MI = M; IN = N)
|
|
func Ident<<$m>>() <<$type>> {
|
|
return <<$type>>{<<range $i := matiter $m $n>><<if eq $i.M $i.N>>1<<else>>0<<end>>,<<end>>}
|
|
}
|
|
<<end>>
|
|
|
|
<<if eq $m $n>>
|
|
// Diag<<$m>> creates a diagonal matrix from the entries of the input vector.
|
|
// That is, for each pointer for row==col, vector[row] is the entry. Otherwise it's 0.
|
|
//
|
|
// Another way to think about it is that the identity is this function where the every vector element is 1.
|
|
func Diag<<$m>>(v <<typename $m 1>>) <<$type>> {
|
|
var m <<$type>>
|
|
<<range $i := iter 0 $m>><<sep "," $i>>m[<<mul $i $m | add $i>>]<<end>> = <<repeat $m "v[%d]" ",">>
|
|
return m
|
|
}
|
|
<<end>>
|
|
|
|
// <<$type>>FromRows builds a new matrix from row vectors.
|
|
// The resulting matrix will still be in column major order, but this can be
|
|
// good for hand-building matrices.
|
|
|
|
func <<$type>>FromRows(<<range $i := iter 0 $m>><<sep "," $i>>row<<$i>><<end>> <<typename $n 1>>) <<$type>> {
|
|
return <<$type>>{<<range $i := matiter $m $n>>row<<$i.M>>[<<$i.N>>],<<end>>}
|
|
}
|
|
|
|
// <<$type>>FromCols builds a new matrix from column vectors.
|
|
func <<$type>>FromCols(<<repeat $n "col%d" ",">> <<typename $m 1>>) <<$type>> {
|
|
return <<$type>>{<<range $i := matiter $m $n>>col<<$i.N>>[<<$i.M>>], <<end>>}
|
|
}
|
|
|
|
// Add performs an element-wise addition of two matrices, this is
|
|
// equivalent to iterating over every element of m1 and adding the corresponding value of m2.
|
|
func (m1 <<$type>>) Add(m2 <<$type>>) <<$type>> {
|
|
return <<$type>>{<< range $i := matiter $m $n>>m1[<<$i>>] + m2[<<$i>>], <<end>>}
|
|
}
|
|
|
|
// Sub performs an element-wise subtraction of two matrices, this is
|
|
// equivalent to iterating over every element of m1 and subtracting the corresponding value of m2.
|
|
func (m1 <<$type>>) Sub(m2 <<$type>>) <<$type>> {
|
|
return <<$type>>{<< range $i := matiter $m $n>>m1[<<$i>>] - m2[<<$i>>], <<end>>}
|
|
}
|
|
|
|
// Mul performs a scalar multiplcation of the matrix. This is equivalent to iterating
|
|
// over every element of the matrix and multiply it by c.
|
|
func (m1 <<$type>>) Mul(c float32) <<$type>> {
|
|
return <<$type>>{<< range $i := matiter $m $n>>m1[<<$i>>] * c, <<end>>}
|
|
}
|
|
|
|
<<range $o := enum 1 2 3 4>>
|
|
// Mul<<$n>><<if ne $n $o>>x<<$o>><<end>> performs a "matrix product" between this matrix
|
|
// and another of the given dimension. For any two matrices of dimensionality
|
|
// MxN and NxO, the result will be MxO. For instance, Mat4 multiplied using
|
|
// Mul4x2 will result in a Mat4x2.
|
|
func (m1 <<$type>>) Mul<<$n>><<if ne $n $o>>x<<$o>><<end>>(m2 <<typename $n $o>>) <<typename $m $o>> {
|
|
return <<typename $m $o>>{<<range $i := matiter $m $o>>
|
|
<<range $k := iter 0 $n>><<sep "+" $k>>m1[<<mul $k $m | add $i.M>>]*m2[<<mul $i.N $n| add $k>>]<<end>>,<<end>>
|
|
}
|
|
}
|
|
<<end>>
|
|
|
|
// Transpose produces the transpose of this matrix. For any MxN matrix
|
|
// the transpose is an NxM matrix with the rows swapped with the columns. For instance
|
|
// the transpose of the Mat3x2 is a Mat2x3 like so:
|
|
//
|
|
// [[a b]] [[a c e]]
|
|
// [[c d]] = [[b d f]]
|
|
// [[e f]]
|
|
func (m1 <<$type>>) Transpose() <<typename $n $m>> {
|
|
return <<typename $n $m>>{<<range $i := matiter $n $m>>m1[<<mul $m $i.M | add $i.N>>], <<end>>}
|
|
}
|
|
|
|
<<if eq $m $n>>
|
|
// The determinant of a matrix is a measure of a square matrix's
|
|
// singularity and invertability, among other things. In this library, the
|
|
// determinant is hard coded based on pre-computed cofactor expansion, and uses
|
|
// no loops. Of course, the addition and multiplication must still be done.
|
|
func (m <<$type>>) Det() float32 {
|
|
<<if eq $m 2 ->>
|
|
return m[0]*m[3] - m[1]*m[2]
|
|
<<else if eq $m 3 ->>
|
|
return m[0]*m[4]*m[8] + m[3]*m[7]*m[2] + m[6]*m[1]*m[5] - m[6]*m[4]*m[2] - m[3]*m[1]*m[8] - m[0]*m[7]*m[5]
|
|
<<else if eq $m 4 ->>
|
|
return m[0]*m[5]*m[10]*m[15] - m[0]*m[5]*m[11]*m[14] - m[0]*m[6]*m[9]*m[15] + m[0]*m[6]*m[11]*m[13] + m[0]*m[7]*m[9]*m[14] - m[0]*m[7]*m[10]*m[13] - m[1]*m[4]*m[10]*m[15] + m[1]*m[4]*m[11]*m[14] + m[1]*m[6]*m[8]*m[15] - m[1]*m[6]*m[11]*m[12] - m[1]*m[7]*m[8]*m[14] + m[1]*m[7]*m[10]*m[12] + m[2]*m[4]*m[9]*m[15] - m[2]*m[4]*m[11]*m[13] - m[2]*m[5]*m[8]*m[15] + m[2]*m[5]*m[11]*m[12] + m[2]*m[7]*m[8]*m[13] - m[2]*m[7]*m[9]*m[12] - m[3]*m[4]*m[9]*m[14] + m[3]*m[4]*m[10]*m[13] + m[3]*m[5]*m[8]*m[14] - m[3]*m[5]*m[10]*m[12] - m[3]*m[6]*m[8]*m[13] + m[3]*m[6]*m[9]*m[12]
|
|
<<end ->>
|
|
}
|
|
<<end>>
|
|
|
|
<<if eq $m $n>>
|
|
// Inv computes the inverse of a square matrix. An inverse is a square matrix such that when multiplied by the
|
|
// original, yields the identity.
|
|
//
|
|
// M_inv * M = M * M_inv = I
|
|
//
|
|
// In this library, the math is precomputed, and uses no loops, though the multiplications, additions, determinant calculation, and scaling
|
|
// are still done. This can still be (relatively) expensive for a 4x4.
|
|
//
|
|
// This function checks the determinant to see if the matrix is invertible.
|
|
// If the determinant is 0.0, this function returns the zero matrix. However, due to floating point errors, it is
|
|
// entirely plausible to get a false positive or negative.
|
|
// In the future, an alternate function may be written which takes in a pre-computed determinant.
|
|
func (m <<$type>>) Inv() <<$type>> {
|
|
det := m.Det()
|
|
if FloatEqual(det, float32(0.0)) {
|
|
return <<$type>>{}
|
|
}
|
|
<<if eq $m 2>>
|
|
retMat := Mat2{m[3], -m[1], -m[2], m[0]}
|
|
<<else if eq $m 3>>
|
|
retMat := Mat3{
|
|
m[4]*m[8] - m[5]*m[7],
|
|
m[2]*m[7] - m[1]*m[8],
|
|
m[1]*m[5] - m[2]*m[4],
|
|
m[5]*m[6] - m[3]*m[8],
|
|
m[0]*m[8] - m[2]*m[6],
|
|
m[2]*m[3] - m[0]*m[5],
|
|
m[3]*m[7] - m[4]*m[6],
|
|
m[1]*m[6] - m[0]*m[7],
|
|
m[0]*m[4] - m[1]*m[3],
|
|
}
|
|
<<else if eq $m 4>>
|
|
retMat := Mat4{
|
|
-m[7]*m[10]*m[13] + m[6]*m[11]*m[13] + m[7]*m[9]*m[14] - m[5]*m[11]*m[14] - m[6]*m[9]*m[15] + m[5]*m[10]*m[15],
|
|
m[3]*m[10]*m[13] - m[2]*m[11]*m[13] - m[3]*m[9]*m[14] + m[1]*m[11]*m[14] + m[2]*m[9]*m[15] - m[1]*m[10]*m[15],
|
|
-m[3]*m[6]*m[13] + m[2]*m[7]*m[13] + m[3]*m[5]*m[14] - m[1]*m[7]*m[14] - m[2]*m[5]*m[15] + m[1]*m[6]*m[15],
|
|
m[3]*m[6]*m[9] - m[2]*m[7]*m[9] - m[3]*m[5]*m[10] + m[1]*m[7]*m[10] + m[2]*m[5]*m[11] - m[1]*m[6]*m[11],
|
|
m[7]*m[10]*m[12] - m[6]*m[11]*m[12] - m[7]*m[8]*m[14] + m[4]*m[11]*m[14] + m[6]*m[8]*m[15] - m[4]*m[10]*m[15],
|
|
-m[3]*m[10]*m[12] + m[2]*m[11]*m[12] + m[3]*m[8]*m[14] - m[0]*m[11]*m[14] - m[2]*m[8]*m[15] + m[0]*m[10]*m[15],
|
|
m[3]*m[6]*m[12] - m[2]*m[7]*m[12] - m[3]*m[4]*m[14] + m[0]*m[7]*m[14] + m[2]*m[4]*m[15] - m[0]*m[6]*m[15],
|
|
-m[3]*m[6]*m[8] + m[2]*m[7]*m[8] + m[3]*m[4]*m[10] - m[0]*m[7]*m[10] - m[2]*m[4]*m[11] + m[0]*m[6]*m[11],
|
|
-m[7]*m[9]*m[12] + m[5]*m[11]*m[12] + m[7]*m[8]*m[13] - m[4]*m[11]*m[13] - m[5]*m[8]*m[15] + m[4]*m[9]*m[15],
|
|
m[3]*m[9]*m[12] - m[1]*m[11]*m[12] - m[3]*m[8]*m[13] + m[0]*m[11]*m[13] + m[1]*m[8]*m[15] - m[0]*m[9]*m[15],
|
|
-m[3]*m[5]*m[12] + m[1]*m[7]*m[12] + m[3]*m[4]*m[13] - m[0]*m[7]*m[13] - m[1]*m[4]*m[15] + m[0]*m[5]*m[15],
|
|
m[3]*m[5]*m[8] - m[1]*m[7]*m[8] - m[3]*m[4]*m[9] + m[0]*m[7]*m[9] + m[1]*m[4]*m[11] - m[0]*m[5]*m[11],
|
|
m[6]*m[9]*m[12] - m[5]*m[10]*m[12] - m[6]*m[8]*m[13] + m[4]*m[10]*m[13] + m[5]*m[8]*m[14] - m[4]*m[9]*m[14],
|
|
-m[2]*m[9]*m[12] + m[1]*m[10]*m[12] + m[2]*m[8]*m[13] - m[0]*m[10]*m[13] - m[1]*m[8]*m[14] + m[0]*m[9]*m[14],
|
|
m[2]*m[5]*m[12] - m[1]*m[6]*m[12] - m[2]*m[4]*m[13] + m[0]*m[6]*m[13] + m[1]*m[4]*m[14] - m[0]*m[5]*m[14],
|
|
-m[2]*m[5]*m[8] + m[1]*m[6]*m[8] + m[2]*m[4]*m[9] - m[0]*m[6]*m[9] - m[1]*m[4]*m[10] + m[0]*m[5]*m[10],
|
|
}
|
|
<<end>>
|
|
return retMat.Mul(1 / det)
|
|
}
|
|
<<end>>
|
|
|
|
// ApproxEqual performs an element-wise approximate equality test between two matrices,
|
|
// as if FloatEqual had been used.
|
|
func (m1 <<$type>>) ApproxEqual(m2 <<$type>>) bool {
|
|
for i := range m1 {
|
|
if !FloatEqual(m1[i], m2[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ApproxEqualThreshold performs an element-wise approximate equality test between two matrices
|
|
// with a given epsilon threshold, as if FloatEqualThreshold had been used.
|
|
func (m1 <<$type>>) ApproxEqualThreshold(m2 <<$type>>, threshold float32) bool {
|
|
for i := range m1 {
|
|
if !FloatEqualThreshold(m1[i], m2[i], threshold) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ApproxEqualFunc performs an element-wise approximate equality test between two matrices
|
|
// with a given equality functions, intended to be used with FloatEqualFunc; although and comparison
|
|
// function may be used in practice.
|
|
func (m1 <<$type>>) ApproxFuncEqual(m2 <<$type>>, eq func(float32, float32) bool) bool {
|
|
for i := range m1 {
|
|
if !eq(m1[i], m2[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// At returns the matrix element at the given row and column.
|
|
// This is equivalent to mat[col * numRow + row] where numRow is constant
|
|
// (E.G. for a Mat3x2 it's equal to 3)
|
|
//
|
|
// This method is garbage-in garbage-out. For instance, on a Mat4 asking for
|
|
// At(5,0) will work just like At(1,1). Or it may panic if it's out of bounds.
|
|
func (m <<$type>>) At(row, col int) float32 {
|
|
return m[col*<<$m>>+row]
|
|
}
|
|
|
|
// Set sets the corresponding matrix element at the given row and column.
|
|
// This has a pointer receiver because it mutates the matrix.
|
|
//
|
|
// This method is garbage-in garbage-out. For instance, on a Mat4 asking for
|
|
// Set(5,0,val) will work just like Set(1,1,val). Or it may panic if it's out of bounds.
|
|
func (m *<<$type>>) Set(row, col int, value float32) {
|
|
m[col*<<$m>>+row] = value
|
|
}
|
|
|
|
// Index returns the index of the given row and column, to be used with direct
|
|
// access. E.G. Index(0,0) = 0.
|
|
//
|
|
// This is a garbage-in garbage-out method. For instance, on a Mat4 asking for the index of
|
|
// (5,0) will work the same as asking for (1,1). Or it may give you a value that will cause
|
|
// a panic if you try to access the array with it if it's truly out of bounds.
|
|
func (m <<$type>>) Index(row, col int) int {
|
|
return col*<<$m>> + row
|
|
}
|
|
|
|
// Row returns a vector representing the corresponding row (starting at row 0).
|
|
// This package makes no distinction between row and column vectors, so it
|
|
// will be a normal VecM for a MxN matrix.
|
|
func (m <<$type>>) Row(row int) <<typename $n 1>> {
|
|
return <<typename $n 1>>{<<range $i := iter 0 $n>>m[row+<<mul $m $i>>],<<end>>}
|
|
}
|
|
|
|
// Rows decomposes a matrix into its corresponding row vectors.
|
|
// This is equivalent to calling mat.Row for each row.
|
|
func (m <<$type>>) Rows() (<<repeat $m "row%d" ",">> <<typename $n 1>>) {
|
|
return <<repeat $m "m.Row(%d)" ",">>
|
|
}
|
|
|
|
// Col returns a vector representing the corresponding column (starting at col 0).
|
|
// This package makes no distinction between row and column vectors, so it
|
|
// will be a normal VecN for a MxN matrix.
|
|
func (m <<$type>>) Col(col int) <<typename $m 1>> {
|
|
return <<typename $m 1>>{<<range $i := iter 0 $m>>m[col*<<$m>>+<<$i>>],<<end>>}
|
|
}
|
|
|
|
// Cols decomposes a matrix into its corresponding column vectors.
|
|
// This is equivalent to calling mat.Col for each column.
|
|
func (m <<$type>>) Cols() (<<repeat $n "col%d" ",">> <<typename $m 1>>) {
|
|
return <<repeat $n "m.Col(%d)" ",">>
|
|
}
|
|
|
|
<<if eq $m $n>>
|
|
// Trace is a basic operation on a square matrix that simply
|
|
// sums up all elements on the main diagonal (meaning all elements such that row==col).
|
|
func (m <<$type>>) Trace() float32 {
|
|
return <<range $i := iter 0 $m>><<sep "+" $i>> m[<<mul $i $m | add $i>>]<<end>>
|
|
}
|
|
<<end>>
|
|
|
|
// Abs returns the element-wise absolute value of this matrix
|
|
func (m <<$type>>) Abs() <<$type>> {
|
|
return <<$type>>{<<repeat (mul $m $n) "Abs(m[%d])" ",">>}
|
|
}
|
|
|
|
// Pretty prints the matrix
|
|
func (m <<$type>>) String() string {
|
|
buf := new(bytes.Buffer)
|
|
w := tabwriter.NewWriter(buf, 4, 4, 1, ' ', tabwriter.AlignRight)
|
|
for i := 0; i < <<$m>>; i++ {
|
|
for _, col := range m.Row(i) {
|
|
fmt.Fprintf(w, "%f\t", col)
|
|
}
|
|
|
|
fmt.Fprintln(w, "")
|
|
}
|
|
w.Flush()
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
<<end>><<end>> <</* range $m range $n */>>
|