/
mat_unsafe.go
151 lines (136 loc) · 3.57 KB
/
mat_unsafe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// 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.
//go:build !safe
// +build !safe
package r3
import (
"unsafe"
"gonum.org/v1/gonum/blas/blas64"
"gonum.org/v1/gonum/mat"
)
type array [3][3]float64
// At returns the value of a matrix element at row i, column j.
// At expects indices in the range [0,2].
// It will panic if i or j are out of bounds for the matrix.
func (m *Mat) At(i, j int) float64 {
if m.data == nil {
m.data = new(array)
}
return m.data[i][j]
}
// Set sets the element at row i, column j to the value v.
func (m *Mat) Set(i, j int, v float64) {
if m.data == nil {
m.data = new(array)
}
m.data[i][j] = v
}
// Eye returns the 3×3 Identity matrix
func Eye() *Mat {
return &Mat{&array{
{1, 0, 0},
{0, 1, 0},
{0, 0, 1},
}}
}
// Skew returns the 3×3 skew symmetric matrix (right hand system) of v.
//
// ⎡ 0 -z y⎤
// Skew({x,y,z}) = ⎢ z 0 -x⎥
// ⎣-y x 0⎦
//
// Deprecated: use Mat.Skew()
func Skew(v Vec) (M *Mat) {
return &Mat{&array{
{0, -v.Z, v.Y},
{v.Z, 0, -v.X},
{-v.Y, v.X, 0},
}}
}
// Mul takes the matrix product of a and b, placing the result in the receiver.
// If the number of columns in a does not equal 3, Mul will panic.
func (m *Mat) Mul(a, b mat.Matrix) {
ra, ca := a.Dims()
rb, cb := b.Dims()
switch {
case ra != 3:
panic(mat.ErrShape)
case cb != 3:
panic(mat.ErrShape)
case ca != rb:
panic(mat.ErrShape)
}
if m.data == nil {
m.data = new(array)
}
if ca != 3 {
// General matrix multiplication for the case where the inner dimension is not 3.
t := mat.NewDense(3, 3, m.slice())
t.Mul(a, b)
return
}
a00 := a.At(0, 0)
b00 := b.At(0, 0)
a01 := a.At(0, 1)
b01 := b.At(0, 1)
a02 := a.At(0, 2)
b02 := b.At(0, 2)
a10 := a.At(1, 0)
b10 := b.At(1, 0)
a11 := a.At(1, 1)
b11 := b.At(1, 1)
a12 := a.At(1, 2)
b12 := b.At(1, 2)
a20 := a.At(2, 0)
b20 := b.At(2, 0)
a21 := a.At(2, 1)
b21 := b.At(2, 1)
a22 := a.At(2, 2)
b22 := b.At(2, 2)
m.data[0][0] = a00*b00 + a01*b10 + a02*b20
m.data[0][1] = a00*b01 + a01*b11 + a02*b21
m.data[0][2] = a00*b02 + a01*b12 + a02*b22
m.data[1][0] = a10*b00 + a11*b10 + a12*b20
m.data[1][1] = a10*b01 + a11*b11 + a12*b21
m.data[1][2] = a10*b02 + a11*b12 + a12*b22
m.data[2][0] = a20*b00 + a21*b10 + a22*b20
m.data[2][1] = a20*b01 + a21*b11 + a22*b21
m.data[2][2] = a20*b02 + a21*b12 + a22*b22
}
// RawMatrix returns the blas representation of the matrix with the backing
// data of this matrix. Changes to the returned matrix will be reflected in
// the receiver.
func (m *Mat) RawMatrix() blas64.General {
if m.data == nil {
m.data = new(array)
}
return blas64.General{Rows: 3, Cols: 3, Data: m.slice(), Stride: 3}
}
// Mat returns a 3×3 rotation matrix corresponding to the receiver. It
// may be used to perform rotations on a 3-vector or to apply the rotation
// to a 3×n matrix of column vectors. If the receiver is not a unit
// quaternion, the returned matrix will not be a pure rotation.
func (r Rotation) Mat() *Mat {
w, i, j, k := r.Real, r.Imag, r.Jmag, r.Kmag
ii := 2 * i * i
jj := 2 * j * j
kk := 2 * k * k
wi := 2 * w * i
wj := 2 * w * j
wk := 2 * w * k
ij := 2 * i * j
jk := 2 * j * k
ki := 2 * k * i
return &Mat{&array{
{1 - (jj + kk), ij - wk, ki + wj},
{ij + wk, 1 - (ii + kk), jk - wi},
{ki - wj, jk + wi, 1 - (ii + jj)},
}}
}
func arrayFrom(vals []float64) *array {
return (*array)(unsafe.Pointer(&vals[0]))
}
func (m *Mat) slice() []float64 {
return (*[9]float64)(unsafe.Pointer(m.data))[:]
}