3D特征识别

译文简介
原作者: Sergey Slyadnev,俄罗斯人,目前为自由职业者
2008年9月 - 2020年11月, OPEN CasCADE, Programmer, Project Manager, Project Director, 3D Modeling Architect
成文时间: 大约在2021年7月-2021年10月
原文链接: https://www.analysissitus.org/features/features_feature-recognition-framework.html
翻译说明: 文中圆括号内容为原作者注释或译者补充的注释。

以下为原文翻译


1. 缘由


规则特征或简单特征是对特定工程活动或应用有意义的CAD面模型或体模型的集合。由于零件的的三维建模成型过程与加工制造成型过程并不相同,所以多数情况下设计特征和加工特征是不同的。不管类型是什么,特征都是零件几何模型主要信息的载体。在CAD软件与CAM软件之间建立桥梁的一个关键问题是如何将建模特征与数控加工程序关联起来。我们推荐读者阅读论文[Wu et al, 1996],该论文对特征识别领域的研究有一个清晰的介绍。

尽管根据最终制造特征来设计CAD零件是可能的,但这种方法并未被广泛使用,并且通常被认为是坏主意[Vandenbrande and Requicha, 1993]。因此,即使设计特征在原始CAD系统中是已知的,但为了生成数控程序,设计特征仍需被转换为制造特征。且通常情况下,在CAD系统和CAM系统之间进行的是有损数据转换,“设计特征”并非已知。因此,特征识别就成为了计算机辅助设计领域的基础问题。

在许多工程实践中都对特征识别提出了很高的要求,例如:

  1. 可加工性分析:在将CAD零件发送至加工车间之前,首先需要确认该零件是可以被加工的。可加工性分析即评估在满足加工工艺要求的前提下,CAD零件上所有孔、型腔、槽、圆角和倒角特征的可达性。
  2. 直接编辑(直接建模):直接建模和基于历史建模是相对应的,不同于基于历史建模,直接建模(如拉伸、替换面等)不依赖于特征树。直接建模需要在操作的影响范围内识别特征,识别到局部特征后可以不改变设计意图而编辑零件的几何形状。
  3. CAD模型简化(删除特征):严格来说,简化(或删除特征)也是一种直接编辑类型。简化,通常是数值仿真或下游系统如游戏引擎的前处理步骤。为了简化特征(例如删除一个孔),首先需要在CAD模型上识别到特征。
  4. 制造成本估算:数字化制造(制造即服务)是一个成长中的行业。在一个CAD零件下订单之前通常需要评估预期生产成本。这些成本一般包括铣削、车削或3D打印工时,而这与零件的特征密切相关。因此,准确的加工时间估算需要特征识别。
  5. 排产:即使设计特征在原始CAD系统中是已知的(尽管通常也并非如此),自动化数控编程需要“制造特征”而非设计特征。

据我们所知,Analysis Situs是第一个、也是唯一一个开源的,旨在提供通用特征识别功能的CAD软件。

2. 为何朴素的方法不是最好的?


​​这里朴素的方法是指遍历CAD模型上的所有面,并将他们组合而成特征。当然,这种暴力扫描的方法并非完全不可取,如果实现得当,它是能够得到一个可行方案的。
遍历模型

同时,朴素的方法从根本上说是“盲目的”,因为我们没有采用任何方法来建立我们的特征识别算法。我们所做的仅仅是遍历CAD模型上的所有面、分析属性来推测他们是否“看起来像一个特征”。以下小节揭示了特征识别过程的主要复杂性。

如果你掌握编程(例如Python,当然我们更推荐C++)并对CAD基础知识有一定了解,那么从CAD模型中提取出所有普通圆柱孔是相对简单的事情。但如果你需要进一步从中区分出普通圆柱孔、圆锥沉头孔、圆柱埋头孔和台阶孔(Contourdrilled),事情就会变得更复杂些。
四种类型孔
如上图所示的各种基本孔型,如果将圆锥沉头孔型、圆柱埋头孔型再与孔的通、盲类型结合起来则可以得出更多形式的组合孔特征。因此,即便对像普通孔这样简单的特征,其可能的特征形式数量都是巨大的,更何况如下图所示彼此相交的孔:
两个相交孔
但有时候即使一些孔没有彼此相交,也难以轻易对他们进行分类,因为不同的孔可能对应不同序列的铣削加工操作,例如台阶镗铣:
黄色箭头所指复杂孔
因为这些相交特征、复杂特征的存在,简单扫描技术(朴素的方法)变得易错,除非算法进行了充分的拓扑和几何检查并对每种情况应用特定的识别策略。虽然在这些特定的识别策略上花费力气并非毫无意义,但是接下来要讲的启发式搜索方法可能会让事情变得不那么复杂。

