【実務・中級編】【実務中級者向け】図面を開く前に、図面内のオブジェクト数をカウントし、処理負荷を予測 – AutoCAD VBA解析バイブル

スポンサーリンク

【AutoCAD VBA超実践】開かずに喰らえ!数百万のオブジェクトを事前に予測し、バッチ処理の破綻を防ぐ技術

開発プロジェクトのリーダーである私たちが、夜間バッチ処理の朝に絶望する瞬間とはどんな時か。
それは、「たった1枚の化け物級の巨大図面」のせいでAutoCADがフリーズし、その後に控えていた数百枚の図面処理がすべてパアになった時だ。

AutoCAD VBAにおいて、`Documents.Open` で図面を開き、メモリ上にモデル空間を展開してからエンティティ数を数えるなどというアプローチは、実務の世界では「素人の自殺行為」と呼ぶ。
重い図面を安易に開けば、メモリリーク、不要なアノテーション尺度やフォントのロード、そして何より図面を開くオーバーヘッドそのものがCPUと時間をドブに捨てる結果になる。

今回は、図面ファイルを一切開くことなく(Invisible)、その内部に潜むオブジェクト数を高速かつ正確にカウントし、処理負荷を完全に予測・制御するプロダクションコードを授けよう。

—

1. なぜ「開かずに数える」必要があるのか?

AutoCADの図面(DWG)のオープン処理は、オブジェクトのデシリアライズ、グラフィックスキャッシュの生成、外部参照の解決など、膨大な処理を伴う。
これをプログラムから `Documents.Open` で行うと、どんなにスペックの高いマシンであっても数秒〜数十秒のコストを支払うことになる。

さらに、もしバッチ処理で500枚の図面を処理するとしよう。その中に1枚だけ「挿入基点が狂ったハッチングの塊(オブジェクト数50万)」が混ざっていたらどうなるか。運悪くその図面を開いた瞬間にAutoCADはメモリを食い潰し、COMコンポーネントごと沈黙する。

解決のアプローチ:ObjectDBX(TypeLib)の活用

AutoCADのUIを起動せず、バックグラウンドでDWGを操作するメカニズム ObjectDBX(AxDbDocument) を使えば、図面を画面に描画することなくダイレクトにデータベースへアクセスできる。
これを使えば、メモリ消費を最小限に抑え、通常のファイルオープンと比較して圧倒的な速度で内部構造を解析できるのだ。

—

2. 堅牢な設計:バッチ処理における負荷予測モデル

オブジェクト数をカウントしただけでは意味がない。それをどう「予測」に繋げるかだ。
実務では、以下のような閾値管理(スレッショルド制御)を設計に組み込むべきだ。

  • 軽負荷 (0 ~ 10,000オブジェクト): 通常処理。即座に実行。
  • 中負荷 (10,001 ~ 100,000オブジェクト): プログレスバーを表示し、ガベージコレクション(メモリ解放)を意識した処理を行う。
  • 重負荷 (100,001オブジェクト超): 処理スキップまたは専用の低速・堅牢モードへルーティングし、必要であれば担当者にアラートメールを飛ばす。

この事前フィルタリングを挟むだけで、夜間バッチの安定性は劇的に向上する。

—

3. 【コピペ即導入】オブジェクト事前カウント&負荷予測モジュール

以下のVBAコードは、指定したDWGファイルをObjectDBX経由でサイレントオープンし、モデル空間およびペーパー空間の全エンティティ数をミリ秒単位で計測・判定する実務用コードだ。

Excel VBA、あるいはAutoCAD内蔵VBAのどちらからでも実行できるように記述している(※早期バインディング、または適切な参照設定を前提とする)。

Option Explicit

‘ =================================================================================
‘ 模块名: ModDrawingLoadPredictor
‘ 概要: 図面を開かずにオブジェクト数をカウントし、処理負荷を予測・判定するクラス/モジュール
‘ =================================================================================

‘ 負荷レベルの定義
Public Enum LoadLevel
Level_Light = 1 ‘ 軽負荷:通常実行
Level_Moderate = 2 ‘ 中負荷:注意実行
Level_Heavy = 3 ‘ 重負荷:スキップ推奨・特別処理
Level_Error = -1 ‘ 異常終了・読み込み不可
End Enum

Public Sub AnalyzeDrawingLoad_Sample()
Dim targetFilePath As String
targetFilePath = “C:\AutoCAD_Data\Sample_HeavyDrawing.dwg”

Dim objCount As Long
Dim estimatedTimeSec As Double
Dim currentLoad As LoadLevel

‘ 負荷予測の実行
currentLoad = PredictDrawingLoad(targetFilePath, objCount, estimatedTimeSec)
基金
‘ 結果のイミディエイト出力(実務ではここに分岐処理を入れる)
Debug.Print “=== 負荷予測結果 ===”
Debug.Print “対象ファイル: ” & targetFilePath
Debug.Print “オブジェクト総数: ” & Format$(objCount, “#,

0″) & ” 意匠”

Debug.Print “予測処理時間: ” & Format$(estimatedTimeSec, “0.00”) & ” 秒”

Select Case currentLoad
Case LoadLevel.Level_Light
Debug.Print “判定: 軽負荷 – 即時処理を実行します。”
Case LoadLevel.Level_Moderate
Debug.Print “判定: 中負荷 – 通常処理ですがメモリ解放に注意してください。”
Case LoadLevel.Level_Heavy
Debug.Print “判定: 【警告】重負荷図面です!スキップまたは別スレッド処理を推奨します。”
Case LoadLevel.Level_Error
Debug.Print “判定: エラー – ファイルが破損しているか、アクセス権がありません。”
End Select
End Sub

