【入門編】【中級者向け】図面内の寸法線レイアウト自動整列:重なった寸法線を検知してオフセットを自動調整 – SolidWorks VBA解析バイブル

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

「マクロの記録」のその先へ。図面を美しく整える「寸法線レイアウト最適化」の思考法

こんにちは。設計自動化の世界へようこそ。

あなたが今、SolidWorks VBAを学んでいて、「マクロの記録」ボタンを連打してコードを生成しているとしたら……。それは素晴らしい第一歩です。しかし、同時に「自動化の壁」に直面しているはずです。

「記録したコードを動かしてみたけれど、別の図面では全く同じ動きをしてくれない」
「寸法が重なってしまい、結局手動で直している」

もしそう感じているなら、おめでとうございます。あなたは今、「操作を記録する人」から「システムを設計するエンジニア」へと進化する境界線に立っています。

今日は、実務で最も泥臭く、かつ最も価値が高いテーマの一つである「図面内の寸法線レイアウトの自動整列」について、その設計思想と実装の極意を伝授します。

1. なぜ「マクロの記録」では寸法を整列させられないのか?

「マクロの記録」が生成するコードの多くは、`SelectByID2`(名前を指定して選択する)や、特定の座標への移動(`SetPosition`)で構成されています。

これは、いわば「決め打ち」のプログラミングです。
「Aという寸法の位置を、10mm上に動かす」という命令は書けますが、「もし寸法同士が重なっていたら、重ならない位置まで動かす」という「判断」は、記録されたコードには書けないのです。

図面を美しく整列させるためには、以下の3つのステップをプログラムに持たせる必要があります。

1. 検知 (Detection): 図面内のすべての寸法オブジェクトをスキャンし、それぞれの「位置」と「サイズ(占有範囲)」を把握する。
2. 判定 (Collision Check): 二つの寸法の占有範囲が重なっているかを、数学的に計算する。
3. 解決 (Resolution): 重なりを解消するために、適切なオフセット量(隙間)を計算して、寸法を再配置する。

ここからは、このロジックをどう実装していくか、エンジニアの思考プロセスを辿っていきましょう。

2. 核心:寸法オブジェクトの「存在」を捉える

寸法を動かすためには、まず「その寸法が図面のどこに、どのくらいの大きさで存在しているか」を知る必要があります。

ここで重要になるのが、SolidWorks APIのオブジェクト階層です。
図面において、私たちが操作したいのは `DisplayDimension` オブジェクトです。しかし、その位置情報や表示領域(Bounding Box)にアクセスするためには、その背後にある `Annotation` オブジェクトを介する必要があるケースがほとんどです。

考えるべきパラメータ

寸法が重なっているかを判定するために、以下の要素を抽出します。

  • $X, Y$ 座標: 寸法テキストの現在の位置。
  • 幅 ($W$) と 高さ ($H$): テキストや寸法線が占有している領域の大きさ。

3. 実装例:寸法重なり検知と自動オフセット

それでは、具体的なコードを見ていきましょう。
ここでは、「水平方向に並んでいる寸法同士が、垂直方向に重なっている場合に、上下に隙間を空ける」という、実務で非常に重宝するロジックをベースに解説します。

※このコードは、学習用にロジックを簡略化していますが、プロフェッショナルな設計の雛形としてそのまま活用できます。

Option Explicit

