dxfファイルの中身をいじる：ソリッドの境界線を抽出する

#概要
eagleでDXF形式のソルダーパターンを作成したはいいが、カッティングマシンで動作するには、dxf形式内のソリッドをラインに変換する必要があった。
一方そのころ、jw_cadは塗りつぶしを解除するとすべて消える仕様に苦戦を強いられていた。どうするAutoCad！？

次回、jw_cad死す

----
つまり、SOLIDをLineに変換する方法を記述します（本当は中身自体をいじらず、ソフト側で処理したいのですが、方法が見つからなかったので）。
ついでに、dxfについて、いくつか説明をば・・・

#dxfデータ

https://qiita.com/r-tezuka/items/3bf01caa3b418906b06c

まず、こちらを読めば、dxfのファイル構造がなんとなくつかめます。
グループコード＋値　のセットで並んでいて、
SECTION～ENDSECTIONで情報がグループ分けされているわけです。

グループコードについては

http://docs.autodesk.com/ACD/2011/JPN/filesDXF/WS1a9193826455f5ff18cb41610ec0a2e719-7a3d.htm

http://docs.autodesk.com/ACD/2011/JPN/filesDXF/WS1a9193826455f5ff18cb41610ec0a2e719-7a62.htm

が参考になります。

http://afsoft.jp/cad/p06.html

も参考になりました。

#まず、読み込んでみる

```Python
"""
dxf データ読み込み

＋
データをに行列分割：グループコードと要素で、配列化

"""

f = open('C:/Users/board5.dxf','r')

dxf_list = []

n = 0

for line in f:
    if n%2 == 0:   #グループコード
        #print(line)
        hoge = [int(line.rstrip('\n'))]
    else:
        hoge.append(line.rstrip('\n'))
        dxf_list.append(hoge)
    n = n + 1
    
f.close()


"""
セクションごとに分割する
"""

section_list = []

for i in dxf_list:
    if i[1] == 'SECTION':
        hoge = []
        #hoge.append(i)
    elif i[1] == 'ENDSEC':
        section_list.append(hoge)
    else:
        hoge.append(i)
```
こんな感じで、正しくファイルの場所を指定すれすれば、読み込めます。
変数section_listの方に、セクションごとに分割されています

```
section_list[0]:Header :バージョン情報・画面サイズ等
section_list[1]:Tables :線種自体の設定情報
section_list[2]:Blocks :ブロック図形の情報（ブロック図形がない場合、中身はない）
section_list[3]:Entitie:図形情報(座標値・レイヤー・線種指定）
```
ブロック図形に関しては、jw_cadのBL解コマンドで、Entity情報に変換することが可能です。

今、私のやりたいSOLIDをLINEに変換する場合、ENTITIE情報の編集を行えばよいということになります。

#Line エンティティ構造

```
[0, 'LINE'],
 [8, '_0-0_'],
 [6, 'CONTINUOUS'],
 [62, '    7'],
 [10, '414.30858895705524'],
 [20, '443.53006134969326'],
 [11, '414.30858895705524'],
 [21, '252.6282208588957'],
```
が、読み込んだデータです。
意味が分からないと思いますが、非常に簡単です。

```
[0, 'LINE'],　　 　　  :線であることを示す
 [8, '_0-0_'],    　　:レイヤ番号
 [6, 'CONTINUOUS'],   :線種
 [62, '    7'],　　　　:線色
```
を意味しています。左のグループコードに関しては前述のリンクから調べられます。

```
 [10, '414.30858895705524'],
 [20, '443.53006134969326'],
 [11, '414.30858895705524'],
 [21, '252.6282208588957'],
```
の意味は、
グループコード10は 1がx座標であることを示し、0が点0を示します
グループコード20は 2がy座標であることを示し、0が点0を示します

グループコード11は 1がx座標であることを示し、1が点1を示します
グループコード21は 2がy座標であることを示し、1が点1を示します

線では、二点示せば線が引けるので、以上で線が引けることになります。

非常に単純ですね。

#SOLIDを探し出して、LINEに変換して、保存する
プログラムは以下のようになります。
以上で変換ができるようになりました。

