diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 0ad8885de3..bd18aa61ac 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -190,18 +190,23 @@ class UpdateRepresentation(bpy.types.Operator): def update_obj_mesh_representation(self, context, obj): product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id) + material = ifcopenshell.util.element.get_material(product, should_skip_usage=True) if not product.is_a("IfcGridAxis"): tool.Geometry.clear_cache(product) if product.is_a("IfcGridAxis"): + # Grid geometry does not follow the "representation" paradigm and needs to be treated specially ifcopenshell.api.run("grid.create_axis_curve", self.file, **{"axis_curve": obj, "grid_axis": product}) return - if product.is_a("IfcRelSpaceBoundary"): + elif product.is_a("IfcRelSpaceBoundary"): # TODO refactor settings = tool.Boundary.get_assign_connection_geometry_settings(obj) ifcopenshell.api.run("boundary.assign_connection_geometry", tool.Ifc.get(), **settings) return + elif material and material.is_a() in ["IfcMaterialProfileSet", "IfcMaterialLayerSet"]: + # These objects are parametrically based on an axis and should not be modified as a mesh + return core.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj) diff --git a/src/blenderbim/blenderbim/bim/module/model/__init__.py b/src/blenderbim/blenderbim/bim/module/model/__init__.py index 1901f2615f..770c17a266 100644 --- a/src/blenderbim/blenderbim/bim/module/model/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/model/__init__.py @@ -39,6 +39,7 @@ classes = ( profile.ChangeProfileDepth, profile.ExtendProfile, profile.RecalculateProfile, + profile.Rotate90, prop.BIMModelProperties, prop.ConstrTypeInfo, ui.BIM_PT_authoring, diff --git a/src/blenderbim/blenderbim/bim/module/model/profile.py b/src/blenderbim/blenderbim/bim/module/model/profile.py index 41ee2eb81c..c85b54453b 100644 --- a/src/blenderbim/blenderbim/bim/module/model/profile.py +++ b/src/blenderbim/blenderbim/bim/module/model/profile.py @@ -482,6 +482,7 @@ class DumbProfileJoiner: is_global=True, should_sync_changes_first=False, ) + tool.Geometry.record_object_materials(obj) def join(self, profile1, profile2, connection1, connection2, is_relating=True, description="BUTT"): element1 = tool.Ifc.get_entity(profile1) @@ -826,3 +827,26 @@ class ChangeCardinalPoint(bpy.types.Operator): objs.append(obj) DumbProfileRecalculator().recalculate(objs) return {"FINISHED"} + + +class Rotate90(bpy.types.Operator): + bl_idname = "bim.rotate_90" + bl_label = "Rotate 90" + bl_options = {"REGISTER", "UNDO"} + axis: bpy.props.StringProperty() + + @classmethod + def poll(cls, context): + return context.selected_objects + + def execute(self, context): + objs = [] + for obj in context.selected_objects: + element = tool.Ifc.get_entity(obj) + if element.ConnectedTo or element.ConnectedFrom: + objs.append(obj) + rotate_matrix = Matrix.Rotation(pi / 2, 4, self.axis) + obj.matrix_world @= rotate_matrix + bpy.context.view_layer.update() + DumbProfileRecalculator().recalculate(objs) + return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/model/wall.py b/src/blenderbim/blenderbim/bim/module/model/wall.py index bbfa428a3a..c589dd992d 100644 --- a/src/blenderbim/blenderbim/bim/module/model/wall.py +++ b/src/blenderbim/blenderbim/bim/module/model/wall.py @@ -1031,6 +1031,7 @@ class DumbWallJoiner: is_global=True, should_sync_changes_first=False, ) + tool.Geometry.record_object_materials(obj) def create_matrix(self, p, x, y, z): return Matrix( diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index 8049f16f26..6a17f00671 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -46,6 +46,7 @@ class BimTool(WorkSpaceTool): ("bim.hotkey", {"type": "G", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_G")]}), ("bim.hotkey", {"type": "M", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_M")]}), ("bim.hotkey", {"type": "O", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_O")]}), + ("bim.hotkey", {"type": "R", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_R")]}), ("bim.hotkey", {"type": "S", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_S")]}), ("bim.hotkey", {"type": "T", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_T")]}), ("bim.hotkey", {"type": "V", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_V")]}), @@ -206,6 +207,10 @@ class BimTool(WorkSpaceTool): row.operator("bim.hotkey", text="Mitre").hotkey = "S_Y" row = layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") + row.label(text="", icon="EVENT_R") + row.operator("bim.hotkey", text="Rotate 90").hotkey = "S_R" + row = layout.row(align=True) + row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_G") row.operator("bim.hotkey", text="Regen Connections").hotkey = "S_G" row = layout.row(align=True) @@ -319,6 +324,16 @@ class Hotkey(bpy.types.Operator): else: bpy.ops.bim.align_product(align_type="NEGATIVE") + def hotkey_S_R(self): + if not self.has_ifc_class: + return + if self.props.ifc_class == "IfcWallType": + bpy.ops.bim.rotate_90(axis="Z") + elif self.props.ifc_class == "IfcColumnType": + bpy.ops.bim.rotate_90(axis="Z") + elif self.props.ifc_class in ["IfcBeamType", "IfcMemberType"]: + bpy.ops.bim.rotate_90(axis="Y") + def hotkey_S_S(self): if self.has_ifc_class and self.props.ifc_class == "IfcWallType": bpy.ops.bim.split_wall() diff --git a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_profile_representation.py b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_profile_representation.py index fef68cce0f..ac107c2d2e 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/geometry/add_profile_representation.py +++ b/src/ifcopenshell-python/ifcopenshell/api/geometry/add_profile_representation.py @@ -132,7 +132,7 @@ class Usecase: else: settings = ifcopenshell.geom.settings() settings.set(settings.INCLUDE_CURVES, True) - shape = ifcopenshell.geom.create_shape(settings, element) + shape = ifcopenshell.geom.create_shape(settings, self.settings["profile"]) x = [verts[i] for i in range(0, len(shape.verts), 3)] return self.convert_si_to_unit(max(x) - min(x)) return 0.0 @@ -161,7 +161,7 @@ class Usecase: else: settings = ifcopenshell.geom.settings() settings.set(settings.INCLUDE_CURVES, True) - shape = ifcopenshell.geom.create_shape(settings, element) + shape = ifcopenshell.geom.create_shape(settings, self.settings["profile"]) y = [verts[i + 1] for i in range(0, len(shape.verts), 3)] return self.convert_si_to_unit(max(y) - min(y)) return 0.0