☰
OpenCASCADE中TopoDS_Edge设计详解:从共享TShape到pcurve避坑指南
2026/10/9 8:09:55 网站建设 项目流程

拿到这条建模数据的时候,我先在OCC里遍历了一遍整个形状的边。结果发现一个很诡异的情况:两条几何上完全重合的边,用==比较却返回false,布尔运算的缝合结果里也出现了本应合并却没合并的裂缝。排查到后面,问题全部指向同一个源头——我没有真正理解TopoDS_Edge的设计。这个类在OpenCASCADE里地位极其特殊,它表面上是个轻量值类型,拷贝、传参都不起眼,但背后挂着一整套拓扑共享、几何引用和方向管理的机制。不了解这套设计,哪怕只是写段遍历边的代码,都可能踩出莫名其妙的bug。

这篇笔记我不会去复述官方文档里那套继承关系图,而是直接从TopoDS_Edge的实际内部构成讲起——为什么它数据量小却能代表一整条边,为什么同样的边在不同面里会有不同朝向,3D曲线和pcurve到底谁说了算,以及我踩过的那些坑是怎么一步步定位到根因的。想搞明白布尔运算、缝合、网格化里各种边相关的玄学问题,这篇应该能帮你省下不少排查时间。

1. 一条边在整个B-Rep体系里到底扮演什么角色

1.1 TopoDS_Edge在拓扑层级中的位置

OpenCASCADE的模型表示核心是边界表示法,也就是B-Rep。一个实体模型先被拆成若干拓扑层级:体积由壳构成,壳由面构成,面由线框围成,线框由边按顺序连接,边的端点是顶点。这个层级里每个元素都有对应的TopoDS类型,而TopoDS_Edge处于一个承上启下的位置——它是构成Wire的最小“线段单元”,同时又是Face的边界约束。

我刚接触OCC时容易搞混一件事:拓扑层级里的“边”和几何里的“曲线”是两个概念。一条边可以对应一条带参数区间的3D曲线,但它本身不等于那条曲线。边的本质是“对一段参数化曲线的拓扑引用”,它额外携带了该曲线在具体模型里的方向、位置以及所属面的信息。换句话说,同样的几何圆弧,在不同位置、不同朝向出现时,它们在几何上是同一条曲线,在拓扑上可能是两条完全不同的边。

这个区分在第三方格式交换时尤为重要。从STEP、IGES文件读进来的模型,经常出现两条几何上重合、拓扑上却是独立TShape的边。修复模型时,第一件事就是识别并合并这类重复边,而这依赖的正是对TopoDS_Edge内部共享机制的理解。

1.2 边、曲线、几何曲线的概念分野

我们口头常说“在OCC里画一条直线边”,实际上造出来的东西包含三层信息。第一层是几何曲线本身,也就是Geom_Line、Geom_Circle、Geom_BSplineCurve这些对象。第二层是曲线的参数区间,比如一条直线只取了[0, 10]这一段。第三层才是TopoDS_Edge,它把“哪条曲线”“取哪段参数”“在模型中的朝向和位置”打包成一个可参与拓扑运算的单元。

这里有个容易忽视的细节:TopoDS_Edge作为拓扑对象,记录的不只是几何信息。它还通过TopLoc_Location记录了一条边位于模型的什么位置,通过TopAbs_Orientation记录了这条边在某个父级结构里是正向还是反向使用。位置和朝向都属于拓扑层的修饰信息,它们不修改下方TShape的原始几何数据。

用生活类比来解释:TShape相当于某本书的原稿,TopoDS_Edge相当于你手里复印的一页。复印页上批注了“这一段要正着读还是倒着读”“放在哪一页的哪个位置”等信息,但原稿内容一个字都没动。

1.3 为什么先理解“边”再理解“面”

很多初学者直接从Face入手学布尔运算,结果一遇到缝合失败、网格裂缝就懵。原因在于,面的大部分边界行为和精度问题,本质上是边的问题。一个Face有没有封闭外环,取决于Wire里的边首尾是否相连;两个Face能不能缝合,取决于共享边的几何容差和参数区间是否匹配;曲线在面上的UV映射正不正确,取决于边是否携带了正确的pcurve。

我在实际项目中总结出一个经验:凡是模型出了问题,先用TopExp_Explorer把模型里的边全部遍历一遍,看边的数量、类型、起始点、闭合性,通常比直接排查Face更有效。边的异常往往是面出现裂缝、结果错误的先兆。

