feat(v4.3): wall thickness analysis — centroid-offset sampling
- analyze_wall_thickness(): samples surface points, computes min distance to vertices/centroids on other faces (no mesh tessellation needed) - WallThicknessResult: min/max/avg, thin_threshold, thick_threshold - 3 new tests, 29/29 passing
This commit is contained in:
@@ -368,4 +368,78 @@ std::vector<BomEntry> generate_bom(const AssemblyNode& node) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// ── analyze_wall_thickness ──────────────────────────────────
|
||||
|
||||
WallThicknessResult analyze_wall_thickness(const BrepModel& body,
|
||||
int samples_per_face) {
|
||||
WallThicknessResult r;
|
||||
r.min_thickness = std::numeric_limits<double>::max();
|
||||
if (body.num_faces() == 0) { r.min_thickness = 0.0; return r; }
|
||||
|
||||
int total = 0;
|
||||
double sum = 0.0;
|
||||
|
||||
for (size_t fi = 0; fi < body.num_faces(); ++fi) {
|
||||
const auto& surf = body.surface(body.face(static_cast<int>(fi)).surface_id);
|
||||
double u0 = surf.knots_u().front(), u1 = surf.knots_u().back();
|
||||
double v0 = surf.knots_v().front(), v1 = surf.knots_v().back();
|
||||
|
||||
int n = std::max(2, samples_per_face);
|
||||
for (int i = 0; i <= n; ++i) {
|
||||
for (int j = 0; j <= n; ++j) {
|
||||
double u = u0 + (u1 - u0) * i / n;
|
||||
double v = v0 + (v1 - v0) * j / n;
|
||||
Point3D p = surf.evaluate(u, v);
|
||||
Vector3D nrm = surf.normal(u, v);
|
||||
if (nrm.norm() < 1e-12) continue;
|
||||
nrm.normalize();
|
||||
|
||||
// Offset slightly inward, then find min distance to any OTHER face
|
||||
Point3D probe = p - nrm * 0.001;
|
||||
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
// Find minimum distance from probe to any vertex on other faces
|
||||
for (size_t vk = 0; vk < body.num_vertices(); ++vk) {
|
||||
bool on_face = false;
|
||||
auto es = body.face_edges(static_cast<int>(fi));
|
||||
for (int ek : es) {
|
||||
const auto& e = body.edge(ek);
|
||||
if (e.v_start == static_cast<int>(vk) ||
|
||||
e.v_end == static_cast<int>(vk)) {
|
||||
on_face = true; break;
|
||||
}
|
||||
}
|
||||
if (on_face) continue;
|
||||
double d = (body.vertex(static_cast<int>(vk)).point - probe).norm();
|
||||
if (d < min_dist) min_dist = d;
|
||||
}
|
||||
|
||||
// Also check face centroids on other faces
|
||||
for (size_t fj = 0; fj < body.num_faces(); ++fj) {
|
||||
if (fj == fi) continue;
|
||||
const auto& os = body.surface(body.face(static_cast<int>(fj)).surface_id);
|
||||
Point3D fc = os.evaluate(
|
||||
(os.knots_u().front() + os.knots_u().back()) * 0.5,
|
||||
(os.knots_v().front() + os.knots_v().back()) * 0.5);
|
||||
double d = (fc - probe).norm();
|
||||
if (d < min_dist) min_dist = d;
|
||||
}
|
||||
|
||||
if (min_dist < std::numeric_limits<double>::max()) {
|
||||
r.min_thickness = std::min(r.min_thickness, min_dist);
|
||||
r.max_thickness = std::max(r.max_thickness, min_dist);
|
||||
sum += min_dist;
|
||||
total++;
|
||||
if (min_dist < r.thin_threshold) r.thin_regions++;
|
||||
if (min_dist > r.thick_threshold) r.thick_regions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total == 0) { r.min_thickness = 0.0; return r; }
|
||||
r.avg_thickness = sum / total;
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace vde::brep
|
||||
|
||||
Reference in New Issue
Block a user