「DXFのUCSを読む|UCSテーブル・原点・X軸・Y軸と座標変換」の内容を表す技術イラスト
UNIT 03CAD・3Dプリント FIG.00 · EYECATCH

DXFのUCSを読む|UCSテーブル・原点・X軸・Y軸と座標変換

DXFのUCSテーブルを、原点・X軸・Y軸のグループコード、WCS・OCSとの違い、直交UCS、座標変換式、Pythonによる検証まで解説。保存作業面の復元や独自パーサー実装で起こりやすい誤りも整理します。

DOC NO.EKP-03-1024
DATE
REVB
READ約 11 分

DXFでは、線や円の座標が常に「画面で見えている向き」の数値として保存されるとは限りません。図面には世界座標系のWCSだけでなく、作業面を定義するUCS(User Coordinate System)も保存できます。

UCSを読み落とすと、名前付き作業座標系の原点や軸方向を復元できません。一方、UCSをすべてのエンティティ座標へ無条件に適用すると、すでにWCSやOCSで表現されている座標を二重変換する危険があります。

この記事では、AutodeskのDXF仕様を基準に、TABLESセクションのUCSテーブル、原点とX軸・Y軸、直交UCS情報、WCSとの座標変換、Pythonでの検証方法を整理します。

目次

UCSテーブルは名前付き作業座標系を保存する

DXFのTABLESセクションには、レイヤー、線種、文字スタイルなどと並んでUCSテーブルがあります。各UCSレコードは、CAD上で保存された名前付きユーザー座標系を表します。

UCSレコードの中心情報は次の3点です。

  • 原点をWCSで表した3次元点
  • UCSのX軸方向をWCSで表した3次元ベクトル
  • UCSのY軸方向をWCSで表した3次元ベクトル

つまり、UCSは「ローカル座標値の一覧」ではなく、ローカル座標系をWCS空間へ配置するための基準です。

UCSレコードの主要グループコード

AutodeskのDXF Referenceで定義される主要コードは次のとおりです。

グループコード内容
0レコード型UCS
2UCS名
70標準フラグ
10・20・30原点のX・Y・Z値(WCS)
11・21・31X軸方向のX・Y・Z成分(WCS)
12・22・32Y軸方向のX・Y・Z成分(WCS)
79常に0
146標高
346直交UCSの基準UCSハンドル
71直交方向の種類
13・23・33直交方向ごとの相対原点

コード10、11、12だけを読むのではなく、それぞれに続くY成分とZ成分を組み合わせて3次元値にします。

10 → 原点X    20 → 原点Y    30 → 原点Z
11 → X軸X     21 → X軸Y     31 → X軸Z
12 → Y軸X     22 → Y軸Y     32 → Y軸Z

コード70はUCS固有の幾何情報ではなく、外部参照への依存や参照済み状態などを示す標準フラグです。座標変換だけが目的でも、元の値を失わず保持しておくと再出力や診断に利用できます。

DXF上のUCS例を読む

次の例は、原点をWCSの(100, 200, 50)に置き、UCSのX軸をWCSの正Y方向、UCSのY軸をWCSの負X方向へ向けた名前付きUCSです。

0
UCS
5
2A
100
AcDbSymbolTableRecord
100
AcDbUCSTableRecord
2
MACHINE_TOP
70
0
10
100.0
20
200.0
30
50.0
11
0.0
21
1.0
31
0.0
12
-1.0
22
0.0
32
0.0
79
0
146
0.0

構造化すると次のようになります。

{
  "name": "MACHINE_TOP",
  "origin_wcs": [100.0, 200.0, 50.0],
  "x_axis_wcs": [0.0, 1.0, 0.0],
  "y_axis_wcs": [-1.0, 0.0, 0.0],
  "elevation": 0.0
}

ここで、コード11と12の値は点ではなく方向ベクトルです。原点の平行移動成分を加えず、向きとして扱います。

WCSとUCSを混同しない

WCSは図面全体の固定基準です。UCSはWCS内に配置された作業用の座標系です。さらに、多くのDXFエンティティはOCS(Object Coordinate System)を使って、自身の押し出し方向に基づく平面座標を保存します。