‘ =================================================================================
‘ 引数のDWGを非表示で解析し、オブジェクト数と負荷を返すメイン関数
‘ =================================================================================
Public Function PredictDrawingLoad(ByVal filePath As String, ByRef outObjectCount As Long, ByRef outEstimatedTime As Double) As LoadLevel

outObjectCount = 0
outEstimatedTime = 0#

‘ ファイル存在チェック
If Dir(filePath) = “” Then
PredictDrawingLoad = LoadLevel.Level_Error
Exit Function
End If

Dim dbxDoc As Object
Dim startTime As Double
startTime = Timer

On Error GoTo ErrorHandler

‘ ObjectDBXのインスタンス生成
‘ AutoCADのバージョンに応じたProgIDを自動生成(AutoCAD 2017〜2024+対応)
Dim acadVersion As String
acadVersion = GetObject(, “AutoCAD.Application”).Preferences.Version
Dim majorVer As Integer
majorVer = CInt(Left(acadVersion, 2))

Dim progID As String
‘ バージョンに応じたDbxAxLibの動的生成(例: AutoCAD.DbxApplication.24 等)
‘ ※環境固定の場合は “ObjectDBX.AxDbDocument.XX” でも可
progID = “ObjectDBX.AxDbDocument.16” ‘ 汎用互換プログID (R16以降)

On Error Resume Next
Set dbxDoc = CreateObject(progID)
If dbxDoc Is Nothing Then
‘ フォールバック: 現在起動中のAutoCADからバージョンを特定してバインド
Set dbxDoc = GetObject(, “AutoCAD.Application”).GetInterfaceObject(“ObjectDBX.AxDbDocument”)
End If
On Error GoTo ErrorHandler

If dbxDoc Is Nothing Then
Err.Raise 9999, “PredictDrawingLoad”, “ObjectDBXのインスタンス化に失敗しました。”
End If

‘ 図面をバックグラウンドでオープン(排他制御を回避するためReadプロテクト)
dbxDoc.Open filePath

‘ カウントロジック
Dim totalCount As Long
totalCount = 0

‘ 1. モデル空間のオブジェクト数
totalCount = totalCount + dbxDoc.ModelSpace.Count

‘ 2. ペーパー空間(レイアウト)のオブジェクト数も合算する場合
Dim blockObj As Object
For Each blockObj In dbxDoc.Layouts
‘ 各レイアウトに対応するブロック定義からエンティティ数を取得
totalCount = totalCount + blockObj.Block.Count
Next blockObj

outObjectCount = totalCount

‘ 負荷時間予測のアルゴリズム(経験則に基づく係数: 10万オブジェクトあたり約1.5秒のロードコストを想定)
outEstimatedTime = (CDbl(totalCount) / 100000#) 1.5 + 0.5

‘ 負荷レベルの分類(閾値はプロジェクトの要件に応じて変更せよ)
If totalCount <= 10000 Then PredictDrawingLoad = LoadLevel.Level_Light ElseIf totalCount <= 100000 Then PredictDrawingLoad = LoadLevel.Level_Moderate Else PredictDrawingLoad = LoadLevel.Level_Heavy End If ' クリーンアップ Set dbxDoc = Nothing Exit Function ErrorHandler: ' 異常系ハンドリング(破損ファイル、パスワード保護など) Set dbxDoc = Nothing outObjectCount = -1 outEstimatedTime = 0# PredictDrawingLoad = LoadLevel.Level_Error End Function ---

4. プロフェッショナルとしての実装上の注意点

このコードを実務の生産ラインに組み込むにあたり、以下の「現場の罠」に注意してほしい。

① バージョン互換性の罠 (`ObjectDBX.AxDbDocument`)

コード内でも触れているが、ObjectDBXのProgIDはAutoCADのバージョン(R17, R18, R19…)によって厳密には紐づくバージョンサフィックスが存在する。
組織内で複数バージョンのAutoCADが混在している場合、`CreateObject(“ObjectDBX.AxDbDocument.16”)` のような固定値は特定のバージョンでクラッシュする原因になる。
可能であれば、現在起動しているAutoCADのセッション経由で `.GetInterfaceObject(“ObjectDBX.AxDbDocument”)` を叩くか、レジストリをポーリングして動的に解決するラッパーを用意するのがプロの仕事だ。

② メモリの断片化(Memory Fragmentation)

ObjectDBXは非常に優秀だが、何千回もループ内でインスタンスの生成・破棄を繰り返すと、VBAのランタイム側でメモリリークや断片化が起きることがある。
大量のバッチ処理を行う場合は、50ファイルごとに一度VBAのガベージコレクションを誘発させるか、処理プロセスを一度完全に切り離す(タスクの分割実行)設計を取り入れるべきだ。

—

5. まとめ

業務自動化において「なんとなく動くコード」を書く時代は終わった。
特にAutoCADを相手にする場合、マシンのリソースをどう管理し、どこでリスクをヘッジするかという「アーキテクチャの視点」がエンジニアの価値を決定付ける。

今回紹介した「開かずに数える」技術は、単なる時短テクニックではない。
「システムを絶対に止ませない」という堅牢な意思そのものなのだ。

あなたの手元のバッチ処理にも、この事前予測レイヤーを今すぐ組み込み、無駄なフリーズと夜間の残業から解放されてほしい。

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