' ==============================================================================
' テーマ: 重なった寸法線の自動整列(垂直方向の衝突回避)
' 概要: 図面内の寸法を走査し、垂直方向の距離が近いものを検知してオフセットする
' ==============================================================================

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 swDispDim As SldWorks.DisplayDimension
    Dim swAnn As SldWorks.Annotation
    
    Dim dimList() As SldWorks.DisplayDimension ' 寸法オブジェクトのリスト
    Dim dimPos() As Double                     ' 寸法のY座標リスト
    Dim dimCount As Long
    Dim i As Long, j As Long
    
    ' 定数設定
    Const MIN_GAP As Double = 0.005 ' 最小の隙間 (単位はメートル: 5mm)
    
    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    
    ' 図面ドキュメントかチェック
    If swModel Is Nothing Or swModel.GetType <> swDocDRAWING Then
        MsgBox "図面ファイルを開いてから実行してください。"
        Exit Sub
    End If
    
    Set swDraw = swModel
    Set swView = swDraw.GetFirstView ' Sheet自体を取得
    
    ' --- STEP 1: 図面内のすべての寸法を収集 ---
    dimCount = 0
    Set swView = swView.GetNextView ' 最初のビュー(シート)の次へ移動
    
    Do While Not swView Is Nothing
        Set swDispDim = swView.GetFirstDisplayDimension
        
        Do While Not swDispDim Is Nothing
            dimCount = dimCount + 1
            ReDim Preserve dimList(1 To dimCount)
            ReDim Preserve dimPos(1 To dimCount)
            
            Set dimList(dimCount) = swDispDim
            
            ' 注釈オブジェクトから位置を取得
            Set swAnn = swDispDim.GetAnnotation
            dimPos(dimCount) = swAnn.GetPosition(0, 0, 0, 0) ' Y座標を取得(簡易化のため)
            ' ※実際にはGetPositionの戻り値から適切なインデックスを抽出
            
            ' 本来はここで Y座標を正確に取得するロジックが必要
            ' 以下、概念的な実装として Y座標を抽出
            Dim pos(2) As Double
            swAnn.GetPosition pos(0), pos(1), pos(2)
            dimPos(dimCount) = pos(1)
            
            Set swDispDim = swDispDim.GetNextDisplayDimension
        Loop
        Set swView = swView.GetNextView
    Loop
    
    If dimCount < 2 Then
        MsgBox "比較可能な寸法が見つかりませんでした。"
        Exit Sub
    End If

    ' --- STEP 2: 重なり判定とオフセット実行 ---
    ' 二重ループで全ての組み合わせを比較(計算量に注意)
    ' 実務では、近接しているものだけに限定する空間分割アルゴリズムを使うのが理想
    
    swModel.DrawingViewUpdate
    
    For i = 1 To dimCount
        For j = i + 1 To dimCount
            
            ' 垂直方向の距離を計算
            Dim diffY As Double
            diffY = Abs(dimPos(i) - dimPos(j))
            
            ' もし距離が設定した閾値(MIN_GAP)より小さければ、重なっているとみなす
            If diffY < MIN_GAP Then
                ' 重なりを解消するために、j番目の寸法を上に押し上げる
                ' (iとjのどちらを動かすかは、既存のレイアウト規則に基づき決定する)
                
                Dim swAnnI As SldWorks.Annotation
                Dim swAnnJ As SldWorks.Annotation
                Set swAnnI = dimList(i).GetAnnotation
                Set swAnnJ = dimList(j).GetAnnotation
                
                Dim currentPosI(2) As Double
                Dim currentPosJ(2) As Double
                swAnnI.GetPosition currentPosI(0), currentPosI(1), currentPosI(2)
                swAnnJ.GetPosition currentPosJ(0), currentPosJ(1), currentPosJ(2)
                
                ' 新しい位置を計算(iより上に配置)
                Dim newY As Double
                If currentPosI(1) > currentPosJ(1) Then
                    newY = currentPosI(1) + MIN_GAP
                Else
                    newY = currentPosJ(1) + MIN_GAP
                End If
                
                ' 位置を更新
                swAnnJ.SetPosition currentPosJ(0), newY, currentPosJ(2)
                
                ' 次の判定のために座標リストを更新(重要!)
                dimPos(j) = newY
                
                ' 画面更新を抑制するために、最後に一括で行うのが理想だが、
                ' 今回は動作確認のため逐次更新
            End If
        Next j
    Next i
    
    ' 描画の再構築
    swModel.ForceRebuild3 True
    MsgBox "レイアウトの最適化が完了しました。"
End Sub

4. チーフアーキテクトからの「極限の知見」

コードを書き終えて満足してはいけません。プロのエンジニアは、常に「計算コスト」と「堅牢性」を気にかけます。このコードをさらに一段上のレベルへ引き上げるためのアドバイスを贈ります。

① 計算量の罠($O(n^2)$ 問題)

上記のコードでは、寸法を総当たりで比較する「二重ループ」を使用しています。寸法が10個なら100回の比較で済みますが、大規模な図面で寸法が500個ある場合、250,000回の比較が発生します。
これを回避するには、「グリッド分割(Spatial Partitioning)」という手法を使います。図面を格子状のエリアに分け、同じエリア、あるいは隣接するエリアにある寸法同士だけを比較するのです。これだけで、処理速度は劇的に向上します。

② オブジェクトのライフサイクルと更新

`swAnn.SetPosition` を実行した直後、SolidWorks内部の座標系はまだ「古い状態」のままです。
コード内で `dimPos(j) = newY` と手動で配列を更新しているのは、「次に比較する相手に対して、最新の(動かした後の)座標で判定するため」です。ここを怠ると、連続して重なっている寸法を正しく回避できなくなります。

③ 単位の意識

SolidWorks APIの内部単位は、常に メートル (m) です。
「5mm空けたい」と思って `SetPosition 5` と書くと、5メートル空けることになり、寸法は図面の遥か彼方へ飛んでいってしまいます。`0.005` と書くか、定数として `Const MM_TO_M = 0.001` を定義する癖をつけましょう。

最後に

「寸法を自動で並べる」というタスクは、一見すると単純な作業に見えます。しかし、そこには幾何学的な判定、オブジェクトの階層構造の理解、そしてパフォーマンスへの配慮といった、エンジニアリングの本質が詰まっています。

マクロの記録から卒業し、こうした「論理的な思考」をコードに落とし込めるようになれば、あなたの自動化スキルは無敵のものになります。

一歩ずつ、確実に。図面を支配するエンジニアを目指していきましょう。応援していますよ。

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