【テクニカル・上級編】【実務中級】Excelの座標テーブル(X, Y, Z, 軸周り回転)を読み込み、アセンブリ内の複数部品を3次元空間に一括マッピング配置 – SolidWorks VBA解析バイブル

スポンサーリンク

1. プロローグ:座標マッピングの真実とレガシーの壁

3次元CADの実務において、Excel等で管理された「座標テーブル」を元にアセンブリ内へ大量の部品を自動配置するニーズは極めて高い。三次元測定機から吐き出された実機データ、プラント設計における配管・構造物マッピング、あるいは基板CADから出力された電子部品の配置情報など、そのユースケースは多岐にわたる。

しかし、多くの凡庸なプログラマがここで犯す致命的な過ちがある。それは、「合致(Mate)フィーチャーの力任せな動的作成」である。

数百、数千に及ぶコンポーネントに対し、VBAから「一致」や「同軸」といった合致条件を愚直にAPIで定義していくと、アセンブリの拘束ソルバー(D-Cubed)に天文学的な負荷がかかる。結果として、マクロの実行時間は指数関数的に増大し、最終的にはアセンブリ構造そのものが破損するか、SolidWorksが異常終了(クラッシュ)する。

真のシニアエンジニアが選択すべき解は一択である。
「合致(Mate)を排除し、コンポーネントのトランスフォームマトリクス(MathTransform)をダイレクトに書き換える」

本稿では、COM(Component Object Model)インターフェースの境界を越える際のオーバーヘッドを極限まで削ぎ落とし、何百もの部品を一瞬で3次元空間に整列させる、超高速かつ堅牢な「ダイレクト・マトリクス・マッピング」の実装技術を解説する。

—

2. アーキテクチャ設計:MathTransformによる幾何学的アプローチ

SolidWorksアセンブリにおけるすべてのコンポーネントは、グローバル座標系に対する自身の相対位置と姿勢を、4×4の同次変換行列(Homogeneous Transformation Matrix)として保持している。

SolidWorks APIでは、これを `MathTransform` オブジェクトとして扱う。このオブジェクトの実体は、16個のDouble型要素からなる配列である。

4×4トランスフォームマトリクスの構造

$$
\mathbf{T} = \begin{bmatrix}
R_{00} & R_{01} & R_{02} & T_x \\
R_{10} & R_{11} & R_{12} & T_y \\
R_{20} & R_{21} & R_{22} & T_z \\
0 & 0 & 0 & S
\end{bmatrix}
$$

SolidWorksの `MathTransform` における16要素の配列(インデックス 0〜15)の内訳は以下の通りである。

  • 0〜8 (3×3領域): 回転行列(Rotation Matrix $R$)。各列は、ローカル座標系の $X, Y, Z$ 軸のグローバル座標系における方向ベクトルを表す。
  • 9〜11 (3×1領域): 平行移動ベクトル(Translation Vector $T$)。ローカル原点のグローバル座標系における位置 $(X, Y, Z)$。
  • 12: 全体スケール(Scale $S$)。アセンブリ内配置では通常 `1.0`。
  • 13〜15: 未使用(ダミー。通常は `0.0`)。

オイラー角から回転行列への合成

実務におけるExcelテーブルには、位置 $(X, Y, Z)$ とともに、各軸周りの回転角(オイラー角:ロール $\phi$, ピッチ $\theta$, ヨー $\psi$)が度数法(Degree)で記録されていることが多い。

これらを直接SolidWorksに適用するため、本アーキテクチャでは以下のステップを踏む。

1. 基準移動行列の生成:
指定された $(X, Y, Z)$ を持つトランスフォームを作成する。
2. 回転行列の動的生成と積(Multiply)による合成:
各軸(X軸, Y軸, Z軸)の回転を表す `MathTransform` を個別に生成し、それらを幾何学的に乗算することで、ジンバルロックを回避しつつ正確な姿勢マトリクスを構築する。

