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

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

図面の幾何学的秩序:寸法線の干渉検知と自動オフセット制御における極限の設計論

自動ビュー生成、自動寸法付与。これらは一見、図面作成のゴールに見える。しかし、現場を知るアーキテクトであれば、その先にある「視認性の地獄」を知っているはずだ。

ビューが自動生成された直後の図面には、無秩序に配置された寸法線が重なり合い、引き出し線が交差する「スパゲッティ・ディメンション」が跋扈している。これを手動で修正するのは、エンジニアの知性を浪費する低付加価値な作業だ。

本稿では、寸法線の幾何学的関係を解析し、干渉を検知して、数学的に最適なオフセット値を再計算・適用する、実戦的なアルゴリズムとその実装におけるメモリ管理、パフォーマンス最適化の極意を伝授する。

1. 幾何学的衝突検知のアーキテクチャ

寸法線の干渉を解決するためには、単なる「座標の比較」では不十分である。寸法線は「点」ではなく「線分(Segment)」だからだ。

我々が実装すべきロジックは、以下の3フェーズからなる。

1. 抽出フェーズ: `IDrawingDoc` から全 `IAnnotation` を走査し、`swAnnotationType_e.swAnnotationType_Dimension` を持つオブジェクトをメモリ上にバッファリングする。
2. 衝突検知フェーズ: 線分同士の最短距離を計算する。ここでは、AABB(Axis-Aligned Bounding Box)による高速な棄却判定を行った後、線分対線分の最短距離アルゴリズムを適用する。
3. 解消フェーズ: 干渉が閾値以下である場合、寸法線の `Offset` プロパティ、あるいは `Leader` の位置をベクトル演算に基づき再配置する。

幾何学計算の重み

大量の寸法を扱う場合、$O(n^2)$ の計算量は致命的となる。全寸法同士を総当たりで比較するのではなく、空間分割(Spatial Partitioning)の概念を導入し、近傍の寸法のみを比較対象とする設計が、シニアエンジニアに求められる視点である。

2. 実装:高精度寸法オフセット・エンジン

以下に、実務レベルで耐えうる、メモリ管理を徹底したVBAコードの骨子を示す。ここでは、簡略化のために「寸法線の中心点近傍の距離」による判定を用いているが、本質は線分間の距離計算にある。

'**
' Module: DimensionLayoutOptimizer
' Description: 図面内の寸法線の干渉を検知し、オフセットを自動調整する
' Author: Legendary Chief Architect
'**

Option Explicit

' Windows API: 高精度な時間計測(パフォーマンスプロファイリング用)
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long

' 定数定義
Private Const MIN_DIM_DISTANCE As Double = 0.005 ' 最小許容間隔 (m単位)
Private Const SEARCH_RADIUS As Double = 0.05    ' 干渉探索範囲

