【入門編】【上級プロ】アセンブリ構造のJSONシリアライゼーション:ツリー階層・合致・座標データを完全なJSONテキストとして書き出し・復元する独自エンジン – SolidWorks VBA解析バイブル

スポンサーリンク

SolidWorks VBAを極めようとする皆さん、こんにちは!
SolidWorks VBAの深淵に足を踏み入れようとしている皆さんを、心から歓迎します。私は長年、SolidWorksの自動化とシステム連携に携わってきたチーフアーキテクトです。皆さんが今、目の前にしている「アセンブリ構造のJSONシリアライゼーション」というテーマは、まさにSolidWorks自動化の「究極の境地」と呼べる領域への第一歩です。

「JSONシリアライゼーション」と聞くと、少し難しく感じるかもしれませんね。しかし、SolidWorksが持つ素晴らしい設計情報を、もっと自由な形で活用できるようになるための、非常に強力な手法なんです。この記事では、その壮大な目標の「入り口」に立つための、SolidWorks VBAの基礎と、アセンブリ情報の取得方法を、皆さんに優しく、そして丁寧に解説していきます。

ここをクリアすれば、SolidWorks VBAの基本はバッチリですよ!さあ、一緒に未来への扉を開きましょう。

—

究極のSolidWorks連携へ!アセンブリをJSONで操る未来の一歩(上級プロの視点から紐解く基礎)

1. SolidWorksデータの壁を越えろ!なぜJSONシリアライゼーションが必要なのか?

皆さんがSolidWorksで設計したアセンブリは、その中に無数の情報を含んでいます。どの部品が、どの位置で、どのように組み合わされているか。それぞれの部品はどのファイルから来ているのか。そして、それらがどのような「合致(Mate)」で拘束されているのか。これらの情報は、SolidWorksのファイル形式(SLDASM, SLDPRT)の中に、非常に効率的ですが、独自のバイナリ形式で保存されています。

しかし、この独自の形式が、時に壁となることがあります。

  • Webシステムとの連携は? クラウドベースのデータベースで設計情報を管理したい。
  • 他部署のシステムと連携は? 製造管理システムやPDM(製品データ管理)システムと情報を共有したい。
  • バージョン管理は? テキストベースで差分を管理したい。
  • SolidWorksなしで情報を参照したい!

このような時、SolidWorksのバイナリデータは直接利用できません。そこで登場するのが、JSON(JavaScript Object Notation) です。JSONは、人間が読みやすく、機械も解析しやすいテキストベースのデータ形式で、WebシステムやAPIの世界ではデファクトスタンダードとなっています。

SolidWorksのアセンブリ情報をJSON形式に変換できれば、次のような夢のような未来が待っています。

  • ブラウザでアセンブリ構造を表示するWebアプリケーション を構築できる。
  • クラウドデータベースにアセンブリのツリー構造と部品情報、合致情報を保存 し、SolidWorksがなくても全体像を把握できる。
  • 設計変更の履歴をJSONの差分として管理 し、詳細な変更点を追跡できる。

今回目指す「アセンブリ構造のJSONシリアライゼーションエンジン」は、まさにこの「SolidWorksデータの壁」を乗り越え、設計情報を自由自在に操るための、最高峰の技術です。

このブログ記事のゴール:
いきなり「完全な独自エンジン」を構築するのは、少しハードルが高いかもしれません。しかし、その壮大なゴールの「第一歩」として、今回はアセンブリの「ツリー階層」と「基本的なコンポーネント情報(名前、ファイルパス、位置と向き)」をSolidWorks VBAで取得し、それをJSON「風」のテキストとして表現する道筋を、丁寧に解説していきます。

2. SolidWorks VBAの基本のキ:APIオブジェクトへのアクセス

SolidWorksの情報をVBAで操作するには、SolidWorksが提供する「API(Application Programming Interface)」という窓口を通して行います。APIは、SolidWorksの内部にある様々な機能やデータにアクセスするための「命令セット」だと思ってください。

2.1 SolidWorksアプリケーションオブジェクトの取得

まず、VBAからSolidWorksアプリケーション本体に接続する必要があります。

