【フィーチャー履歴の深掘り】GetFirstSubFeatureとGetNextFeatureによる複雑なツリー構造の再帰的解析
SolidWorks VBA自動化において、最もエンジニアの技量が問われる領域はどこか。
それは、図形を描くマクロでも、寸法を書き換えるだけの単純作業でもない。「FeatureManagerデザインツリーの闇、すなわち複雑な親子関係の完全制覇」である。
現場でよくある要件を思い出してほしい。
- 「特定のカットフィーチャーの内部にあるサブフィーチャーや、パターン展開されたインスタンスを完全に列挙したい」
- 「ライブラリフィーチャーやアセンブリのコンポーネント構造に潜む、特定条件を満たす要素を漏れなく抽出したい」
素人が書いたコードは、決まって`GetFirstFeature`を一度呼んで満足し、フラットなリストの走査だけで終わる。その結果、サブフィーチャーの階層構造を取りこぼし、現場から「動かない欠陥ツールだ」と突き返される。
今回は、SolidWorks APIのオブジェクトモデルの深淵を覗き、ツリー構造を完全網羅する「再帰的解析アルゴリズム」を、実務でそのまま使えるプロダクションコードと共に伝授する。
—
1. なぜ「フラットな走査」ではツリー構造に太刀打ちできないのか?
SolidWorksのFeatureManagerツリーは、単なる「リスト(配列)」ではない。「N分木(多岐ツリー)」構造体である。
- メインフィーチャーの鎖: `GetFirstFeature` と `GetNextFeature` は、ツリーの「表層(ルートレベル)」を横方向に進むだけのイテレータである。
- サブフィーチャーの壁: 押し出しやカット、あるいはロフトなどの裏側に隠された「スケッチ」「親子の従属関係」「コンポーネント内のフィーチャー」は、表層の鎖からは一切見えない。これらを紐解くには、明示的に子(SubFeature)の方向へダイブ(再帰呼び出し)する必要がある。
これを怠ると、高度な設計規則チェック(DRC)や、社内規格に違反したフィーチャーの自動検出ツールを作った際、見事に「見落とし」が発生する。プロのエンジニアであれば、ツリーの深さ(Depth)に依存しない、堅牢な再帰ロジックを組まなければならない。
—
2. APIの生命線:オブジェクトのライフサイクルと解放の鉄則
ツリー解析を行う際、VBA特有のメモリ管理の罠にハマる開発者が後を絶たない。
SolidWorks APIはCOMオブジェクトの塊であり、不適切な参照の保持は「メモリリーク」や「SolidWorks自体の強制終了(クラッシュ)」を招く。
押さえておくべきAPIの挙動
1. ポインタの有効性: `GetNextFeature` で取得したオブジェクトは、次のイテレーションへ移行する際、適切に変数上書きまたは解放を行わないと、COMコンテキストが汚染される。
2. 無限ループの防止: 複雑なモデルや、外部参照(In-context)を持つアセンブリでは、循環参照の罠が存在しうる。再帰関数には必ず「深さ制限(Max Depth)」や「訪問済みチェック」の概念を頭に入れておくべきである。
—
3. 【プロダクションコード】フィーチャー履歴を完全網羅する再帰解析マクロ
以下のコードは、アクティブなドキュメントのFeatureManagerツリーをルートから最深部のサブフィーチャーまでくまなく走査し、イミディエイトウィンドウにその階層構造とフィーチャー名を出力する、実務直結のモジュールである。
コピペしてそのままSolidWorksのVBAエディタに貼り付け、検証してほしい。
Option Explicit
‘ =========================================================================
‘ módulo名: ModFeatureAnalyzer
‘ 概要 : FeatureManagerツリーの再帰的解析エンジン
‘ 著者 : 首席チーフアーキテクト
‘ =========================================================================
Public Sub RunFeatureAnalyzer()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swSelMgr As SldWorks.SelectionMgr
‘ 1. アプリケーションとドキュメントの取得
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical, “エラー”
Exit Sub
End If
Debug.Print “=========================================”
Debug.Print ” ツリー解析開始: ” & swModel.GetPathName
Debug.Print “=========================================”
Dim startTime As Double
startTime = Timer
‘ 2. ルートフィーチャーの取得と再帰処理のキック
Dim swFeat As SldWorks.Feature
Set swFeat = swModel.FirstFeature
Dim totalCount As Long
totalCount = 0
If Not swFeat Is Nothing Then
Call TraverseFeatures(swFeat, 0, totalCount)
End If
Debug.Print “=========================================”
Debug.Print ” 解析完了. 総フィーチャー数: ” & totalCount & ” (処理時間: ” & Format(Timer – startTime, “0.00秒”) & “)”
Debug.Print “=========================================”
End Sub
‘ ————————————————————————-
‘ サブルーチン: フィーチャーを再帰的に走査するコアロジック
‘ @param swFeat : 現在処理中のフィーチャーオブジェクト
‘ @param depth : 現在のツリー階層(インデント用)
‘ @param totalCount : 累積カウント(参照渡し)
‘ ————————————————————————-
Private Sub TraverseFeatures(ByVal swFeat As SldWorks.Feature, ByVal depth As Long, ByRef totalCount As Long)
‘ 循環参照やゾンビオブジェクト対策のガード節
Do While Not swFeat Is Nothing
totalCount = totalCount + 1
‘ 3. データの抽出と整形(インデント表現)
Dim featName As String
Dim featTypeName As String
featName = swFeat.Name
featTypeName = swFeat.GetTypeName2()
‘ インデントをつけてイミディエイトに出力
Debug.Print String(depth 2, ” “) & “└─ [” & featTypeName & “] ” & featName
‘ ———————————————————————
‘ A. サブフィーチャー(SubFeature)の再帰的処理
‘ ———————————————————————
Dim swSubFeat As SldWorks.Feature
Set swSubFeat = swFeat.GetFirstSubFeature()
If Not swSubFeat Is Nothing Then
‘ 子が存在する場合は、階層を掘り下げて再帰呼び出し
Call TraverseFeatures(swSubFeat, depth + 1, totalCount)
End If
‘ ———————————————————————
‘ B. 添付フィーチャー(AttachedFeature / 履歴に紐づく個別要素)の処理
‘ ※必要に応じて拡張可能なフックポイント
‘ ———————————————————————
‘ Dim swAttFeat As SldWorks.Feature
‘ Set swAttFeat = swFeat.GetNextAttachedFeature()
‘ ‘ If Not swAttFeat Is Nothing Then …
‘ ———————————————————————
‘ 次の兄弟フィーチャーへイテレーションを進める
‘ ———————————————————————
Dim swNextFeat As SldWorks.Feature
Set swNextFeat = swFeat.GetNextFeature()
‘ オブジェクトの参照を明示的に切り替え(メモリ最適化)
Set swFeat = swNextFeat
Loop
End Sub
—
4. プロジェクト実戦投入時の注意点とアーキテクチャの心得
このコードを実際の業務システムや大規模アセンブリ自動化に組み込む際、以下の「現場の罠」に注意してほしい。
① パフォーマンスの最適化(画面描画の凍結)
複雑なモデルでツリーを全走査すると、SolidWorksの画面再描画(グラフィックス更新)が走ることで処理が劇的に遅くなる。
マクロの最初に `swApp.Visible = False` や、ドキュメントの再描画抑制(`swModel.ViewZoomtofit2` などの余計な操作を排除)を行い、処理が終わるまで画面更新をサスペンドするのがプロの作法である。
② データベース・ファイル連携への布石
この再帰解析で得た `featName` や `featTypeName` を、そのままJSON形式やSQLite等のローカルDBへシリアライズ(直列化)することで、「社内標準モデルとの差異比較チェッカー」や「設計変更インパクト解析ツール」への応用が可能になる。
「どの親フィーチャーが消えたら、どのサブフィーチャーが連鎖崩壊するか」の依存関係マップを構築するための基盤データが、まさにこのコードから生み出されるのだ。
—
総括
APIの奥底にある `GetFirstSubFeature` と再帰アルゴリズムの組み合わせは、SolidWorks VBAプログラミングにおける一つの「到達点」である。
表面的なラッパー関数の使用にとどまらず、オブジェクトの階層構造を自らの手で解き明かすコードを書けるようになれば、あなたが作る自動化ツールの信頼性は飛躍的に向上する。現場のエンジニアたちを「おっ」と言わせる、堅牢で美しいアーキテクチャを、ぜひあなたのプロジェクトへ実装してほしい。
