mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Fix #2584. You can now edit any layered or profile material agnostic of class.
This commit is contained in:
@@ -184,7 +184,10 @@ class ObjectMaterialData:
|
|||||||
for item in items or []:
|
for item in items or []:
|
||||||
data = {"id": item.id(), "name": getattr(item, "Name", None) or "Unnamed", "icon": icon}
|
data = {"id": item.id(), "name": getattr(item, "Name", None) or "Unnamed", "icon": icon}
|
||||||
if item.is_a("IfcMaterialProfile") and not item.Name:
|
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"):
|
if item.is_a("IfcMaterialLayer"):
|
||||||
data["name"] += f" ({item.LayerThickness})"
|
data["name"] += f" ({item.LayerThickness})"
|
||||||
if not item.is_a("IfcMaterialList"):
|
if not item.is_a("IfcMaterialList"):
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class AuthoringData:
|
|||||||
cls.data["is_voidable_element"] = cls.is_voidable_element()
|
cls.data["is_voidable_element"] = cls.is_voidable_element()
|
||||||
cls.data["has_visible_openings"] = cls.has_visible_openings()
|
cls.data["has_visible_openings"] = cls.has_visible_openings()
|
||||||
cls.data["active_class"] = cls.active_class()
|
cls.data["active_class"] = cls.active_class()
|
||||||
|
cls.data["active_material_usage"] = cls.active_material_usage()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def type_class(cls):
|
def type_class(cls):
|
||||||
@@ -171,6 +172,17 @@ class AuthoringData:
|
|||||||
if element:
|
if element:
|
||||||
return element.is_a()
|
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
|
@classmethod
|
||||||
def ifc_classes(cls):
|
def ifc_classes(cls):
|
||||||
results = []
|
results = []
|
||||||
|
|||||||
@@ -187,15 +187,19 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
|||||||
else:
|
else:
|
||||||
layer_set_direction = "AXIS2"
|
layer_set_direction = "AXIS2"
|
||||||
|
|
||||||
|
obj = None
|
||||||
if layer_set_direction == "AXIS3":
|
if layer_set_direction == "AXIS3":
|
||||||
if slab.DumbSlabGenerator(relating_type).generate(link_to_scene=link_to_scene):
|
obj = slab.DumbSlabGenerator(relating_type).generate(link_to_scene=link_to_scene)
|
||||||
return True
|
|
||||||
elif layer_set_direction == "AXIS2":
|
elif layer_set_direction == "AXIS2":
|
||||||
if wall.DumbWallGenerator(relating_type).generate(link_to_scene=link_to_scene):
|
obj = wall.DumbWallGenerator(relating_type).generate(link_to_scene=link_to_scene)
|
||||||
return True
|
|
||||||
else:
|
else:
|
||||||
pass # Dumb block generator? Eh? :)
|
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):
|
class ChangeTypePage(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.change_type_page"
|
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.
|
# 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")
|
queue = sorted(tool.Ifc.get().by_type(self.ifc_class), key=lambda e: e.Name or "Unnamed")
|
||||||
if self.limit:
|
if self.limit:
|
||||||
queue = queue[self.offset:self.offset + self.limit]
|
queue = queue[self.offset : self.offset + self.limit]
|
||||||
else:
|
else:
|
||||||
offset = 9 * (props.type_page - 1)
|
offset = 9 * (props.type_page - 1)
|
||||||
if offset < 0:
|
if offset < 0:
|
||||||
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())
|
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
|
height = 100
|
||||||
|
|
||||||
|
is_horizontal = False
|
||||||
if element.is_a("IfcSlabType"):
|
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
|
width, height = height, width
|
||||||
|
|
||||||
x_offset = (size / 2) - (width / 2)
|
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()))
|
obj.data.materials.append(IfcStore.get_element(material[0].id()))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_material_unassigned(usecase_path, ifc_file, settings):
|
def ensure_material_unassigned(usecase_path, ifc_file, settings):
|
||||||
elements = [settings["product"]]
|
elements = [settings["product"]]
|
||||||
if elements[0].is_a("IfcElementType"):
|
if elements[0].is_a("IfcElementType"):
|
||||||
@@ -551,5 +566,5 @@ def ensure_material_unassigned(usecase_path, ifc_file, settings):
|
|||||||
total_removed = 0
|
total_removed = 0
|
||||||
for i in to_remove:
|
for i in to_remove:
|
||||||
obj.active_material_index = i - total_removed
|
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
|
total_removed += 1
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class BimToolUI:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def draw_edit_object_interface(cls, context):
|
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 = cls.layout.row(align=True)
|
||||||
row.prop(data=cls.props, property="extrusion_depth", text="Height")
|
row.prop(data=cls.props, property="extrusion_depth", text="Height")
|
||||||
op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="")
|
op = row.operator("bim.change_extrusion_depth", icon="FILE_REFRESH", text="")
|
||||||
@@ -215,7 +215,7 @@ class BimToolUI:
|
|||||||
row.label(text="", icon="EVENT_G")
|
row.label(text="", icon="EVENT_G")
|
||||||
row.operator("bim.hotkey", text="Regen").hotkey = "S_G"
|
row.operator("bim.hotkey", text="Regen").hotkey = "S_G"
|
||||||
row.operator("bim.join_wall", icon="X", text="").join_type = ""
|
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":
|
if context.active_object.mode == "OBJECT":
|
||||||
row = cls.layout.row(align=True)
|
row = cls.layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
@@ -226,14 +226,7 @@ class BimToolUI:
|
|||||||
row.prop(data=cls.props, property="x_angle", text="X Angle")
|
row.prop(data=cls.props, property="x_angle", text="X Angle")
|
||||||
op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="")
|
op = row.operator("bim.change_extrusion_x_angle", icon="FILE_REFRESH", text="")
|
||||||
op.x_angle = cls.props.x_angle
|
op.x_angle = cls.props.x_angle
|
||||||
elif AuthoringData.data["active_class"] in (
|
elif AuthoringData.data["active_material_usage"] == "PROFILE":
|
||||||
"IfcColumn",
|
|
||||||
"IfcColumnStandardCase",
|
|
||||||
"IfcBeam",
|
|
||||||
"IfcBeamStandardCase",
|
|
||||||
"IfcMember",
|
|
||||||
"IfcMemberStandardCase",
|
|
||||||
):
|
|
||||||
row = cls.layout.row(align=True)
|
row = cls.layout.row(align=True)
|
||||||
row.prop(data=cls.props, property="cardinal_point", text="Axis")
|
row.prop(data=cls.props, property="cardinal_point", text="Axis")
|
||||||
op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="")
|
op = row.operator("bim.change_cardinal_point", icon="FILE_REFRESH", text="")
|
||||||
@@ -343,9 +336,6 @@ class BimToolUI:
|
|||||||
cls.draw_type_selection_interface()
|
cls.draw_type_selection_interface()
|
||||||
|
|
||||||
if AuthoringData.data["ifc_classes"]:
|
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 = cls.layout.row(align=True)
|
||||||
row.label(text="", icon="EVENT_SHIFT")
|
row.label(text="", icon="EVENT_SHIFT")
|
||||||
row.label(text="", icon="EVENT_A")
|
row.label(text="", icon="EVENT_A")
|
||||||
@@ -418,10 +408,18 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
self.has_ifc_class = True
|
self.has_ifc_class = True
|
||||||
|
|
||||||
self.active_class = None
|
self.active_class = None
|
||||||
|
self.active_material_usage = None
|
||||||
element = tool.Ifc.get_entity(context.active_object)
|
element = tool.Ifc.get_entity(context.active_object)
|
||||||
if element:
|
if element:
|
||||||
self.active_class = element.is_a()
|
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:
|
try:
|
||||||
self.has_ifc_class = bool(self.props.ifc_class)
|
self.has_ifc_class = bool(self.props.ifc_class)
|
||||||
except:
|
except:
|
||||||
@@ -451,7 +449,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bpy.ops.bim.add_constr_type_instance()
|
bpy.ops.bim.add_constr_type_instance()
|
||||||
|
|
||||||
def hotkey_S_C(self):
|
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")
|
bpy.ops.bim.align_wall(align_type="CENTERLINE")
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.align_product(align_type="CENTERLINE")
|
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):
|
def hotkey_S_E(self):
|
||||||
if not bpy.context.selected_objects:
|
if not bpy.context.selected_objects:
|
||||||
return
|
return
|
||||||
elif self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
elif self.active_material_usage == "LAYER2":
|
||||||
bpy.ops.bim.join_wall(join_type="T")
|
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:
|
if not bpy.context.active_object:
|
||||||
pass
|
pass
|
||||||
elif bpy.context.active_object.mode == "OBJECT":
|
elif bpy.context.active_object.mode == "OBJECT":
|
||||||
bpy.ops.bim.enable_editing_extrusion_profile()
|
bpy.ops.bim.enable_editing_extrusion_profile()
|
||||||
elif self.active_class in (
|
elif self.active_material_usage == "PROFILE":
|
||||||
"IfcColumn",
|
|
||||||
"IfcColumnStandardCase",
|
|
||||||
"IfcBeam",
|
|
||||||
"IfcBeamStandardCase",
|
|
||||||
"IfcMember",
|
|
||||||
"IfcMemberStandardCase",
|
|
||||||
):
|
|
||||||
bpy.ops.bim.extend_profile(join_type="T")
|
bpy.ops.bim.extend_profile(join_type="T")
|
||||||
|
|
||||||
def hotkey_S_F(self):
|
def hotkey_S_F(self):
|
||||||
if self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
if self.active_material_usage == "LAYER2":
|
||||||
bpy.ops.bim.flip_wall()
|
bpy.ops.bim.flip_wall()
|
||||||
elif self.active_class in ("IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"):
|
elif self.active_class in ("IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"):
|
||||||
bpy.ops.bim.flip_fill()
|
bpy.ops.bim.flip_fill()
|
||||||
|
|
||||||
def hotkey_S_G(self):
|
def hotkey_S_G(self):
|
||||||
if self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
if self.active_material_usage == "LAYER2":
|
||||||
bpy.ops.bim.recalculate_wall()
|
bpy.ops.bim.recalculate_wall()
|
||||||
elif self.active_class in (
|
elif self.active_material_usage == "PROFILE":
|
||||||
"IfcColumn",
|
|
||||||
"IfcColumnStandardCase",
|
|
||||||
"IfcBeam",
|
|
||||||
"IfcBeamStandardCase",
|
|
||||||
"IfcMember",
|
|
||||||
"IfcMemberStandardCase",
|
|
||||||
):
|
|
||||||
bpy.ops.bim.recalculate_profile()
|
bpy.ops.bim.recalculate_profile()
|
||||||
elif self.active_class in ("IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"):
|
elif self.active_class in ("IfcWindow", "IfcWindowStandardCase", "IfcDoor", "IfcDoorStandardCase"):
|
||||||
bpy.ops.bim.recalculate_fill()
|
bpy.ops.bim.recalculate_fill()
|
||||||
|
|
||||||
def hotkey_S_M(self):
|
def hotkey_S_M(self):
|
||||||
if self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
if self.active_material_usage == "LAYER2":
|
||||||
bpy.ops.bim.merge_wall()
|
bpy.ops.bim.merge_wall()
|
||||||
|
|
||||||
def hotkey_S_R(self):
|
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")
|
bpy.ops.bim.rotate_90(axis="Z")
|
||||||
elif self.active_class in ("IfcColumn", "IfcColumnStandardCase"):
|
elif self.active_class in ("IfcColumn", "IfcColumnStandardCase"):
|
||||||
bpy.ops.bim.rotate_90(axis="Z")
|
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")
|
bpy.ops.bim.rotate_90(axis="Y")
|
||||||
|
|
||||||
def hotkey_S_K(self):
|
def hotkey_S_K(self):
|
||||||
if self.active_class in ("IfcWall", "IfcWallStandardCase"):
|
if self.active_material_usage == "LAYER2":
|
||||||
bpy.ops.bim.split_wall()
|
bpy.ops.bim.split_wall()
|
||||||
|
|
||||||
def hotkey_S_T(self):
|
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")
|
bpy.ops.bim.join_wall(join_type="L")
|
||||||
elif self.active_class in (
|
elif self.active_material_usage == "PROFILE":
|
||||||
"IfcColumn",
|
|
||||||
"IfcColumnStandardCase",
|
|
||||||
"IfcBeam",
|
|
||||||
"IfcBeamStandardCase",
|
|
||||||
"IfcMember",
|
|
||||||
"IfcMemberStandardCase",
|
|
||||||
):
|
|
||||||
bpy.ops.bim.extend_profile(join_type="L")
|
bpy.ops.bim.extend_profile(join_type="L")
|
||||||
|
|
||||||
def hotkey_S_V(self):
|
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")
|
bpy.ops.bim.align_wall(align_type="INTERIOR")
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.align_product(align_type="POSITIVE")
|
bpy.ops.bim.align_product(align_type="POSITIVE")
|
||||||
|
|
||||||
def hotkey_S_X(self):
|
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():
|
if bpy.ops.bim.align_wall.poll():
|
||||||
bpy.ops.bim.align_wall(align_type="EXTERIOR")
|
bpy.ops.bim.align_wall(align_type="EXTERIOR")
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.align_product(align_type="NEGATIVE")
|
bpy.ops.bim.align_product(align_type="NEGATIVE")
|
||||||
|
|
||||||
def hotkey_S_Y(self):
|
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")
|
bpy.ops.bim.join_wall(join_type="V")
|
||||||
elif self.active_class in (
|
elif self.active_material_usage == "PROFILE":
|
||||||
"IfcColumn",
|
|
||||||
"IfcColumnStandardCase",
|
|
||||||
"IfcBeam",
|
|
||||||
"IfcBeamStandardCase",
|
|
||||||
"IfcMember",
|
|
||||||
"IfcMemberStandardCase",
|
|
||||||
):
|
|
||||||
bpy.ops.bim.extend_profile(join_type="V")
|
bpy.ops.bim.extend_profile(join_type="V")
|
||||||
|
|
||||||
def hotkey_S_O(self):
|
def hotkey_S_O(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user