Skip to content

Commit ecfef94

Browse files
authored
feat(matrix): added transformation reversal and rotation matrix helper
Matrix enhancements + Missing Dependency License
2 parents 5958961 + 0004d5e commit ecfef94

3 files changed

Lines changed: 160 additions & 0 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright 2015-2017 Daniel Nichter
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

pkg/MeshTypes/matrix.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package MeshTypes
22

3+
import "math"
4+
35
type Matrix struct {
46
X00, X01, X02, X03 float64
57
X10, X11, X12, X13 float64
@@ -59,3 +61,84 @@ func (a Matrix) MulDirection(b Vector) Vector {
5961
z := a.X20*b.X + a.X21*b.Y + a.X22*b.Z
6062
return Vector{x, y, z}.Normalize()
6163
}
64+
65+
func GenerateRotationMatrix(alpha float64, beta float64, gamma float64) Matrix {
66+
alphaSin := math.Sin(alpha / 180 * math.Pi)
67+
alphaCos := math.Cos(alpha / 180 * math.Pi)
68+
betaSin := math.Sin(beta / 180 * math.Pi)
69+
betaCos := math.Cos(beta / 180 * math.Pi)
70+
gammaSin := math.Sin(gamma / 180 * math.Pi)
71+
gammaCos := math.Cos(gamma / 180 * math.Pi)
72+
73+
return Matrix{
74+
X00: betaCos * gammaCos, X01: -betaCos * gammaSin, X02: betaSin, X03: 0,
75+
X10: alphaCos*gammaSin + alphaSin*betaSin*gammaCos, X11: alphaCos*gammaCos - alphaSin*betaSin*gammaSin, X12: -alphaSin * betaCos, X13: 0,
76+
X20: alphaSin*gammaSin - alphaCos*betaSin*gammaCos, X21: alphaSin*gammaCos + alphaCos*betaSin*gammaSin, X22: alphaCos * betaCos, X23: 0,
77+
X30: 0, X31: 0, X32: 0, X33: 1,
78+
}
79+
}
80+
81+
func (a Matrix) Rotate(alpha float64, beta float64, gamma float64) Matrix {
82+
return a.Mul(GenerateRotationMatrix(alpha, beta, gamma))
83+
}
84+
85+
func (a Matrix) ReverseTransformation(previousRotationMatrix Matrix) Matrix {
86+
inv := Matrix{
87+
X00: previousRotationMatrix.X00, X01: previousRotationMatrix.X10, X02: previousRotationMatrix.X20, X03: 0,
88+
X10: previousRotationMatrix.X01, X11: previousRotationMatrix.X11, X12: previousRotationMatrix.X21, X13: 0,
89+
X20: previousRotationMatrix.X02, X21: previousRotationMatrix.X12, X22: previousRotationMatrix.X22, X23: 0,
90+
X30: 0, X31: 0, X32: 0, X33: 1,
91+
}
92+
93+
inv.X03 = -(inv.X00*previousRotationMatrix.X03 + inv.X01*previousRotationMatrix.X13 + inv.X02*previousRotationMatrix.X23)
94+
inv.X13 = -(inv.X10*previousRotationMatrix.X03 + inv.X11*previousRotationMatrix.X13 + inv.X12*previousRotationMatrix.X23)
95+
inv.X23 = -(inv.X20*previousRotationMatrix.X03 + inv.X21*previousRotationMatrix.X13 + inv.X22*previousRotationMatrix.X23)
96+
97+
return a.Mul(inv)
98+
}
99+
100+
func (a Matrix) Transpose() Matrix {
101+
return Matrix{
102+
a.X00, a.X10, a.X20, a.X30,
103+
a.X01, a.X11, a.X21, a.X31,
104+
a.X02, a.X12, a.X22, a.X32,
105+
a.X03, a.X13, a.X23, a.X33,
106+
}
107+
}
108+
109+
func (a Matrix) Determinant() float64 {
110+
return (a.X00*a.X11*a.X22*a.X33 - a.X00*a.X11*a.X23*a.X32 +
111+
a.X00*a.X12*a.X23*a.X31 - a.X00*a.X12*a.X21*a.X33 +
112+
a.X00*a.X13*a.X21*a.X32 - a.X00*a.X13*a.X22*a.X31 -
113+
a.X01*a.X12*a.X23*a.X30 + a.X01*a.X12*a.X20*a.X33 -
114+
a.X01*a.X13*a.X20*a.X32 + a.X01*a.X13*a.X22*a.X30 -
115+
a.X01*a.X10*a.X22*a.X33 + a.X01*a.X10*a.X23*a.X32 +
116+
a.X02*a.X13*a.X20*a.X31 - a.X02*a.X13*a.X21*a.X30 +
117+
a.X02*a.X10*a.X21*a.X33 - a.X02*a.X10*a.X23*a.X31 +
118+
a.X02*a.X11*a.X23*a.X30 - a.X02*a.X11*a.X20*a.X33 -
119+
a.X03*a.X10*a.X21*a.X32 + a.X03*a.X10*a.X22*a.X31 -
120+
a.X03*a.X11*a.X22*a.X30 + a.X03*a.X11*a.X20*a.X32 -
121+
a.X03*a.X12*a.X20*a.X31 + a.X03*a.X12*a.X21*a.X30)
122+
}
123+
124+
func (a Matrix) Inverse() Matrix {
125+
m := Matrix{}
126+
d := a.Determinant()
127+
m.X00 = (a.X12*a.X23*a.X31 - a.X13*a.X22*a.X31 + a.X13*a.X21*a.X32 - a.X11*a.X23*a.X32 - a.X12*a.X21*a.X33 + a.X11*a.X22*a.X33) / d
128+
m.X01 = (a.X03*a.X22*a.X31 - a.X02*a.X23*a.X31 - a.X03*a.X21*a.X32 + a.X01*a.X23*a.X32 + a.X02*a.X21*a.X33 - a.X01*a.X22*a.X33) / d
129+
m.X02 = (a.X02*a.X13*a.X31 - a.X03*a.X12*a.X31 + a.X03*a.X11*a.X32 - a.X01*a.X13*a.X32 - a.X02*a.X11*a.X33 + a.X01*a.X12*a.X33) / d
130+
m.X03 = (a.X03*a.X12*a.X21 - a.X02*a.X13*a.X21 - a.X03*a.X11*a.X22 + a.X01*a.X13*a.X22 + a.X02*a.X11*a.X23 - a.X01*a.X12*a.X23) / d
131+
m.X10 = (a.X13*a.X22*a.X30 - a.X12*a.X23*a.X30 - a.X13*a.X20*a.X32 + a.X10*a.X23*a.X32 + a.X12*a.X20*a.X33 - a.X10*a.X22*a.X33) / d
132+
m.X11 = (a.X02*a.X23*a.X30 - a.X03*a.X22*a.X30 + a.X03*a.X20*a.X32 - a.X00*a.X23*a.X32 - a.X02*a.X20*a.X33 + a.X00*a.X22*a.X33) / d
133+
m.X12 = (a.X03*a.X12*a.X30 - a.X02*a.X13*a.X30 - a.X03*a.X10*a.X32 + a.X00*a.X13*a.X32 + a.X02*a.X10*a.X33 - a.X00*a.X12*a.X33) / d
134+
m.X13 = (a.X02*a.X13*a.X20 - a.X03*a.X12*a.X20 + a.X03*a.X10*a.X22 - a.X00*a.X13*a.X22 - a.X02*a.X10*a.X23 + a.X00*a.X12*a.X23) / d
135+
m.X20 = (a.X11*a.X23*a.X30 - a.X13*a.X21*a.X30 + a.X13*a.X20*a.X31 - a.X10*a.X23*a.X31 - a.X11*a.X20*a.X33 + a.X10*a.X21*a.X33) / d
136+
m.X21 = (a.X03*a.X21*a.X30 - a.X01*a.X23*a.X30 - a.X03*a.X20*a.X31 + a.X00*a.X23*a.X31 + a.X01*a.X20*a.X33 - a.X00*a.X21*a.X33) / d
137+
m.X22 = (a.X01*a.X13*a.X30 - a.X03*a.X11*a.X30 + a.X03*a.X10*a.X31 - a.X00*a.X13*a.X31 - a.X01*a.X10*a.X33 + a.X00*a.X11*a.X33) / d
138+
m.X23 = (a.X03*a.X11*a.X20 - a.X01*a.X13*a.X20 - a.X03*a.X10*a.X21 + a.X00*a.X13*a.X21 + a.X01*a.X10*a.X23 - a.X00*a.X11*a.X23) / d
139+
m.X30 = (a.X12*a.X21*a.X30 - a.X11*a.X22*a.X30 - a.X12*a.X20*a.X31 + a.X10*a.X22*a.X31 + a.X11*a.X20*a.X32 - a.X10*a.X21*a.X32) / d
140+
m.X31 = (a.X01*a.X22*a.X30 - a.X02*a.X21*a.X30 + a.X02*a.X20*a.X31 - a.X00*a.X22*a.X31 - a.X01*a.X20*a.X32 + a.X00*a.X21*a.X32) / d
141+
m.X32 = (a.X02*a.X11*a.X30 - a.X01*a.X12*a.X30 - a.X02*a.X10*a.X31 + a.X00*a.X12*a.X31 + a.X01*a.X10*a.X32 - a.X00*a.X11*a.X32) / d
142+
m.X33 = (a.X01*a.X12*a.X20 - a.X02*a.X11*a.X20 + a.X02*a.X10*a.X21 - a.X00*a.X12*a.X21 - a.X01*a.X10*a.X22 + a.X00*a.X11*a.X22) / d
143+
return m
144+
}

tests/MeshTypes/matrix_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
package MeshTypes_Test
22

33
import (
4+
"math"
5+
"math/rand"
46
"reflect"
57
"testing"
68

79
"github.com/Patch2PDF/GDTF-Mesh-Reader/v2/pkg/MeshTypes"
810
)
911

12+
func MatrixEquals(a MeshTypes.Matrix, b MeshTypes.Matrix) bool {
13+
// Helper to check individual floats
14+
isClose := func(a, b float64) bool {
15+
return math.Abs(a-b) < 0.000000000000001
16+
}
17+
18+
return isClose(a.X00, b.X00) && isClose(a.X01, b.X01) &&
19+
isClose(a.X02, b.X02) && isClose(a.X03, b.X03) &&
20+
isClose(a.X10, b.X10) && isClose(a.X11, b.X11) &&
21+
isClose(a.X12, b.X12) && isClose(a.X13, b.X13) &&
22+
isClose(a.X20, b.X20) && isClose(a.X21, b.X21) &&
23+
isClose(a.X22, b.X22) && isClose(a.X23, b.X23) &&
24+
isClose(a.X30, b.X30) && isClose(a.X31, b.X31) &&
25+
isClose(a.X32, b.X32) && isClose(a.X33, b.X33)
26+
}
27+
1028
func TestIdentityMatrix(t *testing.T) {
1129
want := MeshTypes.Matrix{
1230
X00: 1, X01: 0, X02: 0, X03: 0,
@@ -84,3 +102,41 @@ func TestMulPosition(t *testing.T) {
84102
t.Errorf(`Matrix Vector Multiplication Output does not match`)
85103
}
86104
}
105+
106+
func TestRotation(t *testing.T) {
107+
a := MeshTypes.Matrix{
108+
X00: rand.Float64(), X01: rand.Float64(), X02: rand.Float64(), X03: rand.Float64(),
109+
X10: rand.Float64(), X11: rand.Float64(), X12: rand.Float64(), X13: rand.Float64(),
110+
X20: rand.Float64(), X21: rand.Float64(), X22: rand.Float64(), X23: rand.Float64(),
111+
X30: 0, X31: 0, X32: 0, X33: 1,
112+
}
113+
114+
alpha := rand.Float64()
115+
beta := rand.Float64()
116+
gamma := rand.Float64()
117+
118+
rotation := MeshTypes.GenerateRotationMatrix(alpha, beta, gamma)
119+
120+
if !reflect.DeepEqual(a.Mul(rotation), a.Rotate(alpha, beta, gamma)) {
121+
t.Errorf(`Matrix Vector Rotation Output does not match`)
122+
}
123+
}
124+
125+
func TestMatrixRotationReversal(t *testing.T) {
126+
a := MeshTypes.Matrix{
127+
X00: rand.Float64(), X01: rand.Float64(), X02: rand.Float64(), X03: rand.Float64(),
128+
X10: rand.Float64(), X11: rand.Float64(), X12: rand.Float64(), X13: rand.Float64(),
129+
X20: rand.Float64(), X21: rand.Float64(), X22: rand.Float64(), X23: rand.Float64(),
130+
X30: 0, X31: 0, X32: 0, X33: 1,
131+
}
132+
133+
rotation := MeshTypes.GenerateRotationMatrix(rand.Float64(), rand.Float64(), rand.Float64())
134+
135+
rotated := a.Mul(rotation)
136+
137+
back_rotated := rotated.ReverseTransformation(rotation)
138+
139+
if !MatrixEquals(a, back_rotated) {
140+
t.Errorf(`Matrix Vector Rotation Reversal Output does not match`)
141+
}
142+
}

0 commit comments

Comments
 (0)