穴中心線(座標軸線)作成マクロ|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マクロではどちらも使う場面は出てくると思うので、頭の片隅に入れておきましょう。
CATIAマクロを本気で勉強するなら









