conquer3d 0.3.1__tar.gz → 0.3.3__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 (97) hide show
  1. {conquer3d-0.3.1/conquer3d.egg-info → conquer3d-0.3.3}/PKG-INFO +21 -1
  2. {conquer3d-0.3.1 → conquer3d-0.3.3}/README.md +20 -0
  3. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/_C.so +0 -0
  4. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/__init__.py +4 -1
  5. conquer3d-0.3.3/conquer3d/conversion/__init__.py +13 -0
  6. {conquer3d-0.3.1/conquer3d/data_structure → conquer3d-0.3.3/conquer3d/conversion}/grid.py +49 -88
  7. conquer3d-0.3.3/conquer3d/conversion/mesh.py +120 -0
  8. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +299 -0
  9. conquer3d-0.3.3/conquer3d/csrc/binds/primitive/ray.cpp +37 -0
  10. conquer3d-0.3.3/conquer3d/csrc/binds/primitive/triangle.cpp +68 -0
  11. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/mesh_bvh.cu +1 -1
  12. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/triangle_mesh.cu +299 -1
  13. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/triangle_mesh.h +71 -0
  14. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x1.h +14 -0
  15. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/edge.h +7 -0
  16. conquer3d-0.3.1/conquer3d/csrc/primitive/triangles.h → conquer3d-0.3.3/conquer3d/csrc/primitive/triangle.h +156 -6
  17. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/pybind.cpp +4 -0
  18. conquer3d-0.3.3/conquer3d/data/collate/mesh.py +40 -0
  19. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/dataset/digit3d.py +4 -8
  20. conquer3d-0.3.3/conquer3d/data/transform/base.py +39 -0
  21. conquer3d-0.3.3/conquer3d/data/transform/ops.py +62 -0
  22. conquer3d-0.3.3/conquer3d/data/transform/vertex.py +55 -0
  23. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data_structure/__init__.py +0 -6
  24. conquer3d-0.3.3/conquer3d/data_structure/bmesh.py +23 -0
  25. conquer3d-0.3.3/conquer3d/data_structure/grid.py +65 -0
  26. conquer3d-0.3.3/conquer3d/primitive/__init__.py +3 -0
  27. {conquer3d-0.3.1 → conquer3d-0.3.3/conquer3d.egg-info}/PKG-INFO +21 -1
  28. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/SOURCES.txt +11 -1
  29. {conquer3d-0.3.1 → conquer3d-0.3.3}/pyproject.toml +1 -1
  30. conquer3d-0.3.1/conquer3d/primitive/__init__.py +0 -0
  31. {conquer3d-0.3.1 → conquer3d-0.3.3}/LICENSE +0 -0
  32. {conquer3d-0.3.1 → conquer3d-0.3.3}/MANIFEST.in +0 -0
  33. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/_C.pyi +0 -0
  34. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/creation/__init__.py +0 -0
  35. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/creation/triangle_creation.py +0 -0
  36. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
  37. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
  38. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/grid.cpp +0 -0
  39. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
  40. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
  41. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -0
  42. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
  43. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/ops/chamfer.cpp +0 -0
  44. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/ops/mc.cpp +0 -0
  45. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
  46. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
  47. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/check.h +0 -0
  48. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/constants.h +0 -0
  49. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/creation/triangle_creation.h +0 -0
  50. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/bvh.cu +0 -0
  51. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/bvh.h +0 -0
  52. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
  53. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
  54. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/kdtree.h +0 -0
  55. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/mesh_bvh.h +0 -0
  56. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
  57. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/data_structure/zcurve.h +0 -0
  58. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f2x2.h +0 -0
  59. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x3.h +0 -0
  60. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f3x4.h +0 -0
  61. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f4x1.h +0 -0
  62. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/f4x4.h +0 -0
  63. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/maths.h +0 -0
  64. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/maths/ops.h +0 -0
  65. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/chamfer.cu +0 -0
  66. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/chamfer.h +0 -0
  67. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc.cu +0 -0
  68. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc.h +0 -0
  69. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/ops/mc_data.h +0 -0
  70. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/aabb.h +0 -0
  71. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs.cu +0 -0
  72. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs.h +0 -0
  73. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
  74. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
  75. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs.cu +0 -0
  76. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs.h +0 -0
  77. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
  78. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
  79. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/csrc/primitive/ray.h +0 -0
  80. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/__init__.py +0 -0
  81. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/collate/__init__.py +0 -0
  82. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/collate/sparse_tensor.py +0 -0
  83. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/dataset/__init__.py +0 -0
  84. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/dataset/base_mesh.py +0 -0
  85. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/data/transform/__init__.py +0 -0
  86. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/__init__.py +0 -0
  87. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/diff_marching_cubes.py +0 -0
  88. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/distance.py +0 -0
  89. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/ops/marching_cubes.py +0 -0
  90. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/primitive/gs.py +0 -0
  91. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d/primitive/pgs.py +0 -0
  92. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/dependency_links.txt +0 -0
  93. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/not-zip-safe +0 -0
  94. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/requires.txt +0 -0
  95. {conquer3d-0.3.1 → conquer3d-0.3.3}/conquer3d.egg-info/top_level.txt +0 -0
  96. {conquer3d-0.3.1 → conquer3d-0.3.3}/setup.cfg +0 -0
  97. {conquer3d-0.3.1 → conquer3d-0.3.3}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Geometric Cuda Tool Box