2. 轻量引用与共享TShape:为何TopoDS_Edge数据量小却能描述整条边

2.1 TopoDS_Edge的三个字段

TopoDS_Edge继承自TopoDS_Shape,而TopoDS_Shape内部实际只有三个字段:

  • 一个指向TopoDS_TShape的智能指针,负责真正持有拓扑数据
  • 一个TopLoc_Location,记录位置变换
  • 一个TopAbs_Orientation,记录朝向

其中TopoDS_TShape是引用计数管理的底层对象,具体到边就是BRep_TEdge实例。这意味着你代码里到处传递的TopoDS_Edge,其实只携带了一个指针、一个位置对象和一个枚举值。拷贝一条边的开销极小,赋值、入容器、作为函数返回值都不会造成几何数据复制。

这类结构在计算机网络里有点像“快捷方式”或者“硬链接”:多个快捷方式可以指向同一个文件本体,每个快捷方式可以配置不同的打开方式,但文件本体只有一份。OCC大量使用这个模式,让布尔运算、网格化等重型操作能负担起海量拓扑对象的传递。

2.2 共享TShape带来的拓扑关系

共享机制的核心意义在于拓扑一致性。一个正方体有12条边,每条边都被两个相邻面共享。如果OCC为每个面都复制一份独立的边数据,那么两个面上的公共边就是两份独立对象,一旦模型发生改动,两边数据很容易产生漂移,面与面之间就会出现微小的缝隙。

同一个BRep_TEdge被多个TopoDS_Edge引用时,这些引用通过不同的TopAbs_Orientation值表达使用方式。例如两个相邻面的公共边,在一个面中是正向,在另一个面中是反向。判断两条边是否“共享同一份底层数据”,不需要比较几何坐标,直接用IsSame方法即可:

