穴中心線(座標軸線)作成マクロ|CATIAマクロの作成方法

今回の記事は「お問い合わせ」よりいただいた内容です。
送って頂いた内容は以下のようなマクロです。

●プロダクトファイル開いた状態で
 ツリーにぶら下がっているパートをアクティブにしてマクロを実行させたいです。

③穴中心線(座標軸線)作成

  選択          
   円のエッジ選択 (円はボディ&サーフェスエッジ)
   XY方向を決める直線を選択(入力しない場合は主座標の方向)
    ↓
  結果
   点 と 円の軸線作成 と XY方向線作成

  ・ 軸線及びXY方向線は点から両端で作成 (例 始点-10mmm,終点10mm)
  ・ 線片側長さはダイアログで数値を入力
        (線片側長さは10と入力すれば始点-10mmm,終点10mm 全長は20mm)  
  ・ 作成された線は作成後に履歴により出来れば寸法変更もしたいです 。

複数のマクロ案を頂いたので、それぞれ別ページでまとめていきます。
(上記お問い合わせ内容に番号やタイプがついているのは複数案頂いたためです)
そのため、似たようなマクロを別ページでも作成していることもあり、内容がほとんど同じ部分も出てくるので予めご了承ください。

 

マクロの機能

今回作成したマクロは
『ユーザーが選択した円エッジに対して穴中心線(座標軸線)を作成するマクロ』です。

具体的な機能は以下のとおりです。

  マクロの機能まとめ ・ユーザーに円エッジと直線を選択させる
・円エッジに対して選択された直線の方向での軸線を作成する
・直線が選択されなかった場合は絶対座標の方向を使用する
・作成した形状は全てツリー第1階層に作成する新規形状セットにまとめる

 

サンプルコード

マクロのサンプルコードは以下のとおりです。

Option Explicit

Sub CATMain()

    Dim SEL
    Set SEL = CATIA.ActiveDocument.Selection
    
    Dim VPS As VisPropertySet
    Set VPS = SEL.VisProperties
    
    Dim filter1
    Dim filter2
    Dim msg As String
    Dim Status As String
    Dim check As Boolean
    
    check = False
    
    filter1 = Array("Edge")
    msg = "エッジ(円)を選択して下さい。"
    
