はじめに
「PythonSCAD」検索すると、チュートリアルがいくつか、見つかりますが、OpenSCADの記述と混同していて、()の使い方が適切でなかったりするので、学習できるように、サンプルを紹介します。
PythonSCADについて
PythonSCADは「単なる別のモデリングソフトウェア」ではなく、「プログラムによってモデルを生成する」設計手法です。モデリングがコードになると、モデルはもはやファイルではなく、進化するルールの集合体のようなものになります。新しい可能性ですね。
- 3Dプリント部品(ベース、ブラケット、シェル)
- 仕様の異なるモデルの一括生成
- パラメトリック構造部品設計
- プログラミングとエンジニアリング設計の統合教育
PythonSCADコミュニティ、OpenSCADコミュニティ、CadQueryコミュニティ、build123dコミュニティ、開発者、記事執筆者に感謝申し上げます。ありがとうございます。
001. 寸法50x30x5 の板に φ10 の貫通穴
from pythonscad import *
model = difference(
cube([50, 30, 5]),
translate(cylinder(h=7, r=5),[25, 15, -1]))
show(model)
このコードは「板(直方体)に、円柱で貫通穴を1個あける」モデルです。処理の意味を行ごとに説明します。
何を作っている?
-
cube([50, 30, 5]):50×30×厚さ5 mm の板 -
cylinder(h=7, r=5):半径5 mm(直径10 mm)、高さ7 mm の円柱(これを“穴あけ用の刃物=カッター”として使う) -
difference(本体, カッター):本体からカッターを引き算して穴を開ける -
translate(...,[25, 15, -1]):円柱を板の中心位置へ移動し、さらにZ方向に少し下へずらして「確実に貫通」させる
行ごとの解説
1) model = difference(...)
model = difference(
cube([50, 30, 5]),
translate(cylinder(h=7, r=5),[25, 15, -1]))
-
cube([50, 30, 5])は center指定がないので、座標は- X: 0〜50
- Y: 0〜30
- Z: 0〜5
の範囲にできます(原点から +方向に伸びる置き方)。
-
穴用の円柱
cylinder(h=7, r=5)も center指定がないので、元の位置では- Z: 0〜7
にできます。
- Z: 0〜7
-
それを
translate(...,[25, 15, -1])で移動すると、- X中心:25(板の幅50のちょうど中央)
- Y中心:15(板の奥行30のちょうど中央)
- Z範囲:-1〜6
になります。
つまり板の厚み(Z:0〜5)を上下に少しはみ出す形で円柱が貫くので、確実に穴が貫通します。
(この「少しはみ出させる」のは、ブーリアン演算で面が一致して失敗するのを防ぐ定番テクです。)
2) show(model)
表示するだけです。
改善例
-
difference(...)はOpenSCAD風なので、PythonSCADでは基本-演算子で書くのが推奨(ルール的にもこちら) - 寸法を 変数化すると、あとでサイズ変更が楽(パラメトリック設計)
- 円柱は
fnを指定すると滑らか(例:fn=60) - “はみ出し量”を
epsで管理すると、貫通穴が確実&チラつきも減る
ルールに沿った書き換え例(同じ形状)
# ==========================================
# 50x30x5 の板に φ10 の貫通穴
# 作成日: 2026/08/19
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
w = 50.0
l = 30.0
h = 5.0
hole_r = 5.0
fn_val = 60
eps = 0.1
# --- 本体(足す形状) ---
body = cube([w, l, h]) # 元コードと同じく原点から +方向へ配置
# --- カッター(引く形状) ---
cutter_cyl = cylinder(h=h + 2 * eps, r=hole_r, fn=fn_val)
cutter = translate(cutter_cyl, [w/2, l/2, -eps]) # 中心に配置して少しはみ出す
# --- 一括くり抜き ---
result = body - cutter
show(result)
002. 穴あきプレート
パラメータを変更するとモデルが変更されます。エンジニアリング設計や教室での実験に最適です。
from pythonscad import *
def plate(length, width, hole_r):
return cube([length, width, 5]) - cylinder(h=7, r=hole_r).translate([length/2, width/2, -1])
model = plate(80, 40, 6)
show(model)
1) 元コードの動き
def plate(length, width, hole_r):
return cube([length, width, 5]) - cylinder(h=7, r=hole_r).translate([length/2, width/2, -1])
-
cube([length, width, 5])- 80×40×5 の板を作る(ただし center指定なし なので、原点(0,0,0)から +X,+Y,+Z に伸びる板)
-
cylinder(h=7, r=hole_r)- 半径6、高さ7の円柱(これも center指定なし なので Z=0 から Z=7 に伸びる)
-
.translate([length/2, width/2, -1])- 「板の中心 (length/2, width/2) に移動し、Zを-1して少し下に下げる」ことで、
- 穴用円柱が板を確実に貫通するようにしたい
-
cube - cylinder- 板から円柱を引くので、中心に穴の空いた板になる
2) 改善例
(A) translate関数を使う
今回は、メソッドチェーンの obj.translate(...) ではなく、
translate(obj, [x, y, z])
の形で書きます。
◆ 移動の別の書き方。+ []、プラスとリストの組み合わせで、移動させます。和集合のunionの+と勘違いしないように注意が必要です。
obj + [x, y, z]
(B) center を指定していないので基準がズレやすい
-
cube([L,W,5])は「角が原点」基準 -
cylinder(...)も「底面がZ=0」基準
初心者のうちはこれで混乱しがちなので、XYは中心基準で作るのが安全です(設計が崩れにくい)。
(C) 貫通穴は「eps」でマージンを付けるのが安全
h=7 と z=-1 で貫通を確保していて良い発想です。
ただ、板厚が変わったときに破綻しやすいので、板厚から自動計算して
- 穴の高さ:
t + 2*eps - 穴の中心Z:
t/2
のようにするのが「パラメトリック設計」らしくて強いです。
3) ルールに沿った修正版(同じ見た目で、エラーなし&安全)
完成コード(PythonSCAD)
# ==========================================
# 穴あきプレート
# 作成日: 2026/08/19
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
plate_len = 80.0
plate_wid = 40.0
plate_th = 5.0
hole_r = 6.0
fn_val = 60
eps = 0.1 # チラつき&貫通不足防止
def plate(length, width, th, hole_r, fn):
"""板(足す形状)- 穴カッター(引く形状)"""
# XYはcenter=Trueで作り、底面をZ=0にしたいので +th/2 持ち上げる
body = translate(cube([length, width, th], center=True), [0, 0, th / 2])
# カッターは確実に貫通させる(th + 2*eps)
cutter = translate(
cylinder(h=th + 2 * eps, r=hole_r, center=True, fn=fn),
[0, 0, th / 2]
)
return body - cutter
model = plate(plate_len, plate_wid, plate_th, hole_r, fn_val)
show(model)
4) この修正版の「幾何学的に正しい」ポイント
-
板の中心は常に(0,0)
- 長さや幅を変えても穴が真ん中に残る
-
板の底面がZ=0
- 3Dプリントの配置が直感的(ビルドプレート上に置いた状態)
-
カッターの高さに
epsを入れている- ピッタリ一致して面が重なると、描画のチラつき(Zファイティング)や、引き算失敗が起きやすいのを防ぐ
003. 7個の等間隔穴あきプレート
「リスト内包表記(for文)を使って等間隔に並ぶ複数の穴をスマートに作る」
from pythonscad import *
holes = [
cylinder(h=6, r=2,fn=24).translate([i*10, 0, 0])
for i in range(7)
]
model = difference(cube([60, 20, 5]), *holes)
show(model)
このコードは「長方形の板に、等間隔で7個の丸穴をあける」モデルを作ろうとしています。
1) 何をしているコードか
(A) 穴(円柱)を7本作る
holes = [
cylinder(h=6, r=2,fn=24).translate([i*10, 0, 0])
for i in range(7)
]
-
range(7)→i = 0,1,2,3,4,5,6の7回 -
i*10→ X方向に 0,10,20,30,40,50,60 mm の位置に配置 -
cylinder(h=6, r=2, fn=24)→ 半径2mm、高さ6mmの円柱(穴あけ用カッターにしたい)
つまり「X方向に10mm間隔で並ぶ穴カッター」を作っています。
fn=24 は円の分割数で、値が大きいほど丸がなめらかになります。
(B) 板から穴を引く
model = difference(cube([60, 20, 5]), *holes)
-
cube([60, 20, 5])→ 60×20×5mm の直方体(板) -
difference(本体, 穴1, 穴2, …)→ 本体から穴を全部引いて穴あき板にする
2) 改善例
①:.translate([...]) はメソッドチェーン
ここでは 移動は関数形式を使います:
- 関数形式:
translate(obj, [x, y, z]) - メソッドチェーン:
obj.translate([x, y, z])
②:difference(...) ではなく演算子 - を使う
PythonSCAD学習としては、ブーリアンは演算子で書くのが安全・読みやすいです。
- 正しい設計方針:
- 本体(足す形)を作る
- カッター(引く形)を + で1つにまとめる
- 最後に
body - cutterで一気に引く
追加で大事:穴カッターは「少し長め」に(チラつき防止)
板厚が 5mm なのに穴カッター高さが 6mm は方向性はOKですが、面がギリギリ一致すると表示が乱れることがあります。
そのため eps を使って h = thickness + 2*eps のように「確実に貫通+余裕」を作るのが定石です。
3) 修正版コード(安全・推奨)
# ==========================================
# 7個の等間隔穴あきプレート
# 作成日: 2026/08/19
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
plate_x = 60.0
plate_y = 20.0
plate_z = 5.0
hole_r = 2.0
hole_cnt = 7
pitch_x = 10.0
fn_val = 24
eps = 0.1
# --- 本体(足す形状) ---
body = cube([plate_x, plate_y, plate_z], center=True)
# --- カッター(引く形状)を + で1つにまとめる ---
cutter = None
for i in range(hole_cnt):
x = (i - (hole_cnt - 1) / 2) * pitch_x # 中心対称に並べる(ズレ防止)
hole = cylinder(h=plate_z + 2 * eps, r=hole_r, center=True, fn=fn_val)
hole = translate(hole, [x, 0, 0])
cutter = hole if cutter is None else (cutter + hole)
# --- 一括くり抜き ---
result = body - cutter
show(result)
修正版で良くなった点
-
translate(obj, [...])の書式 - 穴カッターを 1個ずつ引かず、まとめてから一気に引く
- 穴の並びを「中心対称」にして、板の中心と穴列の中心が一致する
(元コードだと穴が 0〜60 に並ぶので、板の中心とズレが出やすい)
4) 別修正版コード(リスト内包表記)
from pythonscad import *
plate_x = 60.0
plate_y = 20.0
plate_z = 5.0
holes = [
cylinder(h=6, r=2,fn=24,center=True)+ [i*10, 0, 0]
for i in range(-3,4)
]
model = difference(cube([plate_x, plate_y, plate_z],center=True), *holes)
show(model)
3D CADのモデリングにおいて、中心(原点 0)を基準にして左右対称にパーツを並べる考え方は、設計の対称性を保つための超重要テクニックです!
range(7)(0, 1, 2, 3, 4, 5, 6)から -3, -2, -1, 0, 1, 2, 3 を作り出す工夫と、それを活用したPythonSCADのコードを解説します。
1. 完成コード(PythonSCAD)
中心(原点)を基準にして、左右対称に7個の穴をあけるプレートのプログラムです。
# ==========================================
# 中心基準・等ピッチ穴あけプレート
# 作成日: 2026/08/19
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
plate_w = 70.0 # プレート幅(X方向)
plate_l = 20.0 # プレート奥行き(Y方向)
plate_h = 5.0 # プレート厚み(Z方向)
hole_r = 2.0 # 穴の半径 (直径 4mm)
hole_num = 7 # 穴の個数 (奇数)
pitch = 8.0 # 穴の間隔(ピッチ)
fn_val = 32 # 円柱の滑らかさ
eps = 0.1 # 面のチラつき(Zファイティング)防止マージン
# --- 関数(モジュール)定義 ---
# 1. プレート本体の生成
def create_base_plate(w, l, h):
return cube([w, l, h], center=True)
# 2. 中心基準(-3〜+3)で穴カッターを生成
def create_centered_hole_array(num, pitch_len, r, h, fn):
# 中央のオフセット値(7個の場合は 3)
center_idx = num // 2
# リスト内包表記で各穴オブジェクトを生成
# i - center_idx により、-3, -2, -1, 0, 1, 2, 3 の倍率で配置される
hole_list = [
translate(
cylinder(h=h + 2 * eps, r=r, center=True, fn=fn),
[(i - center_idx) * pitch_len, 0, 0]
)
for i in range(num)
]
# + 演算子で1つの刃物オブジェクトに統合
cutter = hole_list[0]
for h_obj in hole_list[1:]:
cutter = cutter + h_obj
return cutter
# --- メイン処理 ---
# 土台の生成
base = create_base_plate(plate_w, plate_l, plate_h)
# 穴カッターの生成
cutter = create_centered_hole_array(hole_num, pitch, hole_r, plate_h, fn_val)
# 引き算(- 演算子)で一気に穴を貫通
result = base - cutter
# 3Dプレビュー表示
show(result)
2. -3, -2, -1, 0, 1, 2, 3 を作る3つの工夫
Pythonの文法を使ってこの数列を作るには、主に以下の 3つのアプローチ があります。
工夫A:中央の数値を引く(一番応用が効く方法)
range(7) は 0, 1, 2, 3, 4, 5, 6 です。この各数値から中央の値である 3 を引き算します。
# リスト内包表記
offsets = [i - 3 for i in range(7)]
# 結果: [-3, -2, -1, 0, 1, 2, 3]
【一般化するテクニック(変数対応)】
個数が変数 N = 7 の場合、整数除算(//)を使って center_idx = N // 2 と書けば、N が 5 や 9 に変わっても自動で真ん中が 0 になります。
N = 7
offsets = [i - (N // 2) for i in range(N)]
工夫B:range() の範囲を直接指定する
range(start, stop) を使えば、最初から -3 からスタートさせることができます。
# stop は「指定した数値の手前まで」なので +4 を指定
offsets = [i for i in range(-3, 4)]
# 結果: [-3, -2, -1, 0, 1, 2, 3]
【一般化する書き方】
N = 7
half = N // 2
offsets = [i for i in range(-half, half + 1)]
工夫C:偶数個(例: 6個)にも対応できる対称配置(プロ仕様)
穴が 6個(偶数) の場合、真ん中に穴は来ず、原点 0 を挟んで左右に ±0.5, ±1.5, ±2.5 ピッチずらす必要があります。
これを奇数・偶数の両方に対応できるように一般化すると、以下の計算式になります。
$$\text{X座標} = \left( i - \frac{N - 1}{2} \right) \times \text{ピッチ}$$
# N = 7 (奇数) のとき: [-3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]
# N = 6 (偶数) のとき: [-2.5, -1.5, -0.5, 0.5, 1.5, 2.5]
offsets = [(i - (N - 1) / 2) * pitch for i in range(N)]
ものづくり・工業設計の視点
機械設計において、部品の中心を原点[0, 0, 0]に合わせて左右対称(対称拘束)に作っておくと、「他のパーツと組み立てる(アセンブリ)ときの位置合わせが圧倒的に楽になる」「重心位置がブレない」 という大きなメリットがあります。
おかしいなと気づくきっかけ
上記のことに気づくきっかけは、ブロックの幅の半分だけ、ずらせば良いのではと、思って、つくって確認したときでした。
plate_x = 80.0
plate_y = 20.0
plate_z = 5.0
holes = [
cylinder(h=6, r=2,fn=24,center=True)+ [i*10-plate_x/2, 0, 0]
for i in range(7)
]
previewとrenderボタンを押して、くりかえし、くりかえしですね。ありがとうございます。
参考資料







