_face_matrix_from_verts used only the first 3 vertices and sb.np_normal, which divides by zero when they are collinear. Triangulated meshes from generated spaces often start with collinear boundary vertices, producing NaN matrices and a shapely LinearRing error. Walk the polygon to find a non-degenerate normal and edge.
Generated with the assistance of an AI coding tool.
Vectorize the coplanarity prefilter in _union_coplanar_face_polygon and
compute per-triangle normals once instead of per space face. Add
regression tests for the SmallHouse and Triangle boundary test models.
Generated with the assistance of an AI coding tool.
dissolve_faces with merge_coplanar drops interior rings, so the shaft
opening in a ceiling was lost and replaced by spurious wall-cap
boundaries. Reconstruct the space face from its raw coplanar triangles,
preserve interior rings in the assigned boundary, absorb redundant
candidates by plane offset, and raise the full-face tolerance so walls
offset by their half thickness get a single boundary.
Generated with the assistance of an AI coding tool.
When several elements match the same space face, offset matches that only
duplicate coplanar coverage are now skipped, and a single bounding element
within a small plane offset gets the full space face instead of a clipped
polygon. Existing boundaries are removed before regeneration so stale 2nd
level boundaries are not left behind, and the Bonsai operator delegates
element filtering to auto_generate_boundaries.
Regenerates SmallHouse boundaries to match the reference output and keeps
the ExternalEarth opening unioning intact.
Generated with the assistance of an AI coding tool.
When a building element has multiple ngons matching the same space face,
_process_openings was called multiple times for the same opening/filling,
producing duplicate boundaries (e.g. two boundaries for the same door).
Fix: pass a set of processed filling IDs to _process_openings and skip
already-processed openings.
Generated with the assistance of an AI coding tool.
The a2p placement matrix stores col[0]=X (edge direction) and
col[2]=Z (face normal), but assign_connection_geometry expects
axis=Z (normal) and ref_direction=X (edge).
Generated with the assistance of an AI coding tool.
Move Blender-independent boundary generation algorithm from Bonsai
(GPL) to ifcopenshell.util.boundary (LGPL):
- ifcopenshell.util.shape.dissolve_faces: reconstruct polygonal faces
from triangulated mesh using original edges from get_edges() + Union-Find
- ifcopenshell.util.boundary.auto_generate_boundaries: full boundary
generation algorithm using IFC geometry (numpy, shapely) without
Blender — replaces bmesh, matrix_world, tool.Cad.is_x, mathutils with
numpy equivalents
- Uses existing ifcopenshell.api.boundary.assign_connection_geometry
for connection geometry creation
- Uses existing ifcopenshell.util.placement.a2p + np_normal for face
matrix construction
- BOUNDARY_ELEMENT_CLASSES expanded to include IfcColumn and
IfcCurtainWall
Bonsai's boundary/operator.py auto_generate_boundaries is now a thin
adapter handling Blender-specific preprocessing (flushing moved
objects, building iterator + tree) then delegating to the util module.
Added 12 tests: 3 for dissolve_faces, 3 for auto_generate_boundaries.
Generated with the assistance of an AI coding tool.