[英]How can i change an objects IfcClassification with python/ifcopenshell, f.ex IfcBuildingElementProxy to IfcWindow?
我有一個包含許多元素的模型,這些元素被歸類為 ifcbuildingelementproxy(或未分類,因為這是 ifc 導出軟件又名 ifcObject 的標准)。 我有一個代碼可以找到我想要更改其分類的所有元素,但我似乎找不到更改它的方法。 我想要做的是讓我的腳本將所有名稱以“whatever”開頭的元素重新分類為 IfcWindow 而不是 IfcBuildingElementProxy。
def re_classify():
ifc_loc='thefile.ifc'
ifcfile = ifcopenshell.open(ifc_loc)
create_guid = lambda: ifcopenshell.guid.compress(uuid.uuid1().hex)
owner_history = ifcfile.by_type("IfcOwnerHistory")[0]
element = ifcfile.by_type("IfcElement")
sets = ifcfile.by_type("IfcPropertySet")
search_word_in_name='M_Muntin'
for e in element:
if e.is_a('IfcBuildingElementProxy'):
if e.Name.startswith(search_word_in_name,0,len(search_word_in_name)):
e.is_a()==e.is_a('IfcWindow') #<--- THIS DOES NOTHING
print (e)
print(e.Name,' - ', e.is_a())
re_classify()
我希望 f.ex
# 13505=IfcBuildingElementProxy('3OAbz$kW1DyuZY2KLwUwkk',#41,'M_Muntin Pattern_2x2:M_Muntin Pattern_2x2:346152',$,'M_Muntin Pattern_2x2',#13504,#13499,'346152',$)
將會呈現
# 13505=IfcWindow('3OAbz$kW1DyuZY2KLwUwkk',#41,'M_Muntin Pattern_2x2:M_Muntin Pattern_2x2:346152',$,'M_Muntin Pattern_2x2',#13504,#13499,'346152',$)
在 Unix/Linux shell 上,您可以使用單行(不使用 Python 或 IfcOpenShell)進行替換,如下所示:
sed -i '/IFCBUILDINGELEMENTPROXY(.*,.*,.M_Muntin/{s/IFCBUILDINGELEMENTPROXY/IFCWINDOW/}' thefile.ifc
請注意,它直接在初始文件中進行修改。
(注意:在 Cygwin 上測試)
您不能簡單地更改類型。 不可能為函數賦值,並且is_a
是函數而不是屬性(設計為因為類型不可修改)。
此外, IfcBuildingElementProxy
和IfcWindow
共享其屬性的子集。 也就是說IfcBuildingElementProxy
有一個IfcWindow
沒有,反之亦然。 幸運的是, IfcWindow
的附加屬性都是可選的。 因此,您可以創建一個新的窗口實體,從代理復制公共屬性,不設置其他屬性並刪除代理。
commonAttrs = list(e.get_Info().values())[2:-1]
window = ifcfile.createIfcWindow(*commonAttrs)
ifcfile.remove(e)
您仍然需要查找引用代理的其他實體並將引用替換為對窗口的引用以獲得有效的 ifc 文件。
感謝其他答案和更多研究,我提出了以下代碼來完成這項任務。
如果新類型實例中不能設置的屬性數量超過5個,則不進行更新。
它現在似乎運行良好,不完全確定檢查RelatedElements
和RelatedObjects
是否足夠,或者是否有更多屬性需要檢查。
def change_element_type(
element: entity_instance,
new_type: str,
model: ifcopenshell.file,
) -> None:
"""
Change the element type and pass all the compatible properties.
GlobalId is kept, Element ID is not.
If the new type misses more than 5 of the old attributes,
the change is avoided.
Args:
element: original ifc element
new_type: type to change the element to
model: IFC model containing the element
"""
if new_type == element.is_a():
return
new_element = model.create_entity(new_type)
old_attrs = element.get_info(include_identifier=False)
del old_attrs["type"]
new_attrs = new_element.get_info(include_identifier=False)
missing_attrs = set(old_attrs) - set(new_attrs)
if len(missing_attrs) > 5:
warnings.warn(
f"New type {new_type} for element {element.id} "
f"misses too many attributes:\n {', '.join(missing_attrs)}.\n"
"Type change is cancelled."
)
model.remove(new_element)
return
for name in new_attrs:
if name in old_attrs:
setattr(new_element, name, old_attrs[name])
update_references(element, model, new_element)
model.remove(element)
def update_references(element, model, new_element):
for to_update in model.get_inverse(element):
for attr in ("RelatedElements", "RelatedObjects"):
try:
rel_objs = list(getattr(to_update, attr))
except AttributeError:
continue
try:
rel_objs.remove(element)
except ValueError:
continue
rel_objs.append(new_element)
setattr(to_update, attr, rel_objs)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.