備忘録 ピッチゲージと自動製図のコード
以前作成した エクセルとjww-cadを連動させるためのコードを改善。
① エクセルで加工諸元入力 砥石寸法(外径*厚み*穴)
② エクセルのマクロでpythonを呼び出し製図 ←new
③ ②で作成したデータをjww-cadへ送信、起動
④ 描画図形へ諸元を自動刻印、および図形の座標の取得から寸法を検算←new
⑤ dxfデータからレーザーでピッチゲージを作成
チェック用の歯型生成VBA(エクセル)
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("歯切り")
Dim moduleVal As Double, pressureAngle As Double
Dim toothHeight As Double, topWidth As Double
moduleVal = ws.Range("G18").Value
pressureAngle = ws.Range("G19").Value
toothHeight = ws.Range("I22").Value
topWidth = ws.Range("G29").Value
Dim pythonExe As String, scriptPath As String, cmd As String
pythonExe = "C:\Users\yamat\AppData\Local\Programs\Python\Python313\python.exe"
scriptPath = "C:\jww\hagirichan2.py"
cmd = """" & pythonExe & """ """ & scriptPath & """ " & _
moduleVal & " " & pressureAngle & " " & toothHeight & " " & topWidth
Shell cmd, vbNormalFocus
End Sub
チェック用の歯型生成スクリプト(jww-cad)
import sys
import math
import ezdxf
import os
def generate_teeth(module, top_width, height, pressure_angle, thickness, filename):
print(f"▶ 出力先: {filename}")
os.makedirs(os.path.dirname(filename), exist_ok=True)
pitch = module * math.pi
num_teeth = math.ceil(thickness / pitch)
bottom_width = top_width + 2 * height * math.tan(math.radians(pressure_angle))
doc = ezdxf.new(dxfversion="R2010")
msp = doc.modelspace()
if "STANDARD" not in doc.styles:
doc.styles.new("STANDARD", dxfattribs={"font": "simplex.shx"})
prev_bottom_right = None
leftmost_x = None
rightmost_x = None
# === 歯形描画 ===
for i in range(num_teeth):
offset_x = i * pitch
top_left = (offset_x + (bottom_width - top_width) / 2, height)
top_right = (offset_x + (bottom_width + top_width) / 2, height)
bottom_right = (offset_x + bottom_width, 0)
bottom_left = (offset_x, 0)
if leftmost_x is None:
leftmost_x = bottom_left[0]
rightmost_x = bottom_right[0]
msp.add_lwpolyline([top_left, top_right, bottom_right], close=False)
msp.add_lwpolyline([bottom_left, top_left], close=False)
if prev_bottom_right:
msp.add_line(prev_bottom_right, bottom_left)
prev_bottom_right = bottom_right
# === フレーム ===
frame_top_y = height * 3 if height * 3 > 25 else 25
point_a = (leftmost_x, 0)
point_b = (rightmost_x, 0)
point_a_top = (leftmost_x, frame_top_y)
point_b_top = (rightmost_x, frame_top_y)
msp.add_line(point_a, point_a_top)
msp.add_line(point_b, point_b_top)
msp.add_line(point_a_top, point_b_top)
# === テキスト ===
text_height = 5
base_x = leftmost_x + 5
base_y = frame_top_y - 5
# "°" は化けるので "deg" に変更
labels = [
f"M={module:g}",
f"PA={pressure_angle:g}",
f"H={height:g}"
]
spacing = 35
for i, label in enumerate(labels):
pos = (base_x + i * spacing, base_y)
msp.add_text(
label,
dxfattribs={
"height": text_height,
"style": "STANDARD",
"layer": "TEXT",
}
).set_dxf_attrib("insert", pos)
try:
doc.saveas(filename)
print(f"✅ DXFファイルを保存しました: {filename}")
except Exception as e:
print(f"❌ 保存失敗: {e}")
# --- メイン ---
if __name__ == "__main__":
if len(sys.argv) != 7:
print("使い方: python hagirichan.py <module> <top_width> <height> <pressure_angle> <thickness> <filename>")
else:
module = float(sys.argv[1])
top_width = float(sys.argv[2])
height = float(sys.argv[3])
pressure_angle = float(sys.argv[4])
thickness = float(sys.argv[5])
filename = sys.argv[6]
generate_teeth(module, top_width, height, pressure_angle, thickness, filename)
ピッチゲージ用VBA(エクセル)
Sub RunGearTransformation()
' --- Python実行ファイルとスクリプトのパスを指定 ---
Dim pythonExe As String
Dim scriptPath As String
pythonExe = "C:\Users\yamat\AppData\Local\Programs\Python\Python313\python.exe"
scriptPath = "C:\jww\hagirichan.py"
' --- 値の取得(シート「歯切り」) ---
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("歯切り")
Dim moduleVal As Double
Dim topWidth As Double
Dim height As Double
Dim pressureAngle As Double
Dim thickness As Double
Dim outputPath As String
moduleVal = ws.Range("G18").Value
topWidth = ws.Range("G29").Value
height = ws.Range("B7").Value
pressureAngle = ws.Range("G19").Value
thickness = ws.Range("D16").Value
' --- 出力ファイル名 ---
outputPath = "C:\jww\gear_output.dxf"
' --- 実行用コマンド作成 ---
Dim cmd As String
cmd = """" & pythonExe & """ """ & scriptPath & """ " & _
moduleVal & " " & topWidth & " " & height & " " & _
pressureAngle & " " & thickness & " """ & outputPath & """"
' --- バッチファイルを生成 ---
Dim batPath As String
batPath = Environ$("TEMP") & "\run_hagirichan.bat"
Open batPath For Output As #1
Print #1, "@echo off"
Print #1, cmd
' --- 実行後、Jw_cadで開く処理を追加 ---
Print #1, "if exist """ & outputPath & """ ("
Print #1, " start """" ""C:\jww\Jw_win.exe"" """ & outputPath & """"
Print #1, ")"
Close #1
' --- バッチファイルを実行 ---
Shell batPath, vbNormalFocus
End Sub
ピッチゲージ用スクリプト(jww-cad)
import sys
import math
import ezdxf
import os
import shutil
import time
# ======================================
# DXF 安全保存(temp → move)
# ======================================
def safe_save_dxf(doc, filename):
temp_path = filename + ".tmp"
try:
# 一時ファイルへ保存
doc.saveas(temp_path)
time.sleep(0.1)
# move をリトライ(最大20回)
for _ in range(20):
try:
if os.path.exists(filename):
os.remove(filename)
shutil.move(temp_path, filename)
return
except PermissionError:
time.sleep(0.1)
print("⚠ 上書きできず tmp のまま:", temp_path)
except Exception as e:
print(f"❌ 保存エラー: {e}")
# ======================================
# 歯形生成
# ======================================
def generate_teeth(module, top_width, height, pressure_angle, thickness, filename):
print(f"▶ 出力先: {filename}")
os.makedirs(os.path.dirname(filename), exist_ok=True)
pitch = module * math.pi
num_teeth = math.ceil(thickness / pitch)
# 歯元幅(谷底幅)
bottom_width = top_width + 2 * height * math.tan(math.radians(pressure_angle))
# DXF 初期化(R2010)
doc = ezdxf.new(dxfversion="R2010")
msp = doc.modelspace()
# フォント設定
if "STANDARD" not in doc.styles:
doc.styles.new("STANDARD", dxfattribs={"font": "simplex.shx"})
prev_bottom_right = None
leftmost_x = None
rightmost_x = None
# ------------------------------
# 歯形描画
# ------------------------------
for i in range(num_teeth):
offset_x = i * pitch
top_left = (offset_x + (bottom_width - top_width) / 2, height)
top_right = (offset_x + (bottom_width + top_width) / 2, height)
bottom_right = (offset_x + bottom_width, 0)
bottom_left = (offset_x, 0)
if leftmost_x is None:
leftmost_x = bottom_left[0]
rightmost_x = bottom_right[0]
msp.add_lwpolyline([top_left, top_right, bottom_right], close=False)
msp.add_lwpolyline([bottom_left, top_left], close=False)
if prev_bottom_right:
msp.add_line(prev_bottom_right, bottom_left)
prev_bottom_right = bottom_right
# ------------------------------
# フレーム(25~30範囲)
# ------------------------------
raw_top = height * 3
frame_top_y = 30 if raw_top >= 30 else 25 if raw_top <= 25 else raw_top
A = (leftmost_x, 0)
B = (rightmost_x, 0)
A2 = (leftmost_x, frame_top_y)
B2 = (rightmost_x, frame_top_y)
msp.add_line(A, A2)
msp.add_line(B, B2)
msp.add_line(A2, B2)
# ------------------------------
# テキスト
# ------------------------------
text_height = 5
base_x = leftmost_x + 5
base_y = frame_top_y - 5
labels = [
f"M={module:g}",
f"PA={pressure_angle:g}",
f"H={height:g}",
]
spacing = 35
for i, label in enumerate(labels):
pos = (base_x + i * spacing, base_y)
txt = msp.add_text(
label,
dxfattribs={
"height": text_height,
"style": "STANDARD"
}
)
txt.set_dxf_attrib("insert", pos)
# ------------------------------
# 保存(temp → move)
# ------------------------------
safe_save_dxf(doc, filename)
# =================================================
# UTF-8 → Shift-JIS に再エンコード(強制 flush)
# =================================================
try:
with open(filename, "r", encoding="utf-8") as f:
data = f.read()
with open(filename, "w", encoding="cp932", errors="ignore") as f:
f.write(data)
print("◎ DXF re-encoded to Shift-JIS(flush 完了)")
except Exception as e:
print("❌ Shift-JIS 再エンコード失敗:", e)
# ======================================
# エントリーポイント
# ======================================
if __name__ == "__main__":
if len(sys.argv) != 7:
print("Usage: python hagirichan.py <module> <top_width> <height> <pressure_angle> <thickness> <filename>")
sys.exit(1)
module = float(sys.argv[1])
top_width = float(sys.argv[2])
height = float(sys.argv[3])
pressure_angle = float(sys.argv[4])
thickness = float(sys.argv[5])
filename = sys.argv[6]
generate_teeth(module, top_width, height, pressure_angle, thickness, filename)
チェック用・ビッチゲージ用を一つのファイルにまとめる VBA(エクセル)
On Error GoTo ERR_HANDLER
Dim rackDXF As String, trapDXF As String, combinedDXF As String
Dim pythonExe As String, combineScript As String
Dim shellCmd As String
' --- 出力ファイル設定 ---
rackDXF = "C:\jww\gear_output.dxf"
trapDXF = "C:\jww\gear_output2.dxf"
combinedDXF = "C:\jww\gear_output3.dxf"
' --- Python本体と統合スクリプト ---
pythonExe = "C:\Users\yamat\AppData\Local\Programs\Python\Python313\python.exe"
combineScript = "C:\jww\hagirichan4.py"
' --- 1?? ラック & 台形図を生成 ---
Call RunGearTransformation
Call ボタン11_Click
' --- 2?? 出力確認 ---
If Dir(rackDXF) = "" Then
MsgBox "gear_output.dxf が見つかりません。(RunGearTransformation)", vbExclamation
Exit Sub
End If
If Dir(trapDXF) = "" Then
MsgBox "gear_output2.dxf が見つかりません。(ボタン11_Click)", vbExclamation
Exit Sub
End If
' --- 3?? 統合スクリプト実行 ---
shellCmd = """" & pythonExe & """ """ & combineScript & """"
Debug.Print "実行コマンド: " & shellCmd
Shell shellCmd, vbNormalFocus
' --- 4?? 統合完了待機 ---
Application.Wait (Now + TimeValue("0:00:03"))
' --- 5?? output3 が生成されたら Jw_cad で開く ---
If Dir(combinedDXF) <> "" Then
Shell "C:\jww\Jw_win.exe """ & combinedDXF & """", vbNormalFocus
Else
MsgBox "gear_output3.dxf が生成されませんでした。", vbExclamation
End If
Exit Sub
' --- エラー処理 ---
ERR_HANDLER:
MsgBox "エラーが発生しました: " & Err.Description, vbCritical
End Sub
チェック用・ビッチゲージ用を一つのファイルにまとめる スクリプト(jww-cad)
import ezdxf
import os
# ======================================================
# hagirichan4.py - DXF統合スクリプト(自動終了版)
# ======================================================
RACK_DXF = r"C:\jww\gear_output.dxf"
TRAP_DXF = r"C:\jww\gear_output2.dxf"
OUTPUT_DXF = r"C:\jww\gear_output3.dxf"
print("=== hagirichan4: DXF統合開始 ===")
try:
# --- 出力ファイルが存在すれば削除 ---
if os.path.exists(OUTPUT_DXF):
os.remove(OUTPUT_DXF)
# --- 1つ目を読み込み(ラック) ---
print(f"読込中: {RACK_DXF}")
base_doc = ezdxf.readfile(RACK_DXF)
base_msp = base_doc.modelspace()
# --- 2つ目を読み込み(台形) ---
print(f"追加読み込み: {TRAP_DXF}")
src_doc = ezdxf.readfile(TRAP_DXF)
src_msp = src_doc.modelspace()
# --- 追加図形をY方向に40mm上へ移動して統合 ---
for e in src_msp:
new_e = e.copy()
new_e.translate(0, 40, 0)
base_msp.add_entity(new_e)
# --- 保存 ---
base_doc.saveas(OUTPUT_DXF)
print("DXF統合完了:", OUTPUT_DXF)
except Exception as e:
print("統合処理中にエラー発生:", e)
# --- 自動終了(Enter待ちなし) ---
# input("処理終了。Enterキーを押してください...")
2025.11.10 ピッチゲージにモジュール等の値を自動で入るように修正
2025.11.10 DXFファイルが開いていると、上書きできない不具合を確認。
2025.11.12 上書きで対処(R2000へ変更もいまだラグあり) 別要因??
2025.11.13 原因を特定(UTF-8 → Shift-JIS の再保存が実質 flush だった為) python更新