mirror of
https://github.com/bloeys/gglm.git
synced 2025-12-29 05:28:20 +00:00
Mat2 and Mat3 determinant and inverse matrices
This commit is contained in:
22
gglm/mat2.go
22
gglm/mat2.go
@ -84,7 +84,6 @@ func (m *Mat2) Eq(m2 *Mat2) bool {
|
||||
}
|
||||
|
||||
func (m *Mat2) Transpose() *Mat2 {
|
||||
|
||||
m.Data = [2][2]float32{
|
||||
{m.Data[0][0], m.Data[1][0]},
|
||||
{m.Data[0][1], m.Data[1][1]},
|
||||
@ -93,6 +92,27 @@ func (m *Mat2) Transpose() *Mat2 {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Mat2) Determinant() float32 {
|
||||
return (m.Data[0][0] * m.Data[1][1]) - (m.Data[0][1] * m.Data[1][0])
|
||||
}
|
||||
|
||||
// Invert inverts this matrix.
|
||||
//
|
||||
// Note that the inverse is not defined if the determinant is zero or extremely small.
|
||||
// In the case the determinant is zero the matrix will (usually) get filled with infinities
|
||||
func (m *Mat2) Invert() *Mat2 {
|
||||
|
||||
// https://www.cuemath.com/algebra/inverse-of-2x2-matrix/
|
||||
inverseDet := 1 / m.Determinant()
|
||||
|
||||
m.Data = [2][2]float32{
|
||||
{m.Data[1][1] * inverseDet, -m.Data[0][1] * inverseDet}, // Col0
|
||||
{-m.Data[1][0] * inverseDet, m.Data[0][0] * inverseDet}, // Col1
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// AddMat2 m3 = m1 + m2
|
||||
func AddMat2(m1, m2 *Mat2) *Mat2 {
|
||||
return &Mat2{
|
||||
|
||||
@ -179,6 +179,56 @@ func TestTransposeMat2(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterminantMat2(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat2Id()
|
||||
ans := float32(1)
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
|
||||
m = &gglm.Mat2{
|
||||
Data: [2][2]float32{
|
||||
{1, 8},
|
||||
{5, 31},
|
||||
},
|
||||
}
|
||||
ans = -9
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInverseMat2(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat2Id()
|
||||
ans := gglm.NewMat2Id()
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
|
||||
m = &gglm.Mat2{
|
||||
Data: [2][2]float32{
|
||||
{1, 8},
|
||||
{5, 31},
|
||||
},
|
||||
}
|
||||
|
||||
ans = &gglm.Mat2{
|
||||
Data: [2][2]float32{
|
||||
{-31 / 9.0, 8 / 9.0},
|
||||
{5 / 9.0, -1 / 9.0},
|
||||
},
|
||||
}
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat2(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat2Id()
|
||||
|
||||
58
gglm/mat3.go
58
gglm/mat3.go
@ -145,6 +145,64 @@ func (m *Mat3) Transpose() *Mat3 {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Mat3) Determinant() float32 {
|
||||
x := m.Data[0][0] * (m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2])
|
||||
y := m.Data[1][0] * (m.Data[2][1]*m.Data[0][2] - m.Data[0][1]*m.Data[2][2])
|
||||
z := m.Data[2][0] * (m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2])
|
||||
return x + y + z
|
||||
}
|
||||
|
||||
// Invert inverts this matrix.
|
||||
//
|
||||
// Note that the inverse is not defined if the determinant is zero or extremely small.
|
||||
// In the case the determinant is zero the matrix will (usually) get filled with infinities
|
||||
func (m *Mat3) Invert() *Mat3 {
|
||||
|
||||
// https://www.cuemath.com/algebra/inverse-of-3x3-matrix/
|
||||
|
||||
// Manually inline the determinant function because go doesn't
|
||||
x := m.Data[0][0] * (m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2])
|
||||
y := m.Data[1][0] * (m.Data[2][1]*m.Data[0][2] - m.Data[0][1]*m.Data[2][2])
|
||||
z := m.Data[2][0] * (m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2])
|
||||
|
||||
inverseDet := 1 / (x + y + z)
|
||||
|
||||
// Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;
|
||||
// Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;
|
||||
// Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;
|
||||
// Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;
|
||||
// Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;
|
||||
// Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;
|
||||
// Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;
|
||||
// Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;
|
||||
// Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;
|
||||
|
||||
m.Data = [3][3]float32{
|
||||
// Col0
|
||||
{
|
||||
(m.Data[1][1]*m.Data[2][2] - m.Data[2][1]*m.Data[1][2]) * inverseDet,
|
||||
-(m.Data[0][1]*m.Data[2][2] - m.Data[2][1]*m.Data[0][2]) * inverseDet,
|
||||
(m.Data[0][1]*m.Data[1][2] - m.Data[1][1]*m.Data[0][2]) * inverseDet,
|
||||
},
|
||||
|
||||
// Col1
|
||||
{
|
||||
-(m.Data[1][0]*m.Data[2][2] - m.Data[2][0]*m.Data[1][2]) * inverseDet,
|
||||
(m.Data[0][0]*m.Data[2][2] - m.Data[2][0]*m.Data[0][2]) * inverseDet,
|
||||
-(m.Data[0][0]*m.Data[1][2] - m.Data[1][0]*m.Data[0][2]) * inverseDet,
|
||||
},
|
||||
|
||||
// Col2
|
||||
{
|
||||
(m.Data[1][0]*m.Data[2][1] - m.Data[2][0]*m.Data[1][1]) * inverseDet,
|
||||
-(m.Data[0][0]*m.Data[2][1] - m.Data[2][0]*m.Data[0][1]) * inverseDet,
|
||||
(m.Data[0][0]*m.Data[1][1] - m.Data[1][0]*m.Data[0][1]) * inverseDet,
|
||||
},
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// AddMat3 m3 = m1 + m2
|
||||
func AddMat3(m1, m2 *Mat3) *Mat3 {
|
||||
return &Mat3{
|
||||
|
||||
@ -196,6 +196,59 @@ func TestTransposeMat3(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeterminantMat3(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat3Id()
|
||||
ans := float32(1)
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
|
||||
m = &gglm.Mat3{
|
||||
Data: [3][3]float32{
|
||||
{1, 8, 2},
|
||||
{5, 3, 5},
|
||||
{9, 6, 7},
|
||||
},
|
||||
}
|
||||
ans = 77
|
||||
|
||||
if m.Determinant() != ans {
|
||||
t.Errorf("Got: %f; Expected: %f", m.Determinant(), ans)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInverseMat3(t *testing.T) {
|
||||
|
||||
m := gglm.NewMat3Id()
|
||||
ans := gglm.NewMat3Id()
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
|
||||
m = &gglm.Mat3{
|
||||
Data: [3][3]float32{
|
||||
{1, 8, 2},
|
||||
{5, 3, 5},
|
||||
{9, 6, 7},
|
||||
},
|
||||
}
|
||||
|
||||
ans = &gglm.Mat3{
|
||||
Data: [3][3]float32{
|
||||
{-9 / 77.0, -4 / 7.0, 34 / 77.0},
|
||||
{10 / 77.0, -1 / 7.0, 5 / 77.0},
|
||||
{3 / 77.0, 6 / 7.0, -37 / 77.0},
|
||||
},
|
||||
}
|
||||
|
||||
if !m.Invert().Eq(ans) {
|
||||
t.Errorf("Got: %v; Expected: %v", m.String(), ans.String())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMulMat3(b *testing.B) {
|
||||
|
||||
m1 := gglm.NewMat3Id()
|
||||
|
||||
Reference in New Issue
Block a user