こんにちは!SolidWorks自動化の現場で泥臭く、かつ優雅にプログラムを書き続けている先輩エンジニアです。
皆さんは、こんな絶望を味わったことがありませんか?
「マクロの記録でコードを作ったのに、モデルのサイズを変えたり、押し出しの方向を反転させたりしたら、フィレット(角丸め)や面取りがパーッと消えやがった……!」
そう、SolidWorksのマクロ記録機能は素晴らしい入門ツールですが、エッジに振られた内部ID(例: `Edge<1>`)という名の「呪い」をそのまま記録してしまいます。少しでもモデルが変わり、フィーチャのトポロジー(位相幾何学)が再計算されると、IDがズレてマクロは盛大にエラーを吐く。これが「マクロの記録の限界」です。
今回は、この呪縛を完全に断ち切る極意をお伝えします。
「コード内のエッジ名に一切頼らず、マクロ実行時の『面の法線方向』をベクトル計算で解析し、狙った平滑面のエッジを一網打尽にしてフィレットをかける」という、実務で即戦力になるテクニックです。
ここをクリアすれば、あなたのSolidWorks VBAスキルは「初学者」の領域を抜け出し、一気にプロの仲間入りです。さあ、一緒に扉を開けましょう!
—
なぜ「エッジ名」に頼ってはいけないのか?
SolidWorksのAPIにおいて、エッジや面は「Body(ボディ)」という親オブジェクトの中に存在しています。しかし、人間が画面上で見る「一番上の角」という認識と、APIが裏側で管理しているエッジのインデックスは、形状がわずかに変わるだけで簡単に入れ替わります。
そこで私たちが取るべきアプローチは、こうです。
1. 「点や線」ではなく「面(Face)」に着目する。
2. 形状が変わっても変わらない不変の物理法則、すなわち「面の法線ベクトル(Normal Vector)」を調べる。
3. 「上向き(Z方向)を向いている平滑面」といった条件に合致する面を動的に見つけ出し、その面を取り囲むエッジ(境界)をプログラムに自動で抽出させる。
このアプローチをマスターすれば、形状が変形しようが、モデルが巨大化しようが、寸分違わず狙ったエッジにフィレットをかけられる「ロバスト(堅牢)なマクロ」が完成します。
—
実装の全体像とアーキテクチャ
今回作成するVBAコードの流れは以下の通りです。
1. アクティブなドキュメント(パーツ)を取得する。
2. ソリッドボディ(`Body2`)を安全に取得する。
3. ボディからすべての面(`Face2`)を配列として取り出す(これが `Body2.GetFaces` の役割です!)。
4. 取り出した面を1枚ずつループし、法線ベクトルを解析する。
5. 「平滑面(平面)」であり、かつ「指定した法線方向(例: 上向き Z=1)」を持つ面を特定する。
6. その面を共有する境界エッジを収集し、最後に一括でフィレットフィーチャを生成する。
—
現場で使える!実践VBAコード
それでは、SolidWorks VBAの標準モジュールにそのまま貼り付けて実行できる完全版コードを公開します。コード内のコメントをじっくり読みながら、動きをイメージしてください。
Option Explicit
Sub ApplySmartFilletByNormal()
‘ =========================================================================
‘ 【極意】Body2.GetFacesを活用した法線方向による動的エッジフィレット適用マクロ
‘ =========================================================================
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swPart As SldWorks.PartDoc
Dim swBody As SldWorks.Body2
Dim vBodies As Variant
Dim vFaces As Variant
Dim swFace As SldWorks.Face2
Dim swSurface As SldWorks.Surface
Dim vNormal As Variant
‘ 収集したエッジを格納するための動的配列とコレクション
Dim edgeCollection As Collection
Set edgeCollection = New Collection
Dim swEntity As SldWorks.Entity
Dim swEdge As SldWorks.Edge
Dim i As Long, j As Long
‘ 1. アプリケーションとアクティブドキュメントの取得
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
‘ パーツドキュメント以外が開かれている場合は優しくガード
If swModel Is Nothing Then
MsgBox “ドキュメントが開かれていません。”, vbCritical, “エラー”
Exit Sub
End If
If swModel.GetType <> swDocPART Then
MsgBox “このマクロは「パーツ(Part)」ファイルでのみ実行可能です。”, vbExclamation, “対象外”
Exit Sub
End If
Set swPart = swModel
‘ 2. パーツ内のソリッドボディを取得 (Trueを指定して可視ボディのみ取得)
vBodies = swPart.GetBodies2(swSolidBody, True)
If IsEmpty(vBodies) Then
MsgBox “ソリッドボディが見つかりません。”, vbCritical, “エラー”
Exit Sub
End If
‘ ※今回はシンプルに最初のソリッドボディをターゲットにします
Set swBody = vBodies(0)
‘ 3. 【最重要】Body2.GetFacesでボディを構成するすべての面を一網打尽にする
vFaces = swBody.GetFaces
‘ 4. 面のループ処理と法線ベクトルの解析
For i = LBound(vFaces) To UBound(vFaces)
Set swFace = vFaces(i)
Set swSurface = swFace.GetSurface
‘ 平面(Planar Surface)であるかを判定 (IsPlaneメソッドは平面の場合Trueを返す)
If swSurface.IsPlane() Then
‘ 平面の法線パラメータを取得(通常、平面はパラメータ u, v のどこでも法線は一定)
‘ GetNormalAt または Evaluation を使用しますが、今回は最も手軽な Face2 のパラメータ評価を利用
‘ ※正確には面の中点やUV中心で評価します
Dim vUV As Variant
vUV = swFace.GetUVBounds()
‘ UVの中点を算出
Dim midU As Double, midV As Double
midU = (vUV(0) + vUV(1)) / 2
midV = (vUV(2) + vUV(3)) / 2
‘ その位置での法線ベクトルを取得 (戻り値は 3要素のDouble型配列: X, Y, Z)
vNormal = swFace.EvaluateNormal(midU, midV)
‘ — 【条件判定】 —
‘ ここでは例として「上向き(Z方向の法線が +1.0 近傍)」の平滑面をターゲットにする
‘ 浮動小数点の比較なので、許容誤差(許容差: Tolerance)を考慮します
If Abs(vNormal(0) – 0#) < 0.001 And _
Abs(vNormal(1) - 0#) < 0.001 And _
Abs(vNormal(2) - 1#) < 0.001 Then
' 条件に合致した面が持つ「境界エッジ(Edges)」を取得する
Dim vEdges As Variant
vEdges = swFace.GetEdges()
If Not IsEmpty(vEdges) Then
For j = LBound(vEdges) To UBound(vEdges)
Set swEdge = vEdges(j)
' 重複登録を防ぐため、ユニークなエッジのみをコレクションへ蓄積
' (実際の実装ではポインタアドレス等で重複チェックするのが堅牢ですが、今回は簡略化)
On Error Resume Next
edgeCollection.Add swEdge, "E_" & swEdge.GetHashCode ' HashCodeをキーにする
On Error GoTo 0
Next j
End If
End If
End If
Next i
' 5. ターゲットのエッジが見つかったかチェック
If edgeCollection.Count = 0 Then
MsgBox "条件に合致する法線を持つ面のエッジが見つかりませんでした。", vbInformation, "通知"
Exit Sub
End If
' 6. 収集したエッジをSolidWorksがフィレット機能で扱える配列(VARIANT型)に詰め替える
Dim finalEdges() As Object
ReDim finalEdges(edgeCollection.Count - 1)
For i = 1 To edgeCollection.Count
Set finalEdges(i - 1) = edgeCollection(i)
Next i
' 7. 選択セットをクリアして、収集したエッジを明示的に選択状態にする
swModel.ClearSelection2 True
For i = 0 To UBound(finalEdges)
Set swEntity = finalEdges(i)
swEntity.Select4 True, Nothing ' 複数選択(Append = True)
Next i
' 8. フィレットフィーチャの実行 (例: 半径 5mm の定数半径フィレット)
Dim swFeatMgr As SldWorks.FeatureManager
Set swFeatMgr = swModel.FeatureManager
' 引数: 半径(m単位), プレビュー有無, 形状タイプ...
' ※SolidWorksの単位系は内部的に「メートル法(m)」なので、5mmなら 0.005 を指定します!
Dim filletRadius As Double
filletRadius = 0.005 ' 5mm
Dim success As Boolean
' FeatureFillet3 (半径, フィレットタイプ, バラストタイプ, フラグ, コーナータイプ...)
' 実務では FeatureFilletDefault 等のラッパーメソッドを使うことも多いです
success = swFeatMgr.CreateFillet( _
filletRadius, _
swFeatureFilletType_ConstantRadius, _
swFeatureFilletPropagate, _
False, _
False, _
False, _
False)
If success Then
MsgBox "法線方向の解析に基づく一括フィレットの作成に成功しました!", vbInformation, "完了"
Else
MsgBox "エッジの選択には成功しましたが、フィレットの生成に失敗しました(形状干渉の可能性があります)。", vbExclamation, "警告"
End If
' 選択をクリア
swModel.ClearSelection2 True
End Sub
---
