C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA

座標系からXY,YZ,ZXの各平面のリファレンスを取得

座標系からXY,YZ,ZXの各平面のリファレンスを取得する場合、
座標系の作り方によっては、上手く取得出来たり出来なかったり
します。

例えば、XYZ軸を全て指定している場合
f:id:kandennti:20160404165137p:plain
は、
f:id:kandennti:20160404165144p:plain
X(Y,Z)AxisDirection(Referenceオブジェクト)が取得できています。

僕が結構やってしまう、XY軸のみを指定している場合
f:id:kandennti:20160404165152p:plain
は、
f:id:kandennti:20160404165158p:plain
指定していないZAxisDirectionのみ失敗しています。

"リンクの結果として"・"結果として"や分離した座標系の場合
f:id:kandennti:20160404165203p:plain
は、全滅となります。
f:id:kandennti:20160404165208p:plain

確かに、指定していない部分についてはリファレンスガ取得できていなくても
仕方が無いとは、薄々思います。

代案として考えた場合、こちらを見ると
http://www.coe.org/p/fo/st/topic=113&post=75726
Little Cthulhuさんが(この方物凄いです)
「座標系から原点とXY軸のベクトルが取得できるから
それを元に平面作っちゃえば良いじゃん」
的なサンプルを提示しています。


でも、個人的にはそうじゃなくやっぱり座標系の平面としてリファレンスを
取得したいのが本音です。 軸の指定が不足している座標系でも
手動で操作した場合であれば、通常通りの操作で出来ますし、
座標系の変更にも対応できる。だからやっぱり
座標系の平面としてリファレンスを取得したい
と思い取り組んだら、出来たっぽいので記載しておきます。

'vba
'座標系の各平面のリファレンスの取得
'Return : 0-XY,1-YZ,2-ZY のリファレンス
Private Function GetAxisPlaneRefs(ByVal Ax As AxisSystem) As Variant ' Reference()
    Dim Pt As Part: Set Pt = GetParent_Of_T(Ax, "Part")
    Dim Axs As AxisSystems: Set Axs = Pt.AxisSystems
    
    'Ax要素取得
    Dim AxData As Variant: AxData = GetAxisOriVec(Ax)
    
    'Axのインデックスを取得
    Dim TempAxData As Variant
    Dim i&, Idx&: Idx = -1
    For i = 1 To Axs.Count
        If Ax.Name = Axs.Item(i).Name Then
            TempAxData = GetAxisOriVec(Axs.Item(i))
            If isArrayEqual(AxData, TempAxData) Then
                Idx = i: Exit For
            End If
        End If
    Next
    If Idx < 0 Then Exit Function
    Dim PlaneRef(2) As Reference
    For i = 0 To UBound(PlaneRef)
        Set PlaneRef(i) = Pt.CreateReferenceFromBRepName(GetAxisPlaneBrepName(Idx, i), Ax)
    Next
    GetAxisPlaneRefs = PlaneRef
End Function

'座標系の原点XYベクトル取得
Private Function GetAxisOriVec(ByVal Ax As AxisSystem) As Variant
    Dim AxVri As Variant: Set AxVri = Ax
    Dim AryAxOri(2): Call AxVri.GetOrigin(AryAxOri)
    Dim AryAxXVec(2), AryAxYVec(2)
    Call AxVri.GetVectors(AryAxXVec, AryAxYVec)
    Dim Ary As Variant: Ary = Array_Push(AryAxOri, AryAxXVec)
    GetAxisOriVec = Array_Push(Ary, AryAxYVec)
End Function

'配列の値が一致するか?
Private Function isArrayEqual(ByVal Ary1 As Variant, ByVal Ary2 As Variant) As Boolean
    isArrayEqual = False
    If Not IsArray(Ary1) Or Not IsArray(Ary2) Then Exit Function
    If Not UBound(Ary1) = UBound(Ary2) Then Exit Function
    Dim i&
    For i = 0 To UBound(Ary1)
        If Not Ary1(i) = Ary2(i) Then Exit Function
    Next
    isArrayEqual = True
End Function

'配列の連結
Private Function Array_Push(ByVal Ary1 As Variant, ByVal Ary2 As Variant) As Variant
    If Not IsArray(Ary1) Or Not IsArray(Ary2) Then Exit Function
    Dim StCount&: StCount = UBound(Ary1)
    ReDim Preserve Ary1(UBound(Ary1) + UBound(Ary2) + 1)
    Dim i&
    For i = StCount + 1 To UBound(Ary1)
        Ary1(i) = Ary2(i - StCount - 1)
    Next
    Array_Push = Ary1
End Function

