ボディー/形状セットの名称を再帰的に取得するマクロ|CATIAマクロの作成方法
今回の記事はマクロ案募集でいただいた内容です。
送って頂いた内容は以下のようなマクロです。
ボディーや形状セットの名称を再帰的に取得する
再帰処理とは簡単にいえば「自分自身を呼び出す関数使った処理」です。
個人的には名称の取得でわざわざ再帰処理を使う必要はほとんどないと思っていますが参考程度に紹介していきます。(形状セット内の形状セット、その中の形状セット・・・というような同じことの繰り返し処理の場合には使えるかもしれませんが、再帰処理にこだわる必要はない気もします)
マクロの機能
今回作成したマクロはPart内のボディー/形状セットの名称を再帰的に取得するマクロです。
名称を再帰的に取得し配列に格納するだけなので、実行結果として何かが作り出されれたり、何かが変更されるということはありません。
具体的な機能は以下のとおりです。
・取得した名称は全てnames()という配列に格納する
サンプルコード
マクロのコードは以下のとおりです。
デバッグ確認等で、names()の中身を見ると名称が全て取得できていることがわかります。
取得した名称は「names(1)」「names(7)」のようにして表すことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
Option Explicit Option Base 1 '配列を1スタートにする Dim names() As String '名称格納用配列 Dim objs As Collection '形状セット/ボディー格納用配列 '―――――――――――――――――――――――――――――――――――――――― Sub CATMain() 'アクティブドキュメント定義 Dim doc As PartDocument Set doc = CATIA.ActiveDocument 'Selection定義 Dim sel As Selection Set sel = doc.Selection sel.Clear '形状セットとボディーを全て取得/格納 Set objs = New Collection sel.Search ("(ジェネレーティブ・シェイプ・デザイン.形状セット + パート・デザイン.ボディー),all") Dim i As Integer For i = 1 To sel.Count objs.Add sel.Item(i).Value Next i sel.Clear '再帰処理で形状セットとボディーの名称取得 ReDim names(objs.Count) i = 1 Call GetName(i) End Sub '―――――――――――――――――――――――――――――――――――――――― Function GetName(i As Integer) If i <= objs.Count Then names(i) = objs.Item(i).name Call GetName(i + 1) '再帰処理 End If End Function |
コード解説
オプション/モジュールレベル変数設定
1 2 3 4 5 |
Option Explicit Option Base 1 '配列を1スタートにする Dim names() As String '名称格納用配列 Dim objs As Collection '形状セット/ボディー格納用配列 |
まずはオプション設定を行います。
宣言していない変数を使うとエラーを表示するお馴染みの「Option Explicit」と合わせて、配列を「0」ではなく「1」始まりにする「Option Base 1 」を設定しておきます。これは以降でコレクションと配列を連動させる時に、Itemが「1」始まりであるコレクションに合わせるためです。
次にモジュールレベルの変数を宣言します。
ここでは名称を格納するための「name()」と、ボディー/形状セットをまとめて格納しておくための「objs」コレクションを宣言しておきます。
プロシージャ(Sub,Function)外で宣言した変数はモジュール内で共通変数として利用することが可能になります。(このような変数をモジュールレベル変数という)
Sub CATMain()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
Sub CATMain() 'アクティブドキュメント定義 Dim doc As PartDocument Set doc = CATIA.ActiveDocument 'Selection定義 Dim sel As Selection Set sel = doc.Selection sel.Clear '形状セットとボディーを全て取得/格納 Set objs = New Collection sel.Search ("(ジェネレーティブ・シェイプ・デザイン.形状セット + パート・デザイン.ボディー),all") Dim i As Integer For i = 1 To sel.Count objs.Add sel.Item(i).Value Next i sel.Clear '再帰処理で形状セットとボディーの名称取得 ReDim names(objs.Count) i = 1 Call GetName(i) End Sub |
本マクロのメイン処理部です。
Selectionオブジェクトを使ってボディー/形状セットを全て取得し、「objs」コレクション内に格納しています。(コードの詳しい説明は選択しているオブジェクトを一時保管する方法を参照)
ボディー/形状セットを全て取得したら「GetName」関数を呼び出します。
GetName関数のコード内ではGetName関数を呼び出す処理が書かれているため、終了条件を迎えるまで永遠と処理を続けます。(再帰処理)
GetName関数
1 2 3 4 5 6 7 8 |
Function GetName(i As Integer) If i <= objs.Count Then names(i) = objs.Item(i).name Call GetName(i + 1) '再帰処理 End If End Function |
GetName関数のコードは非常にシンプルで、「objs」コレクション内にある、引数であるインデックス( i 番目)のオブジェクトの名前を「names()」配列に入れるという処理です。
再帰処理として、GetName関数内で自分自身(GetName関数)を呼び出します。
この時、インデックス( i )に+1をすることで「objs」コレクション内のオブジェクトを1つずつ処理することが可能になします。終了条件は「i」が「objs」コレクション内のオブジェクトの個数を上回った時としておきます。
これにより、GetName関数をメインの処理で1度呼び出すだけで、勝手に再帰処理され名称を取得することが可能になります。
まとめ
今回はボディー/形状セットの名称を再帰的に取得するマクロについてでした。
再帰処理は階層フォルダやツリー構造に有効なので、CATIAの使用ツリーにも有効ではありますが、それはSelectionオブジェクトが無ければのお話です。このオブジェクトがないと仕様ツリーの上から順に取得、それこそ再帰処理が必要になってきます。
CATIA VBAではありがたいことにSelectionオブジェクトのSearchメソッドを使うことで、仕様ツリー内の任意のオブジェクトのみを全て選択することが可能になります。これにより再帰処理を使わずともツリー構造のデータから好きなオブジェクトのみを取得することが可能なのです。
そのため今回のサンプルコードでは無理矢理、再帰処理に持っていっていますが、下記コードでも同じ結果を得ることができます。上記サンプルコードはあくまでも参考程度に見ておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
Option Explicit Option Base 1 '配列を1スタートにする '―――――――――――――――――――――――――――――――――――――――― Sub CATMain() 'アクティブドキュメント定義 Dim doc As PartDocument Set doc = CATIA.ActiveDocument 'Selection定義 Dim sel As Selection Set sel = doc.Selection sel.Clear '形状セットとボディーを全て取得/格納 Dim objs As Collection '形状セット/ボディー格納用配列 Set objs = New Collection sel.Search ("(ジェネレーティブ・シェイプ・デザイン.形状セット + パート・デザイン.ボディー),all") Dim i As Integer For i = 1 To sel.Count objs.Add sel.Item(i).Value Next i sel.Clear '再帰処理でなくとも取得可能 Dim names() As String '名称格納用配列 ReDim names(objs.Count) For i = 1 To objs.Count names(i) = objs.item(i).Name Next i End Sub |