【テクニカル・上級編】【中級者向け】大判図面(A0/A1)を複数枚のA3図面へ「ゾーン分割」して自動レイアウトするスプリッターVBA – SolidWorks VBA解析バイブル

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

The Splitting Engine: 大判図面をA3へ解体・再構成する、極限の図面スプリッター設計論

現場のエンジニアが抱える「巨大なプラント図面(A0/A1)を、現場で確認するためにA3に分割して出力したい」という切実な要求。これは単なる「印刷設定」の問題ではない。図面の持つ幾何学的情報を、新しいシートの座標系へと再定義し、スケールと位置関係を数学的に再構成する「再構築(Reconstruction)」のプロセスである。

一般的な「ビューのコピー&ペースト」程度のスクリプトでは、メモリの肥大化と座標のズレによって、数枚の処理でSolidWorksはクラッシュするか、あるいはゴミのような図面を吐き出す。

本稿では、プロフェッショナルが実装すべき、極めて堅牢で数学的に正しい「図面スプリッター」のアーキテクチャを詳解する。

1. 座標変換の数学的パラダイム

大判図面からA3への分割において、最も多くの開発者が陥る罠は、「Sheet座標」と「View座標」の混同である。

SolidWorksのAPIにおいて、ビューの配置(`View.Position`)は、シートの原点からの相対位置ではなく、ビュー自身のスケールと、シート上の座標系に基づいた決定論的な値として扱われる。A0からA3へ分割する場合、単にビューを移動させるだけでは不十分だ。

我々が実装すべきロジックは以下の三段階である:

1. 領域の定義 (Bounding Box Calculation): 元のA0シートにおける、分割したいターゲット領域(Zone)の座標($X_{min}, Y_{min}, X_{max}, Y_{max}$)を特定する。
2. スケーリング・リマッピング: A3という新しい「窓(Window)」に対して、モデルビューの表示範囲をどのようにマッピングするか。
3. Viewの再生成とオフセット調整: 既存のビューをコピーするのではなく、ターゲット領域を「中心」または「起点」とする新しいビューを、適切なスケールで挿入する。

2. 実装:高精度スプリッター・コア

以下に、設計の核となるVBAコードを示す。ここでは、パフォーマンスを最大限に引き出すため、`swApp`への直接的な参照を維持しつつ、オブジェクトのライフサイクルを厳格に管理する設計思想を採用している。

'**
' Module: DrawingSplitterEngine
' Author: Chief Architect
' Description: A0/A1 Drawing to Multiple A3 Sheets Splitting Engine
'**
Option Explicit

' Windows API: 高精度な時間計測(パフォーマンスプロファイリング用)
Private Declare PtrSafe Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Private Declare PtrSafe Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long

Sub ExecuteSplittingProcess()
    Dim swApp As SldWorks.SldWorks
    Dim swModel As SldWorks.ModelDoc2
    Dim swDraw As SldWorks.DrawingDoc
    Dim swSheet As SldWorks.Sheet
    
    ' --- Initialization ---
    Set swApp = Application.SldWorks
    Set swModel = swApp.ActiveDoc
    
    If swModel Is Nothing Or swModel.GetType <> swDocDRAWING Then
        MsgBox "図面ファイルを開いた状態で実行してください。", vbCritical
        Exit Sub
    End If
    
    Set swDraw = swModel
    
    ' 性能計測開始
    Dim startTimer As Currency, endTimer As Currency, freq As Currency
    QueryPerformanceFrequency freq
    QueryPerformanceCounter startTimer

    On Error GoTo ErrorHandler
    
    ' --- Splitting Logic ---
    ' ここでは例として、A0図面を縦に2分割してA3シートへ展開するロジックをシミュレート
    ' 実際の実装では、分割グリッドのループ処理を行う
    
    Dim zoneIndex As Integer
    Dim targetX As Double, targetY As Double
    Dim splitWidth As Double, splitHeight As Double
    
    ' 分割パラメータ(単位はメートル)
    ' 本来はシートサイズから動的に計算すべき
    splitWidth = 0.42 / 2 ' A3幅の半分を想定
    splitHeight = 0.297
    
    For zoneIndex = 1 To 2
        ' 1. 新しいA3シートの生成
        ' 第2引数にサイズを指定(A3: 0.42m x 0.297m)
        Dim newSheetName As String
        newSheetName = "Split_Zone_" & zoneIndex
        
        ' 既存シートの削除または新規作成のハンドリング
        If Not CreateA3Sheet(swDraw, newSheetName) Then GoTo NextIteration
        
        ' 2. ビューの再配置(ここが心臓部)
        ' 既存のモデルビューを、新しい座標系へ「投影」するように再配置する
        ' 既存ビューをコピーするのではなく、モデルから新しいビューを挿入する手法が最も安定する
        If Not InsertSplitView(swDraw, swModel, zoneIndex) Then
            Debug.Print "Zone " & zoneIndex & " のビュー挿入に失敗。"
        End If

