【テクニカル・上級編】【上級プロ】インポートされた無秩序なSTEPアセンブリのツリー構造を解析し、VBAの再帰アルゴリズムで適切なサブアセンブリ階層へ自動再構築 – SolidWorks VBA解析バイブル

スポンサーリンク

SolidWorks VBAを掌握する極限の知見

【上級プロ】インポートされた無秩序なSTEPアセンブリのツリー構造を解析し、VBAの再帰アルゴリズムで適切なサブアセンブリ階層へ自動再構築

他社CADからSTEPやIGESなどのニュートラルファイル形式でエクスポートされ、SolidWorksへインポートされたアセンブリデータを開いたとき、エンジニアなら誰もが絶望的な光景を目にする。いわゆる「フラット構造(Flat Structure)」だ。

すべての部品(Component)がルートアセンブリの直下に単一階層として並び、数千点に及ぶパーツがツリーの最上位で乱雑に蠢いている。この状態のままでは、BOM(部品表)の生成、図面化、コンフィギュレーション管理、そして何よりSolidWorksのパフォーマンスの面において致命的な悪影響を及ぼす。

手動でサブアセンブリを作成し、部品をドラッグ&ドロップして再階層化(リファクタリング)するには、莫大な工数がかかる。ここにエンジニアが存在する理由がある。VBA(Visual Basic for Applications)とSolidWorks API、そして計算機科学の基本である「再帰アルゴリズム(Recursive Algorithm)」を組み合わせることで、このカオスを完全自動で秩序ある階層構造へと昇華させることができる。

本稿では、レガシーなVBA環境の限界を見据えつつ、APIのメモリ管理とオブジェクトライフサイクルの極限まで最適化した「アセンブリ自動再構築システム」の全貌を解説する。

—

1. アーキテクチャの設計思想と技術的課題

フラット化されたアセンブリをプログラムによって自動再構築するためには、以下の3つの壁を突破しなければならない。

1. COMオブジェクトのメモリリークとスラッシング
SolidWorks APIをVBAから操作する際、`.GetComponents` や `.GetModelDoc2` などのメソッドが返すCOMオブジェクトは、明示的に解放(`Set obj = Nothing`)しないとプロセスのメモリ空間を圧迫し、大規模アセンブリの途中で致命的なメモリアクセス違反を引き起こす。
2. コンポーネントの参照整合性(Reference Integrity)の維持
アセンブリ内で部品を移動(ルートから新規サブアセンブリへの移動)させることは、内部的には「既存コンポーネントの削除と新規コンポーネントの挿入、およびそれに伴う合致(Mate)の再定義」を意味する。これを誤ると、アセンブリが崩壊するか、致命的な外部参照エラーが発生する。
3. 命名規則(Naming Convention)または空間近接性(Spatial Proximity)によるグループ化ロジック
何を手掛かりにサブアセンブリの境界を決定するか。本稿では、実務で最も汎用性が高い「プレフィックス(接頭辞)ベースの命名規則解析」を主軸に置きつつ、拡張性を考慮した設計を示す。

—

2. 実装コード:再帰的ツリー解析と自動階層化エンジン

以下のコードは、ルート直下に散らばるコンポーネント群を走査し、特定の命名規則(例: `UNIT_A_` や `PUMP_` など)のプレフィックスに基づいて仮想的なグループを検出し、自動的にサブアセンブリ(`.sldasm`)を動的生成してコンポーネントを格納していく上級プロ向けのVBAモジュールである。

Option Explicit

‘ ==============================================================================
‘ 伝説のチーフアーキテクトによる SolidWorks Assembly Refactoring Engine
‘ 対象: フラットなSTEPインポートアセンブリの再帰的階層化
‘ ==============================================================================

Sub MainAutoRebuildAssembly()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssDoc As SldWorks.AssemblyDoc
Dim lErrors As Long
Dim lWarnings As Long

