DXFファイルの読み込み入門(第1回)

DXF (Drawing Exchange Format)ファイルは、Autodesk 社の AutoCAD の図面交換用の形式です。「図面交換用」の名前のとおり、サードパーティ製のソフトウェアを含め一般的に広く普及しています。3次元情報も保持することはできますが、3D CAD や 3D CG ソフトウェアで必要とされる UV マッピング情報が保持できないなど、あくまでも2次元図面の拡張として用いられることが多いと思われます。この連載では、siren スクリプトを用いて簡単な DXF パーサー(読み込み機能)を作成し、幾何演算を行う方法を説明します。

DXF 形式の基礎

さまざまな仕様とバージョン

一口に DXF といっても様々なバージョンがあります。DXF は今から20年以上も前から AutoCAD を中心に使われ続けてきました。その為、長い時間をかけて変わってきた仕様や DXF が誕生した当初は想定されていなかったデータを保持させる方法などを考えると、フルスペックの DXF はとても複雑です。


autocad-savedialog


AutoCAD 2016 のファイル保存ダイアログ

DXF は一般的に広く普及しているその他のファイル形式のように RFCIEEE などで標準化された形式ではないため、ファイル仕様そのものも AutoCAD のバージョンに依存しています。CAD 図面形式としてデファクトスタンダードになっているにも関わらず標準化されていないということは、「ある CAD システムではサポートされている機能でも、別の CAD システムではサポートされていない」といった現象が多々見受けられるわけです。そのシステムが「DXF をサポート」と銘打っていても、それぞれの機能と読み書きができる図形、属性値の互換性には注意が必要なのです。

ここでは、一つ一つのバージョンについては触れませんが、ほとんどの DXF をサポートするシステムで読み書き可能なバージョン R12 を対象に話を進めていきたいと思います。バージョン R12 は、AutoCAD 95 からサポートされており、最低限のエンティティ(図形)を扱える比較的単純な内容を含んでいます。

アスキー形式

DXF には、アスキー形式とバイナリ形式の2種類がありますが、前者が広く使われており、後者はサポートしているシステムもほとんどない為、本連載ではアスキー形式を対象としています。アスキー形式とは、言い替えるとテキスト形式です。単純にテキストファイルとして出力されたファイルを拡張子 .dxf のファイル名で保存したものが、私たちがよく目にする DXF の正体です。テキストファイルとして読み書きすることができるということは、極端な話、メモ帳などのテキストエディタでも作成したり、編集したりすることができるというわけです。


dxf-notepad


R12で出力したDXFをメモ帳で開いたところ

中身の構造

DXF が単なるアスキー(テキスト)形式と分かったところで、今度は中身について見ていきましょう。サンプルの DXF ファイルをこちらに準備しましたので、AutoCAD が手元にない方はこのファイルをテキストエディタで開いて中身を見てみてください。 DXF の冒頭部分は下記のようになっていると思います。(自分で R12 DXF として出力された方は下記と完全に同じようにならないかもしれませんが、基本構造は同じなので読み替えてください。)

DXF は2行を1ペアとして読むのが基本中の基本です。上の例では、1行目の 0 と2行目の SECTION という文字列が1つのペアとなります。同様に3行目の 2 と4行目の HEADER が1つのペアとなります。 1行目や3行目などの奇数行には、必ず整数値の番号が書かれています。これをグループコードと呼びます。グループコードは次行に定義された値が何を意味するのか、値の型は何なのかを示す番号です。

AutoCAD 2011 のものになりますが、公式のリファレンスのリンクを次に示します。

サンプル DXF の1行目に注目してください。1行目に記述されたグループコードは 0 です。リファレンスによると「図形タイプを表すテキスト文字列(固定)」という意味であることが分かります。その後に続く値 SECTION は厳密には図形を表す文字列ではないので、この意味として書かれている説明はあまり適切ではない気もしますが…、とりあえず今のところは「グループコード 0 は、『情報の区切り』」と覚えておいてください。図形やその他の要素の先頭・末尾を表わすためのコードです。つまり、この1~2行目では、「今から SECTION というものが始まるよ!」と宣言しているものと読み取ることができます。

