【テクニカル・上級編】【上級プロ向け】DrawingDocとModelDoc2の双方向トラバーサル:図面から参照モデルの寸法を逆駆動するVBA – SolidWorks VBA解析バイブル

スポンサーリンク
スポンサーリンク

DrawingDocとModelDoc2の双方向トラバーサル:図面から参照モデルの寸法を逆駆動する極限の知見

設計自動化の領域において、多くのエンジニアが「図面を作成する」あるいは「モデルから寸法を抽出する」という単方向のフローで満足してしまう。しかし、真に堅牢なPLM(Product Lifecycle Management)システムや、高度な設計支援ツールを構築するアーキテクトに求められるのは、2D図面(DrawingDoc)と3Dモデル(ModelDoc2)の間の「意味的結合(Semantic Link)」を、APIレベルで完全に制御することである。

図面上の寸法、あるいは投影ビューは、単なるグラフィックデータではない。それは3Dモデル内の特定のフィーチャー、あるいは特定の幾何学的拘束の「投影された写し」に過ぎない。本稿では、図面ビューから背後の3Dモデルへとトラバース(走査)し、図面上の選択情報をトリガーとしてモデル側のフィーチャーや寸法を操作・ハイライトする、高度な双方向制御手法について詳説する。

1. 階層構造の深層:DrawingViewからModelDoc2への橋渡し

図面操作において、最も基本的な、しかし誤解されやすい概念が「View」の正体である。`DrawingView`オブジェクトは、特定の`ModelDoc2`(PartまたはAssembly)を投影するための「窓」として機能する。

図面上の要素(寸法、注釈、ビュー)を操作する場合、我々は常に`DrawingDoc`のコンテキストにいる。しかし、その背後にある実体(Source of Truth)にアクセスするためには、`DrawingView`を経由してモデルのポインタを奪取しなければならない。

オブジェクト・トラバーサルの論理フロー

1. `SelectionMgr` を介して、図面上の選択オブジェクト(`DisplayDimension` または `View`)を特定する。
2. 選択されたオブジェクトが `DisplayDimension` であれば、その `GetModelDimension` メソッドを呼び出し、3Dモデル側の `Dimension` オブジェクトを取得する。
3. 選択されたオブジェクトが `View` であれば、`GetModelDoc2` を呼び出し、モデルのルート(`PartDoc` または `AssemblyDoc`)へアクセスする。

ここで重要なのは、「図面の寸法(DisplayDimension)」と「モデルの寸法(Dimension)」は、メモリ上では全く異なるクラスであるという事実だ。この乖離を理解していないコードは、ランタイムエラーを頻発させる。

2. 実装:図面選択をトリガーとしたモデルフィーチャーの逆駆動

以下に、図面上の寸法を選択した際、そのソースとなる3Dモデルのフィーチャーを特定し、モデルをアクティブにしてハイライトする、実戦的なVBAモジュールを示す。

Option Explicit

' ======================================================================================
' Module: TraversalEngine
' Description: DrawingDocからModelDoc2への双方向トラバーサルを実現する
' Author: Legendary Chief Architect
' ======================================================================================

Public Sub ReverseDriveModelFromDrawing()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim swSelMgr As SldWorks.SelectionMgr
    Dim swSelObj As Object
    Dim swDispDim As SldWorks.DisplayDimension
    Dim swModelDim As SldWorks.Dimension
    Dim swView As SldWorks.View
    Dim targetModel As SldWorks.ModelDoc2
    Dim targetFeature As SldWorks.Feature
    
    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    
    ' 1. コンテキストチェック: アクティブなドキュメントは図面か?
    If swModel Is Nothing Then Exit Sub
    If swModel.GetType <> swDocDRAWING Then
        MsgBox "図面ドキュメントを開いた状態で実行してください。", vbCritical
        Exit Sub
    End If
    
    Set swDraw = swModel
    Set swSelMgr = swModel.SelectionManager
    
    ' 2. 選択オブジェクトの解析
    Set swSelObj = swSelMgr.GetSelectedObject6(1, -1)
    If swSelObj Is Nothing Then
        MsgBox "図面上の寸法またはビューを選択してください。", vbExclamation
        Exit Sub
    End If
    
    ' 3. トラバーサル・ロジック
    ' パターンA: 図面寸法(DisplayDimension)が選択されている場合
    If TypeOf swSelObj Is SldWorks.DisplayDimension Then
        Set swDispDim = swSelObj
        Set swModelDim = swDispDim.GetModelDimension ' 3Dモデル側の寸法を取得
        
        If Not swModelDim Is Nothing Then
            ' モデルのコンテキストを取得
            Set targetModel = swModelDim.ModelDoc
            Set targetFeature = swModelDim.GetFeature
            
            ' モデル側へジャンプし、ハイライトを実行
            Call ExecuteModelJump(targetModel, targetFeature)
        End If
        
    ' パターンB: ビュー(View)が選択されている場合
    ElseIf TypeOf swSelObj Is SldWorks.View Then
        Set swView = swSelObj
        Set targetModel = swView.GetModelDoc2
        
        If Not targetModel Is Nothing Then
            ' ビューが参照するモデルのルートをハイライト(例として)
            Call ExecuteModelJump(targetModel, targetModel.FirstFeature)
        End If
    Else
        MsgBox "対象となるオブジェクトが特定できません。", vbInformation
    End If

    ' --- メモリ管理: COMオブジェクトの明示的解放 ---
    ' 大規模アセンブリを扱う場合、これを行わないとメモリリークの原因となる
    Set swDispDim = Nothing
    Set swModelDim = Nothing
    Set swView = Nothing
    Set swSelMgr = Nothing
    Set swDraw = Nothing
    Set swModel = Nothing
