diff --git a/Licenses/github.com/go-test/deep/LICENSE b/Licenses/github.com/go-test/deep/LICENSE new file mode 100644 index 0000000..228ef16 --- /dev/null +++ b/Licenses/github.com/go-test/deep/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright 2015-2017 Daniel Nichter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pkg/MeshTypes/matrix.go b/pkg/MeshTypes/matrix.go index 67c64ba..fefd694 100644 --- a/pkg/MeshTypes/matrix.go +++ b/pkg/MeshTypes/matrix.go @@ -1,5 +1,7 @@ package MeshTypes +import "math" + type Matrix struct { X00, X01, X02, X03 float64 X10, X11, X12, X13 float64 @@ -59,3 +61,84 @@ func (a Matrix) MulDirection(b Vector) Vector { z := a.X20*b.X + a.X21*b.Y + a.X22*b.Z return Vector{x, y, z}.Normalize() } + +func GenerateRotationMatrix(alpha float64, beta float64, gamma float64) Matrix { + alphaSin := math.Sin(alpha / 180 * math.Pi) + alphaCos := math.Cos(alpha / 180 * math.Pi) + betaSin := math.Sin(beta / 180 * math.Pi) + betaCos := math.Cos(beta / 180 * math.Pi) + gammaSin := math.Sin(gamma / 180 * math.Pi) + gammaCos := math.Cos(gamma / 180 * math.Pi) + + return Matrix{ + X00: betaCos * gammaCos, X01: -betaCos * gammaSin, X02: betaSin, X03: 0, + X10: alphaCos*gammaSin + alphaSin*betaSin*gammaCos, X11: alphaCos*gammaCos - alphaSin*betaSin*gammaSin, X12: -alphaSin * betaCos, X13: 0, + X20: alphaSin*gammaSin - alphaCos*betaSin*gammaCos, X21: alphaSin*gammaCos + alphaCos*betaSin*gammaSin, X22: alphaCos * betaCos, X23: 0, + X30: 0, X31: 0, X32: 0, X33: 1, + } +} + +func (a Matrix) Rotate(alpha float64, beta float64, gamma float64) Matrix { + return a.Mul(GenerateRotationMatrix(alpha, beta, gamma)) +} + +func (a Matrix) ReverseTransformation(previousRotationMatrix Matrix) Matrix { + inv := Matrix{ + X00: previousRotationMatrix.X00, X01: previousRotationMatrix.X10, X02: previousRotationMatrix.X20, X03: 0, + X10: previousRotationMatrix.X01, X11: previousRotationMatrix.X11, X12: previousRotationMatrix.X21, X13: 0, + X20: previousRotationMatrix.X02, X21: previousRotationMatrix.X12, X22: previousRotationMatrix.X22, X23: 0, + X30: 0, X31: 0, X32: 0, X33: 1, + } + + inv.X03 = -(inv.X00*previousRotationMatrix.X03 + inv.X01*previousRotationMatrix.X13 + inv.X02*previousRotationMatrix.X23) + inv.X13 = -(inv.X10*previousRotationMatrix.X03 + inv.X11*previousRotationMatrix.X13 + inv.X12*previousRotationMatrix.X23) + inv.X23 = -(inv.X20*previousRotationMatrix.X03 + inv.X21*previousRotationMatrix.X13 + inv.X22*previousRotationMatrix.X23) + + return a.Mul(inv) +} + +func (a Matrix) Transpose() Matrix { + return Matrix{ + a.X00, a.X10, a.X20, a.X30, + a.X01, a.X11, a.X21, a.X31, + a.X02, a.X12, a.X22, a.X32, + a.X03, a.X13, a.X23, a.X33, + } +} + +func (a Matrix) Determinant() float64 { + return (a.X00*a.X11*a.X22*a.X33 - a.X00*a.X11*a.X23*a.X32 + + a.X00*a.X12*a.X23*a.X31 - a.X00*a.X12*a.X21*a.X33 + + a.X00*a.X13*a.X21*a.X32 - a.X00*a.X13*a.X22*a.X31 - + a.X01*a.X12*a.X23*a.X30 + a.X01*a.X12*a.X20*a.X33 - + a.X01*a.X13*a.X20*a.X32 + a.X01*a.X13*a.X22*a.X30 - + a.X01*a.X10*a.X22*a.X33 + a.X01*a.X10*a.X23*a.X32 + + a.X02*a.X13*a.X20*a.X31 - a.X02*a.X13*a.X21*a.X30 + + a.X02*a.X10*a.X21*a.X33 - a.X02*a.X10*a.X23*a.X31 + + a.X02*a.X11*a.X23*a.X30 - a.X02*a.X11*a.X20*a.X33 - + a.X03*a.X10*a.X21*a.X32 + a.X03*a.X10*a.X22*a.X31 - + a.X03*a.X11*a.X22*a.X30 + a.X03*a.X11*a.X20*a.X32 - + a.X03*a.X12*a.X20*a.X31 + a.X03*a.X12*a.X21*a.X30) +} + +func (a Matrix) Inverse() Matrix { + m := Matrix{} + d := a.Determinant() + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + return m +} diff --git a/tests/MeshTypes/matrix_test.go b/tests/MeshTypes/matrix_test.go index 156a2ca..c91e0fe 100644 --- a/tests/MeshTypes/matrix_test.go +++ b/tests/MeshTypes/matrix_test.go @@ -1,12 +1,30 @@ package MeshTypes_Test import ( + "math" + "math/rand" "reflect" "testing" "github.com/Patch2PDF/GDTF-Mesh-Reader/v2/pkg/MeshTypes" ) +func MatrixEquals(a MeshTypes.Matrix, b MeshTypes.Matrix) bool { + // Helper to check individual floats + isClose := func(a, b float64) bool { + return math.Abs(a-b) < 0.000000000000001 + } + + return isClose(a.X00, b.X00) && isClose(a.X01, b.X01) && + isClose(a.X02, b.X02) && isClose(a.X03, b.X03) && + isClose(a.X10, b.X10) && isClose(a.X11, b.X11) && + isClose(a.X12, b.X12) && isClose(a.X13, b.X13) && + isClose(a.X20, b.X20) && isClose(a.X21, b.X21) && + isClose(a.X22, b.X22) && isClose(a.X23, b.X23) && + isClose(a.X30, b.X30) && isClose(a.X31, b.X31) && + isClose(a.X32, b.X32) && isClose(a.X33, b.X33) +} + func TestIdentityMatrix(t *testing.T) { want := MeshTypes.Matrix{ X00: 1, X01: 0, X02: 0, X03: 0, @@ -84,3 +102,41 @@ func TestMulPosition(t *testing.T) { t.Errorf(`Matrix Vector Multiplication Output does not match`) } } + +func TestRotation(t *testing.T) { + a := MeshTypes.Matrix{ + X00: rand.Float64(), X01: rand.Float64(), X02: rand.Float64(), X03: rand.Float64(), + X10: rand.Float64(), X11: rand.Float64(), X12: rand.Float64(), X13: rand.Float64(), + X20: rand.Float64(), X21: rand.Float64(), X22: rand.Float64(), X23: rand.Float64(), + X30: 0, X31: 0, X32: 0, X33: 1, + } + + alpha := rand.Float64() + beta := rand.Float64() + gamma := rand.Float64() + + rotation := MeshTypes.GenerateRotationMatrix(alpha, beta, gamma) + + if !reflect.DeepEqual(a.Mul(rotation), a.Rotate(alpha, beta, gamma)) { + t.Errorf(`Matrix Vector Rotation Output does not match`) + } +} + +func TestMatrixRotationReversal(t *testing.T) { + a := MeshTypes.Matrix{ + X00: rand.Float64(), X01: rand.Float64(), X02: rand.Float64(), X03: rand.Float64(), + X10: rand.Float64(), X11: rand.Float64(), X12: rand.Float64(), X13: rand.Float64(), + X20: rand.Float64(), X21: rand.Float64(), X22: rand.Float64(), X23: rand.Float64(), + X30: 0, X31: 0, X32: 0, X33: 1, + } + + rotation := MeshTypes.GenerateRotationMatrix(rand.Float64(), rand.Float64(), rand.Float64()) + + rotated := a.Mul(rotation) + + back_rotated := rotated.ReverseTransformation(rotation) + + if !MatrixEquals(a, back_rotated) { + t.Errorf(`Matrix Vector Rotation Reversal Output does not match`) + } +}