label1:
    
    Status = SEL.SelectElement2(filter1, msg, False)
    If Status <> "Normal" Then
        MsgBox "キャンセルします。"
        Exit Sub
    End If
    
    Dim SelEdge As Edge
    Set SelEdge = SEL.Item(1).Value
    
    SEL.Clear
    
    'エッジを含むCATPart(PartDocumrnt)を取得
    
    Dim tmp_Obj
    Set tmp_Obj = SelEdge
    
    Do Until TypeName(tmp_Obj) = "PartDocument"
        Set tmp_Obj = tmp_Obj.Parent
    Loop
    
    Dim Doc As PartDocument
    Set Doc = tmp_Obj
    
    Dim PT As Part
    Set PT = Doc.Part
    
    Dim HSF As HybridShapeFactory
    Set HSF = PT.HybridShapeFactory
    
    
    '選択されたエッジが円か確認
    
    Dim SPA As Workbench
    Set SPA = Doc.GetWorkbench("SPAWorkbench")
    
    Dim ConfMeasure
    Set ConfMeasure = SPA.GetMeasurable(SelEdge)
    
    On Error GoTo ErrLabel
        Dim getvalues(2) As Variant
        ConfMeasure.GetCenter getvalues
    On Error GoTo 0
    
    
    filter2 = Array("Line", "RectilinearMonoDimFeatEdge", "RectilinearBiDimFeatEdge", "RectilinearTriDimFeatEdge")
    msg = "直線(軸方向)を選択して下さい。([Esc]キーを押すと絶対座標系を軸方向にします。)"
    
    Status = SEL.SelectElement2(filter2, msg, False)
    If Status = "Normal" Then
    
        Dim SelLine As AnyObject
        Dim RefDir As Reference
        Dim HSDir As HybridShapeDirection
        
        If TypeName(SEL.Item(1).Value) <> "Line" Then
            Set SelLine = SEL.Item(1).Value
            Set HSDir = HSF.AddNewDirection(SelLine)
        Else
            Set SelLine = SEL.Item(1).Value
            Set RefDir = PT.CreateReferenceFromObject(SelLine)
            Set HSDir = HSF.AddNewDirection(RefDir)
        End If
        check = True
    End If
    
    SEL.Clear
    
    
    Dim UserLength As String
    UserLength = InputBox("軸線の長さを入力して下さい。", "長さ入力", 10)
    If UserLength = "" Then
        Exit Sub
    End If
    
    
    Dim HB As HybridBody
    Set HB = PT.HybridBodies.Add
    HB.Name = "穴中心線(座標軸線)"
    
    
    
    '① 選択されたエッジの中心点作成
    
    Dim CtrPoint As Point
    Set CtrPoint = HSF.AddNewPointCenter(SelEdge)
    
    HB.AppendHybridShape CtrPoint
    PT.Update
    
    
    '② 選択されたエッジを通る平面を作成(回転軸取得用)
    
    Dim AxisPlane As Plane
    Set AxisPlane = HSF.AddNewPlane1Curve(SelEdge)
    
    HB.AppendHybridShape AxisPlane
    PT.Update
    
    
    '③ ①を通り②に垂直方向の直線を作成
    
    Dim RefPlane As Reference
    Set RefPlane = PT.CreateReferenceFromObject(AxisPlane)
    
    Dim RefPoint As Reference
    Set RefPoint = PT.CreateReferenceFromObject(CtrPoint)
    
    Dim AxisLine1 As Line
    Set AxisLine1 = HSF.AddNewLineNormal(RefPlane, RefPoint, UserLength, -1 * UserLength, False)
    
    HB.AppendHybridShape AxisLine1
    PT.Update

    
    Dim AxisLine2 As Line
    Dim AxisLine3 As Line
    Dim RefAxisLine1 As Reference
    Dim RefAxisLine2 As Reference
    
    
    If check = True Then   '軸方向が選択された場合
    
    
        '④ ①を通り選択した直線方向の直線を作成

        Set AxisLine2 = HSF.AddNewLinePtDir(RefPoint, HSDir, UserLength, -1 * UserLength, False)
        
        HB.AppendHybridShape AxisLine2
        PT.Update
        
        
        '⑤ ④の直線を②を軸に90deg回転した位置に直線を作成

        Set RefAxisLine2 = PT.CreateReferenceFromObject(AxisLine2)
        Set AxisLine3 = HSF.AddNewLineAngle(RefAxisLine2, RefPlane, RefPoint, True, UserLength, -1 * UserLength, 90, False)
        
        HB.AppendHybridShape AxisLine3
        PT.Update
        
        
        'ex ②の平面を非表示
        
        SEL.Add AxisPlane
        VPS.SetShow catVisPropertyNoShowAttr
        SEL.Clear
 

    ElseIf check = False Then   '軸方向が選択されなかった場合
    
    
        '④ ①を通るYZ方向の直線を作成
        
        Dim YZPlane As Plane
        Set YZPlane = PT.OriginElements.PlaneYZ

        Dim RefYZPlane As Reference
        Set RefYZPlane = PT.CreateReferenceFromObject(YZPlane)
        
        Set AxisLine2 = HSF.AddNewLineNormal(RefYZPlane, RefPoint, UserLength, -1 * UserLength, False)
        
        HB.AppendHybridShape AxisLine2
        PT.Update
        
        
        '作成方向の確認
        
        Dim ZXPlane As Plane
        Set ZXPlane = PT.OriginElements.PlaneZX

        Dim RefZXPlane As Reference
        Set RefZXPlane = PT.CreateReferenceFromObject(ZXPlane)
        
        Set ConfMeasure = SPA.GetMeasurable(RefZXPlane)
        
        Dim CheckAngle As Double
        CheckAngle = ConfMeasure.GetAngleBetween(RefPlane)
        
        
        Dim HSExtrude As HybridShapeExtrude
        
        If CheckAngle = 0 Then
        
            '⑤ ④からZX方向への押し出しサーフェス作成
            
            Dim ZXDir As HybridShapeDirection
            Set ZXDir = HSF.AddNewDirection(RefZXPlane)
            
            Set RefAxisLine2 = PT.CreateReferenceFromObject(AxisLine2)
            
            Set HSExtrude = HSF.AddNewExtrude(RefAxisLine2, UserLength, UserLength, ZXDir)
            
            HB.AppendHybridShape HSExtrude
            PT.Update
            
        Else
        
            '⑤ ④からXY方向への押し出しサーフェス作成

            Dim XYPlane As Plane
            Set XYPlane = PT.OriginElements.PlaneXY
    
            Dim RefXYPlane As Reference
            Set RefXYPlane = PT.CreateReferenceFromObject(XYPlane)
            
            Dim XYDir As HybridShapeDirection
            Set XYDir = HSF.AddNewDirection(RefXYPlane)
            
            Set RefAxisLine2 = PT.CreateReferenceFromObject(AxisLine2)

            Set HSExtrude = HSF.AddNewExtrude(RefAxisLine2, UserLength, UserLength, XYDir)
            
            HB.AppendHybridShape HSExtrude
            PT.Update
        
        End If
        
        
        '⑥ ②と⑤の交差を作成
        
        Dim RefHSExtrude As Reference
        Set RefHSExtrude = PT.CreateReferenceFromObject(HSExtrude)
        
        Dim HSIntersect As HybridShapeIntersection
        Set HSIntersect = HSF.AddNewIntersection(RefPlane, RefHSExtrude)
        
        HB.AppendHybridShape HSIntersect
        PT.Update
        
        
        '⑦ ③と⑥を通る平面を作成
        
        Set RefAxisLine1 = PT.CreateReferenceFromObject(AxisLine1)
        
        Dim RefHSIntersect As Reference
        Set RefHSIntersect = PT.CreateReferenceFromObject(HSIntersect)
        
        Dim Line2Plane As HybridShapePlane2Lines
        Set Line2Plane = HSF.AddNewPlane2Lines(RefAxisLine1, RefHSIntersect)
        
        HB.AppendHybridShape Line2Plane
        PT.Update
        
        
        '⑧ ①を通り⑦に直交方向の直線を作成
        
        Dim RefLine2Plane As Reference
        Set RefLine2Plane = PT.CreateReferenceFromObject(Line2Plane)
        
        Set AxisLine3 = HSF.AddNewLineNormal(RefLine2Plane, RefPoint, UserLength, -1 * UserLength, False)
        
        HB.AppendHybridShape AxisLine3
        PT.Update
        
        
        '⑨ ①を通り⑥方向の直線を作成
        
        Dim HSIntersectDir As HybridShapeDirection
        Set HSIntersectDir = HSF.AddNewDirection(RefHSIntersect)
        
        Dim AxisLine4 As Line
        Set AxisLine4 = HSF.AddNewLinePtDir(RefPoint, HSIntersectDir, UserLength, -1 * UserLength, False)
        
        HB.AppendHybridShape AxisLine4
        PT.Update
        
        
        'ex ②の平面を非表示
        
        With SEL
            .Add AxisPlane
            .Add HSExtrude
            .Add HSIntersect
            
            .Add Line2Plane
            .Add AxisLine2
            VPS.SetShow catVisPropertyNoShowAttr
            .Clear
        End With
    
    End If
    

    Exit Sub

