ncca-ngl 0.3.4__tar.gz → 0.5.0__tar.gz
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-0.3.4 → ncca_ngl-0.5.0}/PKG-INFO +3 -2
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/pyproject.toml +25 -2
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/pack_arrays.py +2 -3
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/__init__.py +3 -4
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/base_mesh.py +28 -20
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/image.py +1 -3
- ncca_ngl-0.5.0/src/ncca/ngl/mat2.py +164 -0
- ncca_ngl-0.5.0/src/ncca/ngl/mat3.py +375 -0
- ncca_ngl-0.5.0/src/ncca/ngl/mat4.py +301 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/prim_data.py +42 -36
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/primitives.py +2 -2
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/pyside_event_handling_mixin.py +0 -108
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/quaternion.py +69 -36
- ncca_ngl-0.5.0/src/ncca/ngl/shader.py +113 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shader_program.py +94 -117
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/texture.py +5 -2
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/util.py +7 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vec2.py +117 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vec2_array.py +175 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vec3.py +120 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vec3_array.py +181 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vec4.py +129 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vec4_array.py +175 -0
- ncca_ngl-0.5.0/src/ncca/ngl/vector_base.py +542 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/__init__.py +20 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/__main__.py +640 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/__main__.py.backup +640 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/base_webgpu_pipeline.py +354 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/custom_shader_pipeline.py +288 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/instanced_geometry_pipeline.py +594 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/line_pipeline.py +405 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/pipeline_factory.py +190 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/pipeline_shaders.py +497 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/point_list_pipeline.py +349 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/point_pipeline.py +336 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/triangle_pipeline.py +419 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/webgpu_constants.py +31 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/webgpu_widget.py +322 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/REFACTORING_SUMMARY.md +82 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/UNIFIED_SYSTEM.md +314 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/buffer_manager.py +396 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/pipeline_config.py +463 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/shader_constants.py +328 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/shader_templates.py +563 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/unified_examples.py +390 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/unified_factory.py +449 -0
- ncca_ngl-0.5.0/src/ncca/ngl/webgpu/wip/unified_pipeline.py +469 -0
- ncca_ngl-0.5.0/src/ncca/ngl/widgets/__init__.py +28 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/__main__.py +2 -1
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/lookatwidget.py +2 -1
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/mat4widget.py +2 -2
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/vec2widget.py +1 -1
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/vec3widget.py +1 -0
- ncca_ngl-0.3.4/src/ncca/ngl/mat2.py +0 -138
- ncca_ngl-0.3.4/src/ncca/ngl/mat3.py +0 -456
- ncca_ngl-0.3.4/src/ncca/ngl/mat4.py +0 -466
- ncca_ngl-0.3.4/src/ncca/ngl/shader.py +0 -229
- ncca_ngl-0.3.4/src/ncca/ngl/vec2.py +0 -351
- ncca_ngl-0.3.4/src/ncca/ngl/vec2_array.py +0 -124
- ncca_ngl-0.3.4/src/ncca/ngl/vec3.py +0 -401
- ncca_ngl-0.3.4/src/ncca/ngl/vec3_array.py +0 -128
- ncca_ngl-0.3.4/src/ncca/ngl/vec4.py +0 -229
- ncca_ngl-0.3.4/src/ncca/ngl/vec4_array.py +0 -124
- ncca_ngl-0.3.4/src/ncca/ngl/widgets/__init__.py +0 -12
- ncca_ngl-0.3.4/src/ncca/ngl/widgets/transformation_widget.py +0 -299
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/LICENSE.txt +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/.ruff_cache/.gitignore +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/.ruff_cache/0.13.0/10564494386971134025 +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/.ruff_cache/0.13.0/7783445477288392980 +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/.ruff_cache/CACHEDIR.TAG +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/NGLDebug.log +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/Primitives.npz +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/buddah.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/bunny.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/cube.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/dodecahedron.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/dragon.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/football.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/icosahedron.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/octahedron.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/teapot.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/tetrahedron.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/PrimData/troll.npy +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/abstract_vao.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/base_mesh.pyi +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/bbox.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/bezier_curve.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/first_person_camera.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/log.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/multi_buffer_vao.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/obj.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/plane.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/random.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shader_lib.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/checker_fragment.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/checker_vertex.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/colour_fragment.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/colour_vertex.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/diffuse_fragment.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/diffuse_vertex.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/text_fragment.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/text_geometry.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/shaders/text_vertex.glsl +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/simple_index_vao.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/simple_vao.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/text.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/transform.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/vao_factory.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/NGLDebug.log +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/glsl/phong.frag +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/glsl/phong.vert +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/glsl/picking.frag +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/glsl/picking.vert +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/rgbacolourwidget.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/rgbcolourwidget.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/transformwidget.py +0 -0
- {ncca_ngl-0.3.4 → ncca_ngl-0.5.0}/src/ncca/ngl/widgets/vec4widget.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ncca-ngl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: A Python version of the NGL graphics library.
|
|
5
5
|
Author: Jon Macey
|
|
6
6
|
Author-email: Jon Macey <jmacey@bournemouth.ac.uk>
|
|
@@ -17,6 +17,7 @@ Requires-Dist: pillow
|
|
|
17
17
|
Requires-Dist: glfw>=2.9.0
|
|
18
18
|
Requires-Dist: freetype-py>=2.5.1
|
|
19
19
|
Requires-Dist: pyside6>=6.9.2
|
|
20
|
-
Requires-
|
|
20
|
+
Requires-Dist: wgpu>=0.29.0
|
|
21
|
+
Requires-Python: >=3.11
|
|
21
22
|
Project-URL: Homepage, https://github.com/NCCA/PyNGL
|
|
22
23
|
Project-URL: Issues, https://github.com/NCCA/PyNGL/issues
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ncca-ngl"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
description = "A Python version of the NGL graphics library."
|
|
5
5
|
authors = [{ name = "Jon Macey", email = "jmacey@bournemouth.ac.uk" }]
|
|
6
|
-
requires-python = ">=3.
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
7
|
license = { file = "LICENSE.txt" }
|
|
8
8
|
|
|
9
9
|
dependencies = [
|
|
@@ -13,6 +13,7 @@ dependencies = [
|
|
|
13
13
|
"glfw>=2.9.0",
|
|
14
14
|
"freetype-py>=2.5.1",
|
|
15
15
|
"pyside6>=6.9.2",
|
|
16
|
+
"wgpu>=0.29.0",
|
|
16
17
|
]
|
|
17
18
|
|
|
18
19
|
[project.urls]
|
|
@@ -42,4 +43,26 @@ dev = [
|
|
|
42
43
|
"mkdocs>=1.6.1",
|
|
43
44
|
"mkdocstrings[python]>=0.30.1",
|
|
44
45
|
"mkdocs-material>=9.7.0",
|
|
46
|
+
"pytest-qt>=4.5.0",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
[tool.coverage.run]
|
|
50
|
+
source = ["src/ncca/ngl"]
|
|
51
|
+
omit = [
|
|
52
|
+
"*/tests/*",
|
|
53
|
+
"*/test_*",
|
|
54
|
+
"*/__pycache__/*",
|
|
55
|
+
"*/site-packages/*",
|
|
56
|
+
"__main__.py",
|
|
57
|
+
"__init__.py",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
[tool.coverage.report]
|
|
61
|
+
exclude_lines = [
|
|
62
|
+
"pragma: no cover",
|
|
63
|
+
"def __repr__",
|
|
64
|
+
"raise AssertionError",
|
|
65
|
+
"raise NotImplementedError",
|
|
66
|
+
"if __name__ == .__main__.:",
|
|
67
|
+
"if TYPE_CHECKING:",
|
|
45
68
|
]
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
|
-
import numpy as np
|
|
4
3
|
import pathlib
|
|
5
4
|
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
6
7
|
files = pathlib.Path(".").glob("*.npy")
|
|
7
8
|
|
|
8
9
|
data = {}
|
|
9
10
|
for f in files:
|
|
10
11
|
data[str(f.stem)] = np.load(f)
|
|
11
|
-
# arrays.append(np.load(f))
|
|
12
|
-
# names.append(str(f.stem))
|
|
13
12
|
print(data.keys())
|
|
14
13
|
|
|
15
14
|
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
from importlib.metadata import PackageNotFoundError, version
|
|
3
3
|
|
|
4
4
|
try:
|
|
5
|
-
__version__ = version("ncca-ngl")
|
|
6
|
-
except PackageNotFoundError:
|
|
5
|
+
__version__ = version("ncca-ngl") # pragma: no cover
|
|
6
|
+
except PackageNotFoundError: # pragma: no cover
|
|
7
7
|
__version__ = "0.0.0"
|
|
8
|
-
|
|
9
8
|
__author__ = "Jon Macey jmacey@bournemouth.ac.uk"
|
|
10
9
|
__license__ = "MIT"
|
|
11
10
|
|
|
@@ -16,7 +15,7 @@ from .bezier_curve import BezierCurve
|
|
|
16
15
|
from .first_person_camera import FirstPersonCamera
|
|
17
16
|
from .image import Image, ImageModes
|
|
18
17
|
from .log import logger
|
|
19
|
-
from .mat2 import Mat2
|
|
18
|
+
from .mat2 import Mat2, Mat2Error, Mat2NotSquare
|
|
20
19
|
from .mat3 import Mat3, Mat3Error, Mat3NotSquare
|
|
21
20
|
from .mat4 import Mat4, Mat4Error, Mat4NotSquare
|
|
22
21
|
from .multi_buffer_vao import MultiBufferVAO
|
|
@@ -54,6 +54,24 @@ class BaseMesh:
|
|
|
54
54
|
"""
|
|
55
55
|
return all(len(f.vertex) == 3 for f in self.faces)
|
|
56
56
|
|
|
57
|
+
def _should_skip_vao_creation(self, reset_vao: bool) -> bool:
|
|
58
|
+
"""Check if VAO creation should be skipped."""
|
|
59
|
+
if self.vao is None:
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
if reset_vao:
|
|
63
|
+
logger.warning("VAO exist so returning")
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
logger.warning("Creating new VAO")
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
def _validate_triangular_mesh(self) -> None:
|
|
70
|
+
"""Validate that the mesh is composed of triangles."""
|
|
71
|
+
if not self.is_triangular():
|
|
72
|
+
logger.error("Can only create VBO from all Triangle data at present")
|
|
73
|
+
raise RuntimeError("Can only create VBO from all Triangle data at present")
|
|
74
|
+
|
|
57
75
|
def create_vao(self, reset_vao: bool = False) -> None:
|
|
58
76
|
"""
|
|
59
77
|
Create a Vertex Array Object (VAO) for the mesh.
|
|
@@ -64,20 +82,14 @@ class BaseMesh:
|
|
|
64
82
|
Raises:
|
|
65
83
|
RuntimeError: If the mesh is not composed entirely of triangles.
|
|
66
84
|
"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
data_pack_type = 0
|
|
76
|
-
if self.is_triangular():
|
|
77
|
-
data_pack_type = gl.GL_TRIANGLES
|
|
78
|
-
if data_pack_type == 0:
|
|
79
|
-
logger.error("Can only create VBO from all Triangle data at present")
|
|
80
|
-
raise RuntimeError("Can only create VBO from all Triangle data at present")
|
|
85
|
+
|
|
86
|
+
# Handle existing VAO based on reset_vao flag
|
|
87
|
+
if self._should_skip_vao_creation(reset_vao):
|
|
88
|
+
return
|
|
89
|
+
# Validate mesh is triangular
|
|
90
|
+
self._validate_triangular_mesh()
|
|
91
|
+
|
|
92
|
+
data_pack_type = gl.GL_TRIANGLES
|
|
81
93
|
|
|
82
94
|
@dataclass
|
|
83
95
|
class VertData:
|
|
@@ -123,9 +135,7 @@ class BaseMesh:
|
|
|
123
135
|
vbo_mesh.append(d)
|
|
124
136
|
|
|
125
137
|
mesh_data = np.concatenate([v.as_array() for v in vbo_mesh]).astype(np.float32)
|
|
126
|
-
self.vao = vao_factory.VAOFactory.create_vao(
|
|
127
|
-
vao_factory.VAOType.SIMPLE, data_pack_type
|
|
128
|
-
)
|
|
138
|
+
self.vao = vao_factory.VAOFactory.create_vao(vao_factory.VAOType.SIMPLE, data_pack_type)
|
|
129
139
|
with self.vao as vao:
|
|
130
140
|
mesh_size = len(mesh_data) // 8
|
|
131
141
|
vao.set_data(VertexData(mesh_data, mesh_size))
|
|
@@ -137,9 +147,7 @@ class BaseMesh:
|
|
|
137
147
|
vao.set_vertex_attribute_pointer(2, 2, gl.GL_FLOAT, 8 * 4, 6 * 4)
|
|
138
148
|
vao.set_num_indices(mesh_size)
|
|
139
149
|
self.calc_dimensions()
|
|
140
|
-
self.bbox = BBox.from_extents(
|
|
141
|
-
self.min_x, self.max_x, self.min_y, self.max_y, self.min_z, self.max_z
|
|
142
|
-
)
|
|
150
|
+
self.bbox = BBox.from_extents(self.min_x, self.max_x, self.min_y, self.max_y, self.min_z, self.max_z)
|
|
143
151
|
|
|
144
152
|
def calc_dimensions(self) -> None:
|
|
145
153
|
"""
|
|
@@ -34,9 +34,7 @@ class Image:
|
|
|
34
34
|
if mode == ImageModes.GRAY:
|
|
35
35
|
self._data = np.zeros((height, width), dtype=np.uint8)
|
|
36
36
|
else:
|
|
37
|
-
self._data = np.zeros(
|
|
38
|
-
(height, width, len(mode.value)), dtype=np.uint8
|
|
39
|
-
)
|
|
37
|
+
self._data = np.zeros((height, width, len(mode.value)), dtype=np.uint8)
|
|
40
38
|
else:
|
|
41
39
|
self._data = None
|
|
42
40
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mat2 class with NumPy implementation
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from .vec2 import Vec2
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Mat2Error(Exception):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Mat2NotSquare(Exception):
|
|
15
|
+
"""If we try to construct from a non square (2x2) value or 4 elements this exception will be thrown"""
|
|
16
|
+
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Mat2:
|
|
21
|
+
__slots__ = ["m"]
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
"""
|
|
25
|
+
Initialize a 2x2 matrix.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
self.m = np.eye(2, dtype=np.float64)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_list(cls, lst):
|
|
33
|
+
"class method to create mat2 from list"
|
|
34
|
+
v = Mat2()
|
|
35
|
+
if isinstance(lst, list) and len(lst) == 2 and all(isinstance(row, list) for row in lst):
|
|
36
|
+
# 2D list
|
|
37
|
+
if all(len(row) == 2 for row in lst):
|
|
38
|
+
v.m = np.array(lst, dtype=np.float64)
|
|
39
|
+
return v
|
|
40
|
+
elif any(len(row) != 2 for row in lst):
|
|
41
|
+
raise Mat2NotSquare
|
|
42
|
+
elif isinstance(lst, list) and len(lst) == 4:
|
|
43
|
+
# flat list - reshape to 2x2 in row-major order
|
|
44
|
+
v.m = np.array(lst, dtype=np.float64).reshape(2, 2, order="C")
|
|
45
|
+
return v
|
|
46
|
+
else:
|
|
47
|
+
raise Mat2NotSquare
|
|
48
|
+
|
|
49
|
+
def get_matrix(self) -> list[float]:
|
|
50
|
+
"""
|
|
51
|
+
Get the current matrix representation as a flat list in column-major order.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
list[float]: A flat list of floats.
|
|
55
|
+
"""
|
|
56
|
+
return self.m.flatten("C").tolist()
|
|
57
|
+
|
|
58
|
+
def to_numpy(self):
|
|
59
|
+
"""
|
|
60
|
+
Convert the current matrix to a NumPy array.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
np.ndarray: The matrix as a NumPy array.
|
|
64
|
+
"""
|
|
65
|
+
return self.m.astype(np.float32)
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def identity(cls) -> "Mat2":
|
|
69
|
+
"""
|
|
70
|
+
Create an identity matrix.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Mat2: A new identity Mat2 object.
|
|
74
|
+
"""
|
|
75
|
+
return cls()
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def zero(cls):
|
|
79
|
+
"""class method to return a new zero matrix
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
Mat2
|
|
84
|
+
new Mat2 matrix as all zeros
|
|
85
|
+
|
|
86
|
+
"""
|
|
87
|
+
v = Mat2()
|
|
88
|
+
v.m = np.zeros((2, 2), dtype=np.float64)
|
|
89
|
+
return v
|
|
90
|
+
|
|
91
|
+
def _mat_mul(self, rhs):
|
|
92
|
+
"matrix mult for 3D OpenGL style graphics"
|
|
93
|
+
result = Mat2()
|
|
94
|
+
# Use numpy's @ operator which does standard matrix multiplication
|
|
95
|
+
result.m = rhs.m @ self.m
|
|
96
|
+
return result
|
|
97
|
+
|
|
98
|
+
def __matmul__(self, rhs):
|
|
99
|
+
"""
|
|
100
|
+
Matrix multiplication or vector transformation with a 2D matrix.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
rhs (Mat2 | Vec2): The right-hand side operand.
|
|
104
|
+
If Mat2, perform matrix multiplication.
|
|
105
|
+
If Vec2, transform the vector by the matrix.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Mat2: Resulting matrix from matrix multiplication.
|
|
109
|
+
Vec2: Transformed vector.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: If rhs is neither a Mat2 nor Vec2 object.
|
|
113
|
+
"""
|
|
114
|
+
if isinstance(rhs, Mat2):
|
|
115
|
+
return self._mat_mul(rhs)
|
|
116
|
+
elif isinstance(rhs, Vec2):
|
|
117
|
+
vec = np.array([rhs.x, rhs.y], dtype=np.float64)
|
|
118
|
+
res = self.m @ vec
|
|
119
|
+
return Vec2(res[0], res[1])
|
|
120
|
+
else:
|
|
121
|
+
raise ValueError(f"Can only multiply by Mat2 or Vec2, not {type(rhs)}")
|
|
122
|
+
|
|
123
|
+
def __str__(self) -> str:
|
|
124
|
+
"""
|
|
125
|
+
String representation of the matrix.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
str: The string representation.
|
|
129
|
+
"""
|
|
130
|
+
return f"Mat2({self.m[0].tolist()}, {self.m[1].tolist()})"
|
|
131
|
+
|
|
132
|
+
def to_list(self):
|
|
133
|
+
"convert matrix to list in column-major order"
|
|
134
|
+
return self.m.flatten("C").tolist()
|
|
135
|
+
|
|
136
|
+
def copy(self) -> "Mat2":
|
|
137
|
+
"""Create a copy of the matrix.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
A new Mat2 instance with the same values.
|
|
141
|
+
"""
|
|
142
|
+
new_mat = Mat2()
|
|
143
|
+
new_mat.m = self.m.copy()
|
|
144
|
+
return new_mat
|
|
145
|
+
|
|
146
|
+
def __eq__(self, rhs):
|
|
147
|
+
"""Value-based equality for Mat2: compare underlying matrices numerically.
|
|
148
|
+
Returns NotImplemented for non-Mat2 types so Python can try reflected comparisons
|
|
149
|
+
or handle it appropriately.
|
|
150
|
+
"""
|
|
151
|
+
if not isinstance(rhs, Mat2):
|
|
152
|
+
return NotImplemented
|
|
153
|
+
# self.m and other.m should be numpy arrays; compare with tolerance
|
|
154
|
+
return bool(np.allclose(self.m, rhs.m, rtol=1e-8, atol=1e-12))
|
|
155
|
+
|
|
156
|
+
def __ne__(self, rhs):
|
|
157
|
+
"""Value-based equality for Mat2: compare underlying matrices numerically.
|
|
158
|
+
Returns NotImplemented for non-Mat2 types so Python can try reflected comparisons
|
|
159
|
+
or handle it appropriately.
|
|
160
|
+
"""
|
|
161
|
+
if not isinstance(rhs, Mat2):
|
|
162
|
+
return NotImplemented
|
|
163
|
+
# self.m and other.m should be numpy arrays; compare with tolerance
|
|
164
|
+
return not bool(np.allclose(self.m, rhs.m, rtol=1e-8, atol=1e-12))
|