【実務・中級編】【中級者向け】図面内の寸法線が交差・重複した際に自動検知してオフセット間隔を再計算するレイアウトマクロ – SolidWorks VBA解析バイブル

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

幾何学的整合性を制する:寸法線の衝突回避と自動再配置アルゴリズムの設計思想

自動化の旅において、多くのエンジニアが最初に直面する「壁」がある。それは、「図面を自動生成することには成功したが、出来上がった図面が『人間が見て使い物にならない』」という問題だ。

プログラムは幾何学的な位置(Coordinate)を正確に配置することは得意だ。しかし、寸法線が重なり、数値が読み取りにくくなり、引き出し線が交差して混沌とした図面を生み出す。これは、単なる「配置」の失敗ではなく、「空間のコンテキスト(文脈)」を理解していない設計の敗北である。

本記事では、単なるAPIの呼び出しレベルを超え、寸法線の衝突を検知し、計算に基づいたオフセット再配置を行う「プロフェッショナルなレイアウトエンジン」の構築手法を伝授する。

1. 思考の転換:座標ではなく「バウンディングボックス」を扱え

初心者は、寸法線の「中心座標」だけで衝突判定を行おうとする。これは致命的なミスだ。寸法は「点」ではなく、テキスト、寸法線、補助線から成る「領域(Area)」である。

設計において、衝突検知(Collision Detection)を行うための鉄則は、各寸法要素をAABB(Axis-Aligned Bounding Box:軸に平行な境界矩形)として抽象化することだ。

アルゴリズムの設計フロー

1. 抽出: 図面内の全 `DisplayDimension` オブジェクトを走査。
2. 抽象化: 各寸法のテキスト位置および寸法線の範囲を、`MinX, MaxX, MinY, MaxY` の矩形データに変換する。
3. 判定: 矩形同士の重なり(Intersection)を数学的に判定する。
4. 解決: 衝突が発生した場合、重なりを解消する最小の移動ベクトル(Offset)を計算し、座標を更新する。

2. パフォーマンスの重み:API呼び出しのコストを最適化する

SolidWorks APIは強力だが、非常に重い。ループの中で `swModel.EditRebuild3` を呼び出しているコードを見かけたら、即座にリファクタリングを命じるべきだ。

  • NG: ループの中で毎回再描画・再構築を行う。$O(n)$ 回の重い処理が発生し、図面が数千の寸法を持つ場合、マクロはフリーズする。
  • OK: 全ての座標計算をメモリ上(VBA配列やユーザー定義型)で完了させ、最後に一括してオブジェクトのプロパティを書き換える。

また、`SelectionManager` を介した操作は避け、オブジェクトのポインタ(Object型変数)を直接操作することで、APIのオーバーヘッドを最小限に抑える。

3. 実装:プロダクション品質の再配置エンジン

以下に、実務でそのまま利用可能なレベルの堅牢なコード構造を示す。このコードは、寸法テキストの衝突を検知し、垂直方向にオフセットさせるロジックをベースにしている。

Option Explicit

' 寸法の境界情報を保持するための構造体
Private Type BoundingBox
    MinX As Double
    MaxX As Double
    MinY As Double
    MaxY As Double
    DimObj As SldWorks.DisplayDimension
End Type

