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/vec4.py
CHANGED
|
@@ -1,229 +1,129 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Simple Float only
|
|
2
|
+
Simple Float only Vec4 class for 3D graphics, very similar to the pyngl ones
|
|
3
|
+
NumPy-based implementation with VectorBase inheritance for code reuse.
|
|
3
4
|
"""
|
|
4
5
|
|
|
5
|
-
import ctypes
|
|
6
6
|
import math
|
|
7
|
+
from typing import Union
|
|
7
8
|
|
|
8
9
|
import numpy as np
|
|
9
10
|
|
|
10
|
-
from .
|
|
11
|
+
from .util import clamp
|
|
12
|
+
from .vector_base import VectorBase, _create_properties
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
class Vec4:
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
class Vec4(VectorBase["Vec4"]):
|
|
16
|
+
"""
|
|
17
|
+
A simple 4D vector class for graphics, using numpy for efficient operations.
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
Attributes:
|
|
20
|
+
x (float): The x-coordinate of the vector.
|
|
21
|
+
y (float): The y-coordinate of the vector.
|
|
22
|
+
z (float): The z-coordinate of the vector.
|
|
23
|
+
w (float): The w-coordinate of the vector.
|
|
24
|
+
"""
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
DIMENSION = 4
|
|
27
|
+
COMPONENT_NAMES = ("x", "y", "z", "w")
|
|
28
|
+
DEFAULT_VALUES = (0.0, 0.0, 0.0, 1.0)
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
__slots__ = ["_data"]
|
|
31
|
+
|
|
32
|
+
def cross(self, rhs: "Vec4") -> "Vec4":
|
|
29
33
|
"""
|
|
30
|
-
|
|
34
|
+
Cross product of two vectors a x b (4D version uses first 3 components).
|
|
35
|
+
|
|
31
36
|
Args:
|
|
32
|
-
|
|
33
|
-
Raises:
|
|
34
|
-
ValueError: If v is not a float or int.
|
|
35
|
-
"""
|
|
36
|
-
if not isinstance(v, (int, float, np.float32)):
|
|
37
|
-
raise ValueError("need float or int")
|
|
38
|
-
else:
|
|
39
|
-
setattr(self, name, v)
|
|
37
|
+
rhs (Vec4): The right-hand side vector to cross product with.
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Make the Vec3 class iterable.
|
|
44
|
-
Yields:
|
|
45
|
-
float: The x, y, and z components of the vector.
|
|
39
|
+
Returns:
|
|
40
|
+
Vec4: A new vector that is the result of the cross product.
|
|
46
41
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
result = Vec4()
|
|
43
|
+
# Cross product only makes sense for 3D vectors, use first 3 components
|
|
44
|
+
result._data[:3] = np.cross(self._data[:3], rhs._data[:3])
|
|
45
|
+
result._data[3] = 0.0
|
|
46
|
+
return result
|
|
51
47
|
|
|
52
|
-
def
|
|
48
|
+
def reflect(self, n: "Vec4") -> "Vec4":
|
|
53
49
|
"""
|
|
54
|
-
|
|
50
|
+
Reflect a vector about a normal.
|
|
51
|
+
|
|
55
52
|
Args:
|
|
56
|
-
|
|
53
|
+
n (Vec4): The normal to reflect about.
|
|
54
|
+
|
|
57
55
|
Returns:
|
|
58
|
-
|
|
59
|
-
Raises:
|
|
60
|
-
IndexError: If the index is out of range.
|
|
56
|
+
Vec4: A new vector that is the result of reflecting this vector about the normal.
|
|
61
57
|
"""
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
58
|
+
d = self.dot(n)
|
|
59
|
+
# I - 2.0 * dot(N, I) * N
|
|
60
|
+
result = Vec4()
|
|
61
|
+
result._data = self._data - 2.0 * d * n._data
|
|
62
|
+
return result
|
|
67
63
|
|
|
68
|
-
def
|
|
64
|
+
def outer(self, rhs: "Vec4"):
|
|
69
65
|
"""
|
|
70
|
-
|
|
66
|
+
Outer product of two vectors a x b.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
rhs (Vec4): The right-hand side vector to outer product with.
|
|
70
|
+
|
|
71
71
|
Returns:
|
|
72
|
-
|
|
72
|
+
Mat4: A new 4x4 matrix that is the result of the outer product.
|
|
73
73
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def __add__(self, rhs):
|
|
77
|
-
"return a+b vector addition"
|
|
78
|
-
r = Vec4()
|
|
79
|
-
r.x = self.x + rhs.x
|
|
80
|
-
r.y = self.y + rhs.y
|
|
81
|
-
r.z = self.z + rhs.z
|
|
82
|
-
r.w = self.w + rhs.w
|
|
83
|
-
return r
|
|
84
|
-
|
|
85
|
-
def __iadd__(self, rhs):
|
|
86
|
-
"return a+=b vector addition"
|
|
87
|
-
self.x += rhs.x
|
|
88
|
-
self.y += rhs.y
|
|
89
|
-
self.z += rhs.z
|
|
90
|
-
self.w += rhs.w
|
|
91
|
-
|
|
92
|
-
return self
|
|
93
|
-
|
|
94
|
-
def __sub__(self, rhs):
|
|
95
|
-
"return a+b vector addition"
|
|
96
|
-
r = Vec4()
|
|
97
|
-
r.x = self.x - rhs.x
|
|
98
|
-
r.y = self.y - rhs.y
|
|
99
|
-
r.z = self.z - rhs.z
|
|
100
|
-
r.w = self.w - rhs.w
|
|
101
|
-
return r
|
|
102
|
-
|
|
103
|
-
def __isub__(self, rhs):
|
|
104
|
-
"return a+=b vector addition"
|
|
105
|
-
self.x -= rhs.x
|
|
106
|
-
self.y -= rhs.y
|
|
107
|
-
self.z -= rhs.z
|
|
108
|
-
self.w -= rhs.w
|
|
109
|
-
return self
|
|
110
|
-
|
|
111
|
-
def set(self, x, y, z, w=1.0):
|
|
112
|
-
"set from x,y,z,w will convert to float an raise value error if problem"
|
|
113
|
-
try:
|
|
114
|
-
self.x = float(x)
|
|
115
|
-
self.y = float(y)
|
|
116
|
-
self.z = float(z)
|
|
117
|
-
self.w = float(w)
|
|
118
|
-
except ValueError:
|
|
119
|
-
logger.warning("need float values")
|
|
120
|
-
raise
|
|
74
|
+
from .mat4 import Mat4
|
|
121
75
|
|
|
122
|
-
|
|
123
|
-
|
|
76
|
+
result = Mat4()
|
|
77
|
+
result.m = np.outer(self._data, rhs._data).astype(np.float64)
|
|
78
|
+
return result
|
|
124
79
|
|
|
125
|
-
def
|
|
126
|
-
"
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def length_squared(self):
|
|
130
|
-
"square length of vector"
|
|
131
|
-
return self.x**2 + self.y**2 + self.z**2 + self.w**2
|
|
80
|
+
def __matmul__(self, rhs):
|
|
81
|
+
"""
|
|
82
|
+
Vec4 @ Mat4 matrix multiplication.
|
|
132
83
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
length = self.length()
|
|
136
|
-
try:
|
|
137
|
-
self.x /= length
|
|
138
|
-
self.y /= length
|
|
139
|
-
self.z /= length
|
|
140
|
-
self.w /= length
|
|
141
|
-
except ZeroDivisionError:
|
|
142
|
-
raise ZeroDivisionError("cannot normalize the zero vector")
|
|
143
|
-
return self
|
|
144
|
-
|
|
145
|
-
def __eq__(self, rhs):
|
|
146
|
-
"test a==b using math.isclose"
|
|
147
|
-
if not isinstance(rhs, Vec4):
|
|
148
|
-
return NotImplemented
|
|
149
|
-
return (
|
|
150
|
-
math.isclose(self.x, rhs.x)
|
|
151
|
-
and math.isclose(self.y, rhs.y)
|
|
152
|
-
and math.isclose(self.z, rhs.z)
|
|
153
|
-
and math.isclose(self.w, rhs.w)
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
def __neq__(self, rhs):
|
|
157
|
-
"test a!=b using math.isclose"
|
|
158
|
-
if not isinstance(rhs, Vec4):
|
|
159
|
-
return NotImplemented
|
|
160
|
-
return not (
|
|
161
|
-
math.isclose(self.x, rhs.x)
|
|
162
|
-
and math.isclose(self.y, rhs.y)
|
|
163
|
-
and math.isclose(self.z, rhs.z)
|
|
164
|
-
and math.isclose(self.w, rhs.w)
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
def __neg__(self):
|
|
168
|
-
self.x = -self.x
|
|
169
|
-
self.y = -self.y
|
|
170
|
-
self.z = -self.z
|
|
171
|
-
self.w = -self.w
|
|
172
|
-
return self
|
|
173
|
-
|
|
174
|
-
def __mul__(self, rhs):
|
|
175
|
-
if isinstance(rhs, (float, int)):
|
|
176
|
-
"Vec4 * scalar multiplication"
|
|
177
|
-
return Vec4(self.x * rhs, self.y * rhs, self.z * rhs, self.w * rhs)
|
|
178
|
-
else:
|
|
179
|
-
raise ValueError
|
|
180
|
-
|
|
181
|
-
def __rmul__(self, rhs):
|
|
182
|
-
return self * rhs
|
|
183
|
-
|
|
184
|
-
def __truediv__(self, rhs):
|
|
185
|
-
if isinstance(rhs, (float, int)):
|
|
186
|
-
return Vec4(self.x / rhs, self.y / rhs, self.z / rhs, self.w / rhs)
|
|
187
|
-
elif isinstance(rhs, Vec4):
|
|
188
|
-
return Vec4(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z, self.w / rhs.w)
|
|
189
|
-
else:
|
|
190
|
-
raise ValueError(f"can only do piecewise division with a scalar {rhs=}")
|
|
84
|
+
Args:
|
|
85
|
+
rhs (Mat4): The matrix to multiply by.
|
|
191
86
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
self.x * rhs.m[0][1] + self.y * rhs.m[1][1] + self.z * rhs.m[2][1] + self.w * rhs.m[3][1],
|
|
197
|
-
self.x * rhs.m[0][2] + self.y * rhs.m[1][2] + self.z * rhs.m[2][2] + self.w * rhs.m[3][2],
|
|
198
|
-
self.x * rhs.m[0][3] + self.y * rhs.m[1][3] + self.z * rhs.m[2][3] + self.w * rhs.m[3][3],
|
|
199
|
-
)
|
|
87
|
+
Returns:
|
|
88
|
+
Vec4: A new vector that is the result of multiplying this vector by the matrix.
|
|
89
|
+
"""
|
|
90
|
+
return Vec4(*self._data @ rhs.m)
|
|
200
91
|
|
|
201
|
-
def
|
|
202
|
-
"
|
|
203
|
-
|
|
92
|
+
def set(self, *args: float) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Set the x,y,z,w values of the vector.
|
|
204
95
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
return f"[{self.x},{self.y},{self.z},{self.w}]"
|
|
96
|
+
Args:
|
|
97
|
+
*args: Component values (x, y, z, w). w defaults to 1.0 if not provided.
|
|
208
98
|
|
|
209
|
-
|
|
210
|
-
|
|
99
|
+
Raises:
|
|
100
|
+
ValueError: If wrong number of arguments or they are not floats.
|
|
101
|
+
"""
|
|
102
|
+
if len(args) == 3:
|
|
103
|
+
# Allow (x, y, z) with default w=1.0 for backward compatibility
|
|
104
|
+
args = args + (1.0,)
|
|
105
|
+
elif len(args) != 4:
|
|
106
|
+
raise ValueError(f"Vec4.set requires 3 or 4 arguments, got {len(args)}")
|
|
211
107
|
|
|
212
|
-
|
|
213
|
-
|
|
108
|
+
try:
|
|
109
|
+
for i in range(4):
|
|
110
|
+
self._data[i] = float(args[i])
|
|
111
|
+
except ValueError:
|
|
112
|
+
raise ValueError(f"Vec4.set {args=} all need to be float")
|
|
214
113
|
|
|
114
|
+
def __repr__(self) -> str:
|
|
115
|
+
"""Object representation for debugging."""
|
|
116
|
+
return f"Vec4 [{self._data[0]},{self._data[1]},{self._data[2]},{self._data[3]}]"
|
|
215
117
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def getter(self):
|
|
219
|
-
return getattr(self, f"_{attr_name}")
|
|
118
|
+
def __str__(self) -> str:
|
|
119
|
+
"""String representation of the vector."""
|
|
220
120
|
|
|
221
|
-
|
|
222
|
-
|
|
121
|
+
# Format numbers without decimal point if they're whole numbers
|
|
122
|
+
def fmt(val):
|
|
123
|
+
return str(int(val)) if val == int(val) else str(val)
|
|
223
124
|
|
|
224
|
-
|
|
125
|
+
return f"[{fmt(self._data[0])},{fmt(self._data[1])},{fmt(self._data[2])},{fmt(self._data[3])}]"
|
|
225
126
|
|
|
226
127
|
|
|
227
|
-
#
|
|
228
|
-
|
|
229
|
-
setattr(Vec4, attr, _create_property(attr))
|
|
128
|
+
# Add properties for x, y, z, w components
|
|
129
|
+
_create_properties(Vec4)
|
ncca/ngl/vec4_array.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
A container for ngl.Vec4 objects that mimics some of the behavior of a std::vector
|
|
3
|
+
Optimized for graphics APIs with contiguous numpy storage
|
|
3
4
|
"""
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
@@ -9,52 +10,67 @@ from .vec4 import Vec4
|
|
|
9
10
|
|
|
10
11
|
class Vec4Array:
|
|
11
12
|
"""
|
|
12
|
-
A class to hold
|
|
13
|
+
A class to hold Vec4 data in contiguous memory for efficient GPU transfer.
|
|
14
|
+
Internally uses a numpy array of shape (N, 4) for optimal performance.
|
|
13
15
|
"""
|
|
14
16
|
|
|
15
17
|
def __init__(self, values=None):
|
|
16
18
|
"""
|
|
17
|
-
Initializes the
|
|
19
|
+
Initializes the Vec4Array.
|
|
18
20
|
|
|
19
21
|
Args:
|
|
20
22
|
values (iterable | int, optional): An iterable of Vec4 objects or an integer.
|
|
21
|
-
If an integer, the array is initialized with that many default
|
|
22
|
-
If an iterable, it's initialized with the
|
|
23
|
+
If an integer, the array is initialized with that many default Vec4s.
|
|
24
|
+
If an iterable, it's initialized with the Vec4s from the iterable.
|
|
23
25
|
Defaults to None (an empty array).
|
|
24
26
|
"""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
if values is None:
|
|
28
|
+
# Empty array - start with shape (0, 4)
|
|
29
|
+
self._data = np.zeros((0, 4), dtype=np.float64)
|
|
30
|
+
elif isinstance(values, int):
|
|
31
|
+
# Initialize N default Vec4s (0, 0, 0, 1)
|
|
32
|
+
self._data = np.zeros((values, 4), dtype=np.float64)
|
|
33
|
+
self._data[:, 3] = 1.0 # Set w component to 1.0
|
|
34
|
+
else:
|
|
35
|
+
# Initialize from iterable of Vec4 objects
|
|
36
|
+
vec_list = []
|
|
37
|
+
for v in values:
|
|
38
|
+
if not isinstance(v, Vec4):
|
|
39
|
+
raise TypeError("All elements must be of type Vec4")
|
|
40
|
+
vec_list.append([v.x, v.y, v.z, v.w])
|
|
41
|
+
self._data = np.array(vec_list, dtype=np.float64)
|
|
34
42
|
|
|
35
43
|
def __getitem__(self, index):
|
|
36
44
|
"""
|
|
37
45
|
Get the Vec4 at the specified index.
|
|
38
46
|
|
|
39
47
|
Args:
|
|
40
|
-
index (int): The index of the element.
|
|
48
|
+
index (int | slice): The index or slice of the element(s).
|
|
41
49
|
|
|
42
50
|
Returns:
|
|
43
51
|
Vec4: The Vec4 object at the given index.
|
|
44
52
|
"""
|
|
45
|
-
|
|
53
|
+
if isinstance(index, slice):
|
|
54
|
+
# Return a new Vec4Array with sliced data
|
|
55
|
+
result = Vec4Array()
|
|
56
|
+
result._data = self._data[index].copy()
|
|
57
|
+
return result
|
|
58
|
+
else:
|
|
59
|
+
# Return a single Vec4
|
|
60
|
+
row = self._data[index]
|
|
61
|
+
return Vec4(row[0], row[1], row[2], row[3])
|
|
46
62
|
|
|
47
63
|
def __setitem__(self, index, value):
|
|
48
64
|
"""
|
|
49
|
-
Set the
|
|
65
|
+
Set the Vec4 at the specified index.
|
|
50
66
|
|
|
51
67
|
Args:
|
|
52
68
|
index (int): The index of the element to set.
|
|
53
|
-
value (Vec4): The new
|
|
69
|
+
value (Vec4): The new Vec4 object.
|
|
54
70
|
"""
|
|
55
71
|
if not isinstance(value, Vec4):
|
|
56
72
|
raise TypeError("Only Vec4 objects can be assigned")
|
|
57
|
-
self._data[index] = value
|
|
73
|
+
self._data[index] = [value.x, value.y, value.z, value.w]
|
|
58
74
|
|
|
59
75
|
def __len__(self):
|
|
60
76
|
"""
|
|
@@ -64,9 +80,25 @@ class Vec4Array:
|
|
|
64
80
|
|
|
65
81
|
def __iter__(self):
|
|
66
82
|
"""
|
|
67
|
-
Return an iterator
|
|
83
|
+
Return an iterator that yields Vec4 objects.
|
|
68
84
|
"""
|
|
69
|
-
|
|
85
|
+
for i in range(len(self._data)):
|
|
86
|
+
row = self._data[i]
|
|
87
|
+
yield Vec4(row[0], row[1], row[2], row[3])
|
|
88
|
+
|
|
89
|
+
def __eq__(self, other):
|
|
90
|
+
"""
|
|
91
|
+
Compare two Vec4Array instances for equality.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
other: Another Vec4Array instance to compare with.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
bool: True if the arrays contain the same data, False otherwise.
|
|
98
|
+
"""
|
|
99
|
+
if not isinstance(other, Vec4Array):
|
|
100
|
+
return NotImplemented
|
|
101
|
+
return np.array_equal(self._data, other._data)
|
|
70
102
|
|
|
71
103
|
def append(self, value):
|
|
72
104
|
"""
|
|
@@ -77,7 +109,8 @@ class Vec4Array:
|
|
|
77
109
|
"""
|
|
78
110
|
if not isinstance(value, Vec4):
|
|
79
111
|
raise TypeError("Only Vec4 objects can be appended")
|
|
80
|
-
|
|
112
|
+
new_row = np.array([[value.x, value.y, value.z, value.w]], dtype=np.float64)
|
|
113
|
+
self._data = np.vstack([self._data, new_row])
|
|
81
114
|
|
|
82
115
|
def extend(self, values):
|
|
83
116
|
"""
|
|
@@ -88,7 +121,12 @@ class Vec4Array:
|
|
|
88
121
|
"""
|
|
89
122
|
if not all(isinstance(v, Vec4) for v in values):
|
|
90
123
|
raise TypeError("All elements must be of type Vec4")
|
|
91
|
-
|
|
124
|
+
|
|
125
|
+
new_rows = np.array([[v.x, v.y, v.z, v.w] for v in values], dtype=np.float64)
|
|
126
|
+
if len(self._data) == 0:
|
|
127
|
+
self._data = new_rows
|
|
128
|
+
else:
|
|
129
|
+
self._data = np.vstack([self._data, new_rows])
|
|
92
130
|
|
|
93
131
|
def to_list(self):
|
|
94
132
|
"""
|
|
@@ -97,22 +135,35 @@ class Vec4Array:
|
|
|
97
135
|
Returns:
|
|
98
136
|
list: A list of x, y, z, w components concatenated.
|
|
99
137
|
"""
|
|
100
|
-
return
|
|
138
|
+
return self._data.flatten().tolist()
|
|
101
139
|
|
|
102
140
|
def to_numpy(self):
|
|
103
141
|
"""
|
|
104
142
|
Convert the array of Vec4 objects to a numpy array.
|
|
143
|
+
This is the primary method for GPU data transfer.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
numpy.ndarray: A float32 numpy array of shape (N*4,) for GPU transfer.
|
|
147
|
+
"""
|
|
148
|
+
return self._data.astype(np.float32).flatten()
|
|
149
|
+
|
|
150
|
+
def get_array(self):
|
|
151
|
+
"""
|
|
152
|
+
Get the underlying numpy array in shape (N, 4).
|
|
153
|
+
Useful for vectorized operations.
|
|
105
154
|
|
|
106
155
|
Returns:
|
|
107
|
-
numpy.ndarray:
|
|
156
|
+
numpy.ndarray: The internal float64 array of shape (N, 4).
|
|
108
157
|
"""
|
|
109
|
-
return
|
|
158
|
+
return self._data
|
|
110
159
|
|
|
111
160
|
def __repr__(self):
|
|
112
|
-
|
|
161
|
+
vec_list = [Vec4(row[0], row[1], row[2], row[3]) for row in self._data]
|
|
162
|
+
return f"Vec4Array({vec_list!r})"
|
|
113
163
|
|
|
114
164
|
def __str__(self):
|
|
115
|
-
|
|
165
|
+
vec_list = [Vec4(row[0], row[1], row[2], row[3]) for row in self._data]
|
|
166
|
+
return str(vec_list)
|
|
116
167
|
|
|
117
168
|
def sizeof(self):
|
|
118
169
|
"""
|