if (edge1.IsSame(edge2)) { // 两条边共享同一个TShape,属于“同一条拓扑边” }

这里的IsSame与==是两回事。IsSame只判断TShape指针是否相同,位置和朝向可以不同;==则要求TShape、位置、朝向全部相同。这个差异在实际开发中非常容易踩坑,我后面会专门讲。

2.3 位置与朝向分离的设计收益

把一个三维变换放进TopLoc_Location而不是塞进TShape内部,换来的是极高的复用性。假如模型里有1000个相同的螺栓孔特征,每个孔的边都是同一批TShape,只是Location不同。这样内存占用极小,而且在修改TShape时,所有引用一次性同步更新完成。

TopLoc_Location还支持变换叠加。它内部本质上维护一个三维变换矩阵外加一个缩放因子,可以通过Multiplied等方法把多个位置变换合成一个,减少建模操作过程中的矩阵级联次数。对边的遍历和比较来说,Location必须考虑在内,否则两个位置不同的边可能被错误判断为几何相同。

这里有个常见误解:很多人认为TopoDS_Edge自带顶点,其实顶点信息不在TShape字段里,而是通过边的几何端点推导出来的。边和顶点的拓扑关系,由TopExp工具类负责解析,而不是边内部直接保存顶点指针。这也是TopoDS_Edge能保持轻量的原因之一。

2.4 关于引用计数的细节

在C++环境里,TopoDS_TShape由Handle管理生命周期。大部分情况下你不需要手动释放,句柄析构时引用计数减到零,对象自动销毁。但在多线程环境中,多个线程同时读取同一个TopoDS_Edge没有问题,如果多个线程同时修改共享TShape,就需要外部加锁,因为引用计数的增减和内部数据修改不是原子操作。

PythonOCC环境下,由于Python对象与C++句柄直接绑定,你几乎感知不到引用计数过程,但底层机制完全相同。理解这点有助于解释为什么同一个TopoDS_Edge对象在PythonOCC里复制多份后,底层指向仍然相同。

3. 3D曲线、参数区间与pcurve:边里的几何信息是怎么组织的

3.1 BRep_TEdge内部实际存储了什么

TopoDS_Edge本身不直接保存几何数据,真正保存几何细节的是它指向的BRep_TEdge。打开这个类的内部结构,能看到它持有:

  • 一个Handle(Geom_Curve),即边对应的3D曲线
  • 两个参数值first和last,限定边在曲线上的使用范围
  • 一个容差值myTolerance,用于处理数值误差
  • 一个pcurve容器,内部保存多个CurveOnSurface结构,每个结构由一条Geom2d_Curve曲线加一个面的指针组成

也就是说,一条边可以同时携带多份几何表示。一份是3D空间中的曲线,用于描述边在三维空间里的真实形状;另外若干份是2D参数空间曲线(pcurve),供每个引用它的面使用。

这个设计很好理解:3D曲线描述的是“边本身长什么样”,pcurve描述的是“这条边在某个特定面的参数空间里长什么样”。同一个三维圆弧边,投影到圆柱面和投影到平面上的2D曲线可能是完全不同的形状。

3.2 3D曲线与参数区间

从边里取3D曲线的标准方式是BRep_Tool::Curve:

Standard_Real first, last; Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last); if (!curve.IsNull()) { // 正常使用 curve、first、last }

这个接口返回的不是“曲线的全部定义域”,而是该边实际使用的参数区间。以直线为例,创建直线边时内部可能生成一个参数定义域为(-∞, +∞)的Geom_Line,但边实际使用的是[0, distance]这一段。知道了first和last,才能正确沿边采样、计算切向量、求中点。

参数区间与物理长度之间的关系也需要熟悉。在Geom_Line上,参数间距就是长度;在Geom_Circle上,参数单位是弧度(不一定是从0开始);在Geom_BSplineCurve上,参数是样条节点向量里的值,与弧长没有直接关系。所以计算边长不要用参数区间直接相减,应该用几何属性工具。

3.3 为什么还需要pcurve

单纯有3D曲线,很多建模操作是无法进行的。布尔运算、网格化、蒙皮、倒角这些算法需要把边“贴合”到面上,而面有自己的参数空间UV映射。如果一条边属于某个面,那么在面的UV参数空间里,必须存在一条与该边对应的2D曲线,这条2D曲线就是pcurve。

pcurve的用途非常广泛。网格化时,算法在面的参数空间划分网格,边对应的2D约束曲线决定了网格的边界;在面上计算点的UV坐标时,需要把3D坐标投影回2D参数域,此时要先找到边附近的pcurve;同样,倒角操作要判断边在面上走多远,看的也是pcurve。没有pcurve的边,在几何上可以存在,但在拓扑运算里等同于“不贴面”。第三方格式导入的边若缺少pcurve,缝合或布尔运算极易失败。

Handle(Geom2d_Curve) pcurve; Standard_Real f2d, l2d; pcurve = BRep_Tool::CurveOnSurface(edge, face, f2d, l2d);

这个调用返回边在face参数空间里的2D曲线。如果返回为空,说明这条边没有关联该面的pcurve,那么边和面之间缺少拓扑绑定,后续做UF变换时可能出现问题。

3.4 多pcurve与Multi-edge

一条边在简单情况下只有一条3D曲线加一条pcurve;在复杂情况下,一条边会被多个面共享,每个面各有一条pcurve,这时就出现了“Multi-edge”。Multi-edge本身不是错误,而是B-Rep模型的常见形态,尤其在布尔运算生成的模型中十分常见。

Multi-edge的问题是调试复杂。你对着一条边想找它在某个面上的pcurve,必须指定具体是哪个面。如果不同面上pcurve的形态、参数区间不一致,沿边做操作时结果可能不同。所以做几何算法前,先确认当前流程是“按边查找”还是“按边+面查找”,并写清楚这两个参数。

还有一类特殊情况是退化边。退化边的3D曲线可能为空,或者长度为0,它在3D空间里退化成一点,但在某些面的参数空间里仍然是一条完整曲线。典型例子是球体极点附近,多条边汇聚到同一个空间点。处理这类边时,不要试图读取3D曲线来判断形状,应该优先检查BRep_Tool::Degenerated(edge),否则很容易引入NaN和除零错误。

4. 造边的三种典型路径:显式构造、扫描/旋转、布尔与交线

4.1 用BRepBuilderAPI_MakeEdge直接构造

最直观的造边方式是BRepBuilderAPI_MakeEdge。最常见的是两个点直接构造直线边:

gp_Pnt p1(0.0, 0.0, 0.0); gp_Pnt p2(10.0, 0.0, 0.0); BRepBuilderAPI_MakeEdge makeEdge(p1, p2); if (makeEdge.IsDone()) { TopoDS_Edge edge = makeEdge.Edge(); }

这段代码背后发生的事情是:OCC根据两个点创建一个Geom_Line,并把参数区间设置为0到两点的距离。两端自动生成两个顶点。

用两个点构造直线边时,不需要用户给参数区间,系统会自动计算;但如果你传入一条已有曲线和两个参数值,参数就由你自己控制。例如创建一段圆弧:

gp_Circ circle(gp_Ax2(gp_Pnt(0,0,0), gp::DZ()), 5.0); BRepBuilderAPI_MakeEdge makeEdge(circle, 0.0, M_PI / 2.0);

此时IsDone()可能返回失败,原因通常是参数范围越界、曲线退化,或者输入顶点投影失败。每次构造后都应该判断Status(),而不是直接用Edge(),否则拿到的可能是空对象。常见的状态枚举有EdgeDone、PointProjectionFailed、ParameterizationError等,具体可以查BRepBuilderAPI_EdgeError。

4.2 常见几何类型的构造技巧

  • 用两点造直线,是最简单也最常用的方式。
  • 用圆心、半径和两个角度造圆弧,注意角度单位是弧度,且方向遵循OCC的右手定则。
  • 用圆和两个点造弧,OCC会把点投影到圆上求参数,再决定正向还是反向连接。
  • 用椭圆、双曲线、抛物线、样条曲线造边,则需要确保传入的参数区间满足曲线自身的定义域要求。

构造边时还可以指定已有顶点:

BRepBuilderAPI_MakeEdge makeEdge(circle, v1, v2);

这种带顶点的版本会尝试把顶点投影到曲线上,投影结果决定边的参数端点。如果顶点不在曲线上,投影失败,构造就不成功。这个接口在设计时要谨慎使用,因为投影误差会影响边的容差和后续缝合效果。

4.3 算法产出边的特征差异

建模算法产生的边和手工造的边有一项根本差异:算法产出的边自带完整的pcurve和正确的共享关系,手工造的边没有。比如拉伸一个面:

BRepPrimAPI_MakePrism prism(face, gp_Vec(0, 0, 10));

得到的侧边都不需要你操心pcurve,OCC在拉伸过程中自动为每个生成的边补齐曲面关联。布尔运算、倒角、扫掠也是如此。因此我有个实践建议:能通过算法生成的边,就不要手工拼装;手工拼装边看似可控,实际是在给自己挖坑。

从交互建模软件中导出的STEP文件,边的数据质量受限于导出方的容差设置。有的模型里微小边特别多,长度小于千分之一毫米;有的模型边缺少pcurve。遇到这类数据,最稳的做法不是硬刚算法,而是先用修复工具统一处理容差,再执行布尔或缝合。

5. 天天都在用的边查询清单:从端点、朝向到容差

5.1 从Shape里找出所有边

遍历模型中的全部边,最常用的是TopExp_Explorer:

TopExp_Explorer explorer(shape, TopAbs_EDGE); for (; explorer.More(); explorer.Next()) { const TopoDS_Edge& edge = TopoDS::Edge(explorer.Current()); // 处理这条边 }

TopExp_Explorer会递归遍历复合体中所有层级的边,并且保证每条边在遍历中出现一次。这个遍历不区分边是否被多个面共享,因此如果你需要统计“唯一边”,应该用TopTools_IndexedMapOfShape配合TopExp::MapShapes来做:

TopTools_IndexedMapOfShape edgeMap; TopExp::MapShapes(shape, TopAbs_EDGE, edgeMap);

用Map方式遍历的好处是自动去重,相同的TShape(位置朝向也相同)只会保留一次。这在统计模型复杂度、检查冗余数据时非常有用。

5.2 边的端点、方向与共享关系

取边的两个端点要特别注意朝向问题。TopExp::FirstVertex(edge)与TopExp::LastVertex(edge)都有第二个布尔参数cumOrientation:

TopoDS_Vertex vf = TopExp::FirstVertex(edge, true); TopoDS_Vertex vl = TopExp::LastVertex(edge, true);

参数为true时,端点顺序跟随边的逻辑方向;为false时,直接按TShape本身的方向取端点。对于方向为REVERSED的边,两种方式取到的端点是反过来的。

很多人拿到一条REVERSED的边,不去检查Orientation(),直接用LastVertex当作终点,结果拿到的却是几何上的起点。这在布尔运算后遍历结果时特别容易发生,因为布尔结果的边方向取决于算法内部的体面关系,不会恰好都朝同一个方向。

判断一条边与另一条边是否共享同一底层拓扑,用IsSame:

bool sameTShape = edge1.IsSame(edge2);

而==还会考虑Location和Orientation是否一致。两条边几何形状几乎一样但位置不同,IsSame可能为true(如果它们确实共享TShape),==则相对严格得多。实际业务中,你更需要的是“这两条边是不是同一条拓扑边”这个判断,所以应该优先用IsSame。

5.3 几何查询三板斧

边查询有三个最常用的入口。

第一个是BRep_Tool::Curve(edge, first, last),获取3D曲线和参数区间,适合做几何采样、边长计算、曲线类型判断。

第二个是BRep_Tool::CurveOnSurface(edge, face, f2, l2),获取边在指定面上的2D曲线,适合做UV坐标计算、网格约束、面内偏移。

第三个是BRep_Tool::Tolerance(edge),获取边允许的数值误差范围。这个值在缝合、布尔运算中用来判断两个端点是否能合并到一起。

Standard_Real tolerance = BRep_Tool::Tolerance(edge);

容差值的理解很关键。OCC的容差不是一个“精确比较”的阈值,而是“允许误差”的范围。两个顶点之间的距离小于容差时,模型就把它们视为同一位置。容差不是一个全局统一值,每条边、每个顶点都有自己的容差,这解释了为什么有时候模型局部能缝合、局部却缝不上。

5.4 常用特征判断:闭合边、退化边、长度

判断闭合边直接用BRep_Tool::IsClosed(edge),它判断的是拓扑上的闭合,即两端点相同或者曲线是闭合曲线。

判断退化边用BRep_Tool::Degenerated(edge)。退化边在3D空间可能只是一个点,但在面的参数空间里仍可能对应一段曲线。网格化算法遇到退化边会特殊处理,你不能拿它当普通边做路径规划。

计算边长用几何属性API比较稳妥:

GProp_GProps props; BRepGProp::LinearProperties(edge, props); Standard_Real length = props.Mass();

这段代码会考虑真实曲线形状,而不是直接用两点间距离。对于直线和圆弧,两者差别不大;对于自由曲面上的样条边,差别可能非常大。如果算出来的边长明显异于预期,要考虑是否取错了边(例如拿到的是REVERSED方向不影响长度,但拿到的可能是Multi-edge中不同面的pcurve)。

6. 边在缝合、布尔和网格化中的关键表现

6.1 缝合时边怎么合并

缝合操作是处理离散面片、合并成连续模型的常用手段。BRepBuilderAPI_Sewing工作时,会搜索不同面上几何位置相近的边。合并的依据是顶点坐标差值是否在容差范围内,以及边的3D曲线是否在容差范围内重合。一旦匹配成功,系统会把两条边的TShape合并成一个共享TShape,并同时为合并后的边补齐多个面的pcurve。

缝合失败的常见表现是“结果里出现了两条几乎重合却不相连的边”。排查时不要直接怀疑缝合算法,先检查输入面的边界边的容差设置是否合理。两个相距0.01mm的顶点,如果容差只给了1e-7,缝合必然失败。适当放大容差通常能解决很多“自由边”问题,但容差过大又会导致不同几何边被错误合并。这个权衡没有标准答案,只能根据模型来源和精度要求去调。

6.2 布尔运算对边的硬性要求

布尔运算可以说是对边数据要求最苛刻的操作。两个形状求交集,系统需要在两个模型各自的面上求公共边,这要求每条边都在对应曲面上存在pcurve。如果输入模型存在自由边、缝隙、退化边,布尔运算经常会报错或产出畸形结果。

我在处理第三方格式模型时,会先用BRepCheck_Analyzer检查模型有效性,看返回值里是否有SelfIntersection之类的错误;再用BRepBuilderAPI_Sewing做一次修复,把微小的自由边合并掉。直接拿损坏模型跑布尔的后果,往往是后续步骤全乱,而且你没法定位是哪一步出了问题。

布尔运算结束后的结果里,边通常自带FROM的朝向信息,这些边经过算法重新生成,pcurve也是完整重算的。遍历结果边时,不要把“边的原始方向”当“边的几何方向”,要结合Orientation()和Location综合理解。尤其在做生成立面加工路径这类需求时,方向和位置必须同时参与判定。

6.3 网格化时边是约束线

BRepMesh_IncrementalMesh对模型做网格划分时,边和顶点是约束条件。网格划分算法的输入是面,但面内部的三角形划分不能越过边约束去采样,否则模型轮廓会变形。

网格化之前有必要确认边是否具有正确的pcurve,因为很多网格算法是在面的参数空间里做二维网格生成,然后反算回3D坐标。如果边缺少pcurve,面在边界的采样可能会失真,出现“三角形跨越边界”或“边界锯齿”等现象。

好消息是,网格化算法本身会使用边的容差做边界融合,所以修好模型后,网格质量通常还行;但如果你想利用边的几何信息做局部加密,比如在曲率大的边附近加密网格,就必须从BRep_Tool::Curve里提取曲线曲率,而不是只依赖网格算法默认的Deflection参数设置。

7. 我在真实项目里踩过的TopoDS_Edge的坑

7.1 用==比较边导致重复边判定失败

我第一次在OCC里做模型去重时,直接用了==比较两条边,结果发现两个几何完全相同的候选边被判为不相等。排查后发现,这两条边来自布尔运算的两侧结果,虽然几何形状一样,但Location包含的变换矩阵和Orientation不同。==会综合判断这三个因素,所以它们自然不等。

从那以后,我把“判断两条边是不是同一条边”这件事总结为两个方向:判断拓扑是否共享用IsSame,判断几何是否等价则要额外比较3D曲线的类型、参数区间和端点坐标,单纯用==在大多数业务场景里都不合适。

7.2 拿错REVERSED边的端点,导致加工路径错乱

有一次处理自动编程路径的库,需要遍历一个扫描体的所有边,按顺序生成刀具路径。代码里直接用了TopExp::FirstVertex(edge),没传cumOrientation=true。结果20条边里有一半的路径是反的,刀具轨迹直接画出了锯齿状。排查时比对边的Orientation()才发现,扫描体侧面的边几乎全是REVERSED,因为它们在相邻面上的使用方向与TShape的原始方向相反。

这个坑在涉及方向敏感算法时几乎必踩。每次拿端点、沿边采样、计算切向量之前,先问一句:“我现在是要逻辑方向还是原始方向?”然后用cumOrientation显式指定,不要靠默认参数碰运气。

7.3 拿到NULL的3D曲线,崩溃在没判断空指针

在很多版本中,退化边或一些从文件里读入的特殊边,BRep_Tool::Curve可能返回空句柄。我见过不少同事在代码里直接对返回值调用方法,然后花一下午调崩溃。实际上的标准做法是先判断IsNull(),再决定是跳过还是走退化边分支。排查退化边时,直接把BRep_Tool::Degenerated(edge)的结果打印出来,辅助判断比单纯看曲线快得多。

7.4 手工造边不贴面,缝合怎么都失败

早期做曲面裁剪功能时,我手工构造了一条“看起来正好沿着曲面边界”的边,然后直接拼接出来一个新面。缝合时新面和原模型之间始终留缝,怎么调容差都合不上。最终发现,手工边的几何虽然贴着面边界,但它和面之间没有pcurve,缝合算法认为它和原模型的边没有曲面关联,因此不认为它们属于同一个逻辑边界。

根本原因是:边的几何正确不代表拓扑正确。要让一条边真正属于一个面,必须在面的参数空间里有一条对应的2D曲线。算法生成的边能自动建立这个关联,手工构造的边则不会。补救方式是用BRepLib里贴合边与面的工具把2D曲线补齐,但更稳妥的做法是改造流程,让边由算法派生。

7.5 批量处理时的拷贝与内存问题

大量边的批量处理场景里,TopoDS_Edge的拷贝开销虽然不大,但架不住数量大。在一个百万条边的网格重划分流程里,如果不断用值传递把边塞进容器,内存占用和拷贝开销都会非常明显。更好的做法是用const TopoDS_Edge&传参,容器里存TopTools_IndexedMapOfShape或者索引,而不是存一堆重复的边对象。

同样,批量遍历时不要在一个循环里反复调用BRep_Tool::Curve获取曲线然后马上丢弃。最好先按类型把边分组,再对同一类型的边批量提取几何数据,缓存复用。性能调优做到这一步,通常能省下大量处理时间。


从排查那条重合边的==问题开始,我把TopoDS_Edge从外到里翻了一遍。现在再回到最初的场景,答案很清晰:两条几何重合的边之所以不相等,是因为它们不共享TShape、位置或朝向不同;缝合时产生裂缝,是因为边的pcurve或容差设置没满足拓扑要求。理清轻量引用、共享TShape、3D曲线与pcurve的关系之后,OCC里大部分边相关的疑难杂症,都能顺着“边的拓扑身份、几何数据、朝向位置”这三条线快速定位。希望这篇笔记能帮你少走我走过的弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询