'座標系BrepNameの取得
' Idx : 該当するAxisSystems.Itemのインデックス
' PlaneN0 : 0-XY,1-YZ,2-ZYの何れか
Private Function GetAxisPlaneBrepName$(ByVal Idx&, ByVal PlaneNo&)
    If PlaneNo < 0 Or PlaneNo > 2 Then Exit Function
    GetAxisPlaneBrepName = "RSur:(Face:(Brp:(AxisSystem." + CStr(Idx) + ";" + CStr(PlaneNo + 1) + ");None:();Cf11:());" + _
                           "WithPermanentBody;WithoutBuildError;WithSelectingFeatureSupport;MFBRepVersion_CXR15)"
End Function

'T型のParent取得
Private Function GetParent_Of_T(ByVal AnyOj As AnyObject, ByVal T$) As AnyObject
    If TypeName(AnyOj) = TypeName(AnyOj.Parent) Then
        Set GetParent_Of_T = Nothing
        Exit Function
    End If
    If TypeName(AnyOj) = T Then
        Set GetParent_Of_T = AnyOj
    Else
        Set GetParent_Of_T = GetParent_Of_T(AnyOj.Parent, T)
    End If
End Function

思った以上のボリュームになってしまいましたが、直接使用するのは
最初のGetAxisPlaneRefs関数で、他はこの関数から呼び出しています。
戻り値はReference型の配列で、指定座標系の
0-XY平面 , 1-YZ平面 , 2-ZX平面
のリファレンスです。

結果的にはBrepNameでムリムリにリファレンスを取得しています。
GetAxisPlaneBrepName関数がそれに該当し、こちらの拾ってきた
GetBrepName関数の応用です。
SelectElementからReferenceの取得 - C#ATIA


これを使ったサンプルです。 対象データは、座標系2を作成し、データム化。
コンパスで適当な位置や角度に変更。 点1を始点とし、座標系2の各平面
の向きで長さ100mmの押し出し(線)を作成させます。
f:id:kandennti:20160404165226p:plain
コードはこんな感じです。

'vba
Sub GetAxisPlaneRefs_Test()
    '点の選択
    Dim Pnt As AnyObject: Set Pnt = SelectItem("点を選択", Array("Point"))
    If Pnt Is Nothing Then Exit Sub
    
    '座標系の選択
    Dim Ax As AxisSystem: Set Ax = SelectItem("座標系を選択", Array("AxisSystem"))
    If Ax Is Nothing Then Exit Sub
    
    '点のリファレンス取得
    Dim Pt As Part: Set Pt = CATIA.ActiveDocument.Part
    Dim PntRef As Reference: Set PntRef = Pt.CreateReferenceFromObject(Pnt)
    
    '座標系平面のリファレンス取得
    Dim AxPlnRefs As Variant: AxPlnRefs = GetAxisPlaneRefs(Ax)
    
    '形状セット作成
    Dim HB As HybridBody: Set HB = Pt.HybridBodies.Add()
    
    '押し出し作成
    Dim i&
    For i = 0 To UBound(AxPlnRefs)
        Call HB.AppendHybridShape(InitExtrude(Pt, PntRef, AxPlnRefs(i)))
    Next
End Sub

'押し出し作成
Private Function InitExtrude(ByVal Pt As Part, ByVal OriRef As Reference, _
                             ByVal Dir As Reference)  As HybridShapeExtrude
    Dim Fact As HybridShapeFactory: Set Fact = Pt.HybridShapeFactory
    Dim Extrude As HybridShapeExtrude
    Set Extrude = Fact.AddNewExtrude(OriRef, 100#, 0#, Fact.AddNewDirection(Dir))
    Extrude.SymmetricalExtension = 0
    Call Pt.UpdateObject(Extrude)
    Set InitExtrude = Extrude
End Function

'選択
Private Function SelectItem(ByVal Msg$, ByVal Filter As Variant) As AnyObject
    Dim Sel As Variant: Set Sel = CATIA.ActiveDocument.Selection
    Sel.Clear
    Select Case Sel.SelectElement2(Filter, Msg, False)
        Case "Cancel", "Undo", "Redo"
            Exit Function
    End Select
    Set SelectItem = Sel.Item(1).Value
    Sel.Clear
End Function

実行結果はこちら
f:id:kandennti:20160404165234p:plain
試しに、座標系2のXY平面の向きに作成した線を見てみると
f:id:kandennti:20160404165243p:plain
方向が正しく出来ています。

試しに、座標系2をコンパスでグリグリ移動させても、変更に対応している為
リファレンスは正しく取得できていると思います。
f:id:kandennti:20160404165249p:plain



追記です。
最初にグズグズ書いている部分ですが、よく考えたら座標系の
各平面のリファレンスではなく、各軸のリファレンスでした。スイマセン。

又、今回のGetAxisPlaneRefs関数に関しては
Treeの "座標系" 以下に入っているもののみが対応しており、
形状セット等に入っている座標系に関しては、エラーとなります。
f:id:kandennti:20160405122339p:plain


再度追記です。
上記NGのものも取得でき、シンプルなコードをこちらに記載しました。
座標系からXY,YZ,ZXの各平面のリファレンスを取得2(InternalName) - C#ATIA