座標系主な役割基準
WCS図面全体の固定座標グローバル
UCS利用者が定義する作業座標WCS内の原点と軸
OCSエンティティ固有の平面座標押し出し方向など

UCSテーブルが存在しても、すべてのENTITIES座標がそのUCS値で保存されているとは限りません。各エンティティのDXF仕様を確認し、WCS、OCS、その他の座標表現のどれかを判定します。

UCSレコードは、保存された作業座標系の定義として独立して解析するのが安全です。

UCS座標からWCS座標へ変換する

UCS原点を $\mathbf{o}$、単位X軸を $\mathbf{e}_x$、単位Y軸を $\mathbf{e}_y$ とします。右手系のZ軸は外積から求めます。

$$ \mathbf{e}_z = \mathbf{e}_x \times \mathbf{e}_y $$

UCS座標が $(u,v,w)$ の点をWCSへ変換する式は次のとおりです。

$$ \mathbf{p}_{WCS} = \mathbf{o} + u\mathbf{e}_x + v\mathbf{e}_y + w\mathbf{e}_z $$

前の例で、UCS座標を(20, 10, 5)とすると、

$$ \mathbf{o}=(100,200,50) $$

$$ \mathbf{e}_x=(0,1,0),\quad \mathbf{e}_y=(-1,0,0),\quad \mathbf{e}_z=(0,0,1) $$

したがって、

$$ \mathbf{p}_{WCS}=(100,200,50)+20(0,1,0)+10(-1,0,0)+5(0,0,1) $$

変換結果はWCSの(90, 220, 55)です。

WCS座標からUCS座標へ戻す

3本の軸が単位長で互いに直交している場合、回転行列を次のように定義できます。

$$ R=\begin{bmatrix}\mathbf{e}_x & \mathbf{e}_y & \mathbf{e}_z\end{bmatrix} $$

直交行列では逆行列が転置行列に等しいため、WCS点からUCS座標への変換は次式になります。

$$ \begin{bmatrix}u\\v\\w\end{bmatrix}=R^T(\mathbf{p}_{WCS}-\mathbf{o}) $$

ただし、入力軸が正規化されていない、X軸とY軸が直交していない、または外積がゼロに近い場合、この前提は成立しません。変換前に軸を検証し、不正なデータを黙って補正しないことが重要です。

直交UCSの追加情報を扱う

UCSレコードでは、コード79は常に0と定義されています。直交方向に関する追加情報は、コード71とコード13・23・33の組で表されます。

コード71の値は次の方向を示します。

値直交方向
1Top
2Bottom
3Front
4Back
5Left
6Right

一つのUCSレコードに複数のコード71と原点の組が現れる可能性があります。単純な辞書へ上書きせず、出現順を保つ配列として読み取ります。

コード346は、直交UCSの基準となるUCSレコードのハンドルです。仕様上、該当する参照が省略され、直交状態が示されている場合はWORLDが基準とみなされます。ハンドル索引を使って参照を解決し、未解決なら診断情報を残します。

PythonでUCSを検証して変換する

次の例は、UCSの軸が単位長かつ直交していることを確認し、UCS座標をWCS座標へ変換します。外部ライブラリを使わず、計算境界が分かる形にしています。

from dataclasses import dataclass
from math import isclose, sqrt


Vector3 = tuple[float, float, float]


def dot(a: Vector3, b: Vector3) -> float:
    return sum(x * y for x, y in zip(a, b))


def cross(a: Vector3, b: Vector3) -> Vector3:
    return (
        a[1] * b[2] - a[2] * b[1],
        a[2] * b[0] - a[0] * b[2],
        a[0] * b[1] - a[1] * b[0],
    )


def norm(v: Vector3) -> float:
    return sqrt(dot(v, v))