Sub OptimizeDimensionLayout()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim swSheet As SldWorks.Sheet
    Dim swView As SldWorks.View
    Dim swAnn As SldWorks.Annotation
    Dim swDim As SldWorks.Dimension
    
    Dim startTime As Long
    startTime = GetTickCount()

    On Error GoTo ErrorHandler

    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. メモリ最適化のためのコレクション準備
    ' 大量のアノテーションを扱うため、オブジェクトの参照を保持する
    Dim dimCollection As New Collection
    Dim dimData As Variant ' Array(Annotation, Dimension)
    
    ' 3. 全ビューを走査し、寸法オブジェクトを収集
    Set swView = swDraw.GetFirstView ' Sheet自体が最初のView
    Do While Not swView Is Nothing
        Set swAnn = swView.GetFirstAnnotation2
        Do While Not swAnn Is Nothing
            ' 寸法線のみを抽出
            If swAnn.GetType = swAnnotationType_e.swAnnotationType_Dimension Then
                Set swDim = swAnn.GetSpecificAnnotation
                ' データのカプセル化(AnnotationとDimensionをペアで保持)
                dimCollection.Add Array(swAnn, swDim)
            End If
            Set swAnn = swAnn.GetNext2
        Loop
        Set swView = swView.GetNextView
    Loop

    ' 4. 干渉検知と再計算アルゴリズム
    Dim i As Long, j As Long
    Dim ann1 As SldWorks.Annotation, ann2 As SldWorks.Annotation
    Dim dim1 As SldWorks.Dimension, dim2 As SldWorks.Dimension
    Dim pos1 As Variant, pos2 As Variant
    Dim dist As Double

    Debug.Print "Processing " & dimCollection.Count & " dimensions..."

    For i = 1 To dimCollection.Count - 1
        ' 配列からオブジェクトを取り出し、明示的に参照をセット
        ann1 = dimCollection(i)(0)
        dim1 = dimCollection(i)(1)
        pos1 = ann1.GetPosition

        For j = i + 1 To dimCollection.Count
            ann2 = dimCollection(j)(0)
            dim2 = dimCollection(j)(1)
            pos2 = ann2.GetPosition

            ' 2点間のユークリッド距離計算
            dist = Sqr((pos1(0) - pos2(0)) ^ 2 + (pos1(1) - pos2(1)) ^ 2)

            ' 衝突判定
            If dist < MIN_DIM_DISTANCE Then
                ' 干渉検知:オフセット値を動的に変更
                ' ここでは単純に、現在のオフセットに一定値を加算するロジックを適用
                ' 実務では、ベクトルの向きに基づいた精密な押し出しが必要
                Dim currentOffset As Double
                currentOffset = dim1.GetTextDimension2 ' 簡易的な取得例
                
                ' 寸法線のオフセットを調整(API仕様に基づき、適切なプロパティを操作)
                ' 注: DimensionのOffset操作は、ジオメトリの向きに依存するため注意が必要
                dim1.SetOffset2 0.005, 0 ' X方向にオフセット
                
                Debug.Print "Collision detected and adjusted at: " & pos1(0) & ", " & pos1(1)
            End If
        Next j
    Next i

    ' 5. 後処理とメモリ解放
    swModel.ForceRebuild3 True
    
    Dim endTime As Long
    endTime = GetTickCount()
    Debug.Print "Execution Time: " & (endTime - startTime) & " ms"

    ' 明示的なオブジェクト解放 (COM参照カウントの低減)
    Set swDim = Nothing
    Set swAnn = Nothing
    Set swView = Nothing
    Set swSheet = Nothing
    Set swDraw = Nothing
    Set swModel = Nothing
    Set swApp = Nothing
    
    Exit Sub

ErrorHandler:
    MsgBox "Critical Error: " & Err.Description, vbCritical
    ' エラー時もリソースを解放する
    Set swApp = Nothing
End Sub

3. 伝説的アーキテクトによる「極限の知見」

このコードを単なる「動くスクリプト」で終わらせてはならない。プロフェッショナルとして、以下の3点に留意せよ。

① COMオブジェクトのライフサイクル管理

VBAはCOM(Component Object Model)を介してSolidWorksと通信する。`Set obj = Nothing` を怠ることは、メモリリークを許容し、長時間稼働するサーバーサイド自動化において致命的な「SolidWorksのゾンビプロセス化」を招く。特に、ループ内で大量の `Annotation` オブジェクトを生成する場合、スコープを限定し、明示的に参照を解除する習慣を徹底せよ。

② 浮動小数点誤差への対峙

幾何学計算において `If dist = 0 Then` という比較は「禁忌」である。コンピュータの浮動小数点演算には必ず誤差が伴う。常に `If Abs(dist – target) < epsilon Then` のように、極小値(Epsilon)を用いた比較を行え。これは、レガシーなFortranから現代のC++に至るまで、計算幾何学の鉄則である。

③ 性能のボトルネック:API Overheads

SolidWorks APIの呼び出しは、VBA内部の処理に比べて極めて「重い」。
`swAnn.GetPosition` をループ内で呼び出す回数を最小限に抑えるため、一度取得した座標データは、可能な限り標準的な変数(Double型配列など)にキャッシュして処理せよ。APIを叩く回数を減らすことこそが、最高峰の最適化である。

結び

図面の美しさは、設計者の思考の整理度を映し出す鏡である。
自動化エンジニアの使命は、単に作業を速めることではない。計算機にしかできない「精密な秩序の再構築」を通じて、人間が設計の本質に集中できる環境を構築することにある。

このアルゴリズムを基盤とし、貴殿の現場にふさわしい「幾何学的秩序」を実装せよ。

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