SolidWorks VBAを掌握する極限の知見
【上級プロ】IMateEntity2を用いた高度な面・エッジのプログラム的抽出と、面名変更に左右されないロバスト合致
SolidWorksマクロの自動化において、最も脆弱なポイントはどこか。それは「面の名前(Name)や内部IDに依存した合致(Mate)の構築」である。
CADモデルの設計変更に伴い、フィーチャーの順序が入れ替わったり、フィレットが追加されたりすると、`Face@Part1-1` といった文字列ベースの参照は一瞬で破綻する。コンパイルエラーこそ起きなくとも、実行時に「参照が見つかりません」という冷酷なエラーダイアログがエンジニアの画面を塞ぐ。レガシーなVBA環境や、度重なる仕様変更に耐えなければならない社内システムにおいて、この「面名の変更に弱い」という特性は致命傷になり得る。
我々は、この泥臭い属人性を完全排除しなければならない。本記事では、`IMateEntity2` インターフェイスを駆使し、ジオメトリ特性やトポロジー(位相幾何学)情報を直接解析してターゲットをプログラム的に抽出・固定化する、極限のロバスト合致構築術を公開する。
—
1. なぜ「面名」に依存してはならないのか
SolidWorksのB-Rep(境界表現)モデルにおいて、面やエッジの内部ID(Persistent ID / Tag)は、モデリングの履歴が更新されるたびに再割当てされるリスクを孕んでいる。特にアセンブリのコンテキスト内で外部参照を持つ場合、コンポーネントの再評価(Rebuild)によってエンティティ名が変わるのは日常茶飯事だ。
この呪縛から逃れる唯一の手段が、「ジオメトリの数学的特性(法線ベクトル、曲率、中心座標、面積など)を動的に評価し、`IMateEntity2` を通して直接ポインタをバインドする」 ことである。
[従来の脆弱なアプローチ]
面名文字列 (“Face1@Part1”) -> モデル変更で崩壊
[極限のロバストアプローチ]
形状解析ロジック -> 物理的特徴の一致 -> IMateEntity2生成 -> 合致定義(完全同期)
—
2. `IMateEntity2` とメモリ管理の鉄則
`IMateEntity2` は、合致を作成する際に「どのエンティティの、どの位置を、どう拘束するか」をSolidWorksのソルバーに伝えるための最強の抽象化レイヤーである。
しかし、VBA環境下においてCOMオブジェクトをむやみに生成・放置することは、メモリリークやSolidWorks自体の不安定化(最悪の場合はクラッシュ)を招く。
チーフアーキテクトとしての鉄則として、取得したCOMオブジェクトはスコープの抜け際、あるいはループの各イテレーションの終わりで明示的に `Nothing` 代受け渡しによる参照解放を行う こと。これを怠るな。
—
3. 実装コード:ジオメトリ特性に基づくロバスト合致の自動生成
以下に、指定したパーツから「最大の平らな面(底面など)」をプログラム的に算出し、名前の変更に一切影響されることなく、別のパーツの基準面と一致(Coincident)させる実用的なVBAコードを示す。
Option Explicit
‘ ==============================================================================
‘ チーフアーキテクト専用モジュール: ジオメトリ駆動型ロバスト合致エンジン
‘ ==============================================================================
Sub Main_RobustMateExecution()
Dim swApp As SldWorks.SldWorks
Dim swAssy As SldWorks.AssemblyDoc
Set swApp = Application.SldWorks
Set swAssy = swApp.ActiveDoc
If swAssy Is Nothing Then
MsgBox “アクティブなドキュメントがアセンブリではありません。”, vbCritical
Exit Sub
End If
‘ 処理の高速化と画面描画のロック(メモリ・CPU最適化)
swApp.UserControl = False
swAssy.EditRebuild
Dim targetCompName As String
Dim baseCompName As String
targetCompName = “Plate-1” ‘ 動的に特定するコンポーネント名
baseCompName = “Base-1”
‘ 1. ターゲットコンポーネントから「最大面積を持つ平面」のIMateEntity2を動的抽出
Dim swMateEntTarget As SldWorks.MateEntity2
Set swMateEntTarget = GetLargestPlanarFaceEntity(swAssy, targetCompName)
‘ 2. 基準コンポーネントから対応する合致面を取得
Dim swMateEntBase As SldWorks.MateEntity2
Set swMateEntBase = GetLargestPlanarFaceEntity(swAssy, baseCompName)
If swMateEntTarget Is Nothing Or swMateEntBase Is Nothing Then
MsgBox “条件に合致するジオメトリエンティティが見つかりませんでした。”, vbExclamation
GoTo CleanUp
End If
‘ 3. 合致の定義と実行
Dim swMateDoc As SldWorks.Mate2
Dim errCode As Long
‘ Coincident (一致) 合致の作成
Set swMateDoc = swAssy.AddMate3( _
swMateType_e.swMateCOINCIDENT, _
swMateAlign_e.swMateAlignALIGNED, _
False, _
0.001, 0.001, 0.001, _
0, 0, 0, 0, 0, _
False, errCode)
If errCode = 0 Then
Debug.Print “【成功】面名に依存しないロバスト合致の構築に成功しました。”
Else
Debug.Print “【失敗】合致エラーコード: ” & errCode
End If
CleanUp:
‘ 4. 厳格なメモリ解放 (COMオブジェクトの参照リーク防止)
Set swMateEntTarget = Nothing
Set swMateEntBase = Nothing
Set swMateDoc = Nothing
Set swAssy = Nothing
Set swApp = Nothing
swApp.UserControl = True
End Sub
‘ ==============================================================================
‘ 補助関数: 指定コンポーネントから最大の平面を数学的評価で抽出し、IMateEntity2を返す
‘ ==============================================================================
Private Function GetLargestPlanarFaceEntity(swAssy As SldWorks.AssemblyDoc, compName As String) As SldWorks.MateEntity2
Dim swComp As SldWorks.Component2
Set swComp = swAssy.GetComponentByName(compName)
If swComp Is Nothing Then Exit Function
Dim swModel As SldWorks.ModelDoc2
Set swModel = swComp.GetModelDoc2
Dim swBodyArr As Variant
swBodyArr = swComp.GetBodies2(swBodyType_e.swSolidBody)
If IsEmpty(swBodyArr) Then Exit Function
Dim swBody As SldWorks.Body2
Set swBody = swBodyArr(0) ‘ 単一ボディを想定
Dim swFace As SldWorks.Face2
Set swFace = swBody.GetFirstFace()
Dim maxArea As Double
maxArea = -1
Dim bestFace As SldWorks.Face2
Set bestFace = Nothing
‘ トポロジーを走査し、最大の平面を特定
Do While Not swFace Is Nothing
Dim swSurface As SldWorks.Surface
Set swSurface = swFace.GetSurface()
‘ 平面(Planar Surface)であるかを判定
If swSurface.IsPlane() Then
Dim areaProps As Variant
areaProps = swFace.GetAreaProperties() ‘ [0:Area, 1-3:Centroid, etc.]
If areaProps(0) > maxArea Then
maxArea = areaProps(0)
Set bestFace = swFace
End If
End If
Set swFace = swFace.GetNextFace()
Loop
If bestFace Is Nothing Then Exit Function
‘ Face2 から MateEntity2 を生成する
Dim swModelDocExt As SldWorks.ModelDocExtension
Set swModelDocExt = swModel.Extension
Dim swMateEnt As SldWorks.MateEntity2
‘ アセンブリコンテキストにおけるエンティティ生成
Set swMateEnt = swAssy.CreateMateEntity(swComp, bestFace, swSelectType_e.swSelFACES, 0, 0, 0)
Set GetLargestPlanarFaceEntity = swMateEnt
‘ 局所オブジェクトの解放
Set bestFace = Nothing
Set swBody = Nothing
Set swModel = Nothing
Set swComp = Nothing
End Function
—
4. アーキテクチャの要点:なぜこのコードが「極限」なのか
1. 名前からの完全な脱却
コード内では `Face1` や `Extrude1` といった文字列を一切検索していない。モデルがどうリネームされようとも、「最も面積の大きい平面」という不変の数学的特徴量を追うため、上流の設計変更に対して完全に無敵(ロバスト)である。
2. `CreateMateEntity` によるアセンブリ文脈の保持
単なるパーツ内の面ではなく、アセンブリ(AssemblyDoc)の文脈上におけるコンポーネントの位置・姿勢を加味した `IMateEntity2` を生成しているため、上位アセンブリでの拘束においても座標変換のズレが生じない。
3. リソースの徹底管理
VBAのガベージコレクションはあてにならない。特にSolidWorks APIを大量に叩くループ処理内では、明示的な `Set Object = Nothing` を記述しなければ確実にメモリが肥大化する。本コードはその鉄則を忠実に守っている。
—
5. 総括
実現場における自動化スクリプトの価値は、「動くこと」ではなく、「仕様変更やモデルの改修が行われても、絶対に壊れないこと」にある。
面名に依存したレガシーなアプローチを捨て、`IMateEntity2` とジオメトリ解析を組み合わせたこのアーキテクチャを導入せよ。それこそが、シニアエンジニアに求められる真の堅牢性である。