NextIteration:
    Next zoneIndex

    ' --- Cleanup & Finalize ---
    QueryPerformanceCounter endTimer
    MsgBox "処理完了。経過時間: " & (endTimer - startTimer) / freq & " 秒", vbInformation

ExitSub:
    ' オブジェクトの明示的解放(メモリリーク防止の鉄則)
    Set swDraw = Nothing
    Set swModel = Nothing
    Set swApp = Nothing
    Exit Sub

ErrorHandler:
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical
    Resume ExitSub
End Sub

''' <summary>
''' 新しいA3シートを作成する。既存の同名シートがある場合は削除を試みる。
''' </summary>
Private Function CreateA3Sheet(swDraw As SldWorks.DrawingDoc, sheetName As String) As Boolean
    On Error Resume Next
    ' シートの追加 (Size: swDwgPaperA3size, Scale: 1:1)
    ' 注意: CreateSheetは既存のシートを上書きしないため、管理が必要
    Dim status As Boolean
    status = swDraw.NewSheet(sheetName, swDwgPaperA3size, 0.42, 0.297, 0, 0)
    
    If status Then
        CreateA3Sheet = True
    Else
        ' 既存シートがある場合の処理(実際には削除ロジックを挟む)
        Debug.Print "Sheet creation failed: " & sheetName
        CreateA3Sheet = False
    End If
    On Error GoTo 0
End Function

''' <summary>
''' 指定されたゾーンに基づき、モデルビューを新しいシートへ再配置する
''' </summary>
Private Function InsertSplitView(swDraw As SldWorks.DrawingDoc, swModel As SldWorks.ModelDoc2, zoneIdx As Integer) As Boolean
    Dim swView As SldWorks.View
    Dim swSheet As SldWorks.Sheet
    Dim viewPos As Variant
    Dim modelName As String
    
    modelName = swModel.GetPathName
    Set swSheet = swDraw.GetCurrentSheet
    
    ' 1. モデルから新しいビューを挿入
    ' 第2引数: ViewName, 第3引数: ModelName, 第4引数: Scale, 第5引数: X, 第6引数: Y
    ' ここで、分割座標に基づいたX, Yを計算して渡す
    Dim posX As Double, posY As Double
    posX = (zoneIdx - 1) * 0.21 ' 簡易的な計算例
    posY = 0
    
    ' 挿入 (Scale 1:1 で挿入後、ViewのScaleプロパティで調整するのが定石)
    Set swView = swDraw.CreateDrawViewFromModelView3(modelName, "*Front", posX, posY, 0)
    
    If Not swView Is Nothing Then
        ' 2. ビューのスケール調整
        ' A0の領域をA3の枠内に収めるためのスケール計算
        ' swView.Scale2 = 0.5 ' 例
        
        ' 3. ビューの位置微調整(中心合わせ)
        ' View.Position はシート原点からの距離
        InsertSplitView = True
    Else
        InsertSplitView = False
    End If
End Function

3. 伝説のアーキテクトが教える「極限の最適化」

このコードを、単なる「動くスクリプト」から「産業用システム」へと昇華させるには、以下の3点に留意せよ。

① COMオブジェクトの明示的解放(Deterministic Cleanup)

VBAのガベージコレクションは、大規模な図面処理においてはあまりに不確実だ。`Set swView = Nothing` をループの終わりに明示的に記述せよ。これを怠ると、SolidWorksのメモリ使用量が指数関数的に増大し、`Out of Memory` でプロセスが死ぬ。特に、大量のシートを生成するスプリッターにおいては、これが死活問題となる。

② 再描画(Graphics Update)の抑制

ループ内で `swModel.GraphicsRedraw2` を呼び出すのは愚策だ。描画更新は極めてコストの高い操作である。全てのシート生成、ビュー配置が完了した後に、一括して `swModel.ForceRebuild3` を実行し、最後に一度だけ描画を更新せよ。これだけで処理速度は数倍変わる。

③ Windows APIによるプロファイリング

プロフェッショナルは、勘で「速い」とは言わない。`QueryPerformanceCounter` を用いて、ミリ秒単位での処理時間を計測せよ。どの工程(シート作成、ビュー挿入、スケール計算)にボトルネックがあるかを定量的に特定し、最適化の対象を絞り込むこと。

結言

図面分割スプリッターの開発は、単なる自動化ではない。それは、巨大な設計資産を、実用的な「情報」へと変換するための、高度な幾何学的エンジニアリングである。

座標系を支配し、メモリを統制し、計算の精度を追求せよ。それが、レガシーなCAD環境において、真に価値のあるシステムを構築できる唯一の道である。

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