PythonSCAD
PythonSCADコミュニティ・開発者に感謝申し上げます。ありがとうございます。
参考サイト
OpenSCADコミュニティ、CadQueryコミュニティ、build123dコミュニティ、開発者、記事執筆者に感謝申し上げます。ありがとうございます。
- build123dのExamples
- CadQueryのExamples
- 高校生のためのPythonSCAD練習帳
01. 寸法100×60×30mmの直方体(ボックス)
完成コード(PythonSCAD)
# ==========================================
# 直方体ボックス(100×60×30mm)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
size_x = 100.0 # 幅(X方向)
size_y = 60.0 # 奥行き(Y方向)
size_z = 30.0 # 高さ(Z方向)
# --- メイン処理 ---
# 原点中心に配置(X/Y/Zすべて中心基準)
result = cube([size_x, size_y, size_z], center=True)
show(result)
02. 直径80mm、高さ50mmの円柱
完成コード(PythonSCAD)
# ==========================================
# 円柱(直径80mm・高さ50mm)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
dia = 80.0 # 直径
height = 50.0 # 高さ(Z方向)
fn_val = 80 # 分割数(円の滑らかさ)
def r_from_dia(d):
"""直径→半径 変換"""
return d / 2.0
# --- メイン処理 ---
result = cylinder(h=height, r=r_from_dia(dia), center=True, fn=fn_val)
show(result)
03. 直径60mmの球
完成コード(PythonSCAD)
# ==========================================
# 直径60mmの球
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
sphere_d = 60.0 # 直径
sphere_r = sphere_d / 2.0
fn_val = 80 # 滑らかさ(分割数)
# --- メイン処理 ---
result = sphere(r=sphere_r, fn=fn_val)
show(result)
04. 底面直径100mm、上面直径0mm(先端)、高さ80mmの円すい
完成コード(PythonSCAD)
# ==========================================
# 円錐(底面φ100、先端、H=80)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
base_d = 100.0 # 底面直径
top_d = 0.0 # 上面直径(先端なので0)
height = 80.0 # 高さ(Z方向)
fn_val = 120 # 円の滑らかさ(分割数)
# --- ヘルパー ---
def r_from_dia(d):
return d / 2.0
# --- メイン処理 ---
cone = cylinder(
h=height,
r1=r_from_dia(base_d),
r2=r_from_dia(top_d),
center=False, # 底面をZ=0に置いて、上に伸ばす
fn=fn_val
)
show(cone)
05. 寸法120×80×40mmのボックス。全エッジにR5フィレット
完成コード(PythonSCAD)
# ==========================================
# R5フィレット付きボックス(外形 120×80×40)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
width = 120.0 # X方向
depth = 80.0 # Y方向
height = 40.0 # Z方向
fillet_r = 5.0 # 全エッジのR
fn_val = 80 # 球の分割数(見た目の滑らかさ)
# --- 関数(モジュール)定義 ---
def filleted_box(w, d, h, r, fn):
"""
外形 w×d×h の直方体に、全エッジR=rのフィレットを付けた形状
minkowski(小さくした直方体, 球) で作る
"""
core = cube([w - 2*r, d - 2*r, h - 2*r], center=True)
ball = sphere(r=r, fn=fn)
return minkowski(core, ball)
# --- メイン処理 ---
result = filleted_box(width, depth, height, fillet_r, fn_val)
show(result)
※この方法(minkowski)は「全エッジに均一なR」を付けるのに強い一方、計算が重くなりやすいので、動作が重いときは fn_val を少し下げて調整してください。
06. 寸法100×60×30mmのボックス。全エッジにC3チャンファー
# ==========================================
# 100×60×30mm ボックス(全エッジ C3 チャンファー)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
width = 100.0 # X方向
depth = 60.0 # Y方向
height = 30.0 # Z方向
c = 3.0 # C面取りサイズ(C3)
eps = 0.1 # 念のための微小値
# --- 関数定義 ---
def octahedron(a):
"""原点中心の正八面体(頂点が±X, ±Y, ±Z にある)"""
pts = [
[ a, 0, 0], # 0
[0, a, 0], # 1
[-a, 0, 0], # 2
[0, -a, 0], # 3
[0, 0, a], # 4 (top)
[0, 0, -a], # 5 (bottom)
]
faces = [
[4, 0, 1],
[4, 1, 2],
[4, 2, 3],
[4, 3, 0],
[5, 1, 0],
[5, 2, 1],
[5, 3, 2],
[5, 0, 3],
]
return polyhedron(points=pts, faces=faces)
def chamfered_box(w, d, h, chamfer):
"""
全エッジC面取りの直方体
仕組み:
小さくした直方体 + 正八面体 を minkowski して、角をC面にする
"""
if w <= 2 * chamfer or d <= 2 * chamfer or h <= 2 * chamfer:
raise ValueError("C面取りが大きすぎます。各寸法は 2*C より大きくしてください。")
core = cube([w - 2 * chamfer, d - 2 * chamfer, h - 2 * chamfer], center=True)
tool = octahedron(chamfer)
return minkowski(core, tool)
# --- メイン処理 ---
result = chamfered_box(width, depth, height, c)
show(result)
07. 底面100×100mm、高さ50mmのブロック。側面の縦エッジ(Z方向の4本)は R8。上面の外周エッジも R8。底面の外周エッジは 丸めない。
完成コード(PythonSCAD)
# ==========================================
# 片側(底面だけ)シャープなR付きブロック
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
size_x = 100.0 # 底面サイズX
size_y = 100.0 # 底面サイズY
height = 50.0 # 高さZ
r_edge = 8.0 # 指定R(縦エッジ&上面外周エッジ)
fn_val = 96 # 円・球の分割数
eps = 0.05 # ちらつき防止&わずかに重ねる用
# --- 関数定義 ---
def rounded_square_2d(w, d, r, fn):
"""
XY平面の角丸四角形(縦エッジRの元になる輪郭)
※ square は fn を持てないので minkowski + circle で角丸を作る
"""
core = square([w - 2 * r, d - 2 * r], center=True)
return minkowski(core, circle(r=r, fn=fn))
def full_rounded_block_all_edges(w, d, h, r, fn):
"""
いったん「全部の外周エッジがR」のブロックを作る(Minkowski)
→ 後で底面側だけ“埋め戻して”シャープにする
"""
core = cube([w - 2 * r, d - 2 * r, h - 2 * r], center=True)
return minkowski(core, sphere(r=r, fn=fn))
def bottom_sharp_filler(w, d, r, fn, eps):
"""
底面外周エッジを丸めないための“埋め戻し材”
高さ r だけ、縦壁をストンと立てて底エッジをシャープに戻す。
"""
prof = rounded_square_2d(w, d, r, fn)
# 底~高さ(r)までを埋める(ほんの少し上まで eps で重ねる)
return linear_extrude(prof, height=r + eps, center=False)
# --- メイン処理 ---
# 1) 全エッジRのブロック(中心基準)を作って、底がZ=0になるように持ち上げ
rounded_all = full_rounded_block_all_edges(size_x, size_y, height, r_edge, fn_val)
rounded_all = translate(rounded_all, [0, 0, height / 2])
# 2) 底面だけシャープに戻す“埋め戻し”
filler = bottom_sharp_filler(size_x, size_y, r_edge, fn_val, eps)
# 3) 足す形状は + で結合(底面外周エッジだけ丸めない仕様にする)
result = rounded_all + filler
show(result)
形状の解釈(重要)
- 「縦エッジR8」=平面(XY)で角がR8になっている(四隅が丸い)
- 「底面の外周エッジは丸めない」=底面(Z=0)と側面の境界をZ方向にR付けしない(底の立ち上がりはシャープ)
という意味で作っています。
08. 直径70mm、高さ60mmの円柱。上下両端の円形エッジにR4フィレット
完成コード(PythonSCAD)
# ==========================================
# 円柱(上下エッジR4フィレット)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
from math import pi, sin, cos
# --- パラメータ設定 (単位: mm) ---
dia = 70.0 # 円柱 直径
height = 60.0 # 円柱 高さ
fillet_r = 4.0 # 上下端の円形エッジ フィレット半径
fn_val = 120 # 回転体の分割数(円周方向)
arc_seg = 24 # フィレット(1/4円)の分割数
eps = 0.1 # 予備(今回は未使用)
radius = dia / 2.0
# --- 関数(モジュール)定義 ---
def arc_points(cx, cy, r, deg0, deg1, n):
"""2Dの円弧点列を生成(polygon用:点は [x, y] のリスト)"""
pts = []
for i in range(n + 1):
t = i / n
deg = deg0 + (deg1 - deg0) * t
a = deg * pi / 180.0
pts.append([cx + r * cos(a), cy + r * sin(a)])
return pts
def create_profile_2d(R, H, r, seg):
"""
回転体用2D断面(XY平面)を作る。
rotate_extrudeによりZ軸回転 → 3D化される(y が高さ方向になる)。
"""
if r <= 0:
return polygon([[0, 0], [R, 0], [R, H], [0, H]])
if r * 2 > H or r > R:
raise ValueError("fillet_r が大きすぎます(高さや半径に対して不適切)")
# 下側フィレット(外側コーナー: [R,0] を丸める)
# 中心: [R-r, r]、角度: -90° -> 0°
bottom_arc = arc_points(R - r, r, r, -90.0, 0.0, seg)
# 上側フィレット(外側コーナー: [R,H] を丸める)
# 中心: [R-r, H-r]、角度: 0° -> 90°
top_arc = arc_points(R - r, H - r, r, 0.0, 90.0, seg)
pts = []
pts += [[0.0, 0.0]] # 軸上の底
pts += [[R - r, 0.0]] # 底面の外周(フィレット開始点)
pts += bottom_arc[1:] # [R, r] へ
pts += [[R, H - r]] # 側面を上へ
pts += top_arc[1:] # [R-r, H] へ
pts += [[0.0, H]] # 軸上の上面
return polygon(pts)
# --- メイン処理 ---
profile_2d = create_profile_2d(radius, height, fillet_r, arc_seg)
result = rotate_extrude(profile_2d, fn=fn_val)
show(result)
補足(設計の考え方)
-
minkowskiで丸めると「端面が完全な平面」にならず、カプセル形状に近づきやすいので、今回は 断面を作ってrotate_extrudeで「上下の面はフラットのまま、外周エッジだけR」を確実に作っています。
09. 外径80mm・内径60mm・長さ150mmのパイプ
完成コード(PythonSCAD)
# ==========================================
# パイプ(外径80・内径60・長さ150)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_d = 80.0
inner_d = 60.0
length_z = 150.0
fn_val = 80 # 円の滑らかさ
eps = 0.1 # チラつき防止(カッター用マージン)
# --- 関数(モジュール)定義 ---
def r_from_dia(d):
"""直径から半径へ変換"""
return d / 2.0
def create_body(od, h, fn):
"""本体(足す形状):外径の円柱"""
return cylinder(h=h, r=r_from_dia(od), center=True, fn=fn)
def create_cutter(id_, h, fn, eps_val):
"""カッター(引く形状):内径の円柱(貫通&マージン付き)"""
return cylinder(h=h + 2 * eps_val, r=r_from_dia(id_), center=True, fn=fn)
# --- メイン処理 ---
body = create_body(outer_d, length_z, fn_val)
cutter = create_cutter(inner_d, length_z, fn_val, eps)
result = body - cutter
show(result)
10. 寸法100×100×30mmのボックス。中央に直径40mmの貫通穴
完成コード(PythonSCAD)
# ==========================================
# 100x100x30 Box with Ø40 Through Hole
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
box_x = 100.0 # X方向サイズ
box_y = 100.0 # Y方向サイズ
box_z = 30.0 # Z方向サイズ(高さ)
hole_d = 40.0 # 穴の直径
fn_val = 80 # 円柱の分割数(滑らかさ)
eps = 0.1 # チラつき防止用微小値
# --- 関数(モジュール)定義 ---
def create_body(x, y, z):
"""本体(足す形状)"""
return cube([x, y, z], center=True)
def create_cutter(z, hole_d, fn):
"""カッター(引く形状):Z方向の貫通穴"""
hole_r = hole_d / 2.0
return cylinder(h=z + 2 * eps, r=hole_r, center=True, fn=fn)
# --- メイン処理 ---
body = create_body(box_x, box_y, box_z)
cutter = create_cutter(box_z, hole_d, fn_val)
result = body - cutter
show(result)
11. 寸法120×80×25mmのプレート。四隅に直径10mmの取付穴(穴中心は端から15mm)
完成コード(PythonSCAD)
# ==========================================
# 取付穴つきプレート(120×80×25)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
plate_w = 120.0 # X方向
plate_l = 80.0 # Y方向
plate_h = 25.0 # Z方向
hole_d = 10.0
hole_r = hole_d / 2.0
edge_off = 15.0 # 穴中心の端からの距離
fn_val = 60
eps = 0.1 # チラつき防止(カッターを少し長くする)
# --- 関数(モジュール)定義 ---
def create_body(w, l, h):
"""本体プレート(足す形状)"""
return cube([w, l, h], center=True)
def create_cutter(w, l, h, r, off, fn):
"""四隅の貫通穴カッター(引く形状)を1つにまとめる"""
x = (w / 2.0) - off
y = (l / 2.0) - off
hole = cylinder(h=h + 2.0 * eps, r=r, center=True, fn=fn)
holes = (
translate(hole, [ x, y, 0.0]) +
translate(hole, [ x, -y, 0.0]) +
translate(hole, [-x, y, 0.0]) +
translate(hole, [-x, -y, 0.0])
)
return holes
# --- メイン処理 ---
body = create_body(plate_w, plate_l, plate_h)
cutter = create_cutter(plate_w, plate_l, plate_h, hole_r, edge_off, fn_val)
result = body - cutter
show(result)
補足:プレートは center=True なので中心が原点 [0,0,0]、穴の中心座標は ±(幅/2-15), ±(奥行/2-15) に自動的に配置されています。
12. 直径100mm・高さ40mmの円柱。中央に直径50mm・深さ30mmの凹み(非貫通穴)
完成コード(PythonSCAD)
# ==========================================
# 円柱 + 中央の凹み(非貫通穴)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
base_d = 100.0 # 外径
base_h = 40.0 # 高さ
pocket_d = 50.0 # 凹み径
pocket_h = 30.0 # 凹み深さ(上面から下へ)
fn_val = 100 # 円の滑らかさ
eps = 0.1 # チラつき防止用微小値
# --- 関数(モジュール)定義 ---
def create_body(d, h, fn):
"""本体(足す形状):Z=0を底面にして上へ伸びる円柱"""
return cylinder(h=h, r=d / 2, center=False, fn=fn)
def create_cutter_pocket(d, depth, base_height, fn):
"""カッター(引く形状):上面から深さdepthだけ掘る非貫通の凹み"""
# Z=base_height が上面。そこから depth だけ下へ掘る。
# cutter は少しだけ上に突き出す(+eps)ようにして、面一致による描画バグを防ぐ
pocket = cylinder(h=depth + 2 * eps, r=d / 2, center=False, fn=fn)
return translate(pocket, [0, 0, base_height - depth - eps])
# --- メイン処理 ---
body = create_body(base_d, base_h, fn_val)
cutter = create_cutter_pocket(pocket_d, pocket_h, base_h, fn_val)
result = body - cutter
show(result)
13. 寸法150×100×20mmのベースプレート。中央列に直径8mm の穴を5個、20mm等間隔で配置
完成コード(PythonSCAD)
# ==========================================
# ベースプレート(中央列 8mm穴×5)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
plate_w = 150.0 # 幅(X方向)
plate_l = 100.0 # 奥行き(Y方向)
plate_h = 20.0 # 高さ(Z方向)
hole_d = 8.0 # 穴径
hole_r = hole_d / 2.0
hole_pitch = 20.0 # 穴の等間隔
hole_n = 5 # 穴の個数(中央列)
fn_val = 60 # 円の分割数
eps = 0.1 # チラつき防止用微小値
# --- 関数(モジュール)定義 ---
def create_body(w, l, h):
"""ベースプレート本体(足す形状)"""
return cube([w, l, h], center=True)
def create_cutter(h, r, pitch, n, fn):
"""中央列の貫通穴カッター(引く形状)を + で一体化して返す"""
# 5個なら -2, -1, 0, 1, 2 のように中央対称に並べる
start_i = -(n // 2)
cutter = None
for i in range(n):
x = (start_i + i) * pitch
y = 0.0
z = 0.0
hole = cylinder(h=h + 2 * eps, r=r, center=True, fn=fn)
hole = translate(hole, [x, y, z])
cutter = hole if cutter is None else (cutter + hole)
return cutter
# --- メイン処理 ---
body = create_body(plate_w, plate_l, plate_h)
cutter = create_cutter(plate_h, hole_r, hole_pitch, hole_n, fn_val)
result = body - cutter
show(result)
14. 寸法100×100×50mmのボックスの上面中央に、直径40mm・高さ30mmの円柱ボス
完成コード(PythonSCAD)
# ==========================================
# 100x100x50 Box + Top Center Boss
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
box_w = 100.0 # 幅(X方向)
box_l = 100.0 # 奥行き(Y方向)
box_h = 50.0 # 高さ(Z方向)
boss_d = 40.0 # ボス直径
boss_h = 30.0 # ボス高さ
fn_val = 80 # 円柱の滑らかさ
eps = 0.1 # 予備(今回は未使用だが、穴あけ等で活躍)
# --- 関数(モジュール)定義 ---
def create_box(w, l, h):
"""底面Z=0の箱(ブロック)"""
body = cube([w, l, h], center=True)
return translate(body, [0, 0, h / 2])
def create_boss(d, h, base_z, fn):
"""上面に載る円柱ボス(底面が base_z から開始)"""
r = d / 2
boss = cylinder(h=h, r=r, center=False, fn=fn)
return translate(boss, [0, 0, base_z])
# --- メイン処理 ---
box_body = create_box(box_w, box_l, box_h)
boss = create_boss(boss_d, boss_h, base_z=box_h, fn=fn_val)
result = box_body + boss
show(result)
15. 直径120mm・高さ10mmの円盤の上面に、直径80mm・高さ40mmの円柱を同軸に配置した形状
完成コード(PythonSCAD)
# ==========================================
# 同軸2段円柱(円盤+円柱)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
disc_d = 120.0 # 円盤 直径
disc_h = 10.0 # 円盤 高さ
boss_d = 80.0 # 上の円柱 直径
boss_h = 40.0 # 上の円柱 高さ
fn_val = 120 # 円の分割数(滑らかさ)
# --- メイン処理 ---
# 円盤(底面Z=0から上に積み上げ)
disc = cylinder(h=disc_h, r=disc_d / 2, center=False, fn=fn_val)
# 上の円柱(円盤の上面に同軸で配置)
boss = translate(
cylinder(h=boss_h, r=boss_d / 2, center=False, fn=fn_val),
[0, 0, disc_h]
)
result = disc + boss
show(result)
16. 外径120mm・内径80mm・厚さ15mmのフランジリング。外周部に直径10mmの穴を6個、均等配置
完成コード(PythonSCAD)
# ==========================================
# フランジリング(外周6穴)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
from math import pi, sin, cos
# --- パラメータ設定 (単位: mm) ---
outer_d = 120.0 # 外径
inner_d = 80.0 # 内径
thickness = 15.0 # 厚さ(Z方向)
hole_d = 10.0 # 外周穴の直径
hole_count = 6 # 穴数(等配)
edge_margin = 5.0 # 外周から穴中心までの余裕(外周部の目安)
fn_val = 80 # 円の滑らかさ
eps = 0.1 # チラつき防止用微小値
# --- ヘルパー ---
def r_from_dia(d):
return d / 2.0
# --- 関数(モジュール)定義 ---
def create_body(od, h, fn):
"""本体(足す形状): 外径の円柱"""
return cylinder(h=h, r=r_from_dia(od), center=True, fn=fn)
def create_cutter(od, id_, h, hole_d, hole_n, margin, fn):
"""カッター(引く形状): 内径くり抜き + 外周ボルト穴(等配)"""
r_outer = r_from_dia(od)
r_inner = r_from_dia(id_)
r_hole = r_from_dia(hole_d)
# 内径くり抜き(貫通。Zファイティング防止で高さに余裕)
inner_cut = cylinder(h=h + 2 * eps, r=r_inner, center=True, fn=fn)
# 外周穴の中心半径(外周から margin 分だけ内側、さらに穴半径分内側)
bolt_circle_r = r_outer - margin - r_hole
holes = None
for i in range(hole_n):
ang = 2 * pi * i / hole_n
x = bolt_circle_r * cos(ang)
y = bolt_circle_r * sin(ang)
one_hole = translate(
cylinder(h=h + 2 * eps, r=r_hole, center=True, fn=fn),
[x, y, 0]
)
holes = one_hole if holes is None else (holes + one_hole)
return inner_cut + holes
# --- メイン処理 ---
body = create_body(outer_d, thickness, fn_val)
cutter = create_cutter(outer_d, inner_d, thickness, hole_d, hole_count, edge_margin, fn_val)
result = body - cutter
show(result)
必要なら「穴をどれくらい外周寄りにするか」を edge_margin(外周からの余裕)で調整できます。例えば外周ギリギリに寄せたいなら edge_margin = 2.0 などにします。
17. 対辺距離30mm・高さ25mmの正六角柱
完成コード(PythonSCAD)
# ==========================================
# 正六角柱(対辺距離 30mm・高さ 25mm)
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
from math import pi, sin, cos
# --- パラメータ設定 (単位: mm) ---
across_flats = 30.0 # 対辺距離(向かい合う辺どうしの距離)
height = 25.0 # 高さ(Z方向)
eps = 0.1 # 予備(今回は未使用)
# --- 関数(モジュール)定義 ---
def regular_hexagon_2d(af):
"""
正六角形(2D)をXY平面上に、原点中心で作る。
af = 対辺距離(across flats)
"""
n = 6
apothem = af / 2.0 # 内接円半径(中心→辺の距離)
R = apothem / cos(pi / n) # 外接円半径(中心→頂点の距離)
pts = []
for i in range(n):
theta = 2 * pi * i / n
pts.append([R * cos(theta), R * sin(theta)]) # (x, y)はタプル禁止なのでリストで
return polygon(pts)
def hex_prism(af, h):
"""正六角柱(Z=0を底面基準)"""
hex2d = regular_hexagon_2d(af)
return linear_extrude(hex2d, height=h)
# --- メイン処理 ---
result = hex_prism(across_flats, height)
show(result)
補足(寸法の意味): 「対辺距離30mm」は“向かい合う平らな面どうしの距離”なので、六角ナットの「二面幅」と同じ定義です。高さ25mmはZ方向にそのまま押し出しています(底面がZ=0)。
18. 外接円直径60mm・高さ20mmの正六角柱。全エッジにC2チャンファー
完成コード(PythonSCAD)
# ==========================================
# 正六角柱(外接円φ60・高さ20)全エッジC2チャンファー
# 作成日: 2026/08/14
# ==========================================
from pythonscad import *
from math import pi, sin, cos, sqrt
# --- パラメータ設定 (単位: mm) ---
circum_d = 60.0 # 外接円直径(頂点が乗る円)
height = 20.0 # 高さ(Z方向)
c = 2.0 # チャンファー寸法 C2
eps = 0.05 # チラつき防止&hull用の薄板厚み
# --- 幾何ヘルパー(2Dベクトル) ---
def v_sub(a, b):
return [a[0] - b[0], a[1] - b[1]]
def v_add(a, b):
return [a[0] + b[0], a[1] + b[1]]
def v_mul(a, s):
return [a[0] * s, a[1] * s]
def v_len(a):
return sqrt(a[0] * a[0] + a[1] * a[1])
def v_unit(a):
L = v_len(a)
return [a[0] / L, a[1] / L]
# --- 関数(モジュール)定義 ---
def regular_hex_vertices(R):
"""原点中心・外接円半径Rの正六角形の頂点(CCW順)"""
verts = []
for i in range(6):
th = i * (pi / 3.0)
verts.append([R * cos(th), R * sin(th)])
return verts
def chamfered_hex_profile_2d(R, chamfer):
"""
垂直エッジ(縦の稜線)をC寸法で落とした断面(=頂点を面取りした12角形)を作る。
※この2D断面を押し出すと「縦エッジのC2」が入る。
"""
v = regular_hex_vertices(R)
# out[i] : 頂点iから次の頂点(i+1)方向へ chamfer だけ進んだ点
# inn[i] : 頂点iから前の頂点(i-1)方向へ chamfer だけ進んだ点
out = []
inn = []
for i in range(6):
v_i = v[i]
v_next = v[(i + 1) % 6]
v_prev = v[(i - 1) % 6]
dir_next = v_unit(v_sub(v_next, v_i))
dir_prev = v_unit(v_sub(v_prev, v_i))
out.append(v_add(v_i, v_mul(dir_next, chamfer)))
inn.append(v_add(v_i, v_mul(dir_prev, chamfer)))
# 辺ごとに「out[i] -> inn[i+1]」でつながるので、その順に12点を並べる
pts = []
for i in range(6):
pts.append(out[i])
pts.append(inn[(i + 1) % 6])
return polygon(points=pts)
def plate_at_z(shape2d, z):
"""hull用:2D形状を薄く押し出して、指定Z位置へ置いた“薄板”にする"""
slab = linear_extrude(shape2d, height=eps) # Z: 0..eps
return translate(slab, [0, 0, z])
def create_chamfered_hex_prism(circum_dia, h, chamfer):
"""
全エッジCチャンファーを、3つのボリューム(下C部+中間+上C部)の足し算で作る。
- 縦エッジC:断面を12角形(頂点面取り)にして押し出し
- 上下面の外周エッジC:hullで「フル断面」⇔「内側オフセット断面」を45°で接続
"""
R = circum_dia / 2.0
# 縦エッジC(断面の頂点面取り)を入れた“フル断面”
prof_full = chamfered_hex_profile_2d(R, chamfer)
# 上下面のC用に、断面を内側へ平行オフセット(側面方向に2mm引っ込める)
# これで、上面/下面のC2が「45°(2mm×2mm)」になりやすい形を作れる
prof_in = offset(prof_full, r=-chamfer)
# 中間のストレート部(Z=chamfer .. h-chamfer)
mid_h = h - 2.0 * chamfer
mid = linear_extrude(prof_full, height=mid_h)
mid = translate(mid, [0, 0, chamfer])
# 下のチャンファー部(Z=0..chamfer)
bottom = hull(
plate_at_z(prof_in, 0.0),
plate_at_z(prof_full, chamfer)
)
# 上のチャンファー部(Z=h-chamfer..h)
# plateの厚みeps分だけ上に飛び出さないよう、上側は(h-eps)に置く
top = hull(
plate_at_z(prof_full, h - chamfer),
plate_at_z(prof_in, h - eps)
)
return bottom + mid + top
# --- メイン処理 ---
result = create_chamfered_hex_prism(circum_d, height, c)
show(result)
補足(設計の考え方)
- 「縦の稜線(側面どうしの交線)」のC2は、2D断面で頂点を面取りした12角形を作って押し出すことで入れています
- 「上面・下面の外周エッジ」のC2は、上側/下側で断面を内側へ2mmオフセットした形を用意し、
hull()で45°の斜面になるようにつないでいます
19. 外径20mm・内径10mm・高さ15mmのスペーサー(円筒カラー)
完成コード(PythonSCAD)
# ==========================================
# 円筒スペーサー(円筒カラー)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_d = 20.0 # 外径
inner_d = 10.0 # 内径
height = 15.0 # 高さ
fn_val = 80 # 円の滑らかさ
eps = 0.1 # チラつき防止(貫通カッターの余裕)
def r_from_dia(d):
"""直径→半径"""
return d / 2.0
def create_body(od, h, fn):
"""足す形状(外側円筒)"""
return cylinder(h=h, r=r_from_dia(od), center=True, fn=fn)
def create_cutter(id_, h, fn, eps_):
"""引く形状(内側の貫通穴)"""
return cylinder(h=h + 2 * eps_, r=r_from_dia(id_), center=True, fn=fn)
# --- メイン処理 ---
body = create_body(outer_d, height, fn_val)
cutter = create_cutter(inner_d, height, fn_val, eps)
result = body - cutter
show(result)
※「高さ方向(Z)も center=True」にしてあるので、原点[0,0,0]に対して上下対称の位置にできます(組み立て基準が作りやすいです)。
20. 外径30mm・内径16mm・高さ10mmのカラー。両端にR1フィレット
1. 完成コード(PythonSCAD)
# ==========================================
# カラー(外径30 / 内径16 / 高さ10, 両端R1)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_d = 30.0 # 外径
inner_d = 16.0 # 内径
height = 10.0 # 高さ
fillet_r = 1.0 # フィレット半径 R
fn_val = 96 # 円・球の分割数
eps = 0.05 # チラつき防止用微小値
# --- 寸法の派生 ---
outer_r = outer_d / 2.0
inner_r = inner_d / 2.0
# minkowski でRを付けた後に最終寸法が狙い値になるよう、芯材を縮める
core_outer_r = outer_r - fillet_r
core_inner_r = inner_r + fillet_r
core_h = height - 2.0 * fillet_r
# --- 関数(モジュール)定義 ---
def create_collar_core(r_out, r_in, h, fn):
"""R付け前の芯材(リング)"""
outer = cylinder(h=h, r=r_out, center=True, fn=fn)
inner = cylinder(h=h + 2.0 * eps, r=r_in, center=True, fn=fn) # 余裕を持って貫通
return outer - inner
# --- メイン処理 ---
core = create_collar_core(core_outer_r, core_inner_r, core_h, fn_val)
# 両端(上下)+内外周エッジにR1が入る
result = minkowski(core, sphere(r=fillet_r, fn=fn_val))
show(result)
※この作り方(minkowski)は「両端の角だけ」ではなく、内径側の上下エッジにもRが入ります。もし「外径側の上下エッジだけR1にしたい」など、Rを入れる場所を限定したい場合は別方式を検証してみてください。
参考資料

















