DXFでポリラインを扱うとき、LWPOLYLINEだけを読めれば十分とは限りません。
古いDXFや、3Dポリライン、ポリゴンメッシュ、polyface meshを含むデータでは、POLYLINEエンティティが現れます。
このPOLYLINEは、LWPOLYLINEのように1エンティティ内部へ頂点座標をまとめて持つ構造ではありません。
基本的には、
POLYLINE
VERTEX
VERTEX
VERTEX
...
SEQEND
という複数エンティティからなるシーケンスとして保存されます。
AutodeskのDXF仕様でも、POLYLINE本体とVERTEXは別エンティティとして定義され、SEQENDがその頂点列の終端を示します。
DXFパーサーを作るなら、この構造を理解しておくことが重要です。
POLYLINEは頂点そのものを持たない
LWPOLYLINEではコード10・20が繰り返され、同じエンティティ内部に頂点が並びます。
一方、旧形式のPOLYLINEでは、POLYLINE本体は主として、
- 種類
- 閉じているか
- 2Dか3Dか
- デフォルト幅
- elevation
- mesh情報
などを保持します。
実際の頂点座標は、後続するVERTEXエンティティに格納されます。
つまり、
POLYLINE = ヘッダ
VERTEX = 頂点データ
SEQEND = 終端
と考えると理解しやすくなります。
POLYLINE本体の重要なグループコード
Autodesk公式仕様で、POLYLINEには次のようなコードがあります。
| コード | 意味 |
|---|---|
10,20,30 | ダミー点・elevation |
39 | thickness |
40 | デフォルト開始幅 |
41 | デフォルト終了幅 |
70 | POLYLINEフラグ |
71,72 | meshの頂点数 |
73,74 | smooth surface density |
75 | 曲面フィット方式 |
210,220,230 | extrusion direction |
特に重要なのがコード70です。
これはビットフラグとして使われます。
代表的な値は、
| 値 | 意味 |
|---|---|
| 1 | 閉じたポリライン |
| 2 | curve-fit vertexあり |
| 4 | spline-fit vertexあり |
| 8 | 3D polyline |
| 16 | 3D polygon mesh |
| 32 | meshをN方向にも閉じる |
| 64 | polyface mesh |
| 128 | linetypeを頂点間で連続生成 |
です。
単純な列挙値ではないため、
is_closed = bool(flags & 1)
is_3d = bool(flags & 8)
is_mesh = bool(flags & 16)
is_polyface = bool(flags & 64)
のように判定します。
コード66はどう扱うか
古いDXFを見るとPOLYLINEに、
66
1
が付いている場合があります。
コード66は、かつて後続エンティティが存在することを示すフラグとして使われていました。
しかしAutodeskの現行DXFリファレンスでは、POLYLINEのコード66はobsolete、存在しても無視してよいとされています。
つまり現代的なパーサーでは、
コード66があるから頂点列を読む
のではなく、
POLYLINEを開始したら、後続VERTEXをSEQENDまで読む
という構造として処理する方が明確です。
VERTEXから座標を読む
POLYLINEに続く各頂点はVERTEXエンティティです。
基本座標は、
10 → X
20 → Y
30 → Z
で表されます。
たとえば、
0
VERTEX
10
100.0
20
50.0
30
0.0
なら、
という頂点です。
複数のVERTEXを順番に収集することで、ポリライン形状を再構築できます。
2Dと3Dでは座標系にも注意する
Autodeskの仕様では、VERTEX座標は2Dの場合はOCS、3Dの場合はWCSとして扱われます。
そのため本格的なDXF処理では、
POLYLINE flags
↓
2D / 3D判定
↓
VERTEX取得
↓
必要ならOCS→WCS変換
という段階を設ける方が安全です。
単純なXY図面だけを対象にする初期実装なら、対応範囲を「2D・標準extrusionのみ」と明示して始める方法もあります。
VERTEXにもコード70がある
注意したいのは、POLYLINEだけでなくVERTEXにもコード70が存在することです。
意味は異なります。
VERTEXの主なフラグには、
- 1:curve-fittingで追加された頂点
- 8:spline-fittingで作られた頂点
- 16:spline frame control point
- 32:3D polyline vertex
- 64:3D polygon mesh vertex
- 128:polyface mesh vertex
などがあります。
したがって、
if group_code == 70:
だけで処理を決めることはできません。
必要なのは、
entity type
+
group code
の組み合わせです。
これはDXF全体に共通する重要な設計原則です。
VERTEXにもbulgeがある
2Dポリラインでは、VERTEXのコード42にbulgeを持つことがあります。
Autodesk仕様ではbulgeは、
で定義されます。
ここでは、その頂点から次の頂点へ向かう円弧の包含角です。
したがって、
なら直線、
なら半円に相当します。
負のbulgeは逆方向の円弧を表します。
これはLWPOLYLINEのbulgeと同じ考え方です。LWPOLYLINEでもコード42が各頂点に対応するbulgeとして定義されています。
つまり内部モデルでは、両形式を同じ構造へ変換できます。
SEQENDで頂点列が終わる
旧POLYLINEでは、VERTEXが何個続くかを単純な頂点数だけで読むのではなく、SEQENDまでを一つのシーケンスとして扱うのが基本です。
Autodesk仕様ではSEQENDは、POLYLINEのVERTEX列や、属性を持つINSERTのATTRIB列などの終端を示します。
したがってパーサーは概念的に、
vertices = []
while True:
entity = next_entity()
if entity.type == "VERTEX":
vertices.append(parse_vertex(entity))
elif entity.type == "SEQEND":
break
のような状態遷移を持つことになります。
LWPOLYLINEとの最大の違い
LWPOLYLINEは構造がより単純です。
Autodesk仕様では、
- コード90:頂点数
- コード10・20:各頂点座標
- コード40・41:開始・終了幅
- コード42:bulge
- コード70:closedなどのフラグ
が1つのLWPOLYLINEエンティティ内部に格納されます。
つまり、
LWPOLYLINE
├─ vertex
├─ vertex
└─ vertex
です。
旧形式は、
POLYLINE
↓
VERTEX
↓
VERTEX
↓
VERTEX
↓
SEQEND
です。
この違いはDXFパーサーの設計に直接影響します。
両方を同じ内部モデルへ変換する
アプリケーション側では、POLYLINEとLWPOLYLINEをいつまでも別形式として扱う必要はありません。
読み込み時だけ形式差を吸収し、
from dataclasses import dataclass
@dataclass
class PolylineVertex:
x: float
y: float
z: float = 0.0
bulge: float = 0.0
start_width: float = 0.0
end_width: float = 0.0
@dataclass
class PolylineData:
vertices: list[PolylineVertex]
closed: bool
is_3d: bool
のような中間モデルへ正規化できます。
すると、
POLYLINE + VERTEX + SEQEND
↓
PolylineData
↑
LWPOLYLINE
という構造にできます。
描画側は元のDXF形式を意識する必要がありません。
parserとgeometryを分ける
実装では、
DXF parser
↓
正規化
↓
geometry model
↓
renderer / validator / converter
に分けると再利用しやすくなります。
POLYLINE固有のSEQEND処理やコード70の判定はparser側で完結させます。
その後の、
- SVG変換
- Canvas描画
- 長さ計算
- 閉領域判定
- DXF比較
- JSON化
では、正規化された頂点列だけを使います。
3D POLYLINEも同じヘッダから始まる
コード70のビット8が立っている場合、POLYLINEは3D polylineです。
VERTEX側でもビット32が3D polyline vertexを示します。
したがって、
is_3d = bool(polyline_flags & 8)
を入口にして、
2D
→ OCSを考慮
3D
→ XYZをWCSとして保持
と処理を分けられます。
2D専用ビューアで3D POLYLINEを受け取った場合は、黙ってZを捨てるより、
unsupported: 3d_polyline
として明示する方がデータ品質を保てます。
POLYLINEはmeshにも使われる
旧POLYLINEが単なる折れ線だけではない点にも注意が必要です。
コード70には、
- 16:polygon mesh
- 64:polyface mesh
があります。
polyface meshでは、VERTEXが座標だけでなく面の定義にも使われます。
Autodesk仕様では、polyface meshの面を表すVERTEXでコード71〜74が頂点インデックスとして利用される場合があります。
したがって、
POLYLINEを見たら全部2D折れ線として読む
という実装は安全ではありません。
まずコード70でサブタイプを分類すべきです。
読み込みルールをデータ化する
POLYLINE系を将来の検証資産にするなら、次のようにルール化できます。
{
"entity": "POLYLINE",
"rules": {
"sequence_end": "SEQEND",
"vertex_entity": "VERTEX",
"flag_code": 70,
"closed_bit": 1,
"3d_polyline_bit": 8,
"polygon_mesh_bit": 16,
"polyface_mesh_bit": 64
}
}
さらにVERTEX側を、
{
"entity": "VERTEX",
"coordinate_codes": [10, 20, 30],
"bulge_code": 42,
"flag_code": 70
}
として分離できます。
このような構造なら、DXF仕様をPythonコードへ直書きせず、テーブル駆動型のパーサーやvalidatorへ発展させられます。
よくある失敗
旧POLYLINEを扱う際には、いくつか典型的な落とし穴があります。
POLYLINE本体に頂点座標が全部あると思うと、後続VERTEXを読み落とします。
SEQENDを無視すると、次の独立エンティティまでPOLYLINEの一部として誤認する可能性があります。
POLYLINEのコード70とVERTEXのコード70を同じ意味として扱うと、フラグ判定を誤ります。
また、POLYLINEを常に2D折れ線だと仮定すると、3D polyline、polygon mesh、polyface meshを正しく分類できません。
まとめ
旧形式のDXF POLYLINEで最も重要なのは、1エンティティだけを読んでも図形が完成しないという点です。
基本構造は、
POLYLINE
↓
VERTEX
↓
VERTEX
↓
...
↓
SEQEND
です。
POLYLINE本体で種類やフラグを読み、VERTEXから座標・幅・bulgeなどを取得し、SEQENDでシーケンスを終了します。
一方LWPOLYLINEでは、頂点情報が一つのエンティティ内部へまとめられています。
パーサーでは両形式を別々に読みながら、その後、
POLYLINE / LWPOLYLINE → 共通PolylineData
へ正規化する構造にすると、描画、計算、Web表示、JSON化、CAD変換へ再利用しやすくなります。
旧POLYLINEへの対応は単なる古い形式の互換処理ではありません。3Dポリラインやmesh系DXFを扱うための入口でもあり、DXFを汎用的な幾何データとして読むうえで重要な構造です。
参考情報
Autodesk公式DXF ReferenceのPOLYLINE仕様では、コード70の各ビット、mesh情報、elevation、extrusion directionなどが定義されています。
VERTEX仕様では、座標、幅、bulge、頂点フラグ、polyface mesh用インデックスが定義されています。
SEQENDはPOLYLINEのVERTEXシーケンスなどの終端として使用されます。
LWPOLYLINEとのデータ構造比較にはAutodesk公式LWPOLYLINE仕様を参照しました。

