JW＿CADのDXF保存で点を円で出力するときの半径を0.4mmから任意の半径に変換する方法

# JW＿CADのDXF保存で点を円で出力するときの半径を0.4mmから任意の半径に変換する方法
JW_CADで描いたレザークラフト用の図面をDFX形式で出力すると、LightBurn等のレーザー彫刻用のソフトウエアで読み込んでレーザー彫刻機を使って直接革に図面を描いたりそのまま切り出したりできて便利ですが、JW_CADの点はデフォルト設定だとレーザーで焼いても目に見えないレベルの小さな点になってしまうので、その場合は`JW_CADのDFX設定`の`DXF書出し`オプションで`点を円で出力する`に設定する事で、点を半径0.4mmの円に変換してDFX出力してくれます。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191929/b7fb4de6-8cc5-da13-5455-f93dd2e4da51.png">

ただ、この円のサイズを半径0.4mm以外には変えることができないため、菱錐（菱ギリ）などで縫い穴をあけた時にレーザーの跡が残ってしまいます。これを半径0.2mmにするとほぼ目立たなくすることができるので、以下にその方法を記します。
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191929/25ea7afe-7bca-aa14-4532-a6ff44c11351.jpeg">
やり方は２つあります。どちらもPythonスクリプトで、`ezdxfライブラリを使って書き換える`方法と、`dxfファイルを直接書き換える`方法です。以下、それぞれについて解説します。

## ezdxfライブラリを使って書き換える方法
この方法が一番簡単ですが、保存したファイルのDXFフォーマットが変わってしまうので、LightBurn等のアプリでは問題なく読むことができますが、JW_CADはDXF R12までしか対応していないので読み込めなくなります。
~~~python:ezdxfライブラリを使って書き換えるサンプルコード
import ezdxf

#目的のファイルをフルパスで指定します。
filename = r'your_file_name.dxf'

doc = ezdxf.readfile(filename)
msp = doc.modelspace()

for e in msp:
    if e.dxftype() == "CIRCLE":
        if e.dxf.radius == 0.4:
            e.dxf.radius = 0.2

#元のファイル名に_ezdxfをpostfixを追加して保存します。
outfile = filename.replace('.dxf', '_ezdxf.dxf')
doc.saveas(outfile)
~~~
ezdxfを使えるようにするには`ezdxf`ライブラリをコマンドラインでインストールする必要があります。以下はpipを使ったインストール例です。
~~~
C:\>pip install ezdxf
Collecting ezdxf
  Downloading ezdxf-1.0.2-cp39-cp39-win_amd64.whl (1.5 MB)
     |████████████████████████████████| 1.5 MB 1.7 MB/s
Requirement already satisfied: typing-extensions in c:\users\luthiertn\miniconda3\lib\site-packages (from ezdxf) (3.10.0.2)
Requirement already satisfied: pyparsing>=2.0.1 in c:\users\luthiertn\miniconda3\lib\site-packages (from ezdxf) (2.4.7)
Installing collected packages: ezdxf
Successfully installed ezdxf-1.0.2
~~~

もちろんJupyterでもこんな感じで使えます。コマンドラインでpython使うのが得意じゃない人もJupyterなら敷居が低いですよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3191929/d0a0c75d-2c24-41e4-cca2-111736793375.png)

## dxfファイルを直接書き換える方法
あまりスマートな方法ではありませんが、DXFテキストファイルを先頭から読み込んで半径0.4mmの円の箇所だけを書き換える方法がこちら。メリットとしてはJW_CADで再読み込みすることが可能な事と、他のライブラリを一切必要としない事です。デメリットは、未確認ですがJW_CADが出力するDXF R12フォーマット以外のフォーマットのDXFは処理できない可能性が高いです。まあそもそも目的がJW_CADの出力ファイルの修正なので問題はなさそうですが（笑）。
~~~python:dxfファイルを直接書き換えるサンプルコード
#目的のファイルをフルパスで指定します。
filename = r'your_file_name.dxf'

circle_cnt = 0
circle_found = False

with open(filename, 'r') as f:
    text = ''
    line = f.readline()
    while line:
        line = line.rstrip()
        if line == 'CIRCLE':
            circle_found = True
        elif circle_found:
            circle_cnt += 1
            if circle_cnt == 10:
                if line == '0.4':
                    line = '0.2'
                circle_cnt = 0
                circle_found = False
        text += line + '\n'
        line = f.readline()

#元のファイル名に_ezdxfをpostfixを追加して保存します。
outfile = filename.replace('.dxf', '_point0.2.dxf')
with open(outfile, 'w') as f:
    f.write(text)
~~~

## 補足事項
ezdxfのr12writerを使って各entityを個別に出力することでDXF R12形式で高速にDXF出力することもできるようです。
https://ezdxf.readthedocs.io/en/stable/addons/r12writer.html#reference

ただし、以下のようにadd_xxx関数を使ってそれぞれのentityを個別に出力する必要があるため、既存のDFXのコンバートを行うためにはひと手間をかける必要があります。（以下のコードは上記のezdxfのリファレンスから抜粋引用）
~~~python:
from random import random
from ezdxf.addons import r12writer

with r12writer("quick_and_dirty_dxf_r12.dxf") as dxf:
    dxf.add_line((0, 0), (17, 23))
    dxf.add_circle((0, 0), radius=2)
    dxf.add_arc((0, 0), radius=3, start=0, end=175)
    dxf.add_solid([(0, 0), (1, 0), (0, 1), (1, 1)])
    dxf.add_point((1.5, 1.5))

    # 2d polyline, new in v0.12
    dxf.add_polyline_2d([(5, 5), (7, 3), (7, 6)])

    # 2d polyline with bulge value, new in v0.12
    dxf.add_polyline_2d([(5, 5), (7, 3, 0.5), (7, 6)], format='xyb')

    # 3d polyline only, changed in v0.12
    dxf.add_polyline([(4, 3, 2), (8, 5, 0), (2, 4, 9)])

    dxf.add_text("test the text entity", align="MIDDLE_CENTER")
~~~
自分で作った2DモデリングアプリやCADアプリをJW_CADで読み込めるDXF R12形式で保存したい場合などには使えそうです。

## 元ネタ
この記事の元ネタのTwitterスレです。ezdxfはくろねこさん（＠kuronekonet)から情報頂きました。ありがとうございます！ 
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">需要あるか知らんけど、 <a href="https://twitter.com/hashtag/JW_CAD?src=hash&amp;ref_src=twsrc%5Etfw">#JW_CAD</a> でDXF形式で出力する時に点だと見えないから”点を円で出力する”オプションを選ぶと直径0.4mmの固定サイズの円で出力されるんだけどこれだと菱目打ちよりデカくてレーザー跡が丸見えなので直径0.2mmに一括変換するPythonスクリプトを書きました。欲しい方はどうぞ～ <a href="https://t.co/QP2uKqiy3e">pic.twitter.com/QP2uKqiy3e</a></p>&mdash; LuthierTN (@LuthierTN) <a href="https://twitter.com/LuthierTN/status/1627758691574513664?ref_src=twsrc%5Etfw">February 20, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>