IFC转Mesh/BRep
本文介绍如何利用IfcOpenShell读取IFC文件中的几何数据并生成网格或BREP。另一种方法是使用这个在线3D转换工具,可以将IFC转换为GLTF、GLB、OBJ、PLY等8种格式。
一、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 仍然有更好的导入方式,但如果你激活着色模式,会得到更好的效果:
原文链接:IfcOpenShell – Read Geom As Brep
BimAnt翻译整理,转载请标明出处