アセンブリの「負の遺産」を殲滅せよ:重複コンポーネントを排除するVBA極限最適化術
設計の現場において、アセンブリファイルは時として「ゴミ屋敷」と化す。設計変更の履歴が積み重なり、見えない場所に重なった同一部品、あるいは構成管理から逸脱した幽霊のようなインスタンス。これらはモデルの再構築時間を増大させ、PDMとの連携において致命的なコンフリクトを引き起こす。
本稿では、SolidWorks APIを使い倒し、重複コンポーネントを論理的に特定・削除する「クリーンアップ・アルゴリズム」の深淵に迫る。VBAという古き良き言語を使いながらも、メモリ管理と計算量に配慮した、プロフェッショナルが実装すべきコードを提示する。
—
1. 重複判定の本質:名前か、IDか、それとも「位置」か
単純に「ファイル名が同じだから重複」と見なすのは素人仕事だ。我々が対峙すべきは、「コンポーネントID(Instance ID)」と「コンポーネントの変換行列(Transform Matrix)」である。
- 同一IDの重複: 基本的にSolidWorksのアセンブリ構造上発生しないが、破壊されたフィーチャーデータにより稀に発生する。
- 実質的な重複: ファイル名が同一かつ、配置座標(変換行列)が完全に一致、あるいは極めて近いもの。
これらを判定するには、`IComponent2` インターフェースの `GetTransform` メソッドから得られる行列の各要素を比較し、微小な浮動小数点誤差(イプシロン)を考慮した判定を行う必要がある。
—
2. 破壊的処理を安全に行うためのアーキテクチャ
アセンブリ操作において最も恐ろしいのは、削除したことによる「合致(Mate)の破綻」ではない。「削除したはずのオブジェクトへのポインタがメモリ上に残り、後続の処理でAccess Violation(メモリ違反)を引き起こすこと」である。
実装のポイント
1. SelectionManagerの利用: 削除対象を明示的に選択し、`IModelDoc2::DeleteSelection2` を用いる。
2. オブジェクトの明示的解放: `Set obj = Nothing` をループの最後に行うのは当然だが、さらに `DoEvents` を適切に挟むことで、バックグラウンドの描画処理と同期させる。
3. Undoスタックの制御: 処理の開始と終了で `IModelDoc2::BeginUndoGroup` / `EndUndoGroup` を使い、万が一の際に一括ロールバックを可能にする。
—
3. 実装コード:重複コンポーネント・クリーナー
このコードは、カレントアセンブリ内のコンポーネントをスキャンし、同一ファイル名かつ同一座標の部品を特定して削除する。
Option Explicit
‘ 重複削除のメインプロシージャ
Public Sub CleanUpDuplicateComponents()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim vComps As Variant
Dim i As Long, j As Long
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel.GetType <> swDocASSEMBLY Then Exit Sub
Set swAssy = swModel
swModel.BeginUndoGroup
‘ 全コンポーネント取得
vComps = swAssy.GetComponents(False)
‘ ここでコレクションや配列を使い、重複比較アルゴリズムを回す
‘ 計算量は O(N^2) になるため、大規模アセンブリでは注意が必要
For i = LBound(vComps) To UBound(vComps)
For j = i + 1 To UBound(vComps)
If IsDuplicate(vComps(i), vComps(j)) Then
‘ 重複と判定されたコンポーネントを選択して削除
vComps(j).Select4 False, Nothing, False
swModel.DeleteSelection2 False
Debug.Print “Removed: ” & vComps(j).Name2
End If
Next j
Next i
swModel.EndUndoGroup
MsgBox “クリーンアップ完了”
End Sub
‘ 変換行列に基づいた厳密な一致判定
Private Function IsDuplicate(comp1 As SldWorks.Component2, comp2 As SldWorks.Component2) As Boolean
‘ 1. ファイル名チェック
If comp1.GetPathName <> comp2.GetPathName Then Exit Function
‘ 2. 変換行列の比較 (簡易版: 各要素の差が微小か)
Dim m1 As Variant, m2 As Variant
m1 = comp1.GetTransform.ArrayData
m2 = comp2.GetTransform.ArrayData
Dim k As Integer
For k = 0 To 15
If Abs(m1(k) – m2(k)) > 0.000001 Then Exit Function
Next k
IsDuplicate = True
End Function
—
4. シニアエンジニアのための「極限の知見」
メモリとパフォーマンスの制御
`GetComponents` はアセンブリの深さに関わらず全コンポーネントをフラットに取得する。数千パーツを超えるような巨大アセンブリの場合、この処理はメインスレッドを長時間占有する。
もしシステムがフリーズする場合は、`Win32 API` の `GetTickCount` 等を使い、一定時間ごとに制御をOSに戻す「タイムスライス」を組み込むべきだ。
Windows APIとの連携による堅牢性
自動化プロセス中にSolidWorksが「応答なし」になることを防ぐため、`RegisterWindowMessage` 等を用いて、現在の処理状況を外部の監視ツールへ送信する仕組みを実装することも検討してほしい。これは、社内システム管理者として、自動化プロセスの死活監視を行う上で必須のスキルである。
最後に
VBAはレガシーと言われるが、SolidWorksのCOMインターフェースを直接叩く力において、これに勝る直感的なツールは未だ存在しない。アセンブリの整理は、設計者の思考を整理することと同義である。
無駄なインスタンスを排除し、軽快なモデル環境を作る。それこそが、我々エンジニアが追求すべき「デジタル上の断捨離」なのだ。
このコードをただコピペするだけでなく、君自身の設計環境に合わせて最適化せよ。それが、真のアーキテクトへの第一歩となる。
