第12章:几何表达、布尔运算与三角网格生成
本章在前一章的架构基础上”动手”——具体走通 IFC 几何 → OCCT 实体 → 三角网格的全流程,并解析布尔运算、扫掠、面修复等关键算法在 Xbim 中的入口。
1. IfcRepresentation 体系回顾
IfcProductDefinitionShape
└── IfcShapeRepresentation* (Body / Axis / FootPrint / Profile)
├── ContextOfItems → IfcGeometricRepresentationContext
├── RepresentationType: "SweptSolid" / "Brep" / "Tessellation" / ...
└── Items[]: IfcRepresentationItem
├── IfcExtrudedAreaSolid / IfcRevolvedAreaSolid / IfcSweptDiskSolid
├── IfcBooleanResult / IfcBooleanClippingResult
├── IfcFacetedBrep / IfcManifoldSolidBrep
├── IfcTriangulatedFaceSet / IfcPolygonalFaceSet
├── IfcMappedItem → IfcRepresentationMap
└── IfcGeometricCurveSet, IfcSurfaceCurveSweptAreaSolid, ...
记住几个常见 RepresentationType:
| 类型 | Items 包含 |
|---|---|
SweptSolid |
IfcExtrudedAreaSolid / IfcRevolvedAreaSolid |
Brep |
IfcManifoldSolidBrep 系列 |
Tessellation |
IfcTriangulatedFaceSet / IfcPolygonalFaceSet |
Clipping |
IfcBooleanClippingResult(拉伸 + 半空间裁切) |
MappedRepresentation |
IfcMappedItem(实例化复用) |
Curve2D / Curve3D |
线段、轮廓 |
2. 拉伸(IfcExtrudedAreaSolid)
最常见的 IFC 几何之一。
IfcExtrudedAreaSolid
SweptArea : IfcProfileDef (2D 轮廓)
Position : IfcAxis2Placement3D (拉伸坐标系)
ExtrudedDirection : IfcDirection
Depth : IfcPositiveLengthMeasure
Xbim 的转换路径:
IfcProfileDef→TopoDS_Wire(二维线框):IfcRectangleProfileDef、IfcCircleProfileDef、IfcIShapeProfileDef、IfcArbitraryClosedProfileDef…
- 用
BRepBuilderAPI_MakeFace闭合为面; - 调用
BRepPrimAPI_MakePrism(face, dir * depth)拉伸成TopoDS_Solid; - 应用
Position矩阵变换; - 包装为
XbimSolid返回托管层。
var solid = engine.CreateSolid((IIfcExtrudedAreaSolid)rep);
Console.WriteLine($"V = {solid.Volume}, A = {solid.SurfaceArea}");
3. 旋转、扫掠、放样
| IFC | OCCT 调用 | 说明 |
|---|---|---|
IfcRevolvedAreaSolid |
BRepPrimAPI_MakeRevol |
围绕轴线旋转生成 |
IfcSurfaceCurveSweptAreaSolid |
BRepOffsetAPI_MakePipeShell |
沿引导线扫掠 |
IfcSweptDiskSolid |
BRepOffsetAPI_MakePipe + 圆截面 |
管道(DN)几何 |
IfcSectionedSpine |
自定义放样 | 断面变化的扫掠 |
IfcAdvancedBrep |
OCCT 直接构造 NURBS B-Rep | IFC4 引入,支持精确曲面 |
4. 布尔运算
IFC 用 IfcBooleanResult 表达布尔操作:
IfcBooleanResult
Operator : (UNION | INTERSECTION | DIFFERENCE)
FirstOperand : IfcBooleanOperand
SecondOperand : IfcBooleanOperand
IfcBooleanOperand 可以是 Solid、HalfSpace 或另一个 BooleanResult,递归形成 CSG 树。
Xbim 调用 OCCT 的对应类:
| Operator | OCCT 类 |
|---|---|
| UNION | BRepAlgoAPI_Fuse |
| DIFFERENCE | BRepAlgoAPI_Cut |
| INTERSECTION | BRepAlgoAPI_Common |
var result = engine.CreateBooleanResult((IIfcBooleanResult)rep);
布尔失败的常见原因:
- 共面相切:两个面恰好共面,OCCT 无法判断布尔结果。要么微调容差,要么微小偏移。
- 零厚度面:被扣掉之后剩 0 体积,OCCT 抛错。
- 面方向反向:OCCT 对面朝向敏感;Xbim 的 ShapeFix/Healing 会先做修复。
- 递归过深:上百次嵌套布尔会让性能下降到分钟级。
Xbim.Geometry.Engine 内部对每次失败会尝试若干 fallback:调整容差、跳过某次操作、改用 IfcBooleanClippingResult 的近似。
5. 半空间(IfcHalfSpaceSolid)
IFC 用半空间表达”裁切平面”:
IfcHalfSpaceSolid
BaseSurface : IfcSurface
AgreementFlag : Boolean // false = 法向同侧
Xbim 把它转成 OCCT 的”无界面 + 方向”组合,通常作为 IfcBooleanResult 的 SecondOperand 用来切墙、切板。
IfcPolygonalBoundedHalfSpace(带多边形边界的半空间)则是切土方、屋顶坡时常用。
6. Brep 与离散网格
6.1 IfcFacetedBrep / IfcManifoldSolidBrep
由 IfcClosedShell → IfcFace → IfcFaceBound → IfcPolyLoop 组成,是离散多边形构造的实体。Xbim 直接用 BRepBuilderAPI_MakeFace + MakeShell + MakeSolid 构造对应 OCCT 拓扑,并用 ShapeFix_Solid 修复方向。
6.2 IfcTriangulatedFaceSet(IFC4)
IFC4 引入的高效”三角网格”表达:
IfcTriangulatedFaceSet
Coordinates : IfcCartesianPointList3D (顶点)
CoordIndex : LIST OF LIST OF integer (三角形索引)
Normals : optional
...
Xbim 转换时直接构造 XbimShapeTriangulation,跳过 OCCT B-Rep 中间层(更快)。很多用 web-ifc / IfcOpenShell 导出的 IFC4 文件会用这种 representation,性能极佳。
6.3 IfcPolygonalFaceSet
类似但允许任意 N 边形面,Xbim 内部先做扇形剖分再做三角化。
7. 三角化(Mesh / Tessellation)
OCCT 通过 BRepMesh_IncrementalMesh 把 B-Rep 转成三角网格。Xbim 调用:
BRepMesh_IncrementalMesh mesher(shape, deflection, /*relative*/ false, angle);
mesher.Perform();
参数:
- deflection:弦高偏差,决定圆弧近似精度(mm);
- angle:相邻三角形的最大法线夹角(rad);
- relative:deflection 是否按 BRep 包围盒尺寸归一化。
之后 Xbim 提取 Poly_Triangulation,写入 XbimShapeTriangulation 或直接序列化到 wexbim 流:
using var ms = new MemoryStream();
using var bw = new BinaryWriter(ms);
engine.WriteTriangulation(bw, geomObject, tolerance: precision, deflection: 5, angle: 0.5);
8. Xbim3DModelContext:批量处理
应用层很少手工处理每个 IfcRepresentationItem,而是用 Xbim3DModelContext(Xbim.ModelGeometry.Scene):
using Xbim.ModelGeometry.Scene;
var context = new Xbim3DModelContext(model);
context.CreateContext(progDelegate: (p, m) => Console.Write($"\r{p}% {m} "));
它做的事:
- 找到模型中所有有
Bodyrepresentation 的产品; - 对每个独特的 representation 执行一次几何转换(共享几何只算一次,对应
IfcMappedItem/IfcRepresentationMap); - 计算每个产品的最终变换矩阵;
- 按颜色/材料分桶,方便后续渲染;
- 把网格数据写入
IModel.GeometryStore(在 .xbim 中是单独的几何流); - 内部使用并行任务(
Parallel.ForEach)加速。
之后,可以遍历几何:
using (var reader = model.GeometryStore.BeginRead())
{
foreach (var shape in reader.ShapeInstances)
{
// shape.IfcProductLabel
// shape.Transformation
// shape.RepresentationLabel
}
foreach (var geom in reader.ShapeGeometries)
{
// geom.ReferenceCount, geom.BoundingBox, geom.ShapeData(三角化数据)
}
}
ShapeInstances 是”产品级”实例,ShapeGeometries 是被复用的几何。这种”实例 vs 几何”的分离让大型模型可以高效渲染。
9. Mapped Items(实例化复用)
IFC 用 IfcMappedItem 表达”同一份几何被多次放置”:
IfcMappedItem
MappingSource : IfcRepresentationMap (引用了一个 IfcShapeRepresentation)
MappingTarget : IfcCartesianTransformationOperator
例如一栋楼的 1000 扇相同窗只需要 1 个 IfcRepresentationMap,每个窗用 1 个 IfcMappedItem 引用 + 自己的局部变换。Xbim 会自动识别这种共享,几何引擎只做 1 次三角化。
10. 颜色与表面样式
虽然不属于”几何”,但渲染必备:
IfcStyledItem
Item : IfcRepresentationItem
Styles : IfcPresentationStyle
IfcSurfaceStyle 含表面颜色、镜面、透明度等。Xbim3DModelContext 在打包时会把样式与几何关联到同一个 XbimGeometryStyle,方便渲染端按样式分桶。
11. 实战:导出某构件的 OBJ 网格
using Xbim.Common.Geometry;
void ExportObj(IfcStore model, string outPath)
{
var ctx = new Xbim3DModelContext(model);
ctx.CreateContext();
using var sw = new StreamWriter(outPath);
int vbase = 0;
using var r = model.GeometryStore.BeginRead();
foreach (var inst in r.ShapeInstances)
{
var geom = r.ShapeGeometry(inst.ShapeGeometryLabel);
var data = geom.ShapeData;
var ms = new MemoryStream(data);
var tri = ms.ReadShapeTriangulation();
tri.Transform(inst.Transformation);
foreach (var v in tri.Vertices)
sw.WriteLine($"v {v.X} {v.Y} {v.Z}");
foreach (var face in tri.Faces)
foreach (var t in face.Indices.Chunk(3))
sw.WriteLine($"f {t[0]+1+vbase} {t[1]+1+vbase} {t[2]+1+vbase}");
vbase += tri.Vertices.Count;
}
}
(ReadShapeTriangulation / Transform 等 API 名因版本略有差异,请参考 Xbim.Common.Geometry.XbimShapeTriangulation。)
12. 性能与诊断
- CreateContext 是耗时大头:100MB 的 IFC 通常需要数分钟甚至几十分钟。
- 缓存 wexbim:第一次转换写入
.xbim,之后只读取已转好的几何。 - 诊断报告:
Xbim3DModelContext内部记录BooleanFailures、ShapeConstructionFailures,可通过model.Tag上的统计或日志查看。 - 并行度:默认按 CPU 核数,可通过
Environment.ProcessorCount控制;I/O 密集时建议适当下调。
13. 几何引擎的”修复”功能
针对脏 IFC,Xbim 内置:
- 容差自适应:先用
Precision,失败后逐步放大; - 面修复:调用 OCCT
ShapeFix_Shape、ShapeUpgrade_UnifySameDomain; - 边/顶点缝合:
BRepBuilderAPI_Sewing; - 退化检测:跳过零体积/零面积的 representation;
- 异常隔离:单个产品几何失败不会中断整个
CreateContext。
14. 小结
- IFC 几何由参数化、布尔、Brep、网格四种风格组成;
- Xbim.Geometry 把它们映射到 OCCT 的
BRepBuilderAPI、BRepPrimAPI、BRepAlgoAPI、BRepMesh等 API; - 应用层一般通过
Xbim3DModelContext一键完成批量转换并落入 wexbim 流; - 大模型的几何转换成本高,应该缓存结果;
- 布尔失败、容差不当是常见故障源,必须依赖日志诊断。
下一章我们直接利用这些结果做可视化。