End Sub

' --------------------------------------------------------------------------------------
' Sub: ExecuteModelJump
' Purpose: モデルを前面に出し、特定フィーチャーを選択状態にする
' --------------------------------------------------------------------------------------
Private Sub ExecuteModelJump(ByRef targetDoc As SldWorks.ModelDoc2, ByRef targetFeat As SldWorks.Feature)
    ' モデルをアクティブにする(Windows APIレベルの制御が必要な場合もあるが、APIで完結)
    ' ここでは、対象ドキュメントを可視化し、フィーチャーを選択させる
    
    ' 1. モデル側のウィンドウをフォーカス
    ' 注意: SolidWorksの内部状態を強制的に切り替えるため、
    ' 複雑なアセンブリでは、モデルのドキュメントを一度開く、またはActivateする必要がある
    
    ' 2. フィーチャーの選択
    ' SelectionManagerのコンテキストが図面にあるため、targetDocに対してSelectByID2を明示的に呼ぶ
    Dim status As Boolean
    status = targetDoc.Extension.SelectByID2(targetFeat.Name, "=", False, 0, 0, 0)
    
    If status Then
        ' モデル側の画面を更新し、ユーザーに提示
        targetDoc.ViewZoomToSelection2
        MsgBox "モデル側のフィーチャー [" & targetFeat.Name & "] を特定しました。", vbInformation
    Else
        MsgBox "フィーチャーの選択に失敗しました。", vbCritical
    End If
End Sub

3. アーキテクトの視点:パフォーマンスと安定性の極限

このコードを実用的なプロダクション環境(数千個の部品を持つ大規模アセンブリ)に投入する場合、単なる「動くコード」では不十分である。以下の3点について、設計思想に組み込む必要がある。

A. メモリ管理とCOM参照カウント

VBAはガベージコレクションが緩慢である。特に `DrawingDoc` から `ModelDoc2` へとオブジェクトの参照を渡す際、循環参照が発生しやすい。`Set obj = Nothing` による明示的な解放は、単なる作法ではなく、長時間稼働する自動化サーバーにおいては「必須の生存戦略」である。

B. コンテキスト・スイッチングのコスト

`targetDoc.Extension.SelectByID2` を呼び出す際、SolidWorksの内部エンジンは「図面コンテキスト」から「モデルコンテキスト」への切り替えを試みる。この際、大規模アセンブリではグラフィックスの再構築(Regenerate)が走り、処理が数秒停止することがある。
これを回避するためには、「操作が必要になるまでモデル側へのアクセスを遅延させる(Lazy Loading)」設計が不可欠である。

C. Windows APIによるウィンドウ制御の必要性

API経由でモデルを操作しても、ユーザーの画面(GUI)が図面のまま残る場合がある。これは、SolidWorksがマルチドキュメント環境において、アクティブなウィンドウの管理をAPIの呼び出しと同期させていないことが原因だ。
極限のユーザー体験を求めるならば、`user32.dll` の `SetForegroundWindow` を呼び出し、モデル側のウィンドウハンドルを強制的に最前面へ持ってくる実装を検討せよ。

結語

図面とモデルの双方向トラバーサルをマスターすることは、単なるプログラミングスキルの向上ではない。それは、CADデータが持つ「幾何学的な意味」を、デジタル空間において完全に再定義する行為である。

この知見を武器に、単なる「作業の自動化」を超え、「設計意図の自動制御」へと踏み込んでほしい。

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