5
5
  Author-email: Do Hoang Khoi <khoido8899@gmail.com>
6
6
  License-Expression: MIT
@@ -63,6 +63,8 @@ pip install pybind11-stubgen
63
63
  pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
64
64
 
65
65
  pip install plotly open3d jupyter trimesh point-cloud-utils meshlib
66
+
67
+ pip install rectified-flow-pytorch
66
68
  ```
67
69
 
68
70
  # Development
@@ -129,6 +131,24 @@ twine upload dist/* --verbose
129
131
  }
130
132
  ```
131
133
 
134
+ ```bibtex
135
+ @InProceedings{10.1007/978-3-662-05105-4_2,
136
+ author="Meyer, Mark
137
+ and Desbrun, Mathieu
138
+ and Schr{\"o}der, Peter
139
+ and Barr, Alan H.",
140
+ editor="Hege, Hans-Christian
141
+ and Polthier, Konrad",
142
+ title="Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
143
+ booktitle="Visualization and Mathematics III",
144
+ year="2003",
145
+ publisher="Springer Berlin Heidelberg",
146
+ address="Berlin, Heidelberg",
147
+ pages="35--57",
148
+ isbn="978-3-662-05105-4"
149
+ }
150
+ ```
151
+
132
152
  ## Blog Post
133
153
  - [Thinking Parallel, Part I: Collision Detection on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-i-collision-detection-gpu/)
134
154
  - [Thinking Parallel, Part II: Tree Traversal on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-ii-tree-traversal-gpu/)
@@ -34,6 +34,8 @@ pip install pybind11-stubgen
34
34
  pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
35
35
 
36
36
  pip install plotly open3d jupyter trimesh point-cloud-utils meshlib
37
+
38
+ pip install rectified-flow-pytorch
37
39
  ```
38
40
 
39
41
  # Development
@@ -100,6 +102,24 @@ twine upload dist/* --verbose
100
102
  }
101
103
  ```
102
104
 
105
+ ```bibtex
106
+ @InProceedings{10.1007/978-3-662-05105-4_2,
107
+ author="Meyer, Mark
108
+ and Desbrun, Mathieu
109
+ and Schr{\"o}der, Peter
110
+ and Barr, Alan H.",
111
+ editor="Hege, Hans-Christian
112
+ and Polthier, Konrad",
113
+ title="Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
114
+ booktitle="Visualization and Mathematics III",
115
+ year="2003",
116
+ publisher="Springer Berlin Heidelberg",
117
+ address="Berlin, Heidelberg",
118
+ pages="35--57",
119
+ isbn="978-3-662-05105-4"
120
+ }
121
+ ```
122
+
103
123
  ## Blog Post
104
124
  - [Thinking Parallel, Part I: Collision Detection on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-i-collision-detection-gpu/)