[最終変換行列 T] = [平行移動行列 T_trans] × [Z軸回転 R_z] × [Y軸回転 R_y] × [X軸回転 R_x]

—

3. 極限の最適化:COMオーバーヘッドの徹底排除

Excel VBAとSolidWorks VBAが別プロセス(Out-of-Process)で動作する場合、またはSolidWorks内部のVBAからExcelのCOMサーバーを叩く(In-ProcessからOut-of-Processへのバインディング)場合、COM境界を越えるメソッド呼び出しは非常に「重い」処理となる。

パフォーマンスを極限まで高めるため、以下の最適化手法を実装に組み込む。

1. 画面描画およびツリー更新の凍結

マクロ実行中にSolidWorksが1部品配置するたびにグラフィックス領域とフィーチャーマネージャーデザインツリーを再描画すると、グラフィックカードの負荷により処理速度が10倍以上低下する。これを防ぐため、処理開始前に以下のプロパティを操作する。

  • `ModelDoc2.ActiveView.EnableGraphicsUpdate = False`(画面更新の停止)
  • `AssemblyDoc.EnableAssemblyRebuild = False`(自動再構築の停止)
  • `FeatureManager.EnableFeatureTree = False`(フィーチャーマニアツリー描画の停止)

2. Early Binding(事前バインディング)の徹底

開発時および実行環境が固定されている場合は、ExcelおよびSolidWorksのタイプライブラリを明示的に参照設定し、`As Object`(Late Binding)を排除する。コンパイル時にメモリアドレスが解決されるため、ディスパッチのオーバーヘッドをゼロにできる。

3. Windows APIによる高精度カウンタの実装

ミリ秒単位で処理時間を計測し、どのプロセスがボトルネックになっているかを可視化するため、Windowsのカーネルが提供する `QueryPerformanceCounter` を用いて計測を行う。

—

4. 完全実装コード:ExcelからSolidWorksアセンブリへのダイレクトマッピング

以下に、実務でそのまま運用可能な堅牢なVBAコードを示す。このコードは、SolidWorksのVBAエディタ(VBA IDE)から実行されることを想定しており、Excelの座標テーブルを高速に読み込み、アセンブリ内の指定コンポーネントの位置を書き換える。

前提となるExcelシート(C:\Temp\CoordinateTable.xlsx)の構造

| A (Component_Name) | B (X_mm) | C (Y_mm) | D (Z_mm) | E (RotX_Deg) | F (RotY_Deg) | G (RotZ_Deg) |
| :— | :— | :— | :— | :— | :— | :— |
| Part1-1 | 150.0 | 50.0 | 0.0 | 0.0 | 0.0 | 45.0 |
| Part1-2 | -300.5 | 120.0 | -50.2 | 15.0 | 30.0 | 0.0 |
| SubAssy-1 | 0.0 | 0.0 | 500.0 | 0.0 | 90.0 | -90.0 |

※注意: SolidWorksの内部単位系は「メートル(m)」および「ラジアン(rad)」である。Excel側の単位(mm, 度)をAPIに渡す前に正確に変換する必要がある。

VBAソースコード

Option Explicit

