如何使用python/ifcopenshell,f.ex IfcBuildingElementProxy 将对象 Ifc



我有一个包含许多元素的模型,该模型被归类为 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函数是函数而不是属性(由于类型不可修改的原因,因此设计(。

进一步的IfcBuildingElementProxyIfcWindow仅共享其属性的子集。也就是说IfcBuildingElementProxy有一个IfcWindow没有的,反之亦然。幸运的是,IfcWindow的其他属性都是可选的。因此,您可以创建一个新的窗口实体,从代理复制公共属性,不设置其他属性并删除代理。

commonAttrs = list(e.get_Info().values())[2:-1]
window = ifcfile.createIfcWindow(*commonAttrs)
ifcfile.remove(e)

您仍然必须查找引用代理的其他实体,并将引用替换为对窗口的引用,以获得有效的 ifc 文件。

感谢其他答案和更多研究,我提出了以下代码来完成此任务。

如果新类型实例中无法设置的属性数超过 5 个,则不执行更新。

它目前似乎运行良好,不完全确定是否足以检查RelatedElementsRelatedObjects,或者是否有更多属性需要检查。

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)

相关内容

  • 没有找到相关文章

最新更新