From 011610863fe092722aeebec939066b1fd6471112 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Thu, 16 Jul 2026 13:27:48 +0300 Subject: [PATCH] bonsai: catch kernel RuntimeError when finishing an arbitrary profile edit (#6259) auto_detect_profiles() reconstructs an IfcIndexedPolyCurve from the edited Blender mesh and calls ifcopenshell.geom.create_shape() on it to sort outer boundaries from voids. Every other invalid-profile case in that function (unclosed loops, malformed arcs or circles) returns a graceful (False, reason) tuple, but this create_shape call had no exception handling at all. When the reconstructed curve is geometrically valid topology but numerically degenerate at the kernel's internal tolerance (confirmed live with a weld-safe mesh whose coordinates land near that tolerance once converted to project length units), create_shape raises RuntimeError, which propagated straight through export_profile and crashed bim.edit_arbitrary_profile with a raw traceback instead of the intended "INVALID PROFILE" popup. Catch RuntimeError around the create_shape call and treat it the same as the other invalid-profile branches, so a bad edit surfaces the existing friendly error message instead of an unhandled crash. Generated with the assistance of an AI coding tool. --- src/bonsai/bonsai/tool/model.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/tool/model.py b/src/bonsai/bonsai/tool/model.py index f54633c3cc..93795dab8a 100644 --- a/src/bonsai/bonsai/tool/model.py +++ b/src/bonsai/bonsai/tool/model.py @@ -2450,7 +2450,15 @@ class Model(bonsai.core.tool.Model): # First convert to Shapely polygons = {} for curve in curves: - geometry = ifcopenshell.geom.create_shape(settings, curve) + try: + geometry = ifcopenshell.geom.create_shape(settings, curve) + except RuntimeError: + # The reconstructed curve can be geometrically degenerate (e.g. a + # sliver loop collapsed below the kernel's tolerance after an edit), + # which the geometry kernel rejects outright instead of returning an + # empty shape. Treat that the same as any other invalid profile + # instead of letting the exception crash the calling operator. + return (False, "INVALID_SHAPE") assert isinstance(geometry, W.Triangulation) v = ifcopenshell.util.shape.get_vertices(geometry, is_2d=True) v = np.round(v, 4) # Round to nearest 0.1mm, otherwise things like circles don't polygonise reliably