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 +3 -0
- pytessel/_version.py +6 -0
- pytessel/pytessel_core.cpython-312-x86_64-linux-gnu.so +0 -0
- pytessel-1.3.0.dist-info/METADATA +174 -0
- pytessel-1.3.0.dist-info/RECORD +8 -0
- pytessel-1.3.0.dist-info/WHEEL +6 -0
- pytessel-1.3.0.dist-info/sboms/auditwheel.cdx.json +1 -0
- pytessel.libs/libgomp-e985bcbb.so.1.0.0 +0 -0
pytessel/__init__.py
ADDED
pytessel/_version.py
ADDED
|
Binary file
|
|
@@ -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
|
+
[](https://github.com/ifilot/pytessel/actions/workflows/build_wheels.yml)
|
|
15
|
+
[](https://pypi.org/project/pytessel/)
|
|
16
|
+
[](https://pypi.org/project/pytessel/)
|
|
17
|
+
[](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
|
+

|
|
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
|
+

|
|
165
|
+
|
|
166
|
+
## Gallery
|
|
167
|
+
|
|
168
|
+
### Stanford Bunny
|
|
169
|
+
|
|
170
|
+

|
|
171
|
+
|
|
172
|
+
### Gyroid surface
|
|
173
|
+
|
|
174
|
+

|
|
@@ -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 @@
|
|
|
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
|