ncca-ngl 0.1.0__py3-none-any.whl → 0.1.1__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/util.py DELETED
@@ -1,128 +0,0 @@
1
- """Utility math module, contains various useful functions for 3D.
2
-
3
- Most of these functions are based on functions found in other libraries such as GLM, NGL or GLU
4
- """
5
-
6
- import math
7
-
8
- from .mat4 import Mat4
9
-
10
-
11
- def clamp(num, low, high):
12
- "clamp to range min and max will throw ValueError is low>=high"
13
- if low > high or low == high:
14
- raise ValueError
15
- return max(min(num, high), low)
16
-
17
-
18
- def look_at(eye, look, up):
19
- """
20
- Calculate 4x4 matrix for camera lookAt
21
- """
22
-
23
- n = look - eye
24
- u = up
25
- v = n.cross(u)
26
- u = v.cross(n)
27
- n.normalize()
28
- v.normalize()
29
- u.normalize()
30
-
31
- result = Mat4.identity()
32
- result.m[0][0] = v.x
33
- result.m[1][0] = v.y
34
- result.m[2][0] = v.z
35
- result.m[0][1] = u.x
36
- result.m[1][1] = u.y
37
- result.m[2][1] = u.z
38
- result.m[0][2] = -n.x
39
- result.m[1][2] = -n.y
40
- result.m[2][2] = -n.z
41
- result.m[3][0] = -eye.dot(v)
42
- result.m[3][1] = -eye.dot(u)
43
- result.m[3][2] = eye.dot(n)
44
- return result
45
-
46
-
47
- def perspective(fov, aspect, near, far):
48
- m = Mat4.zero() # as per glm
49
- _range = math.tan(math.radians(fov / 2.0)) * near
50
- left = -_range * aspect
51
- right = _range * aspect
52
- bottom = -_range
53
- top = _range
54
- m.m[0][0] = (2.0 * near) / (right - left)
55
- m.m[1][1] = (2.0 * near) / (top - bottom)
56
- m.m[2][2] = -(far + near) / (far - near)
57
- m.m[2][3] = -1.0
58
- m.m[3][2] = -(2.0 * far * near) / (far - near)
59
- return m
60
-
61
-
62
- def ortho(left, right, bottom, top, near, far):
63
- """Create an orthographic projection matrix."""
64
- m = Mat4.identity()
65
- m.m[0][0] = 2.0 / (right - left)
66
- m.m[1][1] = 2.0 / (top - bottom)
67
- m.m[2][2] = -2.0 / (far - near)
68
- m.m[3][0] = -(right + left) / (right - left)
69
- m.m[3][1] = -(top + bottom) / (top - bottom)
70
- m.m[3][2] = -(far + near) / (far - near)
71
- return m
72
-
73
-
74
- # Mat4 result(1.0f);
75
- # result.m_00= 2.0f / (_right - _left);
76
- # result.m_11= 2.0f / (_top - _bottom);
77
- # result.m_22= - 2.0f / (_zFar - _zNear);
78
- # result.m_30= - (_right + _left) / (_right - _left);
79
- # result.m_31= - (_top + _bottom) / (_top - _bottom);
80
- # result.m_32= - (_zFar + _zNear) / (_zFar - _zNear);
81
- # return result;
82
-
83
-
84
- def frustum(left, right, bottom, top, near, far):
85
- """Create a frustum projection matrix."""
86
- m = Mat4.zero()
87
- m.m[0][0] = (2.0 * near) / (right - left)
88
- m.m[1][1] = (2.0 * near) / (top - bottom)
89
- m.m[2][0] = (right + left) / (right - left)
90
- m.m[2][1] = (top + bottom) / (top - bottom)
91
- m.m[2][2] = -(far + near) / (far - near)
92
- m.m[2][3] = -1.0
93
- m.m[3][2] = -(2.0 * far * near) / (far - near)
94
- return m
95
-
96
-
97
- def lerp(a, b, t):
98
- return a + (b - a) * t
99
-
100
-
101
- def calc_normal(p1, p2, p3):
102
- """
103
- Calculates the normal of a triangle defined by three points.
104
-
105
- This is a Python implementation of the NGL C++ Util::calcNormal function.
106
- It uses the vector cross product method for clarity and leverages the py-ngl library.
107
- The order of the cross product is chosen to match the output of the C++ version.
108
-
109
- Args:
110
- p1: The first vertex of the triangle.
111
- p2: The second vertex of the triangle.
112
- p3: The third vertex of the triangle.
113
-
114
- Returns:
115
- The normalized normal vector of the triangle.
116
- """
117
- # Two vectors on the plane of the triangle
118
- v1 = p3 - p1
119
- v2 = p2 - p1
120
-
121
- # The cross product gives the normal vector.
122
- # The order (v1 x v2) is used to match the C++ implementation's result.
123
- normal = v1.cross(v2)
124
-
125
- # Normalize the result to get a unit length normal
126
- normal.normalize()
127
-
128
- return normal
ncca/ngl/vao_factory.py DELETED
@@ -1,34 +0,0 @@
1
- import enum
2
-
3
- from .multi_buffer_vao import MultiBufferVAO
4
- from .simple_index_vao import SimpleIndexVAO
5
- from .simple_vao import SimpleVAO
6
- from .log import logger
7
-
8
-
9
- class VAOType(enum.Enum):
10
- SIMPLE = "simpleVAO"
11
- MULTI_BUFFER = "multiBufferVAO"
12
- SIMPLE_INDEX = "simpleIndexVAO"
13
-
14
-
15
- class VAOFactory:
16
- _creators = {}
17
-
18
- @staticmethod
19
- def register_vao_creator(name, creator_func):
20
- VAOFactory._creators[name] = creator_func
21
-
22
- @staticmethod
23
- def create_vao(name, mode):
24
- creator = VAOFactory._creators.get(name)
25
- if not creator:
26
- logger.warning(f"VAO type '{name}' not found.")
27
- raise ValueError(name)
28
- return creator(mode)
29
-
30
-
31
- # pre-register the default VAO types
32
- VAOFactory.register_vao_creator(VAOType.SIMPLE, SimpleVAO)
33
- VAOFactory.register_vao_creator(VAOType.MULTI_BUFFER, MultiBufferVAO)
34
- VAOFactory.register_vao_creator(VAOType.SIMPLE_INDEX, SimpleIndexVAO)
ncca/ngl/vec2.py DELETED
@@ -1,350 +0,0 @@
1
- """
2
- Simple float only Vec2 class for 3D graphics, very similar to the pyngl ones
3
- """
4
-
5
- import ctypes
6
- import math
7
-
8
- from .util import clamp
9
-
10
-
11
- class Vec2:
12
- """
13
- A simple 3D vector class for 3D graphics, I use slots to fix the attributes to x,y,z
14
- Attributes:
15
- x (float): The x-coordinate of the vector.
16
- y (float): The y-coordinate of the vector.
17
- """
18
-
19
- __slots__ = ["_x", "_y"] # fix the attributes to x,y,z
20
-
21
- def __init__(self, x=0.0, y=0.0):
22
- """
23
- Initializes a new instance of the Vec2 class.
24
-
25
- Args:
26
- x (float, optional): The x-coordinate of the vector. Defaults to 0.0.
27
- y (float, optional): The y-coordinate of the vector. Defaults to 0.0.
28
- """
29
- self._x = x # x component of vector : float
30
- self._y = y # y component of vector : float
31
-
32
- @classmethod
33
- def sizeof(cls):
34
- return 2 * ctypes.sizeof(ctypes.c_float)
35
-
36
- def __iter__(self):
37
- """
38
- Make the Vec2 class iterable.
39
- Yields:
40
- float: The x and y components of the vector.
41
- """
42
- yield self.x
43
- yield self.y
44
-
45
- def clone(self) -> "Vec2":
46
- """
47
- Create a copy of the vector.
48
- Returns:
49
- Vec2: A new instance of Vec2 with the same x and y values.
50
- """
51
- return Vec2(self.x, self.y)
52
-
53
- def __getitem__(self, index):
54
- """
55
- Get the component of the vector at the given index.
56
- Args:
57
- index (int): The index of the component (0 for x, 1 for y, 2 for z).
58
- Returns:
59
- float: The value of the component at the given index.
60
- Raises:
61
- IndexError: If the index is out of range.
62
- """
63
- components = [self.x, self.y]
64
- try:
65
- return components[index]
66
- except IndexError:
67
- raise IndexError("Index out of range. Valid indices are 0, 1,")
68
-
69
- def _validate_and_set(self, v, name):
70
- """
71
- check if v is a float or int
72
- Args:
73
- v (number): The value to check.
74
- Raises:
75
- ValueError: If v is not a float or int.
76
- """
77
- if not isinstance(v, (int, float)):
78
- raise ValueError("need float or int")
79
- else:
80
- setattr(self, name, v)
81
-
82
- def __add__(self, rhs):
83
- """
84
- vector addition a+b
85
-
86
- Args:
87
- rhs (Vec2): The right-hand side vector to add.
88
- Returns:
89
- Vec2: A new vector that is the result of adding this vector and the rhs vector.
90
- """
91
- r = Vec2()
92
- r.x = self.x + rhs.x
93
- r.y = self.y + rhs.y
94
- return r
95
-
96
- def __iadd__(self, rhs):
97
- """
98
- vector addition a+=b
99
-
100
- Args:
101
- rhs (Vec2): The right-hand side vector to add.
102
- Returns:
103
- Vec2: returns this vector after adding the rhs vector.
104
- """
105
- self.x += rhs.x
106
- self.y += rhs.y
107
- return self
108
-
109
- def __sub__(self, rhs):
110
- """
111
- vector subtraction a-b
112
-
113
- Args:
114
- rhs (Vec2): The right-hand side vector to add.
115
- Returns:
116
- Vec2: A new vector that is the result of subtracting this vector and the rhs vector.
117
- """
118
- r = Vec2()
119
- r.x = self.x - rhs.x
120
- r.y = self.y - rhs.y
121
- return r
122
-
123
- def __isub__(self, rhs):
124
- """
125
- vector subtraction a-=b
126
-
127
- Args:
128
- rhs (Vec2): The right-hand side vector to add.
129
- Returns:
130
- Vec2: returns this vector after subtracting the rhs vector.
131
- """
132
- self.x -= rhs.x
133
- self.y -= rhs.y
134
- return self
135
-
136
- def __eq__(self, rhs):
137
- """
138
- vector comparison a==b using math.isclose not we only compare to 6 decimal places
139
- Args:
140
- rhs (Vec2): The right-hand side vector to compare.
141
- Returns:
142
- bool: True if the vectors are close, False otherwise.
143
- NotImplemented: If the right-hand side is not a Vec2.
144
- """
145
-
146
- if not isinstance(rhs, Vec2):
147
- return NotImplemented
148
- return math.isclose(self.x, rhs.x) and math.isclose(self.y, rhs.y)
149
-
150
- def __neq__(self, rhs):
151
- """
152
- vector comparison a!=b using math.isclose not we only compare to 6 decimal places
153
- Args:
154
- rhs (Vec2): The right-hand side vector to compare.
155
- Returns:
156
- bool: True if the vectors are not close, False otherwise.
157
- NotImplemented: If the right-hand side is not a Vec2.
158
- """
159
-
160
- if not isinstance(rhs, Vec2):
161
- return NotImplemented
162
- return not (math.isclose(self.x, rhs.x) and math.isclose(self.y, rhs.y))
163
-
164
- def __neg__(self):
165
- """
166
- negate a vector -a
167
- """
168
- self.x = -self.x
169
- self.y = -self.y
170
- return self
171
-
172
- def set(self, x, y):
173
- """
174
- set the x,y,z values of the vector
175
- Args:
176
- x (float): The x-coordinate of the vector.
177
- y (float): The y-coordinate of the vector.
178
- Raises :
179
- ValueError: if x,y are not float
180
- """
181
- try:
182
- self.x = float(x)
183
- self.y = float(y)
184
- except ValueError:
185
- raise ValueError(f"Vec2.set {x=} {y=} all need to be float")
186
-
187
- def dot(self, rhs):
188
- """
189
- dot product of two vectors a.b
190
- Args:
191
- rhs (Vec2): The right-hand side vector to dot product with.
192
- """
193
- return self.x * rhs.x + self.y * rhs.y
194
-
195
- def length(self):
196
- """
197
- length of vector
198
- Returns:
199
- float: The length of the vector.
200
- """
201
- return math.sqrt(self.x**2 + self.y**2)
202
-
203
- def length_squared(self):
204
- """
205
- length of vector squared sometimes used to avoid the sqrt for performance
206
- Returns:
207
- float: The length of the vector squared
208
- """
209
- return self.x**2 + self.y**2
210
-
211
- def inner(self, rhs):
212
- """
213
- inner product of two vectors a.b
214
- Args:
215
- rhs (Vec2): The right-hand side vector to inner product with.
216
- Returns:
217
- float: The inner product of the two vectors.
218
- """
219
- return (self.x * rhs.x) + (self.y * rhs.y)
220
-
221
- def null(self):
222
- """
223
- set the vector to zero
224
- """
225
- self.x = 0.0
226
- self.y = 0.0
227
-
228
- def cross(self, rhs):
229
- """
230
- cross product of two vectors a x b
231
- Args:
232
- rhs (Vec2): The right-hand side vector to cross product with.
233
- Returns:
234
- float : 2D cross product or perpendicular dot product.
235
- """
236
- return self.x * rhs.y - self.y * rhs.x
237
-
238
- def normalize(self):
239
- """
240
- normalize the vector to unit length
241
- Returns:
242
- Vec2: A new vector that is the result of normalizing this vector.
243
- Raises:
244
- ZeroDivisionError: If the length of the vector is zero.
245
- """
246
- vector_length = self.length()
247
- try:
248
- self.x /= vector_length
249
- self.y /= vector_length
250
- except ZeroDivisionError:
251
- raise ZeroDivisionError(
252
- f"Vec2.normalize {vector_length} length is zero most likely calling normalize on a zero vector"
253
- )
254
- return self
255
-
256
- def reflect(self, n):
257
- """
258
- reflect a vector about a normal
259
- Args:
260
- n (Vec2): The normal to reflect about.
261
- Returns:
262
- Vec2: A new vector that is the result of reflecting this vector about the normal.
263
- """
264
- d = self.dot(n)
265
- # I - 2.0 * dot(N, I) * N
266
- return Vec2(self.x - 2.0 * d * n.x, self.y - 2.0 * d * n.y)
267
-
268
- def clamp(self, low, high):
269
- """
270
- clamp the vector to a range
271
- Args:
272
- low (float): The low end of the range.
273
- high (float): The high end of the range.
274
-
275
- """
276
- self.x = clamp(self.x, low, high)
277
- self.y = clamp(self.y, low, high)
278
-
279
- def __repr__(self):
280
- "object representation for debugging"
281
- return f"Vec2 [{self.x},{self.y}]"
282
-
283
- def __truediv__(self, rhs):
284
- if isinstance(rhs, (float, int)):
285
- return Vec2(self.x / rhs, self.y / rhs)
286
- elif isinstance(rhs, Vec2):
287
- return Vec2(self.x / rhs.x, self.y / rhs.y)
288
- else:
289
- raise ValueError(f"can only do piecewise division with a scalar {rhs=}")
290
-
291
- def __str__(self):
292
- "object representation for debugging"
293
- return f"[{self.x},{self.y}]"
294
-
295
- def __mul__(self, rhs):
296
- """
297
- piecewise scalar multiplication
298
- Args:
299
- rhs (float): The scalar to multiply by.
300
- Returns:
301
- Vec2: A new vector that is the result of multiplying this vector by the scalar.
302
- Raises:
303
- ValueError: If the right-hand side is not a float.
304
- """
305
- if isinstance(rhs, (float, int)):
306
- return Vec2(self.x * rhs, self.y * rhs)
307
- else:
308
- raise ValueError(f"can only do piecewise multiplication with a scalar {rhs=}")
309
-
310
- def __rmul__(self, rhs):
311
- """
312
- piecewise scalar multiplication
313
- Args:
314
- rhs (float): The scalar to multiply by.
315
- Returns:
316
- Vec2: A new vector that is the result of multiplying this vector by the scalar.
317
- Raises:
318
- ValueError: If the right-hand side is not a float.
319
- """
320
- return self * rhs
321
-
322
- def __matmul__(self, rhs):
323
- """
324
- "Vec2 @ Mat2 matrix multiplication"
325
- Args:
326
- rhs (Mat2): The matrix to multiply by.
327
- Returns:
328
- Vec2: A new vector that is the result of multiplying this vector by the matrix.
329
- """
330
- return Vec2(
331
- self.x * rhs.m[0][0] + self.y * rhs.m[1][0] + self.z * rhs.m[2][0],
332
- self.x * rhs.m[0][1] + self.y * rhs.m[1][1] + self.z * rhs.m[2][1],
333
- self.x * rhs.m[0][2] + self.y * rhs.m[1][2] + self.z * rhs.m[2][2],
334
- )
335
-
336
-
337
- # Helper function to create properties
338
- def _create_property(attr_name):
339
- def getter(self):
340
- return getattr(self, f"_{attr_name}")
341
-
342
- def setter(self, value):
343
- self._validate_and_set(value, f"_{attr_name}")
344
-
345
- return property(getter, setter)
346
-
347
-
348
- # Dynamically add properties for x, y
349
- for attr in ["x", "y"]:
350
- setattr(Vec2, attr, _create_property(attr))
ncca/ngl/vec2_array.py DELETED
@@ -1,106 +0,0 @@
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()