ErrLabel:
    MsgBox "エッジは円を選択してください。"
    SEL.Clear
    Resume label1
End Sub

 

コード解説

形状作成部分のコードは基本的に以下の①〜③を繰り返すだけなのでここでは割愛します。
① 形状の取得
② 取得した形状のReferenceを作成
③ ReferenceとHybridShapeFactoryを使って形状作成

以下では形状作成を行うまでのドキュメントの定義方法、ユーザー選択オブジェクトの確認などの形状作成部分以外のコードを解説していきます。
 

ドキュメントの定義

まずはドキュメントの定義を行います。
通常は「Set DOC = CATIA.ActiveDocument」のように1行で済ませることのできる「ドキュメントの定義」ですが、お問い合わせの内容によると「プロダクトファイル開いた状態でツリーにぶら下がっているパートをアクティブにしてマクロを実行させたいです。」とのことです。この場合、アクティブドキュメントはCATPartではなくCATProductになってしまうので、単純に「Set DOC = CATIA.ActiveDocument」と書いてしまうと以降の処理でCATPartの処理を行うことができません。

というわけでここでは少し違う方法を使ってドキュメント(CATPart)を定義していきます。

  Dim SEL
    Set SEL = CATIA.ActiveDocument.Selection
    
    Dim VPS As VisPropertySet
    Set VPS = SEL.VisProperties
    
    Dim filter1
    Dim filter2
    Dim msg As String
    Dim Status As String
    Dim check As Boolean
    
    check = False
    
    filter1 = Array("Edge")
    msg = "エッジ(円)を選択して下さい。"
    