.net
‘ SolidWorks APIを使用するための参照設定が必要です。
‘ VBAエディタで「ツール」->「参照設定」を選択し、
‘ 「SolidWorks 20XX Type Library」にチェックを入れてください。

Dim swApp As SldWorks.SldWorks ‘ SolidWorksアプリケーションオブジェクト
Dim swModel As SldWorks.ModelDoc2 ‘ 開いているドキュメントのオブジェクト

‘ 1. 実行中のSolidWorksアプリケーションに接続する
Set swApp = Application.SldWorks

If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。またはAPIへの接続に失敗しました。”, vbCritical
Exit Sub
End If

‘ 2. 現在アクティブなドキュメント(ファイル)を取得する
Set swModel = swApp.ActiveDoc

If swModel Is Nothing Then
MsgBox “アクティブなドキュメントがありません。”, vbCritical
Exit Sub
End If

‘ ここまで来れば、swAppとswModelを通じてSolidWorksを操作できます。

【ここがポイント!】参照設定の重要性
上記のコードを動かすためには、VBAプロジェクトに「SolidWorks 20XX Type Library」(XXはSolidWorksのバージョン)への参照設定が必要です。これがないと、`SldWorks.SldWorks` などの型が認識されず、「ユーザー定義型は定義されていません」といったエラーが発生します。

2.2 アセンブリドキュメントへのキャスト

`swModel` は、パーツ、アセンブリ、図面など、全てのSolidWorksドキュメントの共通の型です。今回はアセンブリを扱いますので、`swModel` が本当にアセンブリドキュメントであるかを確認し、`AssemblyDoc` 型に「キャスト」します。

.net
Dim swAssy As SldWorks.AssemblyDoc ‘ アセンブリドキュメントオブジェクト

If swModel.GetType <> swDocumentTypes_e.swDocAssembly Then
MsgBox “アクティブなドキュメントはアセンブリではありません。”, vbCritical
Exit Sub
End If

‘ ModelDoc2型からAssemblyDoc型へキャスト(より具体的な型に変換)
Set swAssy = swModel

これで `swAssy` オブジェクトを通じて、アセンブリ固有のプロパティやメソッドにアクセスできるようになりました。

3. アセンブリの「ツリー階層」を探索する旅

アセンブリは、親アセンブリの中に子部品や子サブアセンブリが含まれる、まさに「ツリー構造」をしています。このツリーをVBAで辿っていくことが、JSONシリアライゼーションの第一歩です。

3.1 コンポーネントとは?`Component2` オブジェクトの理解

SolidWorksのアセンブリにおいて、ツリー構造を構成する一つ一つの要素(部品やサブアセンブリ)は、APIでは `Component2` オブジェクトとして表現されます。

アセンブリの最上位には、ルートとなる `Component2` が存在します。そこから再帰的に (`GetChildren` メソッドを使って) 子コンポーネントを取得していくことで、アセンブリ全体のツリー構造を探索できます。

3.2 再帰処理でアセンブリツリーを辿る

アセンブリのツリー構造を探索する際、最も強力な手法が「再帰処理」です。自分自身を呼び出す関数を使って、深さ優先でツリーを辿ります。

.net
‘ コンポーネント情報を格納するためのカスタムクラス(またはDictionary)を想定
‘ 今回はシンプルに、情報を直接出力する形にします。

Private Sub TraverseAssembly(ByVal swComp As SldWorks.Component2, ByVal indentLevel As Integer)
Dim vChildren As Variant ‘ 子コンポーネントの配列
Dim swChildComp As SldWorks.Component2 ‘ 各子コンポーネント
Dim sIndent As String ‘ インデント用文字列
Dim i As Integer

‘ インデント文字列の生成
For i = 1 To indentLevel
sIndent = sIndent & ” ” ‘ スペース2つでインデント
Next i

‘ 現在のコンポーネント情報を出力
Debug.Print sIndent & “コンポーネント名: ” & swComp.Name2
Debug.Print sIndent & ” 参照名: ” & swComp.GetPathName() ‘ SolidWorks内での一意なパス
Debug.Print sIndent & ” ファイルパス: ” & swComp.GetPathName() & ” (これは参照名と同じではありませんが、簡単化のため)” ‘ 実際のファイルパスはもっと複雑な取得が必要

