【実務・中級編】【実務中級者向け】「Export」メソッドによる特定範囲のDXF切り出し:モデル空間の一部のみを別ファイルとして保存する – AutoCAD VBA解析バイブル

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

脱・初心者:Copy & Pasteを卒業せよ。プロフェッショナルが実践する「特定範囲DXF切り出し」の設計思想

AutoCADの自動化を志す者が、必ずと言っていいほど陥る「稚拙な設計」がある。それは、「オブジェクトをコピーして、新しい図面を開いて、貼り付けて、保存する」という、人間が手作業で行う手順をそのままVBAに書き写す手法だ。

もし君が、現在そのようなコードを書いているなら、今すぐその思考を捨ててほしい。

クリップボードに依存する処理は、実行中のユーザー操作によって容易に破壊される。また、メモリ上のオブジェクトのライフサイクルを無視した大量のコピー・ペーストは、AutoCADのメモリリークや予期せぬクラッシュを招く。我々プロフェッショナルが求めるのは、「図面データベースから、特定のサブセットを、いかにクリーンかつ高速に抽出するか」という設計思想だ。

本記事では、実務で即戦力となる「特定範囲(または選択オブジェクト)のDXF切り出し」を、極めて堅牢な手法で実装する方法を伝授する。

1. なぜ `Copy & Paste` ではいけないのか?

実務レベルのツールにおいて、`Selection.Copy` を使うべきではない理由は3つある。

1. クリップボードの競合: ユーザーが処理中に他のアプリケーションでコピー操作を行うと、プログラムは即座に崩壊する。
2. 情報の欠落と肥大化: 単純なコピーでは、レイヤー、ブロック定義、線種などの「依存関係」が正しく引き継がれない、あるいは逆に不要なデータまで大量に引き連れてきてしまう。
3. パフォーマンスの劣化: オブジェクトのインスタンス化とメモリ転送は、AutoCADのカーネルレベルでの操作(WBLOCK等)に比べて圧倒的に重い。

我々が採用すべきは、AutoCADのコマンドライン・インターフェース(CLI)を高度に制御する `-WBLOCK` プロセス、あるいは `Wblock` メソッドによる、データベースレベルの抽出である。

2. アーキテクチャ設計:堅牢な切り出しフロー

「特定の範囲をDXFとして書き出す」機能を実装する場合、以下のステップで設計を構成する。

STEP 1: 抽出対象の定義(Selection Setの構築)

単なる座標範囲(Bounding Box)なのか、ユーザーが選択したオブジェクトなのかを明確にする。座標範囲の場合は、`SelectByPolygon` を用いて、空間的なフィルタリングをカーネル側で行わせるのが定石だ。

STEP 2: 依存関係の制御

DXFとして切り出す際、そのオブジェクトが参照している「ブロック定義」や「レイヤー」がどう扱われるかを制御する必要がある。`-WBLOCK` コマンドは、選択されたエンティティに必要な定義を自動的にパッケージングしてくれるため、極めて合理的だ。

STEP 3: ファイルI/Oとエラーハンドリング

書き出し先のディレクトリが存在するか、同名のファイルがロックされていないか。これらを事前にチェックせずに出力処理に入るのは、設計ミスと言わざるを得ない。

3. プロダクション・コード:RobustDXFExporter

以下に、実務でそのまま利用可能なレベルの、クラスモジュールを意識した実装例を示す。このコードは、選択したオブジェクト群を、指定したパスにDXF形式で書き出す。

' ==============================================================================
' Module: DXFExportEngine
' Description: 特定のオブジェクトセットをDXFとして堅牢に書き出すエンジン
' Author: Chief Architect
' ==============================================================================

Option Explicit

Public Enum ExportMode
    emSelectionSet ' 選択セットを使用
    emBoundingBox  ' 座標範囲を使用
End Enum