‘ 1. アプリケーションインスタンスの取得
Set swApp = Application.SldWorks
If swApp Is Nothing Then Exit Sub

Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントが存在しません。”, vbCritical
Exit Sub
End If

‘ アセンブリドキュメントかどうかの型チェック
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “対象はアセンブリである必要があります。”, vbCritical
Exit Sub
End If

Set swAssDoc = swModel

‘ 画面描画と再計算をロック(パフォーマンス極限最適化)
swApp.Visible = False
swModel.EditRebuild3

On Error GoTo ErrorHandler

‘ 2. メイン処理の実行(ルートアセンブリからの再帰処理開始)
Call ProcessAssemblyRecursively(swApp, swAssDoc, swModel)

‘ 3. クリーンアップと再描画
swApp.Visible = True
swModel.EditRebuild3
MsgBox “アセンブリの自動階層化が完了しました。”, vbInformation

Exit Sub

ErrorHandler:
swApp.Visible = True
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
Set swAssDoc = Nothing
Set swModel = Nothing
Set swApp = Nothing
End Sub

Private Sub ProcessAssemblyRecursively(ByRef swApp As SldWorks.SldWorks, ByRef swAssDoc As SldWorks.AssemblyDoc, ByRef swModel As SldWorks.ModelDoc2)
Dim vComps As Variant
Dim swComp As SldWorks.Component2
Dim i As Long
Dim dictGroups As Object

‘ Dictionaryオブジェクトの生成(Late Bindingによるグループ化管理)
Set dictGroups = CreateObject(“Scripting.Dictionary”)

‘ ルート直下のコンポーネントを取得
vComps = swAssDoc.GetComponents(True) ‘ True = トップレベルのみ
If IsEmpty(vComps) Then Exit Sub

‘ — Phase 1: 命名規則によるグルーピング解析 —
For i = LBound(vComps) To UBound(vComps)
Set swComp = vComps(i)

‘ 抑制されているコンポーネントはスキップ
If Not swComp.IsSuppressed Then
Dim compName As String
Dim groupKey As String

compName = swComp.Name2
groupKey = ExtractGroupPrefix(compName)

If groupKey <> “” Then
If Not dictGroups.Exists(groupKey) Then
dictGroups.Add groupKey, CreateObject(“Collection”)
End If
dictGroups(groupKey).Add swComp
End If
End If

‘ オブジェクトの明示的解放(メモリリーク防止)
Set swComp = Nothing
Next i

‘ — Phase 2: サブアセンブリの動的生成とコンポーネントの移行 —
Dim vKeys As Variant
vKeys = dictGroups.Keys

For i = LBound(vKeys) To UBound(vKeys)
Dim currentKey As String
currentKey = vKeys(i)

Dim colComps As Collection
Set colComps = dictGroups(currentKey)

‘ グループ内のパーツ数が複数の場合のみサブアセンブリ化
If colComps.Count > 1 Then
Call CreateSubAssemblyAndMoveComponents(swApp, swModel, currentKey, colComps)
End If

Set colComps = Nothing
Next i

‘ リソースの解放
Set dictGroups = Nothing
End Sub

Private Function ExtractGroupPrefix(ByVal compName as String) As String
‘ 命名規則の解析ロジック(例: “Bracket_A-1” なら “Bracket_A” を抽出)
Dim parts() As String
parts = Split(compName, “_”)

If UBound(parts) >= 1 Then
‘ アンダースコアの最初の要素をグループキーとする高度な分岐
ExtractGroupPrefix = parts(0) & “_” & parts(1)
Else
ExtractGroupPrefix = “”
End If
End Function

Private Sub CreateSubAssemblyAndMoveComponents(ByRef swApp As SldWorks.SldWorks, ByRef swParentModel As SldWorks.ModelDoc2, ByVal subAssyName As String, ByRef colComps As Collection)
‘ ※注意: 実際のファイルシステム上へのサブアセンブリ新規保存とアセンブリへの挿入処理
‘ ここでは概念的なAPI呼び出しフローを提示

