diff --git a/src/bonsai/bonsai/bim/module/material/operator.py b/src/bonsai/bonsai/bim/module/material/operator.py index e0761bf416..7d8f9edd9d 100644 --- a/src/bonsai/bonsai/bim/module/material/operator.py +++ b/src/bonsai/bonsai/bim/module/material/operator.py @@ -614,25 +614,29 @@ class EditAssignedMaterial(bpy.types.Operator, tool.Ifc.Operator): attributes=attributes, ) - layer_sets_to_regenerate = set() + slab_planer = slab.DumbSlabPlaner() + wall_objs = [] for obj in objects: obj_element = tool.Ifc.get_entity(obj) obj_material_usage = ifcopenshell.util.element.get_material(obj_element) - if obj_material_usage and obj_material_usage.is_a("IfcMaterialLayerSetUsage"): obj_material_usage.OffsetFromReferenceLine = material.OffsetFromReferenceLine obj_material_usage.DirectionSense = material.DirectionSense obj_material_usage.ReferenceExtent = material.ReferenceExtent - layer_sets_to_regenerate.add(obj_material_usage.ForLayerSet) - # Save custom offset to BBIM_MaterialLayer pset tool.Model.save_custom_offset_to_pset(obj_element, obj) - for layer_set in layer_sets_to_regenerate: - wall.DumbWallPlaner().regenerate_from_layer_set(layer_set) - slab.DumbSlabPlaner().regenerate_from_layer_set(layer_set) + # Targeted regeneration: only update this element's geometry, not + # all elements sharing the layer set (which would corrupt unrelated instances). + if obj_material_usage.LayerSetDirection == "AXIS3": + slab_planer.regenerate_from_occurence(obj_element, obj_material_usage) + elif obj_material_usage.LayerSetDirection == "AXIS2": + wall_objs.append(obj) + + if wall_objs: + tool.Model.recalculate_walls(wall_objs) if material_set_usage.is_a("IfcMaterialProfileSetUsage"): if "CardinalPoint" in attributes: diff --git a/src/bonsai/bonsai/bim/module/model/slab.py b/src/bonsai/bonsai/bim/module/model/slab.py index 58a353ab28..a2957048a9 100644 --- a/src/bonsai/bonsai/bim/module/model/slab.py +++ b/src/bonsai/bonsai/bim/module/model/slab.py @@ -280,6 +280,8 @@ class DumbSlabPlaner: perpendicular_depth = thickness * abs(1 / cos(existing_x_angle)) perpendicular_offset = layer_offset * abs(1 / cos(existing_x_angle)) / self.unit_scale + ifc_position = extrusion.Position + # Check angle and z direction to determine whether the extrusion direction is positive or negative if (abs(existing_x_angle) < (pi / 2) and direction_ratios.z > 0) or ( abs(existing_x_angle) > (pi / 2) and direction_ratios.z < 0 @@ -301,7 +303,6 @@ class DumbSlabPlaner: extrusion.ExtrudedDirection.DirectionRatios = tuple(direction_ratios) extrusion.Depth = perpendicular_depth - ifc_position = extrusion.Position position = offset_direction * perpendicular_offset material = ifcopenshell.util.element.get_material(element) if material: diff --git a/src/bonsai/bonsai/tool/loader.py b/src/bonsai/bonsai/tool/loader.py index 6d30192485..8d11f79670 100644 --- a/src/bonsai/bonsai/tool/loader.py +++ b/src/bonsai/bonsai/tool/loader.py @@ -1063,12 +1063,16 @@ class Loader(bonsai.core.tool.Loader): @classmethod def slice_layerset_mesh(cls, element: ifcopenshell.entity_instance, mesh: bpy.types.Mesh) -> bpy.types.Mesh: + # Always compute unit_scale fresh — cls.unit_scale may be stale (e.g. during live + # geometry updates that don't go through the full import pipeline). + unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) + if not (material := ifcopenshell.util.element.get_material(element)): return mesh elif material.is_a("IfcMaterialLayerSetUsage"): usage = material layer_set = material.ForLayerSet - offset = usage.OffsetFromReferenceLine * cls.unit_scale + offset = usage.OffsetFromReferenceLine * unit_scale sense_factor = 1 if usage.DirectionSense == "POSITIVE" else -1 else: return mesh @@ -1101,7 +1105,7 @@ class Loader(bonsai.core.tool.Loader): for i, layer in enumerate(layer_set.MaterialLayers): if i != last_i: prev_co = co.copy() - co += no * layer.LayerThickness * cls.unit_scale + co += no * layer.LayerThickness * unit_scale bisect_geom = bmesh.ops.bisect_plane( bm, geom=bm.verts[:] + bm.edges[:] + bm.faces[:], dist=0.0001, plane_co=co, plane_no=no ) @@ -1115,14 +1119,17 @@ class Loader(bonsai.core.tool.Loader): for face in bisect_geom["geom"]: if isinstance(face, bmesh.types.BMFace): center = face.calc_center_median() - if (center - co).dot(no) >= 0: + dot = (center - co).dot(no) + if dot >= 0: face.material_index = material_index has_layer_styles = True else: for face in bisect_geom["geom"]: if isinstance(face, bmesh.types.BMFace): center = face.calc_center_median() - if (center - co).dot(no) < 0 and (center - prev_co).dot(no) >= 0: + dot_co = (center - co).dot(no) + dot_prev = (center - prev_co).dot(no) + if dot_co < 0 and dot_prev >= 0: face.material_index = material_index has_layer_styles = True