【実務・中級編】【上級プロ向け】図面内アノテーション(幾何公差・表面粗さ記号)の座標解析と干渉自動検出モジュール – SolidWorks VBA解析バイブル

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

幾何公差の「重なり」を数学的に制圧せよ:図面アノテーションの干渉自動検出とレイアウト最適化の極意

図面自動化のプロジェクトにおいて、多くのエンジニアが「ビューの配置」や「部品番号の書き出し」といった、いわゆる「点の作業」で満足してしまう。しかし、真のプロフェッショナルが直面する地獄は、その先に待っている。

「配置された幾何公差や表面粗さ記号が、互いに重なり合って判読不能になる」という問題だ。

手動で微調整するのは、設計者の貴重な時間をドブに捨てる行為に等しい。かといって、単純な「ランダム移動」を実装すれば、今度は別の記号と重なるという泥沼のループに陥る。

本稿では、SolidWorks APIを使い倒し、アノテーション(注記)の座標空間を数学的に解析することで、干渉を検出し、最適に配置を再計算する、実戦投入レベルのアルゴリズム設計について解説する。

1. なぜ、既存の「簡易的な自動化」は失敗するのか

初心者が書くコードは、大抵の場合、`SelectionMgr` を使って「選択されているものを動かす」という、極めて脆弱な設計に基づいている。これには致命的な欠陥が3つある。

1. COMオーバーヘッドの無視: ループ内で頻繁に `GetAnnotation` や `GetBoundingBox` を呼び出すと、APIを介した通信コストが累積し、大規模図面では処理が指数関数的に重くなる。
2. 座標系の混同: SolidWorksの図面には「モデル空間」「ビュー空間」「シート空間」という異なる座標系が存在する。これらを正しく変換せずに座標比較を行うと、目視では重なっていないのに、計算上は衝突しているという誤判定を招く。
3. 局所最適解の罠: 1つの記号を動かして別の記号と重なれば、それを修正してまた別の記号と重なる。全体を俯瞰した「エネルギー最小化」の視点がないコードは、無限ループか、あるいは「あちらを立てればこちらが立たず」の不完全な配置しか生み出せない。

2. アーキテクチャ設計:衝突検知エンジンの構築

堅牢なモジュールを作るためには、「API操作層」と「幾何計算層」を完全に分離(Decoupling)しなければならない。

ステップ1:データ構造の定義

APIオブジェクトを直接計算に使うのではなく、計算に必要な最小限の情報(座標、幅、高さ、タイプ)を抽出した軽量な構造体(またはクラス)にメモリへキャッシュする。

ステップ2:AABB(Axis-Aligned Bounding Box)アルゴリズム

複雑な多角形判定は不要だ。アノテーションの境界を矩形(AABB)として捉え、その重なりを判定する。計算量は $O(n^2)$ になるが、図面内の注記数は数百程度が限界であるため、VBAの実行速度でも十分に実用範囲に収まる。

3. プロダクション・コード実装例

以下に、図面内の全注記をスキャンし、その境界矩形を解析して干渉を検出するコアロジックを示す。これはそのままプロダクションコードの基盤として利用できる設計思想に基づいている。

Option Explicit

' 注記の情報を格納する軽量な構造体
' APIオブジェクトを直接保持せず、計算に必要な数値のみを抽出することで高速化を図る
Private Type AnnotationBox
    ID As Long
    MinX As Double
    MaxX As Double
    MinY As Double
    MaxY As Double
    Type As Long ' 幾何公差、表面粗さなどの識別用
End Type