‘ 子コンポーネントを取得
vChildren = swComp.GetChildren()

If Not IsEmpty(vChildren) Then
For Each swChildComp In vChildren
‘ 子コンポーネントに対して再帰的に自身を呼び出す
Call TraverseAssembly(swChildComp, indentLevel + 1)
Next swChildComp
End If
End Sub

‘ メイン処理からの呼び出し例
Sub GetAssemblyTreeInfo()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim swRootComp As SldWorks.Component2 ‘ 最上位のアセンブリコンポーネント

Set swApp = Application.SldWorks
If swApp Is Nothing Then MsgBox “SolidWorksが起動していません”: Exit Sub

Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then MsgBox “アクティブなドキュメントがありません”: Exit Sub
If swModel.GetType <> swDocumentTypes_e.swDocAssembly Then MsgBox “アクティブなドキュメントはアセンブリではありません”: Exit Sub

Set swAssy = swModel

‘ 最上位のコンポーネントを取得 (通常はアセンブリ自体)
Set swRootComp = swAssy.GetRootComponent3(True) ‘ TrueはLightweightでない状態を取得

If Not swRootComp Is Nothing Then
Call TraverseAssembly(swRootComp, 0) ‘ 0は最初のインデントレベル
End If

Set swRootComp = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
End Sub

【ここがポイント!】 `Component2.Name2` と `Component2.GetPathName()`

  • `Name2`: SolidWorksのアセンブリツリーに表示されるコンポーネント名です。同じ部品を複数配置した場合、例えば「Part1-1」「Part1-2」のように自動的にサフィックスが付きます。
  • `GetPathName()`: アセンブリ内でのコンポーネントの一意なパスを返します。サブアセンブリの中の部品など、階層構造を含んだパスになります。JSON化する際には、このパスが非常に重要になります。

4. コンポーネントの位置と向き、座標情報を取得する

アセンブリにおいて、各コンポーネントがどこに、どのような向きで配置されているかは、非常に重要な情報です。これはAPIでは `Transform` オブジェクトとして表現されます。

`Transform` は、コンポーネントの「位置(Translation)」と「向き(Rotation Matrix)」を数学的に表現したものです。

.net
Private Sub GetCompTransform(ByVal swComp As SldWorks.Component2, ByVal indentLevel As Integer)
‘ … (前略) …
Dim swTransform As SldWorks.MathTransform ‘ トランスフォームオブジェクト
Dim vMatrix As Variant ‘ 行列データ (16個のDouble値)
Dim sIndent As String

‘ インデント生成 (省略)
For i = 1 To indentLevel: sIndent = sIndent & ” “: Next i

‘ コンポーネントのトランスフォームを取得
‘ 親アセンブリに対する相対的な位置と向きを取得します。
Set swTransform = swComp.Transform2

If Not swTransform Is Nothing Then
‘ トランスフォームの行列データを取得 (16個のDouble値の配列)
‘ この配列には、回転行列 (3×3) と平行移動ベクトル (3×1) が含まれています。
vMatrix = swTransform.ArrayData

‘ 位置情報 (X, Y, Z) を取り出す (メートル単位)
‘ vMatrix(9), vMatrix(10), vMatrix(11) が平行移動ベクトル (X, Y, Z) に対応します。
Debug.Print sIndent & ” 位置 (X, Y, Z): ” & Format(vMatrix(9) 1000, “0.00”) & “mm, ” & _
Format(vMatrix(10) 1000, “0.00”) & “mm, ” & _
Format(vMatrix(11) 1000, “0.00”) & “mm”

‘ 向き情報 (回転行列) を出力(ここでは簡略化)
Debug.Print sIndent & ” 向き (回転行列):”
Debug.Print sIndent & ” [ ” & Format(vMatrix(0), “0.000”) & “, ” & Format(vMatrix(1), “0.000”) & “, ” & Format(vMatrix(2), “0.000”) & ” ]”
Debug.Print sIndent & ” [ ” & Format(vMatrix(3), “0.000”) & “, ” & Format(vMatrix(4), “0.000”) & “, ” & Format(vMatrix(5), “0.000”) & ” ]”
Debug.Print sIndent & ” [ ” & Format(vMatrix(6), “0.000”) & “, ” & Format(vMatrix(7), “0.000”) & “, ” & Format(vMatrix(8), “0.000”) & ” ]”
End If
End Sub

