fix(v4.2): shared topology stability — fillet/chamfer/heal/featuretree pass
- add_vertex: return array index instead of global ID (fix ID/index mismatch) - is_valid: validate by array index, not vertex ID (IDs not contiguous when shared with edges/loops) - fillet/fillet_variable: fix duplicate edge in sorted_edges (loop had fillet edge twice) - test updates: Fillet_NonManifoldEdge expects 2 faces per edge (shared topology)
This commit is contained in:
+8
-10
@@ -5,9 +5,9 @@
|
||||
namespace vde::brep {
|
||||
|
||||
int BrepModel::add_vertex(const Point3D& p) {
|
||||
int id = next_id_++;
|
||||
vertices_.push_back({id, p});
|
||||
return id;
|
||||
int idx = static_cast<int>(vertices_.size());
|
||||
vertices_.push_back({next_id_++, p});
|
||||
return idx;
|
||||
}
|
||||
|
||||
int BrepModel::add_edge(int v0, int v1) {
|
||||
@@ -66,14 +66,12 @@ const TopoVertex& BrepModel::vertex_by_id(int id) const {
|
||||
}
|
||||
|
||||
bool BrepModel::is_valid() const {
|
||||
int nv = static_cast<int>(vertices_.size());
|
||||
for (const auto& e : edges_) {
|
||||
// Validate vertex references by ID (IDs are global, not array indices)
|
||||
bool v0 = false, v1 = false;
|
||||
for (const auto& v : vertices_) {
|
||||
if (v.id == e.v_start) v0 = true;
|
||||
if (v.id == e.v_end) v1 = true;
|
||||
}
|
||||
if (!v0 || !v1) return false;
|
||||
// Validate vertex references by array index
|
||||
// (add_vertex returns array index, add_edge stores it as v_start/v_end)
|
||||
if (e.v_start < 0 || e.v_start >= nv) return false;
|
||||
if (e.v_end < 0 || e.v_end >= nv) return false;
|
||||
}
|
||||
for (const auto& f : faces_) {
|
||||
// Validate surface ID — surfaces stored by add order, use index
|
||||
|
||||
+10
-15
@@ -470,15 +470,11 @@ BrepModel fillet(const BrepModel& body, int edge_id, double radius) {
|
||||
// Found the edge — now we can determine its orientation
|
||||
bool edge_reversed = (edge_src.v_start != body.edge(eidx).v_start);
|
||||
|
||||
// Collect all edges in loop order
|
||||
std::vector<int> sorted_edges(lop.edges.size());
|
||||
// Rotate so we start after the filleted edge
|
||||
int start_offset = static_cast<int>((ei + 1) % lop.edges.size());
|
||||
for (size_t j = 0; j < lop.edges.size(); ++j) {
|
||||
sorted_edges[j] = lop.edges[(start_offset + static_cast<int>(j)) % lop.edges.size()];
|
||||
// Collect non-fillet edges in loop order (excluding the fillet edge)
|
||||
std::vector<int> sorted_edges(lop.edges.size() - 1);
|
||||
for (size_t j = 0; j < lop.edges.size() - 1; ++j) {
|
||||
sorted_edges[j] = lop.edges[(ei + 1 + static_cast<int>(j)) % lop.edges.size()];
|
||||
}
|
||||
// Add the filleted edge (replaced by tangent edge) at the beginning
|
||||
sorted_edges.insert(sorted_edges.begin(), edge_id);
|
||||
|
||||
// Edge direction for the tangent edge
|
||||
Point3D t0 = edge_reversed ? tangent_pts.back() : tangent_pts.front();
|
||||
@@ -488,7 +484,7 @@ BrepModel fillet(const BrepModel& body, int edge_id, double radius) {
|
||||
new_es.push_back(result.add_edge(nvt0, nvt1));
|
||||
|
||||
// Add the other edges (these are the edges NOT being filleted)
|
||||
for (size_t j = 1; j < sorted_edges.size(); ++j) {
|
||||
for (size_t j = 0; j < sorted_edges.size(); ++j) {
|
||||
int old_ei = sorted_edges[j];
|
||||
const auto& e_src = body.edge(old_ei);
|
||||
Point3D p0 = body.vertex_by_id(e_src.v_start).point;
|
||||
@@ -704,19 +700,18 @@ BrepModel fillet_variable(const BrepModel& body, int edge_id,
|
||||
|
||||
bool edge_reversed = (edge_src.v_start != body.edge(eidx).v_start);
|
||||
|
||||
std::vector<int> sorted_edges(lop.edges.size());
|
||||
int start_offset = static_cast<int>((ei + 1) % lop.edges.size());
|
||||
for (size_t j = 0; j < lop.edges.size(); ++j) {
|
||||
sorted_edges[j] = lop.edges[(start_offset + static_cast<int>(j)) % lop.edges.size()];
|
||||
// Collect non-fillet edges in loop order (excluding the fillet edge)
|
||||
std::vector<int> sorted_edges(lop.edges.size() - 1);
|
||||
for (size_t j = 0; j < lop.edges.size() - 1; ++j) {
|
||||
sorted_edges[j] = lop.edges[(ei + 1 + static_cast<int>(j)) % lop.edges.size()];
|
||||
}
|
||||
sorted_edges.insert(sorted_edges.begin(), edge_id);
|
||||
|
||||
Point3D t0 = edge_reversed ? tangent_pts.back() : tangent_pts.front();
|
||||
Point3D t1 = edge_reversed ? tangent_pts.front() : tangent_pts.back();
|
||||
new_es.push_back(result.add_edge(result.add_vertex(t0),
|
||||
result.add_vertex(t1)));
|
||||
|
||||
for (size_t j = 1; j < sorted_edges.size(); ++j) {
|
||||
for (size_t j = 0; j < sorted_edges.size(); ++j) {
|
||||
int old_ei = sorted_edges[j];
|
||||
const auto& e_src = body.edge(old_ei);
|
||||
Point3D p0 = body.vertex_by_id(e_src.v_start).point;
|
||||
|
||||
Reference in New Issue
Block a user