【テクニカル・上級編】【フィレット・面取り】GetEdgesメソッドによるボディ全周エッジの網羅的取得と動的フィレット適用エラーの回避法 – SolidWorks VBA解析バイブル

スポンサーリンク

SolidWorks VBAを掌握する極限の知見:GetEdges全周エッジ網羅と動的フィレットの例外完全克服

SolidWorksの自動化において、最もフラストレーションが溜まる瞬間はどこか。それは、静的なモデルであれば数クリックで終わる「全周フィレット(あるいは面取り)」をVBAで動的に実装しようとした瞬間だ。

「`GetEdges`でボディからエッジ配列を取得し、`FeatureManager.FeatureFillet3`に投げ込むだけ」
そう考えて書いたコードが、モデルの微小なトポロジー変更(位相幾何学的変化)、例えば合流部の微小面(Micro-faces)やゼロ厚みエッジによって轟沈する光景を、私は幾度となく目撃してきた。

本稿では、レガシーなVBA環境であっても、SolidWorks APIの挙動を極限まで理解し、「ボディ全周のエッジを漏れなく安全に取得し、失敗しない動的フィレット適用」を完遂するための実践的知見を提示する。

1. 根源的理解:`GetEdges`のメモリ構造とCOMオブジェクトの寿命

まず、APIの仕様に対する認識を改める必要がある。`Body2::GetEdges`メソッドは、C++のレイヤーで動的配列を生成し、それを安全配列(SafeArray / VARIANT)としてVBA側へマーシャリング(Marshalling)する。

ここで発生するのが、COMオブジェクトの解放漏れによるメモリリークとヒープの断片化だ。
VBAのガベージコレクタは、`Set`で参照を切った瞬間にCOMの参照カウントをデクリメントするほど賢くはない。特に大量のエッジオブジェクト(`Edge`インターフェース)を扱う場合、ループ内で変数を使い回すと、SolidWorksのプロセス空間内でメモリが肥大化し、最悪の場合はCOM例外(エラー 462: オートメーション サーバーはオブジェクトを返せませんでした)を引き起こす。

鉄則:エッジ配列の適切な受取りと即時解放

`GetEdges`を使用する際は、返されたVARIANT配列の境界(LBound / UBound)を厳密に管理し、処理が終わったエッジポインタは即座にメモリから解放しなければならない。

2. 実装コード:全周エッジ抽出と動的フィレットの堅牢な例外回避

以下に、実務の現場で耐えうる、例外処理を網羅したプロシージャを示す。単にエッジを取るだけでなく、「フィレットを適用できないエッジ(接線連続なエッジや極端に短いエッジ)」を事前にフィルタリングし、APIのクラッシュを防ぐロジックを組み込んでいる。

Option Explicit

‘ ==============================================================================
‘ 処理名 : ApplyRobustFilletToAllEdges
‘ 概要 : アクティブなソリッドボディの全周エッジを動的に取得し、
T : 破綻するエッジを排除した上で安全にフィレットを適用する。
‘ ==============================================================================
Public Sub ApplyRobustFilletToAllEdges()
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 swFeat As SldWorks.Feature

‘ 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 “このマクロはパーツドキュメントでのみ実行可能です。”, vbCritical
Exit Sub
End If

Set swPart = swModel

‘ 2. 最初のソリッドボディを取得 (SolidBodyの列挙)
vBodies = swPart.GetBodies2(swSolidBody, False)
If IsEmpty(vBodies) Then
MsgBox “対象となるソリッドボディが存在しません。”, vbCritical
Exit Sub
End If

‘ ここでは簡略化のため最初のボディを対象とする(複数ボディの場合はループを回すこと)
Set swBody = vBodies(0)

‘ 3. エッジの安全な抽出とフィルタリング
Dim vEdges As Variant
vEdges = swBody.GetEdges()

If IsEmpty(vEdges) Then
MsgBox “ボディからエッジを取得できませんでした。”, vbCritical
Exit Sub
End If

Dim i As Long
Dim swEdge As SldWorks.Edge
Dim validEdges() As SldWorks.Edge
Dim validCount As Long
validCount = 0

ReDim validEdges(0 To UBound(vEdges))

‘ 4. 許容されないエッジ(微小エッジ、面取り不可能なトポロジー)の排除
For i = LBound(vEdges) To UBound(vEdges)
Set swEdge = vEdges(i)

‘ 【極限知見】エッジの長さを評価し、ゼロ除算や破綻の原因となる微小エッジをスキップ
Dim swCurve As SldWorks.Curve
Set swCurve = swEdge.GetCurve()

If Not swCurve Is Nothing Then
‘ 簡易的な評価:エッジの長さが許容値(例: 0.1mm)以上か
‘ ※厳密にはEdge::GetStartVertex / GetEndVertexの距離を測る
If IsEdgeValidForFillet(swEdge) Then
Set validEdges(validCount) = swEdge
validCount = validCount + 1
End If
End

‘ オブジェクト参照の明示的破棄(メモリリーク防止)
Set swCurve = Nothing
Set swEdge = Nothing
Next i

If validCount = 0 Then
MsgBox “フィレットを適用可能な有効なエッジが見つかりませんでした。”, vbExclamation
Exit Sub
End If

‘ 配列のサイズを有効な数にリサイズ
ReDim Preserve validEdges(0 To validCount – 1)