【ここがポイント!】Transformの単位と座標系

  • SolidWorks APIから取得できる座標値は、メートル(m)単位です。UIでミリメートル(mm)表示になっていても、VBAで取得するとメートルになりますので、必要に応じて` 1000`などで変換してください。
  • `Transform2` は、親アセンブリの座標系に対する相対的なトランスフォームです。アセンブリの最上位コンポーネントの `Transform2` は通常、単位行列(原点に配置され、向きも軸と一致)になります。
  • 回転行列(vMatrixの最初の9要素)は、X, Y, Z軸の単位ベクトルが、親座標系から見てどこを向いているかを示します。

5. シンプルな「合致」情報の取得に挑戦

合致(Mate)はアセンブリの部品間の拘束条件を定義するもので、これがなければアセンブリはバラバラになってしまいます。合致情報のJSON化は非常に複雑ですが、まずは「合致が存在すること」を認識し、その種類を簡単に識別するところから始めましょう。

`AssemblyDoc` オブジェクトから、アセンブリ内の全ての合致を取得できます。

.net
Sub GetMateInfo()
‘ … (swApp, swModel, swAssy の取得は省略) …

Dim vMates As Variant ‘ 全ての合致の配列
Dim swMate As SldWorks.Mate2 ‘ 各合致オブジェクト
Dim sMateType As String ‘ 合致の種類

‘ アセンブリ内の全ての合致を取得
vMates = swAssy.GetMates()

If Not IsEmpty(vMates) Then
Debug.Print “— 合致情報 —”
For Each swMate In vMates
‘ 合致のタイプを取得し、人間が読める形に変換
Select Case swMate.Type
Case swMateType_e.swMateCOINCIDENT: sMateType = “重合”
Case swMateType_e.swMateCONCENTRIC: sMateType = “同心円”
Case swMateType_e.swMatePARALLEL: sMateType = “平行”
Case swMateType_e.swMatePERPENDICULAR: sMateType = “垂直”
Case swMateType_e.swMateDISTANCE: sMateType = “距離”
Case swMateType_e.swMateANGLE: sMateType = “角度”
Case Else: sMateType = “その他 (” & swMate.Type & “)”
End Select

Debug.Print ” 合致名: ” & swMate.Name
Debug.Print ” タイプ: ” & sMateType
‘ 合致がどのコンポーネントのどのエンティティ(面、エッジなど)を参照しているか、
‘ そしてそのパラメータ(距離値など)を取得するのは、ここからさらに複雑になります。
‘ 今回は、合致の名前とタイプに留めます。
Next swMate
End If

‘ … (オブジェクト解放は省略) …
End Sub

【ここがポイント!】 合致の複雑性
合致は、どのコンポーネントのどの面やエッジといった「エンティティ」を参照しているか、そしてその参照方法やパラメータ(距離値、角度値、反転など)が多岐にわたります。これを全てJSON化するには、各合致タイプの詳細なAPIを理解し、その情報を抽出するコードを書く必要があります。これはまさに「独自エンジン」の中核となる部分であり、今回のブログではその「存在」と「簡単なタイプ識別」に留めました。

6. 取得したデータを「JSON風」に構造化する

VBAには標準でJSONライブラリがありませんが、取得した情報をJSONに似た階層構造で表現することは可能です。最も簡単な方法は、VBAの `Scripting.Dictionary` オブジェクトを使ってキーと値のペアを管理し、それを文字列として整形していくことです。

今回は、再帰処理の中でDictionaryにデータを格納し、最後に手書きでJSON文字列を構築するイメージをお見せします。

.net
‘ JSON風データ格納用 Dictionary
Private Function CreateComponentData(ByVal swComp As SldWorks.Component2, ByVal indentLevel As Integer) As Scripting.Dictionary
Dim dictComp As New Scripting.Dictionary
Dim swTransform As SldWorks.MathTransform
Dim vMatrix As Variant
Dim vChildren As Variant
Dim swChildComp As SldWorks.Component2
Dim arrChildren As New Collection ‘ 子コンポーネントのDictionaryを格納するコレクション

