在之前的文章中,我们使用 IfcOpenShell (IOS) 读取 ifc 几何并将其转换为 brep。 当我们读取 wikilab.ifc文件时,一切似乎都是正确的,但真的如此吗?
当你在项目中使用 BIM 时,坐标始终是正确讨论的主题。 就此而言,我建议你阅读 Dion Moult 的文章 IFC Coordinate Reference Systems and Revit 以及文章中引用的参考资料。
本教程使用的 IfcOpenShell 版本:0.6.0a1,教程中的完整代码可以从这里下载。
几何体通常有自己的局部坐标系 (LCS)。 为什么 ?
以航站楼为例。 你经常在一个项目中使用几种类型的风道末端。 在每个空间中多次复制相同的航站楼几何形状。 如果你的几何图形是使用世界坐标系 (WCS) 定义的,则需要为每个几何体定义一个新几何图形。 如果你的几何图形在其自己的 LCS 中定义,则可以在任何地方使用相同的几何图形,并给出其相对于另一个参考的位置。
在 ifc 规范中,通风终端是 IfcAirTerminal (IFC4) 或 IfcFlowTerminal (IFC2x3)。 两者都继承自IfcProduct(如墙、窗、管道等),它具有 IfcObjectPlacement 类型的 ObjectPlacement 属性。
ObjectPlacement属性描述产品在空间中的放置,放置可以是绝对的(相对于世界坐标系)、相对的(相对于另一个产品的对象放置)或约束(例如相对于网格轴)。 它由 IfcObjectPlacement 的各种子类型决定,其中包括用于确定对象坐标系变换的轴放置信息。 — IFC 文档中的ObjectPlacement属性定义
IfcLocalPlacement 子类型,我认为是最常见的,有 2 个属性:
IfcOpenShell 可用作解析器以获取与 IfcSchema 中定义的完全相同的位置。 然而,它也有方便的工具来避免抓取整个相对放置链。 要了解这一点的选项是 USE_WORLD_COORDS :
/// Specifies whether to apply the local placements of building elements
/// directly to the coordinates of the representation mesh rather than
/// to represent the local placement in the 4x3 matrix, which will in that
/// case be the identity matrix.
USE_WORLD_COORDS = 1 << 1,
当你像我们在之前的文章中所做的那样显示几何体时,坐标是使用几何体的局部坐标系 给出的。 它不可见,因为我们的墙放置在坐标 0,0,0 处。 现在让我们使用来自 ifcopenshell academy 的脚本来生成一个放置在 20,10,3 的新墙。 默认情况下,脚本还会在 0,0,0 处生成一堵墙。 要修改它的相对位置,我们需要修改以下行:
wall_placement = create_ifclocalplacement(ifcfile, relative_to=storey_placement)
考虑到函数定义,我们需要将这一行替换为:
wall_placement = create_ifclocalplacement(ifcfile, point=(20., 10., 3.), relative_to=storey_placement)
现在,如果你尝试根据我们之前的脚本从这个新创建的 hello_wall.ifc 加载几何图形,将看到墙仍然位于 0,0,0,这是错误的。

为了正确放置它,我们有 2 个选项:使用矩阵变换和 USE_WORLD_COORDINATES 设置。
正如你在创建几何体时在其源代码中所述,它的位置由一个 4×3 矩阵给出。 但要注意,当显示为元组时,IfcOpenShell 矩阵和 FreeCAD 矩阵是转置的:
关于 FreeCAD 矩阵的最后 0、0、0、1。 正如 OpenGL 教程的矩阵章节中所述:
这很快就会变得更加清楚,但现在,请记住这一点:
如果 W == 1,则向量 (X,Y,Z,1) 是空间中的一个位置。
如果 W == 0,则向量 (X,Y,Z,0) 是一个方向。
(事实上 ,永远记住这一点。) - OpenGL Tutorial Matrices Chapter
所以我们将使用一个函数将 IfcOpenShell 矩阵转置为 FreeCAD 矩阵:
def ios_to_fc_matrix(ios_matrix):m_l = list()for i in range(3):line = list(ios_matrix[i::3])line[-1] *= SCALEm_l.extend(line)return FreeCAD.Matrix(*m_l)
在几何形状创建之后,我们调用它来设置对象的位置:
# Create FreeCAD shape from Open Cascade BREPfc_shape = Part.Shape()fc_shape.importBrepFromString(occ_shape)# Ifc lenght internal unit : meter. FreeCAD internal unit : mm.fc_shape.scale(SCALE)# Shape scale must be applied before shape placement else placement scale would be doubledfc_shape.Placement = ios_shape_to_fc_placement(ios_shape)
这样我们就得到了正确放置的墙:

定义设置仍然是相同的过程:
settings.set(settings.USE_WORLD_COORDS, True)
我们可以保留相同的代码库,因为它将应用不会改变任何内容的单位矩阵。 通过运行脚本,你将再次获得正确放置的墙,但这次位置仍然是 0, 0, 0,这意味着几何顶点坐标是用它们的绝对坐标定义的:

出于在第一部分中解释的原因,我倾向于说此解决方案不是 HVAC 领域中 CAD/BIM 工作的最佳选择。 目前 FreeCAD 以这种方式导入和导出 ifc 我将调查原因并可能在论坛上发布此主题。
原文链接:IfcOpenShell坐标问题 — BimAnt