github.com/gopherd/gonum@v0.0.4/spatial/r3/mat.go (about) 1 // Copyright ©2021 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package r3 6 7 import "github.com/gopherd/gonum/mat" 8 9 // Mat represents a 3×3 matrix. Useful for rotation matrices and such. 10 // The zero value is usable as the 3×3 zero matrix. 11 type Mat struct { 12 data *array 13 } 14 15 var _ mat.Matrix = (*Mat)(nil) 16 17 // NewMat returns a new 3×3 matrix Mat type and populates its elements 18 // with values passed as argument in row-major form. If val argument 19 // is nil then NewMat returns a matrix filled with zeros. 20 func NewMat(val []float64) *Mat { 21 if len(val) == 9 { 22 return &Mat{arrayFrom(val)} 23 } 24 if val == nil { 25 return &Mat{new(array)} 26 } 27 panic(mat.ErrShape) 28 } 29 30 // Dims returns the number of rows and columns of this matrix. 31 // This method will always return 3×3 for a Mat. 32 func (m *Mat) Dims() (r, c int) { return 3, 3 } 33 34 // T returns the transpose of Mat. Changes in the receiver will be reflected in the returned matrix. 35 func (m *Mat) T() mat.Matrix { return mat.Transpose{Matrix: m} } 36 37 // Scale multiplies the elements of a by f, placing the result in the receiver. 38 // 39 // See the mat.Scaler interface for more information. 40 func (m *Mat) Scale(f float64, a mat.Matrix) { 41 r, c := a.Dims() 42 if r != 3 || c != 3 { 43 panic(mat.ErrShape) 44 } 45 if m.data == nil { 46 m.data = new(array) 47 } 48 for i := 0; i < 3; i++ { 49 for j := 0; j < 3; j++ { 50 m.Set(i, j, f*a.At(i, j)) 51 } 52 } 53 } 54 55 // MulVec returns the matrix-vector product M⋅v. 56 func (m *Mat) MulVec(v Vec) Vec { 57 if m.data == nil { 58 return Vec{} 59 } 60 return Vec{ 61 X: v.X*m.At(0, 0) + v.Y*m.At(0, 1) + v.Z*m.At(0, 2), 62 Y: v.X*m.At(1, 0) + v.Y*m.At(1, 1) + v.Z*m.At(1, 2), 63 Z: v.X*m.At(2, 0) + v.Y*m.At(2, 1) + v.Z*m.At(2, 2), 64 } 65 } 66 67 // MulVecTrans returns the matrix-vector product Mᵀ⋅v. 68 func (m *Mat) MulVecTrans(v Vec) Vec { 69 if m.data == nil { 70 return Vec{} 71 } 72 return Vec{ 73 X: v.X*m.At(0, 0) + v.Y*m.At(1, 0) + v.Z*m.At(2, 0), 74 Y: v.X*m.At(0, 1) + v.Y*m.At(1, 1) + v.Z*m.At(2, 1), 75 Z: v.X*m.At(0, 2) + v.Y*m.At(1, 2) + v.Z*m.At(2, 2), 76 } 77 } 78 79 // CloneFrom makes a copy of a into the receiver m. 80 // Mat expects a 3×3 input matrix. 81 func (m *Mat) CloneFrom(a mat.Matrix) { 82 r, c := a.Dims() 83 if r != 3 || c != 3 { 84 panic(mat.ErrShape) 85 } 86 if m.data == nil { 87 m.data = new(array) 88 } 89 for i := 0; i < 3; i++ { 90 for j := 0; j < 3; j++ { 91 m.Set(i, j, a.At(i, j)) 92 } 93 } 94 } 95 96 // Sub subtracts the matrix b from a, placing the result in the receiver. 97 // Sub will panic if the two matrices do not have the same shape. 98 func (m *Mat) Sub(a, b mat.Matrix) { 99 if r, c := a.Dims(); r != 3 || c != 3 { 100 panic(mat.ErrShape) 101 } 102 if r, c := b.Dims(); r != 3 || c != 3 { 103 panic(mat.ErrShape) 104 } 105 if m.data == nil { 106 m.data = new(array) 107 } 108 109 m.Set(0, 0, a.At(0, 0)-b.At(0, 0)) 110 m.Set(0, 1, a.At(0, 1)-b.At(0, 1)) 111 m.Set(0, 2, a.At(0, 2)-b.At(0, 2)) 112 m.Set(1, 0, a.At(1, 0)-b.At(1, 0)) 113 m.Set(1, 1, a.At(1, 1)-b.At(1, 1)) 114 m.Set(1, 2, a.At(1, 2)-b.At(1, 2)) 115 m.Set(2, 0, a.At(2, 0)-b.At(2, 0)) 116 m.Set(2, 1, a.At(2, 1)-b.At(2, 1)) 117 m.Set(2, 2, a.At(2, 2)-b.At(2, 2)) 118 } 119 120 // Add adds a and b element-wise, placing the result in the receiver. Add will panic if the two matrices do not have the same shape. 121 func (m *Mat) Add(a, b mat.Matrix) { 122 if r, c := a.Dims(); r != 3 || c != 3 { 123 panic(mat.ErrShape) 124 } 125 if r, c := b.Dims(); r != 3 || c != 3 { 126 panic(mat.ErrShape) 127 } 128 if m.data == nil { 129 m.data = new(array) 130 } 131 132 m.Set(0, 0, a.At(0, 0)+b.At(0, 0)) 133 m.Set(0, 1, a.At(0, 1)+b.At(0, 1)) 134 m.Set(0, 2, a.At(0, 2)+b.At(0, 2)) 135 m.Set(1, 0, a.At(1, 0)+b.At(1, 0)) 136 m.Set(1, 1, a.At(1, 1)+b.At(1, 1)) 137 m.Set(1, 2, a.At(1, 2)+b.At(1, 2)) 138 m.Set(2, 0, a.At(2, 0)+b.At(2, 0)) 139 m.Set(2, 1, a.At(2, 1)+b.At(2, 1)) 140 m.Set(2, 2, a.At(2, 2)+b.At(2, 2)) 141 } 142 143 // VecRow returns the elements in the ith row of the receiver. 144 func (m *Mat) VecRow(i int) Vec { 145 if i > 2 { 146 panic(mat.ErrRowAccess) 147 } 148 if m.data == nil { 149 return Vec{} 150 } 151 return Vec{X: m.At(i, 0), Y: m.At(i, 1), Z: m.At(i, 2)} 152 } 153 154 // VecCol returns the elements in the jth column of the receiver. 155 func (m *Mat) VecCol(j int) Vec { 156 if j > 2 { 157 panic(mat.ErrColAccess) 158 } 159 if m.data == nil { 160 return Vec{} 161 } 162 return Vec{X: m.At(0, j), Y: m.At(1, j), Z: m.At(2, j)} 163 } 164 165 // Outer calculates the outer product of the vectors x and y, 166 // where x and y are treated as column vectors, and stores the result in the receiver. 167 // m = alpha * x * yᵀ 168 func (m *Mat) Outer(alpha float64, x, y Vec) { 169 ax := alpha * x.X 170 ay := alpha * x.Y 171 az := alpha * x.Z 172 m.Set(0, 0, ax*y.X) 173 m.Set(0, 1, ax*y.Y) 174 m.Set(0, 2, ax*y.Z) 175 176 m.Set(1, 0, ay*y.X) 177 m.Set(1, 1, ay*y.Y) 178 m.Set(1, 2, ay*y.Z) 179 180 m.Set(2, 0, az*y.X) 181 m.Set(2, 1, az*y.Y) 182 m.Set(2, 2, az*y.Z) 183 } 184 185 // Det calculates the determinant of the receiver using the following formula 186 // ⎡a b c⎤ 187 // m = ⎢d e f⎥ 188 // ⎣g h i⎦ 189 // det(m) = a(ei − fh) − b(di − fg) + c(dh − eg) 190 func (m *Mat) Det() float64 { 191 a := m.At(0, 0) 192 b := m.At(0, 1) 193 c := m.At(0, 2) 194 195 deta := m.At(1, 1)*m.At(2, 2) - m.At(1, 2)*m.At(2, 1) 196 detb := m.At(1, 0)*m.At(2, 2) - m.At(1, 2)*m.At(2, 0) 197 detc := m.At(1, 0)*m.At(2, 1) - m.At(1, 1)*m.At(2, 0) 198 return a*deta - b*detb + c*detc 199 }