@dataclass(frozen=True)
class UCS:
    name: str
    origin: Vector3
    x_axis: Vector3
    y_axis: Vector3

    def validated_axes(self, tol: float = 1e-9) -> tuple[Vector3, Vector3, Vector3]:
        if not isclose(norm(self.x_axis), 1.0, abs_tol=tol):
            raise ValueError("x_axis is not a unit vector")
        if not isclose(norm(self.y_axis), 1.0, abs_tol=tol):
            raise ValueError("y_axis is not a unit vector")
        if not isclose(dot(self.x_axis, self.y_axis), 0.0, abs_tol=tol):
            raise ValueError("x_axis and y_axis are not orthogonal")

        z_axis = cross(self.x_axis, self.y_axis)
        if not isclose(norm(z_axis), 1.0, abs_tol=tol):
            raise ValueError("UCS axes do not form a valid basis")

        return self.x_axis, self.y_axis, z_axis

    def to_wcs(self, point: Vector3) -> Vector3:
        x_axis, y_axis, z_axis = self.validated_axes()
        u, v, w = point
        return tuple(
            self.origin[i]
            + u * x_axis[i]
            + v * y_axis[i]
            + w * z_axis[i]
            for i in range(3)
        )


machine_top = UCS(
    name="MACHINE_TOP",
    origin=(100.0, 200.0, 50.0),
    x_axis=(0.0, 1.0, 0.0),
    y_axis=(-1.0, 0.0, 0.0),
)

print(machine_top.to_wcs((20.0, 10.0, 5.0)))

出力は次のとおりです。

(90.0, 220.0, 55.0)

実務では、許容差を図面の精度や生成元CADに合わせて決めます。わずかな丸め誤差を許容する処理と、明らかに不正な軸を拒否する処理を分けると診断しやすくなります。

パーサーで保持したいデータ

UCSを将来の変換処理やWebツールへ利用するなら、元タグと解釈済みデータを分けて保存します。

{
  "name": "MACHINE_TOP",
  "handle": "2A",
  "flags": 0,
  "origin_wcs": [100.0, 200.0, 50.0],
  "x_axis_wcs": [0.0, 1.0, 0.0],
  "y_axis_wcs": [-1.0, 0.0, 0.0],
  "elevation": 0.0,
  "base_ucs_handle": null,
  "orthographic_origins": [],
  "validation": {
    "unit_axes": true,
    "orthogonal": true,
    "right_handed": true
  }
}

Rawタグを残しておけば、未知のコードや同一コードの繰り返しを失わず、後から仕様解釈を更新できます。

実装で起こりやすい失敗

UCS原点だけを読み、軸方向を無視する。 平行移動しか復元できず、回転した作業座標系を正しく扱えません。

コード11と12を座標点として扱う。 これらはWCSで表した方向ベクトルです。原点を加える対象ではありません。

X軸とY軸からZ軸を作らない。 3次元変換では、右手系のZ軸を外積から構成する必要があります。

軸を検証せず転置行列を逆行列として使う。 軸が正規直交でなければ、転置による逆変換は成立しません。

UCSテーブルを現在の表示状態と決めつける。 UCSテーブルは名前付き定義です。現在のモデル空間・ペーパー空間UCSやビューに関連付くUCS情報は、HEADER変数やVIEWなど別の場所も確認します。

すべてのエンティティ座標へUCS変換を適用する。 エンティティごとの座標仕様を確認せず変換すると、OCSやWCSの値を二重に回転させる可能性があります。

コード71の繰り返しを上書きする。 直交方向ごとの原点は複数保持できるため、順序付きの組として保存します。

まとめ

DXFのUCSレコードは、名前付き作業座標系をWCS内へ配置するための定義です。中心となる情報は次の3つです。

  • コード10・20・30:原点
  • コード11・21・31:X軸方向
  • コード12・22・32:Y軸方向

Z軸はX軸とY軸の外積から構成し、UCS点からWCS点への変換は次式で表せます。

$$ \mathbf{p}_{WCS} = \mathbf{o} + u\mathbf{e}_x + v\mathbf{e}_y + w(\mathbf{e}_x \times \mathbf{e}_y) $$

解析では、原点と方向ベクトルを区別し、軸の長さ・直交性・右手系を検証します。また、UCS定義の存在だけを理由に、全エンティティへ同じ変換を適用してはいけません。

UCSテーブルを構造化できれば、保存作業面の再現、ローカル座標での寸法・位置計算、座標変換API、CADデータ検査ツールへ展開できます。

参考情報

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

この記事を書いた人

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

目次