C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)

ボディ - ボディ の最短距離の測定3

こちらの続きです。
ボディ - ボディ の最短距離の測定2 - C#ATIA

もう一つの測定方法です。

スペース アナリシス ワークベンチ を利用する方法

こちらの方法では、表面積や体積・重心等も取得できる為
測定に関するコマンドに近い感覚です。
海外のサイトを見ても、わりと "上手くいかないよ" と言った書き込みを
目にするのですが、恐らく次の2点が原因のような気がします。

  • Helpのサンプルコードが間違っている

AutomationManual(当方R2012です)にサンプルコードが載っているのですが
間違っています。 こちらは改行させて見やすくしたものです。

'VBA これはエラーになります
    Dim reference1 As Reference
    Set reference1 = part1.CreateReferenceFromObject(object1)
    
    Dim reference2 As Reference
    Set reference2 = part1.CreateReferenceFromObject(object1)
    
    Dim TheSPAWorkbench As Workbench
    Set TheSPAWorkbench = CATIA.ActiveDocument.GetWorkbench("SPAWorkbench")
    
    Dim TheMeasurable As Measurable
    Set TheMeasurable = TheSPAWorkbench.Measurable(reference1) '←ここが間違っている
    
    Dim MinimumDistance As Double
    MinimumDistance = TheMeasurable.GetMinimumDistance(reference2)

コメントを付けた部分、正しくは

    Set TheMeasurable = TheSPAWorkbench.GetMeasurable(reference1)

です。

  • ボディではリファレンスは取得できない

スペース アナリシス ワークベンチを利用する場合、測定対象要素のリファレンスが必要に
なります。 ある程度マクロの経験がある方ならわかると思うのですが、
ボディは単なる入れ物です。
f:id:kandennti:20160329181956p:plain
GSDの点や線等に該当するのがパッドやアセンブルで、ボディは形状セット
のようなものです。
その為、ボディからはリファレンスを取得しようとするとエラーになります。


サンプルです。

'vba
Sub CATMain()
    Dim partDocument1 As PartDocument
    Set partDocument1 = CATIA.ActiveDocument
    
    Dim part1 As Part
    Set part1 = partDocument1.Part
    
    Dim SelFilter  As Variant
    SelFilter = Array("BiDim")
    
    Dim Ref1 As Reference
    Set Ref1 = SelectItem_Ref("一つ目のボディを選択して下さい : [Esc]=キャンセル", SelFilter)
    If Ref1 Is Nothing Then Exit Sub
    
    Dim Ref2 As Reference
    Set Ref2 = SelectItem_Ref("二つ目のボディを選択して下さい : [Esc]=キャンセル", SelFilter)
    If Ref2 Is Nothing Then Exit Sub
    
    MsgBox CStr(GetMinimumLength(part1, Ref1, Ref2)) + "mm"
End Sub

'選択しリファレンスを返す
Private Function SelectItem_Ref(ByVal Msg$, ByVal Filter As Variant) As Reference
    Dim Sel As Variant: Set Sel = CATIA.ActiveDocument.Selection
    Dim Pt As Part: Set Pt = CATIA.ActiveDocument.Part
    Dim LeafBody As Body, LastFuture As AnyObject
    Do
        Sel.Clear
        Select Case Sel.SelectElement2(Filter, Msg, False)
            Case "Cancel", "Undo", "Redo"
                Exit Function
        End Select
        Set LeafBody = GetLeafBody(Sel.Item(1).Value)
        If Not LeafBody Is Nothing Then
            Set LastFuture = GetLastFuture(LeafBody, Pt)
            If LastFuture Is Nothing Then
                MsgBox "空のボディは測定できません!"
            Else
                Exit Do
            End If
        End If
        MsgBox "ボディの要素を選択して下さい!"
    Loop
    Set SelectItem_Ref = Pt.CreateReferenceFromObject(LastFuture)
    Sel.Clear
End Function

'Treeに直接ぶら下がっているボディの取得
Private Function GetLeafBody(AnyOj As AnyObject) As Body
    If TypeName(AnyOj) = TypeName(AnyOj.Parent) Then
        Set GetLeafBody = Nothing
        Exit Function
    End If
    If TypeName(AnyOj.Parent) = "Bodies" Then
        If AnyOj.InBooleanOperation Then
            Set GetLeafBody = GetLeafBody(AnyOj.Parent)
        Else
            Set GetLeafBody = AnyOj
        End If
    Else
        Set GetLeafBody = GetLeafBody(AnyOj.Parent)
    End If
End Function

'Shapesから最後の活動化されたフィーチャーを取得 - 要らなかったかも
Private Function GetLastFuture(ByVal Shs As Shapes, ByVal Pt As Part) As AnyObject
    'Set GetLastFuture = Shs.Item(Shs.Count): Exit Function 'これでもOKみたい
    Dim i As Long
    For i = Shs.Count To 1 Step -1
        If Not IsEmpty(Shs.Item(i)) Then
            If False = Pt.IsInactive(Shs.Item(i)) Then '←Notじゃ上手く行かない
                Set GetLastFuture = Shs.Item(i)
                Exit Function
            End If
        End If
    Next
End Function

'最短距離測定
Private Function GetMinimumLength(ByVal Pt As Part, _
                                  ByVal Ref1 As Reference, _
                                  ByVal Ref2 As Reference) As Double
    GetMinimumLength = Pt.Parent.GetWorkbench("SPAWorkbench") _
                         .GetMeasurable(Ref1) _
                         .GetMinimumDistance(Ref2)
End Function

基本的にボディを選択する手順は同様ですが、前回は選択したボディの
名前が必要だったのですが、今回はボディの最後のパートデザインフューチャーの
リファレンスが必要な為、リファレンスを返すようにしています。

GetLastFuture関数は、このような感じで
f:id:kandennti:20160329182007p:plain
最後の要素が非活動化になっていた場合、"上手く取得出来ないかも"
と思ったのですが、非活動化したものでもリファレンスが取得出来、
正しい数値が取得できたので、無駄なコードです・・・。
(が、作ってしまった為、記載しておきます)

GetMaximumLength関数が最短距離を測定している部分です。
リファレンスさえ取得できていれば、かなりシンプルになります。