From 3abb46eefa81fd1dfe4eb77b6247cde7384cce96 Mon Sep 17 00:00:00 2001 From: CyrilWaechter Date: Thu, 30 Jul 2026 21:12:44 +0200 Subject: [PATCH] Fix dissolve_faces polygon reconstruction with merge_coplanar When merge_coplanar merges two sub-faces that share an edge from the original BRep (e.g. two rectangles forming an L-shape cap), that shared edge remained in boundary_edges via original_edges filtering, causing the edge_adjacency walk to produce wrong polygons. Fix: after coplanar merging, use edge frequency (edges used by exactly 1 triangle = boundary) instead of original_edges filtering, which correctly identifies only outer boundary edges. Also add safety checks: edge_adjacency emptiness guard, infinite loop protection, and minimum polygon length check. Generated with the assistance of an AI coding tool. --- .../ifcopenshell/util/shape.py | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape.py b/src/ifcopenshell-python/ifcopenshell/util/shape.py index 07fe8d82a1..d45027a4b5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape.py @@ -914,11 +914,16 @@ def dissolve_faces( result = [] for tri_indices in ngons.values(): tri_edge_set = set() + edge_count: dict[frozenset, int] = {} for tri_idx in tri_indices: for e in tri_edges[tri_idx]: tri_edge_set.add(e) + edge_count[e] = edge_count.get(e, 0) + 1 - boundary_edges = [e for e in tri_edge_set if e in original_edges] + if merge_coplanar: + boundary_edges = [e for e in tri_edge_set if edge_count.get(e, 0) == 1] + else: + boundary_edges = [e for e in tri_edge_set if e in original_edges] if not boundary_edges: result.append(list(faces[tri_indices[0]])) @@ -938,15 +943,21 @@ def dissolve_faces( continue break + if not edge_adjacency: + result.append(list(faces[tri_indices[0]])) + continue + start = next(iter(edge_adjacency)) polygon = [start] current = edge_adjacency[start] - while current != start: + while current != start and current in edge_adjacency: polygon.append(current) - if current not in edge_adjacency: - break current = edge_adjacency[current] - result.append(polygon) + + if len(polygon) >= 3: + result.append(polygon) + else: + result.append(list(faces[tri_indices[0]])) return result