次の3~4行目に注目してください。3行目はグループコード 2 です。2 はリファレンスに「名前(属性名称、ブロック名など)」と書かれています。4行目に HEADER という文字列が値として定義されていますので、1~2行目と合わせて「HEADERというSECTIONが始まるよ!」と読めます。まだ、ちょっと分かりづらいですね。でも心配しないで読み進めてください。


dxf-groupcode


グループコードと値は2行で1ペア

本節では、DXF は

  • 2行で1ペア
  • ペアの1行目の番号をグループコード、2行目を値という
  • グループコードは値の型と意味を示す

ということが分かりました。この考え方は何千行からなる DXF であろうと基本原則で、2行1ペアですので DXF は必ず偶数行あることになります。ペアとペアの間に空行が入ることもありません。このように行に対して厳密であるのは、行単位でシークしながら読み込むプログラムが簡単に書けるメリットがあります。例えば、200個めのペアの値を取得したい場合、200*2+1 で簡単にデータが記述されている行を算出でき、前後の情報や論理的な構造を検知しなくても、値を読み取ることができます。本連載で作成する siren スクリプトでは、わざわざシーケンシャルなアクセスをするメリットがありませんので、DXF の情報をより使い易い構造にして取り扱っていきます。

DXF の構造

次はもう少し引いた視点で、DXF ファイルの中身を見ていきましょう。DXF はグループコードと値のペアが最初から最後まで並んだ状態ですが、不規則に並んでいるわけではありません。ちゃんと意味を持った順番どおり並んでいます。 この順番が正しく並んでいなければ、AutoCAD をはじめとする CAD システムは DXF を正しく読み込むことができません。前節で「0, SECTION」というペアを見ましたが、これが DXF ファイルの中を大きく分割する要素となります。セクションという名前のとおり、区切りを意味しています。

次の図を見てください。


dxf-section


DXFは1つ以上のセクションの繰り返しと「EOF」で構成される


SECTION から ENDSEC までの間を一つのセクションと呼びます。DXF には最低1つのセクションと、ファイルの末尾に必ず EOF が必要です。 各セクションには、グループコード 2 で「そのセクションは何のセクションなのか」を示す文字列を格納しているデータが冒頭に登場します。上図で言えば、HEADERTABLES が該当します(セクションの内包要素であることを強調するため、字下げをしていますが、実際には字下げはありません)。

セクションには、次の種類があります。

  1. HEADER … ヘッダーセクション。図面全体の情報が格納される。
  2. TABLES … テーブルセクション。シンボルやレイヤー、線種、ビューといった情報が格納される。
  3. BLOCKS … ブロックセクション。図面内のブロックを定義した情報が格納される。
  4. ENTITIES … エンティティセクション。図形情報が格納される。

新しいバージョンの DXF では、これらの種類に加えて CLASSOBJECTS といったセクションも登場しますが基本的なものは上の4つであることに変わりありません。それぞれのセクションは DXF ファイル中に1回だけ登場するか、もしくは省略されます。エンティティセクションだけは例外で必ず登場します。セクションの登場順番は上のリストの順番で登場することが多いですが、厳密に仕様として決まっているかは定かではありません。セクションに関する詳しい説明はリファレンスにありますが、このリファレンスの対象は新しいバージョンのため、R12 ではサポートされていない記述もあることに注意してください。

DXF 中に含まれる線分やポリラインは、ブロックやシンボルとして定義されているものでなければ、エンティティセクションの中に含まれています。

次に、私がテキストエディタで作成した最低限の DXF ファイルの全文を示します。

エンティティセクションが一つだけあり、末尾には EOF があります。エンティティセクションの中には、線分を1つだけ定義しています。これを拡張子 .dxf で保存して AutoCAD などの CAD システムで開いてみてください。


dxf-by-notepad


メモ帳で作成したDXFを開いたところ


上図のように、斜めの線分が1つ表示されたと思います。このように、グループコードと値の概念とセクションの概念を正しく理解していれば、テキストエディタやスクリプトから生成することも可能というわけです。

本連載では DXF 中に含まれる線分やポリラインを読み込みたいので、まずは siren スクリプトを

  • DXF を読み込む
  • グループコードと値のペアのリストを作る
  • リストからエンティティセクションを抽出する
  • 各エンティティを抽出する
  • エンティティから siren の Shape オブジェクトを生成する

という手順で組み立てていきたいと思います。

第2回に続きます!

DXFファイルの読み込み入門(第1回)” への1件のフィードバック

コメントを残す