conquer3d 0.2.5__tar.gz → 0.2.6__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 (66) hide show
  1. {conquer3d-0.2.5/conquer3d.egg-info → conquer3d-0.2.6}/PKG-INFO +1 -1
  2. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/_C.pyi +14 -2
  3. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/_C.so +0 -0
  4. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/bvh.cpp +69 -32
  5. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +9 -1
  6. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +22 -0
  7. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/bvh.cu +93 -0
  8. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/bvh.h +17 -1
  9. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/mesh_bvh.cu +208 -0
  10. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/mesh_bvh.h +8 -0
  11. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/triangle_mesh.h +7 -0
  12. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/aabb.h +18 -0
  13. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/triangles.h +44 -0
  14. {conquer3d-0.2.5 → conquer3d-0.2.6/conquer3d.egg-info}/PKG-INFO +1 -1
  15. {conquer3d-0.2.5 → conquer3d-0.2.6}/pyproject.toml +1 -1
  16. {conquer3d-0.2.5 → conquer3d-0.2.6}/LICENSE +0 -0
  17. {conquer3d-0.2.5 → conquer3d-0.2.6}/MANIFEST.in +0 -0
  18. {conquer3d-0.2.5 → conquer3d-0.2.6}/README.md +0 -0
  19. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/__init__.py +0 -0
  20. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/creation/__init__.py +0 -0
  21. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/creation/triangle_creation.py +0 -0
  22. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/creation/triangle_creation.cpp +0 -0
  23. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
  24. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
  25. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
  26. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
  27. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
  28. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/check.h +0 -0
  29. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/constants.h +0 -0
  30. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/creation/triangle_creation.h +0 -0
  31. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
  32. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
  33. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/kdtree.h +0 -0
  34. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
  35. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/triangle_mesh.cu +0 -0
  36. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/data_structure/zcurve.h +0 -0
  37. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/f2x2.h +0 -0
  38. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/f3x1.h +0 -0
  39. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/f3x3.h +0 -0
  40. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/f3x4.h +0 -0
  41. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/f4x1.h +0 -0
  42. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/f4x4.h +0 -0
  43. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/maths.h +0 -0
  44. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/maths/ops.h +0 -0
  45. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/edge.h +0 -0
  46. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs.cu +0 -0
  47. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs.h +0 -0
  48. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
  49. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
  50. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs.cu +0 -0
  51. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs.h +0 -0
  52. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
  53. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
  54. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/primitive/ray.h +0 -0
  55. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/csrc/pybind.cpp +0 -0
  56. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/data_structure/__init__.py +0 -0
  57. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/primitive/__init__.py +0 -0
  58. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/primitive/gs.py +0 -0
  59. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d/primitive/pgs.py +0 -0
  60. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d.egg-info/SOURCES.txt +0 -0
  61. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d.egg-info/dependency_links.txt +0 -0
  62. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d.egg-info/not-zip-safe +0 -0
  63. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d.egg-info/requires.txt +0 -0
  64. {conquer3d-0.2.5 → conquer3d-0.2.6}/conquer3d.egg-info/top_level.txt +0 -0
  65. {conquer3d-0.2.5 → conquer3d-0.2.6}/setup.cfg +0 -0
  66. {conquer3d-0.2.5 → conquer3d-0.2.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: Geometric Cuda Tool Box
5
5
  Author-email: Do Hoang Khoi <khoido8899@gmail.com>
6
6
  License-Expression: MIT
@@ -14,9 +14,13 @@ class BVH:
14
14
  """
15
15
  Query the BVH with bounding boxes or segments. Returns (query_ids, object_ids).
16
16
  """
17
- def query_ray(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
17
+ def query_point(self, query_points: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
18
18
  """
19
- Query the BVH with rays. Returns (query_ids, object_ids).
19
+ Find the closest leaf AABB to each query point. Returns (query_ids, object_ids, distances)
20
+ """
21
+ def query_ray(self, ray_origins: torch.Tensor, ray_dirs: torch.Tensor, max_capacity: int = 10000000) -> tuple[torch.Tensor, torch.Tensor]:
22
+ """
23
+ Find all ray-AABB intersections. Returns (ray_ids, object_ids)
20
24
  """
21
25
  def query_self(self) -> tuple[torch.Tensor, torch.Tensor]:
22
26
  """
@@ -65,6 +69,10 @@ class MeshBVH(BVH):
65
69
  """
66
70
  Check if there are any self-intersecting triangle pairs
67
71
  """
72
+ def query_point(self, query_points: torch.Tensor, vertices: torch.Tensor, triangles: torch.Tensor, return_sdf: bool = False, return_prj_pts: bool = True, sign_mode: int = 0) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
73
+ """
74
+ Find the closest triangle to each query point. Returns (query_ids, triangle_ids, projected_points, distances)
75
+ """
68
76
  class PGSBVH(BVH):
69
77
  def __init__(self, in_aabb_mins: torch.Tensor, in_aabb_maxs: torch.Tensor) -> None:
70
78
  """
@@ -115,6 +123,10 @@ class TriangleMesh:
115
123
  """
116
124
  def is_vertex_manifold(self) -> bool:
117
125
  ...
126
+ def query_points(self, query_pts: torch.Tensor, return_sdf: bool = False, return_prj_pts: bool = True, sign_mode: int = 0, distance_mode: int = 0) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
127
+ """
128
+ Query points against the mesh. Returns (query_ids, triangle_ids, projected_points, distances)
129
+ """
118
130
  def remove_triangles_by_mask(self, keep_mask: torch.Tensor) -> None:
119
131
  ...
120
132
  @property
@@ -155,48 +155,81 @@ std::tuple<torch::Tensor, torch::Tensor> BVH::query_self()
155
155
 
156
156
  std::tuple<torch::Tensor, torch::Tensor> BVH::query_ray(
157
157
  const torch::Tensor &ray_origins,
158
- const torch::Tensor &ray_dirs)
158
+ const torch::Tensor &ray_dirs,
159
+ int64_t max_capacity)
159
160
  {
160
161
  CHECK_INPUT(ray_origins);
161
162
  CHECK_INPUT(ray_dirs);
162
- TORCH_CHECK(ray_origins.scalar_type() == torch::kFloat32, "ray_origins must be float32");
163
- TORCH_CHECK(ray_dirs.scalar_type() == torch::kFloat32, "ray_dirs must be float32");
164
- TORCH_CHECK(ray_origins.size(1) == 3, "ray_origins must have shape (M, 3)");
165
- TORCH_CHECK(ray_dirs.size(1) == 3, "ray_dirs must have shape (M, 3)");
163
+ TORCH_CHECK(ray_origins.size(0) == ray_dirs.size(0), "ray_origins and ray_dirs must have the same number of rays");
166
164
 
167
- const uint32_t num_queries = static_cast<uint32_t>(ray_origins.size(0));
168
- auto options_int64 = ray_origins.options().dtype(torch::kInt64);
165
+ int num_queries = ray_origins.size(0);
169
166
 
170
- if (num_queries == 0) {
171
- throw std::runtime_error("Cannot query BVH with 0 queries.");
172
- }
173
-
174
- torch::Tensor out_query_ids = torch::empty({BVH_MAX_CAPACITY}, options_int64);
175
- torch::Tensor out_object_ids = torch::empty({BVH_MAX_CAPACITY}, options_int64);
176
- torch::Tensor hit_counter = torch::zeros({1}, options_int64);
167
+ auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(ray_origins.device());
168
+ torch::Tensor out_query_ids = torch::empty({max_capacity}, options_i64);
169
+ torch::Tensor out_object_ids = torch::empty({max_capacity}, options_i64);
170
+ torch::Tensor hit_counter = torch::zeros({1}, options_i64);
177
171
 
178
172
  bvh::query_ray(
179
173
  num_queries,
180
174
  this->num_objects,
181
- reinterpret_cast<const float3 *>(ray_origins.data_ptr<float>()),
182
- reinterpret_cast<const float3 *>(ray_dirs.data_ptr<float>()),
183
- reinterpret_cast<const float3 *>(this->aabb_mins.data_ptr<float>()),
184
- reinterpret_cast<const float3 *>(this->aabb_maxs.data_ptr<float>()),
185
- reinterpret_cast<const int2 *>(this->bvh_children.data_ptr<int>()),
186
- reinterpret_cast<const int *>(this->object_ids.data_ptr<int>()),
187
- reinterpret_cast<int64_t *>(out_query_ids.data_ptr<int64_t>()),
188
- reinterpret_cast<int64_t *>(out_object_ids.data_ptr<int64_t>()),
189
- reinterpret_cast<int64_t *>(hit_counter.data_ptr<int64_t>()),
190
- static_cast<int64_t>(BVH_MAX_CAPACITY)
191
- );
175
+ (const float3 *)ray_origins.data_ptr<float>(),
176
+ (const float3 *)ray_dirs.data_ptr<float>(),
177
+ (const float3 *)this->aabb_mins.data_ptr<float>(),
178
+ (const float3 *)this->aabb_maxs.data_ptr<float>(),
179
+ (const int2 *)this->bvh_children.data_ptr<int>(),
180
+ this->object_ids.data_ptr<int>(),
181
+ out_query_ids.data_ptr<int64_t>(),
182
+ out_object_ids.data_ptr<int64_t>(),
183
+ hit_counter.data_ptr<int64_t>(),
184
+ max_capacity);
185
+
186
+ int64_t h_hit_counter = hit_counter.item<int64_t>();
187
+
188
+ if (h_hit_counter >= max_capacity)
189
+ {
190
+ TORCH_WARN("BVH ray query capacity exceeded. Some hits were dropped.");
191
+ h_hit_counter = max_capacity;
192
+ }
192
193
 
193
- int64_t num_hits = hit_counter.item<int64_t>();
194
- num_hits = std::min(num_hits, static_cast<int64_t>(BVH_MAX_CAPACITY));
194
+ if (h_hit_counter == 0) {
195
+ return std::make_tuple(
196
+ torch::empty({0}, options_i64),
197
+ torch::empty({0}, options_i64)
198
+ );
199
+ }
195
200
 
196
201
  return std::make_tuple(
197
- out_query_ids.slice(0, 0, num_hits),
198
- out_object_ids.slice(0, 0, num_hits)
199
- );
202
+ out_query_ids.slice(0, 0, h_hit_counter),
203
+ out_object_ids.slice(0, 0, h_hit_counter));
204
+ }
205
+
206
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> BVH::query_point(
207
+ const torch::Tensor &query_points)
208
+ {
209
+ CHECK_INPUT(query_points);
210
+
211
+ int num_queries = query_points.size(0);
212
+
213
+ auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_points.device());
214
+ auto options_f32 = torch::TensorOptions().dtype(torch::kFloat32).device(query_points.device());
215
+
216
+ torch::Tensor out_query_ids = torch::empty({num_queries}, options_i64);
217
+ torch::Tensor out_object_ids = torch::empty({num_queries}, options_i64);
218
+ torch::Tensor out_distances = torch::empty({num_queries}, options_f32);
219
+
220
+ bvh::query_point(
221
+ num_queries,
222
+ this->num_objects,
223
+ (const float3 *)query_points.data_ptr<float>(),
224
+ (const float3 *)this->aabb_mins.data_ptr<float>(),
225
+ (const float3 *)this->aabb_maxs.data_ptr<float>(),
226
+ (const int2 *)this->bvh_children.data_ptr<int>(),
227
+ this->object_ids.data_ptr<int>(),
228
+ out_query_ids.data_ptr<int64_t>(),
229
+ out_object_ids.data_ptr<int64_t>(),
230
+ out_distances.data_ptr<float>());
231
+
232
+ return std::make_tuple(out_query_ids, out_object_ids, out_distances);
200
233
  }
201
234
 
202
235
  void bind_ds_bvh(py::module_& m)
@@ -216,7 +249,11 @@ void bind_ds_bvh(py::module_& m)
216
249
  "Query the BVH against itself. Returns unique overlapping (query_ids, object_ids).")
217
250
 
218
251
  .def("query_ray", &BVH::query_ray,
219
- py::arg("ray_origins"),
252
+ py::arg("ray_origins"),
220
253
  py::arg("ray_dirs"),
221
- "Query the BVH with rays. Returns (query_ids, object_ids).");
254
+ py::arg("max_capacity") = BVH_MAX_CAPACITY,
255
+ "Find all ray-AABB intersections. Returns (ray_ids, object_ids)")
256
+ .def("query_point", &BVH::query_point,
257
+ py::arg("query_points"),
258
+ "Find the closest leaf AABB to each query point. Returns (query_ids, object_ids, distances)");
222
259
  }
@@ -32,5 +32,13 @@ void bind_ds_mesh_bvh(py::module_& m)
32
32
  py::arg("vertices"),
33
33
  py::arg("triangles"),
34
34
  py::arg("return_distance") = false,
35
- "Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])");
35
+ "Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])")
36
+ .def("query_point", &MeshBVH::query_point,
37
+ py::arg("query_points"),
38
+ py::arg("vertices"),
39
+ py::arg("triangles"),
40
+ py::arg("return_sdf") = false,
41
+ py::arg("return_prj_pts") = true,
42
+ py::arg("sign_mode") = 0,
43
+ "Find the closest triangle to each query point. Returns (query_ids, triangle_ids, projected_points, distances)");
36
44
  }
@@ -97,6 +97,21 @@ bool TriangleMesh::is_self_intersection()
97
97
  return this->bvh.value().is_self_intersection(this->vertices, this->triangles);
98
98
  }
99
99
 
100
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> TriangleMesh::query_points(
101
+ const torch::Tensor &query_pts,
102
+ bool return_sdf,
103
+ bool return_prj_pts,
104
+ int sign_mode,
105
+ int distance_mode)
106
+ {
107
+ if (distance_mode == 0) {
108
+ this->build_bvh();
109
+ return this->bvh.value().query_point(query_pts, this->vertices, this->triangles, return_sdf, return_prj_pts, sign_mode);
110
+ } else {
111
+ throw std::runtime_error("distance_mode != 0 not implemented yet");
112
+ }
113
+ }
114
+
100
115
  std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> TriangleMesh::get_ray_intersection(
101
116
  const torch::Tensor &ray_origins,
102
117
  const torch::Tensor &ray_dirs,
@@ -338,6 +353,13 @@ void bind_ds_triangle_mesh(py::module_ &m)
338
353
  py::arg("ray_dirs"),
339
354
  py::arg("return_distance") = false,
340
355
  "Find all ray-triangle intersections. Returns (ray_ids, triangle_ids, intersect_points, [distances])")
356
+ .def("query_points", &TriangleMesh::query_points,
357
+ py::arg("query_pts"),
358
+ py::arg("return_sdf") = false,
359
+ py::arg("return_prj_pts") = true,
360
+ py::arg("sign_mode") = 0,
361
+ py::arg("distance_mode") = 0,
362
+ "Query points against the mesh. Returns (query_ids, triangle_ids, projected_points, distances)")
341
363
  .def_property_readonly("edges", &TriangleMesh::get_edges)
342
364
  .def_property_readonly("edge_to_triangle_offsets", &TriangleMesh::get_edge_to_triangle_offsets)
343
365
  .def_property_readonly("edge_to_triangle_counts", &TriangleMesh::get_edge_to_triangle_counts)
@@ -542,4 +542,97 @@ namespace bvh
542
542
  max_capacity
543
543
  );
544
544
  }
545
+
546
+ __global__ void query_point_bvh_kernel(
547
+ const uint32_t num_queries,
548
+ const uint32_t num_objects,
549
+ const float3* __restrict__ query_points,
550
+ const float3* __restrict__ bvh_aabb_mins,
551
+ const float3* __restrict__ bvh_aabb_maxs,
552
+ const int2* __restrict__ bvh_children,
553
+ const int* __restrict__ object_ids,
554
+ int64_t* __restrict__ out_query_ids,
555
+ int64_t* __restrict__ out_object_ids,
556
+ float* __restrict__ out_distances)
557
+ {
558
+ uint32_t q_idx = blockIdx.x * blockDim.x + threadIdx.x;
559
+ if (q_idx >= num_queries) return;
560
+
561
+ float3 p = query_points[q_idx];
562
+
563
+ int stack[BVH_STACK_SIZE];
564
+ int stack_ptr = 0;
565
+ stack[0] = 0;
566
+
567
+ float best_dist_sq = FLT_MAX;
568
+ int best_leaf_original_id = -1;
569
+
570
+ while (stack_ptr >= 0)
571
+ {
572
+ int node_idx = stack[stack_ptr--];
573
+
574
+ float dist_sq = aabb::compute_squared_distance(p, bvh_aabb_mins[node_idx], bvh_aabb_maxs[node_idx]);
575
+
576
+ if (dist_sq > best_dist_sq) continue; // Prune branch
577
+
578
+ if (node_idx >= num_objects - 1)
579
+ {
580
+ if (dist_sq < best_dist_sq) {
581
+ best_dist_sq = dist_sq;
582
+ best_leaf_original_id = object_ids[node_idx - (num_objects - 1)];
583
+ }
584
+ }
585
+ else
586
+ {
587
+ if (stack_ptr + 2 < BVH_STACK_SIZE)
588
+ {
589
+ int2 children = bvh_children[node_idx];
590
+
591
+ float dist_l = aabb::compute_squared_distance(p, bvh_aabb_mins[children.x], bvh_aabb_maxs[children.x]);
592
+ float dist_r = aabb::compute_squared_distance(p, bvh_aabb_mins[children.y], bvh_aabb_maxs[children.y]);
593
+
594
+ if (dist_l > dist_r) {
595
+ stack[++stack_ptr] = children.x;
596
+ stack[++stack_ptr] = children.y;
597
+ } else {
598
+ stack[++stack_ptr] = children.y;
599
+ stack[++stack_ptr] = children.x;
600
+ }
601
+ }
602
+ }
603
+ }
604
+
605
+ out_query_ids[q_idx] = q_idx;
606
+ out_object_ids[q_idx] = best_leaf_original_id;
607
+ out_distances[q_idx] = sqrtf(best_dist_sq);
608
+ }
609
+
610
+ void query_point(
611
+ const uint32_t num_queries,
612
+ const uint32_t num_objects,
613
+ const float3* __restrict__ query_points,
614
+ const float3* __restrict__ bvh_aabb_mins,
615
+ const float3* __restrict__ bvh_aabb_maxs,
616
+ const int2* __restrict__ bvh_children,
617
+ const int* __restrict__ object_ids,
618
+ int64_t* __restrict__ out_query_ids,
619
+ int64_t* __restrict__ out_object_ids,
620
+ float* __restrict__ out_distances)
621
+ {
622
+ uint32_t threads = NTHREADS;
623
+ uint32_t blocks = (num_queries + threads - 1) / threads;
624
+
625
+ query_point_bvh_kernel<<<blocks, threads>>>(
626
+ num_queries,
627
+ num_objects,
628
+ query_points,
629
+ bvh_aabb_mins,
630
+ bvh_aabb_maxs,
631
+ bvh_children,
632
+ object_ids,
633
+ out_query_ids,
634
+ out_object_ids,
635
+ out_distances
636
+ );
637
+ }
545
638
  }
@@ -33,7 +33,11 @@ public:
33
33
 
34
34
  std::tuple<torch::Tensor, torch::Tensor> query_ray(
35
35
  const torch::Tensor &ray_origins,
36
- const torch::Tensor &ray_dirs);
36
+ const torch::Tensor &ray_dirs,
37
+ int64_t max_capacity = BVH_MAX_CAPACITY);
38
+
39
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor> query_point(
40
+ const torch::Tensor &query_points);
37
41
  };
38
42
 
39
43
  namespace bvh
@@ -88,6 +92,18 @@ namespace bvh
88
92
  int64_t *__restrict__ out_object_ids,
89
93
  int64_t *__restrict__ hit_counter,
90
94
  const int64_t max_capacity);
95
+
96
+ __host__ void query_point(
97
+ const uint32_t num_queries,
98
+ const uint32_t num_objects,
99
+ const float3 *__restrict__ query_points,
100
+ const float3 *__restrict__ bvh_aabb_mins,
101
+ const float3 *__restrict__ bvh_aabb_maxs,
102
+ const int2 *__restrict__ bvh_children,
103
+ const int *__restrict__ object_ids,
104
+ int64_t *__restrict__ out_query_ids,
105
+ int64_t *__restrict__ out_object_ids,
106
+ float *__restrict__ out_distances);
91
107
  }
92
108
 
93
109
  #endif // BVH_H
@@ -203,3 +203,211 @@ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> MeshBVH::
203
203
  return_distance ? out_distances.slice(0, 0, h_valid_counter) : out_distances
204
204
  );
205
205
  }
206
+
207
+ __device__ __forceinline__ float compute_sign_ray_parity(
208
+ const float3& p,
209
+ const int best_tri_id,
210
+ const float3* bvh_aabb_mins,
211
+ const float3* bvh_aabb_maxs,
212
+ const int2* bvh_children,
213
+ const int* object_ids,
214
+ const float3* vertices,
215
+ const int3* triangles,
216
+ const uint32_t num_objects)
217
+ {
218
+ int3 tri = triangles[best_tri_id];
219
+ float3 v0 = vertices[tri.x];
220
+ float3 v1 = vertices[tri.y];
221
+ float3 v2 = vertices[tri.z];
222
+ float3 centroid = (v0 + v1 + v2) / 3.0f;
223
+
224
+ float3 ray_dir = centroid - p;
225
+ float dir_len = maths::norm(ray_dir);
226
+ if (dir_len > 1e-6f) {
227
+ ray_dir = ray_dir / dir_len;
228
+ } else {
229
+ ray_dir = make_float3(1.0f, 0.0f, 0.0f);
230
+ }
231
+
232
+ Ray ray2(p, ray_dir, 0.0f);
233
+
234
+ int hit_count = 0;
235
+ int stack[BVH_STACK_SIZE];
236
+ int stack_ptr = 0;
237
+ stack[0] = 0;
238
+
239
+ while (stack_ptr >= 0)
240
+ {
241
+ int node_idx = stack[stack_ptr--];
242
+
243
+ float t_hit_aabb;
244
+ if (!ray2.is_intersect_aabb(bvh_aabb_mins[node_idx], bvh_aabb_maxs[node_idx], t_hit_aabb)) {
245
+ continue;
246
+ }
247
+
248
+ if (node_idx >= num_objects - 1)
249
+ {
250
+ int tri_id = object_ids[node_idx - (num_objects - 1)];
251
+ int3 tri = triangles[tri_id];
252
+ Triangle T(vertices[tri.x], vertices[tri.y], vertices[tri.z]);
253
+
254
+ float t_hit, u, v;
255
+ if (T.is_intersect_ray(ray2, t_hit, u, v)) {
256
+ hit_count++;
257
+ }
258
+ }
259
+ else
260
+ {
261
+ if (stack_ptr + 2 < BVH_STACK_SIZE)
262
+ {
263
+ int2 children = bvh_children[node_idx];
264
+ stack[++stack_ptr] = children.x;
265
+ stack[++stack_ptr] = children.y;
266
+ }
267
+ }
268
+ }
269
+
270
+ return (hit_count % 2 == 1) ? -1.0f : 1.0f;
271
+ }
272
+
273
+ __global__ void query_point_mesh_bvh_kernel(
274
+ const uint32_t num_queries,
275
+ const uint32_t num_objects,
276
+ const float3* __restrict__ query_points,
277
+ const float3* __restrict__ vertices,
278
+ const int3* __restrict__ triangles,
279
+ const float3* __restrict__ bvh_aabb_mins,
280
+ const float3* __restrict__ bvh_aabb_maxs,
281
+ const int2* __restrict__ bvh_children,
282
+ const int* __restrict__ object_ids,
283
+ int64_t* __restrict__ out_query_ids,
284
+ int64_t* __restrict__ out_object_ids,
285
+ float3* __restrict__ out_projected_pts,
286
+ float* __restrict__ out_distances,
287
+ bool return_sdf,
288
+ bool return_prj_pts,
289
+ int sign_mode)
290
+ {
291
+ uint32_t q_idx = blockIdx.x * blockDim.x + threadIdx.x;
292
+ if (q_idx >= num_queries) return;
293
+
294
+ float3 p = query_points[q_idx];
295
+
296
+ int stack[BVH_STACK_SIZE];
297
+ int stack_ptr = 0;
298
+ stack[0] = 0;
299
+
300
+ float best_dist_sq = FLT_MAX;
301
+ int best_tri_id = -1;
302
+ float3 best_pt = make_float3(0, 0, 0);
303
+
304
+ while (stack_ptr >= 0)
305
+ {
306
+ int node_idx = stack[stack_ptr--];
307
+
308
+ float dist_sq = aabb::compute_squared_distance(p, bvh_aabb_mins[node_idx], bvh_aabb_maxs[node_idx]);
309
+
310
+ if (dist_sq > best_dist_sq) continue; // Prune branch
311
+
312
+ if (node_idx >= num_objects - 1)
313
+ {
314
+ int tri_id = object_ids[node_idx - (num_objects - 1)];
315
+ int3 tri = triangles[tri_id];
316
+ Triangle T(vertices[tri.x], vertices[tri.y], vertices[tri.z]);
317
+
318
+ float3 closest_pt = T.compute_closest_point(p);
319
+ float3 diff = p - closest_pt;
320
+ float pt_dist_sq = maths::dot(diff, diff);
321
+
322
+ if (pt_dist_sq < best_dist_sq) {
323
+ best_dist_sq = pt_dist_sq;
324
+ best_tri_id = tri_id;
325
+ best_pt = closest_pt;
326
+ }
327
+ }
328
+ else
329
+ {
330
+ if (stack_ptr + 2 < BVH_STACK_SIZE)
331
+ {
332
+ int2 children = bvh_children[node_idx];
333
+
334
+ float dist_l = aabb::compute_squared_distance(p, bvh_aabb_mins[children.x], bvh_aabb_maxs[children.x]);
335
+ float dist_r = aabb::compute_squared_distance(p, bvh_aabb_mins[children.y], bvh_aabb_maxs[children.y]);
336
+
337
+ if (dist_l > dist_r) {
338
+ stack[++stack_ptr] = children.x;
339
+ stack[++stack_ptr] = children.y;
340
+ } else {
341
+ stack[++stack_ptr] = children.y;
342
+ stack[++stack_ptr] = children.x;
343
+ }
344
+ }
345
+ }
346
+ }
347
+
348
+ float dist = sqrtf(best_dist_sq);
349
+
350
+ if (return_sdf && sign_mode == 0) {
351
+ dist *= compute_sign_ray_parity(p, best_tri_id, bvh_aabb_mins, bvh_aabb_maxs, bvh_children, object_ids, vertices, triangles, num_objects);
352
+ }
353
+
354
+ out_query_ids[q_idx] = q_idx;
355
+ out_object_ids[q_idx] = best_tri_id;
356
+ if (return_prj_pts && out_projected_pts != nullptr) {
357
+ out_projected_pts[q_idx] = best_pt;
358
+ }
359
+ out_distances[q_idx] = dist;
360
+ }
361
+
362
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> MeshBVH::query_point(
363
+ const torch::Tensor &query_points,
364
+ const torch::Tensor &vertices,
365
+ const torch::Tensor &triangles,
366
+ bool return_sdf,
367
+ bool return_prj_pts,
368
+ int sign_mode)
369
+ {
370
+ if (sign_mode != 0) {
371
+ throw std::runtime_error("sign_mode != 0 not implemented yet");
372
+ }
373
+
374
+ int num_queries = query_points.size(0);
375
+ int num_objects = this->object_ids.size(0);
376
+
377
+ auto options_i64 = torch::TensorOptions().dtype(torch::kInt64).device(query_points.device());
378
+ auto options_f32 = torch::TensorOptions().dtype(torch::kFloat32).device(query_points.device());
379
+
380
+ torch::Tensor out_query_ids = torch::empty({num_queries}, options_i64);
381
+ torch::Tensor out_object_ids = torch::empty({num_queries}, options_i64);
382
+ torch::Tensor out_projected_pts;
383
+ if (return_prj_pts) {
384
+ out_projected_pts = torch::empty({num_queries, 3}, options_f32);
385
+ } else {
386
+ out_projected_pts = torch::empty({0, 3}, options_f32);
387
+ }
388
+ torch::Tensor out_distances = torch::empty({num_queries}, options_f32);
389
+
390
+ int threads = NTHREADS;
391
+ int blocks = (num_queries + threads - 1) / threads;
392
+
393
+ query_point_mesh_bvh_kernel<<<blocks, threads>>>(
394
+ num_queries,
395
+ num_objects,
396
+ (const float3*)query_points.data_ptr<float>(),
397
+ (const float3*)vertices.data_ptr<float>(),
398
+ (const int3*)triangles.data_ptr<int>(),
399
+ (const float3*)this->aabb_mins.data_ptr<float>(),
400
+ (const float3*)this->aabb_maxs.data_ptr<float>(),
401
+ (const int2*)this->bvh_children.data_ptr<int>(),
402
+ this->object_ids.data_ptr<int>(),
403
+ out_query_ids.data_ptr<int64_t>(),
404
+ out_object_ids.data_ptr<int64_t>(),
405
+ return_prj_pts ? (float3*)out_projected_pts.data_ptr<float>() : nullptr,
406
+ out_distances.data_ptr<float>(),
407
+ return_sdf,
408
+ return_prj_pts,
409
+ sign_mode
410
+ );
411
+
412
+ return std::make_tuple(out_query_ids, out_object_ids, out_projected_pts, out_distances);
413
+ }
@@ -28,6 +28,14 @@ public:
28
28
  const torch::Tensor &vertices,
29
29
  const torch::Tensor &triangles,
30
30
  bool return_distance = false);
31
+
32
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> query_point(
33
+ const torch::Tensor &query_points,
34
+ const torch::Tensor &vertices,
35
+ const torch::Tensor &triangles,
36
+ bool return_sdf = false,
37
+ bool return_prj_pts = true,
38
+ int sign_mode = 0);
31
39
  };
32
40
 
33
41
  #endif // MESH_BVH_H
@@ -61,6 +61,13 @@ public:
61
61
  torch::Tensor get_self_intersection();
62
62
  bool is_self_intersection();
63
63
 
64
+ std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> query_points(
65
+ const torch::Tensor &query_pts,
66
+ bool return_sdf = false,
67
+ bool return_prj_pts = true,
68
+ int sign_mode = 0,
69
+ int distance_mode = 0);
70
+
64
71
  std::tuple<torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor> get_ray_intersection(
65
72
  const torch::Tensor &ray_origins,
66
73
  const torch::Tensor &ray_dirs,
@@ -112,6 +112,24 @@ namespace aabb
112
112
  out_surface_area = 2.0f * (dim_size.x * dim_size.y + dim_size.x * dim_size.z + dim_size.y * dim_size.z);
113
113
  }
114
114
 
115
+ __device__ __forceinline__ float compute_squared_distance(
116
+ const float3 &p,
117
+ const float3 &aabb_min,
118
+ const float3 &aabb_max)
119
+ {
120
+ float d2 = 0.0f;
121
+ if (p.x < aabb_min.x) d2 += (aabb_min.x - p.x) * (aabb_min.x - p.x);
122
+ else if (p.x > aabb_max.x) d2 += (p.x - aabb_max.x) * (p.x - aabb_max.x);
123
+
124
+ if (p.y < aabb_min.y) d2 += (aabb_min.y - p.y) * (aabb_min.y - p.y);
125
+ else if (p.y > aabb_max.y) d2 += (p.y - aabb_max.y) * (p.y - aabb_max.y);
126
+
127
+ if (p.z < aabb_min.z) d2 += (aabb_min.z - p.z) * (aabb_min.z - p.z);
128
+ else if (p.z > aabb_max.z) d2 += (p.z - aabb_max.z) * (p.z - aabb_max.z);
129
+
130
+ return d2;
131
+ }
132
+
115
133
  __device__ __forceinline__ bool test_aabb_overlap(
116
134
  const float3 &query_aabb_min,
117
135
  const float3 &query_aabb_max,
@@ -43,6 +43,50 @@ struct Triangle {
43
43
  }
44
44
  return false;
45
45
  }
46
+
47
+ __host__ __device__ __forceinline__ float3 compute_closest_point(const float3& p) const {
48
+ float3 ab = v1 - v0;
49
+ float3 ac = v2 - v0;
50
+ float3 ap = p - v0;
51
+
52
+ float d1 = maths::dot(ab, ap);
53
+ float d2 = maths::dot(ac, ap);
54
+ if (d1 <= 0.0f && d2 <= 0.0f) return v0;
55
+
56
+ float3 bp = p - v1;
57
+ float d3 = maths::dot(ab, bp);
58
+ float d4 = maths::dot(ac, bp);
59
+ if (d3 >= 0.0f && d4 <= d3) return v1;
60
+
61
+ float vc = d1*d4 - d3*d2;
62
+ if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f) {
63
+ float v = d1 / (d1 - d3);
64
+ return v0 + v * ab;
65
+ }
66
+
67
+ float3 cp = p - v2;
68
+ float d5 = maths::dot(ab, cp);
69
+ float d6 = maths::dot(ac, cp);
70
+ if (d6 >= 0.0f && d5 <= d6) return v2;
71
+
72
+ float vb = d5*d2 - d1*d6;
73
+ if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f) {
74
+ float w = d2 / (d2 - d6);
75
+ return v0 + w * ac;
76
+ }
77
+
78
+ float va = d3*d6 - d5*d4;
79
+ if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f) {
80
+ float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
81
+ return v1 + w * (v2 - v1);
82
+ }
83
+
84
+ float denom = 1.0f / (va + vb + vc);
85
+ float v = vb * denom;
86
+ float w = vc * denom;
87
+ return v0 + ab * v + ac * w;
88
+ }
89
+
46
90
  __host__ __device__ __forceinline__ float3 compute_normal() const {
47
91
  float3 edge1 = v1 - v0;
48
92
  float3 edge2 = v2 - v0;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.2.5
3
+ Version: 0.2.6
4
4
  Summary: Geometric Cuda Tool Box
5
5
  Author-email: Do Hoang Khoi <khoido8899@gmail.com>
6
6
  License-Expression: MIT
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
 
10
10
  [project]
11
11
  name = "conquer3d"
12
- version = "0.2.5"
12
+ version = "0.2.6"
13
13
  description = "Geometric Cuda Tool Box"
14
14
  readme = "README.md"
15
15
  license = "MIT"
File without changes
File without changes
File without changes
File without changes
File without changes