0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【PythonSCAD】「プログラムによってモデルを生成する」設計手法、チュートリアル

0
Last updated at Posted at 2026-08-19

はじめに

「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)

スクリーンショット 2026-08-19 091640.png

このコードは「板(直方体)に、円柱で貫通穴を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
      にできます。
  • それを translate(...,[25, 15, -1]) で移動すると、

    • X中心:25(板の幅50のちょうど中央)
    • Y中心:15(板の奥行30のちょうど中央)
    • Z範囲:-1〜6
      になります。

つまり板の厚み(Z:0〜5)を上下に少しはみ出す形で円柱が貫くので、確実に穴が貫通します。
(この「少しはみ出させる」のは、ブーリアン演算で面が一致して失敗するのを防ぐ定番テクです。)

2) show(model)

表示するだけです。


改善例

  1. difference(...) はOpenSCAD風なので、PythonSCADでは基本 - 演算子で書くのが推奨(ルール的にもこちら)
  2. 寸法を 変数化すると、あとでサイズ変更が楽(パラメトリック設計)
  3. 円柱は fn を指定すると滑らか(例:fn=60
  4. “はみ出し量”を 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)

スクリーンショット 2026-08-19 092229.png

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)

スクリーンショット 2026-08-19 094213.png


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=7z=-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)

スクリーンショット 2026-08-19 094843.png


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)

スクリーンショット 2026-08-19 100220.png

このコードは「長方形の板に、等間隔で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. 本体(足す形)を作る
    2. カッター(引く形)を + で1つにまとめる
    3. 最後に 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)

スクリーンショット 2026-08-19 101339.png

修正版で良くなった点

  • 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)

スクリーンショット 2026-08-19 102438.png

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 と書けば、N59 に変わっても自動で真ん中が 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)
]

スクリーンショット 2026-08-19 104335.png

previewとrenderボタンを押して、くりかえし、くりかえしですね。ありがとうございます。

参考資料

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?