用于特征识别的基本数据结构当然就是CAD模型本身的边界表达(B-Rep)。由于Analysis Situs是基于OpenCascade的,因此我们直接使用的是它的简约化B-Rep数据结构,它不支持用户定义属性、拓扑遍历也不方便(比如OCC缺少由子向父的拓扑反向引用、循环迭代器)。因此,高效的特征识别算法需要应用一些额外的数据结构,例如:

  1. 属性管理器:该数据结构目的是在特征识别算法识别过程中,存储所有的几何信息和与CAD特征相关联的其他信息(这些其他信息可称为“知识”)。
  2. 邻接图:图数据结构可以让我们关注边界元素(可能是特征)之间的拓扑关系、归一化模型之间的连通性,而不需要去过多关注模型的几何信息。
  3. 迭代器:对B-Rep元素进行高效的迭代遍历至关重要,例如查找给定边的所有父面——可由边得到相邻面。

特征识别引擎需要一个功能丰富的B-Rep建模工具,不仅是因为我们需要基于完整边界呈现一个零件模型,而且在特征识别过程中需要多次查询“几何相关信息”,(而B-Rep恰好具备这样的能力)。因此,我们必须充分利用建模引擎内核API来解决特征识别问题。

一个好的思路是任何几何算法的关键。如果缺乏一个好的思路,算法就有可能变成一个“大泥球”[Foote And Yoder, 1997]——一堆充满疑问不可维护的代码。

已经发表了很多科学论文和技术报告,旨在阐述一个被良好证明的特征识别方法。其中包括采用图论方法针对识别问题建立基于图的抽象化表达。本文灵感即将CAD零件的几何表达转换为纯粹的拓扑表达以方便计算。

3. 基于图的特征识别

3.1. 介绍


Analysis Situs 主要关注基于图的特征识别。本文所述的基于图特征识别方法中,采用一个叫做属性邻接图(Attributed Adjacency Graph, AAG)的补充数据结构来扩种B-Rep模型。关于使用图方法的优点可以参考我们的论文 [Slyadnev et al, 2020]

AAG的提出可以追溯到上世纪80年代。论文[Joshi and Change, 1988]描述了邻接图如何帮助识别布尔减特征,如槽、台阶等。
Joshi and Change, 1988
AAG收集CAD模型的面之间的邻接关系。AAG中的节点与CAD模型的面一一对应,它不关注两个面之间有多少公共边,而是关注他们的邻接性,相邻两个面对应的节点之间只有一条无向边。另外,AAG中也包括属性信息,特征识别所需的属性信息至少包括公共边的凹凸布尔属性——通过计算二面角获得。如下图所示为一个立方体的AAG,图中采用粉色顶点表示面、绿色边表示凸、红色边表示凹:
立方体的属性邻接图
反向立方体的属性邻接图

针对特征识别可以采用不同的技术路线,不一定必须使用AAG。一个更简单的技术方案即如前文所述的扫描方法,扫描方法可以在B-Rep元素之间同样使用邻接属性,且不必将其转换为图数据结构。迭代遍历所有B-Rep面,可以分析曲面的类型、曲面基本信息、面的方向等。该技术并不显式使用图方法,而是基于纯粹的代码实现(如仅使用C++语言逻辑)。在Analysis Situs中引入AAG的主要原因是它可以从几何中抽象出拓扑信息,并且将几何语言转化为图语言(即使用图论方法)。从图论角度来说,一个特征就是AAG的一个子图。

基于图的特征识别其思路是从AAG中找到作为子图的特征。这基本也就是Analysis Situs最初设计的目的:在OpenCascade内核之上添加特征识别逻辑。基于AAG可以实现以下图论相关的功能:

  1. 找到同胚子图;
  2. 相连拓扑分析;
  3. 基于图的拓扑特征虚拟移除且不影响实际模型(不移除几何数据)。

如下图所示为AAG的一个应用:钣金零件的识别。图中易知,我们可以通过移除零件上所有的厚度面,将图拆分为两部分,分别对应零件的上部分、下部分。
钣金零件厚度面识别
同理如下图所示,如果我们仅保留图中的厚度面,将得到一个对应的类似电路形状的子图。进一步地,我们可以在子图中判断是否每个节点都关联两条入边、以及是否相连边封闭成环,如果是,则可以断定:我们找到了一个厚度面链。
厚度面链
在Analysis Situs中,AAG中每个节点都有一个与拓扑面索引相对应的索引,索引从1开始(与OCCT中数据结构索引从1开始保持一致,不过最新版OCCT 7.8.0已部分改进为从0开始)。

