DXFのUNDERLAYを読む|PDF・DWF・DGN参照とクリッピング

「DXFのUNDERLAYを読む|PDF・DWF・DGN参照とクリッピング」の内容を表す技術イラスト

DXFでは、PDF図面、DWF、DGNを背景資料として配置できます。これらは線や円へ変換されるのではなく、外部ファイルを参照するアンダーレイとして保存されます。

アンダーレイの構造は、ラスター画像のIMAGEとIMAGEDEFに似ています。ただし、配置側はPDFUNDERLAY、DWFUNDERLAY、DGNUNDERLAY、定義側はPDFDEFINITIONなどの形式別オブジェクトです。

DXFファイル
├── ENTITIES:PDFUNDERLAYなどの配置情報
├── OBJECTS:PDFDEFINITIONなどの外部ファイル定義
└── 外部ファイル:PDF・DWF・DGN本体

DXFだけを受け渡しても、参照先ファイルがなければアンダーレイは表示できません。この記事では、配置と定義の参照関係、主要グループコード、座標変換、クリッピング、外部パスの安全な解決方法を整理します。

目次

UNDERLAYは外部図面の配置情報

AutodeskのDXF仕様では、アンダーレイの種類をグループコード0のオブジェクト名で区別します。

コード0の値参照する形式
PDFUNDERLAYPDF
DWFUNDERLAYDWF・DWFx
DGNUNDERLAYDGN

3種類の主要グループコードは共通です。

コード内容
340UNDERLAYDEFINITIONへの参照ハンドル
10・20・30挿入点
41・42・43X・Y・Z方向の尺度係数
50回転角度
210・220・230法線ベクトル
280表示・クリッピングなどのフラグ
281コントラスト
282フェード
11・21クリッピング境界の頂点

コード340が、配置情報と外部ファイル定義を結ぶ中心です。

DEFINITIONはパスと表示対象を持つ

定義オブジェクトはOBJECTSセクションに置かれます。形式に応じて、主に次の種類があります。

  • PDFDEFINITION
  • DWFDEFINITION
  • DGNDEFINITION

主要コードは次のとおりです。

コード内容
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の仕様では、次の範囲が定義されています。

項目コード範囲
コントラスト28120~100
フェード2820~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は、どちらも外部ファイル定義を参照しますが、配置の表現方法が異なります。

項目IMAGEUNDERLAY
主な外部形式PNG・JPEGなどPDF・DWF・DGN
定義オブジェクトIMAGEDEF各形式のDEFINITION
配置尺度1画素分のU・VベクトルX・Y・Z尺度係数
回転U・Vベクトルの方向コード50
参照コード340340
クリッピング画像座標の境界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レビュー資料の参照切れ検査、受け渡しパッケージの自動検証、外部参照一覧の生成へ発展させられます。

参考情報

参考になったらシェアしてください
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

機械設計・油圧・CAD・Python・AIなど、ものづくりに関わる技術を扱っています。工学知識を整理・構造化し、設計や自動化に再利用できる形へ変えていくことを目指しています。

目次