DXFでは、PDF図面、DWF、DGNを背景資料として配置できます。これらは線や円へ変換されるのではなく、外部ファイルを参照するアンダーレイとして保存されます。
アンダーレイの構造は、ラスター画像のIMAGEとIMAGEDEFに似ています。ただし、配置側はPDFUNDERLAY、DWFUNDERLAY、DGNUNDERLAY、定義側はPDFDEFINITIONなどの形式別オブジェクトです。
DXFファイル
├── ENTITIES:PDFUNDERLAYなどの配置情報
├── OBJECTS:PDFDEFINITIONなどの外部ファイル定義
└── 外部ファイル:PDF・DWF・DGN本体
DXFだけを受け渡しても、参照先ファイルがなければアンダーレイは表示できません。この記事では、配置と定義の参照関係、主要グループコード、座標変換、クリッピング、外部パスの安全な解決方法を整理します。
UNDERLAYは外部図面の配置情報
AutodeskのDXF仕様では、アンダーレイの種類をグループコード0のオブジェクト名で区別します。
| コード0の値 | 参照する形式 |
|---|---|
| PDFUNDERLAY | |
| DWFUNDERLAY | DWF・DWFx |
| DGNUNDERLAY | DGN |
3種類の主要グループコードは共通です。
| コード | 内容 |
|---|---|
| 340 | UNDERLAYDEFINITIONへの参照ハンドル |
| 10・20・30 | 挿入点 |
| 41・42・43 | X・Y・Z方向の尺度係数 |
| 50 | 回転角度 |
| 210・220・230 | 法線ベクトル |
| 280 | 表示・クリッピングなどのフラグ |
| 281 | コントラスト |
| 282 | フェード |
| 11・21 | クリッピング境界の頂点 |
コード340が、配置情報と外部ファイル定義を結ぶ中心です。
DEFINITIONはパスと表示対象を持つ
定義オブジェクトはOBJECTSセクションに置かれます。形式に応じて、主に次の種類があります。
PDFDEFINITIONDWFDEFINITIONDGNDEFINITION
主要コードは次のとおりです。
| コード | 内容 |
|---|---|
| 5 | 定義オブジェクト自身のハンドル |
| 330 | 所有する辞書への参照 |
| 1 | 外部ファイルのパス |
| 2 | ページ、シートなどの表示対象名 |
PDFではコード2が表示ページを識別します。同じPDFでも、ページごとに別の定義オブジェクトを持つ場合があります。
PDFDEFINITION 4A
├── code 1:references/assembly.pdf
└── code 2:1
PDFUNDERLAY 4B
└── code 340 → 4A
一つの定義を複数のUNDERLAYから参照できます。外部ファイルとページが同じでも、各配置の挿入点、尺度、回転、表示状態、クリッピング境界は独立しています。
PDFUNDERLAYとPDFDEFINITIONのDXF例
次は、PDFの1ページ目をモデル空間へ配置する概念例です。
0
PDFUNDERLAY
5
4B
330
1F
100
AcDbEntity
8
UNDERLAY
100
AcDbUnderlayReference
340
4A
10
100.0
20
50.0
30
0.0
41
0.5
42
0.5
43
1.0
50
30.0
210
0.0
220
0.0
230
1.0
280
3
281
80
282
20
11
0.0
21
0.0
11
200.0
21
120.0
0
PDFDEFINITION
5
4A
330
40
100
AcDbUnderlayDefinition
1
references/assembly.pdf
2
1
この例では、PDFUNDERLAYのコード340が、ハンドル4AのPDFDEFINITIONを参照しています。
コード280の値は3です。ビット1の「クリッピング有効」とビット2の「アンダーレイ表示」が同時に有効になっています。
なお、実ファイルにはリアクタ参照や辞書構造などが追加される場合があります。独自パーサーでは、掲載順を固定フォーマットと考えず、サブクラスとグループコードを組み合わせて読み取ります。
挿入点・尺度・回転から配置を復元する
UNDERLAYは、挿入点、尺度、回転角、法線ベクトルによって配置されます。
法線ベクトルが$(0,0,1)$で、XY平面上だけを扱う単純な場合を考えます。アンダーレイ内の点を$(u,v)$、X・Y尺度を$s_x$、$s_y$、回転角を$\theta$、挿入点を$(x_0,y_0)$とすると、配置後の点は次式で求められます。\[ x=x_0+s_xu\cos\theta-s_yv\sin\theta \]\[ y=y_0+s_xu\sin\theta+s_yv\cos\theta \]
たとえば、挿入点が$(100,50)$、尺度が0.5、回転角が30°なら、アンダーレイ内の点$(200,0)$は、\[ x=100+0.5\times200\cos30^\circ\approx186.60 \]\[ y=50+0.5\times200\sin30^\circ=100.00 \]
へ配置されます。
法線ベクトルが$(0,0,1)$以外の場合、挿入点と回転角はOCSまたはECS上の値として解釈し、任意軸アルゴリズムなどでWCSへ変換します。XY平面用の式をそのまま3次元配置へ適用してはいけません。
コード280はビットフラグ
コード280は複数の状態をビット和で保持します。
| 値 | 状態 |
|---|---|
| 1 | クリッピングを有効化 |
| 2 | アンダーレイを表示 |
| 4 | モノクロ表示 |
| 8 | 背景色に合わせて調整 |
| 16 | 内側クリップモード |
たとえば値15は、1、2、4、8が有効です。
UNDERLAY_FLAGS = {
1: "clipping",
2: "visible",
4: "monochrome",
8: "adjust_for_background",
16: "inside_clip_mode",
}
def decode_underlay_flags(value: int) -> set[str]:
return {
name
for bit, name in UNDERLAY_FLAGS.items()
if value & bit
}
フラグを単一の列挙値として比較すると、複数状態を正しく判定できません。未知のビットが含まれる場合も、既知ビットを解析したうえで警告として残します。
コントラストとフェードを検査する
コード281はコントラスト、コード282はフェードです。Autodeskの仕様では、次の範囲が定義されています。
| 項目 | コード | 範囲 |
|---|---|---|
| コントラスト | 281 | 20~100 |
| フェード | 282 | 0~80 |
範囲外の値を発見しても、パーサーが無断で書き換えるべきではありません。元の値とエンティティのハンドルを診断情報へ残し、修復は別工程にします。
クリッピング境界を読む
アンダーレイは、外部ファイル全体ではなく一部だけを表示できます。クリッピング境界は、コード11と21の組が繰り返される形で保存されます。
- 2点:矩形の左下点と右上点
- 3点以上:多角形の頂点列
頂点の順序を保持する必要があるため、次のような単純な辞書化は不適切です。
tags_by_code[11] = value
同じコード11が現れるたびに上書きされ、最後のX座標しか残らないためです。Raw層では、順序付きタグ列として保持します。
clip_vertices = [
(0.0, 0.0),
(200.0, 0.0),
(200.0, 120.0),
(0.0, 120.0),
]
コード280のビット1が無効なら、境界データが存在しても表示へ適用されない場合があります。境界の有無とクリッピングの有効状態は分けて保存します。
外部ファイルのパスを安全に解決する
コード1のパスが相対パスなら、通常はDXFファイルが置かれたディレクトリを基準に解決します。
project/
├── drawing.dxf
└── references/
└── assembly.pdf
この構成なら、定義側にはreferences/assembly.pdfのような相対パスを保存できます。フォルダ全体を渡せば、別のPCでも同じ関係を保ちやすくなります。
ただし、外部から受け取ったパスを無条件に結合してはいけません。..による親フォルダへの移動や、許可していない絶対パスを検出し、探索範囲を制限します。
from pathlib import Path
def resolve_underlay_path(
dxf_path: Path,
stored_path: str,
allowed_root: Path,
) -> Path:
candidate = Path(stored_path)
if not candidate.is_absolute():
candidate = dxf_path.parent / candidate
resolved = candidate.resolve(strict=False)
root = allowed_root.resolve(strict=False)
if not resolved.is_relative_to(root):
raise ValueError("underlay path escapes allowed root")
return resolved
存在確認とパスの許可判定も分離します。参照先が見つからないだけでUNDERLAYやDEFINITIONを削除すると、後からファイルを復元したときに配置情報を再利用できなくなります。
Pythonで参照関係を検査する
配置と定義を構造化し、型、参照先、表示値を検査する例です。
from dataclasses import dataclass
UNDERLAY_TO_DEFINITION = {
"PDFUNDERLAY": "PDFDEFINITION",
"DWFUNDERLAY": "DWFDEFINITION",
"DGNUNDERLAY": "DGNDEFINITION",
}
@dataclass(frozen=True)
class UnderlayReference:
entity_type: str
handle: str
definition_handle: str
flags: int
contrast: int
fade: int
def validate_underlay(
ref: UnderlayReference,
objects_by_handle: dict[str, dict],
) -> list[str]:
errors: list[str] = []
expected_type = UNDERLAY_TO_DEFINITION.get(ref.entity_type)
if expected_type is None:
errors.append(f"unsupported underlay type: {ref.entity_type}")
return errors
definition = objects_by_handle.get(ref.definition_handle)
if definition is None:
errors.append("underlay definition is unresolved")
elif definition.get("type") != expected_type:
errors.append(
f"expected {expected_type}, "
f"got {definition.get('type')}"
)
if not 20 <= ref.contrast <= 100:
errors.append("contrast must be between 20 and 100")
if not 0 <= ref.fade <= 80:
errors.append("fade must be between 0 and 80")
known_mask = sum(UNDERLAY_FLAGS)
unknown_bits = ref.flags & ~known_mask
if unknown_bits:
errors.append(f"unknown flag bits: {unknown_bits}")
return errors
検査結果には、エンティティのハンドル、コード340の参照先、定義タイプ、保存パスも含めると、参照切れを追跡しやすくなります。
IMAGEとの違い
IMAGEとUNDERLAYは、どちらも外部ファイル定義を参照しますが、配置の表現方法が異なります。
| 項目 | IMAGE | UNDERLAY |
|---|---|---|
| 主な外部形式 | PNG・JPEGなど | PDF・DWF・DGN |
| 定義オブジェクト | IMAGEDEF | 各形式のDEFINITION |
| 配置尺度 | 1画素分のU・Vベクトル | X・Y・Z尺度係数 |
| 回転 | U・Vベクトルの方向 | コード50 |
| 参照コード | 340 | 340 |
| クリッピング | 画像座標の境界 | OCS・ECS上の2D境界 |
IMAGEの解析コードをそのまま流用し、コード11や12を1画素ベクトルとして読むと、UNDERLAYの尺度を誤ります。共通の「外部参照」層を持たせつつ、形式別の配置モデルへ分ける設計が安全です。
実装で起こりやすい失敗
UNDERLAYだけからファイルパスを探す。
パスはコード340の参照先であるDEFINITIONにあります。
PDFをDXFへ埋め込まれたデータとして扱う。
外部ファイル本体は別管理です。DXFだけでは表示を復元できません。
同じDEFINITIONを参照する配置を統合する。
挿入点、尺度、回転、クリッピングは配置ごとに異なります。
コード280を単一状態として読む。
ビットフラグなので、AND演算で個別に判定します。
クリッピング頂点を辞書へ上書きする。
コード11・21は繰り返されます。順序付き配列として保持します。
相対パスを現在の作業フォルダ基準で解決する。
DXFファイルの保存ディレクトリを基準にします。
XY平面用の回転式を任意の法線へ適用する。
コード210・220・230を確認し、必要ならOCSからWCSへ変換します。
まとめ
DXFのアンダーレイは、外部図面を参照する配置エンティティと定義オブジェクトで構成されます。
PDFUNDERLAY・DWFUNDERLAY・DGNUNDERLAY
↓ code 340
PDFDEFINITION・DWFDEFINITION・DGNDEFINITION
↓ code 1
外部ファイル
解析時の要点は次のとおりです。
- コード0でPDF・DWF・DGNを判定する
- コード340から対応するDEFINITIONを解決する
- コード1の外部パスとコード2の表示対象を取得する
- 挿入点、尺度、回転、法線から配置を復元する
- コード280をビットフラグとして読む
- コード11・21のクリッピング頂点を順序どおり保持する
- 外部パスをDXF基準かつ許可範囲内で解決する
この構造を扱えるようになると、図面へ添付されたPDF仕様書やDWFレビュー資料の参照切れ検査、受け渡しパッケージの自動検証、外部参照一覧の生成へ発展させられます。