105
125
  - [Thinking Parallel, Part II: Tree Traversal on the GPU](https://developer.nvidia.com/blog/thinking-parallel-part-ii-tree-traversal-gpu/)
@@ -5,5 +5,8 @@ from . import creation
5
5
  from . import data_structure
6
6
  from . import primitive
7
7
  from . import ops
8
+ from . import conversion
8
9
 
9
- __all__ = ['_C', 'creation', 'data_structure', 'primitive', 'ops']
10
+ from .primitive import Triangle, Ray
11
+
12
+ __all__ = ['_C', 'creation', 'data_structure', 'primitive', 'ops', 'conversion', 'Triangle', 'Ray']
@@ -0,0 +1,13 @@
1
+ from .grid import (
2
+ voxel2sparse,
3
+ sparse2voxel,
4
+ sparse_coo2dense_occ,
5
+ dense_occ2sparse_coo
6
+ )
7
+
8
+ __all__ = [
9
+ "voxel2sparse",
10
+ "sparse2voxel",
11
+ "sparse_coo2dense_occ",
12
+ "dense_occ2sparse_coo"
13
+ ]
@@ -1,68 +1,5 @@
1
1
  import torch
2
2
  from typing import Tuple, List, Union
3
- from .. import _C
4
-
5
- def create_voxel_grid(
6
- grid_min: Union[List[float], Tuple[float, float, float]],
7
- grid_max: Union[List[float], Tuple[float, float, float]],
8
- res: Union[List[int], Tuple[int, int, int]],
9
- device: str = "cuda"
10
- ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
11
- """
12
- Creates a structured 3D voxel grid efficiently.
13
-
14
- Args:
15
- grid_min (List[float] | Tuple[float, float, float]): The minimum (x, y, z) bounding box coordinates.
16
- grid_max (List[float] | Tuple[float, float, float]): The maximum (x, y, z) bounding box coordinates.
17
- res (List[int] | Tuple[int, int, int]): The number of vertices along each axis (rx, ry, rz).
18
- device (str, optional): Target device for the tensors (e.g., "cuda" or "cpu"). Defaults to "cuda".
19
-
20
- Returns:
21
- Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
22
- - grid_vertices (torch.Tensor): A float32 tensor of shape (N, 3) containing all grid coordinates.
23
- - voxels (torch.Tensor): An int32 tensor of shape (V, 8) containing corner indices
24
- for each voxel, mapped identically to the Marching Cubes convention.
25
- - idx_grids (torch.Tensor): An int64 tensor of shape (N, 3) containing the (i, j, k) 3D coordinate indices for each vertex.
26
- """
27
- return _C.create_voxel_grid(list(grid_min), list(grid_max), list(res), device)
28
-
29
- def compute_grid_normal(
30
- sdf: torch.Tensor,
31
- grid_vertices: torch.Tensor,
32
- idx_grids: torch.Tensor,
33
- res: Union[List[int], Tuple[int, int, int]]
34
- ) -> torch.Tensor:
35
- """
36
- Computes smooth normals (gradients) for a voxel grid using central differences.
37
-
38
- Args:
39
- sdf (torch.Tensor): A float32 tensor of shape (N,) containing the SDF values.
40
- grid_vertices (torch.Tensor): A float32 tensor of shape (N, 3) containing the grid coordinates.
41
- idx_grids (torch.Tensor): An int64 tensor of shape (N, 3) containing the (i, j, k) indices, returned by create_voxel_grid.
42
- res (List[int] | Tuple[int, int, int]): The number of vertices along each axis (rx, ry, rz).
43
-
44
- Returns:
45
- torch.Tensor: A float32 tensor of shape (N, 3) containing the normalized gradient vectors.
46
- """
47
- return _C.compute_grid_normal(sdf.contiguous(), grid_vertices.contiguous(), idx_grids.contiguous(), list(res))
48
-
49
- def compute_active_voxels(
50
- voxels: torch.Tensor,
51
- sdf: torch.Tensor,
52
- iso: float = 0.0
53
- ) -> torch.Tensor:
54
- """
55
- Computes the indices of active voxels that intersect the isosurface.
56
-
57
- Args:
58
- voxels (torch.Tensor): An int32 tensor of shape (V, 8) containing corner indices for each voxel.
59
- sdf (torch.Tensor): A float32 tensor of shape (N,) containing the SDF values.
60
- iso (float): The isosurface value. Defaults to 0.0.
61
-
62
- Returns:
63
- torch.Tensor: An int64 tensor containing the indices of the active voxels.
64
- """
65
- return _C.compute_active_voxels(voxels.contiguous(), sdf.contiguous(), iso)
66
3
 
67
4
  def voxel2sparse(
68
5
  active_indices: torch.Tensor,
@@ -104,28 +41,6 @@ def voxel2sparse(
104
41
  return sparse_coords
105
42
 
106
43
  def sparse2voxel(
107
- sparse_coords: torch.Tensor,
108
- res: Union[List[int], Tuple[int, int, int]]
109
- ) -> torch.Tensor:
110
- """
111
- Converts a [N, 4] sparse coordinates tensor back to 1D active voxel indices.
112
-
113
- Args:
114
- sparse_coords (torch.Tensor): An int32 tensor of shape (N, 4) in the format [batch_idx, x, y, z].
115
- res (List[int] | Tuple[int, int, int]): The number of vertices along each axis (rx, ry, rz).
116
-
117
- Returns:
118
- torch.Tensor: An int64 tensor containing the indices of the active voxels.
119
- """
120
- x = sparse_coords[:, 1].to(torch.int64)
121
- y = sparse_coords[:, 2].to(torch.int64)
122
- z = sparse_coords[:, 3].to(torch.int64)
123
-
124
- rx, ry, rz = res
125
- active_indices = x * (ry - 1) * (rz - 1) + y * (rz - 1) + z
126
- return active_indices
127
-
128
- def sparse2mesh_topology(
129
44
  sparse_coords: torch.Tensor,
130
45
  sparse_sdfs: torch.Tensor,
131
46
  grid_min: Union[List[float], Tuple[float, float, float]],
@@ -182,9 +97,9 @@ def sparse2mesh_topology(
182
97
 
183
98
  # 6. Convert integer coordinates back to global float positions
184
99
  rx, ry, rz = res
185
- x_coords = torch.linspace(grid_min[0], grid_max[0], rx, device=device, dtype=torch.float32)
186
- y_coords = torch.linspace(grid_min[1], grid_max[1], ry, device=device, dtype=torch.float32)
187
- z_coords = torch.linspace(grid_min[2], grid_max[2], rz, device=device, dtype=torch.float32)
100
+ x_coords = torch.linspace(grid_min[0], grid_max[0], rx + 1, device=device, dtype=torch.float32)
101
+ y_coords = torch.linspace(grid_min[1], grid_max[1], ry + 1, device=device, dtype=torch.float32)
102
+ z_coords = torch.linspace(grid_min[2], grid_max[2], rz + 1, device=device, dtype=torch.float32)
188
103
 
189
104
  ux = x_coords[unique_corners_int[:, 0]]
190
105
  uy = y_coords[unique_corners_int[:, 1]]
@@ -193,3 +108,49 @@ def sparse2mesh_topology(
193
108
  unique_vertices = torch.stack([ux, uy, uz], dim=1)
194
109
 
195
110
  return unique_vertices, local_voxels, merged_sdfs
111
+
112
+ def sparse_coo2dense_occ(
113
+ sparse_coords: torch.Tensor,
114
+ batch_size: int,
115
+ res: Union[List[int], Tuple[int, int, int]]
116
+ ) -> torch.Tensor:
117
+ """
118
+ Converts a [N, 4] sparse coordinates tensor into a [B, 1, rx, ry, rz] dense occupancy grid.
119
+
120
+ Args:
121
+ sparse_coords (torch.Tensor): An int32 tensor of shape (N, 4) in the format [batch_idx, x, y, z].
122
+ batch_size (int): The batch size B.
123
+ res (List[int] | Tuple[int, int, int]): The grid resolution (rx, ry, rz).
124
+
125
+ Returns:
126
+ torch.Tensor: A float32 tensor of shape [B, 1, rx, ry, rz] containing 1.0 at active voxels and 0.0 otherwise.
127
+ """
128
+ rx, ry, rz = res
129
+ dense_occ = torch.zeros((batch_size, 1, rx, ry, rz), dtype=torch.float32, device=sparse_coords.device)
130
+
131
+ b = sparse_coords[:, 0].to(torch.int64)
132
+ x = sparse_coords[:, 1].to(torch.int64)
133
+ y = sparse_coords[:, 2].to(torch.int64)
134
+ z = sparse_coords[:, 3].to(torch.int64)
135
+
136
+ dense_occ[b, 0, x, y, z] = 1.0
137
+ return dense_occ
138
+
139
+ def dense_occ2sparse_coo(
140
+ dense_occ: torch.Tensor,
141
+ threshold: float = 0.0
142
+ ) -> torch.Tensor:
143
+ """
144
+ Converts a [B, C, rx, ry, rz] dense occupancy grid back to a [N, 4] sparse coordinates tensor.
145
+
146
+ Args:
147
+ dense_occ (torch.Tensor): A tensor of shape [B, C, rx, ry, rz].
148
+
149
+ Returns:
150
+ torch.Tensor: An int32 tensor of shape (N, 4) in the format [batch_idx, x, y, z].
151
+ """
152
+ active_mask = dense_occ > threshold
153
+ indices = torch.argwhere(active_mask)
154
+ # indices has shape [N, 5] for [b, c, x, y, z]. We want [batch_idx, x, y, z]
155
+ sparse_coords = indices[:, [0, 2, 3, 4]].to(torch.int32)
156
+ return sparse_coords
@@ -0,0 +1,120 @@
1
+ import torch
2
+ from conquer3d.data_structure.grid import create_voxel_grid, compute_active_voxels
3
+ from conquer3d.conversion.grid import voxel2sparse
4
+ from conquer3d.data_structure import TriangleMesh
5
+ from conquer3d.data_structure.bmesh import BTriangleMesh
6
+ from typing import Union, List, Tuple
7
+
8
+ def mesh2voxel(vertices: torch.Tensor, res: Union[List[int], Tuple[int, int, int]], grid_bound: float = None):
9
+ """
10
+ Computes bounding box of mesh and returns a structured voxel grid.
11
+ """
12
+ if grid_bound is None:
13
+ grid_min = vertices.min(dim=0)[0].tolist()
14
+ grid_max = vertices.max(dim=0)[0].tolist()
15
+ else:
16
+ grid_min = [-grid_bound, -grid_bound, -grid_bound]
17
+ grid_max = [grid_bound, grid_bound, grid_bound]
18
+
19
+ device_str = str(vertices.device)
20
+ if device_str.startswith('cuda'):
21
+ # Fix format if there's an index like cuda:0
22
+ device_str = "cuda"
23
+
24
+ grid_vertices, voxels, idx_grids = create_voxel_grid(grid_min, grid_max, res, device=device_str)
25
+
26
+ # Ensure they are on the exact same device as vertices (especially if multiple GPUs)
27
+ grid_vertices = grid_vertices.to(vertices.device)
28
+ voxels = voxels.to(vertices.device)
29
+ idx_grids = idx_grids.to(vertices.device)
30
+
31
+ return grid_vertices, voxels, idx_grids, grid_min, grid_max
32
+
33
+ def mesh2voxel_sdf(vertices: torch.Tensor, faces: torch.Tensor, grid_vertices: torch.Tensor):
34
+ """
35
+ Computes SDF for grid vertices against the mesh using C++ TriangleMesh fast winding numbers.
36
+ """
37
+ mesh = TriangleMesh(vertices, faces.to(torch.int32))
38
+
39
+ # query_points returns: q_ids, tri_ids, prj_pts, sdf
40
+ _, _, _, sdf = mesh.query_points(
41
+ grid_vertices,
42
+ return_sdf=True,
43
+ return_prj_pts=False,
44
+ sign_mode=0,
45
+ distance_mode=0
46
+ )
47
+ return sdf
48
+
49
+ def mesh2sparse(bmesh: BTriangleMesh, res: Union[List[int], Tuple[int, int, int]], grid_bound: float = 1.2, iso: float = 0.0):
50
+ """
51
+ Batched processing of BTriangleMesh into sparse tensors.
52
+ """
53
+ all_coords = []
54
+ all_sdfs = []
55
+
56
+ for b in range(bmesh.batch_size):
57
+ # Extract individual mesh
58
+ v_mask = bmesh.vertbids == b
59
+ f_mask = bmesh.facebids == b
60
+
61
+ v = bmesh.vertices[v_mask]
62
+ f = bmesh.faces[f_mask]
63
+
64
+ if len(v) == 0:
65
+ continue
66
+
67
+ # Voxelize and Compute SDF
68
+ grid_vertices, voxels, idx_grids, _, _ = mesh2voxel(v, res, grid_bound)
69
+ sdf = mesh2voxel_sdf(v, f, grid_vertices)
70
+
71
+ # Sparse conversion
72
+ active_voxels = compute_active_voxels(voxels, sdf, iso)
73
+ sparse_coords, sparse_sdfs = voxel2sparse(active_voxels, voxels, idx_grids, sdf=sdf, batch_idx=b)
74
+
75
+ all_coords.append(sparse_coords)
76
+ all_sdfs.append(sparse_sdfs)
77
+
78
+ if len(all_coords) > 0:
79
+ return torch.cat(all_coords, dim=0), torch.cat(all_sdfs, dim=0)
80
+ else:
81
+ # Fallback for empty batch
82
+ device = bmesh.vertices.device
83
+ return torch.empty((0, 4), dtype=torch.int32, device=device), torch.empty((0, 8), dtype=torch.float32, device=device)
84
+
85
+ def mesh2sparse_with_dense(bmesh: BTriangleMesh, res: Union[List[int], Tuple[int, int, int]], grid_bound: float = 1.2, iso: float = 0.0):
86
+ """
87
+ Batched processing of BTriangleMesh into sparse tensors, also returning full dense coords.
88
+ """
89
+ all_coords = []
90
+ all_sdfs = []
91
+ all_dense_coords = []
92
+ all_dense_sdfs = []
93
+
94
+ for b in range(bmesh.batch_size):
95
+ v_mask = bmesh.vertbids == b
96
+ f_mask = bmesh.facebids == b
97
+
98
+ v = bmesh.vertices[v_mask]
99
+ f = bmesh.faces[f_mask]
100
+
101
+ if len(v) == 0:
102
+ continue
103
+
104
+ grid_vertices, voxels, idx_grids, _, _ = mesh2voxel(v, res, grid_bound)
105
+ sdf = mesh2voxel_sdf(v, f, grid_vertices)
106
+
107
+ active_voxels = compute_active_voxels(voxels, sdf, iso)
108
+ sparse_coords, sparse_sdfs = voxel2sparse(active_voxels, voxels, idx_grids, sdf=sdf, batch_idx=b)
109
+ dense_coords, dense_sdfs = voxel2sparse(torch.ones_like(voxels[:, 0], dtype=torch.bool), voxels, idx_grids, sdf=sdf, batch_idx=b)
110
+
111
+ all_coords.append(sparse_coords)
112
+ all_sdfs.append(sparse_sdfs)
113
+ all_dense_coords.append(dense_coords)
114
+ all_dense_sdfs.append(dense_sdfs)
115
+
116
+ if len(all_coords) > 0:
117
+ return torch.cat(all_coords, dim=0), torch.cat(all_sdfs, dim=0), torch.cat(all_dense_coords, dim=0), torch.cat(all_dense_sdfs, dim=0)
118
+ else:
119
+ device = bmesh.vertices.device
120
+ return torch.empty((0, 4), dtype=torch.int32, device=device), torch.empty((0, 8), dtype=torch.float32, device=device), torch.empty((0, 4), dtype=torch.int32, device=device), torch.empty((0, 8), dtype=torch.float32, device=device)