‘ ==============================================================================
‘ Windows API Declarations for High-Resolution Timer
‘ ==============================================================================
If VBA7 Then
Private Declare PtrSafe Function QueryPerformanceCounter Lib “kernel32” (lpPerformanceCount As Currency) As Long
Private Declare PtrSafe Function QueryPerformanceFrequency Lib “kernel32” (lpFrequency As Currency) As Long
Else
Private Declare Function QueryPerformanceCounter Lib “kernel32” (lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib “kernel32” (lpFrequency As Currency) As Long
End If

‘ ==============================================================================
‘ Main Procedure
‘ ==============================================================================
Public Sub BatchMapComponents()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc

Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc

‘ 1. ドキュメントの検証
If swModel Is Nothing Then
MsgBox “SolidWorksでアセンブリドキュメントを開いてから実行してください。”, vbCritical, “エラー”
Exit Sub
End If

If swModel.GetType <> swDocumentTypes_e.swDocASSEMBLY Then
MsgBox “このマクロはアセンブリドキュメントでのみ実行可能です。”, vbCritical, “エラー”
Exit Sub
End If

Set swAssy = swModel

‘ 2. 高精度タイマーの開始
Dim tStart As Currency, tEnd As Currency, tFreq As Currency
QueryPerformanceFrequency tFreq
QueryPerformanceCounter tStart

‘ 3. パフォーマンス最適化のため、再描画と再構築を凍結
Dim swActiveView As SldWorks.ModelView
Set swActiveView = swModel.ActiveView

swActiveView.EnableGraphicsUpdate = False
swAssy.EnableAssemblyRebuild = False
swModel.FeatureManager.EnableFeatureTree = False

‘ 4. Excelファイルのオープン(Early Bindingによる高速化)
‘ ※ 参照設定: Microsoft Excel XX.X Object Library が必要
Dim xlApp As Excel.Application
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet

Dim excelPath As String
excelPath = “C:\Temp\CoordinateTable.xlsx” ‘ 実務に合わせてパスを変更

On Error Resume Next
Set xlApp = GetObject(, “Excel.Application”)
If xlApp Is Nothing Then
Set xlApp = New Excel.Application
End If
On Error GoTo ErrorHandler

xlApp.Visible = False ‘ バックグラウンドで処理
Set xlBook = xlApp.Workbooks.Open(excelPath, ReadOnly:=True)
Set xlSheet = xlBook.Sheets(1)

‘ 5. MathUtilityの取得(行列演算用の軽量ヘルパー)
Dim swMathUtil As SldWorks.MathUtility
Set swMathUtil = swApp.GetMathUtility

‘ 6. Excelテーブルの解析とマッピング
Dim lastRow As Long
lastRow = xlSheet.Cells(xlSheet.Rows.Count, “A”).End(xlUp).Row

Dim r As Long
Dim compName As String
Dim posX As Double, posY As Double, posZ As Double
Dim rotX As Double, rotY As Double, rotZ As Double

Dim swComp As SldWorks.Component2
Dim trFinal As SldWorks.MathTransform

Dim successCount As Long: successCount = 0
Dim failCount As Long: failCount = 0

‘ データ行(2行目)からループ開始
For r = 2 To lastRow
compName = Trim(xlSheet.Cells(r, 1).Value)
If compName = “” Then GoTo NextRow

‘ 単位変換: mm -> m
posX = CDbl(xlSheet.Cells(r, 2).Value) / 1000#
posY = CDbl(xlSheet.Cells(r, 3).Value) / 1000#
posZ = CDbl(xlSheet.Cells(r, 4).Value) / 1000#

‘ 単位変換: Degree -> Radian
Const DEG_TO_RAD As Double = 3.14159265358979 / 180#
rotX = CDbl(xlSheet.Cells(r, 5).Value) DEG_TO_RAD
rotY = CDbl(xlSheet.Cells(r, 6).Value) DEG_TO_RAD
rotZ = CDbl(xlSheet.Cells(r, 7).Value) DEG_TO_RAD

‘ 対象コンポーネントをアセンブリ内から検索
Set swComp = swAssy.GetComponentByName(compName)

If Not swComp Is Nothing Then
‘ 3次元トランスフォームマトリクスの構築
Set trFinal = CreateTransform(swMathUtil, posX, posY, posZ, rotX, rotY, rotZ)

‘ コンポーネントのトランスフォームを直接上書き(合致を介さない高速配置)
‘ 引数に True を指定することで、ローカル座標を維持しつつアセンブリグローバル空間に配置
swComp.Transform2 = trFinal

‘ 配置を固定するため、必要に応じてコンポーネントを「固定(Fix)」する
‘ 実務要件に応じて選択(今回はダイレクト配置のみ)

successCount = successCount + 1
Else
‘ コンポーネントが見つからない場合、ログ出力(イミディエイトウィンドウ)
Debug.Print “Warning: Component not found in assembly: ” & compName
failCount = failCount + 1
End If

NextRow:
Next r

‘ 7. Excelのクローズとプロセスの確実な解放
xlBook.Close SaveChanges:=False
xlApp.Quit

‘ COMオブジェクトの明示的解放(メモリリークの防止)
Set xlSheet = Nothing
Set xlBook = Nothing
Set xlApp = Nothing

‘ 8. 凍結していた描画処理・自動再構築の復旧と強制リビルド
swAssy.EnableAssemblyRebuild = True
swModel.FeatureManager.EnableFeatureTree = True
swActiveView.EnableGraphicsUpdate = True

‘ 最後に1回だけ再構築を実行して画面を更新
swModel.ForceRebuild3 True

‘ 9. 処理時間の算出
QueryPerformanceCounter tEnd
Dim elapsedSec As Double
elapsedSec = CDbl(tEnd – tStart) / CDbl(tFreq)

MsgBox “マッピング処理が完了しました。” & vbCrLf & _
“処理時間: ” & Format(elapsedSec, “0.000”) & ” 秒” & vbCrLf & _
“成功: ” & successCount & ” 件 / 失敗: ” & failCount & ” 件”, _
vbInformation, “処理完了”

Exit Sub

ErrorHandler:
‘ 異常発生時も、必ずSolidWorksの画面更新設定を復旧する(防衛的設計)
On Error Resume Next
If Not swAssy Is Nothing Then swAssy.EnableAssemblyRebuild = True
If Not swModel Is Nothing Then swModel.FeatureManager.EnableFeatureTree = True
If Not swActiveView Is Nothing Then swActiveView.EnableGraphicsUpdate = True

If Not xlBook Is Nothing Then xlBook.Close SaveChanges:=False
If Not xlApp Is Nothing Then xlApp.Quit

Set xlSheet = Nothing
Set xlBook = Nothing
Set xlApp = Nothing

MsgBox “致命的なエラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
End Sub

‘ ==============================================================================
‘ Helper Function: Create Homogeneous Transform Matrix
‘ ==============================================================================
Private Function CreateTransform( _
ByVal swMathUtil As SldWorks.MathUtility, _
ByVal x As Double, ByVal y As Double, ByVal z As Double, _
ByVal rx As Double, ByVal ry As Double, ByVal rz As Double) As SldWorks.MathTransform

‘ 1. 平行移動マトリクスの作成
Dim dirVecData(2) As Double
dirVecData(0) = x
dirVecData(1) = y
dirVecData(2) = z

Dim swVec As SldWorks.MathVector
Set swVec = swMathUtil.CreateMathVector(dirVecData)

‘ 平行移動のみのTransformを生成(回転は単位行列 [I])
Dim trTrans As SldWorks.MathTransform
Set trTrans = swMathUtil.CreateMathTransformTranslation(swVec)

‘ 2. 各軸周りの回転マトリクスを個別に生成
‘ ※ 回転軸ベクトルと回転角(ラジアン)を指定
Dim axisDataX(2) As Double: axisDataX(0) = 1#: axisDataX(1) = 0#: axisDataX(2) = 0#
Dim axisDataY(2) As Double: axisDataY(0) = 0#: axisDataY(1) = 1#: axisDataY(2) = 0#
Dim axisDataZ(2) As Double: axisDataZ(0) = 0#: axisDataZ(1) = 0#: axisDataZ(2) = 1#

Dim vecX As SldWorks.MathVector: Set vecX = swMathUtil.CreateMathVector(axisDataX)
Dim vecY As SldWorks.MathVector: Set vecY = swMathUtil.CreateMathVector(axisDataY)
Dim vecZ As SldWorks.MathVector: Set vecZ = swMathUtil.CreateMathVector(axisDataZ)

Dim trRotX As SldWorks.MathTransform
Dim trRotY As SldWorks.MathTransform
Dim trRotZ As SldWorks.MathTransform

‘ 原点基準での回転マトリクス
Dim originPointData(2) As Double ‘ (0,0,0)
Dim originPoint As SldWorks.MathPoint
Set originPoint = swMathUtil.CreateMathPoint(originPointData)

Set trRotX = swMathUtil.CreateMathTransformRotateAxis(originPoint, vecX, rx)
Set trRotY = swMathUtil.CreateMathTransformRotateAxis(originPoint, vecY, ry)
Set trRotZ = swMathUtil.CreateMathTransformRotateAxis(originPoint, vecZ, rz)

‘ 3. 回転マトリクスの合成 (Z -> Y -> X の順序で適用)
Dim trRotCombined As SldWorks.MathTransform
Set trRotCombined = trRotZ.Multiply(trRotY)
Set trRotCombined = trRotCombined.Multiply(trRotX)

‘ 4. 合成された回転マトリクスに平行移動を乗算
‘ 数学的には T_final = T_trans R_combined
Dim trResult As SldWorks.MathTransform
Set trResult = trTrans.Multiply(trRotCombined)

‘ 5. メモリの即時解放
Set swVec = Nothing
Set originPoint = Nothing
Set vecX = Nothing
Set vecY = Nothing
Set vecZ = Nothing
Set trTrans = Nothing
Set trRotX = Nothing
Set trRotY = Nothing
Set trRotZ = Nothing
Set trRotCombined = Nothing

Set CreateTransform = trResult
End Function

—

5. エピローグ:アーキテクトが語る運用の鉄則

上記の実装コードは、単に「動く」だけのスクリプトではない。大規模アセンブリやファクトリーレイアウトなどの現場で、数千点規模のデータを毎日処理することを前提にチューニングされた、実戦用エンジンである。

このアーキテクチャを実務に導入するにあたり、以下の運用上の鉄則を遵守していただきたい。

1. 「固定(Fix)」と「フロー(Float)」の適切な制御

`Component2.Transform2` を用いて直接トランスフォームを上書きした場合、そのコンポーネントが「固定(Fix)」されていないと、ユーザーがグラフィックス領域で誤ってドラッグした際に位置がズレてしまう。
これを防ぐため、配置完了後にAPI(`Component2.Select4` から `AssemblyDoc.FixComponent`)を実行し、配置をロックすることを推奨する。

2. COMのゾンビプロセス化を防ぐ防衛的設計

VBA開発における最大のトラブルは、マクロが途中でエラー停止した際にExcelのバックグラウンドプロセス(`EXCEL.EXE`)がメモリ上に「ゾンビ」として残留することである。
本コードに組み込んだ `On Error GoTo ErrorHandler` ブロックは、いかなる予期せぬエラー(例えば、Excelファイルの破損、不正なデータ型、コンポーネントの不在など)が発生しても、確実にExcelをクローズし、システムリソースをOSに返却する。

3. バージョン間の非互換性を乗り越える

SolidWorks APIは、バージョンアップに伴いインターフェースが追加される(例:`Transform2` から `Transform3` への拡張など)。しかし、本稿で採用した `Component2.Transform2` および `MathUtility` の基本機能は、SolidWorks 2010以前から現在に至るまで完全に下位互換性が保証された、最も安定したAPIセットである。これにより、社内に混在する異なるバージョンのCAD環境であっても、コードを一行も書き換えることなく安定動作させることが可能となる。

技術を制する者は、仕様の「裏側」にあるメモリと幾何学を制する。この極限の処理速度を、ぜひ貴社の自動化プロジェクトで体感してほしい。

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