label1:
    
    Status = SEL.SelectElement2(filter1, msg, False)
    If Status <> "Normal" Then
        MsgBox "キャンセルします。"
        Exit Sub
    End If
    
    Dim SelEdge As Edge
    Set SelEdge = SEL.Item(1).Value
    
    SEL.Clear
    
    'エッジを含むCATPart(PartDocumrnt)を取得
    
    Dim tmp_Obj
    Set tmp_Obj = SelEdge
    
    Do Until TypeName(tmp_Obj) = "PartDocument"
        Set tmp_Obj = tmp_Obj.Parent
    Loop
    
    Dim Doc As PartDocument
    Set Doc = tmp_Obj

まずはドキュメントの定義はせず、ユーザーに「SelectElement2」を使ってエッジを選択させます。

次にこのエッジの親オブジェクトを順々に見ていき、PartDocumentオブジェクトになった時に、そのオブジェクトをドキュメントとして定義します。(コードでいうと「Do〜Loop」の部分)

エッジを選択し親オブジェクトを見ていくと
選択したEdge < HybridShapeSurfaceExplicit < Parameters < Part < PartDocument
といった具合に、必ず「PartDocument」が見つかります。

つまり「Until TypeName(tmp_Obj) = “PartDocument”」と条件をつければ、いつかはPartDocumentオブジェクトを取得できるというわけです。
実際に下のツリー構造で見てもCATPartを扱うPartDocumentオブジェクトは最上位のオブジェクトなので、親を順々に見ていけば必ず見つけることができるということがわかります。

 

ユーザー選択の円を確認

次にユーザーが選択した円が"正円なのか"を確認していきます。
というのも前項で「SelectElement2」を使ってエッジを取得させましたが、その選択フィルターは"Edge"、つまりはエッジで円でなくても選択できるようになってしまっています。

しかし、以降の形状作成の処理では、ユーザーが選択したエッジは正円である必要があります。
([点]コマンドの[円/球/楕円の中心]を使って作成するため)

    Dim SPA As Workbench
    Set SPA = Doc.GetWorkbench("SPAWorkbench")
    
    Dim ConfMeasure
    Set ConfMeasure = SPA.GetMeasurable(SelEdge)
    
    On Error GoTo ErrLabel
        Dim getvalues(2) As Variant
        ConfMeasure.GetCenter getvalues
    On Error GoTo 0

'-----------------------------------------------------------------------
'                                省略
'-----------------------------------------------------------------------

ErrLabel:
    MsgBox "エッジは円を選択してください。"
    SEL.Clear
    Resume label1
End Sub

上記のコードでは「Measurableオブジェクト」の「GetCenterメソッド」を使って、ユーザーが選択したエッジの中心点の座標を取得しています。

ここでユーザーが選択したエッジが正円でない場合は、中心座標の取得ができないため「GetCenterメソッド」の行でエラーが発生します。つまり言い換えればここでエラーが発生した場合、ユーザーの選択したエッジは正円でないことがわかります。

ここではエラーが出た場合に「On Error GoTo ErrLabel」を使って「ErrLabel:」に処理を飛ばすようにします。これにより、ユーザーに正円エッジを選択するよう促すことが可能になります。

あとは「ErrLabel:」から前項の「label1:」に処理を飛ばすことで、正円が選択されるまではユーザーの選択フェーズが永遠と続くような仕様になっています。(もちろん[Esc]キーでマクロの中断もできます)

 

ユーザ-による直線選択(処理の分岐)

エッジが正円と確認出来たら、軸線の方向を指定するための直線をユーザーに選択させます。
ここでお問い合わせの内容を見ると「XY方向を決める直線を選択(入力しない場合は主座標の方向)」とのことなので、ユーザー選択のフェーズで[Esc]キーが押されたら「主座標の方向(絶対座標)」を使うように処理分岐をするようにします。