3.2. 特征识别输出


如果我们设法从AAG中找到一个与特定特征对应的子图,那么需要将子图作为结果输出,如下图所示。一个特征本质上就是一个索引集合,这很容易序列化输出到任何存储空间,如文件。
特征识别结果
需要注意,对输入模型的任何修改都将使输出结果中的索引失效。当然,如果对模型没有任何修改,那么在CAD数据文件读写过程中特征索引是可以保持不变的。(这其实是对识别特征持久化存储的基本要求)

3.3. AAG API


要构造AAG,使用类asiAlgo_AAG传入TopoDS_Shape进行初始化即可,如下代码所示。初始化时,AAG会为模型中的每个面分配一个唯一索引,索引从1开始,一些映射map可以通过显式调用获得,例如asiAlgo_AAG::RequestMapOf*();同时,计算二面角属性并将其关联到图的无向边上。

Handle(asiAlgo_AAG) aag = new asiAlgo_AAG(shape);

 
 
  • 1

AAG在堆内存上构造,可以看到它是一个句柄类,由OpenCascade的句柄handle管理(即智能指针)。一旦AAG句柄离开其作用域,AAG对象的引用计数将自动减一,这意味着不应显式调用其析构函数。

需要再次强调,对用于AAG初始化的模型shape的任何修改都将使AAG失效。例如,从初始化模型shape模型上移除一个特征后,原AAG将失效,如果需要继续使用AAG则必须重新构造一个新的。因此,上述代码中的aag仅在shape保持“冻结”状态下才有效。

从代码架构的角度来说,一个好的实践是在软件所有的识别器中均使用同一个AAG对象,即基于同一个图对象完成对普通孔、倒角、圆角等特征的识别。
要获取AAG初始化的原始模型,可以调用asiAlgo_AAG::GetMasterShape()。通过asiAlgo_AAG::DumpJSON()可以将AAG对象流化为文本,如下代码所示:

std::string filename = "C:/tmp/dump.json";
std::ofstream filestream(filename);
//
if ( !filestream.is_open() )
  return 1; // Error.

aag->DumpJSON(filestream);
filestream.close();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

AAG数据结构使用一个栈存储表示AAG状态的邻接矩阵,这样允许临时(临时是指该操作之后可以复原)将整个图减小为一个子图,如下示意图所示。例如,使用 push/pop API 插入/删除一个仅由指定几个节点构成的子图。(push/pop允许对模型进行一些局部操作,而不需要重新构造或修改原始完整图)
保存AAG状态的栈数据结构示意图
如以下代码为例,实现从一个feature变量表示的子图中提取出彼此相连的元素,feature由面索引构成。在以下代码中,特征的索引是任意选择的,在实际应用中这些索引可以通过其他识别算法或者用户交互的方式得到。

asiAlgo_Feature feature;
//
feature.Add(10); // 10, 20, 30 即表示在 AAG 中的面(节点)索引
feature.Add(20);
feature.Add(13);
// ...

aag->PushSubgraph(feature);
{
std::vector<asiAlgo_Feature> ccomps;
aag->GetConnectedComponents(ccomps); // 此时对 aag 的操作就是基于子图 feature 进行的

// Iterate the connected components.
for ( const auto& ccomp : ccomps )

aag->PopSubgraph();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

asiAlgo_AAG::PopSubgraph()函数调用作用是将aag恢复至前一状态——即asiAlgo_AAG::PushSubgraph(feature)之前的状态。当需要仅处理shape上局部感兴趣的几个面时,push/pop函数对是非常实用的,它可以撤销此次临时操作对完整大图的修改。
迭代器asiAlgo_AAGIterator的子类可以方便迭代整个AAG。如下代码展示了如何遍历图中的所有面,同时由asiAlgo_AAG::GetNeighbors()获取每个面的相邻面。

for ( asiAlgo_AAGRandomIterator it(aag); it.More(); it.Next() )
{
  const int              fid  = it.GetFaceId();
  const asiAlgo_Feature& nids = aag->GetNeighbors(fid);
  // ...
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如果需要抑制AAG中的某些面、将两个无向边缝合起来,可以使用asiAlgo_AAG::Collapse(),如下示意图所示:
抑制面6
例如,使用该方法的一个场景是:需要检查由倒圆倒角相连的面的邻接关系,且希望忽略倒圆倒角。如下图所示:
抑制圆角面


以上为原文翻译

​转载博客请注明原文链接:https://blog.csdn.net/Mechanicoder/article/details/134875069

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值