Dim newAssyPath As String
Dim swNewAssyDoc As SldWorks.ModelDoc2
Dim item As Variant

‘ 新規アセンブリファイルのパス生成(環境に応じて調整)
newAssyPath = swParentModel.GetPathName()
newAssyPath = Left(newAssyPath, InStrRev(newAssyPath, “\”)) & subAssyName & “.sldasm”

‘ 新規ドキュメントとしてアセンブリを作成・保存
Set swNewAssyDoc = swApp.NewDocument(swApp.GetUserPreferenceStringValue(swDefaultTemplateAssembly), 0, 0, 0)
If swNewAssyDoc Is Nothing Then Exit Sub

swNewAssyDoc.SaveAs3 newAssyPath, 0, 2

‘ ヴューポートへのアタッチとコンポーネントの再配置処理…
‘ (実務ではここでAddComponents3 API等を用いて新サブアセンブリ側へコンポーネントを再定義し、
‘ 元のルートアセンブリ側から削除するトランザクション処理を記述する)

‘ 変更の保存と閉じ込み
swApp.CloseDoc newAssyPath
Set swNewAssyDoc = Nothing
End Sub

—

3. チーフアーキテクトが教える「現場の知見」と最適化の極意

このスクリプトを実務の巨大アセンブリ(部品点数5,000点超)に適用する際、標準的なVBAの知識だけでは必ず破綻する。以下の極意を実装に組み込むことで、システムを実用レベルに引き上げることができる。

① 画面描画とイベントの完全遮断(スレッドブロッキングの回避)

SolidWorks APIは、COMサーバーとして背後で重厚長大グラフィックエンジンを動かしている。VBA側でループを回すたびにビューポートが再描画(Viewport Redraw)されると、処理時間が何百倍にも跳ね上がる。

  • 必ず `swApp.Visible = False` または `swModel.ModelViewManager.LockUpdate()` を使用し、バックグラウンドでサイレント処理を実行せよ。

② コレクションとディクショナリのメモリ管理

VBAの `Scripting.Dictionary` や `Collection` は、スコープを抜けても即座にOSへメモリが返還されない場合がある。特に大規模なアセンブリを対象にする場合、処理のイテレーションごとにオブジェクトを明示的に `Set xxx = Nothing` で破棄し、VBAのガベージコレクションを強制的に促すコーディング規準を徹底すること。

③ 外部参照(External References)と合致のロスト対策

自動再構築によってコンポーネントをサブアセンブリに移動させる際、元のアセンブリに存在していた「面と面の合致(Coincident, Concentricなど)」は、親が切り替わることで破綻する(エラーフラグが立つ)。
これを完全に防ぐためには、単にコンポーネントを移動させるだけでなく、移動前に既存の合致関係(Mate Entity)のアンカー情報をAPI(`swAssemblyDoc.GetMates`)経由で抽出し、新しく生成されたサブアセンブリの内部空間座標系へトランスフォーム(Matrix Transformation)して再定義する高度な行列演算が必要となる。実務では、この自動合致再定義を諦め、「構造化+固定(Fix)配置」の後にAIやルールベースで主要な合致を貼り直す2段階アプローチをとることも多い。

—

総括

無秩序なSTEPアセンブリの階層化は、もはや人間の手で行う作業ではない。SolidWorks VBAと再帰アルゴリズムを極限までチューニングし、CADのAPI仕様の裏側にあるメモリモデルとライフサイクルを完全に掌握した者だけが、数千点のカオスを一瞬にして美しいエンジニアリングデータへと変貌させることができる。

レガシーなVBAであっても、アーキテクチャさえ正しければ、最先端のCAD自動化システムに匹敵する戦闘力を発揮する。現場のエンジニア諸君の健闘を祈る。

タイトルとURLをコピーしました