diff --git a/src/blenderbim/blenderbim/bim/module/material/data.py b/src/blenderbim/blenderbim/bim/module/material/data.py index 20ffd7767d..81be795f0d 100644 --- a/src/blenderbim/blenderbim/bim/module/material/data.py +++ b/src/blenderbim/blenderbim/bim/module/material/data.py @@ -184,7 +184,10 @@ class ObjectMaterialData: for item in items or []: data = {"id": item.id(), "name": getattr(item, "Name", None) or "Unnamed", "icon": icon} if item.is_a("IfcMaterialProfile") and not item.Name: - data["name"] = item.Profile.ProfileName or "Unnamed" + if item.Profile: + data["name"] = item.Profile.ProfileName or "Unnamed" + else: + data["name"] = "No Profile" if item.is_a("IfcMaterialLayer"): data["name"] += f" ({item.LayerThickness})" if not item.is_a("IfcMaterialList"): diff --git a/src/blenderbim/blenderbim/bim/module/model/data.py b/src/blenderbim/blenderbim/bim/module/model/data.py index 665936126c..46b87bcff0 100644 --- a/src/blenderbim/blenderbim/bim/module/model/data.py +++ b/src/blenderbim/blenderbim/bim/module/model/data.py @@ -61,6 +61,7 @@ class AuthoringData: cls.data["is_voidable_element"] = cls.is_voidable_element() cls.data["has_visible_openings"] = cls.has_visible_openings() cls.data["active_class"] = cls.active_class() + cls.data["active_material_usage"] = cls.active_material_usage() @classmethod def type_class(cls): @@ -171,6 +172,17 @@ class AuthoringData: if element: return element.is_a() + @classmethod + def active_material_usage(cls): + element = tool.Ifc.get_entity(bpy.context.active_object) + if element: + material = ifcopenshell.util.element.get_material(element, should_inherit=False) + if material: + if material.is_a("IfcMaterialLayerSetUsage"): + return f"LAYER{material.LayerSetDirection[-1]}" + elif material.is_a("IfcMaterialProfileSetUsage"): + return "PROFILE" + @classmethod def ifc_classes(cls): results = [] diff --git a/src/blenderbim/blenderbim/bim/module/model/product.py b/src/blenderbim/blenderbim/bim/module/model/product.py index 4058a5c926..1c70b83d3a 100644 --- a/src/blenderbim/blenderbim/bim/module/model/product.py +++ b/src/blenderbim/blenderbim/bim/module/model/product.py @@ -187,15 +187,19 @@ class AddConstrTypeInstance(bpy.types.Operator): else: layer_set_direction = "AXIS2" + obj = None if layer_set_direction == "AXIS3": - if slab.DumbSlabGenerator(relating_type).generate(link_to_scene=link_to_scene): - return True + obj = slab.DumbSlabGenerator(relating_type).generate(link_to_scene=link_to_scene) elif layer_set_direction == "AXIS2": - if wall.DumbWallGenerator(relating_type).generate(link_to_scene=link_to_scene): - return True + obj = wall.DumbWallGenerator(relating_type).generate(link_to_scene=link_to_scene) else: pass # Dumb block generator? Eh? :) + if obj: + material = ifcopenshell.util.element.get_material(tool.Ifc.get_entity(obj)) + material.LayerSetDirection = layer_set_direction + return True + class ChangeTypePage(bpy.types.Operator, tool.Ifc.Operator): bl_idname = "bim.change_type_page" @@ -336,12 +340,12 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator): # Large projects have hundreds of types which can lead to unnecessary lag. queue = sorted(tool.Ifc.get().by_type(self.ifc_class), key=lambda e: e.Name or "Unnamed") if self.limit: - queue = queue[self.offset:self.offset + self.limit] + queue = queue[self.offset : self.offset + self.limit] else: offset = 9 * (props.type_page - 1) if offset < 0: offset = 0 - queue = queue[offset:offset + 9] + queue = queue[offset : offset + 9] unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get()) @@ -389,7 +393,19 @@ class LoadTypeThumbnails(bpy.types.Operator, tool.Ifc.Operator): height = 100 + is_horizontal = False if element.is_a("IfcSlabType"): + is_horizontal = True + + parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric") + if parametric: + layer_set_direction = parametric.get("LayerSetDirection", None) + if layer_set_direction == "AXIS2": + is_horizontal = False + elif layer_set_direction == "AXIS3": + is_horizontal = True + + if is_horizontal: width, height = height, width x_offset = (size / 2) - (width / 2) @@ -529,7 +545,6 @@ def ensure_material_assigned(usecase_path, ifc_file, settings): obj.data.materials.append(IfcStore.get_element(material[0].id())) - def ensure_material_unassigned(usecase_path, ifc_file, settings): elements = [settings["product"]] if elements[0].is_a("IfcElementType"): @@ -551,5 +566,5 @@ def ensure_material_unassigned(usecase_path, ifc_file, settings): total_removed = 0 for i in to_remove: obj.active_material_index = i - total_removed - bpy.ops.object.material_slot_remove({'object': obj}) + bpy.ops.object.material_slot_remove({"object": obj}) total_removed += 1 diff --git a/src/blenderbim/blenderbim/bim/module/model/workspace.py b/src/blenderbim/blenderbim/bim/module/model/workspace.py index cdd76e44e4..9330888113 100644 --- a/src/blenderbim/blenderbim/bim/module/model/workspace.py +++ b/src/blenderbim/blenderbim/bim/module/model/workspace.py @@ -162,7 +162,7 @@ class BimToolUI: @classmethod def draw_edit_object_interface(cls, context): - if AuthoringData.data["active_class"] in ("IfcWall", "IfcWallStandardCase"): + if AuthoringData.data["active_material_usage"] == "LAYER2": row = cls.layout.row(align=True) row.prop(data=cls.props, property="extrusion_depth", text="Height") op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="") @@ -215,7 +215,7 @@ class BimToolUI: row.label(text="", icon="EVENT_G") row.operator("bim.hotkey", text="Regen").hotkey = "S_G" row.operator("bim.join_wall", icon="X", text="").join_type = "" - elif AuthoringData.data["active_class"] in ("IfcSlab", "IfcSlabStandardCase", "IfcRamp", "IfcRoof"): + elif AuthoringData.data["active_material_usage"] == "LAYER3": if context.active_object.mode == "OBJECT": row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") @@ -226,14 +226,7 @@ class BimToolUI: row.prop(data=cls.props, property="x_angle", text="X Angle") op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="") op.x_angle = cls.props.x_angle - elif AuthoringData.data["active_class"] in ( - "IfcColumn", - "IfcColumnStandardCase", - "IfcBeam", - "IfcBeamStandardCase", - "IfcMember", - "IfcMemberStandardCase", - ): + elif AuthoringData.data["active_material_usage"] == "PROFILE": row = cls.layout.row(align=True) row.prop(data=cls.props, property="cardinal_point", text="Axis") op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="") @@ -343,9 +336,6 @@ class BimToolUI: cls.draw_type_selection_interface() if AuthoringData.data["ifc_classes"]: - # row = cls.layout.row() - # row.operator("bim.display_constr_types", icon="TRIA_DOWN", text="") - row = cls.layout.row(align=True) row.label(text="", icon="EVENT_SHIFT") row.label(text="", icon="EVENT_A") @@ -418,10 +408,18 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): self.has_ifc_class = True self.active_class = None + self.active_material_usage = None element = tool.Ifc.get_entity(context.active_object) if element: self.active_class = element.is_a() + material = ifcopenshell.util.element.get_material(element, should_inherit=False) + if material: + if material.is_a("IfcMaterialLayerSetUsage"): + self.active_material_usage = f"LAYER{material.LayerSetDirection[-1]}" + elif material.is_a("IfcMaterialProfileSetUsage"): + self.active_material_usage = "PROFILE" + try: self.has_ifc_class = bool(self.props.ifc_class) except: @@ -451,7 +449,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): bpy.ops.bim.add_constr_type_instance() def hotkey_S_C(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.align_wall(align_type="CENTERLINE") else: bpy.ops.bim.align_product(align_type="CENTERLINE") @@ -459,50 +457,36 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): def hotkey_S_E(self): if not bpy.context.selected_objects: return - elif self.active_class in ("IfcWall", "IfcWallStandardCase"): + elif self.active_material_usage == "LAYER2": bpy.ops.bim.join_wall(join_type="T") - elif self.active_class in ("IfcSlab", "IfcSlabStandardCase", "IfcRamp", "IfcRoof"): + elif self.active_material_usage == "LAYER3": if not bpy.context.active_object: pass elif bpy.context.active_object.mode == "OBJECT": bpy.ops.bim.enable_editing_extrusion_profile() - elif self.active_class in ( - "IfcColumn", - "IfcColumnStandardCase", - "IfcBeam", - "IfcBeamStandardCase", - "IfcMember", - "IfcMemberStandardCase", - ): + elif self.active_material_usage == "PROFILE": bpy.ops.bim.extend_profile(join_type="T") def hotkey_S_F(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.flip_wall() elif self.active_class in ("IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"): bpy.ops.bim.flip_fill() def hotkey_S_G(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.recalculate_wall() - elif self.active_class in ( - "IfcColumn", - "IfcColumnStandardCase", - "IfcBeam", - "IfcBeamStandardCase", - "IfcMember", - "IfcMemberStandardCase", - ): + elif self.active_material_usage == "PROFILE": bpy.ops.bim.recalculate_profile() elif self.active_class in ("IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"): bpy.ops.bim.recalculate_fill() def hotkey_S_M(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.merge_wall() def hotkey_S_R(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.rotate_90(axis="Z") elif self.active_class in ("IfcColumn", "IfcColumnStandardCase"): bpy.ops.bim.rotate_90(axis="Z") @@ -510,46 +494,32 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator): bpy.ops.bim.rotate_90(axis="Y") def hotkey_S_K(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.split_wall() def hotkey_S_T(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.join_wall(join_type="L") - elif self.active_class in ( - "IfcColumn", - "IfcColumnStandardCase", - "IfcBeam", - "IfcBeamStandardCase", - "IfcMember", - "IfcMemberStandardCase", - ): + elif self.active_material_usage == "PROFILE": bpy.ops.bim.extend_profile(join_type="L") def hotkey_S_V(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.align_wall(align_type="INTERIOR") else: bpy.ops.bim.align_product(align_type="POSITIVE") def hotkey_S_X(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": if bpy.ops.bim.align_wall.poll(): bpy.ops.bim.align_wall(align_type="EXTERIOR") else: bpy.ops.bim.align_product(align_type="NEGATIVE") def hotkey_S_Y(self): - if self.active_class in ("IfcWall", "IfcWallStandardCase"): + if self.active_material_usage == "LAYER2": bpy.ops.bim.join_wall(join_type="V") - elif self.active_class in ( - "IfcColumn", - "IfcColumnStandardCase", - "IfcBeam", - "IfcBeamStandardCase", - "IfcMember", - "IfcMemberStandardCase", - ): + elif self.active_material_usage == "PROFILE": bpy.ops.bim.extend_profile(join_type="V") def hotkey_S_O(self):