conquer3d 0.3.4__tar.gz → 0.3.9__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 (112) hide show
  1. {conquer3d-0.3.4/conquer3d.egg-info → conquer3d-0.3.9}/PKG-INFO +3 -1
  2. {conquer3d-0.3.4 → conquer3d-0.3.9}/README.md +1 -0
  3. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/_C.so +0 -0
  4. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/creation/triangle_creation.py +16 -0
  5. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/creation/triangle_creation.cpp +11 -0
  6. conquer3d-0.3.9/conquer3d/csrc/binds/data_structure/zcurve.cpp +32 -0
  7. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/creation/triangle_creation.h +25 -0
  8. conquer3d-0.3.9/conquer3d/csrc/data_structure/zcurve.cu +27 -0
  9. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/zcurve.h +10 -5
  10. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/pybind.cpp +2 -0
  11. conquer3d-0.3.9/conquer3d/data/assets/__init__.py +2 -0
  12. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/assets/common.py +7 -0
  13. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/assets/iphigenia.py +7 -0
  14. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/dataset/digit3d.py +29 -0
  15. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data_structure/__init__.py +3 -1
  16. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data_structure/grid.py +18 -1
  17. conquer3d-0.3.9/conquer3d/data_structure/sort.py +37 -0
  18. conquer3d-0.3.9/conquer3d/io/__init__.py +2 -0
  19. conquer3d-0.3.9/conquer3d/io/obj.py +38 -0
  20. conquer3d-0.3.9/conquer3d/io/off.py +20 -0
  21. conquer3d-0.3.9/conquer3d/ops/__init__.py +19 -0
  22. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/ops/delaunay_triangulation.py +0 -1
  23. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/ops/distance.py +27 -0
  24. {conquer3d-0.3.4 → conquer3d-0.3.9/conquer3d.egg-info}/PKG-INFO +3 -1
  25. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d.egg-info/SOURCES.txt +3 -0
  26. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d.egg-info/requires.txt +1 -0
  27. {conquer3d-0.3.4 → conquer3d-0.3.9}/pyproject.toml +2 -1
  28. conquer3d-0.3.4/conquer3d/data/transform/__init__.py +0 -0
  29. conquer3d-0.3.4/conquer3d/io/__init__.py +0 -0
  30. conquer3d-0.3.4/conquer3d/io/obj.py +0 -46
  31. conquer3d-0.3.4/conquer3d/io/off.py +0 -84
  32. conquer3d-0.3.4/conquer3d/ops/__init__.py +0 -10
  33. {conquer3d-0.3.4 → conquer3d-0.3.9}/LICENSE +0 -0
  34. {conquer3d-0.3.4 → conquer3d-0.3.9}/MANIFEST.in +0 -0
  35. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/_C.pyi +0 -0
  36. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/__init__.py +0 -0
  37. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/conversion/__init__.py +0 -0
  38. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/conversion/grid.py +0 -0
  39. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/conversion/mesh.py +0 -0
  40. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/creation/__init__.py +0 -0
  41. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/bvh.cpp +0 -0
  42. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/grid.cpp +0 -0
  43. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/gs_bvh.cpp +0 -0
  44. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/kdtree.cpp +0 -0
  45. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/mesh_bvh.cpp +0 -0
  46. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/pgs_bvh.cpp +0 -0
  47. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/data_structure/triangle_mesh.cpp +0 -0
  48. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/ops/chamfer.cpp +0 -0
  49. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/ops/mc.cpp +0 -0
  50. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/primitive/gs.cpp +0 -0
  51. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/primitive/pgs.cpp +0 -0
  52. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/primitive/ray.cpp +0 -0
  53. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/binds/primitive/triangle.cpp +0 -0
  54. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/check.h +0 -0
  55. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/constants.h +0 -0
  56. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/bvh.cu +0 -0
  57. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/bvh.h +0 -0
  58. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/gs_bvh.h +0 -0
  59. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/kdtree.cu +0 -0
  60. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/kdtree.h +0 -0
  61. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/mesh_bvh.cu +0 -0
  62. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/mesh_bvh.h +0 -0
  63. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/pgs_bvh.h +0 -0
  64. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/triangle_mesh.cu +0 -0
  65. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/data_structure/triangle_mesh.h +0 -0
  66. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/f2x2.h +0 -0
  67. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/f3x1.h +0 -0
  68. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/f3x3.h +0 -0
  69. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/f3x4.h +0 -0
  70. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/f4x1.h +0 -0
  71. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/f4x4.h +0 -0
  72. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/maths.h +0 -0
  73. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/maths/ops.h +0 -0
  74. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/ops/chamfer.cu +0 -0
  75. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/ops/chamfer.h +0 -0
  76. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/ops/mc.cu +0 -0
  77. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/ops/mc.h +0 -0
  78. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/ops/mc_data.h +0 -0
  79. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/aabb.h +0 -0
  80. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/edge.h +0 -0
  81. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/gs.cu +0 -0
  82. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/gs.h +0 -0
  83. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/gs_aabb.cu +0 -0
  84. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/gs_math.cuh +0 -0
  85. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/pgs.cu +0 -0
  86. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/pgs.h +0 -0
  87. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/pgs_aabb.cu +0 -0
  88. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/pgs_math.cuh +0 -0
  89. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/ray.h +0 -0
  90. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/csrc/primitive/triangle.h +0 -0
  91. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/__init__.py +0 -0
  92. {conquer3d-0.3.4/conquer3d/data/assets → conquer3d-0.3.9/conquer3d/data/collate}/__init__.py +0 -0
  93. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/collate/mesh.py +0 -0
  94. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/collate/sparse_tensor.py +0 -0
  95. {conquer3d-0.3.4/conquer3d/data/collate → conquer3d-0.3.9/conquer3d/data/dataset}/__init__.py +0 -0
  96. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/dataset/base_mesh.py +0 -0
  97. {conquer3d-0.3.4/conquer3d/data/dataset → conquer3d-0.3.9/conquer3d/data/transform}/__init__.py +0 -0
  98. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/transform/base.py +0 -0
  99. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/transform/ops.py +0 -0
  100. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data/transform/vertex.py +0 -0
  101. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/data_structure/bmesh.py +0 -0
  102. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/ops/diff_marching_cubes.py +0 -0
  103. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/ops/marching_cubes.py +0 -0
  104. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/ops/marching_tetrahedra.py +0 -0
  105. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/primitive/__init__.py +0 -0
  106. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/primitive/gs.py +0 -0
  107. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d/primitive/pgs.py +0 -0
  108. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d.egg-info/dependency_links.txt +0 -0
  109. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d.egg-info/not-zip-safe +0 -0
  110. {conquer3d-0.3.4 → conquer3d-0.3.9}/conquer3d.egg-info/top_level.txt +0 -0
  111. {conquer3d-0.3.4 → conquer3d-0.3.9}/setup.cfg +0 -0
  112. {conquer3d-0.3.4 → conquer3d-0.3.9}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.3.4
