mesh2sdf2 2.2.0__tar.gz → 2.3.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.
Files changed (28) hide show
  1. mesh2sdf2-2.3.0/PKG-INFO +187 -0
  2. mesh2sdf2-2.3.0/README.md +161 -0
  3. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/array3.h +2 -47
  4. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/geometry.h +40 -16
  5. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/makelevelset3.cpp +62 -97
  6. mesh2sdf2-2.3.0/csrc/makelevelset3.h +13 -0
  7. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/parallel.cpp +56 -85
  8. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/parallel.h +4 -6
  9. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/pybind.cpp +16 -8
  10. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/csrc/vec.h +0 -1
  11. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/mesh2sdf/compute.py +1 -1
  12. mesh2sdf2-2.3.0/mesh2sdf2.egg-info/PKG-INFO +187 -0
  13. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/pyproject.toml +1 -1
  14. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/tests/test_mesh2sdf.py +3 -75
  15. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/tests/test_sweep_equivalence.py +2 -12
  16. mesh2sdf2-2.2.0/PKG-INFO +0 -118
  17. mesh2sdf2-2.2.0/README.md +0 -92
  18. mesh2sdf2-2.2.0/csrc/makelevelset3.h +0 -21
  19. mesh2sdf2-2.2.0/mesh2sdf2.egg-info/PKG-INFO +0 -118
  20. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/LICENSE +0 -0
  21. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/MANIFEST.in +0 -0
  22. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/mesh2sdf/__init__.py +0 -0
  23. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/mesh2sdf2.egg-info/SOURCES.txt +0 -0
  24. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/mesh2sdf2.egg-info/dependency_links.txt +0 -0
  25. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/mesh2sdf2.egg-info/requires.txt +0 -0
  26. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/mesh2sdf2.egg-info/top_level.txt +0 -0
  27. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/setup.cfg +0 -0
  28. {mesh2sdf2-2.2.0 → mesh2sdf2-2.3.0}/setup.py +0 -0
