ncca-ngl 0.1.1__py3-none-any.whl → 0.1.2__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/Primitives.npz +0 -0
- ncca/ngl/PrimData/pack_arrays.py +20 -0
- ncca/ngl/__init__.py +100 -0
- ncca/ngl/abstract_vao.py +85 -0
- ncca/ngl/base_mesh.py +170 -0
- ncca/ngl/base_mesh.pyi +11 -0
- ncca/ngl/bbox.py +224 -0
- ncca/ngl/bezier_curve.py +75 -0
- ncca/ngl/first_person_camera.py +174 -0
- ncca/ngl/image.py +94 -0
- ncca/ngl/log.py +44 -0
- ncca/ngl/mat2.py +128 -0
- ncca/ngl/mat3.py +466 -0
- ncca/ngl/mat4.py +456 -0
- ncca/ngl/multi_buffer_vao.py +49 -0
- ncca/ngl/obj.py +416 -0
- ncca/ngl/plane.py +47 -0
- ncca/ngl/primitives.py +706 -0
- ncca/ngl/pyside_event_handling_mixin.py +318 -0
- ncca/ngl/quaternion.py +112 -0
- ncca/ngl/random.py +167 -0
- ncca/ngl/shader.py +229 -0
- ncca/ngl/shader_lib.py +536 -0
- ncca/ngl/shader_program.py +816 -0
- ncca/ngl/shaders/checker_fragment.glsl +35 -0
- ncca/ngl/shaders/checker_vertex.glsl +19 -0
- ncca/ngl/shaders/colour_fragment.glsl +8 -0
- ncca/ngl/shaders/colour_vertex.glsl +11 -0
- ncca/ngl/shaders/diffuse_fragment.glsl +21 -0
- ncca/ngl/shaders/diffuse_vertex.glsl +24 -0
- ncca/ngl/shaders/text_fragment.glsl +10 -0
- ncca/ngl/shaders/text_geometry.glsl +53 -0
- ncca/ngl/shaders/text_vertex.glsl +18 -0
- ncca/ngl/simple_index_vao.py +65 -0
- ncca/ngl/simple_vao.py +42 -0
- ncca/ngl/text.py +346 -0
- ncca/ngl/texture.py +75 -0
- ncca/ngl/transform.py +95 -0
- ncca/ngl/util.py +128 -0
- ncca/ngl/vao_factory.py +34 -0
- ncca/ngl/vec2.py +350 -0
- ncca/ngl/vec2_array.py +106 -0
- ncca/ngl/vec3.py +401 -0
- ncca/ngl/vec3_array.py +110 -0
- ncca/ngl/vec4.py +229 -0
- ncca/ngl/vec4_array.py +106 -0
- {ncca_ngl-0.1.1.dist-info → ncca_ngl-0.1.2.dist-info}/METADATA +10 -9
- ncca_ngl-0.1.2.dist-info/RECORD +51 -0
- {ncca_ngl-0.1.1.dist-info → ncca_ngl-0.1.2.dist-info}/WHEEL +2 -1
- ncca_ngl-0.1.2.dist-info/top_level.txt +1 -0
- ncca_ngl-0.1.1.dist-info/RECORD +0 -4
- {ncca_ngl-0.1.1.dist-info → ncca_ngl-0.1.2.dist-info}/licenses/LICENSE.txt +0 -0
ncca/ngl/vec2_array.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A container for ngl.Vec2 objects that mimics some of the behavior of a std::vector
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .vec2 import Vec2
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Vec2Array:
|
|
11
|
+
"""
|
|
12
|
+
A class to hold a list of Vec2 objects and perform operations on them.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, values=None):
|
|
16
|
+
"""
|
|
17
|
+
Initializes the Vec2Array.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
values (iterable, optional): An iterable of Vec2 objects. Defaults to None.
|
|
21
|
+
"""
|
|
22
|
+
self._data = []
|
|
23
|
+
if values is not None:
|
|
24
|
+
for v in values:
|
|
25
|
+
if not isinstance(v, Vec2):
|
|
26
|
+
raise TypeError("All elements must be of type Vec2")
|
|
27
|
+
self._data.append(v)
|
|
28
|
+
|
|
29
|
+
def __getitem__(self, index):
|
|
30
|
+
"""
|
|
31
|
+
Get the Vec2 at the specified index.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
index (int): The index of the element.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Vec2: The Vec2 object at the given index.
|
|
38
|
+
"""
|
|
39
|
+
return self._data[index]
|
|
40
|
+
|
|
41
|
+
def __len__(self):
|
|
42
|
+
"""
|
|
43
|
+
Return the number of elements in the array.
|
|
44
|
+
"""
|
|
45
|
+
return len(self._data)
|
|
46
|
+
|
|
47
|
+
def __iter__(self):
|
|
48
|
+
"""
|
|
49
|
+
Return an iterator for the array.
|
|
50
|
+
"""
|
|
51
|
+
return iter(self._data)
|
|
52
|
+
|
|
53
|
+
def append(self, value):
|
|
54
|
+
"""
|
|
55
|
+
Append a Vec2 object to the array.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
value (Vec2): The Vec2 object to append.
|
|
59
|
+
"""
|
|
60
|
+
if not isinstance(value, Vec2):
|
|
61
|
+
raise TypeError("Only Vec2 objects can be appended")
|
|
62
|
+
self._data.append(value)
|
|
63
|
+
|
|
64
|
+
def extend(self, values):
|
|
65
|
+
"""
|
|
66
|
+
Extend the array with a list of Vec2 objects.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
values (list): A list of Vec2 objects to extend.
|
|
70
|
+
"""
|
|
71
|
+
if not all(isinstance(v, Vec2) for v in values):
|
|
72
|
+
raise TypeError("All elements must be of type Vec2")
|
|
73
|
+
self._data.extend(values)
|
|
74
|
+
|
|
75
|
+
def to_list(self):
|
|
76
|
+
"""
|
|
77
|
+
Convert the array of Vec2 objects to a single flat list of floats.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
list: A list of x, y components concatenated.
|
|
81
|
+
"""
|
|
82
|
+
return [comp for vec in self._data for comp in vec]
|
|
83
|
+
|
|
84
|
+
def to_numpy(self):
|
|
85
|
+
"""
|
|
86
|
+
Convert the array of Vec2 objects to a numpy array.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
numpy.ndarray: A numpy array of the vector data.
|
|
90
|
+
"""
|
|
91
|
+
return np.array(self.to_list(), dtype=np.float32)
|
|
92
|
+
|
|
93
|
+
def __repr__(self):
|
|
94
|
+
return f"Vec2Array({self._data!r})"
|
|
95
|
+
|
|
96
|
+
def __str__(self):
|
|
97
|
+
return str(self._data)
|
|
98
|
+
|
|
99
|
+
def sizeof(self):
|
|
100
|
+
"""
|
|
101
|
+
Return the size of the array in bytes.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
int: The size of the array in bytes.
|
|
105
|
+
"""
|
|
106
|
+
return len(self._data) * Vec2.sizeof()
|
ncca/ngl/vec3.py
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simple float only Vec3 class for 3D graphics, very similar to the pyngl ones
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import ctypes
|
|
6
|
+
import math
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from .util import clamp
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Vec3:
|
|
14
|
+
"""
|
|
15
|
+
A simple 3D vector class for 3D graphics, I use slots to fix the attributes to x,y,z
|
|
16
|
+
Attributes:
|
|
17
|
+
x (float): The x-coordinate of the vector.
|
|
18
|
+
y (float): The y-coordinate of the vector.
|
|
19
|
+
z (float): The z-coordinate of the vector.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
__slots__ = ["_x", "_y", "_z"] # fix the attributes to x,y,z
|
|
24
|
+
|
|
25
|
+
def __init__(self, x=0.0, y=0.0, z=0.0):
|
|
26
|
+
"""
|
|
27
|
+
Initializes a new instance of the Vec3 class.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
x (float, optional): The x-coordinate of the vector. Defaults to 0.0.
|
|
31
|
+
y (float, optional): The y-coordinate of the vector. Defaults to 0.0.
|
|
32
|
+
z (float, optional): The z-coordinate of the vector. Defaults to 0.0.
|
|
33
|
+
"""
|
|
34
|
+
self._x = x # x component of vector : float
|
|
35
|
+
self._y = y # y component of vector : float
|
|
36
|
+
self._z = z # z component of vector : float
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def sizeof(cls):
|
|
40
|
+
return 3 * ctypes.sizeof(ctypes.c_float)
|
|
41
|
+
|
|
42
|
+
def __iter__(self):
|
|
43
|
+
"""
|
|
44
|
+
Make the Vec3 class iterable.
|
|
45
|
+
Yields:
|
|
46
|
+
float: The x, y, and z components of the vector.
|
|
47
|
+
"""
|
|
48
|
+
yield self.x
|
|
49
|
+
yield self.y
|
|
50
|
+
yield self.z
|
|
51
|
+
|
|
52
|
+
def __getitem__(self, index):
|
|
53
|
+
"""
|
|
54
|
+
Get the component of the vector at the given index.
|
|
55
|
+
Args:
|
|
56
|
+
index (int): The index of the component (0 for x, 1 for y, 2 for z).
|
|
57
|
+
Returns:
|
|
58
|
+
float: The value of the component at the given index.
|
|
59
|
+
Raises:
|
|
60
|
+
IndexError: If the index is out of range.
|
|
61
|
+
"""
|
|
62
|
+
components = [self.x, self.y, self.z]
|
|
63
|
+
try:
|
|
64
|
+
return components[index]
|
|
65
|
+
except IndexError:
|
|
66
|
+
raise IndexError("Index out of range. Valid indices are 0, 1, and 2.")
|
|
67
|
+
|
|
68
|
+
def _validate_and_set(self, v, name):
|
|
69
|
+
"""
|
|
70
|
+
check if v is a float or int
|
|
71
|
+
Args:
|
|
72
|
+
v (number): The value to check.
|
|
73
|
+
Raises:
|
|
74
|
+
ValueError: If v is not a float or int.
|
|
75
|
+
"""
|
|
76
|
+
if not isinstance(v, (int, float)):
|
|
77
|
+
raise ValueError("need float or int")
|
|
78
|
+
else:
|
|
79
|
+
setattr(self, name, v)
|
|
80
|
+
|
|
81
|
+
def clone(self) -> "Vec3":
|
|
82
|
+
"""
|
|
83
|
+
Create a clone of the current vector.
|
|
84
|
+
Returns:
|
|
85
|
+
Vec3: A new instance of Vec3 with the same x, y, and z values.
|
|
86
|
+
"""
|
|
87
|
+
return Vec3(self.x, self.y, self.z)
|
|
88
|
+
|
|
89
|
+
def __add__(self, rhs):
|
|
90
|
+
"""
|
|
91
|
+
vector addition a+b
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
rhs (Vec3): The right-hand side vector to add.
|
|
95
|
+
Returns:
|
|
96
|
+
Vec3: A new vector that is the result of adding this vector and the rhs vector.
|
|
97
|
+
"""
|
|
98
|
+
r = Vec3()
|
|
99
|
+
r.x = self.x + rhs.x
|
|
100
|
+
r.y = self.y + rhs.y
|
|
101
|
+
r.z = self.z + rhs.z
|
|
102
|
+
return r
|
|
103
|
+
|
|
104
|
+
def __iadd__(self, rhs):
|
|
105
|
+
"""
|
|
106
|
+
vector addition a+=b
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
rhs (Vec3): The right-hand side vector to add.
|
|
110
|
+
Returns:
|
|
111
|
+
Vec3: returns this vector after adding the rhs vector.
|
|
112
|
+
"""
|
|
113
|
+
self.x += rhs.x
|
|
114
|
+
self.y += rhs.y
|
|
115
|
+
self.z += rhs.z
|
|
116
|
+
return self
|
|
117
|
+
|
|
118
|
+
def __sub__(self, rhs):
|
|
119
|
+
"""
|
|
120
|
+
vector subtraction a-b
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
rhs (Vec3): The right-hand side vector to subtract.
|
|
124
|
+
Returns:
|
|
125
|
+
Vec3: A new vector that is the result of subtracting this vector and the rhs vector.
|
|
126
|
+
"""
|
|
127
|
+
r = Vec3()
|
|
128
|
+
r.x = self.x - rhs.x
|
|
129
|
+
r.y = self.y - rhs.y
|
|
130
|
+
r.z = self.z - rhs.z
|
|
131
|
+
return r
|
|
132
|
+
|
|
133
|
+
def __isub__(self, rhs):
|
|
134
|
+
"""
|
|
135
|
+
vector subtraction a-=b
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
rhs (Vec3): The right-hand side vector to add.
|
|
139
|
+
Returns:
|
|
140
|
+
Vec3: returns this vector after subtracting the rhs vector.
|
|
141
|
+
"""
|
|
142
|
+
self.x -= rhs.x
|
|
143
|
+
self.y -= rhs.y
|
|
144
|
+
self.z -= rhs.z
|
|
145
|
+
return self
|
|
146
|
+
|
|
147
|
+
def __eq__(self, rhs):
|
|
148
|
+
"""
|
|
149
|
+
vector comparison a==b using math.isclose not we only compare to 6 decimal places
|
|
150
|
+
Args:
|
|
151
|
+
rhs (Vec3): The right-hand side vector to compare.
|
|
152
|
+
Returns:
|
|
153
|
+
bool: True if the vectors are close, False otherwise.
|
|
154
|
+
NotImplemented: If the right-hand side is not a Vec3.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
if not isinstance(rhs, Vec3):
|
|
158
|
+
return NotImplemented
|
|
159
|
+
return math.isclose(self.x, rhs.x) and math.isclose(self.y, rhs.y) and math.isclose(self.z, rhs.z)
|
|
160
|
+
|
|
161
|
+
def __neq__(self, rhs):
|
|
162
|
+
"""
|
|
163
|
+
vector comparison a!=b using math.isclose not we only compare to 6 decimal places
|
|
164
|
+
Args:
|
|
165
|
+
rhs (Vec3): The right-hand side vector to compare.
|
|
166
|
+
Returns:
|
|
167
|
+
bool: True if the vectors are not close, False otherwise.
|
|
168
|
+
NotImplemented: If the right-hand side is not a Vec3.
|
|
169
|
+
"""
|
|
170
|
+
if not isinstance(rhs, Vec3):
|
|
171
|
+
return NotImplemented
|
|
172
|
+
return not (math.isclose(self.x, rhs.x) and math.isclose(self.y, rhs.y) and math.isclose(self.z, rhs.z))
|
|
173
|
+
|
|
174
|
+
def __neg__(self):
|
|
175
|
+
"""
|
|
176
|
+
negate a vector -a
|
|
177
|
+
"""
|
|
178
|
+
self.x = -self.x
|
|
179
|
+
self.y = -self.y
|
|
180
|
+
self.z = -self.z
|
|
181
|
+
return self
|
|
182
|
+
|
|
183
|
+
def set(self, x, y, z):
|
|
184
|
+
"""
|
|
185
|
+
set the x,y,z values of the vector
|
|
186
|
+
Args:
|
|
187
|
+
x (float): The x-coordinate of the vector.
|
|
188
|
+
y (float): The y-coordinate of the vector.
|
|
189
|
+
z (float): The z-coordinate of the vector.
|
|
190
|
+
Raises :
|
|
191
|
+
ValueError: if x,y,z are not float
|
|
192
|
+
"""
|
|
193
|
+
try:
|
|
194
|
+
self.x = float(x)
|
|
195
|
+
self.y = float(y)
|
|
196
|
+
self.z = float(z)
|
|
197
|
+
except ValueError:
|
|
198
|
+
raise ValueError(f"Vec3.set {x=} {y=} {z=} all need to be float")
|
|
199
|
+
|
|
200
|
+
def dot(self, rhs):
|
|
201
|
+
"""
|
|
202
|
+
dot product of two vectors a.b
|
|
203
|
+
Args:
|
|
204
|
+
rhs (Vec3): The right-hand side vector to dot product with.
|
|
205
|
+
"""
|
|
206
|
+
return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
|
|
207
|
+
|
|
208
|
+
def length(self):
|
|
209
|
+
"""
|
|
210
|
+
length of vector
|
|
211
|
+
Returns:
|
|
212
|
+
float: The length of the vector.
|
|
213
|
+
"""
|
|
214
|
+
return math.sqrt(self.x**2 + self.y**2 + self.z**2)
|
|
215
|
+
|
|
216
|
+
def length_squared(self):
|
|
217
|
+
"""
|
|
218
|
+
length of vector squared sometimes used to avoid the sqrt for performance
|
|
219
|
+
Returns:
|
|
220
|
+
float: The length of the vector squared
|
|
221
|
+
"""
|
|
222
|
+
return self.x**2 + self.y**2 + self.z**2
|
|
223
|
+
|
|
224
|
+
def inner(self, rhs):
|
|
225
|
+
"""
|
|
226
|
+
inner product of two vectors a.b
|
|
227
|
+
Args:
|
|
228
|
+
rhs (Vec3): The right-hand side vector to inner product with.
|
|
229
|
+
Returns:
|
|
230
|
+
float: The inner product of the two vectors.
|
|
231
|
+
"""
|
|
232
|
+
return (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z)
|
|
233
|
+
|
|
234
|
+
def null(self):
|
|
235
|
+
"""
|
|
236
|
+
set the vector to zero
|
|
237
|
+
"""
|
|
238
|
+
self.x = 0.0
|
|
239
|
+
self.y = 0.0
|
|
240
|
+
self.z = 0.0
|
|
241
|
+
|
|
242
|
+
def cross(self, rhs):
|
|
243
|
+
"""
|
|
244
|
+
cross product of two vectors a x b
|
|
245
|
+
Args:
|
|
246
|
+
rhs (Vec3): The right-hand side vector to cross product with.
|
|
247
|
+
Returns:
|
|
248
|
+
Vec3: A new vector that is the result of the cross product.
|
|
249
|
+
"""
|
|
250
|
+
return Vec3(
|
|
251
|
+
self.y * rhs.z - self.z * rhs.y,
|
|
252
|
+
self.z * rhs.x - self.x * rhs.z,
|
|
253
|
+
self.x * rhs.y - self.y * rhs.x,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def normalize(self):
|
|
257
|
+
"""
|
|
258
|
+
normalize the vector to unit length
|
|
259
|
+
Returns:
|
|
260
|
+
Vec3: A new vector that is the result of normalizing this vector.
|
|
261
|
+
Raises:
|
|
262
|
+
ZeroDivisionError: If the length of the vector is zero.
|
|
263
|
+
"""
|
|
264
|
+
vector_length = self.length()
|
|
265
|
+
try:
|
|
266
|
+
self.x /= vector_length
|
|
267
|
+
self.y /= vector_length
|
|
268
|
+
self.z /= vector_length
|
|
269
|
+
except ZeroDivisionError:
|
|
270
|
+
raise ZeroDivisionError(
|
|
271
|
+
f"Vec3.normalize {vector_length} length is zero most likely calling normalize on a zero vector"
|
|
272
|
+
)
|
|
273
|
+
return self
|
|
274
|
+
|
|
275
|
+
def reflect(self, n):
|
|
276
|
+
"""
|
|
277
|
+
reflect a vector about a normal
|
|
278
|
+
Args:
|
|
279
|
+
n (Vec3): The normal to reflect about.
|
|
280
|
+
Returns:
|
|
281
|
+
Vec3: A new vector that is the result of reflecting this vector about the normal.
|
|
282
|
+
"""
|
|
283
|
+
d = self.dot(n)
|
|
284
|
+
# I - 2.0 * dot(N, I) * N
|
|
285
|
+
return Vec3(self.x - 2.0 * d * n.x, self.y - 2.0 * d * n.y, self.z - 2.0 * d * n.z)
|
|
286
|
+
|
|
287
|
+
def clamp(self, low, high):
|
|
288
|
+
"""
|
|
289
|
+
clamp the vector to a range
|
|
290
|
+
Args:
|
|
291
|
+
low (float): The low end of the range.
|
|
292
|
+
high (float): The high end of the range.
|
|
293
|
+
|
|
294
|
+
"""
|
|
295
|
+
self.x = clamp(self.x, low, high)
|
|
296
|
+
self.y = clamp(self.y, low, high)
|
|
297
|
+
self.z = clamp(self.z, low, high)
|
|
298
|
+
|
|
299
|
+
def __repr__(self):
|
|
300
|
+
"object representation for debugging"
|
|
301
|
+
return f"Vec3 [{self.x},{self.y},{self.z}]"
|
|
302
|
+
|
|
303
|
+
def __str__(self):
|
|
304
|
+
"object representation for debugging"
|
|
305
|
+
return f"[{self.x},{self.y},{self.z}]"
|
|
306
|
+
|
|
307
|
+
def outer(self, rhs):
|
|
308
|
+
"""
|
|
309
|
+
outer product of two vectors a x b
|
|
310
|
+
Args:
|
|
311
|
+
rhs (Vec3): The right-hand side vector to outer product with.
|
|
312
|
+
Returns:
|
|
313
|
+
Mat3: A new 3x3 matrix that is the result of the outer product.
|
|
314
|
+
"""
|
|
315
|
+
from .mat3 import Mat3
|
|
316
|
+
|
|
317
|
+
return Mat3.from_list([
|
|
318
|
+
[self.x * rhs.x, self.x * rhs.y, self.x * rhs.z],
|
|
319
|
+
[self.y * rhs.x, self.y * rhs.y, self.y * rhs.z],
|
|
320
|
+
[self.z * rhs.x, self.z * rhs.y, self.z * rhs.z],
|
|
321
|
+
])
|
|
322
|
+
|
|
323
|
+
def __mul__(self, rhs):
|
|
324
|
+
"""
|
|
325
|
+
piecewise scalar multiplication
|
|
326
|
+
Args:
|
|
327
|
+
rhs (float): The scalar to multiply by.
|
|
328
|
+
Returns:
|
|
329
|
+
Vec3: A new vector that is the result of multiplying this vector by the scalar.
|
|
330
|
+
Raises:
|
|
331
|
+
ValueError: If the right-hand side is not a float.
|
|
332
|
+
"""
|
|
333
|
+
if isinstance(rhs, (float, int)):
|
|
334
|
+
return Vec3(self.x * rhs, self.y * rhs, self.z * rhs)
|
|
335
|
+
else:
|
|
336
|
+
raise ValueError(f"can only do piecewise multiplication with a scalar {rhs=}")
|
|
337
|
+
|
|
338
|
+
def __rmul__(self, rhs):
|
|
339
|
+
"""
|
|
340
|
+
piecewise scalar multiplication
|
|
341
|
+
Args:
|
|
342
|
+
rhs (float): The scalar to multiply by.
|
|
343
|
+
Returns:
|
|
344
|
+
Vec3: A new vector that is the result of multiplying this vector by the scalar.
|
|
345
|
+
Raises:
|
|
346
|
+
ValueError: If the right-hand side is not a float.
|
|
347
|
+
"""
|
|
348
|
+
return self * rhs
|
|
349
|
+
|
|
350
|
+
def __truediv__(self, rhs):
|
|
351
|
+
"""
|
|
352
|
+
piecewise scalar division
|
|
353
|
+
Args:
|
|
354
|
+
rhs (float): The scalar to divide by.
|
|
355
|
+
Returns:
|
|
356
|
+
Vec3: A new vector that is the result of dividing this vector by the scalar.
|
|
357
|
+
Raises:
|
|
358
|
+
ValueError: If the right-hand side is not a float.
|
|
359
|
+
"""
|
|
360
|
+
if isinstance(rhs, (float, int)):
|
|
361
|
+
return Vec3(self.x / rhs, self.y / rhs, self.z / rhs)
|
|
362
|
+
elif isinstance(rhs, Vec3):
|
|
363
|
+
return Vec3(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
|
|
364
|
+
else:
|
|
365
|
+
raise ValueError(f"can only do piecewise division with a scalar {rhs=}")
|
|
366
|
+
|
|
367
|
+
def __matmul__(self, rhs):
|
|
368
|
+
"""
|
|
369
|
+
"Vec3 @ Mat3 matrix multiplication"
|
|
370
|
+
Args:
|
|
371
|
+
rhs (Mat3): The matrix to multiply by.
|
|
372
|
+
Returns:
|
|
373
|
+
Vec3: A new vector that is the result of multiplying this vector by the matrix.
|
|
374
|
+
"""
|
|
375
|
+
return Vec3(
|
|
376
|
+
self.x * rhs.m[0][0] + self.y * rhs.m[1][0] + self.z * rhs.m[2][0],
|
|
377
|
+
self.x * rhs.m[0][1] + self.y * rhs.m[1][1] + self.z * rhs.m[2][1],
|
|
378
|
+
self.x * rhs.m[0][2] + self.y * rhs.m[1][2] + self.z * rhs.m[2][2],
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
def to_list(self):
|
|
382
|
+
return [self.x, self.y, self.z]
|
|
383
|
+
|
|
384
|
+
def to_numpy(self):
|
|
385
|
+
return np.array([self.x, self.y, self.z])
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
# Helper function to create properties
|
|
389
|
+
def _create_property(attr_name):
|
|
390
|
+
def getter(self):
|
|
391
|
+
return getattr(self, f"_{attr_name}")
|
|
392
|
+
|
|
393
|
+
def setter(self, value):
|
|
394
|
+
self._validate_and_set(value, f"_{attr_name}")
|
|
395
|
+
|
|
396
|
+
return property(getter, setter)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
# Dynamically add properties for x, y, z
|
|
400
|
+
for attr in ["x", "y", "z"]:
|
|
401
|
+
setattr(Vec3, attr, _create_property(attr))
|
ncca/ngl/vec3_array.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A container for ngl.Vec3 objects that mimics some of the behavior of a std::vector
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .vec3 import Vec3
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Vec3Array:
|
|
11
|
+
"""
|
|
12
|
+
A class to hold a list of Vec3 objects and perform operations on them.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, values=None):
|
|
16
|
+
"""
|
|
17
|
+
Initializes the Vec3Array.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
values (iterable, optional): An iterable of Vec3 objects. Defaults to None.
|
|
21
|
+
"""
|
|
22
|
+
self._data = []
|
|
23
|
+
if values is not None:
|
|
24
|
+
for v in values:
|
|
25
|
+
if not isinstance(v, Vec3):
|
|
26
|
+
raise TypeError("All elements must be of type Vec3")
|
|
27
|
+
self._data.append(v)
|
|
28
|
+
|
|
29
|
+
def __getitem__(self, index):
|
|
30
|
+
"""
|
|
31
|
+
Get the Vec3 at the specified index.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
index (int): The index of the element.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Vec3: The Vec3 object at the given index.
|
|
38
|
+
"""
|
|
39
|
+
return self._data[index]
|
|
40
|
+
|
|
41
|
+
def __len__(self):
|
|
42
|
+
"""
|
|
43
|
+
Return the number of elements in the array.
|
|
44
|
+
"""
|
|
45
|
+
return len(self._data)
|
|
46
|
+
|
|
47
|
+
def __iter__(self):
|
|
48
|
+
"""
|
|
49
|
+
Return an iterator for the array.
|
|
50
|
+
"""
|
|
51
|
+
return iter(self._data)
|
|
52
|
+
|
|
53
|
+
def append(self, value):
|
|
54
|
+
"""
|
|
55
|
+
Append a Vec3 object to the array.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
value (Vec3): The Vec3 object to append.
|
|
59
|
+
"""
|
|
60
|
+
if not isinstance(value, Vec3):
|
|
61
|
+
raise TypeError("Only Vec3 objects can be appended")
|
|
62
|
+
self._data.append(value)
|
|
63
|
+
|
|
64
|
+
def extend(self, values):
|
|
65
|
+
"""
|
|
66
|
+
Extend the array by appending elements from the iterable.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
values (iterable): An iterable of Vec3 objects to append.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
TypeError: If any element in values is not a Vec3.
|
|
73
|
+
"""
|
|
74
|
+
for v in values:
|
|
75
|
+
if not isinstance(v, Vec3):
|
|
76
|
+
raise TypeError("All elements must be of type Vec3")
|
|
77
|
+
self._data.append(v)
|
|
78
|
+
|
|
79
|
+
def to_list(self):
|
|
80
|
+
"""
|
|
81
|
+
Convert the array of Vec3 objects to a single flat list of floats.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
list: A list of x, y, z components concatenated.
|
|
85
|
+
"""
|
|
86
|
+
return [comp for vec in self._data for comp in vec]
|
|
87
|
+
|
|
88
|
+
def to_numpy(self):
|
|
89
|
+
"""
|
|
90
|
+
Convert the array of Vec3 objects to a numpy array.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
numpy.ndarray: A numpy array of the vector data.
|
|
94
|
+
"""
|
|
95
|
+
return np.array(self.to_list(), dtype=np.float32)
|
|
96
|
+
|
|
97
|
+
def __repr__(self):
|
|
98
|
+
return f"Vec3Array({self._data!r})"
|
|
99
|
+
|
|
100
|
+
def __str__(self):
|
|
101
|
+
return str(self._data)
|
|
102
|
+
|
|
103
|
+
def sizeof(self):
|
|
104
|
+
"""
|
|
105
|
+
Return the size of the array in bytes.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
int: The size of the array in bytes.
|
|
109
|
+
"""
|
|
110
|
+
return len(self._data) * Vec3.sizeof()
|