基于惯性主轴方向的CATIA包围盒(Bounding Box)
通俗地说,零部件的包围盒(Bounding Box
)指的是一个最小的能将对象包含在内的长方体盒子。在机械设计中,零件(部件)的包围盒可用于确定是否和其他零件在装配中发生干涉,或者用于确定加工该零件所需材料的最小尺寸。
在CATIA
中,使用惯量测量(Mearure Inertia
)工具可以直接测量得到3D模型的包围盒,这是一种确定对象包围盒尺寸的常用工具。惯量测量工具所测的包围盒等尺寸为相对于坐标系方向的包围盒,但有时候我们希望测得相对于惯性主轴的包围盒,此时通过简单地测量则不能实现我们的目的。
博文CATIA VBA获取零件“最小”包围盒对相对与坐标系和相对于惯性主轴的包围盒进行了简要的说明,并提供了计算零部件包围盒的CATIA VBA
程序,但本博文中给出的代码分享已失效,其他获取该代码的途径是该博文文末给出的原始链接:基于惯量主轴的包围盒创建,该网页为全英文,英文较好的读者可以仔细了解下关于相对于惯性主轴的最小包围盒的讨论、实现和改进过程,以及该方法存在的问题。
本文的重要任务是对基于惯量主轴的包围盒创建中的代码进行简要地说明,并指出使用过程中应注意的问题。
相对于惯性主轴的最小包围盒的CATIA VBA
代码摘录
Sub CATMain()
' 定义应用程序变量并赋值为CATIA,便于统一修改
Dim oCATIA As Application
Set oCATIA = CATIA
' 定义部件类型的文档并调用 Get_PartDocument 函数获取应用当前已打开的 Part 类型的文件
' 如果不存在 Part 类型的文件,则脚本抛出信息框并退出该子函数
Dim oPartDocument As PartDocument
Set oPartDocument = Get_PartDocument
' 如果应用未打开任何 Part 类型的文件,则退出脚本
If oPartDocument Is Nothing Then
Exit Sub
End If
' 定义Section个对象:其内容一般为用户通过鼠标选中的对象,但也可为搜索到的对象等
Dim oSelection As Selection
' 设置选择对象的内容为 Part 文件当前选中的内容
Set oSelection = oPartDocument.Selection
' 清除选择对象的内容:这3句代码的作用就是让 PartDocument 处于不选中任何内容的状态
oSelection.Clear
' 获取部件的重心
Dim COGArray
' 通过自定义函数 Get_COD 获取部件的重心
COGArray = Get_COG(oPartDocument)
' 获取部件的3个惯性主轴终点的3D坐标,其元素排列是3个点的X坐标为与前3个元素,
' 3个点的Y坐标为与中间3个元素,而3个点Z坐标位于数组最后的3个元素
Dim PrincipalAxes_temp
PrincipalAxes_temp = Get_PrincipalAxes(oPartDocument)
' 重排数组中的坐标值,按点的坐标为一组排列,即处理为:
' X方向惯性主轴的终点坐标为数组前3个元素(下标0,1,2),
' Y方向惯性主轴的终点坐标为数组中间3个元素(下标3,4,5)
' Z方向惯性主轴的终点坐标为数组最后3个元素(下标6,7,8)
Dim PrincipalAxes
PrincipalAxes = PrincipalAxesCorrection(PrincipalAxes_temp)
' 将 Part文件的部件放入 oPart 对象中
Dim oPart As Part
Set oPart = oPartDocument.Part
' 如果 Part 中不存在任何形状,则说明虽然有部件,但部件无内容,因此退出脚本
If oPart.MainBody.Shapes.Count = 0 Then
MsgBox "The PartBody Is Empty Exiting Script."
End
End If
Dim oHybridBodies As HybridBodies
Set oHybridBodies = oPart.HybridBodies
Dim oHybridBody As HybridBody
On Error Resume Next
Set oHybridBody = oHybridBodies.Item("Inertia_Bounding_Box")
If Err.Number = 0 Then
oSelection.Add oHybridBody
oSelection.Delete
oSelection.Clear
End If
On Error GoTo 0
' 新增一个零件集合体,并取名 Inertia_Bounding_Box (惯性边包围盒)
Set oHybridBody = oHybridBodies.Add
oHybridBody.Name = "Inertia_Bounding_Box"
' 操作混合形状的对象均需要以 HybridShapeFactory 对象为接口,为此定义这样一个对象并赋值
Dim oHybridShapeFactory As HybridShapeFactory
Set oHybridShapeFactory = oPart.HybridShapeFactory
' 根据重心的坐标分量,键建立部件的重心对象
Dim oHybridshapePointCoord As HybridShapePointCoord
Set oHybridshapePointCoord = Build_COG(oHybridShapeFactory, COGArray)
' 建立惯性主轴:前两条基于重心坐标和主轴方向向量建立,第3条通过获取前两条惯性主轴构成的平面的法向量建立
' 建立的方法为自定义的函数,函数的实现细节可在完整的原始代码中看到
Dim InertiaAxis(2) As Line
Set InertiaAxis(0) = Build_InertiaAxis(oHybridShapeFactory, oHybridshapePointCoord, PrincipalAxes, 1)
Set InertiaAxis(1) = Build_InertiaAxis(oHybridShapeFactory, oHybridshapePointCoord, PrincipalAxes, 2)
Set InertiaAxis(2) = Build_ThirdDirection_InertiaAxis(oHybridShapeFactory, oHybridshapePointCoord, InertiaAxis(0), InertiaAxis(1))
' 获取线框的6个极点坐标(此时的极点为原点在重心上的坐标轴和包围盒六个平面的交点)
Dim oExtremum(5) As HybridShapeExtremum
' 获取 InertiaAxis(0) 方向上相对于坐标极哒值的点
Set oExtremum(0) = Build_Extremums(oPart.MainBody, oPart, oHybridShapeFactory, 1, InertiaAxis(0), InertiaAxis(1), InertiaAxis(2))
' 注意这里:获取 InertiaAxis(0) 方向上坐标的极小值点,其值可为负值。因此最小的负值代表着在 InertiaAxis(0) 方向上距离选定的原点最远的点
Set oExtremum(1) = Build_Extremums(oPart.MainBody, oPart, oHybridShapeFactory, 0, InertiaAxis(0), InertiaAxis(1), InertiaAxis(2))
' 余下同上
Set oExtremum(2) = Build_Extremums(oPart.MainBody, oPart, oHybridShapeFactory, 1, InertiaAxis(1), InertiaAxis(2), InertiaAxis(0))
Set oExtremum(3) = Build_Extremums(oPart.MainBody, oPart, oHybridShapeFactory, 0, InertiaAxis(1), InertiaAxis(2), InertiaAxis(0))
Set oExtremum(4) = Build_Extremums(oPart.MainBody, oPart, oHybridShapeFactory, 1, InertiaAxis(2), InertiaAxis(0), InertiaAxis(1))
Set oExtremum(5) = Build_Extremums(oPart.MainBody, oPart, oHybridShapeFactory, 0, InertiaAxis(2), InertiaAxis(0), InertiaAxis(1))
' ------- 以下被注释掉的部分为原代码存在的代码,但其存在会使得VBA程序对于纯圆柱体、立方体等简单零件的包围盒绘制出错,
' 而删掉它们后程序反而不会出错。因此在这里将它们注释掉
' ' 用多段线连接正上面得到6个极点
' Dim oPolyLine As HybridShapePolyline
' Set oPolyLine = Build_PolyLine(oHybridShapeFactory, oExtremum)
' ' 获取最终的极点坐标(此时的极点为线框的6个顶点)
' Dim oFinalExtremums(5) As HybridShapeExtremum
' ' 求多段线的极点,此为部件最终的极值点
' Set oFinalExtremums(0) = Build_Extremums(oPolyLine, oPart, oHybridShapeFactory, 1, InertiaAxis(0))
' Set oFinalExtremums(1) = Build_Extremums(oPolyLine, oPart, oHybridShapeFactory, 0, InertiaAxis(0))
' Set oFinalExtremums(2) = Build_Extremums(oPolyLine, oPart, oHybridShapeFactory, 1, InertiaAxis(1))
' Set oFinalExtremums(3) = Build_Extremums(oPolyLine, oPart, oHybridShapeFactory, 0, InertiaAxis(1))
' Set oFinalExtremums(4) = Build_Extremums(oPolyLine, oPart, oHybridShapeFactory, 1, InertiaAxis(2))
' Set oFinalExtremums(5) = Build_Extremums(oPolyLine, oPart, oHybridShapeFactory, 0, InertiaAxis(2))
' 建立包围盒的6个侧面
Dim oFinalPlanes(5) As HybridShapePlaneNormal
' Set oFinalPlanes(0) = Build_Planes(oHybridShapeFactory, oFinalExtremums(0), InertiaAxis(0))
' Set oFinalPlanes(1) = Build_Planes(oHybridShapeFactory, oFinalExtremums(1), InertiaAxis(0))
' Set oFinalPlanes(2) = Build_Planes(oHybridShapeFactory, oFinalExtremums(2), InertiaAxis(1))
' Set oFinalPlanes(3) = Build_Planes(oHybridShapeFactory, oFinalExtremums(3), InertiaAxis(1))
' Set oFinalPlanes(4) = Build_Planes(oHybridShapeFactory, oFinalExtremums(4), InertiaAxis(2))
' Set oFinalPlanes(5) = Build_Planes(oHybridShapeFactory, oFinalExtremums(5), InertiaAxis(2))
' ------ 以下6行代码原程序中没有。因为上面注释掉了部分代码,因此这里需要略作修改以保证程序正常运行 ---------
Set oFinalPlanes(0) = Build_Planes(oHybridShapeFactory, oExtremum(0), InertiaAxis(0))
Set oFinalPlanes(1) = Build_Planes(oHybridShapeFactory, oExtremum(1), InertiaAxis(0))
Set oFinalPlanes(2) = Build_Planes(oHybridShapeFactory, oExtremum(2), InertiaAxis(1))
Set oFinalPlanes(3) = Build_Planes(oHybridShapeFactory, oExtremum(3), InertiaAxis(1))
Set oFinalPlanes(4) = Build_Planes(oHybridShapeFactory, oExtremum(4), InertiaAxis(2))
Set oFinalPlanes(5) = Build_Planes(oHybridShapeFactory, oExtremum(5), InertiaAxis(2))
' 以下3部分按3步创建包围盒:点 => 线 => 面 => 包围盒(连接两点作直线,拉伸直线的曲面,拉伸平面的长方体,即包围盒)
' 建立基线:过重心且垂直于平面 oFinalPlanes(0) 且直线的两端位于平面 oFinalPlanes(0) 和 oFinalPlanes(1) 上
Dim oBaseLine As HybridShapeLinePtDir
Set oBaseLine = Build_LinePtDir(oHybridShapeFactory, oHybridshapePointCoord, oFinalPlanes(0), oFinalPlanes(1))
' 拉伸直线得到曲面
Dim oExtrudedSurface As HybridShapeExtrude
Set oExtrudedSurface = Build_ExtrudedSurface(oHybridShapeFactory, oBaseLine, oFinalPlanes(2), oFinalPlanes(3))
' 拉伸平面得到包围盒
Dim oFinalBoundingBox As HybridShapeExtrude
Set oFinalBoundingBox = Build_ExtrudedSurface(oHybridShapeFactory, oExtrudedSurface, oFinalPlanes(4), oFinalPlanes(5))
' 将得到的包围盒追加到混合body中
oHybridBody.AppendHybridShape oFinalBoundingBox
End Sub
完整的代码近500行,就不在此处列出了,有需要的读者可去基于惯量主轴的包围盒创建中下载。如果想获取带有中文注释的代码,可去带中文注释的最小包围盒CATIA VBA实现中下载。
注意点
- 正如上面的代码注释中提到的,原始的代码还是存在一些问题。比如当零件为简单的圆柱体或长方体时,原程序执行会出错,这是因为原程序获得极点后,先用折线连接极点然后再求这些的极点作为最终的极点,而基于这些极点的包围盒会导致参考平面匹配不上。个人认为,原程序的这种处理是多余的;
- 如果只是希望获得相对惯性主轴的包围盒的尺寸,而不需要绘制出包围盒时,则绘制包围盒部分就可以完全省去,从而简化代码。