@@ -0,0 +1,187 @@
1
+ Metadata-Version: 2.4
2
+ Name: mesh2sdf2
3
+ Version: 2.3.0
4
+ Summary: Compute the signed distance field from an input mesh
5
+ Author-email: Lucas Mosquera <25126199+LuckJMG@users.noreply.github.com>, Peng-Shuai Wang <wangps@hotmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/LuckJMG/mesh2sdf2
8
+ Project-URL: Source, https://github.com/LuckJMG/mesh2sdf2
9
+ Project-URL: Issues, https://github.com/LuckJMG/mesh2sdf2/issues
10
+ Project-URL: Upstream, https://github.com/wang-ps/mesh2sdf
11
+ Keywords: sdf,mesh,signed-distance-field,pybind11,3d
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Development Status :: 5 - Production/Stable
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy
23
+ Requires-Dist: trimesh
24
+ Requires-Dist: scikit-image
25
+ Dynamic: license-file
26
+
27
+ [![Downloads](https://static.pepy.tech/badge/mesh2sdf2)](https://pepy.tech/project/mesh2sdf2) [![Downloads](https://static.pepy.tech/badge/mesh2sdf2/month)](https://pepy.tech/project/mesh2sdf2/month) [![PyPI](https://img.shields.io/pypi/v/mesh2sdf2)](https://pypi.org/project/mesh2sdf2/)
28
+
29
+ # mesh2sdf2
30
+
31
+ Repository: <https://github.com/LuckJMG/mesh2sdf2>. Maintainer: Lucas Mosquera.
32
+
33
+ mesh2sdf2 is a community-maintained fork of [mesh2sdf](https://github.com/wang-ps/mesh2sdf) by Peng-Shuai Wang. The fork keeps the algorithm and the public API of the original project, so the import name is still `mesh2sdf`.
34
+
35
+ ## Project description
36
+
37
+ With mesh2sdf2 you can convert a triangle mesh to a signed distance field (SDF) on a regular grid. The library also works with **non-watertight** meshes, such as the meshes of ShapeNet, since it repairs the surface before it computes the sign.
38
+
39
+ Compared with the original project, mesh2sdf2 supports Python 3.10 to 3.14, builds with current versions of setuptools and pybind11, and computes the SDF about 26 times faster on a 12-thread CPU.
40
+
41
+ ![Example of a mesh from ShapeNet](https://raw.githubusercontent.com/wang-ps/mesh2sdf/master/example/data/result.png)
42
+
43
+ ## Who this project is for
44
+
45
+ This project is for researchers and developers who need signed distance fields from 3D meshes, for example to generate training data for 3D deep learning. The original mesh2sdf generated the training data of the paper [Dual Octree Graph Networks (SIGGRAPH 2022)](https://wang-ps.github.io/dualocnn).
46
+
47
+ ## Project dependencies
48
+
49
+ Before you use mesh2sdf2, make sure that you have:
50
+
51
+ - Python 3.10 or later.
52
+ - A C++ compiler that [pybind11 supports](https://github.com/pybind/pybind11#supported-compilers), if no wheel exists for your platform or you install from source.
53
+
54
+ pip installs the Python dependencies (NumPy, trimesh, and scikit-image) automatically.
55
+
56
+ ## Instructions for using mesh2sdf2
57
+
58
+ Get started with mesh2sdf2 by installing it from PyPI.
59
+
60
+ ### Install mesh2sdf2
61
+
62
+ 1. Install the package from PyPI.
63
+
64
+ ```shell
65
+ pip install mesh2sdf2
66
+ ```
67
+
68
+ 2. Alternatively, install it from the source code.
69
+
70
+ ```shell
71
+ git clone https://github.com/LuckJMG/mesh2sdf2.git
72
+ cd mesh2sdf2
73
+ pip install .
74
+ ```
75
+
76
+ ### Run mesh2sdf2
77
+
78
+ 1. Scale the vertices of your mesh to the range `[-1, 1]` and call `mesh2sdf.compute`.
79
+
80
+ ```python
81
+ import trimesh
82
+ import mesh2sdf
83
+
84
+ mesh = trimesh.creation.icosphere(radius=0.8)
85
+ size = 128
86
+ sdf = mesh2sdf.compute(mesh.vertices, mesh.faces, size, fix=True, level=2 / size)
87
+ print(sdf.shape) # (128, 128, 128)
88
+ ```
89
+
90
+ 2. To process the example mesh of the repository, run the demo script from the repository root.
91
+
92
+ ```shell
93
+ python example/demo.py
94
+ ```
95
+
96
+ The script writes `example/data/plane.fixed.obj` with the repaired mesh and `example/data/plane.npy` with the SDF. To process another mesh, pass its path, for example `python example/demo.py path/to/mesh.obj`.
97
+
98
+ The signature of the function is `mesh2sdf.compute(vertices, faces, size=128, fix=False, level=0.015, return_mesh=False)`.
99
+
100
+ | Parameter | Description |
101
+ |---|---|
102
+ | `vertices` | Array of shape `(N, 3)`. The values must be in the range `[-1, 1]`. |
103
+ | `faces` | Array of shape `(M, 3)` with the vertex indices of each triangle. |
104
+ | `size` | Resolution of the grid. The grid has `size` samples per axis and spans `[-1, 1]`, both ends included. |
105
+ | `fix` | If `True`, repairs the mesh before it computes the sign. Use it for non-watertight meshes. |
106
+ | `level` | Level-set value for the repair. The recommended value is `2 / size`. |
107
+ | `return_mesh` | If `True`, also returns the repaired mesh as a `trimesh.Trimesh`. |
108
+
109
+ The function returns a `float32` array of shape `(size, size, size)`.
110
+
111
+ ### Troubleshoot mesh2sdf2
112
+
113
+ | Issue | Solution |
114
+ |---|---|
115
+ | The SDF has wrong values and no error appears. | Scale the vertices to the range `[-1, 1]`, since the function does not check the range. |
116
+ | The sign of the SDF is wrong on an open mesh. | Call `compute` with `fix=True`. |
117
+ | `compute` raises `ValueError`. | Use a `size` of 2 or more. |
118
+ | `pip install` fails while it builds the extension. | Install a C++ compiler that pybind11 supports. |
119
+
120
+ ## Performance
121
+
122
+ mesh2sdf2 2.3.0 computes the SDF about **26x faster** than the original mesh2sdf 1.1.0 on a 12-thread CPU, and about 5.6x faster on one thread. Both numbers are the geometric mean over five workloads, which are the four in the next table and a cube with `size=64`. Each time is the median of 3 runs with Python 3.14.
123
+
124
+ | Workload | mesh2sdf 1.1.0 | 2.3.0, 12 threads | 2.3.0, 1 thread |
125
+ |---|---|---|---|
126
+ | cube | 6066 ms | 116 ms (52.5x) | 402 ms (15.1x) |
127
+ | plane | 7245 ms | 277 ms (26.2x) | 1195 ms (6.1x) |
128
+ | icosphere, 5k triangles | 7442 ms | 405 ms (18.4x) | 2815 ms (2.6x) |
129
+ | icosphere, 20k triangles | 9040 ms | 634 ms (14.3x) | 4626 ms (2.0x) |
130
+
131
+ The next table gives the cumulative gain of each improvement on the cube, with `size=128` and 12 threads.
132
+
133
+ | Stage | Time | Speedup |
134
+ |---|---|---|
135
+ | mesh2sdf 1.1.0 | 6066 ms | 1.00x |
136
+ | cache triangle distance data | 4011 ms | 1.51x |
137
+ | wavefront parallel sweep | 1321 ms | 4.59x |
138
+ | Orthodox C++ port | 1167 ms | 5.20x |
139
+ | geometry and parallel split (2.2.0) | 1077 ms | 5.63x |
140
+ | skip repeated distances, row wavefront (2.3.0) | 116 ms | 52.5x |
141
+
142
+ The C++ core releases the Python global interpreter lock (GIL), so several Python threads can call `compute` at the same time. With `OMP_NUM_THREADS=1`, four Python threads that each process the cube finish 57x faster than with the original project, from 24.3 s to 0.43 s. The release of the GIL gives 4x of that gain. In 2.2.0, the sweep took almost all the time, so the parallel sign, memcpy, and parallel init steps gave no measurable gain on these meshes.
143
+
144
+ To reproduce the numbers, run `just bench-versions`. The run takes about 30 minutes, and the speedup depends on the number of CPU cores.
145
+
146
+ ## How it works
147
+
148
+ 1. mesh2sdf2 computes the **unsigned** distance field with the fast sweeping algorithm of [SDFGen](https://github.com/christopherbatty/SDFGen) by Christopher Batty. This step is accurate even for non-watertight meshes, since the unsigned distance does not depend on the inside or the outside of the surface.
149
+ 2. If `fix=True`, the marching cubes algorithm extracts the level set at the small value `level`. The result is a manifold triangle mesh.
150
+ 3. The extracted mesh can have several connected components, so mesh2sdf2 keeps the component with the largest bounding box.
151
+ 4. mesh2sdf2 computes the signed distance field again on the kept mesh and returns it as the final output.
152
+
153
+ ## Contributing guidelines
154
+
155
+ To report a bug or propose a change, open an issue or a pull request in the [GitHub repository](https://github.com/LuckJMG/mesh2sdf2).
156
+
157
+ ## Additional documentation
158
+
159
+ For more information:
160
+
161
+ - [Original mesh2sdf repository](https://github.com/wang-ps/mesh2sdf), with the paper and the algorithm.
162
+ - [Dual Octree Graph Networks](https://wang-ps.github.io/dualocnn), the project page of the paper that uses mesh2sdf.
163
+ - [SDFGen](https://github.com/christopherbatty/SDFGen), the source of the fast sweeping algorithm.
164
+
165
+ ## How to get help
166
+
167
+ - [GitHub issues](https://github.com/LuckJMG/mesh2sdf2/issues), for bugs and questions about the fork.
168
+
169
+ ## Citation
170
+
171
+ If you use the code in your research, please cite the paper of the original authors.
172
+
173
+ ```bibtex
174
+ @article {Wang-Sig2022,
175
+ title = {Dual Octree Graph Networks for Learning Adaptive Volumetric
176
+ Shape Representations},
177
+ author = {Wang, Peng-Shuai and Liu, Yang and Tong, Xin},
178
+ journal = {ACM Transactions on Graphics (SIGGRAPH)},
179
+ volume = {41},
180
+ number = {4},
181
+ year = {2022},
182
+ }
183
+ ```
184
+
185
+ ## Terms of use
186
+
187
+ mesh2sdf2 is licensed under the MIT License. See [LICENSE](LICENSE).
@@ -0,0 +1,161 @@
1
+ [![Downloads](https://static.pepy.tech/badge/mesh2sdf2)](https://pepy.tech/project/mesh2sdf2) [![Downloads](https://static.pepy.tech/badge/mesh2sdf2/month)](https://pepy.tech/project/mesh2sdf2/month) [![PyPI](https://img.shields.io/pypi/v/mesh2sdf2)](https://pypi.org/project/mesh2sdf2/)
2
+
3
+ # mesh2sdf2
4
+
5
+ Repository: <https://github.com/LuckJMG/mesh2sdf2>. Maintainer: Lucas Mosquera.
6
+
7
+ mesh2sdf2 is a community-maintained fork of [mesh2sdf](https://github.com/wang-ps/mesh2sdf) by Peng-Shuai Wang. The fork keeps the algorithm and the public API of the original project, so the import name is still `mesh2sdf`.
8
+
9
+ ## Project description
10
+
11
+ With mesh2sdf2 you can convert a triangle mesh to a signed distance field (SDF) on a regular grid. The library also works with **non-watertight** meshes, such as the meshes of ShapeNet, since it repairs the surface before it computes the sign.
12
+
13
+ Compared with the original project, mesh2sdf2 supports Python 3.10 to 3.14, builds with current versions of setuptools and pybind11, and computes the SDF about 26 times faster on a 12-thread CPU.
14
+
15
+ ![Example of a mesh from ShapeNet](https://raw.githubusercontent.com/wang-ps/mesh2sdf/master/example/data/result.png)
16
+
17
+ ## Who this project is for
18
+
19
+ This project is for researchers and developers who need signed distance fields from 3D meshes, for example to generate training data for 3D deep learning. The original mesh2sdf generated the training data of the paper [Dual Octree Graph Networks (SIGGRAPH 2022)](https://wang-ps.github.io/dualocnn).
20
+
21
+ ## Project dependencies
22
+
23
+ Before you use mesh2sdf2, make sure that you have:
24
+
25
+ - Python 3.10 or later.
26
+ - A C++ compiler that [pybind11 supports](https://github.com/pybind/pybind11#supported-compilers), if no wheel exists for your platform or you install from source.
27
+
28
+ pip installs the Python dependencies (NumPy, trimesh, and scikit-image) automatically.
29
+
30
+ ## Instructions for using mesh2sdf2
31
+
32
+ Get started with mesh2sdf2 by installing it from PyPI.
33
+
34
+ ### Install mesh2sdf2
35
+
36
+ 1. Install the package from PyPI.
37
+
38
+ ```shell
39
+ pip install mesh2sdf2
40
+ ```
41
+
42
+ 2. Alternatively, install it from the source code.
43
+
44
+ ```shell
45
+ git clone https://github.com/LuckJMG/mesh2sdf2.git
46
+ cd mesh2sdf2
47
+ pip install .
48
+ ```
49
+
50
+ ### Run mesh2sdf2
51
+
52
+ 1. Scale the vertices of your mesh to the range `[-1, 1]` and call `mesh2sdf.compute`.
53
+
54
+ ```python
55
+ import trimesh
56
+ import mesh2sdf
57
+
58
+ mesh = trimesh.creation.icosphere(radius=0.8)
59
+ size = 128
60
+ sdf = mesh2sdf.compute(mesh.vertices, mesh.faces, size, fix=True, level=2 / size)
61
+ print(sdf.shape) # (128, 128, 128)
62
+ ```
63
+
64
+ 2. To process the example mesh of the repository, run the demo script from the repository root.
65
+
66
+ ```shell
67
+ python example/demo.py
68
+ ```
69
+
70
+ The script writes `example/data/plane.fixed.obj` with the repaired mesh and `example/data/plane.npy` with the SDF. To process another mesh, pass its path, for example `python example/demo.py path/to/mesh.obj`.
71
+
72
+ The signature of the function is `mesh2sdf.compute(vertices, faces, size=128, fix=False, level=0.015, return_mesh=False)`.
73
+
74
+ | Parameter | Description |
75
+ |---|---|
76
+ | `vertices` | Array of shape `(N, 3)`. The values must be in the range `[-1, 1]`. |
77
+ | `faces` | Array of shape `(M, 3)` with the vertex indices of each triangle. |
78
+ | `size` | Resolution of the grid. The grid has `size` samples per axis and spans `[-1, 1]`, both ends included. |
79
+ | `fix` | If `True`, repairs the mesh before it computes the sign. Use it for non-watertight meshes. |
80
+ | `level` | Level-set value for the repair. The recommended value is `2 / size`. |
81
+ | `return_mesh` | If `True`, also returns the repaired mesh as a `trimesh.Trimesh`. |
82
+
83
+ The function returns a `float32` array of shape `(size, size, size)`.
84
+
85
+ ### Troubleshoot mesh2sdf2
86
+
87
+ | Issue | Solution |
88
+ |---|---|
89
+ | The SDF has wrong values and no error appears. | Scale the vertices to the range `[-1, 1]`, since the function does not check the range. |
90
+ | The sign of the SDF is wrong on an open mesh. | Call `compute` with `fix=True`. |
91
+ | `compute` raises `ValueError`. | Use a `size` of 2 or more. |
92
+ | `pip install` fails while it builds the extension. | Install a C++ compiler that pybind11 supports. |
93
+
94
+ ## Performance
95
+
96
+ mesh2sdf2 2.3.0 computes the SDF about **26x faster** than the original mesh2sdf 1.1.0 on a 12-thread CPU, and about 5.6x faster on one thread. Both numbers are the geometric mean over five workloads, which are the four in the next table and a cube with `size=64`. Each time is the median of 3 runs with Python 3.14.
97
+
98
+ | Workload | mesh2sdf 1.1.0 | 2.3.0, 12 threads | 2.3.0, 1 thread |
99
+ |---|---|---|---|
100
+ | cube | 6066 ms | 116 ms (52.5x) | 402 ms (15.1x) |
101
+ | plane | 7245 ms | 277 ms (26.2x) | 1195 ms (6.1x) |
102
+ | icosphere, 5k triangles | 7442 ms | 405 ms (18.4x) | 2815 ms (2.6x) |
103
+ | icosphere, 20k triangles | 9040 ms | 634 ms (14.3x) | 4626 ms (2.0x) |
104
+
105
+ The next table gives the cumulative gain of each improvement on the cube, with `size=128` and 12 threads.
106
+
107
+ | Stage | Time | Speedup |
108
+ |---|---|---|
109
+ | mesh2sdf 1.1.0 | 6066 ms | 1.00x |
110
+ | cache triangle distance data | 4011 ms | 1.51x |
111
+ | wavefront parallel sweep | 1321 ms | 4.59x |
112
+ | Orthodox C++ port | 1167 ms | 5.20x |
113
+ | geometry and parallel split (2.2.0) | 1077 ms | 5.63x |
114
+ | skip repeated distances, row wavefront (2.3.0) | 116 ms | 52.5x |
115
+
116
+ The C++ core releases the Python global interpreter lock (GIL), so several Python threads can call `compute` at the same time. With `OMP_NUM_THREADS=1`, four Python threads that each process the cube finish 57x faster than with the original project, from 24.3 s to 0.43 s. The release of the GIL gives 4x of that gain. In 2.2.0, the sweep took almost all the time, so the parallel sign, memcpy, and parallel init steps gave no measurable gain on these meshes.
117
+
118
+ To reproduce the numbers, run `just bench-versions`. The run takes about 30 minutes, and the speedup depends on the number of CPU cores.
119
+
120
+ ## How it works
121
+
122
+ 1. mesh2sdf2 computes the **unsigned** distance field with the fast sweeping algorithm of [SDFGen](https://github.com/christopherbatty/SDFGen) by Christopher Batty. This step is accurate even for non-watertight meshes, since the unsigned distance does not depend on the inside or the outside of the surface.
123
+ 2. If `fix=True`, the marching cubes algorithm extracts the level set at the small value `level`. The result is a manifold triangle mesh.
124
+ 3. The extracted mesh can have several connected components, so mesh2sdf2 keeps the component with the largest bounding box.
125
+ 4. mesh2sdf2 computes the signed distance field again on the kept mesh and returns it as the final output.
126
+
127
+ ## Contributing guidelines
128
+
129
+ To report a bug or propose a change, open an issue or a pull request in the [GitHub repository](https://github.com/LuckJMG/mesh2sdf2).
130
+
131
+ ## Additional documentation
132
+
133
+ For more information:
134
+
135
+ - [Original mesh2sdf repository](https://github.com/wang-ps/mesh2sdf), with the paper and the algorithm.
136
+ - [Dual Octree Graph Networks](https://wang-ps.github.io/dualocnn), the project page of the paper that uses mesh2sdf.
137
+ - [SDFGen](https://github.com/christopherbatty/SDFGen), the source of the fast sweeping algorithm.
138
+
139
+ ## How to get help
140
+
141
+ - [GitHub issues](https://github.com/LuckJMG/mesh2sdf2/issues), for bugs and questions about the fork.
142
+
143
+ ## Citation
144
+
145
+ If you use the code in your research, please cite the paper of the original authors.
146
+
147
+ ```bibtex
148
+ @article {Wang-Sig2022,
149
+ title = {Dual Octree Graph Networks for Learning Adaptive Volumetric
150
+ Shape Representations},
151
+ author = {Wang, Peng-Shuai and Liu, Yang and Tong, Xin},
152
+ journal = {ACM Transactions on Graphics (SIGGRAPH)},
153
+ volume = {41},
154
+ number = {4},
155
+ year = {2022},
156
+ }
157
+ ```
158
+
159
+ ## Terms of use
160
+
161
+ mesh2sdf2 is licensed under the MIT License. See [LICENSE](LICENSE).
@@ -16,21 +16,6 @@ template <class T> struct Array3 {
16
16
  storage = NULL;
17
17
  }
18
18
 
19
- Array3(int ni_, int nj_, int nk_) {
20
- assert(ni_ >= 0 && nj_ >= 0 && nk_ >= 0);
21
-
22
- ni = ni_;
23
- nj = nj_;
24
- nk = nk_;
25
- storage = NULL;
26
-
27
- size_t n = (size_t)ni_ * nj_ * nk_;
28
- if (n > 0) {
29
- storage = (T *)malloc(n * sizeof(T));
30
- assert(storage != NULL);
31
- }
32
- }
33
-
34
19
  Array3(int ni_, int nj_, int nk_, const T &value) {
35
20
  assert(ni_ >= 0 && nj_ >= 0 && nk_ >= 0);
36
21
 
@@ -54,49 +39,19 @@ template <class T> struct Array3 {
54
39
  Array3(const Array3 &) = delete;
55
40
  Array3 &operator=(const Array3 &) = delete;
56
41
 
57
- Array3(Array3 &&o) noexcept {
58
- ni = o.ni;
59
- nj = o.nj;
60
- nk = o.nk;
61
- storage = o.storage;
62
-
63
- o.ni = 0;
64
- o.nj = 0;
65
- o.nk = 0;
66
- o.storage = NULL;
67
- }
68
-
69
- Array3 &operator=(Array3 &&o) noexcept {
70
- if (this != &o) {
71
- free(storage);
72
-
73
- ni = o.ni;
74
- nj = o.nj;
75
- nk = o.nk;
76
- storage = o.storage;
77
-
78
- o.ni = 0;
79
- o.nj = 0;
80
- o.nk = 0;
81
- o.storage = NULL;
82
- }
83
-
84
- return *this;
85
- }
86
-
87
42
  inline size_t index(int i, int j, int k) const {
88
43
  return (size_t)i + (size_t)ni * ((size_t)j + (size_t)nj * (size_t)k);
89
44
  }
90
45
 
91
46
  const T &operator()(int i, int j, int k) const {
92
47
  assert(i >= 0 && i < ni && j >= 0 && j < nj && k >= 0 && k < nk);
93
- // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
48
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-security.ArrayBound)
94
49
  return storage[index(i, j, k)];
95
50
  }
96
51
 
97
52
  T &operator()(int i, int j, int k) {
98
53
  assert(i >= 0 && i < ni && j >= 0 && j < nj && k >= 0 && k < nk);
99
- // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
54
+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn,clang-analyzer-security.ArrayBound)
100
55
  return storage[index(i, j, k)];
101
56
  }
102
57
 
@@ -2,7 +2,6 @@
2
2
  #define GEOMETRY_H
3
3
 
4
4
  #include <assert.h>
5
- #include <math.h>
6
5
 
7
6
  #include "vec.h"
8
7
 
@@ -18,6 +17,14 @@ struct TriangleData {
18
17
  SegmentData edge12, edge13, edge23;
19
18
  };
20
19
 
20
+ struct Grid {
21
+ Vec3f origin;
22
+ float dx;
23
+ int ni, nj, nk;
24
+ };
25
+
26
+ static constexpr int exact_band = 1;
27
+
21
28
  static inline int clamp_int(int v, int lo, int hi) {
22
29
  if (v < lo) {
23
30
  return lo;
@@ -28,8 +35,6 @@ static inline int clamp_int(int v, int lo, int hi) {
28
35
  return v;
29
36
  }
30
37
 
31
- static inline float min_f(float a, float b) { return a < b ? a : b; }
32
-
33
38
  static inline double min3(double a, double b, double c) {
34
39
  double m = a;
35
40
  if (b < m) {
@@ -52,6 +57,25 @@ static inline double max3(double a, double b, double c) {
52
57
  return m;
53
58
  }
54
59
 
60
+ struct IndexRange {
61
+ int lo, hi;
62
+ };
63
+
64
+ // grid cells within exact_band of a triangle's extent [min(p,q,r), max(p,q,r)]
65
+ static inline IndexRange band_range(double p, double q, double r, int n) {
66
+ IndexRange range = {
67
+ clamp_int((int)min3(p, q, r) - exact_band, 0, n - 1),
68
+ clamp_int((int)max3(p, q, r) + exact_band + 1, 0, n - 1)};
69
+ return range;
70
+ }
71
+
72
+ // grid rows inside a triangle's extent [min(p,q,r), max(p,q,r)]
73
+ static inline IndexRange row_range(double p, double q, double r, int n) {
74
+ IndexRange range = {clamp_int((int)ceil(min3(p, q, r)), 0, n - 1),
75
+ clamp_int((int)floor(max3(p, q, r)), 0, n - 1)};
76
+ return range;
77
+ }
78
+
55
79
  // find distance x0 is from segment x1-x2
56
80
  static inline float point_segment_distance(const Vec3f &x0, const Vec3f &x1,
57
81
  const Vec3f &x2,
@@ -172,15 +196,15 @@ struct TriSetup {
172
196
  double r_i, r_j, r_k;
173
197
  };
174
198
 
175
- static inline TriSetup setup_triangle(const Vec3ui &t, const Vec3f *x,
199
+ static inline TriSetup setup_triangle(const Vec3ui &t, const Vec3f *vertices,
176
200
  const Vec3f &origin, float dx) {
177
201
  unsigned int p = t.x, q = t.y, r = t.z;
178
202
  TriSetup s;
179
203
 
180
204
  TriangleData &triangle = s.triangle;
181
- triangle.x1 = x[p];
182
- triangle.x2 = x[q];
183
- triangle.x3 = x[r];
205
+ triangle.x1 = vertices[p];
206
+ triangle.x2 = vertices[q];
207
+ triangle.x3 = vertices[r];
184
208
  triangle.x13 = triangle.x1 - triangle.x3;
185
209
  triangle.x23 = triangle.x2 - triangle.x3;
186
210
  triangle.m13 = mag2(triangle.x13);
@@ -199,15 +223,15 @@ static inline TriSetup setup_triangle(const Vec3ui &t, const Vec3f *x,
199
223
  triangle.edge23 = {triangle.x3 - triangle.x2,
200
224
  (double)mag2(triangle.x3 - triangle.x2)};
201
225
 
202
- s.p_i = ((double)x[p].x - origin.x) / dx;
203
- s.p_j = ((double)x[p].y - origin.y) / dx;
204
- s.p_k = ((double)x[p].z - origin.z) / dx;
205
- s.q_i = ((double)x[q].x - origin.x) / dx;
206
- s.q_j = ((double)x[q].y - origin.y) / dx;
207
- s.q_k = ((double)x[q].z - origin.z) / dx;
208
- s.r_i = ((double)x[r].x - origin.x) / dx;
209
- s.r_j = ((double)x[r].y - origin.y) / dx;
210
- s.r_k = ((double)x[r].z - origin.z) / dx;
226
+ s.p_i = ((double)vertices[p].x - origin.x) / dx;
227
+ s.p_j = ((double)vertices[p].y - origin.y) / dx;
228
+ s.p_k = ((double)vertices[p].z - origin.z) / dx;
229
+ s.q_i = ((double)vertices[q].x - origin.x) / dx;
230
+ s.q_j = ((double)vertices[q].y - origin.y) / dx;
231
+ s.q_k = ((double)vertices[q].z - origin.z) / dx;
232
+ s.r_i = ((double)vertices[r].x - origin.x) / dx;
233
+ s.r_j = ((double)vertices[r].y - origin.y) / dx;
234
+ s.r_k = ((double)vertices[r].z - origin.z) / dx;
211
235
  return s;
212
236
  }
213
237