Skip to content

Commit d15395b

Browse files
SarahWeiiiclaude
andcommitted
Add real metric mode and bump version to 1.0.9
Add `-rm`/`--real-metric` flag that lets users specify the concavity threshold in meters (real-world scale) instead of normalized units. The algorithm automatically converts it to the internal normalized threshold based on the mesh bounding box extent. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 45c7af7 commit d15395b

8 files changed

Lines changed: 63 additions & 13 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
[![Build](https://github.com/SarahWeiii/CoACD/actions/workflows/build.yml/badge.svg)](https://github.com/SarahWeiii/CoACD/actions/workflows/build.yml)
55
![PyPI - Downloads](https://img.shields.io/pypi/dm/coacd)
66

7+
[***News***] CoACD now supports real metric mode (`-rm`), ideal for meshes in real-world scale (e.g., from 3D scans or CAD models in meters). Specify the concavity threshold directly in meters instead of normalized units!
8+
79
[***News***] Check our new library, [PaMO](https://github.com/SarahWeiii/pamo.git), which converts any mesh into a low-poly, manifold, intersection-free mesh in seconds (CUDA required). It’s perfect as a preprocessing tool for CoACD.
810

911
[***News***] CoACD (both Python and C++) is supported on Linux (x86_64), Windows (amd64) and MacOS (x86_64 & apple sillicon) now!
@@ -31,6 +33,9 @@ import coacd
3133
mesh = trimesh.load(input_file, force="mesh")
3234
mesh = coacd.Mesh(mesh.vertices, mesh.faces)
3335
parts = coacd.run_coacd(mesh) # a list of convex hulls.
36+
37+
# Or use real metric mode (threshold in meters)
38+
parts = coacd.run_coacd(mesh, threshold=0.01, real_metric=True)
3439
```
3540
The complete example script is in `python/package/bin/coacd`, run it by the following command:
3641
```
@@ -155,6 +160,7 @@ Here is the description of the parameters (sorted by importance).
155160
* `-dt/--max-ch-vertex`: max vertex value for each convex hull, **only when decimate is enabled**, default = 256.
156161
* `-ex/--extrude`: extrude neighboring convex hulls along the overlapping faces (other faces unchanged), default = false.
157162
* `-em/--extrude-margin`: extrude margin, **only when extrude is enabled**, default = 0.01.
163+
* `-rm/--real-metric`: flag to enable real metric mode, where the threshold is interpreted as an error in meters (the input mesh should be in meter scale). The algorithm automatically converts it to the normalized threshold used internally. Default = false.
158164
* `-am/--approximate-mode`: approximation shape type ("ch" for convex hulls, "box" for cubes), default = "ch". I would recommend using a 2x threshold than it in convex for box approximation.
159165
* `--seed`: random seed used for sampling, default = random().
160166

main.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ int main(int argc, char *argv[])
110110
{
111111
sscanf(argv[i + 1], "%le", &params.dmc_thres);
112112
}
113+
if (strcmp(argv[i], "-rm") == 0 || strcmp(argv[i], "--real-metric") == 0)
114+
{
115+
params.real_metric = true;
116+
}
113117
}
114118
}
115119

@@ -142,17 +146,35 @@ int main(int argc, char *argv[])
142146
exit(0);
143147
}
144148

145-
if (params.threshold > 1)
146-
logger::warn("Threshold t exceeds the higher bound and is automatically set as 1!");
147-
params.threshold = min(params.threshold, 1.0);
149+
if (!params.real_metric)
150+
{
151+
if (params.threshold > 1)
152+
logger::warn("Threshold t exceeds the higher bound and is automatically set as 1!");
153+
params.threshold = min(params.threshold, 1.0);
154+
}
148155

149156
Model m;
150157
array<array<double, 3>, 3> rot;
151158

152-
SaveConfig(params);
153-
154159
m.LoadOBJ(params.input_model);
155160
vector<double> bbox = m.Normalize();
161+
162+
double real_metric_len = 0;
163+
double real_metric_original_threshold = params.threshold;
164+
if (params.real_metric)
165+
{
166+
real_metric_len = max(max(bbox[1] - bbox[0], bbox[3] - bbox[2]), bbox[5] - bbox[4]);
167+
params.threshold = params.threshold * 2.0 / real_metric_len * 0.8;
168+
}
169+
170+
SaveConfig(params);
171+
172+
if (params.real_metric)
173+
{
174+
logger::info("Real metric mode: mesh max length = {:.2f} cm", real_metric_len * 100.0);
175+
logger::info("Real metric mode: error threshold = {:.2f} cm", real_metric_original_threshold * 100.0);
176+
logger::info("Real metric mode: threshold {:.4f} cm (real) -> {:.4f} (normalized)", real_metric_original_threshold * 100.0, params.threshold);
177+
}
156178
// m.SaveOBJ("normalized.obj");
157179

158180
#if WITH_3RD_PARTY_LIBS

public/coacd.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ std::vector<Mesh> CoACD(Mesh const &input, double threshold,
1818
int mcts_nodes, int mcts_iteration, int mcts_max_depth,
1919
bool pca, bool merge, bool decimate, int max_ch_vertex,
2020
bool extrude, double extrude_margin,
21-
std::string apx_mode, unsigned int seed) {
21+
std::string apx_mode, unsigned int seed,
22+
bool real_metric) {
2223

2324
logger::info("threshold {}", threshold);
2425
logger::info("max # convex hull {}", max_convex_hull);
@@ -36,7 +37,7 @@ std::vector<Mesh> CoACD(Mesh const &input, double threshold,
3637
logger::info("approximate mode {}", apx_mode);
3738
logger::info("seed {}", seed);
3839

39-
if (threshold > 1) {
40+
if (!real_metric && threshold > 1) {
4041
throw std::runtime_error("CoACD threshold > 1 (should be 0-1).");
4142
}
4243

@@ -67,10 +68,22 @@ std::vector<Mesh> CoACD(Mesh const &input, double threshold,
6768
params.extrude_margin = extrude_margin;
6869
params.apx_mode = apx_mode;
6970
params.seed = seed;
71+
params.real_metric = real_metric;
7072

7173
Model m;
7274
m.Load(input.vertices, input.indices);
7375
vector<double> bbox = m.Normalize();
76+
77+
if (real_metric) {
78+
double m_len = max(max(bbox[1] - bbox[0], bbox[3] - bbox[2]), bbox[5] - bbox[4]);
79+
double original_threshold = params.threshold;
80+
params.threshold = params.threshold * 2.0 / m_len * 0.8;
81+
logger::info("Real metric mode: mesh max length = {:.2f} cm", m_len * 100.0);
82+
logger::info("Real metric mode: error threshold = {:.2f} cm", original_threshold * 100.0);
83+
logger::info("Real metric mode: threshold {:.4f} cm (real) -> {:.4f} (normalized)", original_threshold * 100.0, params.threshold);
84+
}
85+
86+
7487
array<array<double, 3>, 3> rot{
7588
{{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}};
7689

@@ -139,7 +152,8 @@ CoACD_MeshArray CoACD_run(CoACD_Mesh const &input, double threshold,
139152
int mcts_max_depth, bool pca, bool merge,
140153
bool decimate, int max_ch_vertex,
141154
bool extrude, double extrude_margin,
142-
int apx_mode, unsigned int seed) {
155+
int apx_mode, unsigned int seed,
156+
bool real_metric) {
143157
coacd::Mesh mesh;
144158
for (uint64_t i = 0; i < input.vertices_count; ++i) {
145159
mesh.vertices.push_back({input.vertices_ptr[3 * i],
@@ -171,8 +185,8 @@ CoACD_MeshArray CoACD_run(CoACD_Mesh const &input, double threshold,
171185

172186
auto meshes = coacd::CoACD(mesh, threshold, max_convex_hull, pm,
173187
prep_resolution, sample_resolution, mcts_nodes,
174-
mcts_iteration, mcts_max_depth, pca, merge, decimate, max_ch_vertex,
175-
extrude, extrude_margin, apx, seed);
188+
mcts_iteration, mcts_max_depth, pca, merge, decimate, max_ch_vertex,
189+
extrude, extrude_margin, apx, seed, real_metric);
176190

177191
CoACD_MeshArray arr;
178192
arr.meshes_ptr = new CoACD_Mesh[meshes.size()];

public/coacd.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ std::vector<Mesh> CoACD(Mesh const &input, double threshold = 0.05,
2525
int mcts_max_depth = 3, bool pca = false,
2626
bool merge = true, bool decimate = false, int max_ch_vertex = 256,
2727
bool extrude = false, double extrude_margin = 0.01,
28-
std::string apx_mode = "ch", unsigned int seed = 0);
28+
std::string apx_mode = "ch", unsigned int seed = 0,
29+
bool real_metric = false);
2930
void set_log_level(std::string_view level);
3031

3132
} // namespace coacd
@@ -60,7 +61,8 @@ CoACD_MeshArray COACD_API CoACD_run(CoACD_Mesh const &input, double threshold,
6061
int mcts_max_depth, bool pca, bool merge,
6162
bool decimate, int max_ch_vertex,
6263
bool extrude, double extrude_margin,
63-
int apx_mode, unsigned int seed);
64+
int apx_mode, unsigned int seed,
65+
bool real_metric);
6466

6567
void COACD_API CoACD_setLogLevel(char const *level);
6668
}

python/package/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class CoACD_MeshArray(ctypes.Structure):
6161
c_double,
6262
c_int,
6363
c_uint,
64+
c_bool,
6465
]
6566
_lib.CoACD_run.restype = CoACD_MeshArray
6667

@@ -95,6 +96,7 @@ def run_coacd(
9596
extrude_margin: float = 0.01,
9697
apx_mode: str = "ch",
9798
seed: int = 0,
99+
real_metric: bool = False,
98100
):
99101
vertices = np.ascontiguousarray(mesh.vertices, dtype=np.double)
100102
indices = np.ascontiguousarray(mesh.indices, dtype=np.int32)
@@ -143,6 +145,7 @@ def run_coacd(
143145
extrude_margin,
144146
apx,
145147
seed,
148+
real_metric,
146149
)
147150

148151
meshes = []

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def build_extension(self, ext):
7575

7676
setup(
7777
name="coacd",
78-
version="1.0.8",
78+
version="1.0.9",
7979
author_email="xiwei@ucsd.edu",
8080
keywords="collision convex decomposition",
8181
description="Approximate Convex Decomposition for 3D Meshes with Collision-Aware Concavity and Tree Search",

src/config.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace coacd
4040
int max_ch_vertex;
4141
bool extrude;
4242
double extrude_margin;
43+
bool real_metric;
4344

4445
/////////////// MCTS Config ///////////////
4546
int mcts_iteration;
@@ -65,6 +66,7 @@ namespace coacd
6566
max_ch_vertex = 256;
6667
extrude = false;
6768
extrude_margin = 0.01;
69+
real_metric = false;
6870

6971
mcts_iteration = 150;
7072
mcts_max_depth = 3;

src/io.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace coacd
2525
logger::info("\tk for Rv: {}", params.rv_k);
2626
logger::info("\tHausdorff Sampling Resolution: {}", params.resolution);
2727
logger::info("\tApproximation Mode (ch/box): {}", params.apx_mode);
28+
logger::info("\tReal Metric Mode (ON/OFF): {}", params.real_metric);
2829
logger::info("\tRandom Seed: {}", params.seed);
2930
}
3031

0 commit comments

Comments
 (0)