diff --git a/src/bonsai/bonsai/bim/module/root/operator.py b/src/bonsai/bonsai/bim/module/root/operator.py index 5ad4aeae3e..636a3635ce 100644 --- a/src/bonsai/bonsai/bim/module/root/operator.py +++ b/src/bonsai/bonsai/bim/module/root/operator.py @@ -199,6 +199,16 @@ class AssignClass(bpy.types.Operator, tool.Ifc.Operator): if obj.mode != "OBJECT": self.report({"ERROR"}, "Object must be in OBJECT mode to assign class") continue + + # Clear any transform modifications. + if not tool.Blender.apply_transform_as_local(obj): + self.report( + {"ERROR"}, + f"Object '{obj.name}' has parent/constraints with a shear transform that cannot be applied safely as a local transform. " + "Please apply parent/constraints manually and try again.", + ) + continue + element = core.assign_class( tool.Ifc, tool.Collector, diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index 97d188a321..539b7664fa 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -1233,3 +1233,27 @@ class Blender(bonsai.core.tool.Blender): system = bpy.context.preferences.system system_scale = system.dpi * system.pixel_size return (system_scale / default_scale) * size + + @classmethod + def apply_transform_as_local(cls, obj: bpy.types.Object) -> bool: + """Apply object transforms as local matrix, if possible. + + Clear parent and constraints. + + :return: `True` if transform was applied and `False` + if transform wasn't applied it's not possible due to a shear. + """ + + if not obj.parent or not obj.constraints: + return True + + matrix = obj.matrix_world.copy() + # Matrix has a shear, it cannot be represented as a local matrix + # based on rotation+translation+scale. + if not matrix.to_3x3().is_orthogonal_axis_vectors: + return False + + obj.parent = None + obj.constraints.clear() + obj.matrix_world = matrix + return True