備忘録 ピッチゲージと自動製図のコード

 

以前作成した エクセルと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更新



人気の投稿