OpenCASCADE Poly HLR Edge
Abstract. HLRBRep_PolyAlgo is based on the principle of comparing each edge of the shape to be visualized with each of the triangles of the shape, and caculating the visible and the hidden parts of each edge. For a given projection, HLRBRep_PolyAlgo calculates a set of lines characteristic of the shape being represented, include outlines. The line stored in HLRAlgo_PolyShellData member variable mySegList. Each line have a type flag and end points data. The paper focus on the line data.
Key Words. Poly HLR, Edge, Outline, Hidden Line
1 Introduction
OpenCASCADE的HLR算法提供两种方式,一种是数值精确算法,一种是基于显示数据离散算法。精确算法使用数值解析算法计算精确结果,如返回的边是精确几何,若投影是圆得到的也是几何圆,但速度较慢;离散算法基于显示数据,逻辑简单,速度较快,但是结果为多段线。这里将Poly译为离散算法。
离散算法逻辑简单,依赖的文件少,为了深入理解其实现原理,将离散算法的源文件单独摘出,通过修改相关类,输出一些中间结果,更直观地理解算法底层逻辑。从而能知道其能力边界,能修复相关BUG,以及对Poly HLR进行改进,甚至有能力根据实际需求完全重写。
HLR算法是根据三维模型生成工程图纸的关键算法,OCC中HLR算法实现原理用一句话来说,就是在指定投影方向上,判断每条边与每个面的遮挡关系。我们抓住HLR中的两个关键数据边和面,看看边和面的数据从哪里来,到哪里去来解析HLR算法。本文主要关注离散算法中线的分类和来源。
2 Poly Edge Type
离散HLR算法的边和面的数据保存在HLRAlgo_PolyShellData类中,其中边的数据为成员变量mySegList,即边的容器,每条边由类HLRAlgo_BiPoint表示,即两个点表示的线段。
其中myIndices保存一些索引值,如边对应的模型索引,相连面的索引等,还保存了边的类型值SegFlags。myPoints为线段的两个坐标值。其中将边的类型分成五类:
lEMskRg1Line:普通边;
lEMskRgnLine:相邻两个面连续性为G2的边;
lEMskOutLine:轮廓线;
lEMskIntLine:相交线;
lEMskHidden:被遮挡隐藏的边;
HLR算法代码写得不太规范,有很多不知道含义的缩写。理解这些缩写,对HLR结果的理解也有帮助。在类HLRAlgo_PolyShellData中增加函数,输出这些边的BREP数据方便在DRAW中显示出来:
在类HLRBRep_PolyAlgo的StoreShell()函数中输出一些中间过程数据,可以查看每种类型的边的数据来源。先用简单的圆柱体来测试验证。
3 Edge Line
在类HLRBRep_PolyAlgo的StoreShell()函数中如下代码:
对每个Shell中的Edge找其父Face,与边相关的面通过EF边面映射表返回LS,传入函数InitBiPointsWithConnexity()中,这个字面意思是通过边的连接状态初始化BiPoints边。先看边没有面的情况,即边为单独的边不属于任意一个面的情况:
首先从边中取出离散的多段线Polygon3D(),多段线中相邻的两个点都会生成一个HLRAlgo_BiPoint,会保存线段变换后的端点值,和所属边的索引,这种边的类型设置成0。当是两个面共享的边时,会计算边的连续性:
这时生成的HLRAlgo_BiPoint的标志会根据连续性来设置,若为C0连续即为Sharp Edges;若为G1连续即为Smooth Edge;若为C2连续,即为Sewn Edge。经过这个逻辑得到的边的状态是Rg1Line和RgNLine。
在函数InsertOnOutLine()之前将边的数据输出来验证。不考虑边的状态,调用新增加的函数DumpEdges()输出所有的边:
Rg1Line和RgNLine:
4 Outline & Intersection Line
如果只有BREP中的Edge边做消隐还不够,还需要加上轮廓边OutLine。在函数HLRBRep_PolyAlgo::UpdateOutLines()和UpdateEdgesBiPoints()中根据每个线段和相连三角形的状态,更新边的是否为轮廓边状态。
若是轮廓边则增加相应的数据:
这里的标志直接使用数字12,实际上是EMskOutLine | EMskIntLine得来的。即轮廓边同时也是Int相交边。在UpdateEdgesBiPoints()函数之后,输出所有边的数据:
仅输出轮廓边OutLine:
5 Hidden Line
在函数UpdateEdgesBiPoints()中同时也根据每段线相连的两个三角的状态,判断是否为轮廓线OutLine或被完全遮挡的线Hidden Line:
如线段相连的两个三角形面的状态都是后向面,则这个线段设置为隐藏状态Hidden。这个隐藏是整个线段都是隐藏状态,还有线段部分隐藏状态这里没有处理。输出隐藏状态的线段:
6 Conclusion
离散消隐算法相对精确消隐算法要简单,从消隐边出发,找出其实现原理。离散边的数据来源为Edge中的离散数据Polygon,每个离散多段线中两个点构成一个消隐边。将消隐边分成几种类型,如Rg1Line&RgNLine,轮廓线OutLine、相交线IntLine、及被完全隐藏的线Hidden。轮廓线的计算是一个关键,标记成完全隐藏的线可以减少后面的计算量。通过边的分类及来源,可以大概归纳出离散消隐算法的主要逻辑:
1 从Edge中取出离散多段线,将多段线中每两个点生成的消隐边;
2 建立消隐边与三角形之间有关系;
3 根据投影方向设置三角形状态,如是否为后向面;
4 根据消隐边相连三角形状态生成轮廓边和完全被隐藏的边;
5 将普通消隐边和轮廓边与三角形求交,处理消隐边被部分隐藏的情况;