我有一个包含许多元素的模型,该模型被归类为 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)