ここではブーリアン型の変数「check」を使って直線が選択された場合に「True」にすることで、以降の形状作成部分のコードで分岐できるようにしています。

    filter2 = Array("Line", "RectilinearMonoDimFeatEdge", "RectilinearBiDimFeatEdge", "RectilinearTriDimFeatEdge")
    msg = "直線(軸方向)を選択して下さい。([Esc]キーを押すと絶対座標系を軸方向にします。)"
    
    Status = SEL.SelectElement2(filter2, msg, False)
    If Status = "Normal" Then
    
        Dim SelLine As AnyObject
        Dim RefDir As Reference
        Dim HSDir As HybridShapeDirection
        
        If TypeName(SEL.Item(1).Value) <> "Line" Then
            Set SelLine = SEL.Item(1).Value
            Set HSDir = HSF.AddNewDirection(SelLine)
        Else
            Set SelLine = SEL.Item(1).Value
            Set RefDir = PT.CreateReferenceFromObject(SelLine)
            Set HSDir = HSF.AddNewDirection(RefDir)
        End If
        check = True
    End If

先のエッジと同じく「SelectElement2」を使って、ユーザーに直線を選択させるようにしますが、ここではフィルターに「Line」だけでなくサブエレメントである「直線エッジ」も選択できるように「RectilinearMonoDimFeatEdge」「RectilinearBiDimFeatEdge」「RectilinearTriDimFeatEdge」もいれています。
(上記3つのオブジェクトについては「CATIA VBAでのサブエレメント(内部要素)」を参照下さい)

ここで1つだけ注意する点があります。
それは、直線(Line)が選択された場合と、直線エッジ(Rectilinear~)が選択された場合に少し処理を変える必要があるという点です。

基本的にCATIAマクロでは形状を作成する時に、その材料となる形状(直線や点などの通常のコマンドで作成できるもの)のオブジェクトはReferenceオブジェクトに変換する必要があります。しかし、その材料がサブエレメントの場合はReferenceオブジェクトに変換する必要がありません。(というよりも変換自体ができません)

今回の場合、初めに「HSDir」という方向を扱うための「HybridShapeDirection」を定義していきます。このオブジェクトの材料となるのはユーザーが選択した直線(もしくは直線エッジ)です。

直線が選択された場合はその直線をReferenceオブジェクトに変換し、そのReferenceオブジェクトを使うことで方向を定義することができます。

            Set SelLine = SEL.Item(1).Value 'ユーザー選択の「直線」を取得
            Set RefDir = PT.CreateReferenceFromObject(SelLine) '「直線」をReferenceオブジェクトに変換
            Set HSDir = HSF.AddNewDirection(RefDir) '方向の定義

 
しかし直線エッジが選択された場合はReferenceオブジェクトに変換できないので、以下のように直線が選択された場合ではReferenceオブジェクトに変換していた部分を端折る必要があります。

            Set SelLine = SEL.Item(1).Value 'ユーザー選択の「直線エッジ」を取得
            Set HSDir = HSF.AddNewDirection(SelLine) '方向の定義

 

このように「SelectElement系」のメソッドでのフィルターに「形状のオブジェクト」と「サブエレメントのオブジェクト」をまとめる場合は、上記のように処理を分ける必要があるので注意しましょう。

「HSDir」が定義できれば以降で形状作成の処理を行います。
この部分は初めにもいった通り、同じような処理の繰り返しなので割愛します。
(コードのコメント文を見れば何をやっているかある程度理解できると思います)

 

まとめ

今回は「穴中心線(座標軸線)作成マクロ」についての内容でした。

今回は詳細な履歴の内容も教えて頂いたので、形状作成の流れはそれに従っています。
ただ、CATIAでの形状作成の方法はいくつもあり、これが絶対に正解という訳ではありません。
 
形状作成についてはコードの書き方さえ理解すれば、あとは手動と同じ考え方です。
(形状を作成し、その形状を使って新しい形状を作成していく)
VBAでの形状作成ははじめは少し苦戦するかもしれませんが、理解できればコードすら覚える必要がなくなるほどワンパターンなことに気が付きます。本サイトのサンプルマクロをいくつか見ればパターンがつかめると思うので参考にしてみて下さい。

最後に今回のマクロで学べる、他のマクロでも流用できる部分をまとめると。
コード解説でもあった「CATProduct時に選択されたエッジのあるPartDocumentを取得する方法」と「SelectElement2でのフィルターで形状オブジェクトとサブエレメントオブジェクトがまとまっている場合には処理分岐をさせる」という2点です。

CATIAマクロではどちらも使う場面は出てくると思うので、頭の片隅に入れておきましょう。
 

目次へ戻る
 

icon-book CATIAマクロを本気で勉強するなら

 

2024年8月26日0から学ぶCATIA V5,CATIA,CATIAマクロ