‘ 基本情報
dictComp.Add “Name”, swComp.Name2
dictComp.Add “PathName”, swComp.GetPathName()
dictComp.Add “FileName”, swComp.GetPathName() ‘ 簡略化

‘ トランスフォーム情報
Set swTransform = swComp.Transform2
If Not swTransform Is Nothing Then
vMatrix = swTransform.ArrayData
Dim dictTransform As New Scripting.Dictionary
dictTransform.Add “X”, vMatrix(9) 1000 ‘ mm単位
dictTransform.Add “Y”, vMatrix(10) 1000 ‘ mm単位
dictTransform.Add “Z”, vMatrix(11) 1000 ‘ mm単位
‘ 回転行列も追加可能だが、ここでは省略
dictComp.Add “Position”, dictTransform
End If

‘ 子コンポーネントの再帰処理
vChildren = swComp.GetChildren()
If Not IsEmpty(vChildren) Then
For Each swChildComp In vChildren
arrChildren.Add CreateComponentData(swChildComp, indentLevel + 1)
Next swChildComp
End If
If arrChildren.Count > 0 Then
dictComp.Add “Children”, arrChildren ‘ 子コンポーネントの配列を格納
End If

Set CreateComponentData = dictComp
End Function

‘ DictionaryをJSON文字列に変換する簡易関数 (非常に簡易的な例)
Private Function ConvertDictToJsonString(ByVal dict As Scripting.Dictionary, Optional ByVal indent As String = “”, Optional ByVal level As Integer = 0) As String
Dim sJson As String
Dim sKey As Variant
Dim sCurrentIndent As String
Dim sNextIndent As String
Dim i As Integer

For i = 1 To level: sCurrentIndent = sCurrentIndent & indent: Next i
sNextIndent = sCurrentIndent & indent

sJson = “{” & vbCrLf
Dim bFirstItem As Boolean: bFirstItem = True

For Each sKey In dict.Keys
If Not bFirstItem Then sJson = sJson & “,” & vbCrLf
sJson = sJson & sNextIndent & “””” & sKey & “””: ”

Select Case VarType(dict.Item(sKey))
Case vbString: sJson = sJson & “””” & Replace(dict.Item(sKey), “”””, “\”””) & “”””
Case vbInteger, vbLong, vbSingle, vbDouble: sJson = sJson & CStr(dict.Item(sKey))
Case vbObject ‘ Dictionary または Collection の場合
If TypeOf dict.Item(sKey) Is Scripting.Dictionary Then
sJson = sJson & ConvertDictToJsonString(dict.Item(sKey), indent, level + 1)
ElseIf TypeOf dict.Item(sKey) Is Collection Then
Dim col As Collection: Set col = dict.Item(sKey)
Dim vItem As Variant
sJson = sJson & “[” & vbCrLf
Dim bFirstArrayItem As Boolean: bFirstArrayItem = True
For Each vItem In col
If Not bFirstArrayItem Then sJson = sJson & “,” & vbCrLf
If TypeOf vItem Is Scripting.Dictionary Then
sJson = sJson & ConvertDictToJsonString(vItem, indent, level + 1)
Else
sJson = sJson & sNextIndent & indent & “””” & Replace(CStr(vItem), “”””, “\”””) & “””” ‘ 配列内の単純な値
End If
bFirstArrayItem = False
Next vItem
sJson = sJson & vbCrLf & sNextIndent & “]”
Else
sJson = sJson & “null” ‘ 未対応のオブジェクト
End If
Case Else: sJson = sJson & “null” ‘ その他の型
End Select
bFirstItem = False
Next sKey

sJson = sJson & vbCrLf & sCurrentIndent & “}”
ConvertDictToJsonString = sJson
End Function