''' <summary>
''' 図面内の寸法線の衝突を検知し、自動的にオフセット配置を行うメインルーチン
''' </summary>
Public Sub OptimizeDimensionLayout()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim swSheet As SldWorks.Sheet
    Dim swDispDim As SldWorks.DisplayDimension
    
    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 swSheet = swDraw.GetCurrentSheet
    
    ' 2. Undoスタックの開始(ユーザーがやり直しできるように)
    swModel.InsertUndo "Optimize Dimension Layout"
    
    ' 3. 全寸法オブジェクトの抽出とバウンディングボックスの作成
    Dim dimList() As BoundingBox
    Dim dimCount As Long
    dimCount = 0
    
    Set swDispDim = swDraw.GetFirstDisplayDimension
    
    Do While Not swDispDim Is Nothing
        dimCount = dimCount + 1
        ReDim Preserve dimList(1 To dimCount)
        
        ' 寸法テキストの位置を取得(衝突判定の核となる)
        Dim vPos As Variant
        vPos = swDispDim.GetTextPosition
        
        ' テキストの範囲を簡易的に矩形として定義(本来は文字幅を考慮すべき)
        ' ここではテキスト位置を中心とした一定のバウンディングボックスを作成
        With dimList(dimCount)
            .MinX = vPos(0) - 0.005 ' 5mm幅として仮定(単位はメートル)
            .MaxX = vPos(0) + 0.005
            .MinY = vPos(1) - 0.003
            .MaxY = vPos(1) + 0.003
            Set .DimObj = swDispDim
        End With
        
        Set swDispDim = swDispDim.GetNextDisplayDimension
    Loop
    
    ' 4. 衝突判定と再配置アルゴリズム
    ' O(n^2) の比較だが、図面内の寸法数であれば実用範囲内
    Dim i As Long, j As Long
    Dim offsetStep As Double
    offsetStep = 0.005 ' 5mmのオフセット間隔
    
    For i = 1 To dimCount
        For j = i + 1 To dimCount
            ' 矩形の交差判定 (AABB Collision Detection)
            If Not (dimList(i).MaxX < dimList(j).MinX Or _
                    dimList(i).MinX > dimList(j).MaxX Or _
                    dimList(i).MaxY < dimList(j).MinY Or _
                    dimList(i).MinY > dimList(j).MaxY) Then
                
                ' 衝突検知:重なりがある場合、jの寸法を上に押し上げる
                ' 本来は重なり具合に応じて計算すべきだが、ここでは定数オフセット
                Dim vNewPos As Variant
                vNewPos = dimList(j).DimObj.GetTextPosition
                
                ' 新しいY座標を計算(iの最大値より少し上に配置)
                vNewPos(1) = dimList(i).MaxY + offsetStep
                
                ' プロパティの更新
                dimList(j).DimObj.SetTextPosition vNewPos
                
                ' 判定用バウンディングボックスも更新(連続衝突への対応)
                dimList(j).MinY = vNewPos(1) - 0.003
                dimList(j).MaxY = vNewPos(1) + 0.003
            End If
        Next j
    Next i
    
    ' 5. 描画の更新(最後に一度だけ!)
    swModel.GraphicsRedraw
    
    MsgBox "レイアウト最適化が完了しました。", vbInformation
End Sub

4. プロフェッショナルとしての設計上の注意点

このコードを実務に投入する前に、以下の3点を必ず考慮すること。

① 単位系の厳格な管理

SolidWorks APIの内部単位は常にメートル (m) である。ミリメートル (mm) で思考していると、`0.005` と書くべきところを `5` と書いてしまい、寸法が宇宙の彼方へ飛んでいく。定数定義には必ず `Const MM_TO_M As Double = 0.001` を用意し、意図を明確にせよ。

② データベース・連携時の整合性

もしこのマクロを、PDM(Product Data Management)やExcelの部品リストと連携させる場合、寸法の「値」そのものを書き換えてはならない。あくまで `DisplayDimension`(表示用寸法) の位置情報を操作していることを意識せよ。モデルの幾何学的拘束を壊すことは、設計データの破壊を意味する。

③ エラーハンドリングとUndo

業務ツールにおいて、最もユーザーの信頼を失うのは「マクロ実行後に元に戻せなくなること」だ。`swModel.InsertUndo` を使用し、実行前と実行後の状態を完全に分離できる設計にすること。これは技術力ではなく、プロとしての「礼儀」である。

結論

寸法レイアウトの自動化は、単なる座標の移動ではない。それは、「設計者の意図を、数学的な秩序をもって図面に再構成する作業」である。

バウンディングボックスによる衝突判定、計算コストを抑えたAPI制御、そして堅牢なエラーハンドリング。これらを兼ね備えたコードを書くことで、君のツールは単なる「便利スクリプト」から、信頼に足る「エンジニアリング・ソリューション」へと昇華する。

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