mirror of
https://github.com/gonum/gonum.git
synced 2025-10-08 16:40:06 +08:00
200 lines
5.1 KiB
Go
200 lines
5.1 KiB
Go
// Copyright ©2021 The Gonum Authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
package r3
|
||
|
||
import "gonum.org/v1/gonum/mat"
|
||
|
||
// Mat represents a 3×3 matrix. Useful for rotation matrices and such.
|
||
// The zero value is usable as the 3×3 zero matrix.
|
||
type Mat struct {
|
||
data *array
|
||
}
|
||
|
||
var _ mat.Matrix = (*Mat)(nil)
|
||
|
||
// NewMat returns a new 3×3 matrix Mat type and populates its elements
|
||
// with values passed as argument in row-major form. If val argument
|
||
// is nil then NewMat returns a matrix filled with zeros.
|
||
func NewMat(val []float64) *Mat {
|
||
if len(val) == 9 {
|
||
return &Mat{arrayFrom(val)}
|
||
}
|
||
if val == nil {
|
||
return &Mat{new(array)}
|
||
}
|
||
panic(mat.ErrShape)
|
||
}
|
||
|
||
// Dims returns the number of rows and columns of this matrix.
|
||
// This method will always return 3×3 for a Mat.
|
||
func (m *Mat) Dims() (r, c int) { return 3, 3 }
|
||
|
||
// T returns the transpose of Mat. Changes in the receiver will be reflected in the returned matrix.
|
||
func (m *Mat) T() mat.Matrix { return mat.Transpose{Matrix: m} }
|
||
|
||
// Scale multiplies the elements of a by f, placing the result in the receiver.
|
||
//
|
||
// See the mat.Scaler interface for more information.
|
||
func (m *Mat) Scale(f float64, a mat.Matrix) {
|
||
r, c := a.Dims()
|
||
if r != 3 || c != 3 {
|
||
panic(mat.ErrShape)
|
||
}
|
||
if m.data == nil {
|
||
m.data = new(array)
|
||
}
|
||
for i := 0; i < 3; i++ {
|
||
for j := 0; j < 3; j++ {
|
||
m.Set(i, j, f*a.At(i, j))
|
||
}
|
||
}
|
||
}
|
||
|
||
// MulVec returns the matrix-vector product M⋅v.
|
||
func (m *Mat) MulVec(v Vec) Vec {
|
||
if m.data == nil {
|
||
return Vec{}
|
||
}
|
||
return Vec{
|
||
X: v.X*m.At(0, 0) + v.Y*m.At(0, 1) + v.Z*m.At(0, 2),
|
||
Y: v.X*m.At(1, 0) + v.Y*m.At(1, 1) + v.Z*m.At(1, 2),
|
||
Z: v.X*m.At(2, 0) + v.Y*m.At(2, 1) + v.Z*m.At(2, 2),
|
||
}
|
||
}
|
||
|
||
// MulVecTrans returns the matrix-vector product Mᵀ⋅v.
|
||
func (m *Mat) MulVecTrans(v Vec) Vec {
|
||
if m.data == nil {
|
||
return Vec{}
|
||
}
|
||
return Vec{
|
||
X: v.X*m.At(0, 0) + v.Y*m.At(1, 0) + v.Z*m.At(2, 0),
|
||
Y: v.X*m.At(0, 1) + v.Y*m.At(1, 1) + v.Z*m.At(2, 1),
|
||
Z: v.X*m.At(0, 2) + v.Y*m.At(1, 2) + v.Z*m.At(2, 2),
|
||
}
|
||
}
|
||
|
||
// CloneFrom makes a copy of a into the receiver m.
|
||
// Mat expects a 3×3 input matrix.
|
||
func (m *Mat) CloneFrom(a mat.Matrix) {
|
||
r, c := a.Dims()
|
||
if r != 3 || c != 3 {
|
||
panic(mat.ErrShape)
|
||
}
|
||
if m.data == nil {
|
||
m.data = new(array)
|
||
}
|
||
for i := 0; i < 3; i++ {
|
||
for j := 0; j < 3; j++ {
|
||
m.Set(i, j, a.At(i, j))
|
||
}
|
||
}
|
||
}
|
||
|
||
// Sub subtracts the matrix b from a, placing the result in the receiver.
|
||
// Sub will panic if the two matrices do not have the same shape.
|
||
func (m *Mat) Sub(a, b mat.Matrix) {
|
||
if r, c := a.Dims(); r != 3 || c != 3 {
|
||
panic(mat.ErrShape)
|
||
}
|
||
if r, c := b.Dims(); r != 3 || c != 3 {
|
||
panic(mat.ErrShape)
|
||
}
|
||
if m.data == nil {
|
||
m.data = new(array)
|
||
}
|
||
|
||
m.Set(0, 0, a.At(0, 0)-b.At(0, 0))
|
||
m.Set(0, 1, a.At(0, 1)-b.At(0, 1))
|
||
m.Set(0, 2, a.At(0, 2)-b.At(0, 2))
|
||
m.Set(1, 0, a.At(1, 0)-b.At(1, 0))
|
||
m.Set(1, 1, a.At(1, 1)-b.At(1, 1))
|
||
m.Set(1, 2, a.At(1, 2)-b.At(1, 2))
|
||
m.Set(2, 0, a.At(2, 0)-b.At(2, 0))
|
||
m.Set(2, 1, a.At(2, 1)-b.At(2, 1))
|
||
m.Set(2, 2, a.At(2, 2)-b.At(2, 2))
|
||
}
|
||
|
||
// 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.
|
||
func (m *Mat) Add(a, b mat.Matrix) {
|
||
if r, c := a.Dims(); r != 3 || c != 3 {
|
||
panic(mat.ErrShape)
|
||
}
|
||
if r, c := b.Dims(); r != 3 || c != 3 {
|
||
panic(mat.ErrShape)
|
||
}
|
||
if m.data == nil {
|
||
m.data = new(array)
|
||
}
|
||
|
||
m.Set(0, 0, a.At(0, 0)+b.At(0, 0))
|
||
m.Set(0, 1, a.At(0, 1)+b.At(0, 1))
|
||
m.Set(0, 2, a.At(0, 2)+b.At(0, 2))
|
||
m.Set(1, 0, a.At(1, 0)+b.At(1, 0))
|
||
m.Set(1, 1, a.At(1, 1)+b.At(1, 1))
|
||
m.Set(1, 2, a.At(1, 2)+b.At(1, 2))
|
||
m.Set(2, 0, a.At(2, 0)+b.At(2, 0))
|
||
m.Set(2, 1, a.At(2, 1)+b.At(2, 1))
|
||
m.Set(2, 2, a.At(2, 2)+b.At(2, 2))
|
||
}
|
||
|
||
// VecRow returns the elements in the ith row of the receiver.
|
||
func (m *Mat) VecRow(i int) Vec {
|
||
if i > 2 {
|
||
panic(mat.ErrRowAccess)
|
||
}
|
||
if m.data == nil {
|
||
return Vec{}
|
||
}
|
||
return Vec{X: m.At(i, 0), Y: m.At(i, 1), Z: m.At(i, 2)}
|
||
}
|
||
|
||
// VecCol returns the elements in the jth column of the receiver.
|
||
func (m *Mat) VecCol(j int) Vec {
|
||
if j > 2 {
|
||
panic(mat.ErrColAccess)
|
||
}
|
||
if m.data == nil {
|
||
return Vec{}
|
||
}
|
||
return Vec{X: m.At(0, j), Y: m.At(1, j), Z: m.At(2, j)}
|
||
}
|
||
|
||
// Outer calculates the outer product of the vectors x and y,
|
||
// where x and y are treated as column vectors, and stores the result in the receiver.
|
||
// m = alpha * x * yᵀ
|
||
func (m *Mat) Outer(alpha float64, x, y Vec) {
|
||
ax := alpha * x.X
|
||
ay := alpha * x.Y
|
||
az := alpha * x.Z
|
||
m.Set(0, 0, ax*y.X)
|
||
m.Set(0, 1, ax*y.Y)
|
||
m.Set(0, 2, ax*y.Z)
|
||
|
||
m.Set(1, 0, ay*y.X)
|
||
m.Set(1, 1, ay*y.Y)
|
||
m.Set(1, 2, ay*y.Z)
|
||
|
||
m.Set(2, 0, az*y.X)
|
||
m.Set(2, 1, az*y.Y)
|
||
m.Set(2, 2, az*y.Z)
|
||
}
|
||
|
||
// Det calculates the determinant of the receiver using the following formula
|
||
// ⎡a b c⎤
|
||
// m = ⎢d e f⎥
|
||
// ⎣g h i⎦
|
||
// det(m) = a(ei − fh) − b(di − fg) + c(dh − eg)
|
||
func (m *Mat) Det() float64 {
|
||
a := m.At(0, 0)
|
||
b := m.At(0, 1)
|
||
c := m.At(0, 2)
|
||
|
||
deta := m.At(1, 1)*m.At(2, 2) - m.At(1, 2)*m.At(2, 1)
|
||
detb := m.At(1, 0)*m.At(2, 2) - m.At(1, 2)*m.At(2, 0)
|
||
detc := m.At(1, 0)*m.At(2, 1) - m.At(1, 1)*m.At(2, 0)
|
||
return a*deta - b*detb + c*detc
|
||
}
|