''' <summary>
''' 指定したオブジェクト範囲をDXFとして書き出す。
''' </summary>
''' <param name="targetPath">保存先のフルパス(拡張子は.dxfを推奨)</param>
''' <param name="mode">抽出モード</param>
''' <param name="optionalBounds">座標範囲指定時(Array(x1, y1, x2, y2))</param>
Public Sub ExportRangeToDXF(ByVal targetPath As String, _
                             ByVal mode As ExportMode, _
                             Optional ByVal optionalBounds As Variant)
    
    Dim acadApp As AcadApplication
    Dim acadDoc As AcadDocument
    Dim sset As AcadSelectionSet
    Dim ssetName As String
    Dim cmdString As String
    
    On Error GoTo ErrorHandler
    
    Set acadApp = ThisDrawing.Application
    Set acadDoc = ThisDrawing
    
    ' 1. 出力パスのバリデーション
    If Not ValidatePath(targetPath) Then
        Err.Raise vbObjectError + 513, "DXFExportEngine", "無効な保存先パスです。"
    End If

    ' 2. 既存の選択セットがあれば削除(クリーンな設計の基本)
    ssetName = "SS_EXPORT_TEMP"
    On Error Resume Next
    acadDoc.SelectionSets.Item(ssetName).Delete
    On Error GoTo ErrorHandler
    
    Set sset = acadDoc.SelectionSets.Add(ssetName)

    ' 3. 抽出対象の決定
    Select Case mode
        Case emSelectionSet
            ' ユーザーに選択させる(実務では事前に選択済みのものを渡す設計も検討せよ)
            sset.SelectOnScreen
            
        Case emBoundingBox
            If IsMissing(optionalBounds) Then
                Err.Raise vbObjectError + 514, "DXFExportEngine", "座標範囲が指定されていません。"
            End If
            ' 座標範囲によるフィルタリング
            ' optionalBounds は Array(MinX, MinY, MaxX, MaxY) を想定
            sset.SelectByPolygon optionalBounds 
    End Select

    ' 選択セットが空の場合は終了
    If sset.Count = 0 Then
        MsgBox "書き出し対象のオブジェクトが見つかりません。", vbExclamation
        GoTo CleanUp
    End If

    ' 4. -WBLOCK コマンドの実行
    ' コマンドライン経由で実行することで、メモリ効率と依存関係の整合性を確保する
    ' 構文: -WBLOCK [ファイル名] [挿入点] [オブジェクト選択] [Enter]
    ' 挿入点は 0,0,0 に固定し、オブジェクトの座標系を維持する
    
    ' 注意: コマンド文字列の組み立てには細心の注意を払う。
    ' ダブルクォーテーションでパスを囲むことで、スペースを含むパスに対応する。
    cmdString = "-WBLOCK " & Chr(34) & targetPath & Chr(34) & " 0,0,0 "
    
    ' 選択セットの内容をコマンドラインに流し込む代わりに、
    ' WBLOCKの特性を利用して、現在の選択セットを直接書き出すアプローチをとる。
    ' VBAのSendCommandは非同期的に動く性質があるため、
    ' 本来はWblockメソッドを使用するのが最もエレガントである。
    
    ' プロフェッショナルの選択: Wblockメソッド
    ' これにより、コマンドラインの文字列操作に伴うバグを回避する。
    acadDoc.Wblock sset, targetPath

    MsgBox "DXFの書き出しが完了しました:" & vbCrLf & targetPath, vbInformation

CleanUp:
    ' 5. リソースの解放
    If Not sset Is Nothing Then
        sset.Delete
        Set sset = Nothing
    End If
    Exit Sub

ErrorHandler:
    MsgBox "致命的なエラーが発生しました。" & vbCrLf & _
           "Error No: " & Err.Number & vbCrLf & _
           "Description: " & Err.Description, vbCritical
    Resume CleanUp
End Sub

''' <summary>
''' パスの妥当性を検証する
''' </summary>
Private Function ValidatePath(ByVal path As String) As Boolean
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' フォルダが存在するかチェック
    Dim parentDir As String
    parentDir = fso.GetParentFolderName(path)
    
    If Not fso.FolderExists(parentDir) Then
        ValidatePath = False
        Exit Function
    End If
    
    ' 拡張子が .dxf かチェック
    If LCase(fso.GetExtensionName(path)) <> "dxf" Then
        ValidatePath = False
        Exit Function
    End If
    
    ValidatePath = True
End Function

4. 実務における極限の注意点

このコードをプロダクション環境に投入する際、君が考慮すべき「重み」がいくつかある。

ファイルロックの競合

書き出し先のファイルが既に開かれている場合、`Wblock` メソッドは失敗する。
実務ツールでは、`FileSystemObject` を用いて `File.IsLocked` 的なチェックを行うか、`On Error` でファイルアクセスエラーを捕捉し、「ファイルが開かれているため保存できません」というユーザーに伝わるエラーメッセージを返す設計にせよ。

座標系の整合性(WCS vs UCS)

`Wblock` はデフォルトで WCS(世界座標系) を基準に動作する。もしユーザーが特定のUCS(ユーザー座標系)で作業している場合、切り出されたDXFの原点が意図しない位置に飛ぶ可能性がある。
「加工データとして切り出す」という目的であれば、必ず `WCS` での抽出を前提とした設計にし、ユーザーに対して「現在の座標系を確認してください」という警告を出すのがプロの配慮だ。

バージョン互換性の制御

AutoCADのバージョンによって、DXFのフォーマット(R12, R2000, R2018等)が異なる。
もし書き出し先のシステム(CAMソフトなど)が古い形式を要求する場合、`Wblock` だけでは制御しきれないことがある。その場合は、書き出し後に `SaveAs` を用いて、明示的に `acR12DXF` などの定数を用いてバージョン変換を行うレイヤーを追加すべきだ。

結論

「動けばいい」コードを書くのは誰でもできる。しかし、「壊れない、メンテナンスできる、意図通りに動く」コードを書くのが、エンジニアリングだ。

`Copy & Paste` という安易な道を選ばず、AutoCADの内部構造(データベースとコマンドの仕組み)を理解し、それを制御する。この一歩が、君を単なる「マクロ使い」から「業務自動化エンジニア」へと進化させる。

Stay Sharp.

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