3
+ Version: 0.3.9
4
4
  Summary: Geometric Cuda Tool Box
5
5
  Author-email: Do Hoang Khoi <khoido8899@gmail.com>
6
6
  License-Expression: MIT
@@ -13,6 +13,7 @@ Requires-Python: >=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: torch>=2.0.0
16
+ Requires-Dist: meshio>=5.3.5
16
17
  Requires-Dist: gdown
17
18
  Provides-Extra: cuda
18
19
  Requires-Dist: cuda-toolkit==12.8.2; extra == "cuda"
@@ -49,6 +50,7 @@ pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
49
50
  ```bash
50
51
  conda create -c conda-forge -n geocutool python=3.10 gxx_linux-64=13 gcc_linux-64=13 -y
51
52
  conda activate geocutool
53
+ conda install -c conda-forge sparsehash -y
52
54
 
53
55
  conda install nvidia::cuda-toolkit==12.8.2 -y
54
56
 
@@ -20,6 +20,7 @@ pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
20
20
  ```bash
21
21
  conda create -c conda-forge -n geocutool python=3.10 gxx_linux-64=13 gcc_linux-64=13 -y
22
22
  conda activate geocutool
23
+ conda install -c conda-forge sparsehash -y
23
24
 
24
25
  conda install nvidia::cuda-toolkit==12.8.2 -y
25
26
 
@@ -2,6 +2,7 @@ import torch
2
2
  from typing import Tuple
3
3
 
4
4
  from .._C import create_sphere as create_sphere_c
5
+ from .._C import create_tetrahedra as create_tetrahedra_c
5
6
 
