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  }