whistle
example for AI modeling https://zenn.dev/polygoro/articles/010-ai-whistle?locale=en 大音量ホイッスル AIモデリングのサンプルです。 https://zenn.dev/polygoro/articles/010-ai-whistle
# 大音量ホイッスル — 円筒の共鳴室 + 接線方向に吹き込むウィンドウェイ + エッジ(ラビウム)
# 設計は X = 息の流れる向き(吹き口は -X 側)、Y = 共鳴室の軸、Z = 上(エッジのある側)で行い、
# 最後に X 軸まわりに 90° 起こして、ストラップ穴のある円筒の端面を Z = 0 の底面にする。
# ウィンドウェイ・窓・エッジの断面(設計の XZ 面)が各層の中に収まり、隙間 1.0mm を
# 層の厚みではなくノズルの精度で出せる向き。STL はそのままスライサーに置ける
@param 5..12 step:0.5 desc:"共鳴室の内半径 (mm)"
cham_r = 8.0
@param 6..20 desc:"共鳴室の内長さ = 軸方向 (mm)"
cham_l = 12
@param 1.6..3 step:0.1 desc:"肉厚 (mm)"
wall = 2.0
@param 4..12 desc:"ウィンドウェイの幅 (mm)"
ww = 8
@param 0.6..1.6 step:0.1 desc:"ウィンドウェイの高さ = 息の隙間 (mm)"
wh = 1.0
@param 1.5..4.5 step:0.1 desc:"窓の長さ = ウィンドウェイ出口からエッジ先端まで (mm)"
win = 2.8
@param 20..45 desc:"エッジ上面の傾斜 (度)"
bevel = 35
@param 15..35 desc:"吹き口の長さ (mm)"
mouth_l = 22
@param desc:"ストラップ穴を高さの中央に置く(印刷の向きで宙に浮くのでサポートが必要)"
ring_mid = true
floor_t = 0.6 # ウィンドウェイ出口での床の厚み(床端面の高さ)
body_l = cham_l + 2 * wall
# --- 窓の位置を2次方程式で解く --------------------------------------------
# 共鳴室の中心を原点に置き、ウィンドウェイ出口 x0 とエッジ先端 x1 をどちらも
# 共鳴室の内壁(円)の上に乗せる。条件は
# 円上の点 (x0, zl - a) … 床端面の下端(a = wh/2 + floor_t)
# 円上の点 (x1, zl) … エッジ先端 = 息の中心高さ zl
# x1 - x0 = win
# p = sqrt(R² - (zl-a)²), q = sqrt(R² - zl²) とおくと p - q = win, p + q = (2a·zl - a²)/win
a = wh / 2 + floor_t
k = 2 * a / win
m = -(a * a) / win - win
qa = k * k + 4
qb = 2 * k * m
qc = m * m - 4 * cham_r * cham_r
zl = (-qb + sqrt(qb * qb - 4 * qa * qc)) / (2 * qa) # 息の中心高さ = エッジ先端の高さ
x1 = -(k * zl + m) / 2 # エッジ先端
x0 = x1 - win # ウィンドウェイ出口
zf = zl - wh / 2 # ウィンドウェイの床
zr = zl + wh / 2 # ウィンドウェイの天井
mouth_bot = zf - 3 # 吹き口の下面
# 円柱の頂点と吹き口の上面を同じ高さにして、上面が円柱に接線で入るようにする。
# ウィンドウェイの天井の上に肉厚 wall を残すので、半径は共鳴室側と天井側の大きいほう
outer_r = max(cham_r + wall, zr + wall)
# 吹き口の下の角 P から円に引いた接線の接点 T(下側)。下面も円柱に接線で入る
px = x0 - mouth_l
pd = sqrt(px * px + mouth_bot * mouth_bot)
ta = atan2(mouth_bot, px) + acos(outer_r / pd)
tx = outer_r * cos(ta)
tz = outer_r * sin(ta)
# Y 方向の中央に揃えた XZ 断面の押し出し
def yslab($pts, $w) = workplane XZ | polyline $pts | extrude $w | translate 0 (-$w / 2) 0
def ycyl($r, $l) = cylinder $r $l | rotate 90 0 0
# --- 外形 -------------------------------------------------------------------
# 円と吹き口を1枚の横断面にまとめる:P → 接点 T → 円弧(下・右を回って頂点へ)→ 吹き口の上面
$shell = workplane XZ
| sketch [(px, mouth_bot), (tx, tz), arc (tx, tz) (outer_r, 0) (0, outer_r), (px, outer_r)]
| extrude body_l | translate 0 (-body_l / 2) 0
# ストラップ穴。既定は印刷の向きで底になる -Y 端面に揃え、ring_mid では Y の中央に置く
ring_y = if ring_mid then 0 else -body_l / 2 + 2
$ring = ycyl(4.5, 4) - ycyl(2.5, 6) | translate (outer_r + 3) ring_y 0
# --- 空洞 -------------------------------------------------------------------
$chamber = ycyl(cham_r, cham_l)
$windway = yslab([(x0 - mouth_l - 1, zf), (x0 + 0.5, zf), (x0 + 0.5, zr), (x0 - mouth_l - 1, zr)], ww)
# 窓 + エッジ上面の斜面:エッジ先端 (x1, zl) を通る傾き bevel の直線で切る
zt = outer_r + 3
zb = zl - win * tan(bevel) # 斜面を x0 まで延長した点(共鳴室の中)
$window = yslab([(x0, zb), (x1 + (zt - zl) / tan(bevel), zt), (x0, zt)], ww)
$whistle = union [$shell, $ring] | diff (union [$chamber, $windway, $window])
# 印刷の向き: X 軸まわりに 90° 起こすと設計の -Y 端面(ストラップ穴の面)が下に来る
$whistle | rotate 90 0 0 | floor