From 46aa20c0b1c900214850b50200f31823a47a7f13 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Thu, 23 Jul 2026 11:24:56 +0300 Subject: [PATCH] Bonsai: populate empty derived set when usage-assigning material to typeless occurrence Follow-up to the previous commit's material=None usage fix. When the usage-path assignment runs on an occurrence that has no type, the API derives a brand new empty IfcMaterialLayerSet (or IfcMaterialProfileSet) and wraps it in the usage. core.assign_material then reads the assigned material back with should_inherit=False, which returns the Usage entity itself. The Usage fails is_a_material_set, so the add_material_to_set follow-up that is supposed to seed the first layer/profile never runs and the set stays empty with zero layers. The BDD scenario 'Edit layer item defaults null IsVentilated to FALSE in UI' then dies with IndexError on ifc.by_type('IfcMaterialLayer')[0]. Unwrap the usage to its ForLayerSet/ForProfileSet before the set population step. add_material_to_set only seeds a set that is still empty, so a populated layer set inherited from a type is untouched. This change was made with the assistance of an AI tool. --- src/bonsai/bonsai/core/material.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bonsai/bonsai/core/material.py b/src/bonsai/bonsai/core/material.py index f641909a65..fc489ff82d 100644 --- a/src/bonsai/bonsai/core/material.py +++ b/src/bonsai/bonsai/core/material.py @@ -150,12 +150,20 @@ def assign_material( assigned_material = material_tool.get_material(element) assert assigned_material # Type checker. + # Usages wrap the actual material set, unwrap it so an empty derived + # set (occurrence without a type) still gets its first layer/profile. + assigned_material_set = assigned_material + if assigned_material.is_a("IfcMaterialLayerSetUsage"): + assigned_material_set = assigned_material.ForLayerSet + elif assigned_material.is_a("IfcMaterialProfileSetUsage"): + assigned_material_set = assigned_material.ForProfileSet + if material_tool.is_a_material_set(material): # Ensure set is a valid IFC. default_material = material_tool.get_default_material() material_tool.add_material_to_set(material_set=material, material=default_material) - elif material_tool.is_a_material_set(assigned_material): - material_tool.add_material_to_set(material_set=assigned_material, material=material) + elif material_tool.is_a_material_set(assigned_material_set): + material_tool.add_material_to_set(material_set=assigned_material_set, material=material) material_tool.ensure_material_assigned( elements=[element], material_type=element_material_type, material=material )