视频号文稿,详细内容请访问同名视频号。

大家好!今天咱们要聊的话题,BIM软件需要怎样的几何内核?
工业软件掐脖子这个话题这几年很火,几何内核就是其中关键技术之一。几何内核?大家马上想到Parasolid、ACIS、OpenCASCADE,他们都比较通用,但是内容太多了,很多和BIM无关。
对于BIM软件,大家一直在争论它需要什么样的几何能力,但我认为答案其实一直是客观存在的,直接找标杆软件即可。
下面的内容非常技术化,我们来从Revit API的几何类库来看看BIM软件需要具备什么样的几何内核。今天只是从几何角度让有个直观的概念,复杂的几何操作先不涉及,如果想要深入讨论细节,这个视频就不够了,可以在评论区留言。
在开始进入技术细节之前,我用通俗的话来解释一下几何内核到底干了什么事情。几何,从逻辑上来讲,就是点、线、面、体,以及他们之间的关系,或者说对他们进行操作。三维空间中的任意物体都可以用点线面体来表达,三维设计软件的所有操作不过是把它从一种状态变到另外一种状态。操作前后的状态都是确定的,可以用点线面体来表示。所以,理论上,任何复杂的几何变换,只要是能被描述出来的,算法就应该可以解决。
接下来,我们就根据这张表,一起拆解BIM世界里的“点线面体”,看看它们在API里是怎么被定义、怎么被操作的。
首先,咱们得搞清楚Revit API的几何体系是怎么搭起来的。就像盖房子先有地基一样,所有几何对象都有一个共同的“老祖宗”——基类GeometryObject。这个基类看上去平平无奇,但实际上可不简单,它定义了所有几何图形的通用能力:比如判断两个几何图形是不是一样、设置显示样式、控制可见性,还有判断这个几何图形是不是直接属于某个BIM构件。很多时候,魔鬼都藏在细节,想一下“判断这个几何图形是不是直接属于某个BIM构件”,这个设计意味着什么?几何元素可以快速找到它对应的构件。那么,相比商业或者开源内核,它是特有的,针对BIM场景的,它更加好用,方便代码的编写,提升研发效率,最终会反应到软件产品的质量和性能上。当然,难点是怎么实现这个接口下面的一整套逻辑,把几何和构件关联起来,如果你做得不好,可能就是累赘了。
在这个基类之下,就分化出了我们最熟悉的“点线面体”四大核心成员,还有两个“集合管家”:
•点:对应Point类,是整个几何世界的最小单元;
•线:不只有简单的Line,还有Arc(圆弧)、Ellipse(椭圆)、CylindricalHelix(螺旋线)这些复杂类型,统一归在Curve大类下,还有Edge(边)、PolyLine(多段线);
•面:包括Face(面)和Mesh(网格面),Face又细分出平面、圆柱面、圆锥面等多种类型;
•体:就是Solid(实体),是三维实体BIM构件的最终形态;
集合类:GeometryElement和GeometryInstance,专门用来管理多个几何图形的集合,比如一个构件可能包含多个面和多个体,就靠它们来组织。为什么要设计这两个集合类?他们的好处是什么?推导过程这里就不解释了,答案是他们是针对构件图元,或者说是对Element进行了针对性的设计,最终会反应到软件产品的质量和性能的提升上。
简单说,这个体系就像“原子-分子-物质”的结构,点构成线,线构成面,面构成体,最终组装成我们看到的BIM模型。这里再说一句,这个几何体系是按照BRep来设计的,其他软件厂商大多也是按照BRep实现的,但会有微小的差异。就像德国哲学家莱布尼茨说的:“世界上没有两片完全相同的树叶”。但他们都是叶子,引申出来,每个软件的BRep都是BRep,没有标准答案。
聊完框架,咱们从最基础的“点”开始。Revit API里的Point类,看起来简单,但核心全靠一个“万能工具”——XYZ结构体。为什么说它万能?因为它既可以表示三维空间中的一个点(比如构件的角点坐标),也可以表示一个向量(比如构件的朝向、移动的方向)。可以把它看成几何世界里的“基本粒子”。
创建一个点很简单,只要调用Point.Create方法,传入一个XYZ坐标就行。而XYZ自带了一系列实用操作,咱们挑几个BIM工作中常用的说说:
•计算距离:用DistanceTo方法计算两个点之间的直线距离;
•向量运算:想知道两个构件的方向夹角?用AngleTo方法;想计算方向?靠叉乘(CrossProduct)和点乘(DotProduct);
•其他基础操作:加减乘除能实现点的移动、缩放,Normalize方法能把向量标准化,方便统一计算方向。
还有几个现成的常量特别好用,XYZ.Zero是原点,BasisX、BasisY、BasisZ分别对应X、Y、Z三个坐标轴方向,比如想让构件沿着X轴移动,直接用BasisX当方向向量就行,不用自己手动输入坐标。
有了点,接下来就是连接点的“线”。Revit API里的Curve家族特别庞大,除了直线(Line),还有圆弧(Arc)、螺旋线(CylindricalHelix)、Nurbs曲线这些复杂类型,几乎能满足所有BIM建模的线型需求。
每种线都有专门的创建方法,比如创建圆弧,既可以用“三点确定一个圆”的方式,也可以指定平面、半径和起止角度,非常灵活。而不管哪种线,都有一些通用的核心能力,咱们结合实际应用场景说说:
•长度相关:Length能拿到精确长度,ApproximateLength是粗略长度,可以根据需求使用,比如计算管线的长度来算工程量;
•端点操作:GetEndPoint能获取线的起点和终点,GetEndParameter能拿到端点的参数,方便调整线的位置;
•实用操作:CreateOffset能实现线的偏移,比如绘制墙的时候偏移轴线;CreateReversed能反转线的方向,Project能把一个点投影到线上,比如判断某个设备是否在线路上方。
线与线之间的关系也很重要,ComputeClosestPoints能找到两条线的最近点,避免管线碰撞;Intersect方法能计算两条线的交点,比如确定构件的连接位置。
上面这些操作,总结下来,可以认为是线和点,以及线和线的关系。
另外,不同类型的线也会有各自的特点,这里就不展开说明了,大家可以带着问题自己去翻翻Revit API文档。大家可以思考一下,比如,为什么圆弧的接口要这样设计?和商用内核或者开源内核为什么有差异?这些差异的优劣是什么?
线再进一步,就能构成“面”。Revit API里的Face,其实是由“Surface”(曲面)和一圈闭合的Edge(边)组成的。比如墙的表面是平面(PlanarFace),柱子的侧面是圆柱面(CylindricalFace),每种面都对应一种专门的Surface类型。
面的核心操作,总结起来就是面和点、面和线,以及面和面:
•面和点:IsInside能判断一个点是否在面内,Project能把三维点投影到面上,比如判断设备是否在楼板范围内;
•面和线:Intersect方法能计算线与面的交点,比如确定管线穿透墙体的位置;
•面和面:两个面之间也能通过Intersect求交,比如计算两个构件的交线,方便调整构件位置。
篇幅所限,这里就不展开说明了,大家仍然可以带着问题自己去翻翻Revit API文档。思考一下,为什么圆柱面的接口要这样设计?和商用内核或者开源内核为什么有差异?这些差异的优劣是什么?
最后,面组合起来就形成了BIM模型的核心——“体”(Solid)。一个Solid是由多个Face和Edge构成的三维实体,比如柱子、楼板、梁,本质上都是Solid对象。
创建Solid有两种主要方式,一种是用BRepBuilder手动搭建,另一种是用GeometryCreationUtilities类提供的现成方法,后者更常用,咱们挑几个重点说说:
•拉伸(Extrusion):把一个闭合的轮廓线沿着某个方向拉伸,比如把矩形轮廓拉伸成墙体;
•扫略(Swept):让闭合轮廓线沿着一条路径移动,形成实体,比如让圆形轮廓沿着曲线移动,形成弯管;
•放样(Loft):在多个闭合截面之间创建平滑的实体,比如创建异形的屋顶;
•旋转(Revolved):让轮廓线绕着某个轴旋转,形成实体,比如创建圆环。
Solid的属性也很实用,Volume能拿到体积,SurfaceArea是表面积,直接用来算工程量再方便不过。而体与体之间的“布尔运算”,Union(并集)能把两个实体合并,Difference(差集)能从一个实体中减去另一个,Intersect(交集)能拿到两个实体的重叠部分。比如创建异形构件时,先做一个基本实体,再用差集减去多余部分,就能得到想要的形状。
Solid还有一系列其它操作,大家可以参考对应的接口。总结下来,还是可以按照体与点、体与面、体与体的关系,用这个框架去理解体的逻辑。
回到开头的问题,BIM软件需要怎样的几何内核?Revit API给的接口本身就是一个完整的设计,基本上已经给出BIM软件几何内核的基本要求。难点在于它为什么要这么设计?肯定是基于Revit的历史和现实处境才这么做的。那么,如果你要写个BIM软件的几何内核,你该怎么做?参考多少?参考哪个部分?这个就需要大家自己在实践中去寻找答案了。
本期视频的内容,主要来自我的Revit API几何专题博客,想要深入学习代码细节的朋友,可以去CSDN搜索“Revit API 几何专题”。
感谢大家的观看,咱们下回见!
夜雨聆风