‘ 5. フィレットフィーチャの動的適用
‘ エラーハンドリングの有効化(APIの予期せぬ失敗に対する備え)
On Error GoTo ErrorHandler

swModel.ClearSelection2 True

‘ 選択セットへ有効なエッジを投入
Dim swSelData As SldWorks.SelectionData
Set swSelData = swModel.Extension.CreateSelectionData

For i = 0 To UBound(validEdges)
Dim swEntity As SldWorks.Entity
Set swEntity = validEdges(i)
swEntity.Select4 True, swSelData
Set swEntity = Nothing
Next i

‘ フィレット実行 (半径: 2.0mm, 伝播: True)
‘ FeatureFillet3 (R, 処理フラグ, 形状, 等)
Dim radius As Double
radius = 0.002 ‘ 2mm (内部単位はメートル)

Set swFeat = swModel.FeatureManager.FeatureFillet3( _
radius, _
1, _ ‘ swFilletType_ConstantRadius
0, _ ‘ swFilletSymmType_Circular
0, _ ‘ 伝播なし(0) / 接線伝播あり(1) -> ここでは1を推奨
False, False, False)

If swFeat Is Nothing Then
Err.Raise vbObjectError + 1000, “FilletMacro”, “FeatureManagerがフィレットの生成に失敗しました。トポロジーが複雑すぎます。”
End If

‘ 成功時のクリーンアップ
swModel.ClearSelection2 True
MsgBox “全周フィレットの適用が完了しました。”, vbInformation

Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
swModel.ClearSelection2 True
‘ 失敗時はフィーチャツリーのロールバック等を考慮した堅牢な処理をここに記述
End Sub

‘ ==============================================================================
‘ 補助関数 : IsEdgeValidForFillet
‘ 概要 : 評価対象のエッジがフィレット処理に耐えうるか検証する
‘ ==============================================================================
private Function IsEdgeValidForFillet(ByVal swEdge As SldWorks.Edge) As Boolean
IsEdgeValidForFillet = True

Dim vVerts As Variant
vVerts = swEdge.GetVertices()

‘ 閉じたループや退化したエッジの排除
If IsEmpty(vVerts) Then
IsEdgeValidForFillet = False
Exit Function
End If

‘ 微小エッジの排除 (例: 0.05mm未満)
Dim vStartCoord As Variant
vStartCoord = swEdge.GetStartVertex.GetPoint
Dim vEndCoord As Variant
vEndCoord = swEdge.GetEndVertex.GetPoint

Dim length As Double
length = Sqr((vEndCoord(0) – vStartCoord(0))^2 + _
(vEndCoord(1) – vStartCoord(1))^2 + _
(vEndCoord(2) – vStartCoord(2))^2)

If length < 0.00005 Then ' 0.05mm IsEdgeValidForFillet = False End If End Function ---

3. チーフアーキテクトが教える:動的フィレットエラーの「根本原因と回避策」

上記のコードを実装したとしても、複雑な板金部品やインポートされたSTEPモデル(IGES/STEP)では、依然として`FeatureFillet3`が失敗することがある。その原因は主に以下の3点に集約される。

① 内部単位(MKS系)の罠

SolidWorks APIは、入力値を常に「メートル(meters)」で要求する。UI上で「2mm」と指定したい場合、コード上では必ず `0.002` と記述しなければならない。これを怠ると、巨大なフィレットを作ろうとしてジオメトリが自己交差(Self-intersection)を起こし、APIがエラーを吐く。

② 接線伝播(Tangent Propagation)の衝突

全周フィレットを行う際、すべてのエッジを個別に選択セットに追加すると、SolidWorksのソルバーが過剰な制約を検知し、計算が破綻する。
もし「ボディのすべての鋭利な角」を狙うのであれば、全エッジを羅列するのではなく、「主要な面(Faces)」の境界、あるいは接線伝播フラグを有効にした単一のエッジ選択から展開するアプローチの方が、ソルバーの負荷を劇的に軽減できる。

③ COMオブジェクトの参照解放漏れによる「サイレントクラッシュ」

VBAのループ内で `swEdge.GetCurve()` や `swEdge.GetVertices()` を呼び出すと、内部で新しいCOMオブジェクトのインスタンスが生成される。これらをローカル変数に格納したままループを抜けたり、明示的に `Set xxx = Nothing` で解放しないと、VBAランタイムのメモリ空間がリークを起こし、数回実行しただけでSolidWorksごと強制終了する。
上記のコードで、こまめに `Set` を解除しているのはそのためだ。

4. 総括:レガシーの壁を越えるために

VBAは、現代のソフトウェア開発において「レガシー」と揶揄されることがある。しかし、SolidWorksの巨大なAPIエコシステムを直叩きし、CADのコアエンジン(Parasolid)の挙動を直接制御するという点において、これほど手軽で強力なインターフェースはほかにない。

`GetEdges` と動的フィレットの制御を完全に手中に収めることは、単なるマクロの自動化を超え、「CADのトポロジー構造をプログラムでハックする」領域への到達を意味する。本稿で示したメモリ管理と例外回避の哲学を、あなたのシステム基盤に深く組み込んでほしい。妥協なきエンジニアリングの成果が、そこには必ずある。

タイトルとURLをコピーしました