在之前的文章中,我们使用 IfcOpenShell (IOS) 读取 ifc 几何并将其转换为 brep。 当我们读取 wikilab.ifc文件时,一切似乎都是正确的,但真的如此吗?
当你在项目中使用 BIM 时,坐标始终是正确讨论的主题。 就此而言,我建议你阅读 Dion Moult 的文章 IFC Coordinate Reference Systems and Revit 以及文章中引用的参考资料。
本教程使用的 IfcOpenShell 版本:0.6.0a1,教程中的完整代码可以从这里下载。
1、IFC 中的Placement
几何体通常有自己的局部坐标系 (LCS)。 为什么 ?
以航站楼为例。 你经常在一个项目中使用几种类型的风道末端。 在每个空间中多次复制相同的航站楼几何形状。 如果你的几何图形是使用世界坐标系 (WCS) 定义的,则需要为每个几何体定义一个新几何图形。 如果你的几何图形在其自己的 LCS 中定义,则可以在任何地方使用相同的几何图形,并给出其相对于另一个参考的位置。
在 ifc 规范中,通风终端是 IfcAirTerminal (IFC4) 或 IfcFlowTerminal (IFC2x3)。 两者都继承自IfcProduct(如墙、窗、管道等),它具有 IfcObjectPlacement 类型的 ObjectPlacement 属性。
ObjectPlacement属性描述产品在空间中的放置,放置可以是绝对的(相对于世界坐标系)、相对的(相对于另一个产品的对象放置)或约束(例如相对于网格轴)。 它由 IfcObjectPlacement 的各种子类型决定,其中包括用于确定对象坐标系变换的轴放置信息。 — IFC 文档中的ObjectPlacement属性定义
IfcLocalPlacement 子类型,我认为是最常见的,有 2 个属性:
- #1 - IfcObjectPlacement 类型的 PlacementRelTo。 如果填充位置是相对的。 如果空放置使用 WCS。
- #2 - RelativePlacement 基本上是一个 2D 或 3D 坐标。
可以链接相对位置,例如: AirTerminal << space << buildingstorey << building << Site。 要检索相对于 WCS 的对象放置,需要通过完整链转换第一个相对放置。
2、IfcOpenShell 中的Placement
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 设置。
3、使用Placement矩阵
正如你在创建几何体时在其源代码中所述,它的位置由一个 4×3 矩阵给出。 但要注意,当显示为元组时,IfcOpenShell 矩阵和 FreeCAD 矩阵是转置的:
- IfcOpenShell 矩阵值是 4 个连续向量的 xyz 的元组。格式 : (v1.x, v1.y, v1.z, v2.x, v2.y …, v4.z)
- FreeCAD 矩阵构造函数最多占用 16 个浮点数。 按 x、y、z 值分组的 4 个向量。格式 : (v1.x, v2.x, v3.x, v4.x, v1.y, …, v4.z, 0, 0, 0, 1)
关于 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] *= SCALE
m_l.extend(line)
return FreeCAD.Matrix(*m_l)
在几何形状创建之后,我们调用它来设置对象的位置:
# 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(SCALE)
# Shape scale must be applied before shape placement else placement scale would be doubled
fc_shape.Placement = ios_shape_to_fc_placement(ios_shape)
这样我们就得到了正确放置的墙:
4、USE_WORLD_COORDINATES
定义设置仍然是相同的过程:
settings.set(settings.USE_WORLD_COORDS, True)
我们可以保留相同的代码库,因为它将应用不会改变任何内容的单位矩阵。 通过运行脚本,你将再次获得正确放置的墙,但这次位置仍然是 0, 0, 0,这意味着几何顶点坐标是用它们的绝对坐标定义的:
出于在第一部分中解释的原因,我倾向于说此解决方案不是 HVAC 领域中 CAD/BIM 工作的最佳选择。 目前 FreeCAD 以这种方式导入和导出 ifc 我将调查原因并可能在论坛上发布此主题。
原文链接:IfcOpenShell坐标问题 — BimAnt