6
7
  def create_sphere(
7
8
  sectors: int = 32,
@@ -21,3 +22,18 @@ def create_sphere(
21
22
  triangles: (M, 3) int32 tensor of triangle indices.
22
23
  """
23
24
  return create_sphere_c(sectors, stacks, radius)
25
+
26
+ def create_tetrahedra(
27
+ radius: float = 1.0
28
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
29
+ """
30
+ Creates a regular tetrahedron returning (vertices, triangles) tensors on the CPU.
31
+
32
+ Args:
33
+ radius (float, optional): Circumscribed radius of the tetrahedron. Defaults to 1.0.
34
+
35
+ Returns:
36
+ vertices: (4, 3) float32 tensor of vertex positions.
37
+ triangles: (4, 3) int32 tensor of triangle indices.
38
+ """
39
+ return create_tetrahedra_c(radius)
@@ -17,6 +17,17 @@ Args:
17
17
  stacks (int): The number of latitudinal stacks. Defaults to 16.
18
18
  radius (float): The radius of the sphere. Defaults to 1.0.
19
19
 
20
+ Returns:
21
+ tuple: A tuple containing the vertices tensor and the triangles tensor.
22
+ )doc");
23
+
24
+ m.def("create_tetrahedra", &triangle_creation::create_tetrahedra,
25
+ py::arg("radius") = 1.0f,
26
+ R"doc(Creates a regular tetrahedron returning (vertices, triangles) tensors on the CPU.
27
+
28
+ Args:
29
+ radius (float): The circumscribed radius of the tetrahedron. Defaults to 1.0.
30
+
20
31
  Returns:
21
32
  tuple: A tuple containing the vertices tensor and the triangles tensor.
22
33
  )doc");
@@ -0,0 +1,32 @@
1
+ #include <torch/extension.h>
2
+ #include <pybind11/pybind11.h>
3
+ #include "../../data_structure/zcurve.h"
4
+ #include "../../check.h"
5
+
6
+ namespace py = pybind11;
7
+
8
+ torch::Tensor compute_zcurve_wrapper(torch::Tensor points)
9
+ {
10
+ CHECK_INPUT(points);
11
+
12
+ // We expect points to be [..., 3]
13
+ auto num_points = points.numel() / 3;
14
+ const float *p_points = points.data_ptr<float>();
15
+
16
+ // Output is same shape as points but without the last dim
17
+ auto sizes = points.sizes().vec();
18
+ sizes.pop_back();
19
+
20
+ torch::Tensor codes = torch::empty(sizes, points.options().dtype(torch::kInt64));
21
+ int64_t *p_codes = codes.data_ptr<int64_t>();
22
+
23
+ zcurve::compute_zcurve(p_points, num_points, p_codes);
24
+
25
+ return codes;
26
+ }
27
+
28
+ void bind_ds_zcurve(py::module_ &m)
29
+ {
30
+ m.def("compute_zcurve", &compute_zcurve_wrapper, "Compute Z-curve codes for a batch of points",
31
+ py::arg("points"));
32
+ }
@@ -92,6 +92,31 @@ namespace triangle_creation
92
92
  return {V, F};
93
93
  }
94
94
 
95
+ inline std::tuple<torch::Tensor, torch::Tensor> create_tetrahedra(float radius = 1.0f) {
96
+ float a = radius / std::sqrt(3.0f);
97
+ std::vector<float> vertices = {
98
+ a, a, a,
99
+ -a, -a, a,
100
+ -a, a, -a,
101
+ a, -a, -a
102
+ };
103
+
104
+ std::vector<int> triangles = {
105
+ 0, 2, 1,
106
+ 0, 1, 3,
107
+ 0, 3, 2,
108
+ 1, 2, 3
109
+ };
110
+
111
+ auto opts_f32 = torch::TensorOptions().dtype(torch::kFloat32);
112
+ auto opts_i32 = torch::TensorOptions().dtype(torch::kInt32);
113
+
114
+ torch::Tensor V = torch::from_blob(vertices.data(), {4, 3}, opts_f32).clone();
115
+ torch::Tensor F = torch::from_blob(triangles.data(), {4, 3}, opts_i32).clone();
116
+
117
+ return {V, F};
118
+ }
119
+
95
120
  }
96
121
 
97
122
  #endif // TRIANGLE_CREATION_H
@@ -0,0 +1,27 @@
1
+ #include "zcurve.h"
2
+ #include "../constants.h"
3
+ #include <cuda_runtime.h>
4
+
5
+ namespace zcurve
6
+ {
7
+
8
+ __global__ void compute_zcurve_kernel(const float3 *__restrict__ points, uint32_t num_points, int64_t *__restrict__ codes)
9
+ {
10
+ uint32_t idx = blockIdx.x * blockDim.x + threadIdx.x;
11
+ if (idx >= num_points)
12
+ return;
13
+
14
+ float3 p = points[idx];
15
+ unsigned int code = morton3D(p.x, p.y, p.z);
16
+ codes[idx] = (int64_t)code;
17
+ }
18
+
19
+ void compute_zcurve(const float *points, uint32_t num_points, int64_t *codes)
20
+ {
21
+ uint32_t threads = NTHREADS;
22
+ uint32_t blocks = (num_points + threads - 1) / threads;
23
+
24
+ compute_zcurve_kernel<<<blocks, threads>>>((const float3 *)points, num_points, codes);
25
+ }
26
+
27
+ }
@@ -6,7 +6,7 @@
6
6
 
7
7
  namespace zcurve
8
8
  {
9
- __device__ unsigned int expandBits(unsigned int v)
9
+ inline __device__ unsigned int expandBits(unsigned int v)
10
10
  {
11
11
  v = (v * 0x00010001u) & 0xFF0000FFu;
12
12
  v = (v * 0x00000101u) & 0x0F00F00Fu;
@@ -15,16 +15,21 @@ namespace zcurve
15
15
  return v;
16
16
  }
17
17
 
18
- __device__ unsigned int morton3D(float x, float y, float z)
18
+ inline __device__ unsigned int morton3D(float x, float y, float z)
19
19
  {
20
- x = min(max(x * 1024.0f, 0.0f), 1023.0f);
21
- y = min(max(y * 1024.0f, 0.0f), 1023.0f);
22
- z = min(max(z * 1024.0f, 0.0f), 1023.0f);
20
+ x = x * 1024.0f;
21
+ y = y * 1024.0f;
22
+ z = z * 1024.0f;
23
+ x = x < 0.0f ? 0.0f : (x > 1023.0f ? 1023.0f : x);
24
+ y = y < 0.0f ? 0.0f : (y > 1023.0f ? 1023.0f : y);
25
+ z = z < 0.0f ? 0.0f : (z > 1023.0f ? 1023.0f : z);
23
26
  unsigned int xx = expandBits((unsigned int)x);
24
27
  unsigned int yy = expandBits((unsigned int)y);
25
28
  unsigned int zz = expandBits((unsigned int)z);
26
29
  return xx * 4 + yy * 2 + zz;
27
30
  }
31
+
32
+ void compute_zcurve(const float *points, uint32_t num_points, int64_t *codes);
28
33
  }
29
34
 
30
35
  #endif // ZCURVE_H
@@ -15,6 +15,7 @@ void bind_ds_pgs_bvh(py::module_& m);
15
15
  void bind_ds_mesh_bvh(py::module_& m);
16
16
  void bind_ds_triangle_mesh(py::module_& m);
17
17
  void bind_ds_grid(py::module_& m);
18
+ void bind_ds_zcurve(py::module_& m);
18
19
 
19
20
  void bind_creation_triangle_creation(py::module_& m);
20
21
 
@@ -36,6 +37,7 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
36
37
  bind_ds_mesh_bvh(m);
37
38
  bind_ds_triangle_mesh(m);
38
39
  bind_ds_grid(m);
40
+ bind_ds_zcurve(m);
39
41
 
40
42
  bind_creation_triangle_creation(m);
41
43
 
@@ -0,0 +1,2 @@
1
+ from .common import *
2
+ from .iphigenia import *
@@ -33,6 +33,13 @@ class Common3D:
33
33
  print(f"Reading {self.filename}...")
34
34
  self.vertices, self.faces, self.colors = read_obj(obj_path)
35
35
 
36
+ def get(self):
37
+ return (
38
+ self.vertices.clone(),
39
+ self.faces.clone(),
40
+ self.colors.clone() if self.colors is not None else None
41
+ )
42
+
36
43
  # --- Child Classes ---
37
44
 
38
45
  class Alligator(Common3D):
@@ -15,6 +15,7 @@ class Iphiagenia:
15
15
  self.download_dir = os.path.expanduser(download_dir)
16
16
  self.vertices = None
17
17
  self.faces = None
18
+ self.colors = None
18
19
 
19
20
  self._load()
20
21
 
@@ -41,3 +42,9 @@ class Iphiagenia:
41
42
  # off_file is a file-like object of bytes.
42
43
  # read_off will automatically decode and parse it.
43
44
  self.vertices, self.faces = read_off(off_file)
45
+ def get(self):
46
+ return (
47
+ self.vertices.clone(),
48
+ self.faces.clone(),
49
+ self.colors.clone() if self.colors is not None else None
50
+ )
@@ -130,3 +130,32 @@ class SparseDigit3D(Digit3D):
130
130
  sparse_idx_grids = sparse_coords[:, 1:]
131
131
 
132
132
  return sparse_idx_grids, sparse_sdfs, label
133
+
134
+ class PointDigit3D(Digit3D):
135
+ """
136
+ Digit3D Dataset that constructs a point cloud by sampling on the mesh.
137
+ """
138
+ def __init__(self, root: str = "~/.conquer3d/", train: bool = True, transform=None, download: bool = False,
139
+ cached: bool = False, num_points: int = 512):
140
+ super().__init__(root, train, transform, download, cached=cached)
141
+ self.num_points = num_points
142
+
143
+ def __getitem__(self, idx: int):
144
+ # 1. Obtain vertices, faces, and label from Digit3D
145
+ vertices, faces, label = super().__getitem__(idx)
146
+
147
+ import trimesh
148
+ # 2. Construct trimesh object (CPU safe for DataLoader workers)
149
+ mesh = trimesh.Trimesh(vertices=vertices.numpy(), faces=faces.numpy(), process=False)
150
+
151
+ # 3. Sample points uniformly over the surface
152
+ points_np, face_indices = trimesh.sample.sample_surface(mesh, self.num_points)
153
+ normals_np = mesh.face_normals[face_indices]
154
+
155
+ points = torch.tensor(points_np, dtype=torch.float32)
156
+ normals = torch.tensor(normals_np, dtype=torch.float32)
157
+
158
+ # 4. Combine into features
159
+ features = torch.cat([points, normals], dim=-1)
160
+
161
+ return points, features, label
@@ -11,6 +11,7 @@ from .grid import (
11
11
  compute_grid_normal,
12
12
  compute_active_voxels,
13
13
  )
14
+ from .sort import z_curve_sort
14
15
 
15
16
  spatial_data_structures = ['KDTree', 'BVH', 'GSBVH', 'PGSBVH', 'MeshBVH']
16
17
  mesh_data_structures = ['TriangleMesh']
@@ -19,5 +20,6 @@ grid_data_structures = [
19
20
  'compute_grid_normal',
20
21
  'compute_active_voxels',
21
22
  ]
23
+ sort_data_structures = ['z_curve_sort']
22
24
 
23
- __all__ = spatial_data_structures + mesh_data_structures + grid_data_structures
25
+ __all__ = spatial_data_structures + mesh_data_structures + grid_data_structures + sort_data_structures
@@ -62,4 +62,21 @@ def compute_active_voxels(
62
62
  Returns:
63
63
  torch.Tensor: An int64 tensor containing the indices of the active voxels.
64
64
  """
65
- return _C.compute_active_voxels(voxels.contiguous(), sdf.contiguous(), iso)
65
+ return _C.compute_active_voxels(voxels.contiguous(), sdf.contiguous(), iso)
66
+
67
+ def create_random_points_ball(n_points: int, radius: float = 1.0, device: str = 'cuda') -> torch.Tensor:
68
+ """
69
+ Creates a set of random points uniformly distributed inside a sphere.
70
+
71
+ Args:
72
+ n_points (int): Number of points to sample.
73
+ radius (float): Radius of the sphere. Defaults to 1.0.
74
+ device (str): Device to place the tensor on. Defaults to 'cuda'.
75
+
76
+ Returns:
77
+ torch.Tensor: Random points of shape (n_points, 3).
78
+ """
79
+ points = torch.randn(n_points, 3, device=device)
80
+ radii = torch.rand(n_points, 1, device=device) ** (1/3) * radius
81
+ points = (points / points.norm(dim=-1, keepdim=True)) * radii
82
+ return points
@@ -0,0 +1,37 @@
1
+ import torch
2
+ import conquer3d._C as _C
3
+
4
+ def z_curve_sort(points: torch.Tensor):
5
+ """
6
+ Computes the Z-curve (Morton code) for a batch of points and sorts them.
7
+ Assumes points are normalized between [0, 1]. The function will clamp points outside this range.
8
+
9
+ Args:
10
+ points (torch.Tensor): Tensor of shape (..., 3) containing the point coordinates.
11
+
12
+ Returns:
13
+ sorted_points (torch.Tensor): Points sorted by their Z-curve value.
14
+ sorted_indices (torch.Tensor): The indices used to sort the points.
15
+ inverse_indices (torch.Tensor): The indices to reverse the sorting.
16
+ """
17
+ assert points.is_cuda, "Points must be on CUDA"
18
+ assert points.dtype == torch.float32, "Points must be float32"
19
+ assert points.shape[-1] == 3, "Points must be 3D"
20
+
21
+ # Compute the Morton codes for each point
22
+ codes = _C.compute_zcurve(points.contiguous())
23
+
24
+ # codes has shape (..., N). We always sort along the last dimension (dim=-1)
25
+
26
+ sorted_codes, sorted_indices = torch.sort(codes, dim=-1)
27
+
28
+ # Gather the points using the sorted indices
29
+ # We need to expand sorted_indices to match points: (..., N, 3)
30
+ dim = -2 if points.dim() > 1 else -1
31
+ expanded_indices = sorted_indices.unsqueeze(-1).expand_as(points)
32
+ sorted_points = torch.gather(points, dim=dim, index=expanded_indices)
33
+
34
+ # Compute the inverse indices (scatter)
35
+ inverse_indices = torch.argsort(sorted_indices, dim=-1)
36
+
37
+ return sorted_points, sorted_indices, inverse_indices
@@ -0,0 +1,2 @@
1
+ from .obj import read_obj, write_obj
2
+ from .off import read_off
@@ -0,0 +1,38 @@
1
+ import torch
2
+ import trimesh
3
+ import numpy as np
4
+
5
+ def read_obj(file_obj):
6
+ """
7
+ Reads an OBJ file and returns vertices, faces, and optional vertex colors using trimesh.
8
+
9
+ Args:
10
+ file_obj: A file-like object or a string path.
11
+ """
12
+ # trimesh safely handles UV seams and mismatched v/vt counts
13
+ mesh = trimesh.load(file_obj, process=False, force='mesh', skip_materials=True)
14
+
15
+ vertices = torch.tensor(mesh.vertices, dtype=torch.float32)
16
+ faces = torch.tensor(mesh.faces, dtype=torch.long)
17
+
18
+ colors = None
19
+ if hasattr(mesh.visual, 'vertex_colors') and mesh.visual.vertex_colors is not None and len(mesh.visual.vertex_colors) > 0:
20
+ colors = torch.tensor(mesh.visual.vertex_colors[:, :3], dtype=torch.float32) / 255.0
21
+
22
+ return vertices, faces, colors
23
+
24
+ def write_obj(filepath, vertices, faces, colors=None):
25
+ """
26
+ Writes vertices, faces, and optional vertex colors to an OBJ file using trimesh.
27
+ """
28
+ v = vertices.detach().cpu().numpy()
29
+ f = faces.detach().cpu().numpy()
30
+
31
+ vc = None
32
+ if colors is not None:
33
+ vc = (colors.detach().cpu().numpy() * 255.0).clip(0, 255).astype(np.uint8)
34
+
35
+ mesh = trimesh.Trimesh(vertices=v, faces=f, vertex_colors=vc, process=False)
36
+ mesh.export(filepath)
37
+
38
+
@@ -0,0 +1,20 @@
1
+ import torch
2
+ import trimesh
3
+
4
+ def read_off(filepath_or_filelike):
5
+ """
6
+ Read an OFF (Object File Format) file and return vertices and faces as PyTorch tensors using trimesh.
7
+
8
+ Args:
9
+ filepath_or_filelike: A string path or a file-like object (including binary streams).
10
+
11
+ Returns:
12
+ tuple: (vertices, faces) as torch.Tensor
13
+ """
14
+ # trimesh handles both string paths and binary file streams natively
15
+ mesh = trimesh.load(filepath_or_filelike, file_type='off', process=False, force='mesh')
16
+
17
+ vertices = torch.tensor(mesh.vertices, dtype=torch.float32)
18
+ faces = torch.tensor(mesh.faces, dtype=torch.long)
19
+
20
+ return vertices, faces
@@ -0,0 +1,19 @@
1
+ from .marching_cubes import marching_cubes
2
+ from .diff_marching_cubes import diff_marching_cubes
3
+
4
+ from .delaunay_triangulation import tetrahedralize, get_edges
5
+ from .marching_tetrahedra import marching_tetrahedra
6
+
7
+ from .distance import one_sided_chamfer_distance, chamfer_distance, one_sided_hausdorff_distance, hausdorff_distance
8
+
9
+ __all__ = [
10
+ "marching_cubes",
11
+ "diff_marching_cubes",
12
+ "one_sided_chamfer_distance",
13
+ "chamfer_distance",
14
+ "one_sided_hausdorff_distance",
15
+ "hausdorff_distance",
16
+ "tetrahedralize",
17
+ "get_edges",
18
+ "marching_tetrahedra"
19
+ ]
@@ -1,6 +1,5 @@
1
1
  import torch
2
2
  import numpy as np
3
- import tetgen
4
3
 
5
4
  def find_near_duplicates_sort(points, epsilon=1e-7):
6
5
  """
@@ -26,3 +26,30 @@ def chamfer_distance(x: torch.Tensor, y: torch.Tensor, squared: bool = True, ret
26
26
  if return_indices:
27
27
  return loss, idx_x_to_y, idx_y_to_x
28
28
  return loss
29
+
30
+ def one_sided_hausdorff_distance(query_points: torch.Tensor, reference_points: torch.Tensor, squared: bool = True, return_indices: bool = False):
31
+ distances, indices = one_sided_chamfer_distance(query_points, reference_points, squared=squared)
32
+
33
+ max_dist, max_idx = torch.max(distances, dim=0)
34
+
35
+ if return_indices:
36
+ return max_dist, max_idx, indices[max_idx]
37
+ return max_dist
38
+
39
+ def hausdorff_distance(x: torch.Tensor, y: torch.Tensor, squared: bool = True, return_indices: bool = False):
40
+ if return_indices:
41
+ dist_x_to_y, idx_x1, idx_y1 = one_sided_hausdorff_distance(x, y, squared=squared, return_indices=True)
42
+ dist_y_to_x, idx_y2, idx_x2 = one_sided_hausdorff_distance(y, x, squared=squared, return_indices=True)
43
+
44
+ if dist_x_to_y > dist_y_to_x:
45
+ return dist_x_to_y, idx_x1, idx_y1
46
+ else:
47
+ return dist_y_to_x, idx_x2, idx_y2
48
+ else:
49
+ dist_x_to_y = one_sided_hausdorff_distance(x, y, squared=squared, return_indices=False)
50
+ dist_y_to_x = one_sided_hausdorff_distance(y, x, squared=squared, return_indices=False)
51
+
52
+ if dist_x_to_y > dist_y_to_x:
53
+ return dist_x_to_y
54
+ else:
55
+ return dist_y_to_x
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conquer3d
3
- Version: 0.3.4
3
+ Version: 0.3.9
4
4
  Summary: Geometric Cuda Tool Box
5
5
  Author-email: Do Hoang Khoi <khoido8899@gmail.com>
6
6
  License-Expression: MIT
@@ -13,6 +13,7 @@ Requires-Python: >=3.9
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: torch>=2.0.0
16
+ Requires-Dist: meshio>=5.3.5
16
17
  Requires-Dist: gdown
17
18
  Provides-Extra: cuda
18
19
  Requires-Dist: cuda-toolkit==12.8.2; extra == "cuda"
@@ -49,6 +50,7 @@ pip install git+https://github.com/KhoiDOO/geocutool.git --no-build-isolation
49
50
  ```bash
50
51
  conda create -c conda-forge -n geocutool python=3.10 gxx_linux-64=13 gcc_linux-64=13 -y
51
52
  conda activate geocutool
53
+ conda install -c conda-forge sparsehash -y
52
54
 
53
55
  conda install nvidia::cuda-toolkit==12.8.2 -y
54
56
 
@@ -28,6 +28,7 @@ conquer3d/csrc/binds/data_structure/kdtree.cpp
28
28
  conquer3d/csrc/binds/data_structure/mesh_bvh.cpp
29
29
  conquer3d/csrc/binds/data_structure/pgs_bvh.cpp
30
30
  conquer3d/csrc/binds/data_structure/triangle_mesh.cpp
31
+ conquer3d/csrc/binds/data_structure/zcurve.cpp
31
32
  conquer3d/csrc/binds/ops/chamfer.cpp
32
33
  conquer3d/csrc/binds/ops/mc.cpp
33
34
  conquer3d/csrc/binds/primitive/gs.cpp
@@ -45,6 +46,7 @@ conquer3d/csrc/data_structure/mesh_bvh.h
45
46
  conquer3d/csrc/data_structure/pgs_bvh.h
46
47
  conquer3d/csrc/data_structure/triangle_mesh.cu
47
48
  conquer3d/csrc/data_structure/triangle_mesh.h
49
+ conquer3d/csrc/data_structure/zcurve.cu
48
50
  conquer3d/csrc/data_structure/zcurve.h
49
51
  conquer3d/csrc/maths/f2x2.h
50
52
  conquer3d/csrc/maths/f3x1.h
@@ -88,6 +90,7 @@ conquer3d/data/transform/vertex.py
88
90
  conquer3d/data_structure/__init__.py
89
91
  conquer3d/data_structure/bmesh.py
90
92
  conquer3d/data_structure/grid.py
93
+ conquer3d/data_structure/sort.py
91
94
  conquer3d/io/__init__.py
92
95
  conquer3d/io/obj.py
93
96
  conquer3d/io/off.py
@@ -1,4 +1,5 @@
1
1
  torch>=2.0.0
2
+ meshio>=5.3.5
2
3
  gdown
3
4
 
4
5
  [cuda]
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
 
10
10
  [project]
11
11
  name = "conquer3d"
12
- version = "0.3.4"
12
+ version = "0.3.9"
13
13
  description = "Geometric Cuda Tool Box"
14
14
  readme = "README.md"
15
15
  license = "MIT"
@@ -20,6 +20,7 @@ requires-python = ">=3.9"
20
20
  keywords = ["geometry"]
21
21
  dependencies = [
22
22
  "torch>=2.0.0",
23
+ "meshio>=5.3.5",
23
24
  "gdown",
24
25
  ]
25
26
 
File without changes
File without changes
@@ -1,46 +0,0 @@
1
- import torch
2
-
3
- def read_obj(file_obj):
4
- """
5
- Reads an OBJ file and returns vertices, faces, and optional vertex colors.
6
-
7
- Args:
8
- file_obj: A file-like object or a string path.
9
- """
10
- vertices = []
11
- faces = []
12
- colors = []
13
-
14
- close_file = False
15
- if isinstance(file_obj, str):
16
- file_obj = open(file_obj, 'r', encoding='utf-8')
17
- close_file = True
18
-
19
- try:
20
- for line in file_obj:
21
- if isinstance(line, bytes):
22
- line = line.decode('utf-8', errors='ignore')
23
- line = line.strip()
24
- if line.startswith('v '):
25
- parts = line.split()
26
- vertices.append([float(parts[1]), float(parts[2]), float(parts[3])])
27
- if len(parts) >= 7:
28
- colors.append([float(parts[4]), float(parts[5]), float(parts[6])])
29
- elif line.startswith('f '):
30
- parts = line.split()
31
- # Face elements can be v, v/vt, or v/vt/vn. We just want the first index (v).
32
- face = [int(p.split('/')[0]) - 1 for p in parts[1:4]]
33
- faces.append(face)
34
- finally:
35
- if close_file:
36
- file_obj.close()
37
-
38
- vertices = torch.tensor(vertices, dtype=torch.float32)
39
- faces = torch.tensor(faces, dtype=torch.long)
40
-
41
- if len(colors) == len(vertices):
42
- colors = torch.tensor(colors, dtype=torch.float32)
43
- else:
44
- colors = None
45
-
46
- return vertices, faces, colors
@@ -1,84 +0,0 @@
1
- import torch
2
- import numpy as np
3
- import io
4
-
5
- def read_off(filepath_or_filelike):
6
- """
7
- Read an OFF (Object File Format) file and return vertices and faces as PyTorch tensors.
8
- Supports reading from a file path or a file-like object.
9
-
10
- Args:
11
- filepath_or_filelike: A string path or a file-like object.
12
-
13
- Returns:
14
- tuple: (vertices, faces) as torch.Tensor
15
- """
16
- if isinstance(filepath_or_filelike, str):
17
- with open(filepath_or_filelike, "r") as f:
18
- lines = f.readlines()
19
- else:
20
- # Assuming text-based or bytes file-like object
21
- lines = filepath_or_filelike.readlines()
22
- if len(lines) > 0 and isinstance(lines[0], bytes):
23
- lines = [line.decode('utf-8') for line in lines]
24
-
25
- # Clean up empty lines and comments
26
- lines = [line.strip() for line in lines if line.strip() and not line.startswith('#')]
27
-
28
- if not lines:
29
- raise ValueError("Empty OFF file.")
30
-
31
- first_line = lines[0].strip()
32
- if first_line.upper().startswith("OFF"):
33
- if len(first_line) > 3:
34
- # Format: 'OFF 123 456 0'
35
- parts = first_line[3:].strip().split()
36
- # If the rest of the line doesn't contain counts, maybe they are on the next line
37
- if parts:
38
- lines = [parts] + lines[1:]
39
- else:
40
- lines = lines[1:]
41
- else:
42
- lines = lines[1:]
43
-
44
- # If the format parsing above resulted in a list of parts at index 0, handle it
45
- if isinstance(lines[0], list):
46
- counts = lines[0]
47
- else:
48
- counts = lines[0].split()
49
-
50
- num_verts, num_faces, num_edges = map(int, counts[:3])
51
-
52
- # Fast parsing with numpy
53
- verts_lines = lines[1:num_verts + 1]
54
- verts_str = '\n'.join(verts_lines)
55
- verts = np.fromstring(verts_str, sep=' ').reshape(num_verts, -1)[:, :3]
56
-
57
- faces_lines = lines[num_verts + 1 : num_verts + 1 + num_faces]
58
- faces_str = '\n'.join(faces_lines)
59
-
60
- # In an OFF file, face lines look like: `3 v1 v2 v3` for triangles.
61
- # We parse the flat array and reshape based on the number of elements per line
62
- faces_raw = np.fromstring(faces_str, sep=' ', dtype=int)
63
-
64
- # We assume all faces are triangles!
65
- # The first element of each chunk will be 3, followed by 3 indices.
66
- # Total length should be num_faces * 4
67
- if len(faces_raw) == num_faces * 4:
68
- faces = faces_raw.reshape(num_faces, 4)[:, 1:4]
69
- else:
70
- # If faces are mixed (e.g. some quads), we fall back to a slower parsing
71
- faces_list = []
72
- idx = 0
73
- for _ in range(num_faces):
74
- n_v = faces_raw[idx]
75
- if n_v == 3:
76
- faces_list.append([faces_raw[idx+1], faces_raw[idx+2], faces_raw[idx+3]])
77
- else:
78
- # Naive triangulation for ngons (fan triangulation)
79
- for i in range(1, n_v - 1):
80
- faces_list.append([faces_raw[idx+1], faces_raw[idx+i+1], faces_raw[idx+i+2]])
81
- idx += n_v + 1
82
- faces = np.array(faces_list, dtype=int)
83
-
84
- return torch.from_numpy(verts).float(), torch.from_numpy(faces).long()
@@ -1,10 +0,0 @@
1
- from .marching_cubes import marching_cubes
2
- from .diff_marching_cubes import diff_marching_cubes
3
- from .distance import one_sided_chamfer_distance, chamfer_distance
4
-
5
- __all__ = [
6
- "marching_cubes",
7
- "diff_marching_cubes",
8
- "one_sided_chamfer_distance",
9
- "chamfer_distance"
10
- ]
File without changes
File without changes
File without changes
File without changes
File without changes