```Python
input_file = 'C:/Users/Desktop/board7.dxf'
save_file = 'C:/Users/Desktop/py_test7_kai.dxf'


f = open(input_file,'r')

dxf_list = []

n = 0

for line in f:
    if n%2 == 0:   #グループコード
        #print(line)
        hoge = [int(line.rstrip('\n'))]
    else:
        hoge.append(line.rstrip('\n'))
        dxf_list.append(hoge)
    n = n + 1
    
f.close()


"""
セクションごとに分割する
"""

section_list = []

for i in dxf_list:
    if i[1] == 'SECTION':
        hoge = []
        hoge.append(i)
        
    elif i[1] == 'ENDSEC':
        hoge.append(i)
        section_list.append(hoge)
    else:
        hoge.append(i)
    
    
"""
セクション内で、’SOLID'を見つけたら、下の10~23のデータをもとに線を4本生成する
Lineのフォーマットは解析済み。
以上を繰り返すプログラムを作成

SOLIDをすべて潰したら、SECTIONをまとめて、dxfで保存する
"""


#section_line[3]にあると決め打ちする。
found_flag = 0
section_list_edit=[]          

for i in section_list[3]:
    
    if i[1] == 'SOLID':
        found_flag = 1
        
    elif found_flag == 1 and i[0] == 8:
        layer = i[1]                       #レイヤ情報
    
    elif found_flag == 1 and i[0] == 6:
        line_def = i[1]                    #線種
    
    elif found_flag == 1 and i[0] == 62:
        color = i[1]                       #色 
    
    elif found_flag == 1 and i[0] == 10:
        x0 = float(i[1])
    elif found_flag == 1 and i[0] == 20:
        y0 = float(i[1])
    
    
    elif found_flag == 1 and i[0] == 11:
        x1 = float(i[1])
    elif found_flag == 1 and i[0] == 21:
        y1 = float(i[1])
        
    elif found_flag == 1 and i[0] == 12:
        x2 = float(i[1])
    elif found_flag == 1 and i[0] == 22:
        y2 = float(i[1])
        
    elif found_flag == 1 and i[0] == 13:
        x3 = float(i[1])
    elif found_flag == 1 and i[0] == 23:
        y3 = float(i[1])
        
        """
        ここで、SOLIDが完了として、Line情報として保存していく
        """
        hoge = []
        hoge.append(['0','LINE'])
        hoge.append(['8',layer])
        hoge.append(['6',line_def])
        hoge.append(['62',color])
        
        #0-1
        section_list_edit.extend(hoge)

        section_list_edit.append(['10',x0])
        section_list_edit.append(['20',y0])
        section_list_edit.append(['11',x1])
        section_list_edit.append(['21',y1])
        
            
        #1-3
        section_list_edit.extend(hoge)

        section_list_edit.append(['10',x1])
        section_list_edit.append(['20',y1])
        section_list_edit.append(['11',x3])
        section_list_edit.append(['21',y3])
        
        #2-3
        section_list_edit.extend(hoge)

        section_list_edit.append(['10',x2])
        section_list_edit.append(['20',y2])
        section_list_edit.append(['11',x3])
        section_list_edit.append(['21',y3])
        
        #0-2
        section_list_edit.extend(hoge)

        section_list_edit.append(['10',x0])
        section_list_edit.append(['20',y0])
        section_list_edit.append(['11',x2])
        section_list_edit.append(['21',y2])
        
    else:
        #削除するとインデックスが不明瞭になるので、別の配列に保存するかどうかで変更する
        found_flag = 0                 # SOLIDブロックを抜けたという判定
        section_list_edit.append(i)
        
    #print(i)
    
    
#まとめる
section_list_final = []
section_list_final.append(section_list[0])
section_list_final.append(section_list[1])
section_list_final.append(section_list[2])
section_list_final.append(section_list_edit)


#dxfファイルとして保存する。
file = open(save_file ,'w')

for i in section_list_final:
    for j in i:                 # j = [group, code] 
        print(j)
        
        file.write(str(j[0]))
        file.write("\n")
        
        file.write(str(j[1]))
        file.write("\n")
        
file.close()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/3e231440-cbdf-3e7a-cf2a-7852006780e3.png)

このデータを

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/7523c982-ed4d-fab4-6c33-47debe87c22a.png)

のように、境界のみを取り出すことができるようになりました。