序文:なぜあなたの合致(Mate)は「壊れる」のか
SolidWorks APIを操るエンジニアにとって、アセンブリ自動化の最大の壁は「モデル変更への耐性」だ。
マクロ記録から生成されたコードや、単純な `SelectByID2` に頼る実装は、部品の形状が少し変わっただけで「エンティティが見つかりません」という無慈悲なエラーを吐き、停止する。これは内部的なID(Persistent ID)が、フィーチャーの再構築やフィレットの追加といったトポロジー(位相)の変化によって容易に変質してしまうからだ。
真のアーキテクトが目指すべきは、「形状を解釈し、意図を再定義する」ロバストなエンジンである。本稿では、`IMateEntity2` を核とし、幾何学的特徴量からターゲットを動的に特定する「幾何学的シグネチャ照合」の実装戦略を詳解する。
—
1. IMateEntity2:抽象化された合致のインターフェース
合致を定義する際、我々は `ModelDoc2.AddMate5` を呼び出すが、その引数に渡すべきは単なる `Entity` ではない。`IMateEntity2` は、合致に関与するエンティティ(面、エッジ、点)をラップし、合致のパラメータ(整列、オフセット等)を保持する高度なオブジェクトだ。
このオブジェクトを直接操作することで、以下の利点が得られる。
1. 選択依存からの脱却: `SelectByID2` を介さず、メモリ上のオブジェクト参照だけで完結する。
2. 実行時の動的変更: 合致が作成される直前に、そのパラメータをプログラム側で微調整できる。
—
2. トポロジー変更検知と幾何学的シグネチャ
形状変更に強いコードを書くための鉄則は、「IDを信じず、幾何学的特徴(面法線、面積、重心)を信じる」ことだ。
幾何学的シグネチャの定義例
特定の面を特定するために、以下のプロパティを組み合わせた「ハッシュ値」に近い概念を導入する。
- Surface Type: 平面か、円筒面か(`ISurface::IsPlane`)。
- Normal Vector: 面の法線方向(アセンブリ座標系への変換が必要)。
- Bounding Box Center: 面の幾何学的な中心点。
- Area: 面の面積(微小な変更を許容する閾値設定が必要)。
—
3. 実践:ロバスト合致定義エンジンの実装
以下のコードは、特定のコンポーネントから「最も面積が広く、かつ特定の方向を向いている平面」を動的に探索し、合致を定義するプロトタイプだ。
‘
‘ Module: RobustMateEngine
‘ Description: 形状変更に強い動的エンティティ抽出とIMateEntity2による合致定義
‘
Option Explicit
‘ Windows API: メモリ消費量監視(大規模アセンブリ用)
Private Declare PtrSafe Sub GlobalMemoryStatusEx Lib “kernel32″ (ByRef lpBuffer As MEMORYSTATUSEX)
Private Type MEMORYSTATUSEX
dwLength As Long
dwMemoryLoad As Long
ullTotalPhys As Currency
ullAvailPhys As Currency
‘ … 他のフィールドは省略
End Type
”’
”’
Public Sub CreateRobustMate(ByRef swApp As SldWorks.SldWorks, ByRef swAssy As SldWorks.AssemblyDoc)
Dim swModel As SldWorks.ModelDoc2: Set swModel = swAssy
Dim swComp As SldWorks.Component2
Dim swBody As SldWorks.Body2
Dim swFace As SldWorks.Face2
Dim swTargetFace As SldWorks.Face2
Dim maxArea As Double: maxArea = -1
‘ 1. コンポーネントの取得(例:アクティブな選択または特定の名前から)
‘ ここでは簡略化のため、最初のコンポーネントを対象とする
Dim vComps As Variant: vComps = swAssy.GetComponents(False)
Set swComp = vComps(0)
‘ 2. トポロジー解析アルゴリズム
‘ IDではなく、幾何学的性質(面積最大、法線がZ+方向など)で面を特定する
Set swBody = swComp.GetBody
Set swFace = swBody.GetFirstFace
Do While Not swFace Is Nothing
Dim swSurf As SldWorks.Surface: Set swSurf = swFace.GetSurface
If swSurf.IsPlane Then
‘ 面積の取得
Dim currentArea As Double: currentArea = swFace.GetArea
‘ ここで法線方向の判定(swFace.Normal)などを組み合わせる
If currentArea > maxArea Then
maxArea = currentArea
Set swTargetFace = swFace
End If
End If
Set swFace = swFace.GetNextFace
Loop
If swTargetFace Is Nothing Then Exit Sub
‘ 3. IMateEntity2 による合致定義
Dim swMateEnt As SldWorks.MateEntity2
Set swMateEnt = swComp.CreateMateEntity(swTargetFace)
‘ ここで、もう一方の合致相手(例:アセンブリの基準面)も同様に取得
‘ swAssy.AddMate5(…) の引数として、抽出したエンティティを渡す
‘ 4. オブジェクトの明示的解放(メモリリーク防止)
‘ 大規模ループ内ではこれを怠ると、SolidWorksのプロセスが肥大化しクラッシュする
Set swMateEnt = Nothing
Set swTargetFace = Nothing
Set swBody = Nothing
End Sub
—
4. プロフェッショナルのための最適化知見
① COM参照カウンタの意識
VBAからSolidWorks APIを叩く際、`Do While Not swFace Is Nothing` のようなループで数万個のエンティティを走査する場合、各オブジェクトはCOMラッパーとしてメモリに蓄積される。`Set obj = Nothing` は、参照カウンタを減らすために不可欠だ。特に大規模アセンブリのバッチ処理では、これを行わないと「アウト・オブ・リソース」で沈む。
② Windows APIによるリソース管理
大規模な自動生成を行う際、SolidWorksのメモリ消費を監視し、一定の閾値を超えたら `swApp.CloseAllDocuments` を実行し、自分自身を再起動するようなウォッチドッグ(監視)機能をVBA側に持たせるべきだ。
③ レガシーコードとの共存
古いモデルには、`Name` が付与されていないエンティティが多々ある。最新の `IMateEntity2` を使いつつ、フォールバック(代替策)として、一時的に `Entity::Select4` を使用して選択バッファに入れ、`AddMate5` に流し込むハイブリッド手法も検討に値する。しかし、その場合も「選択解除(ClearSelection2)」を即座に行い、選択セットを汚染しないのが鉄則だ。
—
5. 結論:コードの「寿命」を設計せよ
初心者は「動くコード」を書く。中級者は「速いコード」を書く。だが、我々チーフアーキテクトは「保守の要らない、死なないコード」を書かなければならない。
トポロジー変更を前提とした動的なエンティティ検索エンジンを構築することは、初期コストこそ高いが、将来的な設計変更に伴うマクロの修正工数をゼロに近づける唯一の道だ。`IMateEntity2` を使いこなし、形状のDNAを解析するロジックを組み込むことで、あなたのシステムは「CAD操作の自動化」から「設計意図の自動継承」へと昇華するだろう。
この次元のエンジニアリングこそが、真に価値のある業務自動化の姿である。