【コードのポイント!】

  • `Scripting.Dictionary` を使うには、VBAエディタで「ツール」->「参照設定」を選択し、「Microsoft Scripting Runtime」にチェックを入れてください。
  • `CreateComponentData` 関数は、再帰的に自身を呼び出し、各コンポーネントの情報をDictionaryに格納します。子コンポーネントは `Children` というキーの `Collection` オブジェクトとして格納されます。
  • `ConvertDictToJsonString` は、VBAでJSON形式の文字列を手動で構築する非常に簡易的な例です。実用的なJSONパーサー・シリアライザー(例えばVBA-JSON)に比べると機能は限られますが、データの構造を理解する上では役立ちます。

7. 実践!アセンブリ情報を取得し、JSON風に出力するVBAコード

これまでの要素を組み合わせ、アセンブリのツリー構造と基本的なコンポーネント情報を取得し、JSON風の文字列としてデバッグウィンドウに出力する完全なコードです。

.net
‘ — 参照設定 —
‘ 1. SolidWorks 20XX Type Library
‘ 2. Microsoft Scripting Runtime

‘ JSON風データ格納用 Dictionaryを生成する再帰関数
Private Function BuildComponentDictionary(ByVal swComp As SldWorks.Component2) As Scripting.Dictionary
Dim dictComp As New Scripting.Dictionary
Dim swTransform As SldWorks.MathTransform
Dim vMatrix As Variant
Dim vChildren As Variant
Dim swChildComp As SldWorks.Component2
Dim colChildren As New Collection ‘ 子コンポーネントのDictionaryを格納するコレクション

On Error GoTo ErrorHandler

‘ 基本情報
dictComp.Add “Name”, swComp.Name2 ‘ SolidWorksツリー表示名
dictComp.Add “ReferencedPath”, swComp.GetPathName() ‘ アセンブリ内での一意なパス

‘ 参照しているファイルパス (実ファイルパスはGetPathName()とは異なる場合が多いが、ここでは簡略化)
‘ 実際のファイルパスを取得するには、ModelDoc2を取得し、GetPathNameを呼び出す必要があります。
‘ 例: swComp.GetModelDoc2.GetPathName()
If Not swComp.GetModelDoc2 Is Nothing Then
dictComp.Add “SourceFile”, swComp.GetModelDoc2.GetPathName()
Else
dictComp.Add “SourceFile”, “Not available (Virtual component or error)”
End If

‘ トランスフォーム情報 (位置と向き)
Set swTransform = swComp.Transform2
If Not swTransform Is Nothing Then
vMatrix = swTransform.ArrayData
Dim dictPosition As New Scripting.Dictionary

‘ 位置 (メートル単位 -> ミリメートル単位に変換)
dictPosition.Add “X_mm”, vMatrix(9) 1000
dictPosition.Add “Y_mm”, vMatrix(10) 1000
dictPosition.Add “Z_mm”, vMatrix(11) 1000

‘ 回転行列 (3×3) を表現
Dim arrRotation(2, 2) As Double
arrRotation(0, 0) = vMatrix(0): arrRotation(0, 1) = vMatrix(1): arrRotation(0, 2) = vMatrix(2)
arrRotation(1, 0) = vMatrix(3): arrRotation(1, 1) = vMatrix(4): arrRotation(1, 2) = vMatrix(5)
arrRotation(2, 0) = vMatrix(6): arrRotation(2, 1) = vMatrix(7): arrRotation(2, 2) = vMatrix(8)

‘ JSONに配列として格納するため、Collectionに変換
Dim colRotMatrix As New Collection
colRotMatrix.Add Array(arrRotation(0, 0), arrRotation(0, 1), arrRotation(0, 2))
colRotMatrix.Add Array(arrRotation(1, 0), arrRotation(1, 1), arrRotation(1, 2))
colRotMatrix.Add Array(arrRotation(2, 0), arrRotation(2, 1), arrRotation(2, 2))

Dim dictTransformData As New Scripting.Dictionary
dictTransformData.Add “Translation”, dictPosition
dictTransformData.Add “RotationMatrix”, colRotMatrix

dictComp.Add “Transform”, dictTransformData
End If

‘ 子コンポーネントの再帰処理
vChildren = swComp.GetChildren()
If Not IsEmpty(vChildren) Then
For Each swChildComp In vChildren
‘ 子コンポーネントが有効な場合のみ処理
If Not swChildComp Is Nothing Then
colChildren.Add BuildComponentDictionary(swChildComp)
End If
Next swChildComp
End If
If colChildren.Count > 0 Then
dictComp.Add “Children”, colChildren
End If

