こんにちは!AutoCADの自動化の世界へようこそ。
日々、図面の大規模な整理や、何枚もの図面からデータをかき集める作業に頭を悩ませていませんか?
「図面Aにある特定のブロックや図形を、プログラムで別の図面Bにごっそりコピーしたい」
そんなとき、素朴に考えつくのは 「画面上でコピー(Ctrl+C)して、別の図面を開いてペースト(Ctrl+V)する」 というマクロの記録的なアプローチですよね。
ですが、プロの現場でそれやってしまうと、「OSのクリップボードの競合でフリーズする」「画面がパカパカ切り替わって遅い」「予期せぬエラーで止まる」 という悪夢の三拍子が揃ってしまいます。特に何千枚もの図面を相手にするバッチ処理では致命傷です。
今回は、OSのクリップボードを一切介さず、AutoCADのメモリ(Database)上で一瞬にして図形をワープさせる極限のテクニック──`AcadDocument.Database.CopyObjects` を使った「図面間高速オブジェクトコピー」の真髄を伝授します。
ここをクリアすれば、あなたのVBAスキルは「お絵かきマクロ」から「本物のエンジニアリング自動化」へと一段階上に飛躍しますよ。さあ、一緒に扉を開けましょう!
—
1. なぜ「クリップボード経由」は悪手なのか?
まずは敵を知ることから始めましょう。
VBAから `SendKeys` や `CopyClipboard` などのメソッドを使って図形をコピーしようとすると、以下の問題が必ず発生します。
1. 目に見える(画面描画のオーバーヘッド): 図面が開閉したり、画面がアクティブになったりするたびに数秒のロスが発生します。
2. OS依存の不安定さ: クリップボードはWindows全体の共有資源です。他のアプリケーション(Excelなど)の操作とタイミングが被ると、平気でコピーに失敗します。
3. メモリリークの温床: 画面を介したコピー&ペーストは、AutoCAD内部のCOMオブジェクトの参照管理を非常に不安定にします。
救世主:`Database.CopyObjects` とは?
AutoCADの裏側では、すべての図面データは `Database`(データベース) という巨大なメモリ上のツリー構造として管理されています。
`Database.CopyObjects` メソッドは、「コピー元のデータベースにある図形オブジェクトの配列を、コピー先のデータベースの特定の場所(通常はModelSpaceなどのブロックテーブルレコード)に、メモリ上で直接クローン(複製)しなさい」 という、AutoCAD内部のエンジンに直接命令を下す超高速なルートです。
画面を表示する必要すらありません。バックグラウンドで一瞬にして数千の図形が転送されます。
—
2. 全体像のイメージ:図解的アプローチ
コードを書く前に、メモリ上で何が起きているのかを頭に思い浮かべられるようにしましょう。
[ 元図面 (Source Drawing) ]
└─ Database
└─ ModelSpace (ここにコピーしたい図形がある)
├─ [Line A] ───┐
├─ [Circle B] ─┼─ (これらをまとめて包み込む:Variant配列化)
└─ [Block C] ──┘
│
▼ 【 Database.CopyObjects 】の魔法!
│ (OSのクリップボードをバイパス・メモリ上で直結)
▼
[ 先端図面 (Destination Drawing) ]
└─ Database
└─ ModelSpace (ここに流し込む)
├─ [Line A (複製)]
├─ [Circle B (複製)]
└─ [Block C (複製)]
シンプルですね。要するに、「コピーしたいオブジェクトを集めて配列に入れ、行先(オーナー)を指定して `CopyObjects` を呼ぶだけ」 です。
—
3. 実装コード:図面間高速オブジェクトコピー
それでは、開発の現場でそのままコピペして使える実用的なプロシージャを公開します。
このコードは、現在アクティブな図面(または指定した開いている図面)から、別の図面のモデル空間へ特定の図形たちを一瞬で転送します。
Sub CopyObjectsBetweenDrawings_Pro()
On Error GoTo ErrorHandler
‘ — 1. 事前準備とオブジェクトの参照取得 —
Dim sourceDoc As AcadDocument
Dim destDoc As AcadDocument
‘ ここでは例として、現在アクティブな図面をコピー元、
‘ アプリケーション内で開いている2番目の図面をコピー先とします。
‘ ※実運用では Documents コレクションから名前で取得するなどしてください。
Set sourceDoc = ThisDrawing
If Documents.Count < 2 Then
MsgBox "コピー先の図面がもう1つ開いている必要があります。", vbExclamation, "前提エラー"
Exit Sub
End If
' 例として、開いているドキュメントの2番目をコピー先にする
Dim i As Long
For i = 0 To Documents.Count - 1
If Documents(i).Name <> sourceDoc.Name Then
Set destDoc = Documents(i)
Exit For
End If
Next i
If destDoc Is Nothing Then
MsgBox “有効なコピー先図面が見つかりません。”, vbCritical
Exit Sub
End If
‘ — 2. コピー元から対象となるオブジェクトをピックアップ —
‘ 今回は「モデル空間にあるすべての図形」をコピー対象の配列にします。
‘ (実務では、特定の画層やSelectionSetで絞り込んだ図形を指定します)
Dim sourceEnts() As AcadEntity
Dim entCount As Long
entCount = sourceDoc.ModelSpace.Count
If entCount = 0 Then
MsgBox “コピー元に図形が存在しません。”, vbInformation
Exit Sub
End If
‘ AcadEntityの動的配列にオブジェクトを格納
ReDim sourceEnts(0 To entCount – 1)
Dim j As Long
For j = 0 To entCount – 1
Set sourceEnts(j) = sourceDoc.ModelSpace.Item(j)
Next j
‘ — 3. Variant型配列への変換(CopyObjectsの必須仕様) —
‘ AutoCADのDatabase.CopyObjectsメソッドは、引数に「オブジェクトの入ったVariant配列」を要求します。
Dim varSourceObjects As Variant
varSourceObjects = sourceEnts
‘ — 4. コピー先の宛先(ブロックテーブルレコード:通常はModelSpace)を取得 —
Dim destOwner As AcadBlock
Set destOwner = destDoc.ModelSpace
‘ — 5. 【核心】Database.CopyObjects によるメモリ上での超高速転送 —
Dim varCopiedObjects As Variant
‘ CopyObjects (ObjectsArray, Owner, [Mapping])
‘ コピー元データベースからコピー先データベースへ、メモリ上で直接オブジェクトが複製されます。
sourceDoc.Database.CopyObjects varSourceObjects, destOwner.Object, varCopiedObjects
‘ — 6. 完了通知 —
destDoc.Regen acAllViewports
MsgBox “図面のコピーが完了しました!” & vbCrLf & _
“転送元: ” & sourceDoc.Name & vbCrLf & _
“転送先: ” & destDoc.Name, vbInformation, “高速コピー成功”
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“エラー内容: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
—
4. コードの深掘りとプロの技(ここに注目!)
上記のコードで、特に重要なポイントをエンジニアの視点で解説します。
① Variant配列へのキャスト(型変換)の罠
`CopyObjects` メソッドは非常に低レベルなAPI(ARXラッパー)に近いため、引数に渡すオブジェクト群は「必ず `Variant` 型の配列」である必要があります。
VBAでは、`AcadEntity` 型の固定・動的配列をそのまま `Variant` 型の変数に代入(暗黙の型変換)することで、この要件を満たすことができます。ここが抜けると「型が一致しません(Error 13)」で即座に弾かれます。
② オーナー(Owner)の指定方法
`destOwner.Object` という記述に注目してください。
VBAの `AcadBlock` オブジェクトから、内部のCOMラッパーである `IAcadBlockTableRecord`(あるいはそれに相当するオブジェクトポインタ)を安全に渡すために `.Object` プロパティを介しています。ここを間違えると、コピー先を指定できずに図形が迷子になります。
③ 参照整合性(画層やブロック定義はどうなるの?)
プロが最も気になるのが、「コピーする図形が、特定の画層(Layer)やブロック定義(Block Definition)に依存している場合どうなるのか?」という点です。
安心してください。`Database.CopyObjects` は優秀で、依存している画層やLinetype(線種)なども自動的にコピー先のデータベースへ同時に持ち込もうとします。
ただし、もしコピー先に同名の画層やブロックがすでに存在する場合の挙動(上書きするのか、スキップするのかなど)を厳密にコントロールしたい場合は、第3引数の `Mapping`(IDPair配列)を操作する高度な実装が必要になります。まずは今回の基本形で9割のユースケースをカバーできます。
—
まとめ:自動化のステージを上げよう
今回は、`AcadDocument.Database.CopyObjects` を用いた、図面間高速オブジェクトコピーの極意を解説しました。
- クリップボードは使うな: 画面のチラつきやOS依存のエラーを防ぐため、メモリ上で完結させる。
- Databaseの力を借りる: AutoCADの根幹であるデータベース間で直接クローンを作ることで、圧倒的なパフォーマンスを手に入れる。
- Variant配列の準備: メソッドの仕様に合わせた確実な型アプローチを行う。
この手法をマスターすれば、何十枚もの図面から必要なパーツだけを抽出し、バックグラウンドで一瞬にして統合図面を作り上げるような、プロフェッショナルなバッチ処理システムが構築できるようになります。
「ここをクリアすれば、AutoCAD VBAの基本はバッチリですよ!」
ぜひあなたの業務自動化ツールに組み込んで、その圧倒的なスピードを体感してください。それでは、次のレベルでお会いしましょう!
