【上級プロ向け】SolidWorksアセンブリ構造をJSONで完全シリアライズ:ツリー階層・合致・マトリクス座標をテキスト化して完全復元する独自エンジン
開発プロジェクトの皆さん、そしてSolidWorksの自動化に情熱を燃やすエンジニア諸君。私は長年、この強力なCADツールのAPIと格闘し、その深淵を覗き込んできました。今回は、皆さんが日々の業務で直面するであろう、アセンブリモデルの管理と再構築という、極めてクリティカルな課題に対する、私なりの「究極の解」を伝授したいと思います。
「なぜ、SolidWorksの複雑なアセンブリ構造を、単なるファイル保存で済ませているのか?」「なぜ、手作業での合致定義や配置に、貴重な時間を浪費しているのか?」—— これらの問いに、私は「No」と断言します。今日、皆さんと共有するのは、アセンブリのツリー階層、全ての合致定義、そして各コンポーネントのマトリクス座標情報までを、独自のJSONスキーマにシリアライズし、コードベースから完全に再現する、まさに「究極のデータ管理手法」です。
これは単なるデータのエクスポート・インポートではありません。SolidWorksのAPIの奥深くに眠る「コンポーネントのライフサイクル」、API呼び出しの「パフォーマンスの重み」を理解したからこそ到達できる、堅牢で、保守性が高く、そして何よりも「バグの起きにくい」設計思想に基づいた、プロダクションレベルのソリューションです。
なぜ、JSONシリアライゼーションが「究極」なのか?
まず、なぜこのアプローチが他の方法よりも優れているのかを明確にしましょう。
- 完全な再現性: SolidWorksのネイティブファイル形式は、その内部構造を直接的に、かつ網羅的に把握することは困難です。JSONは、構造化されたテキストデータであり、ツリー構造、プロパティ、関係性を明確に定義できます。これにより、コードから完全に同一のアセンブリを、一切の誤差なく再構築することが可能になります。
- コードベースでの管理: アセンブリ情報をJSONという「コード」として扱うことで、Gitなどのバージョン管理システムで管理できます。これにより、誰が、いつ、どのような変更を加えたのかが明確になり、変更履歴の追跡や、過去の状態へのロールバックが容易になります。
- 柔軟な連携: JSONは、Web API、データベース、他のアプリケーションとの連携において、デファクトスタンダードとも言えるフォーマットです。このJSONデータを出力できれば、他のシステムとの連携が劇的に容易になります。例えば、PDMシステムとの連携、Webベースのビューアへのデータ投入などが考えられます。
- APIの「重み」を理解した設計: SolidWorks APIの呼び出しは、特に大規模アセンブリになると、そのパフォーマンスへの影響は無視できません。コンポーネントの列挙、合致の取得・設定、トランスフォーメーションの適用といった操作は、APIの呼び出し回数と処理内容によってパフォーマンスが大きく左右されます。 JSONシリアライゼーションでは、必要な情報を一度に取得し、後続の処理で効率的に利用することで、API呼び出しのオーバーヘッドを最小限に抑えます。
独自JSONスキーマ設計の鍵:コンポーネント、合致、トランスフォーメーション
では、具体的にどのようなJSONスキーマを設計すべきか。ここで、SolidWorks APIのオブジェクトライフサイクルと、各要素の依存関係を深く理解しているかどうかが、設計の質を決定づけます。
1. アセンブリツリー階層の表現
アセンブリは、親子関係を持つツリー構造です。これをJSONで表現するには、再帰的な構造が適しています。
{
“assemblyName”: “MyTopLevelAssembly.SLDASM”,
“components”: [
{
“componentName”: “Part1.SLDPRT”,
“componentType”: “Part”, // “Part” or “Assembly”
“configurationName”: “Default”,
“suppressed”: false,
“locked”: false,
“transform”: { // ローカル座標系でのトランスフォーメーション
“m11”: 1.0, “m12”: 0.0, “m13”: 0.0, “m14”: 0.0,
“m21”: 0.0, “m22”: 1.0, “m23”: 0.0, “m24”: 0.0,
“m31”: 0.0, “m32”: 0.0, “m33”: 1.0, “m34”: 0.0,
“m41”: 0.0, “m42”: 0.0, “m43”: 0.0, “m44”: 1.0
},
“children”: [ // サブコンポーネント (サブアセンブリの場合)
{
“componentName”: “SubAssembly1.SLDASM”,
“componentType”: “Assembly”,
“configurationName”: “ConfigA”,
“suppressed”: false,
“locked”: false,
“transform”: { … },
“children”: []
}
],
“mates”: [ // このコンポーネントに定義された合致
// 合致定義オブジェクト
]
},
// … 他のコンポーネント
]
}
【設計のポイント】
- `componentName`: ファイル名(拡張子含む)を基本とします。
- `componentType`: PartかAssemblyかを明示します。
- `configurationName`: コンポーネントが参照するコンフィギュレーション名を記録します。
- `suppressed`, `locked`: コンポーネントの状態も保持します。
- `transform`: SolidWorks APIの `ITransform` オブジェクトが持つ16要素のマトリクスです。このマトリクスは、親コンポーネント(またはアセンブリ原点)からの相対的な位置・姿勢を示します。 これを正しく取得・設定することが、復元時の配置の鍵となります。
- `children`: サブアセンブリの場合、その内部のコンポーネントを再帰的に定義します。
2. 合致(Mate)定義の表現
合致は、アセンブリの拘束条件を定義する最も重要な要素です。各合致には、定義に使用されたジオメトリ、合致の種類、オフセット、反転などの情報が含まれます。
{
“mateName”: “Distance-0001”, // SolidWorksでの合致名
“mateType”: “Distance”, // e.g., “Concentric”, “Coincident”, “Distance”, “Angle”, “Width”
“entity1”: {
“componentName”: “Part1.SLDPRT”,
“entityType”: “Face”, // e.g., “Face”, “Edge”, “Vertex”, “Plane”, “Axis”
“entityID”: 12345 // SolidWorks内部のエンティティID (取得・利用には注意が必要)
// または、復元時に特定しやすい識別子 (例: Feature名、ジオメトリ名)
},
“entity2”: {
“componentName”: “Part2.SLDPRT”,
“entityType”: “Face”,
“entityID”: 67890
},
“value”: 0.001, // 合致の値 (距離、角度など)
“reverse”: false, // 合致の方向反転
“standardMate”: true, // 標準合致かどうか
“tolerance”: { // 公差情報 (必要であれば)
“type”: “Symmetric”,
“upper”: 0.002,
“lower”: -0.002
}
}
【設計のポイント】
- `mateName`: SolidWorksでの合致名を保持します。デバッグや特定に役立ちます。
- `mateType`: 合致の種類を文字列で定義します。APIで利用可能な定数とマッピングします。
- `entity1`, `entity2`: 合致を定義する2つのエンティティを指定します。
- `componentName`: どのコンポーネントのエンティティかを特定します。
- `entityType`: エンティティの種類(面、エッジ、頂点、平面、軸)を明示します。
- `entityID`: SolidWorks内部のエンティティIDは、アセンブリの再構築後には無効になる可能性が非常に高いです。これは、APIのオブジェクトライフサイクルの観点から非常に重要です。復元時には、このIDに依存せず、エンティティを特定する別の方法(例:Feature名、ジオメトリの特定方法、あるいは復元時に動的にエンティティを特定するロジック)を実装する必要があります。
- `value`, `reverse`: 合致の具体的な設定値を保持します。
- `tolerance`: 公差情報も必要であれば含めます。
3. トランスフォーメーション(マトリクス座標)の表現
コンポーネントの配置情報(位置と姿勢)は、16要素の転置行列(`ITransform`)で表現されます。
{
“m11”: 1.0, “m12”: 0.0, “m13”: 0.0, “m14”: 0.0,
“m21”: 0.0, “m22”: 1.0, “m23”: 0.0, “m24”: 0.0,
“m31”: 0.0, “m32”: 0.0, “m33”: 1.0, “m34”: 0.0,
“m41”: 0.0, “m42”: 0.0, “m43”: 0.0, “m44”: 1.0
}
【設計のポイント】
- これは、APIの `ITransform` オブジェクトをそのままJSONにマッピングしたものです。
- このトランスフォーメーションは、親コンポーネント(またはアセンブリ原点)からの相対的なものです。 復元時には、この親コンポーネントのトランスフォーメーションも考慮して、最終的な絶対座標(ワールド座標)を計算して適用する必要があります。
- 「First Component Pattern」や「Component Pattern」など、パターン配置されたコンポーネントのトランスフォーメーションは、直接取得するのではなく、パターン定義から再計算する必要があります。 JSONに格納する際には、パターン情報を別途保持するか、あるいはパターンとして復元するロジックを実装する必要があります。
実務で役立つ堅牢な設計とプロダクションコード例
ここからは、皆さんが開発現場でそのままコピペして使える、堅牢で保守性の高いVBA/VB.NETコード例を示します。バグの温床となりやすい「エンティティIDへの依存」や「API呼び出しの非効率性」を回避するための設計思想を盛り込んでいます。
1. JSONシリアライゼーション(エクスポート)コード例(VBA)
ここでは、アセンブリツリーを走査し、コンポーネント情報、合致情報、トランスフォーメーションを取得してJSON構造に格納するVBAコードを示します。`entityID` への依存を避けるため、合致定義には「Feature名」や「ジオメトリの特定方法」を考慮するロジックを実装することが重要ですが、ここでは簡略化のため、APIで直接取得できる情報(例:合致の定義エンティティの参照)を元に構造化します。
【注意点】
- このコードは、「アセンブリのコンポーネントを、その配置情報(トランスフォーメーション)と合致定義を保持したまま、JSONとしてエクスポートする」 ことを目的としています。
- `entityID` の扱いは、前述の通り、復元時の問題の元凶となり得ます。 実際のプロダクションコードでは、エンティティを特定するためのよりロバストな方法(例:フィーチャー名、ジオメトリのプロパティ、あるいは復元時に動的に特定するロジック)を検討してください。
- JSONの生成には、外部ライブラリ(例:`Newtonsoft.Json` for VB.NET)を使用するのが一般的ですが、VBAでは直接的なJSON生成が困難なため、ここでは構造体と文字列結合で簡易的に表現します。VB.NET環境であれば、`Newtonsoft.Json` を利用することを強く推奨します。
Option Explicit
‘ — JSON構造を模倣するためのクラスモジュール —
‘ (VBAではクラスモジュールがJSONオブジェクトの代わりになります)
‘ コンポーネント情報
Public Type ComponentInfo
ComponentName As String
ComponentType As String ‘ “Part” or “Assembly”
ConfigurationName As String
Suppressed As Boolean
Locked As Boolean
Transform As TypeTransform
Children() As ComponentInfo
Mates() As MateInfo
End Type
‘ Transform情報 (16要素のマトリクス)
Public Type TypeTransform
m11 As Double, m12 As Double, m13 As Double, m14 As Double
m21 As Double, m22 As Double, m23 As Double, m24 As Double
m31 As Double, m32 As Double, m33 As Double, m34 As Double
m41 As Double, m42 As Double, m43 As Double, m44 As Double
End Type
‘ 合致情報
Public Type MateInfo
MateName As String
MateType As String
Entity1 As MateEntity
Entity2 As MateEntity
Value As Double
Reverse As Boolean
StandardMate As Boolean
‘ Tolerance As TypeTolerance ‘ 必要であれば追加
End Type
‘ 合致エンティティ情報
Public Type MateEntity
ComponentName As String
EntityType As String ‘ “Face”, “Edge”, “Vertex”, “Plane”, “Axis”
‘ EntityID As Long ‘ ← ★★★ 復元時の問題になりやすいため、ここでは使用しない ★★★
‘ 代わりに、復元時に特定しやすい情報(例:フィーチャー名、ジオメトリの特定方法)を考慮する
End Type
‘ — メイン処理 —
‘ SolidWorks アプリケーションオブジェクト (グローバル、または引数で渡す)
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swAssembly As SldWorks.AssemblyDoc
Dim swComponent As SldWorks.Component2
Dim swConfiguration As SldWorks.Configuration
‘ JSON生成用変数
Dim rootComponent As ComponentInfo
Dim jsonOutput As String
Sub ExportAssemblyToJson()
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
If swModel Is Nothing Then
MsgBox “アクティブなドキュメントがありません。”, vbExclamation
Exit Sub
End If
If swModel.GetType <> swDocASSEMBLY Then
MsgBox “アクティブなドキュメントはアセンブリではありません。”, vbExclamation
Exit Sub
End If
Set swAssembly = swModel
Set swConfiguration = swAssembly.GetActiveConfiguration
‘ ルートコンポーネントの初期化
ReDim rootComponent.Children(0)
ReDim rootComponent.Mates(0)
‘ ルートアセンブリの情報を取得
rootComponent.ComponentName = swModel.GetPathName
rootComponent.ComponentType = “Assembly”
rootComponent.ConfigurationName = swConfiguration.Name
rootComponent.Suppressed = False ‘ ルートアセンブリ自体は抑制されない
rootComponent.Locked = False ‘ ルートアセンブリ自体はロックされない
‘ ルートコンポーネントに直下のコンポーネントを再帰的に処理
Dim topLevelComponents As Variant
topLevelComponents = swAssembly.GetComponents(True) ‘ True = Flatten
Dim componentCount As Long
componentCount = UBound(topLevelComponents) + 1
ReDim rootComponent.Children(componentCount – 1)
Dim i As Long
For i = 0 To UBound(topLevelComponents)
Set swComponent = topLevelComponents(i)
ProcessComponent swComponent, rootComponent.Children(i)
Next i
‘ JSON文字列の生成 (簡易版)
jsonOutput = ConvertToJson(rootComponent)
‘ ファイルに保存
Dim filePath As String
filePath = swModel.GetPathName
filePath = Left(filePath, InStrRev(filePath, “.”)) & “json”
Dim fso As Object
Set fso = CreateObject(“Scripting.FileSystemObject”)
Dim ts As Object
Set ts = fso.CreateTextFile(filePath, True)
ts.Write jsonOutput
ts.Close
MsgBox “アセンブリ構造をJSONファイルにエクスポートしました: ” & filePath, vbInformation
End Sub
‘ コンポーネントを再帰的に処理する関数
Private Sub ProcessComponent(ByVal currentSWComponent As SldWorks.Component2, ByRef targetComponentInfo As ComponentInfo)
Dim swModelDoc As SldWorks.ModelDoc2
Dim swSubAssembly As SldWorks.AssemblyDoc
Dim swPart As SldWorks.PartDoc
Dim swTransform As SldWorks.ITransform
Set swModelDoc = currentSWComponent.GetModelDoc2
targetComponentInfo.ComponentName = swModelDoc.GetPathName
targetComponentInfo.Suppressed = currentSWComponent.IsSuppressed
targetComponentInfo.Locked = currentSWComponent.IsLocked
‘ コンフィギュレーション名を取得
Dim swComponentConfiguration As SldWorks.Configuration
Set swComponentConfiguration = currentSWComponent.ReferencedConfiguration
If Not swComponentConfiguration Is Nothing Then
targetComponentInfo.ConfigurationName = swComponentConfiguration.Name
Else
targetComponentInfo.ConfigurationName = “” ‘ 参照コンフィギュレーションがない場合
End If
‘ コンポーネントタイプを判定
If swModelDoc.GetType = swDocPART Then
targetComponentInfo.ComponentType = “Part”
Set swPart = swModelDoc
ElseIf swModelDoc.GetType = swDocASSEMBLY Then
targetComponentInfo.ComponentType = “Assembly”
Set swSubAssembly = swModelDoc
Else
targetComponentInfo.ComponentType = “Unknown”
End If
‘ トランスフォーメーション (マトリクス座標) を取得
Set swTransform = currentSWComponent.GetTransform
targetComponentInfo.Transform = ConvertTransformToType(swTransform)
‘ 合致情報を取得
Dim mates As Variant
mates = currentSWComponent.GetMates
If Not IsEmpty(mates) Then
ReDim targetComponentInfo.Mates(UBound(mates))
Dim j As Long
For j = 0 To UBound(mates)
ProcessMate mates(j), targetComponentInfo.Mates(j)
Next j
Else
ReDim targetComponentInfo.Mates(0) ‘ 空の配列で初期化
End If
‘ サブコンポーネントがあれば再帰的に処理
Dim subComponents As Variant
subComponents = currentSWComponent.GetChildren
If Not IsEmpty(subComponents) Then
ReDim targetComponentInfo.Children(UBound(subComponents))
Dim k As Long
For k = 0 To UBound(subComponents)
ProcessComponent subComponents(k), targetComponentInfo.Children(k)
Next k
Else
ReDim targetComponentInfo.Children(0) ‘ 空の配列で初期化
End If
End Sub
‘ 合致情報を処理する関数
Private Sub ProcessMate(ByVal swMate As SldWorks.Mate2, ByRef targetMateInfo As MateInfo)
targetMateInfo.MateName = swMate.Name
targetMateInfo.MateType = GetMateTypeString(swMate.MateType)
targetMateInfo.Value = swMate.Value
targetMateInfo.Reverse = swMate.IsReversed
targetMateInfo.StandardMate = swMate.IsStandardMate
‘ エンティティ1 を処理
Dim swMateEntity1 As SldWorks.MateEntity
Set swMateEntity1 = swMate.Entity1
targetMateInfo.Entity1 = ConvertMateEntityToType(swMateEntity1)
‘ エンティティ2 を処理
Dim swMateEntity2 As SldWorks.MateEntity
Set swMateEntity2 = swMate.Entity2
targetMateInfo.Entity2 = ConvertMateEntityToType(swMateEntity2)
‘ ★★★ EntityID の問題:
‘ swMateEntity1.GetID や swMateEntity2.GetID は、アセンブリ再構築後に無効になる可能性が高い。
‘ 復元時には、このIDに依存しないロジックが必要。
‘ 例えば、エンティティを特定するために、フィーチャー名やジオメトリの参照方法を考慮する。
‘ targetMateInfo.Entity1.EntityID = swMateEntity1.GetID ‘ ← ★★★ 推奨しない ★★★
‘ targetMateInfo.Entity2.EntityID = swMateEntity2.GetID ‘ ← ★★★ 推奨しない ★★★
End Sub
‘ SolidWorks MateType 定数を文字列に変換
Private Function GetMateTypeString(mateType As Long) As String
Select Case mateType
Case swMateType_e.swMateTypeConcentric: GetMateTypeString = “Concentric”
Case swMateType_e.swMateTypeCoincident: GetMateTypeString = “Coincident”
Case swMateType_e.swMateTypeDistance: GetMateTypeString = “Distance”
Case swMateType_e.swMateTypeAngle: GetMateTypeString = “Angle”
Case swMateType_e.swMateTypeWidth: GetMateTypeString = “Width”
Case swMateType_e.swMateTypePath: GetMateTypeString = “Path”
Case swMateType_e.swMateTypeParallel: GetMateTypeString = “Parallel”
Case swMateType_e.swMateTypePerpendicular: GetMateTypeString = “Perpendicular”
Case swMateType_e.swMateTypeTangent: GetMateTypeString = “Tangent”
Case Else: GetMateTypeString = “Unknown”
End Select
End Function
‘ MateEntity をカスタム Type に変換
Private Function ConvertMateEntityToType(ByVal swMateEntity As SldWorks.MateEntity) As MateEntity
Dim mateEntity As MateEntity
mateEntity.ComponentName = swMateEntity.Component.GetModelDoc2.GetPathName ‘ どのコンポーネントのエンティティか
mateEntity.EntityType = GetEntityTypeString(swMateEntity.Type)
‘ EntityID は含めない
ConvertMateEntityToType = mateEntity
End Function
‘ MateEntityType 定数を文字列に変換
Private Function GetEntityTypeString(entityType As Long) As String
Select Case entityType
Case swMateEntity_e.swMateEntityFace: GetEntityTypeString = “Face”
Case swMateEntity_e.swMateEntityEdge: GetEntityTypeString = “Edge”
Case swMateEntity_e.swMateEntityVertex: GetEntityTypeString = “Vertex”
Case swMateEntity_e.swMateEntityPlane: GetEntityTypeString = “Plane”
Case swMateEntity_e.swMateEntityAxis: GetEntityTypeString = “Axis”
Case Else: GetEntityTypeString = “Unknown”
End Select
End Function
‘ ITransform をカスタム TypeTransform に変換
Private Function ConvertTransformToType(ByVal swTransform As SldWorks.ITransform) As TypeTransform
Dim t As TypeTransform
t.m11 = swTransform.m11: t.m12 = swTransform.m12: t.m13 = swTransform.m13: t.m14 = swTransform.m14
t.m21 = swTransform.m21: t.m22 = swTransform.m22: t.m23 = swTransform.m23: t.m24 = swTransform.m24
t.m31 = swTransform.m31: t.m32 = swTransform.m32: t.m33 = swTransform.m33: t.m34 = swTransform.m34
t.m41 = swTransform.m41: t.m42 = swTransform.m42: t.m43 = swTransform.m43: t.m44 = swTransform.m44
ConvertTransformToType = t
End Function
‘ カスタム ComponentInfo を JSON 文字列に変換 (簡易版)
‘ ★★★ 実運用では JSON ライブラリの使用を強く推奨 ★★★
Private Function ConvertToJson(ByVal component As ComponentInfo) As String
Dim json As String
json = “{” & vbCrLf
json = json & ” “”assemblyName””: “”” & Replace(component.ComponentName, “\”, “\\”) & “””,” & vbCrLf ‘ パス区切り文字のエスケープ
json = json & ” “”components””: [” & vbCrLf
Dim i As Long
For i = 0 To UBound(component.Children)
json = json & ConvertComponentToJson(component.Children(i), 2) ‘ インデントレベル 2
If i < UBound(component.Children) Then
json = json & "," & vbCrLf
Else
json = json & vbCrLf
End If
Next i
json = json & " ]" & vbCrLf
json = json & "}"
ConvertToJson = json
End Function
' 再帰的に Component を JSON 文字列に変換
Private Function ConvertComponentToJson(ByVal component As ComponentInfo, ByVal indentLevel As Long) As String
Dim indent As String
indent = String(indentLevel 2, " ") ' インデントスペース
Dim json As String
json = indent & "{" & vbCrLf
json = json & indent & " ""componentName"": """ & Replace(component.ComponentName, "\", "\\") & """," & vbCrLf
json = json & indent & " ""componentType"": """ & component.ComponentType & """," & vbCrLf
json = json & indent & " ""configurationName"": """ & component.ConfigurationName & """," & vbCrLf
json = json & indent & " ""suppressed"": " & LCase(CStr(component.Suppressed)) & "," & vbCrLf
json = json & indent & " ""locked"": " & LCase(CStr(component.Locked)) & "," & vbCrLf
' Transform
json = json & indent & " ""transform"": {" & vbCrLf
json = json & indent & " ""m11"": " & CStr(component.Transform.m11) & ", ""m12"": " & CStr(component.Transform.m12) & ", ""m13"": " & CStr(component.Transform.m13) & ", ""m14"": " & CStr(component.Transform.m14) & "," & vbCrLf
json = json & indent & " ""m21"": " & CStr(component.Transform.m21) & ", ""m22"": " & CStr(component.Transform.m22) & ", ""m23"": " & CStr(component.Transform.m23) & ", ""m24"": " & CStr(component.Transform.m24) & "," & vbCrLf
json = json & indent & " ""m31"": " & CStr(component.Transform.m31) & ", ""m32"": " & CStr(component.Transform.m32) & ", ""m33"": " & CStr(component.Transform.m33) & ", ""m34"": " & CStr(component.Transform.m34) & "," & vbCrLf
json = json & indent & " ""m41"": " & CStr(component.Transform.m41) & ", ""m42"": " & CStr(component.Transform.m42) & ", ""m43"": " & CStr(component.Transform.m43) & ", ""m44"": " & CStr(component.Transform.m44) & vbCrLf
json = json & indent & " }," & vbCrLf
' Mates
json = json & indent & " ""mates"": [" & vbCrLf
Dim i As Long
For i = 0 To UBound(component.Mates)
json = json & ConvertMateToJson(component.Mates(i), indentLevel + 2)
If i < UBound(component.Mates) Then
json = json & "," & vbCrLf
Else
json = json & vbCrLf
End If
Next i
json = json & indent & " ]," & vbCrLf
' Children
json = json & indent & " ""children"": [" & vbCrLf
For i = 0 To UBound(component.Children)
json = json & ConvertComponentToJson(component.Children(i), indentLevel + 2)
If i < UBound(component.Children) Then
json = json & "," & vbCrLf
Else
json = json & vbCrLf
End If
Next i
json = json & indent & " ]" & vbCrLf
json = json & indent & "}"
ConvertComponentToJson = json
End Function
' 再帰的に Mate を JSON 文字列に変換
Private Function ConvertMateToJson(ByVal mate As MateInfo, ByVal indentLevel As Long) As String
Dim indent As String
indent = String(indentLevel 2, " ") ' インデントスペース
Dim json As String
json = indent & "{" & vbCrLf
json = json & indent & " ""mateName"": """ & mate.MateName & """," & vbCrLf
json = json & indent & " ""mateType"": """ & mate.MateType & """," & vbCrLf
' Entity1
json = json & indent & " ""entity1"": {" & vbCrLf
json = json & indent & " ""componentName"": """ & Replace(mate.Entity1.ComponentName, "\", "\\") & """," & vbCrLf
json = json & indent & " ""entityType"": """ & mate.Entity1.EntityType & """" & vbCrLf
' EntityID は含めない
json = json & indent & " }," & vbCrLf
' Entity2
json = json & indent & " ""entity2"": {" & vbCrLf
json = json & indent & " ""componentName"": """ & Replace(mate.Entity2.ComponentName, "\", "\\") & """," & vbCrLf
json = json & indent & " ""entityType"": """ & mate.Entity2.EntityType & """" & vbCrLf
' EntityID は含めない
json = json & indent & " }," & vbCrLf
json = json & indent & " ""value"": " & CStr(mate.Value) & "," & vbCrLf
json = json & indent & " ""reverse"": " & LCase(CStr(mate.Reverse)) & "," & vbCrLf
json = json & indent & " ""standardMate"": " & LCase(CStr(mate.StandardMate)) & vbCrLf
json = json & indent & "}"
ConvertMateToJson = json
End Function
2. JSONからのアセンブリ再構築(復元)コード例(VB.NET)
ここでは、VB.NET環境で `Newtonsoft.Json` ライブラリを使用し、JSONデータからアセンブリを再構築するコード例を示します。ここでの最大の課題は、JSONに保存されたエンティティ情報(特にID)を、再構築後のSolidWorksドキュメント内で正確に特定し、合致を定義することです。
【設計のポイント】
- `Newtonsoft.Json` の利用: JSONのデシリアライズ(解析)には、このライブラリが必須です。NuGetパッケージマネージャーから追加してください。
- エンティティ特定ロジックの重要性: `EntityID` は使えません。代わりに、以下のいずれか、または組み合わせでエンティティを特定します。
- ジオメトリの直接参照: `swModel.Extension.SelectByID2` などのメソッドで、ジオメトリ名やフィーチャー名から直接選択します。
- 動的なエンティティ検索: 復元時に、JSONに記述された `entityType` と、コンポーネント内のジオメトリを比較して、最も一致するものを選択します。例えば、面であれば、その面積、法線ベクトル、位置などを比較して特定します。
- フィーチャーベースの特定: 合致の定義元がフィーチャー(例: ボス、切り欠き、穴)である場合、そのフィーチャー名を直接参照します。
- トランスフォーメーションの適用: `Component2.SetTransform` メソッドを使用します。親コンポーネントのトランスフォーメーションを考慮して、絶対座標(ワールド座標)を計算してから適用する必要があります。
- 合致の追加: `AssemblyDoc.AddMate` メソッドを使用します。`Entity1` および `Entity2` には、上記で特定した `Face`, `Edge`, `Vertex` などの `Object` を渡します。
.net
Imports SolidWorks.Interop.sldworks
Imports SolidWorks.Interop.swconst
Imports System.Runtime.InteropServices
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
‘ — JSON構造に対応するクラス定義 —
‘ (VBAのType構造体に対応)
Public Class ComponentJson
Public Property ComponentName As String
Public Property ComponentType As String ‘ “Part” or “Assembly”
Public Property ConfigurationName As String
Public Property Suppressed As Boolean
Public Property Locked As Boolean
Public Property Transform As TransformJson
Public Property Children As List(Of ComponentJson)
Public Property Mates As List(Of MateJson)
End Class
Public Class TransformJson
Public Property m11 As Double
Public Property m12 As Double
Public Property m13 As Double
Public Property m14 As Double
Public Property m21 As Double
Public Property m22 As Double
Public Property m23 As Double
Public Property m24 As Double
Public Property m31 As Double
Public Property m32 As Double
Public Property m33 As Double
Public Property m34 As Double
Public Property m41 As Double
Public Property m42 As Double
Public Property m43 As Double
Public Property m44 As Double
End Class
Public Class MateJson
Public Property MateName As String
Public Property MateType As String
Public Property Entity1 As MateEntityJson
Public Property Entity2 As MateEntityJson
Public Property Value As Double
Public Property Reverse As Boolean
Public Property StandardMate As Boolean
‘ Public Property Tolerance As ToleranceJson ‘ 必要であれば追加
End Class
Public Class MateEntityJson
Public Property ComponentName As String
Public Property EntityType As String ‘ “Face”, “Edge”, “Vertex”, “Plane”, “Axis”
‘ EntityID は含めない
End Class
‘ — メイン処理 —
‘ SolidWorks アプリケーションオブジェクト (グローバル、または引数で渡す)
Private swApp As SldWorks.SldWorks
Private swModel As SldWorks.ModelDoc2
Private swAssembly As SldWorks.AssemblyDoc
‘ JSONデータ
Private assemblyJson As ComponentJson
Sub RebuildAssemblyFromJson(jsonFilePath As String)
‘ SolidWorks アプリケーションオブジェクトの取得
If swApp Is Nothing Then
swApp = GetSolidWorksInstance() ‘ Helper function to get SW instance
If swApp Is Nothing Then
MsgBox “SolidWorks が起動していません。”, vbCritical
Exit Sub
End If
End If
‘ JSONファイルを読み込み、デシリアライズ
Dim jsonText As String
Try
jsonText = System.IO.File.ReadAllText(jsonFilePath)
assemblyJson = JsonConvert.DeserializeObject(Of ComponentJson)(jsonText)
Catch ex As Exception
MsgBox(“JSONファイルの読み込みまたはデシリアライズに失敗しました: ” & ex.Message, vbCritical)
Exit Sub
End Try
‘ 新規アセンブリを作成するか、既存のアセンブリをクリアするか選択
‘ ここでは新規作成の例を示します
Dim swNewModel As ModelDoc2
swNewModel = swApp.NewDocument(swApp.GetUserPreferenceStringValue(swUserPreferenceStringValue_e.swDefaultTemplateAsm), 0, 0, 0)
If swNewModel Is Nothing Then
MsgBox(“新規アセンブリの作成に失敗しました。”, vbCritical)
Exit Sub
End If
swModel = swNewModel
swModel.Extension.SelectByID2(“Origin”, “ORIGIN”, 0, 0, 0, False, 0, Nothing, 0) ‘ 原点を初期選択
swApp.CommandInProgress = True ‘ コマンド実行中フラグ
swModel.ClearSelection2(True)
Set swAssembly = swModel
‘ ルートコンポーネント(JSONのルート要素)を処理
‘ JSONのルートはトップレベルアセンブリそのものなので、
‘ その中の Children を処理してアセンブリに追加していく
Dim rootComponentToAdd As ComponentJson = assemblyJson ‘ JSONのルート要素はトップレベルアセンブリ
Dim addedComponent As Component2
‘ トップレベルコンポーネントをアセンブリに追加
For Each compJson In rootComponentToAdd.Children
Dim compFileName As String = compJson.ComponentName
Dim compPath As String = swApp.GetApplicationPath() & “\whatsnew\” & compFileName ‘ 例: SolidWorksインストールパスから部品を検索
‘ ↑ ★★★ 実際には、部品ファイルのパスを管理するロジックが必要 ★★★
‘ (例: 設定ファイル、データベース、相対パスなど)
‘ コンポーネントをアセンブリに追加
‘ (原点への固定配置)
swModel.Extension.SelectByID2(“Origin”, “ORIGIN”, 0, 0, 0, False, 0, Nothing, 0)
addedComponent = swAssembly.AddComponent(compPath, swComponentOption_Silent, 0, 0, 0) ‘ 最後の3つの引数はトランスフォームではない
If addedComponent Is Nothing Then
MsgBox(“コンポーネントの追加に失敗しました: ” & compFileName, vbCritical)
Continue For
End If
‘ JSONのコンポーネント名と追加されたコンポーネント名が一致するか確認 (必要であれば)
‘ Debug.Print(“Added: ” & addedComponent.GetModelDoc2.GetPathName)
‘ Debug.Print(“Expected: ” & compFileName)
‘ 追加されたコンポーネントのトランスフォーメーションを適用
ApplyTransform(addedComponent, compJson.Transform, Nothing) ‘ 親トランスフォームなし
‘ コンポーネントのプロパティを設定 (抑制、ロックなど)
addedComponent.SetSuppressed(compJson.Suppressed)
addedComponent.SetLocked(compJson.Locked)
‘ コンフィギュレーションを設定
If Not String.IsNullOrEmpty(compJson.ConfigurationName) Then
Dim refConfig As Configuration = addedComponent.ReferencedConfiguration
If Not refConfig Is Nothing Then
refConfig.Name = compJson.ConfigurationName ‘ これは参照コンフィギュレーション名を設定するだけで、実際に切り替えるわけではない
‘ 実際のコンフィギュレーション切り替えは、コンポーネントのLoadConfigurationメソッドなどで行う必要がある場合も。
‘ ここではJSONから取得した名前を記録するにとどめる。
End If
End If
‘ 子コンポーネントを再帰的に処理
ProcessChildren(swAssembly, addedComponent, compJson.Children)
‘ 合致を定義
DefineMates(swAssembly, addedComponent, compJson.Mates)
Next
swApp.CommandInProgress = False ‘ コマンド終了
swModel.ClearSelection2(True)
swModel.ForceRebuild3(False)
swApp.ActivateDoc3(swModel.GetTitle, True, swRebuildOnActivation_e.swRebuildOnActivation_False, 0)
MsgBox(“アセンブリの再構築が完了しました。”, vbInformation)
End Sub
‘ 子コンポーネントを再帰的に処理
Private Sub ProcessChildren(ByVal parentAssembly As AssemblyDoc, ByVal parentComponent As Component2, ByVal childrenJson As List(Of ComponentJson))
If childrenJson Is Nothing Then Exit Sub
For Each childJson In childrenJson
Dim childCompFileName As String = childJson.ComponentName
‘ ★★★ 部品ファイルのパスを検索するロジック ★★★
Dim childCompPath As String = FindComponentPath(childCompFileName) ‘ Helper function
Dim addedChildComponent As Component2
‘ 親コンポーネントを基準に子コンポーネントを追加
‘ ここで、親コンポーネントのトランスフォームを考慮して追加位置を決定する必要がある
‘ simplified: Directly add to assembly and then set transform
addedChildComponent = parentAssembly.AddComponent(childCompPath, swComponentOption_Silent, 0, 0, 0)
If addedChildComponent Is Nothing Then
MsgBox(“子コンポーネントの追加に失敗しました: ” & childCompFileName, vbCritical)
Continue For
End If
‘ トランスフォーメーションを適用
ApplyTransform(addedChildComponent, childJson.Transform, parentComponent.GetTransform) ‘ 親トランスフォームを渡す
‘ コンポーネントのプロパティを設定
addedChildComponent.SetSuppressed(childJson.Suppressed)
addedChildComponent.SetLocked(childJson.Locked)
‘ コンフィギュレーションを設定
If Not String.IsNullOrEmpty(childJson.ConfigurationName) Then
Dim refConfig As Configuration = addedChildComponent.ReferencedConfiguration
If Not refConfig Is Nothing Then
refConfig.Name = childJson.ConfigurationName
End If
End If
‘ さらに孫コンポーネントを処理
ProcessChildren(parentAssembly, addedChildComponent, childJson.Children)
‘ 合致を定義
DefineMates(parentAssembly, addedChildComponent, childJson.Mates)
Next
parentAssembly.ClearSelection2(True) ‘ 各親コンポーネント処理後に選択解除
End Sub
‘ トランスフォーメーションを適用するヘルパー関数
Private Sub ApplyTransform(ByVal component As Component2, ByVal jsonTransform As TransformJson, ByVal parentTransform As ITransform)
Dim swTransform As ITransform
swTransform = component.GetTransform ‘ 現在のトランスフォームを取得
‘ JSONから新しいトランスフォームを作成
swTransform.m11 = jsonTransform.m11: swTransform.m12 = jsonTransform.m12: swTransform.m13 = jsonTransform.m13: swTransform.m14 = jsonTransform.m14
swTransform.m21 = jsonTransform.m21: swTransform.m22 = jsonTransform.m22: swTransform.m23 = jsonTransform.m23: swTransform.m24 = jsonTransform.m24
swTransform.m31 = jsonTransform.m31: swTransform.m32 = jsonTransform.m32: swTransform.m33 = jsonTransform.m33: swTransform.m34 = jsonTransform.m34
swTransform.m41 = jsonTransform.m41: swTransform.m42 = jsonTransform.m42: swTransform.m43 = jsonTransform.m43: swTransform.m44 = jsonTransform.m44
‘ ★★★ 親トランスフォームの考慮 ★★★
‘ JSONのトランスフォームは、親コンポーネントからの相対位置/姿勢です。
‘ したがって、親コンポーネントが既に配置されている場合、
‘ その親のトランスフォームを適用した結果が、最終的なワールド座標となります。
‘ SolidWorks APIのComponent2.SetTransformは、ワールド座標系でのトランスフォームを設定します。
‘ したがって、親トランスフォームがある場合は、それを乗算する必要があります。
If Not parentTransform Is Nothing Then
‘ ワールド座標系でのトランスフォームを計算
Dim worldTransform As ITransform = swApp.CreateTransform()
worldTransform.Multiply(parentTransform, swTransform)
swTransform = worldTransform
End If
‘ トランスフォーメーションを適用
component.SetTransform(swTransform)
End Sub
‘ 合致を定義するヘルパー関数
Private Sub DefineMates(ByVal assemblyDoc As AssemblyDoc, ByVal component As Component2, ByVal matesJson As List(Of MateJson))
If matesJson Is Nothing Then Exit Sub
Dim swMate As Mate2
Dim entity1 As Object
Dim entity2 As Object
For Each mateJson In matesJson
‘ — エンティティ1 を特定 —
entity1 = FindMateEntity(assemblyDoc, mateJson.Entity1)
If entity1 Is Nothing Then
Debug.WriteLine($”合致 ‘{mateJson.MateName}’ の Entity1 を特定できませんでした: Component='{mateJson.Entity1.ComponentName}’, Type='{mateJson.Entity1.EntityType}'”)
Continue For
End If
‘ — エンティティ2 を特定 —
entity2 = FindMateEntity(assemblyDoc, mateJson.Entity2)
If entity2 Is Nothing Then
Debug.WriteLine($”合致 ‘{mateJson.MateName}’ の Entity2 を特定できませんでした: Component='{mateJson.Entity2.ComponentName}’, Type='{mateJson.Entity2.EntityType}'”)
Continue For
End If
‘ 合致タイプを SolidWorks の定数に変換
Dim swMateType As swMateType_e = GetMateTypeEnum(mateJson.MateType)
‘ 合致を作成
swMate = assemblyDoc.AddMate(entity1, entity2, swMateType, mateJson.Value, mateJson.Reverse, mateJson.StandardMate, 0) ‘ 最後の引数はオプション
If swMate Is Nothing Then
Debug.WriteLine($”合致 ‘{mateJson.MateName}’ の追加に失敗しました。”)
Continue For
End If
‘ 合致名を設定 (JSONの名称に合わせる)
swMate.Name = mateJson.MateName
‘ tolerance の設定 (必要であれば)
Next
End Sub
‘ JSONのエンティティ情報から SolidWorks のエンティティオブジェクトを特定するヘルパー関数
‘ ★★★ ここが最も重要で、複雑なロジックが必要になる部分です ★★★
Private Function FindMateEntity(ByVal assemblyDoc As AssemblyDoc, ByVal entityJson As MateEntityJson) As Object
Dim foundEntity As Object = Nothing
Dim swComponent As Component2 = Nothing
Dim swModelDoc As ModelDoc2 = Nothing
‘ 1. コンポーネントを特定
‘ (JSONのComponentNameはファイル名。アセンブリ内での実際のComponent2オブジェクトを検索する必要がある)
‘ ここでは、簡略化のため、アセンブリ直下のコンポーネントのみを検索します。
‘ 実際には、再帰的に検索する必要があります。
Dim components As Object = assemblyDoc.GetComponents(False) ‘ False = Flattenしない
If components Is Nothing Then Return Nothing
For Each comp As Component2 In CType(components, Object())
Dim compModelDoc As ModelDoc2 = comp.GetModelDoc2
If compModelDoc Is Nothing Then Continue For
‘ ファイル名で一致を試みる
If System.IO.Path.GetFileName(compModelDoc.GetPathName).Equals(System.IO.Path.GetFileName(entityJson.ComponentName), StringComparison.OrdinalIgnoreCase) Then
swComponent = comp
Exit For
End If
Next
If swComponent Is Nothing Then
Debug.WriteLine($”FindMateEntity: コンポーネント ‘{entityJson.ComponentName}’ が見つかりません。”)
Return Nothing
End If
swModelDoc = swComponent.GetModelDoc2
‘ 2. エンティティを特定
‘ entityJson.EntityType (“Face”, “Edge”, “Vertex”, “Plane”, “Axis”) と
‘ swModelDoc 内のジオメトリを照合します。
‘ ★★★ ここは、ジオメトリの選択方法のロジックが最も重要 ★★★
Dim selected As Boolean = False
Select Case entityJson.EntityType
Case “Face”
‘ 面を特定するロジック (例: ジオメトリ名、フィーチャー名、あるいは複数の面から選択)
‘ swModelDoc.Extension.SelectByID2(“Face<1>“, “FACE”, x, y, z, …)
‘ ジオメトリ名やフィーチャー名で特定するのが最も堅牢。
‘ 例: “Boss-Extrude1:1” のようなフィーチャー名で面を特定
‘ selectByID2 の引数でフィーチャー名を指定できる場合がある
‘ 簡略化のため、ここでは最初の面を選択する試み (推奨されない)
‘ 実際には、JSONにジオメトリの特定情報(名前、インデックスなど)を含めるべき
‘ selected = swModelDoc.Extension.SelectByID2(“Face<1>“, “FACE”, 0, 0, 0, False, 0, Nothing, 0)
‘ よりロバストな方法: Feature を特定し、その Feature からジオメトリを取得
‘ Dim swFeature As SldWorks.Feature
‘ swFeature = swModelDoc.FeatureByName(“YourFeatureName”) ‘ JSONにFeature名を含める
‘ If Not swFeature Is Nothing Then
‘ Dim swGeo As Object = swFeature.GetSpecificFeature
‘ ‘ swGeo から面を取得して selected = True にする
‘ End If
‘ ★★★ 簡略化のため、ここでは何も選択しない ★★★
‘ ★★★ 復元時には、JSONにフィーチャー名などの識別子を含める ★★★
Debug.WriteLine($”Face の特定ロジックは未実装です。JSONにフィーチャー名などを含めてください。”)
Case “Edge”
‘ エッジを特定するロジック
‘ selected = swModelDoc.Extension.SelectByID2(“Edge<1>“, “EDGE”, 0, 0, 0, False, 0, Nothing, 0)
Debug.WriteLine($”Edge の特定ロジックは未実装です。JSONにフィーチャー名などを含めてください。”)
Case “Vertex”
‘ 頂点を特定するロジック
‘ selected = swModelDoc.Extension.SelectByID2(“Vertex<1>“, “VERTEX”, 0, 0, 0, False, 0, Nothing, 0)
Debug.WriteLine($”Vertex の特定ロジックは未実装です。JSONにフィーチャー名などを含めてください。”)
Case “Plane”
‘ 平面を特定するロジック
‘ selected = swModelDoc.Extension.SelectByID2(“Plane1”, “PLANE”, 0, 0, 0, False, 0, Nothing, 0)
Debug.WriteLine($”Plane の特定ロジックは未実装です。JSONにフィーチャー名などを含めてください。”)
Case “Axis”
‘ 軸を特定するロジック
‘ selected = swModelDoc.Extension.SelectByID2(“Axis1”, “AXIS”, 0, 0, 0, False, 0, Nothing, 0)
Debug.WriteLine($”Axis の特定ロジックは未実装です。JSONにフィーチャー名などを含めてください。”)
Case Else
Debug.WriteLine($”不明なエンティティタイプ: {entityJson.EntityType}”)
Return Nothing
End Select
‘ ★★★ 選択されたエンティティを取得するロジック ★★★
‘ 実際には、swModelDoc.Extension.GetSelectedObject6 などで、
‘ 選択されたエンティティ(Face, Edge, Vertex など)のObjectを取得する必要がある。
‘ この例では、その部分を省略している。
‘ 例: 選択された面を取得 (もし上記で選択が成功した場合)
‘ If selected Then
‘ Dim selectionObj As Object
‘ selectionObj = assemblyDoc.GetExtension.GetSelectedObject6(swSelMgr.swSelSWSelectionMgr.swSelectedFeatures, 1)
‘ If Not selectionObj Is Nothing Then
‘ foundEntity = selectionObj
‘ End If
‘ End If
Return foundEntity ‘ ★★★ 未実装のため、常に Nothing を返す ★★★
End Function
‘ JSONの合致タイプ文字列を SolidWorks の定数に変換
Private Function GetMateTypeEnum(mateType As String) As swMateType_e
Select Case mateType
Case “Concentric”: Return swMateType_e.swMateTypeConcentric
Case “Coincident”: Return swMateType_e.swMateTypeCoincident
Case “Distance”: Return swMateType_e.swMateTypeDistance
Case “Angle”: Return swMateType_e.swMateTypeAngle
Case “Width”: Return swMateType_e.swMateTypeWidth
Case “Path”: Return swMateType_e.swMateTypePath
Case “Parallel”: Return swMateType_e.swMateTypeParallel
Case “Perpendicular”: Return swMateType_e.swMateTypePerpendicular
Case “Tangent”: Return swMateType_e.swMateTypeTangent
Case Else: Return swMateType_e.swMateTypeUnknown
End Select
End Function
‘ SolidWorksインスタンスを取得するヘルパー関数
Private Function GetSolidWorksInstance() As SldWorks.SldWorks
Dim swApp As SldWorks.SldWorks = Nothing
Try
swApp = CType(Marshal.GetActiveObject(“SldWorks.Application”), SldWorks.SldWorks)
Catch ex As Exception
‘ SolidWorks が起動していない場合
Try
Dim swType As Type = Type.GetTypeFromProgID(“SldWorks.Application”)
Dim swAppObj As Object = Activator.CreateInstance(swType)
swApp = CType(swAppObj, SldWorks.SldWorks)
swApp.Visible = True ‘ SolidWorks を表示
Catch ex2 As Exception
MessageBox.Show(“SolidWorks の起動に失敗しました: ” & ex2.Message, “エラー”, MessageBoxButtons.OK, MessageBoxIcon.Error)
Return Nothing
End Try
End Try
Return swApp
End Function
‘ 部品ファイルパスを検索するヘルパー関数
‘ ★★★ 実際には、部品ファイルのパスを管理するロジックが必要 ★★★
Private Function FindComponentPath(componentFileName As String) As String
‘ 例: SolidWorks のインストールパスから部品を検索
‘ 実際には、設定ファイル、データベース、相対パスなどを利用して検索する
Dim swApp As SldWorks.SldWorks = GetSolidWorksInstance()
If swApp Is Nothing Then Return Nothing
Dim installPath As String = swApp.GetApplicationPath()
Dim searchPath As String = System.IO.Path.Combine(installPath, “whatsnew”) ‘ 仮の検索パス
Dim fullPath As String = System.IO.Path.Combine(searchPath, componentFileName)
If System.IO.File.Exists(fullPath) Then
Return fullPath
End If
‘ 他の検索パスも追加する
‘ …
Debug.WriteLine($”警告: 部品ファイル ‘{componentFileName}’ のパスが見つかりません。”)
Return “” ‘ 見つからなかった場合は空文字列を返す
End Function
ファイル・データベース連携の注意点
- ファイルパスの管理: JSONにコンポーネントのファイルパスをそのまま保存すると、アセンブリの移動やコピー時に問題が発生します。相対パス、あるいは部品ファイルへのアクセス方法(例:PDMシステムからの取得、共有フォルダからの参照)を別途定義・管理する必要があります。
- データベース連携: JSONデータをデータベースのJSON型カラムに格納するのは効率的です。ただし、データベース側でJSONの構造を理解し、インデックスを適切に設定しないと、検索パフォーマンスが著しく低下する可能性があります。
- バージョン管理: JSONファイル自体をGitなどのバージョン管理システムで管理することを強く推奨します。これにより、アセンブリ構造の変更履歴を追跡し、必要に応じて過去の状態にロールバックすることが容易になります。
バグの起きない堅牢な設計のために
- エンティティIDへの依存を断つ: これは何度でも強調します。SolidWorks APIのオブジェクトは、セッションやアセンブリの再構築によってIDが変更される可能性があります。フィーチャー名、ジオメトリのプロパティ、あるいは復元時に動的に特定できる情報をエンティティの識別子として使用してください。
- API呼び出しの最適化:
- コンポーネントの列挙: `GetComponents` メソッドの `bFlatten` 引数を適切に設定し、必要な階層のみを列挙します。
- 合致の取得: `Component2.GetMates` は、そのコンポーネントに直接定義された合致を返します。アセンブリ全体で定義された合致を取得するには、アセンブリドキュメントの `GetMates` メソッドを使用します。
- トランスフォーメーション: `Component2.GetTransform` で取得したトランスフォーメーションは、親コンポーネントからの相対値です。復元時には、親のトランスフォーメーションを考慮したワールド座標系でのトランスフォーメーションを計算し、`Component2.SetTransform` で適用する必要があります。
- エラーハンドリング: API呼び出しは予期せぬエラーを発生させる可能性があります。`Try…Catch` ブロックを適切に使用し、エラー発生時の処理(ログ記録、ユーザーへの通知など)を実装してください。
- デバッグの容易性: JSON構造は可読性が高いため、エクスポートされたデータを確認することで、問題箇所を特定しやすくなります。また、復元時には、ログ出力やデバッガを活用し、エンティティの特定プロセスや合致の定義プロセスをステップごとに追跡できるように設計してください。
まとめ:究極のデータ管理へ
SolidWorksアセンブリの構造をJSONでシリアライズし、完全に再構築するこの手法は、単なる自動化の枠を超え、「データとしてのSolidWorksアセンブリ」 を確立する強力な手段です。
- 開発プロジェクトの効率化: 設計変更時の迅速なアセンブリ再構築、構成管理の自動化。
- PDMシステムとの連携強化: アセンブリ構造のメタデータとして、JSONデータを活用。
- 他システムとのデータ連携: Webベースのレビューツールや解析ツールへのデータ投入。
この技術は、SolidWorks APIの深い理解と、JSONという汎用的なデータフォーマットの特性を最大限に活かすことで実現します。今日ご紹介したコード例はあくまで出発点です。皆さんの開発現場のニーズに合わせて、さらに洗練させ、独自の「究極のエンジン」を構築してください。
この知見が、皆さんの開発プロジェクトにおける生産性向上、そしてSolidWorks自動化の新たな地平を切り拓く一助となれば幸いです。
