図面の幾何学的秩序:寸法線の干渉検知と自動オフセット制御における極限の設計論
自動ビュー生成、自動寸法付与。これらは一見、図面作成のゴールに見える。しかし、現場を知るアーキテクトであれば、その先にある「視認性の地獄」を知っているはずだ。
ビューが自動生成された直後の図面には、無秩序に配置された寸法線が重なり合い、引き出し線が交差する「スパゲッティ・ディメンション」が跋扈している。これを手動で修正するのは、エンジニアの知性を浪費する低付加価値な作業だ。
本稿では、寸法線の幾何学的関係を解析し、干渉を検知して、数学的に最適なオフセット値を再計算・適用する、実戦的なアルゴリズムとその実装におけるメモリ管理、パフォーマンス最適化の極意を伝授する。
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を叩く回数を減らすことこそが、最高峰の最適化である。
結び
図面の美しさは、設計者の思考の整理度を映し出す鏡である。
自動化エンジニアの使命は、単に作業を速めることではない。計算機にしかできない「精密な秩序の再構築」を通じて、人間が設計の本質に集中できる環境を構築することにある。
このアルゴリズムを基盤とし、貴殿の現場にふさわしい「幾何学的秩序」を実装せよ。
