秩序なき図面を制する:BOM同期型バルーン自動配置アルゴリズムの設計思想
設計現場において、アセンブリ図面の「バルーン(部品番号)」の配置は、エンジニアの精神を最も削る作業の一つだ。
「BOMの順番とバラバラだ」「引き出し線が重なってスパゲッティ状態だ」「部品を追加したら番号がズレた」――。これらはすべて、「図面を単なる『絵』として扱い、データ構造(BOM)との同期を軽視している」ことに起因する。
多くのプログラマが陥る罠は、`DrawingDoc.GetFirstBalloon` のように、図面に既に存在するオブジェクトをループで回して位置を調整しようとすることだ。そんなものは「修正ツール」であって「自動生成エンジン」ではない。
真に堅牢な自動化ツールを構築するには、「BOMを正(Single Source of Truth)とし、図面ビュー上の幾何学的座標を決定論的に計算する」というアーキテクチャが必要だ。
本稿では、中級者以上のエンジニアに向けて、BOMの並び順に基づいたバルーンの自動配置と、保守性の高いコード設計について、その極限の知見を伝授する。
1. アーキテクチャ設計:なぜ「既存のバルーン操作」では失敗するのか
一般的な「バルーン整理マクロ」は、既存のバルーンを一つずつ取得し、そのテキストを読み取り、位置を動かすというアプローチをとる。しかし、これには致命的な欠陥がある。
1. データの不整合: BOMの行が入れ替わった際、既存のバルーンの「テキスト」と「BOMのインデックス」の紐付けが崩壊する。
2. 計算コストの増大: 既存オブジェクトの検索とプロパティ書き換えは、オブジェクトモデルの再構築を頻繁に引き起こし、大規模アセンブリでは極めて低速になる。
3. 幾何学的制御の欠如: 既存の配置に依存するため、新しい部品が増えた際に「どこに置くべきか」という空間的な判断ができない。
推奨される設計フロー
我々が実装すべきは、以下の「Destroy & Rebuild(破壊と再構築)」戦略だ。
1. Extract: BOMから「部品名」「部品番号」「数量」のリストをメモリ上に抽出する。
2. Locate: 図面ビュー内の各コンポーネントの「重心座標(Center of Gravity)」または「境界ボックスの中心」を特定する。
3. Calculate: 重心座標に基づき、衝突を回避する「配置予定座標」を計算する。
4. Execute: 既存のバルーンを一旦クリアし、計算結果に基づいて新しいバルーンを「一括生成」する。
2. 実装の核心:BOM同期型バルーン配置アルゴリズム
以下に、プロダクション環境で耐えうる堅牢な設計思想に基づいたVBAコードの骨子を示す。ここでは、単なるコピペ用コードではなく、「エラーハンドリング」と「オブジェクトのライフサイクル管理」を組み込んだ、設計図としてのコードを提示する。
Option Explicit
' ==============================================================================
' Module: BalloonAutomationEngine
' Description: BOMの並び順に基づき、図面ビューへバルーンを最適配置する
' Author: Chief Architect
' ==============================================================================
Sub Main()
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swDraw As SldWorks.DrawingDoc
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
' 2. 処理の開始(パフォーマンス向上のため再描画を抑制)
swModel.LockVisualUpdates = True
' 3. メインプロセスの実行
' ここでは、アクティブなシートの最初のビューを対象とする
Dim swSheet As SldWorks.Sheet
Set swSheet = swDraw.GetCurrentSheet
Dim swView As SldWorks.View
Set swView = swDraw.GetFirstView ' Sheet自体が最初のViewとして取得される
Set swView = swView.GetNextView ' 次のView(実際の投影図)へ移動
If Not swView Is Nothing Then
Debug.Print "Processing View: " & swView.Name
ProcessViewBOMAlignment swView
Else
MsgBox "有効なビューが見つかりません。", vbExclamation
End If
CleanUp:
' 4. 後処理(必ず実行されるべきリソース解放)
swModel.LockVisualUpdates = False
swModel.ForceRebuild3 True
Set swDraw = Nothing
Set swModel = Nothing
Set swApp = Nothing
Exit Sub
ErrorHandler:
MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
Resume CleanUp
End Sub
''' <summary>
''' 指定されたビュー内のコンポーネントをBOM順に走査し、バルーンを配置する
''' </summary>
Private Sub ProcessViewBOMAlignment(ByRef swView As SldWorks.View)
Dim swModel As SldWorks.ModelDoc2
Set swModel = swView.ReferencedDocument
' --- [重要] ここでBOMデータを取得するロジックを分離して実装すべき ---
' 今回は概念を示すため、ビュー内のコンポーネントを直接走査する
' 実際の実務では、BOMテーブルからItemNumberを取得する関数を介すこと
Dim swComp As SldWorks.Component2
Dim swAnnotation As SldWorks.Annotation
Dim swBalloon As SldWorks.Note ' バルーンはNoteオブジェクトとして扱われる
Dim vComps As Variant
vComps = swView.GetVisibleEntities2(swView.GetFirstEntity, swEntityQuery_Components)
' ※実際には GetVisibleEntities2 の使い方は複雑なため、
' 投影図内のコンポーネントリストを適切に取得するロジックが必要
' 仮のループ処理(設計思想の提示)
' 1. 既存のバルーンを削除
DeleteExistingBalloons swView
' 2. コンポーネントをBOM順にループ
' ※ 本来は BOM Table から ItemNumber を引き、その番号に対応するComponentを探す
' 以下のコードは、その「配置ロジック」の核心部である
Dim i As Integer
For i = 0 To 10 ' 仮のループ
' [Step A] コンポーネントの幾何学的中心を取得
' [Step B] 配置座標の計算 (Collision Avoidance Algorithm)
' [Step C] Balloonの生成
' CreateSmartBalloon swView, compCenterPos, itemNumber
Next i
Debug.Print "Alignment Complete."
End Sub
''' <summary>
''' ビュー内の既存バルーンを安全に削除する
''' </summary>
Private Sub DeleteExistingBalloons(ByRef swView As SldWorks.View)
Dim swAnn As SldWorks.Annotation
Set swAnn = swView.GetFirstAnnotation
Do While Not swAnn Is Nothing
' バルーンタイプ(AnnotationType)を確認して削除
If swAnn.GetAnnotationType = swAnnotationType_e.swAnnotationType_Balloon Then
swAnn.GetAnnotation.Remove
End If
Set swAnn = swAnn.GetNext
Loop
End Sub
''' <summary>
''' 幾何学的計算に基づきバルーンを生成する(設計の肝)
''' </summary>
Private Sub CreateSmartBalloon(ByRef swView As SldWorks.View, ByVal centerPos As Variant, ByVal itemNum As String)
' ここに「中心から半径Rの円周上に配置する」
' あるいは「グリッド状に配置する」といった幾何学アルゴリズムを実装する
' 単に centerPos + Offset とするだけでは、部品が密集した際に破綻する
End Sub
3. プロフェッショナルのための技術的アドバイス
幾何学的配置アルゴリズムの選択
バルーンの配置において、最も困難なのは「重なり(Collision)」の回避だ。実務的な解法として、以下の2段階アプローチを推奨する。
1. Radial Placement(放射状配置):
コンポーネントの重心を中心とし、一定の距離($R$)を保った円周上の座標 $(x, y) = (x_c + R\cos\theta, y_c + R\sin\theta)$ を計算する。$\theta$ は、部品の「詰まり具合」に応じて、既存のバルーンとの角度差を計算して決定する。
2. Grid-based Offset(グリッド・オフセット):
部品が極端に密集している場合、放射状では円周が重なりすぎる。その場合は、コンポーネントのBounding Box(境界ボックス)の外側に、仮想的なグリッドを生成し、空いているセルに配置する。
パフォーマンスを支配する「Update抑制」
SolidWorks APIを叩く際、最もコストが高いのは「モデルの再構築(Rebuild)」だ。
バルーンを1つ作るたびに図面全体が再計算されるような実装は、エンジニアを待たせる「質の低いツール」の証だ。
必ず `swModel.LockVisualUpdates = True` を使用し、全てのオブジェクト生成が終わった後に、一度だけ `ForceRebuild3` を実行せよ。
データベース(BOM)との連携における注意点
BOMは「アセンブリファイル」に内包されている場合と、「Excel」などの外部ファイルである場合がある。
ツールを設計する際は、「データ取得層(Data Layer)」を分離せよ。
- `GetBOMData()` という関数をインターフェースとして定義し、中身がExcelからなのか、SolidWorksのBOMテーブルからなのかを、メインロジック(配置エンジン)に意識させない設計にすること。これが、保守性の高いコードを作るための鉄則だ。
結論:自動化とは「秩序の構築」である
バルーンの自動配置は、単なる座標計算ではない。それは、「設計意図(BOM)」を「視覚的情報(図面)」へと、数学的根拠を持って変換する作業である。
「なんとなく動く」コードを書くのは今日で終わりにしよう。
「なぜその位置に配置されるのか」を論理的に説明でき、BOMの変更に対して強靭な、プロフェッショナルなアーキテクチャを構築してほしい。
それが、世界最高峰のエンジニアリングを支える自動化への第一歩だ。
