mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-30 03:59:55 +00:00
Purge/merge IfcPerson entities
This commit is contained in:
@@ -739,9 +739,6 @@ class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator, ExportHe
|
|||||||
tool.Ifc.get().write(self.filepath)
|
tool.Ifc.get().write(self.filepath)
|
||||||
|
|
||||||
|
|
||||||
PurgeObjectType = Literal["TYPE", "PROFILE", "STYLE", "MATERIAL", "ORGANIZATION", "APPLICATION"]
|
|
||||||
|
|
||||||
|
|
||||||
class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
|
class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.purge_unused_objects"
|
bl_idname = "bim.purge_unused_objects"
|
||||||
bl_label = "Purge Unused Objects"
|
bl_label = "Purge Unused Objects"
|
||||||
@@ -749,11 +746,11 @@ class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
object_type: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
|
object_type: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
|
||||||
name="Object Type",
|
name="Object Type",
|
||||||
items=((s, s.capitalize(), "") for s in get_args(PurgeObjectType)),
|
items=((s, s.capitalize(), "") for s in get_args(tool.Debug.PurgeMergeObjectType)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
object_type: PurgeObjectType
|
object_type: tool.Debug.PurgeMergeObjectType
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
object_type = self.object_type
|
object_type = self.object_type
|
||||||
@@ -767,6 +764,8 @@ class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
purged = tool.Material.purge_unused_materials()
|
purged = tool.Material.purge_unused_materials()
|
||||||
elif object_type in ("APPLICATION", "ORGANIZATION"):
|
elif object_type in ("APPLICATION", "ORGANIZATION"):
|
||||||
purged = core.purge_unused_elements(tool.Ifc, tool.Debug, "IfcApplication")
|
purged = core.purge_unused_elements(tool.Ifc, tool.Debug, "IfcApplication")
|
||||||
|
elif object_type == "PERSON":
|
||||||
|
purged = core.purge_unused_elements(tool.Ifc, tool.Debug, "IfcPerson")
|
||||||
else:
|
else:
|
||||||
assert_never(object_type)
|
assert_never(object_type)
|
||||||
|
|
||||||
@@ -775,22 +774,7 @@ class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if purged == 0:
|
if purged == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
if object_type == "PROFILE":
|
tool.Debug.refresh_ui_after_purge_merge(object_type)
|
||||||
props = tool.Profile.get_profile_props()
|
|
||||||
if props.is_editing:
|
|
||||||
bpy.ops.bim.load_profiles()
|
|
||||||
elif object_type == "STYLE":
|
|
||||||
props = tool.Style.get_style_props()
|
|
||||||
if props.is_editing:
|
|
||||||
bpy.ops.bim.load_styles()
|
|
||||||
elif object_type == "MATERIAL":
|
|
||||||
props = tool.Material.get_material_props()
|
|
||||||
if props.is_editing:
|
|
||||||
bpy.ops.bim.load_materials()
|
|
||||||
elif object_type == "ORGANIZATION":
|
|
||||||
props = tool.Owner.get_owner_props()
|
|
||||||
if tool.Ifc.get_entity_by_id(props.active_organisation_id) is None:
|
|
||||||
props.active_organisation_id = 0
|
|
||||||
|
|
||||||
|
|
||||||
class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
|
class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
@@ -801,11 +785,11 @@ class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
object_type: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
|
object_type: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
|
||||||
name="Object Type",
|
name="Object Type",
|
||||||
items=((s, s.capitalize(), "") for s in get_args(PurgeObjectType)),
|
items=((s, s.capitalize(), "") for s in get_args(tool.Debug.PurgeMergeObjectType)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
object_type: PurgeObjectType
|
object_type: tool.Debug.PurgeMergeObjectType
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
object_type: str = self.object_type
|
object_type: str = self.object_type
|
||||||
@@ -817,8 +801,10 @@ class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
plural_object_type = f"{object_type.lower()}s"
|
plural_object_type = f"{object_type.lower()}s"
|
||||||
if merged_data:
|
if merged_data:
|
||||||
for element_type, element_names in merged_data.items():
|
for element_type, element_names in merged_data.items():
|
||||||
names = ", ".join([n or "Unnamed" for n in element_names])
|
print(f"- {element_type}:")
|
||||||
print(f"- {element_type}: {names}")
|
for name in element_names:
|
||||||
|
name = name or "Unnamed"
|
||||||
|
print(f" - '{name}'")
|
||||||
merged = sum(len(v) for v in merged_data.values())
|
merged = sum(len(v) for v in merged_data.values())
|
||||||
|
|
||||||
msg = " See system console for details." if merged else ""
|
msg = " See system console for details." if merged else ""
|
||||||
@@ -827,18 +813,7 @@ class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if merged == 0:
|
if merged == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
if object_type == "PROFILE":
|
tool.Debug.refresh_ui_after_purge_merge(object_type)
|
||||||
props = tool.Profile.get_profile_props()
|
|
||||||
if props.is_editing:
|
|
||||||
bpy.ops.bim.load_profiles()
|
|
||||||
elif object_type == "STYLE":
|
|
||||||
props = tool.Style.get_style_props()
|
|
||||||
if props.is_editing:
|
|
||||||
bpy.ops.bim.load_styles()
|
|
||||||
elif object_type == "MATERIAL":
|
|
||||||
props = tool.Material.get_material_props()
|
|
||||||
if props.is_editing:
|
|
||||||
bpy.ops.bim.load_materials()
|
|
||||||
|
|
||||||
|
|
||||||
class PipInstall(bpy.types.Operator):
|
class PipInstall(bpy.types.Operator):
|
||||||
|
|||||||
@@ -635,7 +635,7 @@ class BIM_PT_purge(Panel):
|
|||||||
layout.operator("bim.purge_unused_objects", text="Purge Unused Types").object_type = "TYPE"
|
layout.operator("bim.purge_unused_objects", text="Purge Unused Types").object_type = "TYPE"
|
||||||
layout.operator("bim.purge_unused_openings", text="Purge Unused Openings in Selected Objects")
|
layout.operator("bim.purge_unused_openings", text="Purge Unused Openings in Selected Objects")
|
||||||
|
|
||||||
MERGEABLE_OBJECT_TYPES = ("MATERIAL", "STYLE", "ORGANIZATION", "APPLICATION")
|
MERGEABLE_OBJECT_TYPES = ("MATERIAL", "STYLE", "ORGANIZATION", "APPLICATION", "PERSON")
|
||||||
|
|
||||||
for object_type in MERGEABLE_OBJECT_TYPES:
|
for object_type in MERGEABLE_OBJECT_TYPES:
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ def purge_unused_elements(ifc: type[tool.Ifc], debug: type[tool.Debug], ifc_clas
|
|||||||
if ifc_class == "IfcApplication":
|
if ifc_class == "IfcApplication":
|
||||||
for element in unused_elements:
|
for element in unused_elements:
|
||||||
ifc.run("owner.remove_application", application=element)
|
ifc.run("owner.remove_application", application=element)
|
||||||
|
elif ifc_class == "IfcPerson":
|
||||||
|
for element in unused_elements:
|
||||||
|
ifc.run("owner.remove_person", person=element)
|
||||||
else:
|
else:
|
||||||
debug.remove_unused_elements(unused_elements)
|
debug.remove_unused_elements(unused_elements)
|
||||||
return unused_elements_amount
|
return unused_elements_amount
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class Debug(bonsai.core.tool.Debug):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def merge_identical_objects(
|
def merge_identical_objects(
|
||||||
cls,
|
cls,
|
||||||
object_type: Literal["STYLE", "MATERIAL", "ORGANIZATION", "APPLICATION"],
|
object_type: Literal["STYLE", "MATERIAL", "ORGANIZATION", "APPLICATION", "PERSON"],
|
||||||
) -> dict[str, list[str]]:
|
) -> dict[str, list[str]]:
|
||||||
"""Merge identical objects.
|
"""Merge identical objects.
|
||||||
|
|
||||||
@@ -153,6 +153,8 @@ class Debug(bonsai.core.tool.Debug):
|
|||||||
element_types = ["IfcOrganization"]
|
element_types = ["IfcOrganization"]
|
||||||
elif object_type == "APPLICATION":
|
elif object_type == "APPLICATION":
|
||||||
element_types = ["IfcApplication"]
|
element_types = ["IfcApplication"]
|
||||||
|
elif object_type == "PERSON":
|
||||||
|
element_types = ["IfcPerson"]
|
||||||
else:
|
else:
|
||||||
assert_never(object_type)
|
assert_never(object_type)
|
||||||
|
|
||||||
@@ -163,8 +165,13 @@ class Debug(bonsai.core.tool.Debug):
|
|||||||
hash_to_elements: defaultdict[int, list[ifcopenshell.entity_instance]] = defaultdict(list)
|
hash_to_elements: defaultdict[int, list[ifcopenshell.entity_instance]] = defaultdict(list)
|
||||||
for element in elements:
|
for element in elements:
|
||||||
# Except for styles, ignore unnamed elements as they may be not safe to merge
|
# Except for styles, ignore unnamed elements as they may be not safe to merge
|
||||||
|
merge_optional_names = ("STYLE", "PERSON")
|
||||||
not_optional_name = ("APPLICATION", "ORGANIZATION")
|
not_optional_name = ("APPLICATION", "ORGANIZATION")
|
||||||
if object_type != "STYLE" and object_type not in not_optional_name and not element.Name:
|
if (
|
||||||
|
object_type not in merge_optional_names
|
||||||
|
and object_type not in not_optional_name
|
||||||
|
and not element.Name
|
||||||
|
):
|
||||||
continue
|
continue
|
||||||
element_hash = get_hash(element)
|
element_hash = get_hash(element)
|
||||||
hash_to_elements[element_hash].append(element)
|
hash_to_elements[element_hash].append(element)
|
||||||
@@ -206,9 +213,50 @@ class Debug(bonsai.core.tool.Debug):
|
|||||||
merged_elements_names.append(application.ApplicationFullName)
|
merged_elements_names.append(application.ApplicationFullName)
|
||||||
ifcopenshell.api.owner.remove_application(ifc_file, application)
|
ifcopenshell.api.owner.remove_application(ifc_file, application)
|
||||||
|
|
||||||
|
elif object_type == "PERSON":
|
||||||
|
for person in elements[1:]:
|
||||||
|
ifcopenshell.util.element.replace_element(person, main_element)
|
||||||
|
merged_elements_names.append(
|
||||||
|
f"{person.Identification} / {person.FamilyName} / {person.GivenName}"
|
||||||
|
)
|
||||||
|
ifcopenshell.api.owner.remove_person(ifc_file, person)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert_never(object_type)
|
assert_never(object_type)
|
||||||
|
|
||||||
if merged_elements_names:
|
if merged_elements_names:
|
||||||
merged_element_types[element_type] = merged_elements_names
|
merged_element_types[element_type] = merged_elements_names
|
||||||
return merged_element_types
|
return merged_element_types
|
||||||
|
|
||||||
|
PurgeMergeObjectType = Literal["TYPE", "PROFILE", "STYLE", "MATERIAL", "ORGANIZATION", "APPLICATION", "PERSON"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def refresh_ui_after_purge_merge(cls, object_type: PurgeMergeObjectType) -> None:
|
||||||
|
if object_type == "PROFILE":
|
||||||
|
props = tool.Profile.get_profile_props()
|
||||||
|
if props.is_editing:
|
||||||
|
bpy.ops.bim.load_profiles()
|
||||||
|
elif object_type == "STYLE":
|
||||||
|
props = tool.Style.get_style_props()
|
||||||
|
if props.is_editing:
|
||||||
|
bpy.ops.bim.load_styles()
|
||||||
|
elif object_type == "MATERIAL":
|
||||||
|
props = tool.Material.get_material_props()
|
||||||
|
if props.is_editing:
|
||||||
|
bpy.ops.bim.load_materials()
|
||||||
|
elif object_type == "TYPE":
|
||||||
|
pass
|
||||||
|
elif object_type == "ORGANIZATION":
|
||||||
|
props = tool.Owner.get_owner_props()
|
||||||
|
if tool.Ifc.get_entity_by_id(props.active_organisation_id) is None:
|
||||||
|
props.active_organisation_id = 0
|
||||||
|
elif object_type == "APPLICATION":
|
||||||
|
props = tool.Owner.get_owner_props()
|
||||||
|
if tool.Ifc.get_entity_by_id(props.active_application_id) is None:
|
||||||
|
tool.Owner.clear_application()
|
||||||
|
elif object_type == "PERSON":
|
||||||
|
props = tool.Owner.get_owner_props()
|
||||||
|
if tool.Ifc.get_entity_by_id(props.active_person_id) is None:
|
||||||
|
tool.Owner.clear_person()
|
||||||
|
else:
|
||||||
|
assert_never(object_type)
|
||||||
|
|||||||
Reference in New Issue
Block a user