fix(v4.2): boolean/validate/heal/step_export use vertex array index, not v.id
Root cause: add_vertex returns array index but copy_brep/merge_brep/extract_face_fragment keyed by v.id (next_id_ value). When vertices and edges are interleaved, v.id != array index → map lookup fails → OOB access. Fixes in brep_boolean.cpp: - copy_brep: key by vertex index (vi) instead of v.id - merge_brep: key by vi, value = best_idx (array index) not result.vertex(id).id - extract_face_fragment: use body.vertex(e.v_start) directly (e.v_start is array index) - face_bounds/face_centroid/faces_intersect: same direct access pattern Also fixed same pattern in brep_heal.cpp, brep_validate.cpp, step_export.cpp
This commit is contained in:
+15
-31
@@ -238,12 +238,8 @@ Point3D face_centroid(const BrepModel& body, int face_id) {
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
for (int ei : edges) {
|
for (int ei : edges) {
|
||||||
const auto& e = body.edge(ei);
|
const auto& e = body.edge(ei);
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
c += body.vertex(e.v_start).point; count++;
|
||||||
auto& v = body.vertex(static_cast<int>(vi));
|
c += body.vertex(e.v_end).point; count++;
|
||||||
if (v.id == e.v_start || v.id == e.v_end) {
|
|
||||||
c += v.point; count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (count > 0) c /= static_cast<double>(count);
|
if (count > 0) c /= static_cast<double>(count);
|
||||||
return c;
|
return c;
|
||||||
@@ -257,18 +253,14 @@ bool faces_intersect(const BrepModel& body_a, int face_a,
|
|||||||
auto ea = body_a.face_edges(face_a);
|
auto ea = body_a.face_edges(face_a);
|
||||||
for (int ei : ea) {
|
for (int ei : ea) {
|
||||||
auto& e = body_a.edge(ei);
|
auto& e = body_a.edge(ei);
|
||||||
for (size_t vi = 0; vi < body_a.num_vertices(); ++vi) {
|
bb_a.expand(body_a.vertex(e.v_start).point);
|
||||||
auto& v = body_a.vertex(static_cast<int>(vi));
|
bb_a.expand(body_a.vertex(e.v_end).point);
|
||||||
if (v.id == e.v_start || v.id == e.v_end) bb_a.expand(v.point);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
auto eb = body_b.face_edges(face_b);
|
auto eb = body_b.face_edges(face_b);
|
||||||
for (int ei : eb) {
|
for (int ei : eb) {
|
||||||
auto& e = body_b.edge(ei);
|
auto& e = body_b.edge(ei);
|
||||||
for (size_t vi = 0; vi < body_b.num_vertices(); ++vi) {
|
bb_b.expand(body_b.vertex(e.v_start).point);
|
||||||
auto& v = body_b.vertex(static_cast<int>(vi));
|
bb_b.expand(body_b.vertex(e.v_end).point);
|
||||||
if (v.id == e.v_start || v.id == e.v_end) bb_b.expand(v.point);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bb_a.intersects(bb_b);
|
return bb_a.intersects(bb_b);
|
||||||
}
|
}
|
||||||
@@ -306,9 +298,9 @@ BrepModel sew_faces(const std::vector<BrepModel>& face_bodies) {
|
|||||||
if (d < best_dist) { best_dist = d; best_idx = static_cast<int>(ri); }
|
if (d < best_dist) { best_dist = d; best_idx = static_cast<int>(ri); }
|
||||||
}
|
}
|
||||||
if (best_idx >= 0) {
|
if (best_idx >= 0) {
|
||||||
old_to_new[v.id] = result.vertex(static_cast<int>(best_idx)).id;
|
old_to_new[static_cast<int>(vi)] = best_idx;
|
||||||
} else {
|
} else {
|
||||||
old_to_new[v.id] = result.add_vertex(v.point);
|
old_to_new[static_cast<int>(vi)] = result.add_vertex(v.point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,21 +345,15 @@ BrepModel extract_face_fragment(const BrepModel& body, int face_id) {
|
|||||||
auto& f = body.face(face_id);
|
auto& f = body.face(face_id);
|
||||||
auto es = body.face_edges(face_id);
|
auto es = body.face_edges(face_id);
|
||||||
|
|
||||||
// Map original vertex IDs to new vertex IDs in fragment
|
// Map original vertex indices to new vertex indices in fragment
|
||||||
std::map<int, int> old_to_new;
|
std::map<int, int> old_to_new;
|
||||||
for (int ei : es) {
|
for (int ei : es) {
|
||||||
auto& e = body.edge(ei);
|
auto& e = body.edge(ei);
|
||||||
if (old_to_new.find(e.v_start) == old_to_new.end()) {
|
if (old_to_new.find(e.v_start) == old_to_new.end()) {
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
old_to_new[e.v_start] = frag.add_vertex(body.vertex(e.v_start).point);
|
||||||
auto& tv = body.vertex(static_cast<int>(vi));
|
|
||||||
if (tv.id == e.v_start) { old_to_new[e.v_start] = frag.add_vertex(tv.point); break; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (old_to_new.find(e.v_end) == old_to_new.end()) {
|
if (old_to_new.find(e.v_end) == old_to_new.end()) {
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
old_to_new[e.v_end] = frag.add_vertex(body.vertex(e.v_end).point);
|
||||||
auto& tv = body.vertex(static_cast<int>(vi));
|
|
||||||
if (tv.id == e.v_end) { old_to_new[e.v_end] = frag.add_vertex(tv.point); break; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,11 +413,11 @@ split_and_classify_faces(const BrepModel& a, const BrepModel& b) {
|
|||||||
/// Create a deep copy of a BrepModel, preserving all topology exactly.
|
/// Create a deep copy of a BrepModel, preserving all topology exactly.
|
||||||
BrepModel copy_brep(const BrepModel& src) {
|
BrepModel copy_brep(const BrepModel& src) {
|
||||||
BrepModel result;
|
BrepModel result;
|
||||||
// Copy vertices
|
// Copy vertices (key by array index, since e.v_start/e.v_end store indices)
|
||||||
std::map<int, int> old_vid_to_new_idx;
|
std::map<int, int> old_vid_to_new_idx;
|
||||||
for (size_t vi = 0; vi < src.num_vertices(); ++vi) {
|
for (size_t vi = 0; vi < src.num_vertices(); ++vi) {
|
||||||
auto& v = src.vertex(static_cast<int>(vi));
|
auto& v = src.vertex(static_cast<int>(vi));
|
||||||
old_vid_to_new_idx[v.id] = result.add_vertex(v.point);
|
old_vid_to_new_idx[static_cast<int>(vi)] = result.add_vertex(v.point);
|
||||||
}
|
}
|
||||||
// Copy surfaces
|
// Copy surfaces
|
||||||
std::map<int, int> old_sid_to_new_idx;
|
std::map<int, int> old_sid_to_new_idx;
|
||||||
@@ -468,10 +454,8 @@ core::AABB3D face_bounds(const BrepModel& body, int face_id) {
|
|||||||
auto es = body.face_edges(face_id);
|
auto es = body.face_edges(face_id);
|
||||||
for (int ei : es) {
|
for (int ei : es) {
|
||||||
const auto& e = body.edge(ei);
|
const auto& e = body.edge(ei);
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
bb.expand(body.vertex(e.v_start).point);
|
||||||
const auto& v = body.vertex(static_cast<int>(vi));
|
bb.expand(body.vertex(e.v_end).point);
|
||||||
if (v.id == e.v_start || v.id == e.v_end) bb.expand(v.point);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,11 +250,8 @@ Point3D face_centroid(const BrepModel& body, const TopoFace& face) {
|
|||||||
for (int ei : loop.edges) {
|
for (int ei : loop.edges) {
|
||||||
if (ei < 0 || ei >= static_cast<int>(body.num_edges())) continue;
|
if (ei < 0 || ei >= static_cast<int>(body.num_edges())) continue;
|
||||||
const auto& e = body.edge(ei);
|
const auto& e = body.edge(ei);
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
sum = sum + body.vertex(e.v_start).point; count++;
|
||||||
const auto& v = body.vertex(static_cast<int>(vi));
|
sum = sum + body.vertex(e.v_end).point; count++;
|
||||||
if (v.id == e.v_start) { sum = sum + v.point; count++; }
|
|
||||||
if (v.id == e.v_end) { sum = sum + v.point; count++; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,9 @@ using core::AABB3D;
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// Compute edge length by looking up vertices
|
/// Compute edge length by looking up vertices
|
||||||
double edge_length(const BrepModel& body, int edge_idx) {
|
static double edge_length(const BrepModel& body, int edge_idx) {
|
||||||
auto& e = body.edge(edge_idx);
|
auto& e = body.edge(edge_idx);
|
||||||
Point3D p0(0,0,0), p1(0,0,0);
|
return (body.vertex(e.v_end).point - body.vertex(e.v_start).point).norm();
|
||||||
bool found0 = false, found1 = false;
|
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
|
||||||
auto& v = body.vertex(static_cast<int>(vi));
|
|
||||||
if (v.id == e.v_start) { p0 = v.point; found0 = true; }
|
|
||||||
if (v.id == e.v_end) { p1 = v.point; found1 = true; }
|
|
||||||
}
|
|
||||||
if (!found0 || !found1) return 0.0;
|
|
||||||
return (p1 - p0).norm();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if two faces share an edge
|
/// Check if two faces share an edge
|
||||||
@@ -60,10 +52,8 @@ bool faces_self_intersect(const BrepModel& body, int fa, int fb) {
|
|||||||
auto ea = body.face_edges(fa);
|
auto ea = body.face_edges(fa);
|
||||||
for (int ei : ea) {
|
for (int ei : ea) {
|
||||||
auto& e = body.edge(ei);
|
auto& e = body.edge(ei);
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
bb_a.expand(body.vertex(e.v_start).point);
|
||||||
auto& v = body.vertex(static_cast<int>(vi));
|
bb_a.expand(body.vertex(e.v_end).point);
|
||||||
if (v.id == e.v_start || v.id == e.v_end) bb_a.expand(v.point);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Expand slightly to account for numerical error
|
// Expand slightly to account for numerical error
|
||||||
auto ext_a = bb_a.extent();
|
auto ext_a = bb_a.extent();
|
||||||
@@ -73,10 +63,8 @@ bool faces_self_intersect(const BrepModel& body, int fa, int fb) {
|
|||||||
auto eb = body.face_edges(fb);
|
auto eb = body.face_edges(fb);
|
||||||
for (int ei : eb) {
|
for (int ei : eb) {
|
||||||
auto& e = body.edge(ei);
|
auto& e = body.edge(ei);
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
bb_b.expand(body.vertex(e.v_start).point);
|
||||||
auto& v = body.vertex(static_cast<int>(vi));
|
bb_b.expand(body.vertex(e.v_end).point);
|
||||||
if (v.id == e.v_start || v.id == e.v_end) bb_b.expand(v.point);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return bb_a.intersects(bb_b);
|
return bb_a.intersects(bb_b);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,13 +355,8 @@ std::string export_step(const std::vector<BrepModel>& bodies) {
|
|||||||
|
|
||||||
for (int ei : face_edges) {
|
for (int ei : face_edges) {
|
||||||
auto& e = body.edge(ei);
|
auto& e = body.edge(ei);
|
||||||
core::Point3D p0 = body.vertex(0).point;
|
core::Point3D p0 = body.vertex(e.v_start).point;
|
||||||
core::Point3D p1 = body.vertex(0).point;
|
core::Point3D p1 = body.vertex(e.v_end).point;
|
||||||
for (size_t vi = 0; vi < body.num_vertices(); ++vi) {
|
|
||||||
auto& v = body.vertex(static_cast<int>(vi));
|
|
||||||
if (v.id == e.v_start) p0 = v.point;
|
|
||||||
if (v.id == e.v_end) p1 = v.point;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write VERTEX_POINT for start vertex
|
// Write VERTEX_POINT for start vertex
|
||||||
int vp_start = writer.write_cartesian_point(p0);
|
int vp_start = writer.write_cartesian_point(p0);
|
||||||
|
|||||||
Reference in New Issue
Block a user