PythonSCAD
PythonSCADコミュニティ・開発者に感謝申し上げます。ありがとうございます。
参考サイト
OpenSCADコミュニティ、CadQueryコミュニティ、build123dコミュニティ、開発者、記事執筆者に感謝申し上げます。ありがとうございます。
- build123dyのExamples
- CadQueryのExamples
- 高校生のためのPythonSCAD練習帳
21. 外形寸法200×200×10mmのプレート。直径15mmの穴を4×4のグリッド(40mm間隔)に配置
完成コード(PythonSCAD)
# ==========================================
# 200x200x10 Plate with 4x4 Hole Grid
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
plate_w = 200.0 # X方向
plate_l = 200.0 # Y方向
plate_h = 10.0 # Z方向
hole_d = 15.0
hole_r = hole_d / 2.0
grid_n = 4 # 4x4
pitch = 40.0 # 穴間隔
fn_val = 80
eps = 0.1 # チラつき防止(カッターのはみ出し)
# --- 関数定義 ---
def create_plate(w, l, h):
"""プレート本体(足す形状)"""
return cube([w, l, h], center=True)
def create_hole_cutter(hole_r, plate_h, n, pitch, fn):
"""4x4の貫通穴カッター(引く形状)を1つにまとめて返す"""
# 4点を中心対称に並べる座標: [-60, -20, 20, 60] (pitch=40, n=4)
offset0 = -((n - 1) / 2.0) * pitch
coords = [offset0 + i * pitch for i in range(n)]
cutter = None
for x in coords:
for y in coords:
hole = cylinder(h=plate_h + 2 * eps, r=hole_r, center=True, fn=fn)
hole = translate(hole, [x, y, 0.0])
cutter = hole if cutter is None else (cutter + hole)
return cutter
# --- メイン処理 ---
body = create_plate(plate_w, plate_l, plate_h)
cutter = create_hole_cutter(hole_r, plate_h, grid_n, pitch, fn_val)
result = body - cutter
show(result)
22. 外形寸法150×60×10mmのプレート。直径8mmの穴を3×2(X方向50mm間隔・Y方向30mm間隔)で配置
完成コード(PythonSCAD)
# ==========================================
# 150×60×10mm プレート(3×2 穴あき)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
from math import pi # 今回は未使用だが、拡張しやすいので残してOK
# --- パラメータ設定 (単位: mm) ---
plate_x = 150.0 # プレート寸法 X
plate_y = 60.0 # プレート寸法 Y
plate_z = 10.0 # 厚み Z
hole_d = 8.0 # 穴の直径
hole_r = hole_d / 2.0
nx = 3 # X方向の穴数
ny = 2 # Y方向の穴数
pitch_x = 50.0 # X方向ピッチ
pitch_y = 30.0 # Y方向ピッチ
fn_val = 60
eps = 0.1 # チラつき防止&確実に貫通させる余裕
# --- 関数(モジュール)定義 ---
def create_plate(w, d, h):
"""プレート本体(足す形状)"""
return cube([w, d, h], center=True)
def create_hole_cutter(h, r, nx, ny, px, py, fn):
"""穴カッター(引く形状):3×2の円柱を + で一括結合"""
cutter = None
# 中心基準で座標を作る(3列なら -px, 0, +px / 2列なら -py/2, +py/2)
x0 = -(nx - 1) * px / 2.0
y0 = -(ny - 1) * py / 2.0
for ix in range(nx):
for iy in range(ny):
x = x0 + ix * px
y = y0 + iy * py
hole = cylinder(h=h + 2 * eps, r=r, center=True, fn=fn)
hole = translate(hole, [x, y, 0])
cutter = hole if cutter is None else (cutter + hole)
return cutter
# --- メイン処理 ---
plate = create_plate(plate_x, plate_y, plate_z)
cutter = create_hole_cutter(plate_z, hole_r, nx, ny, pitch_x, pitch_y, fn_val)
result = plate - cutter
show(result)
補足(位置の確認)
- X位置:
-50, 0, +50mm(50mm間隔で3列、中心揃え) - Y位置:
-15, +15mm(30mm間隔で2列、中心揃え)
23. 底面80×80mm、上面40×40mm、高さ60mmのピラミッド台形
完成コード(PythonSCAD)
# ==========================================
# 角錐台(ピラミッド台形)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
base_w = 80.0 # 底面の幅(X方向)
base_l = 80.0 # 底面の奥行(Y方向)
top_w = 40.0 # 上面の幅(X方向)
top_l = 40.0 # 上面の奥行(Y方向)
height = 60.0 # 高さ(Z方向)
# --- メイン処理 ---
# square は常にXY平面、center=Trueで原点中心に配置
base_2d = square([base_w, base_l], center=True)
# linear_extrude はZ=0を底面基準(center=False)で積み上げ
# scale は [X倍率, Y倍率]
scale_xy = [top_w / base_w, top_l / base_l]
result = linear_extrude(base_2d, height=height, scale=scale_xy, center=False)
show(result)
ポイント:
-
scale=[top/base, top/base]を使うと、底面→上面へ線形に縮小される「角錐台」が作れます - XYは原点中心、Zは底面が
z=0からスタートする配置です
24. 外径60mm・内径56mm・高さ20mmの円筒キャップ(上面閉じ・底面開口)
完成コード(PythonSCAD)
# ==========================================
# 円筒キャップ(上面閉じ・底面開口)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_d = 60.0 # 外径
inner_d = 56.0 # 内径(中空部の直径)
cap_h = 20.0 # 高さ
fn_val = 80 # 円の滑らかさ
eps = 0.1 # チラつき防止用微小値
# 半径に変換
outer_r = outer_d / 2.0
inner_r = inner_d / 2.0
# 肉厚(半径方向)
wall_th = (outer_d - inner_d) / 2.0
# 上面の板厚(指定が無いので「肉厚と同じ」にする)
top_th = wall_th
# --- 関数定義 ---
def create_body(outer_radius, height, fn):
"""外形(足す形状): 底面Z=0、上面Z=height"""
return cylinder(h=height, r=outer_radius, center=False, fn=fn)
def create_cutter(inner_radius, height, top_thickness, fn, eps):
"""
中空を作るカッター(引く形状)
底面は開口したいので下にepsだけはみ出させる。
上面は top_thickness を残す(削りすぎ防止で eps 分だけ余裕を残す)。
"""
hollow_h = height - top_thickness - eps
if hollow_h < 0:
hollow_h = 0
hollow = cylinder(h=hollow_h, r=inner_radius, center=False, fn=fn)
hollow = translate(hollow, [0, 0, -eps]) # 底面側を少しはみ出して確実に開口
return hollow
# --- メイン処理 ---
body = create_body(outer_r, cap_h, fn_val)
cutter = create_cutter(inner_r, cap_h, top_th, fn_val, eps)
result = body - cutter
show(result)
25. 外径80mm・高さ30mmの円筒容器(底面あり・上面開口・肉厚4mm)
完成コード(PythonSCAD)
# ==========================================
# 円筒容器(底あり・上面開口)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_d = 80.0 # 外径
height = 30.0 # 全高(Z方向)
thick = 4.0 # 肉厚(側面+底)
fn_val = 120 # 円の滑らかさ
eps = 0.1 # チラつき防止用微小値
outer_r = outer_d / 2.0
inner_r = outer_r - thick
inner_h = height - thick # 底厚=thick として、内側空間の高さ
def create_body(outer_r, height, fn):
"""足す形状:外側の円筒(底面Z=0基準)"""
return cylinder(h=height, r=outer_r, center=False, fn=fn)
def create_cutter(inner_r, inner_h, thick, fn):
"""引く形状:内側の空洞(上面を確実に開口させるためにepsを追加)"""
cavity = cylinder(h=inner_h + 2 * eps, r=inner_r, center=False, fn=fn)
# 底を残すため、空洞は底厚(thick)の上から開始
cavity = translate(cavity, [0, 0, thick + eps])
return cavity
# --- メイン処理 ---
body = create_body(outer_r, height, fn_val)
cutter = create_cutter(inner_r, inner_h, thick, fn_val)
result = body - cutter
show(result)
必要なら「底だけ厚みを変えたい(例:底6mm、側面4mm)」など仕様変更してみましょう。
26. 直径25mm・長さ200mmの段付きシャフト。中央80mmは直径35mm
完成コード(PythonSCAD)
# ==========================================
# 段付きシャフト(中央太径)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
shaft_d = 25.0 # 両端側の直径
shaft_len = 200.0 # 全長(Z方向)
middle_d = 35.0 # 中央の直径
middle_len = 80.0 # 中央太径部の長さ
fn_val = 80 # 円柱の滑らかさ
eps = 0.1 # 念のため(今回は未使用)
# --- 関数(モジュール)定義 ---
def r_from_dia(d):
"""直径→半径"""
return d / 2.0
def create_shaft(d_small, len_total, d_mid, len_mid, fn):
"""
段付きシャフト(足す形状のみ)
・全体: 直径 d_small, 長さ len_total
・中央: 直径 d_mid, 長さ len_mid(中心に配置)
"""
base = cylinder(h=len_total, r=r_from_dia(d_small), center=True, fn=fn)
mid = cylinder(h=len_mid, r=r_from_dia(d_mid), center=True, fn=fn)
return base + mid
# --- メイン処理 ---
result = create_shaft(shaft_d, shaft_len, middle_d, middle_len, fn_val)
show(result)
補足(設計の考え方): 「全長200mmの細い軸」に「中央80mmだけ太い円柱を足す」ことで段付き形状を作っています。全て center=True なので、原点 [0,0,0] がシャフトの真ん中になります。
27. M10ナット相当: 対辺距離17mm・高さ8mmの正六角柱。中央に直径10.5mmの貫通穴
完成コード(PythonSCAD)
# ==========================================
# M10ナット相当(六角柱 + 貫通穴)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
from math import pi, sin, cos
# --- パラメータ設定 (単位: mm) ---
across_flats = 17.0 # 対辺距離(二面幅)
height_z = 8.0 # 高さ(Z方向)
hole_d = 10.5 # 貫通穴 直径
fn_val = 80 # 円の分割数
eps = 0.1 # チラつき防止用微小値
# --- 関数(モジュール)定義 ---
def hex_points_from_across_flats(af):
"""
正六角形の頂点座標を作る(XY平面、原点中心)
対辺距離 af から外接円半径 R を求める:
af = R * sqrt(3) => R = af / sqrt(3)
※ sqrt(3) は (3 ** 0.5) で計算
"""
R = af / (3 ** 0.5)
pts = []
for i in range(6):
ang = i * (pi / 3.0) # 0, 60, 120, ...
pts.append([R * cos(ang), R * sin(ang)])
return pts
def create_body(af, h):
"""六角柱(足す形状)"""
hex2d = polygon(hex_points_from_across_flats(af))
return linear_extrude(hex2d, height=h) # Z=0 を底面(center=False相当)
def create_cutter(hole_dia, h):
"""貫通穴カッター(引く形状)"""
hole = cylinder(h=h + 2 * eps, r=hole_dia / 2.0, center=False, fn=fn_val)
hole = translate(hole, [0, 0, -eps]) # 下にもepsだけはみ出させて確実に貫通
return hole
# --- メイン処理 ---
body = create_body(across_flats, height_z)
cutter = create_cutter(hole_d, height_z)
result = body - cutter
show(result)
28. 外径30mm・内径10.5mm・厚さ3mmの丸座金(ワッシャー)
完成コード(PythonSCAD)
# ==========================================
# 丸座金(ワッシャー)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_d = 30.0 # 外径
inner_d = 10.5 # 内径(穴径)
thick = 3.0 # 厚さ(Z方向)
fn_val = 80 # 円の分割数(滑らかさ)
eps = 0.1 # チラつき防止用微小値
# --- ヘルパー ---
def r_from_dia(d):
"""直径 -> 半径"""
return d / 2.0
# --- メイン処理 ---
outer = cylinder(h=thick, r=r_from_dia(outer_d), center=True, fn=fn_val)
hole = cylinder(h=thick + 2 * eps, r=r_from_dia(inner_d), center=True, fn=fn_val)
result = outer - hole
show(result)
29. 直径150mm・高さ15mmの円盤。中心から半径50mmの位置に直径8mmの穴を8個、均等配置
完成コード(PythonSCAD)
# ==========================================
# 8穴円盤(等配)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
from math import pi, sin, cos
# --- パラメータ設定 (単位: mm) ---
disk_d = 150.0 # 円盤の直径
disk_h = 15.0 # 円盤の高さ(厚み)
hole_d = 8.0 # 穴の直径
hole_count = 8 # 穴の個数
hole_pitch_r = 50.0 # 中心から穴中心までの半径
fn_val = 80 # 円の滑らかさ
eps = 0.1 # チラつき防止用微小値
# --- 関数(モジュール)定義 ---
def create_body(d, h, fn):
"""本体(足す形状)"""
return cylinder(h=h, r=d/2, center=True, fn=fn)
def create_cutter(hole_d, disk_h, hole_count, pitch_r, fn, eps):
"""カッター(引く形状): 8個の穴を + でまとめる"""
hole_h = disk_h + 2 * eps
one_hole = cylinder(h=hole_h, r=hole_d/2, center=True, fn=fn)
cutters = None
for i in range(hole_count):
ang = 2 * pi * i / hole_count
x = pitch_r * cos(ang)
y = pitch_r * sin(ang)
h_i = translate(one_hole, [x, y, 0.0])
cutters = h_i if cutters is None else (cutters + h_i)
return cutters
# --- メイン処理 ---
body = create_body(disk_d, disk_h, fn_val)
cutter = create_cutter(hole_d, disk_h, hole_count, hole_pitch_r, fn_val, eps)
result = body - cutter
show(result)
(確認ポイント)穴は「中心から半径50mm」の円周上に、45°ずつ(360°/8)均等配置されています。必要なら「穴の開始角度(回し始め)」も検討してみてください。
30. ヒートシンク:60×60×5mmのベースプレートの上に、厚さ2mm、高さ20mm、長さ60mmの放熱フィンを4mm間隔で15枚並べた形状。ベースの四隅には直径3mmの取り付け穴
完成コード(PythonSCAD)
# ==========================================
# ヒートシンク(60x60ベース + 15枚フィン + 取付穴)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
base_w = 60.0 # ベース幅(X)
base_l = 60.0 # ベース奥行(Y)
base_t = 5.0 # ベース厚み(Z)
fin_n = 15 # フィン枚数
fin_t = 2.0 # フィン厚み(X方向)
fin_h = 20.0 # フィン高さ(Z方向)
fin_len = 60.0 # フィン長さ(Y方向)
fin_pitch = 4.0 # フィンのピッチ(中心-中心の間隔) ※「4mm間隔」をピッチと解釈
hole_d = 3.0
hole_r = hole_d / 2.0
fn_val = 80
eps = 0.1
# --- 関数(モジュール)定義 ---
def create_body():
"""足す形状:ベース + フィン群"""
# ベース(XYは原点中心、底面Z=0になるようにZだけ持ち上げ)
base = translate(
cube([base_w, base_l, base_t], center=True),
[0, 0, base_t / 2.0]
)
# フィン(ベース上に積み上げ)
fins = None
x0 = -((fin_n - 1) * fin_pitch) / 2.0 # フィン列の中心合わせ
for i in range(fin_n):
x = x0 + i * fin_pitch
fin = translate(
cube([fin_t, fin_len, fin_h], center=True),
[x, 0, base_t + fin_h / 2.0]
)
fins = fin if fins is None else (fins + fin)
return base + fins
def create_cutter():
"""引く形状:ベース四隅の取付穴(貫通)"""
# 穴はベース厚みを確実に貫通させ、Zファイティング防止でepsを上下に足す
hole = cylinder(h=base_t + 2 * eps, r=hole_r, center=True, fn=fn_val)
x = base_w / 2.0 - hole_r
y = base_l / 2.0 - hole_r
z = base_t / 2.0 # ベース中心高さ
holes = (
translate(hole, [ x, y, z]) +
translate(hole, [ x, -y, z]) +
translate(hole, [-x, y, z]) +
translate(hole, [-x, -y, z])
)
return holes
# --- メイン処理 ---
body = create_body()
cutter = create_cutter()
result = body - cutter
show(result)
補足(設計の読み替え)
- 「4mm間隔」は、フィンの中心同士の間隔(ピッチ)= 4mmとして配置しています(厚み2mmなので、すき間は2mm)。この解釈だと 15枚が60mm幅に収まります
- もし「すき間が4mm(ピッチ6mm)」の意味だと、15枚は60mmに入らないので、枚数や寸法の再指定が必要です
31. 電子基板ケース:外寸100×70×30mmのボックスを、肉厚2mmでシェル化(上部が開口)。底面の内側四隅に、高さ10mm、外径6mm、内径3mmのボス(円柱のスタンドオフ)を配置。側面の1つに15×8mmの長方形のUSBポート用切り欠き。
完成コード(PythonSCAD)
# ==========================================
# 電子基板ケース(上部開口・ボス付き)
# 作成日: 2026/08/15
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
outer_w = 100.0 # 外寸X
outer_l = 70.0 # 外寸Y
outer_h = 30.0 # 外寸Z
t_wall = 2.0 # 肉厚(側壁&底)
# ボス(スタンドオフ)
boss_h = 10.0
boss_od = 6.0 # 外径
boss_id = 3.0 # 内径
boss_clear = 1.0 # 壁からの逃げ(組付け余裕)
# USB切り欠き(側面)
usb_w = 15.0 # 幅(X方向)
usb_h = 8.0 # 高さ(Z方向)
usb_zc = 12.0 # 切り欠き中心Z(底からの高さ)
usb_side = "pos_y" # "pos_y" 側面に配置(+Y側)
fn_val = 80
eps = 0.15 # チラつき防止&貫通マージン
# --- 関数定義 ---
def create_outer_block(w, l, h):
"""外形ブロック(底面Z=0、XYは原点中心)"""
blk = cube([w, l, h], center=True)
return translate(blk, [0, 0, h / 2])
def create_inner_cavity(w, l, h, t):
"""
内側空間カッター(上部開口)
底は t_wall を残し、上は少しepsだけ突き抜けて確実に開口させる
"""
inner_w = w - 2 * t
inner_l = l - 2 * t
inner_h = h - t + eps # 上にepsだけはみ出して開口を確実に
cav = cube([inner_w, inner_l, inner_h], center=True)
zc = t + inner_h / 2
return translate(cav, [0, 0, zc])
def create_usb_cutout(w, l, t, usb_w, usb_h, usb_zc, side):
"""USBポート用の長方形切り欠き(側壁を貫通するカッター)"""
cut_th = t + 2 * eps # 壁厚より少し厚くして確実に貫通
cut = cube([usb_w, cut_th, usb_h], center=True)
if side == "pos_y":
yc = (l / 2) - (t / 2)
return translate(cut, [0, yc, usb_zc])
elif side == "neg_y":
yc = -(l / 2) + (t / 2)
return translate(cut, [0, yc, usb_zc])
else:
# 必要なら pos_x / neg_x も追加してOK
return translate(cut, [0, (l / 2) - (t / 2), usb_zc])
def create_boss(od, idd, h, fn):
"""ボス1本(筒形:外径od、内径idd)"""
r_out = od / 2
r_in = idd / 2
outer = cylinder(h=h, r=r_out, center=False, fn=fn)
inner = cylinder(h=h + 2 * eps, r=r_in, center=False, fn=fn)
inner = translate(inner, [0, 0, -eps]) # 上下にepsはみ出し
return outer - inner
def create_bosses(outer_w, outer_l, t, boss_h, boss_od, boss_id, boss_clear, fn):
"""内側底面四隅にボスを配置(底の内側=Z=t から立ち上げ)"""
r_out = boss_od / 2
x = (outer_w / 2) - t - (r_out + boss_clear)
y = (outer_l / 2) - t - (r_out + boss_clear)
one = create_boss(boss_od, boss_id, boss_h, fn)
b1 = translate(one, [ x, y, t])
b2 = translate(one, [ x, -y, t])
b3 = translate(one, [-x, y, t])
b4 = translate(one, [-x, -y, t])
return b1 + b2 + b3 + b4
# --- メイン処理 ---
outer_block = create_outer_block(outer_w, outer_l, outer_h)
# カッター(引く形状)は + でまとめる
cavity_cutter = create_inner_cavity(outer_w, outer_l, outer_h, t_wall)
usb_cutter = create_usb_cutout(outer_w, outer_l, t_wall, usb_w, usb_h, usb_zc, usb_side)
cutter = cavity_cutter + usb_cutter
# まず外形から中空化&切り欠き
shell = outer_block - cutter
# ボスは「残したい形状」なので、くり抜き後に足し算で追加
bosses = create_bosses(outer_w, outer_l, t_wall, boss_h, boss_od, boss_id, boss_clear, fn_val)
result = shell + bosses
show(result)
USB切り欠きの位置(底から何mmか、左右どちら寄りか)、フタ(上蓋)も作るかどうかで、実用性が一気に上がります。
参考資料










