ncca-ngl 0.3.4__py3-none-any.whl → 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ncca/ngl/PrimData/pack_arrays.py +2 -3
- ncca/ngl/__init__.py +3 -4
- ncca/ngl/base_mesh.py +28 -20
- ncca/ngl/image.py +1 -3
- ncca/ngl/mat2.py +79 -53
- ncca/ngl/mat3.py +104 -185
- ncca/ngl/mat4.py +144 -309
- ncca/ngl/prim_data.py +42 -36
- ncca/ngl/primitives.py +2 -2
- ncca/ngl/pyside_event_handling_mixin.py +0 -108
- ncca/ngl/quaternion.py +69 -36
- ncca/ngl/shader.py +0 -116
- ncca/ngl/shader_program.py +94 -117
- ncca/ngl/texture.py +5 -2
- ncca/ngl/util.py +7 -0
- ncca/ngl/vec2.py +58 -292
- ncca/ngl/vec2_array.py +79 -28
- ncca/ngl/vec3.py +59 -340
- ncca/ngl/vec3_array.py +76 -23
- ncca/ngl/vec4.py +90 -190
- ncca/ngl/vec4_array.py +78 -27
- ncca/ngl/vector_base.py +542 -0
- ncca/ngl/webgpu/__init__.py +20 -0
- ncca/ngl/webgpu/__main__.py +640 -0
- ncca/ngl/webgpu/__main__.py.backup +640 -0
- ncca/ngl/webgpu/base_webgpu_pipeline.py +354 -0
- ncca/ngl/webgpu/custom_shader_pipeline.py +288 -0
- ncca/ngl/webgpu/instanced_geometry_pipeline.py +594 -0
- ncca/ngl/webgpu/line_pipeline.py +405 -0
- ncca/ngl/webgpu/pipeline_factory.py +190 -0
- ncca/ngl/webgpu/pipeline_shaders.py +497 -0
- ncca/ngl/webgpu/point_list_pipeline.py +349 -0
- ncca/ngl/webgpu/point_pipeline.py +336 -0
- ncca/ngl/webgpu/triangle_pipeline.py +419 -0
- ncca/ngl/webgpu/webgpu_constants.py +31 -0
- ncca/ngl/webgpu/webgpu_widget.py +322 -0
- ncca/ngl/webgpu/wip/REFACTORING_SUMMARY.md +82 -0
- ncca/ngl/webgpu/wip/UNIFIED_SYSTEM.md +314 -0
- ncca/ngl/webgpu/wip/buffer_manager.py +396 -0
- ncca/ngl/webgpu/wip/pipeline_config.py +463 -0
- ncca/ngl/webgpu/wip/shader_constants.py +328 -0
- ncca/ngl/webgpu/wip/shader_templates.py +563 -0
- ncca/ngl/webgpu/wip/unified_examples.py +390 -0
- ncca/ngl/webgpu/wip/unified_factory.py +449 -0
- ncca/ngl/webgpu/wip/unified_pipeline.py +469 -0
- ncca/ngl/widgets/__init__.py +18 -2
- ncca/ngl/widgets/__main__.py +2 -1
- ncca/ngl/widgets/lookatwidget.py +2 -1
- ncca/ngl/widgets/mat4widget.py +2 -2
- ncca/ngl/widgets/vec2widget.py +1 -1
- ncca/ngl/widgets/vec3widget.py +1 -0
- {ncca_ngl-0.3.4.dist-info → ncca_ngl-0.5.0.dist-info}/METADATA +3 -2
- ncca_ngl-0.5.0.dist-info/RECORD +105 -0
- ncca/ngl/widgets/transformation_widget.py +0 -299
- ncca_ngl-0.3.4.dist-info/RECORD +0 -82
- {ncca_ngl-0.3.4.dist-info → ncca_ngl-0.5.0.dist-info}/WHEEL +0 -0
ncca/ngl/mat4.py
CHANGED
|
@@ -1,49 +1,41 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Simple Mat4 class which can be used with the Vec4 class
|
|
3
|
+
NumPy-based implementation
|
|
3
4
|
"""
|
|
4
5
|
|
|
5
6
|
import copy
|
|
6
|
-
import functools
|
|
7
7
|
import math
|
|
8
|
-
import operator
|
|
9
8
|
|
|
10
9
|
import numpy as np
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class Mat4Error(Exception):
|
|
14
|
-
"""An exception class for
|
|
13
|
+
"""An exception class for Mat4"""
|
|
15
14
|
|
|
16
15
|
pass
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
class Mat4NotSquare(Exception):
|
|
20
|
-
"""Make sure we have
|
|
19
|
+
"""Make sure we have 4x4"""
|
|
21
20
|
|
|
22
21
|
pass
|
|
23
22
|
|
|
24
23
|
|
|
25
|
-
_identity = [
|
|
26
|
-
[1.0, 0.0, 0.0, 0.0],
|
|
27
|
-
[0.0, 1.0, 0.0, 0.0],
|
|
28
|
-
[0.0, 0.0, 1.0, 0.0],
|
|
29
|
-
[0.0, 0.0, 0.0, 1.0],
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
|
|
33
24
|
class Mat4:
|
|
34
25
|
__slots__ = ["m"]
|
|
35
26
|
|
|
36
27
|
def __init__(self):
|
|
37
28
|
"construct to identity matrix"
|
|
38
|
-
self.m =
|
|
29
|
+
self.m = np.eye(4, dtype=np.float64)
|
|
39
30
|
|
|
40
31
|
def get_matrix(self):
|
|
41
32
|
"return matrix elements as list ideal for OpenGL etc"
|
|
42
|
-
|
|
33
|
+
# Flatten in row-major order (C-style)
|
|
34
|
+
return self.m.flatten("C").tolist()
|
|
43
35
|
|
|
44
36
|
def to_numpy(self):
|
|
45
37
|
"return matrix as a numpy array ideal for WebGPU etc"
|
|
46
|
-
return
|
|
38
|
+
return self.m.astype(np.float32)
|
|
47
39
|
|
|
48
40
|
@classmethod
|
|
49
41
|
def identity(cls):
|
|
@@ -55,36 +47,30 @@ class Mat4:
|
|
|
55
47
|
def zero(cls):
|
|
56
48
|
"class method to return a zero matrix"
|
|
57
49
|
v = Mat4()
|
|
58
|
-
v.m =
|
|
59
|
-
[0.0, 0.0, 0.0, 0.0],
|
|
60
|
-
[0.0, 0.0, 0.0, 0.0],
|
|
61
|
-
[0.0, 0.0, 0.0, 0.0],
|
|
62
|
-
[0.0, 0.0, 0.0, 0.0],
|
|
63
|
-
]
|
|
50
|
+
v.m = np.zeros((4, 4), dtype=np.float64)
|
|
64
51
|
return v
|
|
65
52
|
|
|
66
53
|
@classmethod
|
|
67
54
|
def from_list(cls, lst):
|
|
68
55
|
"class method to create mat4 from list"
|
|
69
56
|
v = Mat4()
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if len(
|
|
73
|
-
v.m =
|
|
57
|
+
if isinstance(lst, list) and len(lst) == 4 and all(isinstance(row, list) for row in lst):
|
|
58
|
+
# 2D list
|
|
59
|
+
if all(len(row) == 4 for row in lst):
|
|
60
|
+
v.m = np.array(lst, dtype=np.float64)
|
|
74
61
|
return v
|
|
75
|
-
|
|
62
|
+
elif any(len(row) != 4 for row in lst):
|
|
76
63
|
raise Mat4NotSquare
|
|
77
|
-
|
|
64
|
+
elif isinstance(lst, list) and len(lst) == 16:
|
|
65
|
+
# flat list - reshape to 4x4 in row-major order
|
|
66
|
+
v.m = np.array(lst, dtype=np.float64).reshape(4, 4, order="C")
|
|
78
67
|
return v
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
"ensure matrix is square"
|
|
82
|
-
return len(self.m) == 4 and all(len(i) == 4 for i in self.m)
|
|
68
|
+
else:
|
|
69
|
+
raise Mat4NotSquare
|
|
83
70
|
|
|
84
71
|
def to_list(self):
|
|
85
72
|
"convert matrix to list"
|
|
86
|
-
|
|
87
|
-
return functools.reduce(operator.concat, self.m)
|
|
73
|
+
return self.m.flatten("C").tolist()
|
|
88
74
|
|
|
89
75
|
def copy(self) -> "Mat4":
|
|
90
76
|
"""Create a copy of the matrix.
|
|
@@ -93,48 +79,86 @@ class Mat4:
|
|
|
93
79
|
A new Mat4 instance with the same values.
|
|
94
80
|
"""
|
|
95
81
|
new_mat = Mat4()
|
|
96
|
-
new_mat.m =
|
|
82
|
+
new_mat.m = self.m.copy()
|
|
97
83
|
return new_mat
|
|
98
84
|
|
|
99
85
|
def transpose(self):
|
|
100
86
|
"transpose this matrix"
|
|
101
|
-
self.m =
|
|
87
|
+
self.m = self.m.T
|
|
102
88
|
|
|
103
89
|
def get_transpose(self):
|
|
104
90
|
"return a new matrix as the transpose of ourself"
|
|
105
91
|
m = Mat4()
|
|
106
|
-
m.m =
|
|
92
|
+
m.m = self.m.T.copy()
|
|
107
93
|
return m
|
|
108
94
|
|
|
109
95
|
@classmethod
|
|
110
96
|
def scale(cls, x: float, y: float, z: float):
|
|
111
|
-
"return a
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
97
|
+
"""return a scale matrix resetting to identity first
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
x : float
|
|
102
|
+
uniform scale in the x axis
|
|
103
|
+
y : float
|
|
104
|
+
uniform scale in the y axis
|
|
105
|
+
z : float
|
|
106
|
+
uniform scale in the z axis
|
|
107
|
+
|
|
108
|
+
.. highlight:: python
|
|
109
|
+
.. code-block:: python
|
|
110
|
+
|
|
111
|
+
scale=Mat4.scale(2.0,1.0,3.0)
|
|
112
|
+
|
|
113
|
+
Returns
|
|
114
|
+
-------
|
|
115
|
+
Mat3
|
|
116
|
+
matrix with diagonals set to the scale
|
|
117
|
+
|
|
118
|
+
"""
|
|
119
|
+
a = Mat4()
|
|
120
|
+
a.m[0, 0] = x
|
|
121
|
+
a.m[1, 1] = y
|
|
122
|
+
a.m[2, 2] = z
|
|
116
123
|
return a
|
|
117
124
|
|
|
118
125
|
@classmethod
|
|
119
126
|
def translate(cls, x: float, y: float, z: float):
|
|
120
127
|
"return a new matrix as translation"
|
|
121
|
-
a = Mat4()
|
|
122
|
-
a.m[3
|
|
123
|
-
a.m[3
|
|
124
|
-
a.m[3
|
|
128
|
+
a = Mat4()
|
|
129
|
+
a.m[3, 0] = x
|
|
130
|
+
a.m[3, 1] = y
|
|
131
|
+
a.m[3, 2] = z
|
|
125
132
|
return a
|
|
126
133
|
|
|
127
134
|
@classmethod
|
|
128
135
|
def rotate_x(cls, angle):
|
|
129
|
-
"return a rotation around the X axis by angle degrees
|
|
136
|
+
"""return a rotation around the X axis by angle degrees
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
angle : float
|
|
141
|
+
angle in degrees
|
|
142
|
+
|
|
143
|
+
.. highlight:: python
|
|
144
|
+
.. code-block:: python
|
|
145
|
+
|
|
146
|
+
rotate_x=Mat3.rotate_x(90.0)
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
Mat3
|
|
151
|
+
matrix with rotation set to the angle
|
|
152
|
+
|
|
153
|
+
"""
|
|
130
154
|
a = Mat4()
|
|
131
155
|
beta = math.radians(angle)
|
|
132
156
|
sr = math.sin(beta)
|
|
133
157
|
cr = math.cos(beta)
|
|
134
|
-
a.m[1
|
|
135
|
-
a.m[1
|
|
136
|
-
a.m[2
|
|
137
|
-
a.m[2
|
|
158
|
+
a.m[1, 1] = cr
|
|
159
|
+
a.m[1, 2] = sr
|
|
160
|
+
a.m[2, 1] = -sr
|
|
161
|
+
a.m[2, 2] = cr
|
|
138
162
|
return a
|
|
139
163
|
|
|
140
164
|
@classmethod
|
|
@@ -144,10 +168,10 @@ class Mat4:
|
|
|
144
168
|
beta = math.radians(angle)
|
|
145
169
|
sr = math.sin(beta)
|
|
146
170
|
cr = math.cos(beta)
|
|
147
|
-
a.m[0
|
|
148
|
-
a.m[0
|
|
149
|
-
a.m[2
|
|
150
|
-
a.m[2
|
|
171
|
+
a.m[0, 0] = cr
|
|
172
|
+
a.m[0, 2] = -sr
|
|
173
|
+
a.m[2, 0] = sr
|
|
174
|
+
a.m[2, 2] = cr
|
|
151
175
|
return a
|
|
152
176
|
|
|
153
177
|
@classmethod
|
|
@@ -157,18 +181,18 @@ class Mat4:
|
|
|
157
181
|
beta = math.radians(angle)
|
|
158
182
|
sr = math.sin(beta)
|
|
159
183
|
cr = math.cos(beta)
|
|
160
|
-
a.m[0
|
|
161
|
-
a.m[0
|
|
162
|
-
a.m[1
|
|
163
|
-
a.m[1
|
|
184
|
+
a.m[0, 0] = cr
|
|
185
|
+
a.m[0, 1] = sr
|
|
186
|
+
a.m[1, 0] = -sr
|
|
187
|
+
a.m[1, 1] = cr
|
|
164
188
|
return a
|
|
165
189
|
|
|
166
190
|
def __getitem__(self, idx):
|
|
167
|
-
"access array elements
|
|
168
|
-
return self.m[idx]
|
|
191
|
+
"access array elements"
|
|
192
|
+
return self.m[idx].tolist()
|
|
169
193
|
|
|
170
194
|
def __setitem__(self, idx, item):
|
|
171
|
-
"set items
|
|
195
|
+
"set items"
|
|
172
196
|
self.m[idx] = item
|
|
173
197
|
|
|
174
198
|
def __mul__(self, rhs):
|
|
@@ -179,288 +203,99 @@ class Mat4:
|
|
|
179
203
|
rhs : float int
|
|
180
204
|
multiply each matrix element by rhs
|
|
181
205
|
|
|
182
|
-
raises :
|
|
206
|
+
raises : Mat4Error
|
|
183
207
|
if rhs is not a number
|
|
184
208
|
"""
|
|
185
209
|
if isinstance(rhs, (int, float)):
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return self
|
|
210
|
+
result = Mat4()
|
|
211
|
+
result.m = self.m * rhs
|
|
212
|
+
return result
|
|
190
213
|
raise Mat4Error
|
|
191
214
|
|
|
192
215
|
def _mat_mul(self, rhs):
|
|
193
|
-
"matrix mult
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
a03 = self.m[0][3]
|
|
199
|
-
a10 = self.m[1][0]
|
|
200
|
-
a11 = self.m[1][1]
|
|
201
|
-
a12 = self.m[1][2]
|
|
202
|
-
a13 = self.m[1][3]
|
|
203
|
-
a20 = self.m[2][0]
|
|
204
|
-
a21 = self.m[2][1]
|
|
205
|
-
a22 = self.m[2][2]
|
|
206
|
-
a23 = self.m[2][3]
|
|
207
|
-
a30 = self.m[3][0]
|
|
208
|
-
a31 = self.m[3][1]
|
|
209
|
-
a32 = self.m[3][2]
|
|
210
|
-
a33 = self.m[3][3]
|
|
211
|
-
b00 = rhs.m[0][0]
|
|
212
|
-
b01 = rhs.m[0][1]
|
|
213
|
-
b02 = rhs.m[0][2]
|
|
214
|
-
b03 = rhs.m[0][3]
|
|
215
|
-
b10 = rhs.m[1][0]
|
|
216
|
-
b11 = rhs.m[1][1]
|
|
217
|
-
b12 = rhs.m[1][2]
|
|
218
|
-
b13 = rhs.m[1][3]
|
|
219
|
-
b20 = rhs.m[2][0]
|
|
220
|
-
b21 = rhs.m[2][1]
|
|
221
|
-
b22 = rhs.m[2][2]
|
|
222
|
-
b23 = rhs.m[2][3]
|
|
223
|
-
b30 = rhs.m[3][0]
|
|
224
|
-
b31 = rhs.m[3][1]
|
|
225
|
-
b32 = rhs.m[3][2]
|
|
226
|
-
b33 = rhs.m[3][3]
|
|
227
|
-
ret=Mat4() # result mat4
|
|
228
|
-
ret.m[0][0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30
|
|
229
|
-
ret.m[0][1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31
|
|
230
|
-
ret.m[0][2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32
|
|
231
|
-
ret.m[0][3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33
|
|
232
|
-
ret.m[1][0] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30
|
|
233
|
-
ret.m[1][1] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31
|
|
234
|
-
ret.m[1][2] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32
|
|
235
|
-
ret.m[1][3] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33
|
|
236
|
-
ret.m[2][0] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30
|
|
237
|
-
ret.m[2][1] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31
|
|
238
|
-
ret.m[2][2] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32
|
|
239
|
-
ret.m[2][3] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33
|
|
240
|
-
ret.m[3][0] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30
|
|
241
|
-
ret.m[3][1] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31
|
|
242
|
-
ret.m[3][2] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32
|
|
243
|
-
ret.m[3][3] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33
|
|
244
|
-
return ret
|
|
245
|
-
# fmt: on
|
|
216
|
+
"matrix mult for 3D OpenGL style graphics"
|
|
217
|
+
result = Mat4()
|
|
218
|
+
# Use numpy's @ operator which does standard matrix multiplication
|
|
219
|
+
result.m = rhs.m @ self.m
|
|
220
|
+
return result
|
|
246
221
|
|
|
247
222
|
def __matmul__(self, rhs):
|
|
248
|
-
from .vec4 import Vec4
|
|
223
|
+
from .vec4 import Vec4
|
|
249
224
|
|
|
250
|
-
"multiply matrix by another matrix"
|
|
225
|
+
"multiply matrix by another matrix or vector"
|
|
251
226
|
if isinstance(rhs, Mat4):
|
|
252
227
|
return self._mat_mul(rhs)
|
|
253
|
-
elif isinstance(rhs,
|
|
254
|
-
#
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
rhs.x * self.m[2][0]+ rhs.y * self.m[2][1]+ rhs.z * self.m[2][2]+ rhs.w * self.m[2][3],
|
|
259
|
-
rhs.x * self.m[3][0]+ rhs.y * self.m[3][1]+ rhs.z * self.m[3][2]+ rhs.w * self.m[3][3])
|
|
260
|
-
# fmt: on
|
|
228
|
+
elif isinstance(rhs, Vec4):
|
|
229
|
+
# Vector transformation
|
|
230
|
+
# vec = np.array([rhs.x, rhs.y, rhs.z, rhs.w], dtype=np.float64)
|
|
231
|
+
res = self.m @ rhs._data
|
|
232
|
+
return Vec4(res[0], res[1], res[2], res[3])
|
|
261
233
|
else:
|
|
262
234
|
raise Mat4Error
|
|
263
235
|
|
|
264
236
|
def __str__(self):
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
def _addfunc(self, rhs):
|
|
268
|
-
"internal add function"
|
|
269
|
-
temp = Mat4()
|
|
270
|
-
for i in range(0, len(temp.m)):
|
|
271
|
-
temp.m[i] = [a + b for a, b in zip(self.m[i], rhs.m[i], strict=False)]
|
|
272
|
-
return temp
|
|
237
|
+
rows = [self.m[i].tolist() for i in range(4)]
|
|
238
|
+
return f"[{rows[0]}\n{rows[1]}\n{rows[2]}\n{rows[3]}]"
|
|
273
239
|
|
|
274
240
|
def __add__(self, rhs):
|
|
275
241
|
"piecewise addition of elements"
|
|
276
|
-
|
|
242
|
+
result = Mat4()
|
|
243
|
+
result.m = self.m + rhs.m
|
|
244
|
+
return result
|
|
277
245
|
|
|
278
246
|
def __iadd__(self, rhs):
|
|
279
247
|
"piecewise addition of elements to this"
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
"internal sub function"
|
|
284
|
-
temp = Mat4()
|
|
285
|
-
for i in range(0, len(temp.m)):
|
|
286
|
-
temp.m[i] = [a - b for a, b in zip(self.m[i], rhs.m[i], strict=False)]
|
|
287
|
-
return temp
|
|
248
|
+
result = Mat4()
|
|
249
|
+
result.m = self.m + rhs.m
|
|
250
|
+
return result
|
|
288
251
|
|
|
289
252
|
def __sub__(self, rhs):
|
|
290
253
|
"piecewise subtraction of elements"
|
|
291
|
-
|
|
254
|
+
result = Mat4()
|
|
255
|
+
result.m = self.m - rhs.m
|
|
256
|
+
return result
|
|
292
257
|
|
|
293
258
|
def __isub__(self, rhs):
|
|
294
259
|
"piecewise subtraction of elements to this"
|
|
295
|
-
|
|
260
|
+
result = Mat4()
|
|
261
|
+
result.m = self.m - rhs.m
|
|
262
|
+
return result
|
|
296
263
|
|
|
297
264
|
def determinant(self):
|
|
298
265
|
"determinant of matrix"
|
|
299
|
-
|
|
300
|
-
return (
|
|
301
|
-
self.m[0][0] * self.m[1][1] * self.m[2][2] * self.m[3][3]
|
|
302
|
-
- self.m[0][0] * self.m[1][1] * self.m[2][3] * self.m[3][2]
|
|
303
|
-
+ self.m[0][0] * self.m[1][2] * self.m[2][3] * self.m[3][1]
|
|
304
|
-
- self.m[0][0] * self.m[1][2] * self.m[2][1] * self.m[3][3]
|
|
305
|
-
+ self.m[0][0] * self.m[1][3] * self.m[2][1] * self.m[3][2]
|
|
306
|
-
- self.m[0][0] * self.m[1][3] * self.m[2][2] * self.m[3][1]
|
|
307
|
-
- self.m[1][0] * self.m[2][1] * self.m[3][2] * self.m[0][3]
|
|
308
|
-
+ self.m[1][0] * self.m[2][1] * self.m[0][2] * self.m[3][3]
|
|
309
|
-
- self.m[1][0] * self.m[3][1] * self.m[0][2] * self.m[2][3]
|
|
310
|
-
+ self.m[1][0] * self.m[3][1] * self.m[2][2] * self.m[0][3]
|
|
311
|
-
- self.m[1][0] * self.m[0][1] * self.m[2][2] * self.m[3][3]
|
|
312
|
-
+ self.m[1][0] * self.m[0][1] * self.m[3][2] * self.m[2][3]
|
|
313
|
-
+ self.m[2][0] * self.m[3][1] * self.m[0][2] * self.m[1][3]
|
|
314
|
-
- self.m[2][0] * self.m[3][1] * self.m[1][2] * self.m[0][3]
|
|
315
|
-
+ self.m[2][0] * self.m[0][1] * self.m[1][2] * self.m[3][3]
|
|
316
|
-
- self.m[2][0] * self.m[0][1] * self.m[3][2] * self.m[1][3]
|
|
317
|
-
+ self.m[2][0] * self.m[1][1] * self.m[3][2] * self.m[0][3]
|
|
318
|
-
- self.m[2][0] * self.m[1][1] * self.m[0][2] * self.m[3][3]
|
|
319
|
-
- self.m[3][0] * self.m[0][1] * self.m[1][2] * self.m[2][3]
|
|
320
|
-
+ self.m[3][0] * self.m[0][1] * self.m[2][2] * self.m[1][3]
|
|
321
|
-
- self.m[3][0] * self.m[1][1] * self.m[2][2] * self.m[0][3]
|
|
322
|
-
+ self.m[3][0] * self.m[1][1] * self.m[0][2] * self.m[2][3]
|
|
323
|
-
- self.m[3][0] * self.m[2][1] * self.m[0][2] * self.m[1][3]
|
|
324
|
-
+ self.m[3][0] * self.m[2][1] * self.m[1][2] * self.m[0][3]
|
|
325
|
-
)
|
|
266
|
+
return np.linalg.det(self.m)
|
|
326
267
|
|
|
327
268
|
def inverse(self):
|
|
328
269
|
"Inverse of matrix raise MatrixError if not calculable"
|
|
329
270
|
try:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
self.m[1][1] * self.m[2][2] * self.m[3][3]
|
|
335
|
-
+ self.m[1][2] * self.m[2][3] * self.m[3][1]
|
|
336
|
-
+ self.m[1][3] * self.m[2][1] * self.m[3][2]
|
|
337
|
-
- self.m[1][1] * self.m[3][2] * self.m[2][3]
|
|
338
|
-
- self.m[1][2] * self.m[2][1] * self.m[3][3]
|
|
339
|
-
- self.m[1][3] * self.m[2][2] * self.m[3][1]
|
|
340
|
-
) * invdet
|
|
341
|
-
tmp.m[0][1] = (
|
|
342
|
-
self.m[0][1] * self.m[2][3] * self.m[3][2]
|
|
343
|
-
+ self.m[0][2] * self.m[2][1] * self.m[3][3]
|
|
344
|
-
+ self.m[0][3] * self.m[2][2] * self.m[3][1]
|
|
345
|
-
- self.m[0][1] * self.m[2][2] * self.m[3][3]
|
|
346
|
-
- self.m[0][2] * self.m[2][3] * self.m[3][1]
|
|
347
|
-
- self.m[0][3] * self.m[2][1] * self.m[3][2]
|
|
348
|
-
) * invdet
|
|
349
|
-
tmp.m[0][2] = (
|
|
350
|
-
self.m[0][1] * self.m[1][2] * self.m[3][3]
|
|
351
|
-
+ self.m[0][2] * self.m[1][3] * self.m[3][1]
|
|
352
|
-
+ self.m[0][3] * self.m[1][1] * self.m[3][2]
|
|
353
|
-
- self.m[0][1] * self.m[1][3] * self.m[3][2]
|
|
354
|
-
- self.m[0][2] * self.m[1][1] * self.m[3][3]
|
|
355
|
-
- self.m[0][3] * self.m[1][2] * self.m[3][1]
|
|
356
|
-
) * invdet
|
|
357
|
-
tmp.m[0][3] = (
|
|
358
|
-
self.m[0][1] * self.m[1][3] * self.m[2][2]
|
|
359
|
-
+ self.m[0][2] * self.m[1][1] * self.m[2][3]
|
|
360
|
-
+ self.m[0][3] * self.m[1][2] * self.m[2][1]
|
|
361
|
-
- self.m[0][1] * self.m[1][2] * self.m[2][3]
|
|
362
|
-
- self.m[0][2] * self.m[1][3] * self.m[2][1]
|
|
363
|
-
- self.m[0][3] * self.m[1][1] * self.m[2][2]
|
|
364
|
-
) * invdet
|
|
365
|
-
tmp.m[1][0] = (
|
|
366
|
-
self.m[1][0] * self.m[2][3] * self.m[3][2]
|
|
367
|
-
+ self.m[1][2] * self.m[2][0] * self.m[3][3]
|
|
368
|
-
+ self.m[1][3] * self.m[2][2] * self.m[3][0]
|
|
369
|
-
- self.m[1][0] * self.m[2][2] * self.m[3][3]
|
|
370
|
-
- self.m[1][2] * self.m[2][3] * self.m[3][0]
|
|
371
|
-
- self.m[1][3] * self.m[2][0] * self.m[3][2]
|
|
372
|
-
) * invdet
|
|
373
|
-
tmp.m[1][1] = (
|
|
374
|
-
self.m[0][0] * self.m[2][2] * self.m[3][3]
|
|
375
|
-
+ self.m[0][2] * self.m[2][3] * self.m[3][0]
|
|
376
|
-
+ self.m[0][3] * self.m[2][0] * self.m[3][2]
|
|
377
|
-
- self.m[0][0] * self.m[2][3] * self.m[3][2]
|
|
378
|
-
- self.m[0][2] * self.m[2][0] * self.m[3][3]
|
|
379
|
-
- self.m[0][3] * self.m[2][2] * self.m[3][0]
|
|
380
|
-
) * invdet
|
|
381
|
-
tmp.m[1][2] = (
|
|
382
|
-
self.m[0][0] * self.m[1][3] * self.m[3][2]
|
|
383
|
-
+ self.m[0][2] * self.m[1][0] * self.m[3][3]
|
|
384
|
-
+ self.m[0][3] * self.m[1][2] * self.m[3][0]
|
|
385
|
-
- self.m[0][0] * self.m[1][2] * self.m[3][3]
|
|
386
|
-
- self.m[0][2] * self.m[1][3] * self.m[3][0]
|
|
387
|
-
- self.m[0][3] * self.m[1][0] * self.m[3][2]
|
|
388
|
-
) * invdet
|
|
389
|
-
tmp.m[1][3] = (
|
|
390
|
-
self.m[0][0] * self.m[1][2] * self.m[2][3]
|
|
391
|
-
+ self.m[0][2] * self.m[1][3] * self.m[2][0]
|
|
392
|
-
+ self.m[0][3] * self.m[1][0] * self.m[2][2]
|
|
393
|
-
- self.m[0][0] * self.m[1][3] * self.m[2][2]
|
|
394
|
-
- self.m[0][2] * self.m[1][0] * self.m[2][3]
|
|
395
|
-
- self.m[0][3] * self.m[1][2] * self.m[2][0]
|
|
396
|
-
) * invdet
|
|
397
|
-
tmp.m[2][0] = (
|
|
398
|
-
self.m[1][0] * self.m[2][1] * self.m[3][3]
|
|
399
|
-
+ self.m[1][1] * self.m[2][3] * self.m[3][0]
|
|
400
|
-
+ self.m[1][3] * self.m[2][0] * self.m[3][1]
|
|
401
|
-
- self.m[1][0] * self.m[2][3] * self.m[3][1]
|
|
402
|
-
- self.m[1][1] * self.m[2][0] * self.m[3][3]
|
|
403
|
-
- self.m[1][3] * self.m[2][1] * self.m[3][0]
|
|
404
|
-
) * invdet
|
|
405
|
-
tmp.m[2][1] = (
|
|
406
|
-
self.m[0][0] * self.m[2][3] * self.m[3][1]
|
|
407
|
-
+ self.m[0][1] * self.m[2][0] * self.m[3][3]
|
|
408
|
-
+ self.m[0][3] * self.m[2][1] * self.m[3][0]
|
|
409
|
-
- self.m[0][0] * self.m[2][1] * self.m[3][3]
|
|
410
|
-
- self.m[0][1] * self.m[2][3] * self.m[3][0]
|
|
411
|
-
- self.m[0][3] * self.m[2][0] * self.m[3][1]
|
|
412
|
-
) * invdet
|
|
413
|
-
tmp.m[2][2] = (
|
|
414
|
-
self.m[0][0] * self.m[1][1] * self.m[3][3]
|
|
415
|
-
+ self.m[0][1] * self.m[1][3] * self.m[3][0]
|
|
416
|
-
+ self.m[0][3] * self.m[1][0] * self.m[3][1]
|
|
417
|
-
- self.m[0][0] * self.m[1][3] * self.m[3][1]
|
|
418
|
-
- self.m[0][1] * self.m[1][0] * self.m[3][3]
|
|
419
|
-
- self.m[0][3] * self.m[1][1] * self.m[3][0]
|
|
420
|
-
) * invdet
|
|
421
|
-
tmp.m[2][3] = (
|
|
422
|
-
self.m[0][0] * self.m[1][3] * self.m[2][1]
|
|
423
|
-
+ self.m[0][1] * self.m[1][0] * self.m[2][3]
|
|
424
|
-
+ self.m[0][3] * self.m[1][1] * self.m[2][0]
|
|
425
|
-
- self.m[0][0] * self.m[1][1] * self.m[2][3]
|
|
426
|
-
- self.m[0][1] * self.m[1][3] * self.m[2][0]
|
|
427
|
-
- self.m[0][3] * self.m[1][0] * self.m[2][1]
|
|
428
|
-
) * invdet
|
|
429
|
-
tmp.m[3][0] = (
|
|
430
|
-
self.m[1][0] * self.m[2][2] * self.m[3][1]
|
|
431
|
-
+ self.m[1][1] * self.m[2][0] * self.m[3][2]
|
|
432
|
-
+ self.m[1][2] * self.m[2][1] * self.m[3][0]
|
|
433
|
-
- self.m[1][0] * self.m[2][1] * self.m[3][2]
|
|
434
|
-
- self.m[1][1] * self.m[2][2] * self.m[3][0]
|
|
435
|
-
- self.m[1][2] * self.m[2][0] * self.m[3][1]
|
|
436
|
-
) * invdet
|
|
437
|
-
tmp.m[3][1] = (
|
|
438
|
-
self.m[0][0] * self.m[2][1] * self.m[3][2]
|
|
439
|
-
+ self.m[0][1] * self.m[2][2] * self.m[3][0]
|
|
440
|
-
+ self.m[0][2] * self.m[2][0] * self.m[3][1]
|
|
441
|
-
- self.m[0][0] * self.m[2][2] * self.m[3][1]
|
|
442
|
-
- self.m[0][1] * self.m[2][0] * self.m[3][2]
|
|
443
|
-
- self.m[0][2] * self.m[2][1] * self.m[3][0]
|
|
444
|
-
) * invdet
|
|
445
|
-
tmp.m[3][2] = (
|
|
446
|
-
self.m[0][0] * self.m[1][2] * self.m[3][1]
|
|
447
|
-
+ self.m[0][1] * self.m[1][0] * self.m[3][2]
|
|
448
|
-
+ self.m[0][2] * self.m[1][1] * self.m[3][0]
|
|
449
|
-
- self.m[0][0] * self.m[1][1] * self.m[3][2]
|
|
450
|
-
- self.m[0][1] * self.m[1][2] * self.m[3][0]
|
|
451
|
-
- self.m[0][2] * self.m[1][0] * self.m[3][1]
|
|
452
|
-
) * invdet
|
|
453
|
-
tmp.m[3][3] = (
|
|
454
|
-
self.m[0][0] * self.m[1][1] * self.m[2][2]
|
|
455
|
-
+ self.m[0][1] * self.m[1][2] * self.m[2][0]
|
|
456
|
-
+ self.m[0][2] * self.m[1][0] * self.m[2][1]
|
|
457
|
-
- self.m[0][0] * self.m[1][2] * self.m[2][1]
|
|
458
|
-
- self.m[0][1] * self.m[1][0] * self.m[2][2]
|
|
459
|
-
- self.m[0][2] * self.m[1][1] * self.m[2][0]
|
|
460
|
-
) * invdet
|
|
461
|
-
return tmp
|
|
462
|
-
except ZeroDivisionError:
|
|
271
|
+
result = Mat4()
|
|
272
|
+
result.m = np.linalg.inv(self.m)
|
|
273
|
+
return result
|
|
274
|
+
except np.linalg.LinAlgError:
|
|
463
275
|
raise Mat4Error
|
|
464
276
|
|
|
465
277
|
def __repr__(self) -> str:
|
|
466
|
-
|
|
278
|
+
rows = [self.m[i].tolist() for i in range(4)]
|
|
279
|
+
return f"Mat4({rows})"
|
|
280
|
+
|
|
281
|
+
def __eq__(self, other):
|
|
282
|
+
"""Value-based equality for Mat4: compare underlying matrices numerically.
|
|
283
|
+
|
|
284
|
+
Returns NotImplemented for non-Mat4 types so Python can try reflected comparisons
|
|
285
|
+
or handle it appropriately.
|
|
286
|
+
"""
|
|
287
|
+
if not isinstance(other, Mat4):
|
|
288
|
+
return NotImplemented
|
|
289
|
+
# self.m and other.m should be numpy arrays; compare with tolerance
|
|
290
|
+
return np.allclose(self.m, other.m, rtol=1e-8, atol=1e-12)
|
|
291
|
+
|
|
292
|
+
def __ne__(self, other):
|
|
293
|
+
"""Value-based not equality for Mat4: compare underlying matrices numerically.
|
|
294
|
+
|
|
295
|
+
Returns NotImplemented for non-Mat4 types so Python can try reflected comparisons
|
|
296
|
+
or handle it appropriately.
|
|
297
|
+
"""
|
|
298
|
+
if not isinstance(other, Mat4):
|
|
299
|
+
return NotImplemented
|
|
300
|
+
# self.m and other.m should be numpy arrays; compare with tolerance
|
|
301
|
+
return not np.allclose(self.m, other.m, rtol=1e-8, atol=1e-12)
|