pytessel 1.3.0__cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.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.
pytessel/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .pytessel_core import PyTessel
2
+
3
+ from ._version import __version__
pytessel/_version.py ADDED
@@ -0,0 +1,6 @@
1
+ from importlib.metadata import version, PackageNotFoundError
2
+
3
+ try:
4
+ __version__ = version("pytessel")
5
+ except PackageNotFoundError:
6
+ __version__ = "0.0.0" # optional fallback
@@ -0,0 +1,174 @@
1
+ Metadata-Version: 2.1
2
+ Name: pytessel
3
+ Version: 1.3.0
4
+ Summary: Python package for building isosurfaces from 3D scalar fields
5
+ Author-Email: Ivo Filot <ivo@ivofilot.nl>
6
+ License: GPL-3.0-only
7
+ Project-URL: Homepage, https://github.com/ifilot/pyqint
8
+ Requires-Python: >=3.9
9
+ Requires-Dist: numpy
10
+ Description-Content-Type: text/markdown
11
+
12
+ # PyTessel
13
+
14
+ [![CI](https://github.com/ifilot/pytessel/actions/workflows/build_wheels.yml/badge.svg)](https://github.com/ifilot/pytessel/actions/workflows/build_wheels.yml)
15
+ [![PyPI](https://img.shields.io/pypi/v/pytessel?color=green)](https://pypi.org/project/pytessel/)
16
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/pypi)](https://pypi.org/project/pytessel/)
17
+ [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
18
+
19
+ ## Purpose
20
+
21
+ PyTessel is a Python package for constructing isosurfaces from 3D scalar fields
22
+ using the marching cubes algorithm. It is designed for scientific visualization,
23
+ computational geometry, and mesh generation workflows. While PyTessel was
24
+ originally developed for rendering molecular orbitals, it is flexible enough to
25
+ tessellate arbitrary scalar fields.
26
+
27
+ ![isosurface](img/isosurface.png)
28
+
29
+ ## Installation
30
+
31
+ ```
32
+ pip install pytessel
33
+ ```
34
+
35
+ ## Getting started
36
+
37
+ The example below constructs an isosurface of a three-dimensional Gaussian function.
38
+ The resulting surface is written to `test.ply`, which can be viewed using tools
39
+ such as:
40
+
41
+ * `ctmviewer` (Linux)
42
+ * `3D Viewer` (Windows, free via Microsoft Store)
43
+ * Blender, MeshLab, etc.
44
+
45
+ ```python
46
+ from pytessel import PyTessel
47
+ import numpy as np
48
+
49
+ def main():
50
+ pytessel = PyTessel()
51
+
52
+ # Generate a regular grid
53
+ x = np.linspace(0, 10, 50)
54
+
55
+ # Grid ordering:
56
+ # z is the slowest-moving index, x is the fastest-moving index
57
+ grid = np.flipud(
58
+ np.vstack(np.meshgrid(x, x, x, indexing='ij')).reshape(3, -1)
59
+ ).T
60
+
61
+ R = [5, 5, 5]
62
+ scalarfield = np.reshape(
63
+ np.array([gaussian(r, R) for r in grid]),
64
+ (len(x), len(x), len(x))
65
+ )
66
+
67
+ unitcell = np.diag(np.ones(3) * 10.0)
68
+
69
+ vertices, normals, indices = pytessel.marching_cubes(
70
+ scalarfield.flatten(),
71
+ scalarfield.shape,
72
+ unitcell.flatten(),
73
+ 0.1
74
+ )
75
+
76
+ pytessel.write_ply('test.ply', vertices, normals, indices)
77
+
78
+ def gaussian(r, R):
79
+ return np.exp(-(r - R).dot(r - R))
80
+
81
+ if __name__ == '__main__':
82
+ main()
83
+ ```
84
+
85
+ ## Isosurface quality
86
+
87
+ The script below demonstrates how grid resolution affects surface quality. Six
88
+ isosurfaces of an icosahedral metaball are generated using grids of:
89
+
90
+ * `10×10×10`
91
+ * `20×20×20`
92
+ * `25×25×25`
93
+ * `50×50×50`
94
+ * `100×100×100`
95
+ * `200×200×200`
96
+
97
+ Each surface is exported as a .ply file and rendered using [Blender](https://www.blender.org/).
98
+
99
+ ```python
100
+ from pytessel import PyTessel
101
+ import numpy as np
102
+
103
+ def main():
104
+ """
105
+ Build 6 .ply files of increasing quality
106
+ """
107
+ pytessel = PyTessel()
108
+
109
+ for nrpoints in [10, 20, 25, 50, 100, 200]:
110
+ sz = 3
111
+
112
+ x = np.linspace(-sz, sz, nrpoints)
113
+ y = np.linspace(-sz, sz, nrpoints)
114
+ z = np.linspace(-sz, sz, nrpoints)
115
+
116
+ xx, yy, zz, field = icosahedron_field(x, y, z)
117
+
118
+ unitcell = np.diag(np.ones(3) * sz * 2)
119
+ isovalue = 3.75
120
+
121
+ vertices, normals, indices = pytessel.marching_cubes(
122
+ field.flatten(),
123
+ field.shape,
124
+ unitcell.flatten(),
125
+ isovalue
126
+ )
127
+
128
+ pytessel.write_ply(
129
+ f'icosahedron_{nrpoints:03d}.ply',
130
+ vertices,
131
+ normals,
132
+ indices
133
+ )
134
+
135
+ def icosahedron_field(x, y, z):
136
+ """
137
+ Produce a scalar field for icosahedral metaballs
138
+ """
139
+ phi = (1 + np.sqrt(5)) / 2
140
+ vertices = [
141
+ [0, 1, phi], [0, -1, -phi], [0, 1, -phi], [0, -1, phi],
142
+ [1, phi, 0], [-1, -phi, 0], [1, -phi, 0], [-1, phi, 0],
143
+ [phi, 0, 1], [-phi, 0, -1], [phi, 0, -1], [-phi, 0, 1]
144
+ ]
145
+
146
+ xx, yy, zz = np.meshgrid(x, y, z)
147
+ field = np.zeros_like(xx)
148
+
149
+ for v in vertices:
150
+ field += metaball(xx, yy, zz, v[0], v[1], v[2])
151
+
152
+ return xx, yy, zz, field
153
+
154
+ def metaball(x, y, z, X0, Y0, Z0):
155
+ """
156
+ Single metaball function
157
+ """
158
+ return 1 / ((x - X0)**2 + (y - Y0)**2 + (z - Z0)**2)
159
+
160
+ if __name__ == '__main__':
161
+ main()
162
+ ```
163
+
164
+ ![Icosahedral metaballs](img/metaballs_3x2.png)
165
+
166
+ ## Gallery
167
+
168
+ ### Stanford Bunny
169
+
170
+ ![bunny](img/bunny.png)
171
+
172
+ ### Gyroid surface
173
+
174
+ ![gyroid](img/gyroid.png)
@@ -0,0 +1,8 @@
1
+ pytessel/__init__.py,sha256=kHTE7wabS-nZLEyqsrlSuWQqJGDtCo4MNvCIz_QPcU0,71
2
+ pytessel/_version.py,sha256=lmA3Whag-oIFhF2gLlkg_Zx3MXYTQXbbmlsUoMU_2Eg,180
3
+ pytessel/pytessel_core.cpython-312-x86_64-linux-gnu.so,sha256=Q6e8zCsWTBwFUMCLDW4micr1_zhl4CCCPGOqhahJnxw,231729
4
+ pytessel.libs/libgomp-e985bcbb.so.1.0.0,sha256=pDkE5PopcwHUZA3BuzyKNIC0BvmeSY66mxkUtoqrYEo,253289
5
+ pytessel-1.3.0.dist-info/METADATA,sha256=8P4tJAxVOXXdYOTCj1U2bvqWvOJ17HQ9D1gtuApptf4,4442
6
+ pytessel-1.3.0.dist-info/WHEEL,sha256=5CT1xAVtUA3SK4LW_XdoM9Kto3PJPVP1rBIfK8BYqcM,138
7
+ pytessel-1.3.0.dist-info/RECORD,,
8
+ pytessel-1.3.0.dist-info/sboms/auditwheel.cdx.json,sha256=3yzl_jxhbct6Yuo34-t3DhdZaBKHE0_C2JekAZ3QjD4,1430
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: meson
3
+ Root-Is-Purelib: false
4
+ Tag: cp312-cp312-manylinux_2_24_x86_64
5
+ Tag: cp312-cp312-manylinux_2_28_x86_64
6
+
@@ -0,0 +1 @@
1
+ {"bomFormat": "CycloneDX", "specVersion": "1.4", "version": 1, "metadata": {"component": {"type": "library", "bom-ref": "pkg:pypi/pytessel@1.3.0?file_name=pytessel-1.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", "name": "pytessel", "version": "1.3.0", "purl": "pkg:pypi/pytessel@1.3.0?file_name=pytessel-1.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}, "tools": [{"name": "auditwheel", "version": "6.5.0"}]}, "components": [{"type": "library", "bom-ref": "pkg:pypi/pytessel@1.3.0?file_name=pytessel-1.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", "name": "pytessel", "version": "1.3.0", "purl": "pkg:pypi/pytessel@1.3.0?file_name=pytessel-1.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl"}, {"type": "library", "bom-ref": "pkg:rpm/almalinux/libgomp@8.5.0-28.el8_10.alma.1#c61017c9a24eb6e1e1a3cdc9becd004a6419cbda3d54b4848b98f240a4829571", "name": "libgomp", "version": "8.5.0-28.el8_10.alma.1", "purl": "pkg:rpm/almalinux/libgomp@8.5.0-28.el8_10.alma.1"}], "dependencies": [{"ref": "pkg:pypi/pytessel@1.3.0?file_name=pytessel-1.3.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", "dependsOn": ["pkg:rpm/almalinux/libgomp@8.5.0-28.el8_10.alma.1#c61017c9a24eb6e1e1a3cdc9becd004a6419cbda3d54b4848b98f240a4829571"]}, {"ref": "pkg:rpm/almalinux/libgomp@8.5.0-28.el8_10.alma.1#c61017c9a24eb6e1e1a3cdc9becd004a6419cbda3d54b4848b98f240a4829571"}]}
Binary file