はじめに:なぜあなたのSolidWorksマクロは「時々壊れる」のか?
SolidWorks API開発において、初心者が最初にぶつかり、そしてベテランであっても設計を誤ると永遠に苦しみ続ける鬼門――それが「エンティティ(要素)の選択」です。
マクロの記録ボタンを押し、面やエッジをクリックして生成されたVBAコードをそのまま使っていませんか?
そこには必ず、以下のようなコードが出力されているはずです。
boolstatus = swModel.Extension.SelectByID2(“”, “FACE”, 0.012345, 0.067890, 0.001122, False, 0, Nothing, 0)
一見すると動きます。しかし、CADモデルの寸法を少し変更したり、別のPCで実行したり、アセンブリ構成を変更した途端、コードは静かに、しかし確実に牙をむきます。「要素が選択できずに処理がスキップされる」「明らかな誤選択によって予期せぬジオメトリが破壊される」といった障害です。
なぜこのような壊れやすいコードが生まれるのか?
理由は明確です。`ModelDocExtension.SelectByID2` という強力無比なメソッドの「引数の意味」と「SolidWorks内部のトポロジー認識の仕組み」を正しく理解していないからです。
本記事では、世界標準の業務自動化を目指す開発者に向けて、`SelectByID2` の真の挙動を解剖し、どのような設計変更にも耐えうる堅牢なエンティティ選択アーキテクチャを伝授します。
—
1. `SelectByID2` の真解剖:引数16個(VBAは9個)の解像度を限界まで高める
まずは `SelectByID2` のシグネチャを正しく理解しましょう。VBAにおけるインターフェースは以下の通りです。
Function SelectByID2( _
ByVal Name As String, _
ByVal Type As String, _
ByVal X As Double, _
ByVal Y As Double, _
ByVal Z As Double, _
ByVal Append As Boolean, _
ByVal Mark As Integer, _
ByVal Callout As Callout, _
ByVal SelectOption As Integer _
) As Boolean
一見すると単純な引数の並びに見えますが、実務においてこの引数群は「排他的かつ補完的な3つのモード」で動作しています。
主要引数の挙動と本番開発における決定的な解釈
| 引数名 | 役割 | 現場での「罠」と正しい使い方 |
| :— | :— | :— |
| `Name` | オブジェクトの識別名 | フィーチャー(例: `”Extrude1″`)やスケッチ要素、コンポーネント名を指定。面やエッジを選択する場合、空文字 `””` になることが多い。 |
| `Type` | オブジェクトの型文字列 | `”FACE”`, `”EDGE”`, `”BODYFEATURE”`, `”COMPONENT”` など。大文字小文字を厳密に区別する点に注意。 |
| `X, Y, Z` | 三次元座標(メートル単位) | 最大の罠。 `Name` で特定できない生エンティティ(面・エッジ)を、モデル空間の座標で直接突くために使用される。 |
| `Append` | 選択の追加判定 | `False` なら現在の選択を全解除して新規選択。`True` なら既存の選択セットに追加。ロジックの節目でコントロールが必須。 |
| `Mark` | 処理用のビットマスク | 合致、フィレット、押し出しなどのターゲットを指定する超重要引数。 単なる0指定は実務では通用しない。 |
| `SelectOption`| 選択オプション | 通常は `swSelectOptionDefault` (0) を使用。ビューの不可視要素を選択対象外にする場合は `swSelectOptionExtensiveMatching` などを検討。 |
—
2. なぜ「座標指定(X, Y, Z)」の自動記録コードは本番環境で崩壊するのか?
マクロ記録が生成する `SelectByID2(“”, “FACE”, x, y, z, …)` は、「指定された3D座標に最も近い面(あるいは交差する線上の面)を取得する」というアルゴリズムで動いています。
これが本番環境で100%失敗する理由は3つあります。
1. パラメータ変更による座標移動
パラメトリックCADの価値は寸法変更にあります。モデルの幅が50mmから100mmに変更された瞬間、かつてそこにあった面の座標 (0.025, 0, 0) には「空虚」しか残っていません。
2. 浮動小数点数の丸め誤差
内部処理による幾何計算のわずかな誤差(`1e-7` レベル)により、レイキャスト(光線追跡)がわずかに隣の面やエッジに逸れ、全く関係のない要素を選択します。
3. グラフィック表示(テッセレーション)依存
座標指定の選択アルゴリズムの一部は、グラフィックキャッシュの状態に依存します。バックグラウンド処理(非表示モード)でマクロを実行した場合、座標による選択は極めて不安定になります。
> 【アーキテクトの教訓】
> プロダクションコードにおいて、`SelectByID2` に直接生の座標(X, Y, Z)をハードコーディングすることは完全に禁じ手と心得よ。
—
3. 堅牢な選択を実現する「3つの代替戦略」
座標による愚直な選択を捨て、以下のいずれかの設計パターンを採用する必要があります。
[選択の戦略]
├── 戦略A: 永続名 / 属性(Named Entity / Attribute)を利用した直接選択
├── 戦略B: フィーチャーのトポロジー走査(Feature -> Body -> Face / Edge)
└── 戦略C: 幾何学的特性による自動抽出(Bounding Box, Normal Vector)
実務で最も堅牢、かつ変更に強いのは「戦略B:フィーチャーからトポロジーを辿るアプローチ」です。
目的の面を直接選ぶのではなく、「どのフィーチャーによって作られた面か」からロジカルにアプローチします。
—
4. 完全実用:プロダクションレベルの「トポロジー追跡・確実選択」コード
以下は、座標依存を100%排除し、「指定したフィーチャーの最も面積が広い面」や「指定した方向を向いている面」を確実に捕獲して選択する、そのまま実務に投入可能なVBAコードです。
モジュール名: `mod_EntitySelector.bas`
Attribute VB_Name = “mod_EntitySelector”
Option Explicit
‘ SolidWorks API 定数定義
Private Const swDocPART As Long = 1
Private Const swSelectOptionDefault As Long = 0
”
‘ 指定されたフィーチャーの面の中から、最も面積の大きい面を「Mark」付きで選択する
‘
‘ @param swModel [in] 対象ドキュメント
‘ @param featureName [in] フィーチャー名(例: “Boss-Extrude1″)
‘ @param markValue [in] 選択マーク (例: 1 = フィレットの対象面, 2 = 勾配の固定方向等)
‘ @return 成功時 True
”
Public Function SelectLargestFaceByFeatureName( _
ByVal swModel As SldWorks.ModelDoc2, _
ByVal featureName As String, _
ByVal markValue As Long _
) As Boolean
Dim swFeat As SldWorks.Feature
Dim swFace As SldWorks.Face2
Dim vFaces As Variant
Dim i As Long
Dim maxArea As Double
Dim targetEntity As SldWorks.Entity
Dim swCurrentFace As SldWorks.Face2
SelectLargestFaceByFeatureName = False
If swModel Is Nothing Then Exit Function
‘ 1. フィーチャーオブジェクトの取得
Set swFeat = swModel.FeatureByName(featureName)
If swFeat Is Nothing Then
Debug.Print “Error: フィーチャー ‘” & featureName & “‘ が見つかりません。”
Exit Function
End If
‘ 2. フィーチャーを構成する面(Face)の配列を取得
vFaces = swFeat.GetFaces()
If IsEmpty(vFaces) Then
Debug.Print “Error: フィーチャー ‘” & featureName & “‘ に面が存在しません。”
Exit Function
End If
‘ 3. 最も面積が大きい面を探索(幾何特性による絞り込み)
maxArea = -1#
For i = 0 To UBound(vFaces)
Set swCurrentFace = vFaces(i)
‘ 面の表面積を取得
Dim currentArea As Double
currentArea = swCurrentFace.GetArea()
If currentArea > maxArea Then
maxArea = currentArea
Set targetEntity = swCurrentFace ‘ Face2はEntityを継承している
End If
Next i
‘ 4. EntityHelperによる確実な選択処理
If Not targetEntity Is Nothing Then
Dim swSelData As SldWorks.SelectData
Dim swSelectionMgr As SldWorks.SelectionMgr
Set swSelectionMgr = swModel.SelectionManager
‘ Mark構造体を含むSelectDataを作成
Set swSelData = swSelectionMgr.CreateSelectData()
swSelData.Mark = markValue
‘ Extension.SelectByID2ではなく、Entity.Select4を使用するのが最もバグが少ない
SelectLargestFaceByFeatureName = targetEntity.Select4(True, swSelData)
End If
End Function
”
‘ 実行メインルーチン(使用例)
”
Public Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim success As Boolean
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “パーツモデルを開いてから実行してください。”, vbCritical
Exit Sub
End If
‘ 既存の選択をクリア
swModel.ClearSelection2 True
‘ “Boss-Extrude1” の中で最大の面を Mark=1(例: フィレット入力用)として選択
success = SelectLargestFaceByFeatureName(swModel, “Boss-Extrude1”, 1)
If success Then
MsgBox “意図した面を正確に選択しました!”, vbInformation
Else
MsgBox “選択処理に失敗しました。フィーチャー名を確認してください。”, vbExclamation
End If
End Sub
—
5. 選択のライフサイクル管理とパフォーマンスを極める
アーキテクチャの観点から、要素の選択処理を大量にループ実行する自動化ツールを作る場合の「絶対ルール」を3つ伝授します。
① `Select4` と `SelectData` の組み合わせを第一選択にせよ
`ModelDocExtension.SelectByID2` は「文字列検索と座標投影」という余分なレイヤーを挟むため低速であり、失敗するリスクを常に抱えます。
コード内で直接 `Face2` や `Edge` の参照が取得できている場合は、上記サンプルコードのように `Entity.Select4` を使用してください。これが最も高速であり、確実に動作します。
② 大規模処理では `ClearSelection2` と描画停止を徹底せよ
要素の選択はSolidWorks内部でグラフィックのハイライト表示(描画バッファの更新)を伴います。1000個の要素をループ選択する場合、これが原因で処理時間が数分レベルで遅延します。
‘ 画面更新とイベントを抑制して超高速化
swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swEnableGraphicsUpdate, False
‘ 処理ループ
For Each item In items
‘ 処理…
Next item
‘ 必ず元の状態に復帰させる
swApp.SetUserPreferenceToggle swUserPreferenceToggle_e.swEnableGraphicsUpdate, True
また、用途が終わった選択フラグは `swModel.ClearSelection2 True` で即座に解放してください。古い選択状態が破棄されていないことによる意図しない「重複選択」は、自動化バグの典型例です。
—
まとめ:真のエンジニアが目指すべきコード
API自動記録ツールが出力する `SelectByID2(“…”, “FACE”, X, Y, Z)` は、開発の「出発点」でしかありません。それをそのまま本番コードに組み込むのは、耐震補強をしていない家に住むようなものです。
1. 座標(X, Y, Z)の直接指定はプロダクションコードから排除する。
2. フィーチャー名やトポロジー構造(幾何面積、法線ベクトル)からエンティティを動的に特定する。
3. `SelectByID2` ではなく、オブジェクト参照からの `Entity.Select4` を活用する。
この「トポロジー主導型」の設計思想へ切り替えることで、あなたの作成するSolidWorksマクロは、モデルの変更にも揺るがない、プロフェッショナルにふさわしい堅牢性を手に入れることができます。
