【極限の知見】SolidWorks図面における「ユーザー定義記号」の完全制御:配置と一括削除の堅牢な設計思想
図面自動化の世界へようこそ。
多くの開発者が「とりあえず動くコード」を書き、現場の例外処理(イレギュラーな図面構成や古いデータ)に直面して、そのコードをゴミ箱に捨てていく。もし君が、単なる「スクリプト職人」ではなく、プロフェッショナルな「自動化エンジニア」を目指すなら、今日この記事で語るオブジェクトの階層構造への理解とコレクション操作の鉄則を血肉にしてほしい。
今回のテーマは、図面内における「ユーザー定義記号(Sketch Block / 独自シンボル)」の制御だ。社内標準の注記マークや、検図印、特殊な警告記号をプログラムで正確な座標に配置し、あるいは不要になった旧規格の記号を一掃する。
このタスクは一見単純に見えるが、設計を誤れば「座標がズレる」「一部の記号が消えない」「実行中にSolidWorksが落ちる」といった、実務では致命的なバグを招く。
1. 階層構造を掌握せよ:Sketch Blockはどこに「住んでいる」のか
初心者が陥る最大のミスは、図面オブジェクト(`DrawingDoc`)に対して直接「記号を探せ」と命令することだ。SolidWorksのAPIにおいて、記号(Sketch Block)は独立した浮遊物ではない。
記号は必ず以下のいずれかの「器(コンテナ)」の中に存在する。
1. Sheet(シート)のスケッチ: 図面全体の枠組みや、シート共通の注記として配置されるもの。
2. Drawing View(図面ビュー)のスケッチ: 特定の投影図の中に紐付いたもの。
もし君が「シート全体から記号を消したい」と考えているのに、ビュー内のスケッチを走査していなければ、そのスクリプトは不完全だ。逆に、ビューの座標系を無視してシートの座標で配置しようとすれば、記号は意図しない場所へ飛んでいく。
エンジニアの視点:
「対象となる記号が、どの階層のどのスケッチに属しているか」を特定するロジックを、設計の最上位に置け。
2. 配置の極意:座標系の罠を回避する
記号を配置する際、`InsertSketchBlock` などのメソッドを使用するが、ここで重要になるのが「座標系(Coordinate System)」の管理だ。
図面の原点は、シートの左下か、それともビューの中心か?
プログラムで `0, 0` を指定したとき、それが「図面の絶対座標」なのか「ビュー相対座標」なのかを厳格に定義しなければならない。
設計指針:
実務ツールでは、配置座標を「シート基準(Sheet Origin)」で管理することを推奨する。ビューの移動や削除に影響されない、強固な配置が可能になるからだ。
3. 削除の鉄則:コレクション・ミューテーションの回避
ここが最も重要だ。不要な記号を一括削除する際、多くのプログラマーが犯す致命的なミスがある。
' --- 敗北者のコード(絶対に書くな) ---
For i = 1 To Sketch.GetFeatureCount()
Set feat = Sketch.GetFeature(i)
If feat.GetTypeName2 = "SketchBlockInstance" Then
feat.Delete
End If
Next i
なぜこれがダメなのか? 答えは単純だ。「要素を削除すると、コレクションのインデックスが詰まるから」である。
`i=1` を削除した瞬間、元々 `i=2` だった要素が `i=1` に繰り上がる。次のループで `i=2` を参照すると、本来消すべきだった要素をスキップしてしまう。これが「一部の記号が残る」バグの正体だ。
エンジニアの鉄則:
コレクションから要素を削除する場合は、必ず「後ろから(逆順に)ループ」せよ。
4. プロダクション・レディな実装例
以下に、実務でそのまま使えるレベルの堅牢なコードを示す。このコードは、シート内のスケッチを走査し、指定した名前のブロックを安全に削除する設計になっている。
Option Explicit
''
' @description 図面シート内の特定の名称を持つスケッチブロックを一括削除する
' @param swDraw SolidWorks DrawingDoc オブジェクト
' @param targetName 削除対象とするブロックの名前(部分一致)
''
Public Sub RemoveCustomSymbols(swDraw As SldWorks.DrawingDoc, targetName As String)
Dim swSheet As SldWorks.Sheet
Dim swView As SldWorks.View
Dim swSketch As SldWorks.Sketch
Dim swFeat As SldWorks.Feature
Dim swBlockInst As SldWorks.SketchBlockInstance
Dim i As Long
Dim featCount As Long
On Error GoTo ErrorHandler
' 1. アクティブなシートを取得
Set swSheet = swDraw.GetCurrentSheet
If swSheet Is Nothing Then Exit Sub
' 2. シートのスケッチを取得(図面全体の記号はここにある)
' 注: 図面ビュー内の記号を消す場合は、各ビューのスケッチを走査するロジックが必要
Set swSketch = swSheet.GetSketch
If swSketch Is Nothing Then
Debug.Print "Sheet sketch not found."
Exit Sub
End If
' 3. 特徴(Feature)の数を取得
featCount = swSketch.GetFeatureCount()
' --- 核心部: 逆順ループによる安全な削除 ---
' インデックスのズレを防ぐため、末尾から先頭に向かって走査する
For i = featCount To 1 Step -1
Set swFeat = swSketch.GetFeature(i)
' スケッチブロックインスタンスかどうかを判定
If swFeat.GetTypeName2 = "SketchBlockInstance" Then
' ブロックインスタンスを取得
Set swBlockInst = swFeat.GetSpecificFeature2
If Not swBlockInst Is Nothing Then
' ブロックの名前をチェック(定義名での判定)
' ここでは、設計上の要件に基づき「名前が含まれているか」で判定
If InStr(1, swBlockInst.Name, targetName, vbTextCompare) > 0 Then
Debug.Print "Deleting Block: " & swBlockInst.Name
swFeat.Select2 False, 0
swFeat.Delete2
End If
End If
End If
Next i
swDraw.EditRebuild
MsgBox "Cleanup complete.", vbInformation
Exit Sub
ErrorHandler:
MsgBox "Critical Error in RemoveCustomSymbols: " & Err.Description, vbCritical
End Sub
''
' @description 指定座標にカスタム記号(ブロック)を配置する
' @param swDraw SolidWorks DrawingDoc オブジェクト
' @param blockName 配置したいブロックの定義名
' @param x 座標 (mm単位で計算する場合は変換が必要)
' @param y 座標
''
Public Sub InsertCustomSymbol(swDraw As SldWorks.DrawingDoc, blockName As String, x As Double, y As Double)
Dim swSheet As SldWorks.Sheet
Dim swSketch As SldWorks.Sketch
Dim swBlockDef As SldWorks.SketchBlockDefinition
Dim swBlockInst As SldWorks.SketchBlockInstance
On Error GoTo ErrorHandler
Set swSheet = swDraw.GetCurrentSheet
Set swSketch = swSheet.GetSketch
' 1. ブロック定義の取得(ドキュメント内に存在することを前提)
' 実際には、外部ファイルから読み込むか、テンプレートから取得する設計が望ましい
Set swBlockDef = swDraw.GetSketchBlockDefinition(blockName)
If swBlockDef Is Nothing Then
MsgBox "Block definition not found: " & blockName, vbExclamation
Exit Sub
End If
' 2. ブロックの挿入
' 座標はメートル単位であることに注意(SolidWorks APIの標準)
Set swBlockInst = swSketch.InsertSketchBlock(swBlockDef, x, y, 0)
If Not swBlockInst Is Nothing Then
Debug.Print "Inserted: " & blockName & " at " & x & ", " & y
Else
Debug.Print "Failed to insert block."
End If
Exit Sub
ErrorHandler:
MsgBox "Error in InsertCustomSymbol: " & Err.Description, vbCritical
End Sub
5. プロダクション環境での拡張:データベース連携
実務において、記号の名前や座標をVBAのソースコードにハードコード(直書き)するのは、三流の仕事だ。
- 何が問題か?: 社内標準が変わったとき、あるいは配置場所を微調整したいとき、全てのツールを再ビルド・再配布しなければならなくなる。
- どう設計すべきか?: 記号の「定義名」「配置座標」「適用シート名」を管理する外部マスター(CSVまたはExcel)を用意せよ。
理想的なデータフロー:
1. VBAが起動。
2. 外部CSVを読み込み、`Dictionary` オブジェクトに「記号名 $\to$ 座標」のペアを格納。
3. ループ処理で、CSVに基づき正確な位置へ記号を配置。
これだけで、君の作ったツールは「使い捨てのスクリプト」から「保守可能な業務システム」へと昇華する。
結びに代えて
自動化エンジニアの価値は、コードの行数ではなく、「例外をどれだけ事前に排除できているか」で決まる。
オブジェクトの階層を意識し、コレクションの操作に細心の注意を払い、データの外部化を忘れない。この3点を守るだけで、君のコードの堅牢性は劇的に向上するはずだ。
健闘を祈る。
