mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 06:21:40 +00:00
ifcgeom: keep one copy of repeated faces in faceset helper duplicate removal
When an IfcConnectedFaceSet lists the same IfcFace instance multiple times, the faceset helper registered the loop identity in duplicates_ and wires() then skipped every occurrence of that identity, so the face vanished from the shell entirely instead of being deduplicated to a single copy. The resulting shell had holes, sewing produced a non-manifold first/second boolean operand, and opening subtraction was discarded (Boolean operation yields non-manifold result), leaving the element with no geometry. Count how many occurrences of a loop identity are redundant and skip only that many in wires(), so exactly one copy of each repeated face is still built. In 418--walls--segfault.ifc the opening of wall #2543 repeats 84 of the 350 unique faces of its closed shell (once to three times over the 518 entries), which previously dropped those 84 faces and yielded a 0-vertex wall. With this change the opening operand is manifold and the wall gets a closed, dimensionally correct body. No output changes on the other 257 files in test/input. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -86,6 +86,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
OpenCascadeKernel* kernel_;
|
OpenCascadeKernel* kernel_;
|
||||||
std::set<int> duplicates_;
|
std::set<int> duplicates_;
|
||||||
|
std::map<int, int> duplicate_skips_remaining_;
|
||||||
std::map<int, int> vertex_mapping_;
|
std::map<int, int> vertex_mapping_;
|
||||||
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
|
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
|
||||||
double eps_;
|
double eps_;
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper(
|
|||||||
|
|
||||||
vertex_mapping_.clear();
|
vertex_mapping_.clear();
|
||||||
duplicates_.clear();
|
duplicates_.clear();
|
||||||
|
duplicate_skips_remaining_.clear();
|
||||||
|
|
||||||
edge_use.clear();
|
edge_use.clear();
|
||||||
|
|
||||||
@@ -174,6 +175,7 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper(
|
|||||||
if (edge_sets.find({loop->external.get_value_or(false), segment_set}) != edge_sets.end()) {
|
if (edge_sets.find({loop->external.get_value_or(false), segment_set}) != edge_sets.end()) {
|
||||||
duplicate_faces++;
|
duplicate_faces++;
|
||||||
duplicates_.insert(loop->identity());
|
duplicates_.insert(loop->identity());
|
||||||
|
duplicate_skips_remaining_[loop->identity()]++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
edge_sets.insert({loop->external.get_value_or(false), segment_set});
|
edge_sets.insert({loop->external.get_value_or(false), segment_set});
|
||||||
@@ -250,7 +252,10 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const ifcopenshell::geomet
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, NCollection_List<TopoDS_Shape>& wires) {
|
bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, NCollection_List<TopoDS_Shape>& wires) {
|
||||||
if (duplicates_.find(loop->identity()) != duplicates_.end()) {
|
// Skip only the redundant occurrences, keep one copy of the face.
|
||||||
|
auto it = duplicate_skips_remaining_.find(loop->identity());
|
||||||
|
if (it != duplicate_skips_remaining_.end() && it->second > 0) {
|
||||||
|
--it->second;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TopoDS_Wire wire;
|
TopoDS_Wire wire;
|
||||||
|
|||||||
Reference in New Issue
Block a user