こんにちは!SolidWorks自動化の現場で泥臭く、かつエレガントなコードを書き続けている先輩エンジニアです。
「マクロの記録」ボタンを押して部品を組み合わせてみたものの、ちょっと設計変更(モデル修正)が入った瞬間に、マクロがエラーの嵐で爆発した……そんな苦い経験はありませんか?
「面名(Face1, Face2など)が変わっても絶対に破綻しない、プロフェッショナルなアセンブリ合致の自動化」をテーマに、SolidWorks VBAの奥義を授けましょう。ここをクリアすれば、あなたの自動化スキルは間違いなく一段上のステージに到達しますよ!
—
なぜ「マクロの記録」による合致はすぐに壊れるのか?
まず、敵を知ることから始めましょう。
マクロの記録を使うと、以下のようなコードが出力されます。
‘ 破綻しやすい典型的なコード
boolstatus = swModel.Extension.SelectByID2(“Face1@Part1-1@Assembly”, “FACE”, 0, 0, 0, True, 0, Nothing, 0)
boolstatus = swModel.Extension.SelectByID2(“Face2@Part2-1@Assembly”, “FACE”, 0, 0, 0, True, 0, Nothing, 0)
swModel.AssemblyMates2 swAddMateCE_Coincident, swAddMateError_NoError, False, 0, 0, 0, 0, 0, 0, 0, 0, 0, False, 0
このコードの何がいけないのでしょうか?
それは、「Face1」や「Face2」というSolidWorksが勝手に振った一時的な名前(トポロジー名)に依存しているからです。
設計者がモデルのフィレットを追加したり、形状を少し修正したりしただけで、SolidWorks内部の面IDはガラリと変わります。その結果、マクロを実行すると「面が見つかりません」というエラー(Null参照)で止まってしまうのです。
ロバスト(堅牢)な合致を実現するアプローチ
モデルが変更されても壊れないようにするためには、以下のいずれかの特徴(ジオメトリ特性)を利用してプログラム的に面を「特定」する必要があります。
1. 平面の法線ベクトル(Normal Vector)と原点からの距離
2. 円柱面・穴の軸方向と半径
3. IMateEntity2インターフェースを用いた高度なエンティティのラップ
今回は、この中でも最も実用的で強力な「ジオメトリ特性(法線や形状)による面の動的抽出」と「IMateEntity2」を組み合わせた極限のテクニックを解説します。
—
実装の全体像:コードの設計図
今回は、親部品(ベース)の特定の平滑面と、子部品の平滑面をプログラム側で数学的に特定し、名前が変わろうとも正確に「一致(Coincident)」合致を組むVBAマクロを作成します。
以下のコードは、開発現場でそのままコピー&ペーストして、微調整だけで使える実用的なものです。
Option Explicit
‘ =================================================================================
‘ 伝説のチーフアーキテクト直伝:面名に依存しないロバスト合致自動化マクロ
‘ =================================================================================
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swAssy As SldWorks.AssemblyDoc
Dim swModel As SldWorks.ModelDoc2
Set swApp = Application.SldWorks
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 swAssy = swModel
‘ — Step 1: コンポーネントの取得(例:Part1 と Part2) —
Dim swComp1 As SldWorks.Component2
Dim swComp2 As SldWorks.Component2
‘ ※実際の環境にあわせてコンポーネント名(拡張子なしのファイル名)に変更してください
Set swComp1 = swAssy.GetComponentByName(“Part1-1”)
Set swComp2 = swAssy.GetComponentByName(“Part2-1”)
If swComp1 Is Nothing Or swComp2 Is Nothing Then
MsgBox “指定されたコンポーネントが見つかりません。”, vbCritical
Exit Sub
End If
‘ — Step 2: ジオメトリ特性(法線ベクトル等)から面を動的にハントする —
Dim swFaceEntity1 As SldWorks.MateEntity2
Dim swFaceEntity2 As SldWorks.MateEntity2
‘ Part1から「上向き(Z方向が+1)」の平面をプログラム的に探す
Set swFaceEntity1 = GetPlanarFaceByNormal(swComp1, 0, 0, 1)
‘ Part2から「下向き(Z方向が-1)」の平面をプログラム的に探す
Set swFaceEntity2 = GetPlanarFaceByNormal(swComp2, 0, 0, -1)
If swFaceEntity1 Is Nothing Or swFaceEntity2 Is Nothing Then
MsgBox “条件に合致する面が特定できませんでした。モデル形状を確認してください。”, vbCritical
Exit Sub
End If
‘ — Step 3: IMateEntity2 を用いた堅牢な合致の実行 —
Dim swMateData As SldWorks.MateData
Set swMateData = swAssy.CreateMateData(swMateType_Coincident, swMateAlign_ALIGNED, False, 0, 0, 0, 0, 0, 0, 0, 0, False, 0)
‘ 取得したMateEntityをセット
swMateData.AddEntities 0, swFaceEntity1
swMateData.AddEntities 1, swFaceEntity2
‘ 合致の作成実行
Dim swMate As SldWorks.Mate
Set swMate = swAssy.CreateMate(swMateData)
If Not swMate Is Nothing Then
swModel.EditRebuild3
MsgBox “面名に依存しないロバスト合致の作成に成功しました!”, vbInformation
Else
MsgBox “合致の作成に失敗しました。”, vbCritical
End If
End Sub
‘ =================================================================================
‘ 指定した法線ベクトルを持つ平面をコンポーネントのボディから動的に探す関数
‘ =================================================================================
Private Function GetPlanarFaceByNormal(swComp As SldWorks.Component2, ByVal targetNx As Double, ByVal targetNy As Double, ByVal targetNz As Double) As SldWorks.MateEntity2
Dim swBodyPrer As SldWorks.Body2
Dim swModelDoc As SldWorks.ModelDoc2
Dim swPartDoc As SldWorks.PartDoc
Set swModelDoc = swComp.GetModelDoc2
If swModelDoc.GetType() <> swDocPART Then Exit Function
Set swPartDoc = swModelDoc
‘ コンポーネントの最初のソリッドボディを取得
Dim vBodies As Variant
vBodies = swPartDoc.GetBodies2(swSolidBody, True)
If IsEmpty(vBodies) Then Exit Function
Dim swBody As SldWorks.Body2
Set swBody = vBodies(0) ‘ 簡易的に最初のボディを対象
Dim vFaces As Variant
vFaces = swBody.GetFaces
Dim i As Long
Dim swFace As SldWorks.Face2
Dim swSurface As SldWorks.Surface
For i = LBound(vFaces) To UBound(vFaces)
Set swFace = vFaces(i)
Set swSurface = swFace.GetSurface()
‘ 平面(Planar Surface)かどうかを判定
If swSurface.IsPlane() Then
Dim vParams As Variant
vParams = swSurface.PlaneParams
‘ 平面の法線パラメータ: vParams(0), vParams(1), vParams(2) が法線ベクトル(Nx, Ny, Nz)
‘ ターゲットのベクトルと一致するか比較(許容誤差 0.001)
If Abs(vParams(0) – targetNx) < 0.001 And _
Abs(vParams(1) - targetNy) < 0.001 And _
Abs(vParams(2) - targetNz) < 0.001 Then
' 見つかった場合、アセンブリコンテキストに適合した MateEntity2 を作成して返す
Dim swAssyDoc As SldWorks.AssemblyDoc
Set swAssyDoc = swComp.GetParent().GetModelDoc2 ' 階層構造に注意
' MateEntity2の生成(IMateEntity2)
Dim swMateEnt As SldWorks.MateEntity2
Set swMateEnt = swAssyDoc.CreateMateEntity(swComp, swFace, swConstrainedFace_Plane, 0, 0)
Set GetPlanarFaceByNormal = swMateEnt
Exit Function
End If
End If
Next i
Set GetPlanarFaceByNormal = Nothing
End Function
---
コードの核心:なぜこの方法が「神」なのか?
ここが一番重要なポイントです。コードの肝を分かりやすく解説します。
1. トポロジー名(Face1など)を一切見ない
`GetPlanarFaceByNormal`関数の中では、面の名前(Name)を1回も参照していません。
代わりに、「面の数式(サーフェスの数学的定義)」にアクセスしています。
`swSurface.IsPlane()` でそれが平面であることを確認し、`vParams`(法線ベクトル)を取り出して「上向きの面か?」「下向きの面か?」を数学的に判定しています。そのため、設計者がその面の面積を広げようが、フィレットを追加して形状が微妙に変わろうが、「上を向いている平面」という本質が変わらない限り、プログラムは一発でその面を捉え続けます。
2. IMateEntity2 と CreateMateEntity の魔法
従来の古いAPIでは、画面上で面を選択状態(SelectByID2など)にしてから合致コマンドを発行していましたが、これだと画面の描画や選択の競合(他が選択されている等)でバグの温床になりました。
現代のSolidWorks API(上級アプローチ)では、`IMateEntity2` インターフェースを使用します。
`AssemblyDoc.CreateMateEntity` メソッドを使うことで、画面上で「手動選択」を一切行わずに、メモリ上で直接「このコンポーネントの、このFace2オブジェクトを合致エンティティとしてラップする」ことが可能です。
これにより、画面がチラつかず、爆発的な高速化と圧倒的な安定性を手に入れることができます。
—
陥りやすいエラーと現場の知恵
1. 法線ベクトルの向き(正負)の罠
- モデルの作成方向や押し出しの向きによって、法線ベクトルが逆(`+Z`ではなく`-Z`)になることがあります。マクロが面を見つけられないときは、イミディエイトウィンドウに `vParams` の値を書き出すデバッグコードを挟んで、実際のベクトル値を確認するのがプロの技です。
2. アセンブリの階層(コンポーネントの深さ)
- サブアセンブリ(アセンブリの中のアセンブリ)に含まれる部品を操作する場合、`GetComponentByName` のパス指定が変わります(例:`SubAssy-1/Part1-1`)。マルチ階層の場合は、再帰的なコンポーネント探索ロジックを組む必要がありますが、まずは単一アセンブリのマスターから始めてみてください。
—
まとめ
今回は、面名に依存しないロバストな合致自動化の極意を解説しました。
- マクロの記録の `SelectByID2` は現場では使わない(モデル変更で即破綻するため)
- `Surface` オブジェクトの数学的特性(法線ベクトルや半径)を利用して動的に面をハントする
- `IMateEntity2` を活用してメモリ上でスマートに合致を定義する
ここをクリアできれば、あなたの作るSolidWorksマクロは、単なる「おもちゃの自動化」から、現場の設計ミスを防ぐ「堅牢なエンジニアリングツール」へと生まれ変わります。
ぜひ、あなたの設計自動化ワークフローに取り入れて、圧倒的な効率化を実感してください。それでは、また次の極限の知見でお会いしましょう!
