|
a |
|
b/app/resources/b3d/math3d.py |
|
|
1 |
import math |
|
|
2 |
|
|
|
3 |
|
|
|
4 |
# Converts angle from degree to radian |
|
|
5 |
def to_radian(angle): |
|
|
6 |
return angle / 180.0 * math.pi |
|
|
7 |
|
|
|
8 |
|
|
|
9 |
# Constructs a quaternion from a rotation of degree 'angle' around vector 'axis' |
|
|
10 |
def quaternion(axis, angle): |
|
|
11 |
angle *= 0.5 |
|
|
12 |
sinAngle = math.sin(to_radian(angle)) |
|
|
13 |
return normalize((axis[0] * sinAngle, axis[1] * sinAngle, axis[2] * sinAngle, math.cos(to_radian(angle)))) |
|
|
14 |
|
|
|
15 |
|
|
|
16 |
# Normalizes quaternion 'q' |
|
|
17 |
def normalize(q): |
|
|
18 |
length = math.sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]) |
|
|
19 |
return (q[0] / length, q[1] / length, q[2] / length, q[3] / length) |
|
|
20 |
|
|
|
21 |
|
|
|
22 |
# Multiplies 2 quaternions : 'q1' * 'q2' |
|
|
23 |
def multiply_quat(q1, q2): |
|
|
24 |
return (q1[3] * q2[0] + q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1], |
|
|
25 |
q1[3] * q2[1] + q1[1] * q2[3] + q1[2] * q2[0] - q1[0] * q2[2], |
|
|
26 |
q1[3] * q2[2] + q1[2] * q2[3] + q1[0] * q2[1] - q1[1] * q2[0], |
|
|
27 |
q1[3] * q2[3] - q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2]) |
|
|
28 |
|
|
|
29 |
|
|
|
30 |
# Converts quaternion 'q' to a rotation matrix |
|
|
31 |
def matrix_from_quat(q): |
|
|
32 |
x2 = q[0] * q[0] |
|
|
33 |
y2 = q[1] * q[1] |
|
|
34 |
z2 = q[2] * q[2] |
|
|
35 |
xy = q[0] * q[1] |
|
|
36 |
xz = q[0] * q[2] |
|
|
37 |
yz = q[1] * q[2] |
|
|
38 |
wx = q[3] * q[0] |
|
|
39 |
wy = q[3] * q[1] |
|
|
40 |
wz = q[3] * q[2] |
|
|
41 |
return (1.0 - 2.0 * (y2 + z2), 2.0 * (xy - wz), 2.0 * (xz + wy), 0.0, |
|
|
42 |
2.0 * (xy + wz), 1.0 - 2.0 * (x2 + z2), 2.0 * (yz - wx), 0.0, |
|
|
43 |
2.0 * (xz - wy), 2.0 * (yz + wx), 1.0 - 2.0 * (x2 + y2), 0.0, |
|
|
44 |
0.0, 0.0, 0.0, 1.0) |
|
|
45 |
|
|
|
46 |
|
|
|
47 |
# Constructs a translation matrix |
|
|
48 |
def matrix_from_trans(trans): |
|
|
49 |
return (1, 0, 0, trans[0], |
|
|
50 |
0, 1, 0, trans[1], |
|
|
51 |
0, 0, 1, trans[2], |
|
|
52 |
0, 0, 0, 1) |
|
|
53 |
|
|
|
54 |
|
|
|
55 |
# Returns an identity matrix |
|
|
56 |
def identity_matrix(): |
|
|
57 |
return (1, 0, 0, 0, |
|
|
58 |
0, 1, 0, 0, |
|
|
59 |
0, 0, 1, 0, |
|
|
60 |
0, 0, 0, 1) |
|
|
61 |
|
|
|
62 |
|
|
|
63 |
# Multiplies 2 Mat4 : 'm1' * 'm2' |
|
|
64 |
def multiply_matrix(m1, m2): |
|
|
65 |
res = [] |
|
|
66 |
for i in range(0, 4): |
|
|
67 |
for j in range(0, 4): |
|
|
68 |
res.append(m1[i * 4] * m2[j] + m1[i * 4 + 1] * m2[j + 4] + m1[i * 4 + 2] * m2[j + 8] + m1[i * 4 + 3] * m2[j + 12]) |
|
|
69 |
return res |
|
|
70 |
|
|
|
71 |
|
|
|
72 |
# Multiplies matrix 'm' by vector 'v' |
|
|
73 |
def multiply_mat_by_vec(m, v): |
|
|
74 |
w = 1.0 |
|
|
75 |
if len(v) == 4: |
|
|
76 |
w = v[3] |
|
|
77 |
return (m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * w, |
|
|
78 |
m[4] * v[0] + m[5] * v[1] + m[6] * v[2] + m[7] * w, |
|
|
79 |
m[8] * v[0] + m[9] * v[1] + m[10] * v[2] + m[11] * w, |
|
|
80 |
m[12] * v[0] + m[13] * v[1] + m[14] * v[2] + m[15] * w) |
|
|
81 |
|
|
|
82 |
|
|
|
83 |
# Transposes matrix 'm' |
|
|
84 |
def transpose(m): |
|
|
85 |
return (m[0], m[4], m[8], m[12], |
|
|
86 |
m[1], m[5], m[9], m[13], |
|
|
87 |
m[2], m[6], m[10], m[14], |
|
|
88 |
m[3], m[7], m[11], m[15]) |
|
|
89 |
|
|
|
90 |
|
|
|
91 |
# Calculates inverse of matrix m |
|
|
92 |
# Reimplement of gluInvertMatrix |
|
|
93 |
def invert_matrix(m): |
|
|
94 |
inv = [] |
|
|
95 |
inv.append(m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]) |
|
|
96 |
inv.append(-m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]) |
|
|
97 |
inv.append(m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]) |
|
|
98 |
inv.append(-m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]) |
|
|
99 |
inv.append(-m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]) |
|
|
100 |
inv.append(m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]) |
|
|
101 |
inv.append(-m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]) |
|
|
102 |
inv.append(m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]) |
|
|
103 |
inv.append(m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]) |
|
|
104 |
inv.append(-m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]) |
|
|
105 |
inv.append(m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]) |
|
|
106 |
inv.append(-m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]) |
|
|
107 |
inv.append(-m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]) |
|
|
108 |
inv.append(m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]) |
|
|
109 |
inv.append(-m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]) |
|
|
110 |
inv.append(m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]) |
|
|
111 |
|
|
|
112 |
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12] |
|
|
113 |
if det == 0: |
|
|
114 |
return None |
|
|
115 |
|
|
|
116 |
det = 1.0 / det |
|
|
117 |
mOut = [] |
|
|
118 |
for i in range(16): |
|
|
119 |
mOut.append(inv[i] * det) |
|
|
120 |
return mOut |
|
|
121 |
|
|
|
122 |
|
|
|
123 |
# Calculates length^2 of vector 'v' |
|
|
124 |
def length2(v): |
|
|
125 |
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] |
|
|
126 |
|
|
|
127 |
|
|
|
128 |
# Calculates vector dot product : 'v1' * 'v2' |
|
|
129 |
def dot(v1, v2): |
|
|
130 |
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] |
|
|
131 |
|
|
|
132 |
|
|
|
133 |
# Calculates vector cross product : 'v1' x 'v2' |
|
|
134 |
def cross(v1, v2): |
|
|
135 |
return (v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]) |
|
|
136 |
|
|
|
137 |
|
|
|
138 |
# Normalizes vector 'v' |
|
|
139 |
def normalize_vec(v): |
|
|
140 |
l2 = length2(v) |
|
|
141 |
if l2 == 0: |
|
|
142 |
return (0, 0, 0) |
|
|
143 |
l = math.sqrt(l2) |
|
|
144 |
return (v[0] / l, v[1] / l, v[2] / l) |