IFC转MESH和BREPIfcOpenShell
本文介绍如何利用IfcOpenShell读取IFC文件中的几何数据并生成网格或BREP。
一、IfcOpenShell简介
IfcOpenShell 是一个用于处理 IFC 数据的库,采用 LGPL 3.0(自由和开源)许可。
IfcOpenShell的功能包括: 解析ifc 从 ifc 表示创建几何体 使用 pythonOCC 显示几何体 提供Blender 的 Ifc 导入器 提供3ds Max 的 Ifc 导入器 将几何体转换为多种格式
一些使用 IfcOpenShell 的项目包括: FreeCAD:参数化 CAD 建模器,包括 BIM 工作台 BIMserver :多用户自托管 BIM 平台,带有插件生态系统以查看、分析、合并等……
在本文中,我们将使用一个从 ifc 实体生成网格体的函数,在我们的例子中是 IfcWall,看看我们可以得到什么结果。 二、获取原始IFC文件
首先使用 FreeCAD 创建一个简单墙并导出为 .ifc 文件:
先决条件:已安装 IfcOpenShell。 此处使用的版本:0.6.0a1 三、IFC转网格体
首先我们需要引入 ifcopenshell 并打开 ifc 文件: import ifcopenshell from ifcopenshell import geom def read_geom(ifc_path): ifc_file = ifcopenshell.open(ifc_path) settings = geom.settings()
geom.settings 用于设置转换选项。 默认情况下,ifcopenshell 生成具有顶点、边和面的网格。
ifc_file.by_type("IfcClass")是获取所选类(包括子类)的所有元素的一种非常方便的方法。 因此,如果使用 IfcBuildingElement,它还将包括 IfcWall、IfcWindow、IfcSlab、IfcBeam 等……
geom.create_shape(settings, ifc_entity) 是将 ifc 实体转换为网格的函数。 我们可以观察到顶点存储在单个元组中,而不是 xyz 三元组。 边和面也一样。 for ifc_entity in ifc_file.by_type("IfcWall"): shape = geom.create_shape(settings, ifc_entity) # ios stands for IfcOpenShell ios_vertices = shape.geometry.verts ios_edges = shape.geometry.edges ios_faces = shape.geometry.faces # IfcOpenShell store vertices in a single tuple, same for edges and faces print(ios_vertices) print(ios_edges) print(ios_faces) """ Above will result in : (0.0, 0.0, 0.0, 0.0, 0.0, 3.0, 10.0, 0.0, 0.0, 10.0, 0.0, 3.0, 10.0, 0.2, 0.0, 10.0, 0.2, 3.0, 0.0, 0.2, 0.0, 0.0, 0.2, 3.0) (0, 1, 1, 3, 0, 2, 2, 3, 2, 3, 2, 4, 3, 5, 4, 5, 4, 5, 5, 7, 4, 6, 6, 7, 6, 7, 0, 6, 1, 7, 0, 1, 0, 6, 0, 2, 4, 6, 2, 4, 1, 7, 1, 3, 5, 7, 3, 5) (1, 0, 3, 3, 0, 2, 3, 2, 4, 5, 3, 4, 5, 4, 7, 7, 4, 6, 7, 6, 0, 1, 7, 0, 0, 6, 2, 2, 6, 4, 3, 7, 1, 5, 7, 3) """
很明显,顶点是 x,y,z 一个接一个的三元组。 但是如何定义边和面呢? 边是由 2 个顶点包围的线,但我们看到的值不是顶点。 网格中的面是由 3 个顶点和 3 条边界定的三角形表面。 如果我们制作一组边和面值,我们会得到一组长度为 8 的值。 print(set(ios_edges)) print(set(ios_faces)) """ Above will result in : {0, 1, 2, 3, 4, 5, 6, 7} {0, 1, 2, 3, 4, 5, 6, 7} """
如果我们按 3 个值 (x,y,z) 对顶点进行分组,按 2 个值 (vertex1, vertex2) 对边进行分组,按 3 个值对面进行分组(3 个顶点或 3 条边),我们会看到我们的墙几何体由 8 个顶点、24 条边和12个面定义。 边和面值都是顶点索引。 # Let"s parse it and prepare it for FreeCAD import vertices = [ FreeCAD.Vector(ios_vertices[i : i + 3]) for i in range(0, len(ios_vertices), 3) ] edges = [ios_edges[i : i + 2] for i in range(0, len(ios_edges), 2)] faces = [tuple(ios_faces[i : i + 3]) for i in range(0, len(ios_faces), 3)] print( f"This {ifc_entity.is_a()} has been defined by {len(vertices)} vertices, {len(edges)} edges and {len(faces)} faces" ) print(vertices) print(edges) print(faces) """ Above will result in : This IfcWall has been defined by 8 vertices, 24 edges and 12 faces [(0.0, 0.0, 0.0), (0.0, 0.0, 3.0), (10.0, 0.0, 0.0), (10.0, 0.0, 3.0), (10.0, 0.2, 0.0), (10.0, 0.2, 3.0), (0.0, 0.2, 0.0), (0.0, 0.2, 3.0)] [(0, 1), (1, 3), (0, 2), (2, 3), (2, 3), (2, 4), (3, 5), (4, 5), (4, 5), (5, 7), (4, 6), (6, 7), (6, 7), (0, 6), (1, 7), (0, 1), (0, 6), (0, 2), (4, 6), (2, 4), (1, 7), (1, 3), (5, 7), (3, 5)] [(1, 0, 3), (3, 0, 2), (3, 2, 4), (5, 3, 4), (5, 4, 7), (7, 4, 6), (7, 6, 0), (1, 7, 0), (0, 6, 2), (2, 6, 4), (3, 7, 1), (5, 7, 3)] """ return {"vertices": vertices, "edges": edges, "faces": faces}
当然 FreeCAD 已经有更好的方法来导入 IfcWall ,但让我们使用自己的网格来生成几何图形: import FreeCAD import FreeCADGui import Mesh if __name__ == "__main__": mesh_values = read_geom( "/home/cyril/git/pythoncvc.net/IfcOpenShellSamples/Wall.ifc" ) # Create a FreeCAD geometry. A FreeCAD can take vertices and faces as input mesh = Mesh.Mesh((mesh_values["vertices"], mesh_values["faces"])) # Ifc lenght internal unit : meter. FreeCAD internal unit : mm. scale_factor = 1000 matrix = FreeCAD.Matrix() matrix.scale(scale_factor, scale_factor, scale_factor) mesh.transform(matrix) # Allow you to embed FreeCAD in python https://www.freecadweb.org/wiki/Embedding_FreeCAD FreeCADGui.showMainWindow() doc = FreeCAD.newDocument() # Add geometry to FreeCAD scenegraph (Coin) fc_mesh = doc.addObject("Mesh::Feature", "IfcMesh") fc_mesh.Mesh = mesh # Set Draw Style to display mesh edges. Orient view and fit to wall FreeCADGui.runCommand("Std_DrawStyle",1) FreeCADGui.Selection.addSelection(fc_mesh) FreeCADGui.activeView().viewIsometric() FreeCADGui.SendMsgToActiveView("ViewSelection") FreeCADGui.exec_loop()
上图是在 FreeCAD 中生成的几何图形,网格可以快速显示,但它通常不是你想要在 BIM 创作软件中使用的内容。 所以下次我们将看到如何生成边界表示。
完整的源代码可在此处获得。 四、IFC转BREP
前面我们使用 IfcOpenShell (IOS) 的标准设置来读取正在生成网格的 ifc 几何体。 要生成其他内容,让我们看一下可用的设置。
如果你的 IDE 提供了良好的自动完成功能,你将能够看到有哪些选项,但看不到它们的含义。 通过使用其中一个选项作为关键字在 IOS 存储库中进行快速搜索,可以很快找到一个名为 IfcGeomIteratorSettings.h 的头文件,其中包含所有定义: /// Specifies whether to use the Open Cascade BREP format for representation /// items rather than to create triangle meshes. This is useful is IfcOpenShell /// is used as a library in an application that is also built on Open Cascade. USE_BREP_DATA = 1 << 3,
BREP 代表边界表示,这可能是你在对参数化风管或管道及其相关组件建模时想要使用的。 在 python 中定义设置如下: # Define settings settings = geom.settings() settings.set(settings.USE_BREP_DATA, True)
如果将生成的 brep 数据写入文件,你将看到它实际上是设置说明中建议的OpenCascade BREP 格式。 shape = geom.create_shape(settings, ifc_entity) # occ stands for OpenCascade occ_shape = shape.geometry.brep_data # IfcOpenShell generate an Open Cascade BREP with open("IfcOpenShellSamples/brep_data", "w") as file: file.write(occ_shape)
幸运的是,被视为 FreeCAD 核心组件的 Part 模块也基于 Open Cascade,这使得将几何体导入 FreeCAD 变得如此简单: # Create FreeCAD shape from Open Cascade BREP fc_shape = Part.Shape() fc_shape.importBrepFromString(occ_shape) # Ifc lenght internal unit : meter. FreeCAD internal unit : mm. fc_shape.scale(1000) # Add geometry to FreeCAD scenegraph (Coin) fc_part = doc.addObject("Part::Feature", "IfcPart") fc_part.Shape = fc_shape
不要忘记在文件顶部导入Part而不是Mesh。
如果我们使用此处提供的完整代码为之前文章中的墙生成几何图形,将获得相同的实体,但这次不是网格(没有三角形):
上面只导入了 IfcWall 实体,现在让我们从 wikilab.ifc 的 wikihouse 项目导入 IfcElement 实体,得到以下几何图形:
当然 FreeCAD 仍然有更好的导入方式,但如果你激活着色模式,会得到更好的效果:
原文链接:http://www.bimant.com/blog/ifc-to-mesh-and-brep/