Set BuildComponentDictionary = dictComp
Exit Function

ErrorHandler:
Debug.Print “エラー発生: ” & Err.Description & ” (コンポーネント: ” & swComp.Name2 & “)”
Set BuildComponentDictionary = New Scripting.Dictionary ‘ エラー時は空のDictionaryを返す
End Function

‘ DictionaryオブジェクトからJSON文字列を生成する関数 (簡略版)
‘ 実運用ではVBA-JSONのようなライブラリの使用を強く推奨します。
Private Function DictionaryToJson(ByVal dict As Scripting.Dictionary, Optional ByVal indentChar As String = ” “, Optional ByVal level As Integer = 0) As String
Dim sJson As String
Dim sKey As Variant
Dim sCurrentIndent As String
Dim sNextIndent As String
Dim bFirstItem As Boolean
Dim i As Integer

For i = 1 To level: sCurrentIndent = sCurrentIndent & indentChar: Next i
sNextIndent = sCurrentIndent & indentChar

sJson = “{” & vbCrLf
bFirstItem = True

For Each sKey In dict.Keys
If Not bFirstItem Then sJson = sJson & “,” & vbCrLf
sJson = sJson & sNextIndent & “””” & sKey & “””: ”

Select Case True
Case TypeOf dict.Item(sKey) Is Scripting.Dictionary
sJson = sJson & DictionaryToJson(dict.Item(sKey), indentChar, level + 1)
Case TypeOf dict.Item(sKey) Is Collection
Dim col As Collection: Set col = dict.Item(sKey)
sJson = sJson & “[” & vbCrLf
Dim bFirstColItem As Boolean: bFirstColItem = True
For Each vItem In col
If Not bFirstColItem Then sJson = sJson & “,” & vbCrLf
If TypeOf vItem Is Scripting.Dictionary Then
sJson = sJson & DictionaryToJson(vItem, indentChar, level + 1)
ElseIf IsArray(vItem) Then ‘ 回転行列の配列など
sJson = sJson & sNextIndent & indentChar & “[” & Join(vItem, “, “) & “]”
Else ‘ 単純な値
sJson = sJson & sNextIndent & indentChar & “””” & Replace(CStr(vItem), “”””, “\”””) & “”””
End If
bFirstColItem = False
Next vItem
sJson = sJson & vbCrLf & sNextIndent & “]”
Case IsNumeric(dict.Item(sKey))
sJson = sJson & CStr(dict.Item(sKey))
Case Else ‘ 文字列など
sJson = sJson & “””” & Replace(CStr(dict.Item(sKey)), “”””, “\”””) & “”””
End Select
bFirstItem = False
Next sKey

sJson = sJson & vbCrLf & sCurrentIndent & “}”
DictionaryToJson = sJson
End Function

‘ メインの実行プロシージャ
Sub ExportAssemblyToJson()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssy As SldWorks.AssemblyDoc
Dim swRootComp As SldWorks.Component2
Dim dictAssemblyData As Scripting.Dictionary
Dim sJsonOutput As String

‘ SolidWorksアプリケーションに接続
Set swApp = Application.SldWorks
If swApp Is Nothing Then
MsgBox “SolidWorksが起動していません。”, vbCritical: Exit Sub
End If

‘ アクティブなドキュメントを取得し、アセンブリであることを確認
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントがありません。”, vbCritical: Exit Sub
End If
If swModel.GetType <> swDocumentTypes_e.swDocAssembly Then
MsgBox “アクティブなドキュメントはアセンブリではありません。”, vbCritical: Exit Sub
End If
Set swAssy = swModel

‘ 最上位のコンポーネントを取得
Set swRootComp = swAssy.GetRootComponent3(True) ‘ Trueでライトウェイト解除

If Not swRootComp Is Nothing Then
‘ アセンブリツリーを辿り、Dictionaryにデータを構築
Set dictAssemblyData = BuildComponentDictionary(swRootComp)

‘ 構築したDictionaryからJSON文字列を生成
sJsonOutput = DictionaryToJson(dictAssemblyData)

