24. Revit API: 几何对象(五)- (Sur)Face
一、前言
虽然Face
是GeometryObject的子类,Surface
不是,但这两者之间还是挺有关联的,每个Face都有一个对应的Surface,类似于Edge
和Curve
的关系。
Surface
是数学意义上的面,纯定义。
Face
是几何形状(实体)上的面,是Surface
上截取了一块区域,有边界。
所以,Revit种面、线、点之类的关系的计算,都是在Face上,而Surface主要是对“抽象”面的定义。
二、Face
Face
及其子类都没有构造函数,只能通过Solid获取。类方法,就是常规的相交、投影、计算面上点的法向、切向等方法。
2.1. 方法
// UV
public BoundingBoxUV GetBoundingBox(); // 面UV包围盒
// 点坐标、法向、切向
public Transform ComputeDerivatives(UV point); // 一阶导。可得点坐标、法向、切向
public XYZ ComputeNormal(UV point); // 计算法向,上面方法的简化版
public XYZ Evaluate(UV params); // 计算点坐标
public FaceSecondDerivatives ComputeSecondDerivatives(UV point); // 二阶导
// 获取边、面
public IList<CurveLoop> GetEdgesAsCurveLoops();
public Surface GetSurface();
// 点、面、线关系
public IntersectionResult Project(XYZ point); // 点在面上的投影
public FaceIntersectionFaceResult Intersect(Face face); // 面-面相交
public SetComparisonResult Intersect(Curve curve); // 面-线相交
public bool IsInside(UV point); // 指定UV是否在面上
// 三角细分
public Mesh Triangulate(double levelOfDetail)
UV
咋解释呢,模型贴图知道吧,把图片映射到模型上。怎么让图片贴准呢,建模软件里有个叫“展UV”的功能。
讲不来讲不来,看【Wiki】。
下图是方正的、填满了UV的,还有那种没填满的,有的区域是无映射的。
下面模型/贴图来自【sketchfab.com】
2.2. 属性
属性如下:
OrientationMatchesSurfaceOrientation
:表示面朝向与其Surface
的是否为同向,用到Surface时需要依此判断。(Has/Get)Region
:这个“Region”没有接触过,具体是个什么东西还不知道。查了好一会儿,才在【这篇】中找到一点信息,但测试发现,这只是在平面图中创建填充(FilledRegion
)的方法,与面没有关系😑。
三、Surface
Revit中,有这些面:
面 | Face | Surface |
---|---|---|
平面 | PlanarFace | Plane |
圆柱面 | CylindricalFace | CylindricalSurface |
圆锥面 | ConicalFace | ConicalSurface |
旋转面 | RevolvedFace | RevolvedSurface |
直纹(曲)面 | RuledFace | RuledSurface |
埃尔米特曲面 | HermiteFace | HermiteSurface |
Nurbs | 简化为其它类型的面 | NurbsSurface(Data) |
前面6种面都是从某个类派生的,最后的 NurbsSurface 则是例外,它只有NurbsSurfaceData
这个数据类,且只在BRepBuilderSurfaceGeometry
中使用,最后创建出的面,也会被简化,由其它类型表示。
Face没有构造函数,Surface的属性也会出现在其对应的Face中,就直接看Surface。
在Revit几何对象中,都有使用Frame
,用以确定局部坐标系,在18. Revit API: 元素位置与变换这篇写过。
3.1. 平面(Plane)
平面有属性:面原点、面法向、X轴向、Y轴向。
构造方法:
- 由Frame创建
- 由面法向,和面上原点创建
- 由原点,和X、Y轴创建,法向为
Vector3.Corss(dir_x,dir_y)
; - 由面上三点创建,面方向按点顺序和右手螺旋确定,原点为第一个点。
warning
:三点创建时,X轴的方向是怎么确定的?
尝试了几种方式,算到的和读取的都不一样,不清楚Revit三点创建平面时,XY轴的确定方式。
3.2. 圆柱面(CylindricalSurface)
定义: S(u, v) = center + radius*cos(u)*xVec + radius*sin(u)*yVec + v*zVec
圆柱面比较简单,属性:圆半径、坐标系原点、中心轴、X轴向、Y轴向
后四个组合就算一个Frame。
构造方法:
- 由 Frame + 半径 创建。
3.3. 圆锥面(ConicalSurface)
定义:S(u, v) = center + v*[sin(halfAngle)(cos(u)*xVec + sin(u)*yVec) + cos(halfAngle)*zVec]
圆锥面属性:半角(弧度制)、顶点、中心轴、X轴、Y轴
构造方法:
- 由 Frame + 半角 创建
3.4. 旋转面(RevolvedSurface)
吐槽:就一个旋转方程,现在的我已经看不懂了,现在我只是个API调用仔。
旋转面的属性:原点、轴、X、Y,方法中获取旋转轮廓。
构造方法
- 从Frame(或类似表示方位的东西)创建
- 可以设置旋转的起始和终点角度
Info
:①构造方法返回的是Surface
类型,可能简化为其它类型的面;②可以设置起始角度,即不转满1圈。但属性中没有没有角度信息。
- 返回类型很好理解,比如:当轮廓为直线且与旋转轴平行时,就算创建一个圆柱面。
- 起始角度计算:
// 1. 从Surface本身无法获得,如下:
Curve curve = Line.CreateBound(new XYZ(10, 0, 0), new XYZ(9, 0, 10));
Surface revolvedSurface = RevolvedSurface.Create(new Frame(), curve, 0, Math.PI / 2); // 1/4 PI
Arc arc = Arc.Create(XYZ.Zero, 10, 0, Math.PI * 2, XYZ.BasisX, XYZ.BasisY); // 2 PI
IList<XYZ> points = arc.Tessellate();
string msg = string.Empty;
for (int i = 0; i < points.Count; i++)
{
revolvedSurface.Project(points[i], out UV uv, out double dis); // 期望有1/4的点投影距离为0,
msg += $"{i}\t {dis.Round(5)}\t {uv.Round(4)}\r\n";
}
TaskDialog.Show("project", msg);
// 实际所有的 dis 全部 0,表示投影计算时,是投影到“完整转一圈”的面上
// 2. 如果是从Face上获取的旋转面,可以计算出该面的旋转角度
Reference faceRef = this.Selection.PickObject(ObjectType.Face);
GeometryObject geoObj = this.Document.GetElement(faceRef).GetGeometryObjectFromReference(faceRef);
RevolvedFace revolvedFace = geoObj as RevolvedFace;
XYZ startDir = revolvedFace.get_Radius(0); // 这个获取起点轴方向 (Xvec)
// XYZ endDir = revolvedFace.get_Radius(1); // Yvec
UV startUV = new UV(startDir.X, startDir.Y);
//UV endUV = new UV(endDir.X, endDir.Y);
double startAngle = UV.BasisU.AngleTo(startUV).RadToDeg();
//double endAngle = UV.BasisU.AngleTo(endUV).RadToDeg();
BoundingBoxUV uvBounding = revolvedFace.GetBoundingBox();
double rangeAngle = (uvBounding.Max.U - uvBounding.Min.U).RadToDeg();
double endAngle = startAngle + rangeAngle;
TaskDialog.Show("Revolved", $"RevolvedFace info:\r\n" +
$"min:{uvBounding.Min}\r\n" +
$"max:{uvBounding.Max}\r\n" +
$"Xvec:{revolvedFace.get_Radius(0)}\r\n" +
$"Yvec:{revolvedFace.get_Radius(1)}\r\n" +
$"startAngle:{startAngle}\r\n" +
$"range:{rangeAngle}\r\n" +
$"endAngle:{endAngle}");
RevolvedFace
上的Radius
属性,表示的不是直径信息,而是(当前的)X轴向量和Y轴向量。
3.5. 直纹面(RuledSurface)
直纹(曲)面【Wiki】,没啥特殊的属性,创建结果可能简化为其它类型的面。
它有2类形式:① 两条Curve,② 点+Curve。
2个轨道,一根棍子搭在轨道上向前滚(按长度比例),滚过的区域就是直纹面。
结合Revit里的定义:S(u,v) = C1(u) + v⋅(C2(u)−C1(u))
3.6. NurbsSurface(Data)
Tips:NurbSpline叫非均匀有理样条线,参照这个问题链接。
Revit中并不支持NurbsSurface
(会被简化),而是提供了一个对应的数据类NurbsSurfaceData
。
NurbsSurfaceData:
① 该类只在
BRepBuilderSurfaceGeometry
中使用;② 在
ExportUtils
工具类中提供了一个由面获取近似NurbsSurface数据的方法,只支持HermiteFace
和RuledFace
。
我对这东西一知半解,就不多写了。
使用示例,请查看SDK下的示例“SDKSample/BRepBuilderExample/CreateNURBS.cs”,或者看【GitHub】,生成的模型长下面的样子。
四、总结
这篇,补充了几何对象中 Face、Surface 相关的内容,由于Face没有构造方法,主要写的是Surface。