''' <summary>
''' 図面内の注記干渉を解析し、衝突しているペアを特定する
''' </summary>
''' <param name="swDraw">SolidWorks Drawingオブジェクト</param>
Public Sub AnalyzeAnnotationInterference(swDraw As SldWorks.DrawingDoc)
    Dim swSheet As SldWorks.Sheet
    Set swSheet = swDraw.GetCurrentSheet
    
    Dim swView As SldWorks.View
    Set swView = swDraw.GetFirstView ' Sheet自体が最初のView
    
    Dim annoList() As AnnotationBox
    Dim count As Long
    count = 0
    
    ' --- PHASE 1: データキャッシング (API呼び出しを最小化) ---
    Dim swAnn As SldWorks.Annotation
    Dim swNote As SldWorks.Note
    Dim vBox As Variant
    
    ' 全てのビューを走査
    Dim currentView As SldWorks.View
    Set currentView = swView.GetNextView
    
    Do While Not currentView Is Nothing
        Dim swViewAnn As SldWorks.Annotation
        Set swViewAnn = currentView.GetFirstAnnotation2
        
        Do While Not swViewAnn Is Nothing
            ' 注記(Note)または幾何公差(Tolerance)を対象とする
            ' ここでは簡略化のためNoteとして扱っているが、実際はTypeで判定
            If swViewAnn.GetType = swAnnotationType_e.swAnnotationType_e.swNote Then
                count = count + 1
                ReDim Preserve annoList(1 To count)
                
                ' 境界ボックスを取得 (Sheet座標系への変換が必要な点に注意)
                ' GetBoundingBoxはビューの座標系を返すため、
                ' 本来はViewのTransform行列を用いてSheet座標へ変換するロジックが必要
                vBox = swViewAnn.GetBoundingBox
                
                With annoList(count)
                    .ID = count
                    .MinX = vBox(0)
                    .MaxX = vBox(3)
                    .MinY = vBox(1)
                    .MaxY = vBox(4)
                    .Type = swViewAnn.GetType
                End With
            End If
            Set swViewAnn = swViewAnn.GetNextAnnotation
        Loop
        Set currentView = currentView.GetNextView
    Loop

    ' --- PHASE 2: 衝突判定アルゴリズム (AABB) ---
    Debug.Print "--- 干渉検出レポート ---"
    Dim i As Long, j As Long
    Dim collisionFound As Boolean
    
    For i = 1 To count
        For j = i + 1 To count
            If IsColliding(annoList(i), annoList(j)) Then
                Debug.Print "衝突検知: ID[" & annoList(i).ID & "] と ID[" & annoList(j).ID & "]"
                collisionFound = True
                ' ここで自動微調整ロジック(Repulsion Forceなど)を呼び出す
                ' AdjustPosition annoList(i), annoList(j)
            End If
        Next j
    Next i
    
    If Not collisionFound Then Debug.Print "干渉は見つかりませんでした。"
End Sub

''' <summary>
''' 二つの矩形が衝突しているかを判定する高速な関数
''' </summary>
Private Function IsColliding(box1 As AnnotationBox, box2 As AnnotationBox) As Boolean
    ' AABBの衝突判定条件: 
    ' 片方の矩形が、もう片方の矩形の上下左右のいずれにも外れていなければ衝突している
    IsColliding = Not (box1.MaxX < box2.MinX Or _
                       box1.MinX > box2.MaxX Or _
                       box1.MaxY < box2.MinY Or _
                       box1.MinY > box2.MaxY)
End Function

4. 実装における「極限の知見」:設計者が守るべき鉄則

コードを書いただけで満足してはいけない。このツールをプロダクション環境に投入する際、以下の3点を設計に組み込んでいるか自問自答せよ。

① 座標変換の完全性

上記のサンプルコードでは簡略化しているが、`GetBoundingBox` が返す値は「ビューの座標系」である。図面内でビューが回転していたり、スケールがかかっている場合、単純な比較は無意味だ。
必ず `swView.GetCoordinateSystem` を取得し、その座標系を用いて、全ての注記を「シートの絶対座標(Sheet Space)」に変換してから比較せよ。これができないツールは、ゴミ箱行きだ。

② データベース連携による「ルール」の外部化

「どれくらい離すべきか」「どの記号を優先して動かすか」というルールをVBAのハードコードにしてはいけない。

  • 幾何公差は優先度:高(動かさない)
  • 表面粗さは優先度:低(動かす)

このようなルールを XML または CSV ファイルとして外部化しておけ。設計部門の要求変更のたびにVBAをコンパイルし直すような非効率な運用は、アーキテクトの恥である。

③ 冪等性(Idempotency)の確保

「何度実行しても、同じ結果(正しい配置)に収束するか」を保証せよ。
位置微調整アルゴリズム(例:衝突している要素間に反発力を与える物理シミュレーション的な手法)を実装する場合、一度の実行で決着がつかないことがある。
「最大試行回数」を設定し、それを超えた場合は「手動修正が必要」という警告をユーザーに返す。「自動化ツールが勝手に図面を破壊した」という事態を防ぐことこそが、最も重要な仕様である。

結論

図面自動化の真髄は、単なる「作業の置き換え」ではない。「設計者の意図を、数学的な整合性をもって具現化すること」にある。

座標解析、衝突検知、そして最適化。これらのステップを論理的に構築することで、君の作成するツールは、単なるマクロから、エンジニアリングを支える「プラットフォーム」へと昇華する。

次にコードを書くときは、その一行が、描画される図面の「品質」にどう寄与するかを、常に意識せよ。

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