‘ デバッグウィンドウに出力 (VBEのCtrl+Gで表示)
Debug.Print “— 生成されたJSONデータ —”
Debug.Print sJsonOutput
Debug.Print “—————————-”

‘ 必要であれば、ファイルに書き出す
‘ Dim fso As Object: Set fso = CreateObject(“Scripting.FileSystemObject”)
‘ Dim ts As Object: Set ts = fso.CreateTextFile(“C:\temp\assembly_data.json”, True)
‘ ts.Write sJsonOutput
‘ ts.Close
‘ MsgBox “JSONデータが C:\temp\assembly_data.json に出力されました。”
Else
MsgBox “アセンブリのルートコンポーネントが取得できませんでした。”, vbCritical
End If

‘ オブジェクトの解放 (重要!)
Set swRootComp = Nothing
Set swAssy = Nothing
Set swModel = Nothing
Set swApp = Nothing
Set dictAssemblyData = Nothing
End Sub

【エラーハンドリングの重要性】
上記コードでは、`BuildComponentDictionary` 関数に `On Error GoTo ErrorHandler` を追加しました。SolidWorks APIは、様々な状況でエラーを返すことがあります(例えば、コンポーネントが解決できない、ライトウェイト状態、外部参照が壊れているなど)。堅牢なコードを書くためには、常にエラーハンドリングを意識することが非常に重要です。

【オブジェクトのライフサイクル】
VBAでSolidWorks APIを扱う際、取得したオブジェクト(`swApp`, `swModel`, `swComp` など)は、使い終わったら必ず `Set obj = Nothing` で解放するようにしましょう。これを怠ると、メモリリークやSolidWorksアプリケーションの不安定化の原因となることがあります。特にループ内で大量のオブジェクトを生成・取得する場合は、この解放処理がパフォーマンスに大きく影響します。

8. 次のステップへ:JSONからの復元、本格的なJSONライブラリ、合致の完全シリアライズ

お疲れ様でした!この一歩を踏み出した皆さんは、SolidWorks VBAの基本をしっかりとマスターし、アセンブリ情報の取得と構造化の基礎を築きました。

この記事で学んだことは:

  • SolidWorks APIを通じてアプリケーションとドキュメントにアクセスする方法
  • アセンブリのツリー階層を再帰的に探索し、各コンポーネントの情報を取得する方法
  • コンポーネントの位置と向き(Transform)の基本概念と取得方法
  • 合致情報の概要と簡単な識別方法
  • 取得したデータをVBAのDictionaryとCollectionを使ってJSON「風」に構造化する基本

もちろん、「アセンブリ構造のJSONシリアライゼーションエンジン」という究極の目標へは、まだ道半ばです。

次のステップで挑戦したいこと:

1. 本格的なJSONライブラリの導入: VBAでより堅牢かつ効率的にJSONを扱うには、[VBA-JSON](https://github.com/VBA-tools/VBA-JSON) のような外部ライブラリの利用を検討しましょう。これにより、手書きのJSON文字列生成から解放され、より複雑なデータ構造も簡単に扱えるようになります。
2. 合致の完全シリアライゼーション: これが最も難しく、しかし最も価値のある挑戦です。各合致タイプ(同心円、平行、距離など)が参照しているエンティティ(面、エッジ、頂点)や、そのパラメータ(距離値、角度値、反転など)を詳細に取得し、JSONとして表現する必要があります。これは、SolidWorksのAPIドキュメントを深く読み込み、多くの試行錯誤が必要となるでしょう。
3. JSONからのアセンブリ復元: シリアライズしたJSONデータから、VBAを使ってSolidWorksアセンブリをプログラム的に再構築するプロセスです。これは、`AddComponent` や `AddMate` といったAPIメソッドを駆使することになります。

アセンブリのJSONシリアライゼーションと復元は、皆さんがSolidWorksと他のシステムを連携させ、設計プロセスを革新するための強力な武器となります。道のりは長いかもしれませんが、この一歩一歩が、皆さんのエンジニアとしての視野を広げ、新たな可能性を切り開く原動力となるでしょう。

未来の設計システムを創造する旅は、まだ始まったばかりです。頑張ってください!応援しています!

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