はじめに
Pythonプログラミングで始める形状作成の練習帳です。PythonSCADにコピペして、確認していきましょう。きっと、世界は広いと感じられます。ありがとうございます。
PythonSCAD
PythonSCADコミュニティ・開発者に感謝申し上げます。ありがとうございます。
01. Google検索のAIモードのサンプル例
検索「PythonSCAD」の簡単なサンプルコード:
原点に配置した10角柱(円柱)を、X軸方向に20移動させて黄色く塗るコード例です。
from pythonscad import *
# 形状の定義(半径5、高さ10、側面の細かさ10)
my_cylinder = cylinder(r=5, h=10, fn=10)
# X方向に20移動
moved_obj = translate(my_cylinder, [20, 0, 0])
# 黄色に着色して配置
final_obj = color(moved_obj, "yellow")
show(final_obj)
02. 色を変更。移動の方法を + [x, y, z]で記述
from pythonscad import *
# 形状の定義(半径5、高さ10、側面の細かさ10,10角形)
my_cylinder = cylinder(r=5, h=10, fn=10)
# X方向に20移動、+ [20, 0, 0]が使えます。
moved_obj = my_cylinder + [20, 0, 0]
# dodgerblueに着色
final_obj = color(moved_obj, "dodgerblue")
show(final_obj)
色の名前は以下を参考にしてください。
03. 寸法20×20×2mmのcubeに、以下の147色を割り当て、xy平面上に、等間隔で、12列で並べる
カラーは、アルファベット順
完成コード(PythonSCAD)
# ==========================================
# Color Tiles Grid (147 colors)
# 作成日: 2026/08/17
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
tile_x = 20.0
tile_y = 20.0
tile_z = 2.0
cols = 12 # 12列
gap = 2.0 # タイル同士のすき間(等間隔)
pitch_x = tile_x + gap
pitch_y = tile_y + gap
# --- 色リスト(ユーザー指定) ---
colors = [
"aliceblue",
"antiquewhite",
"aqua",
"aquamarine",
"azure",
"beige",
"bisque",
"black",
"blanchedalmond",
"blue",
"blueviolet",
"brown",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"coral",
"cornflowerblue",
"cornsilk",
"crimson",
"cyan",
"darkblue",
"darkcyan",
"darkgoldenrod",
"darkgray",
"darkgreen",
"darkgrey",
"darkkhaki",
"darkmagenta",
"darkolivegreen",
"darkorange",
"darkorchid",
"darkred",
"darksalmon",
"darkseagreen",
"darkslateblue",
"darkslategray",
"darkslategrey",
"darkturquoise",
"darkviolet",
"deeppink",
"deepskyblue",
"dimgray",
"dimgrey",
"dodgerblue",
"firebrick",
"floralwhite",
"forestgreen",
"fuchsia",
"gainsboro",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"green",
"greenyellow",
"grey",
"honeydew",
"hotpink",
"indianred",
"indigo",
"ivory",
"khaki",
"lavender",
"lavenderblush",
"lawngreen",
"lemonchiffon",
"lightblue",
"lightcoral",
"lightcyan",
"lightgoldenrodyellow",
"lightgray",
"lightgreen",
"lightgrey",
"lightpink",
"lightsalmon",
"lightseagreen",
"lightskyblue",
"lightslategray",
"lightslategrey",
"lightsteelblue",
"lightyellow",
"lime",
"limegreen",
"linen",
"magenta",
"maroon",
"mediumaquamarine",
"mediumblue",
"mediumorchid",
"mediumpurple",
"mediumseagreen",
"mediumslateblue",
"mediumspringgreen",
"mediumturquoise",
"mediumvioletred",
"midnightblue",
"mintcream",
"mistyrose",
"moccasin",
"navajowhite",
"navy",
"oldlace",
"olive",
"olivedrab",
"orange",
"orangered",
"orchid",
"palegoldenrod",
"palegreen",
"paleturquoise",
"palevioletred",
"papayawhip",
"peachpuff",
"peru",
"pink",
"plum",
"powderblue",
"purple",
"red",
"rosybrown",
"royalblue",
"saddlebrown",
"salmon",
"sandybrown",
"seagreen",
"seashell",
"sienna",
"silver",
"skyblue",
"slateblue",
"slategray",
"slategrey",
"snow",
"springgreen",
"steelblue",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"wheat",
"white",
"whitesmoke",
"yellow",
"yellowgreen",
]
# --- メイン処理 ---
n = len(colors)
rows = (n + cols - 1) // cols # 必要な行数(切り上げ)
# 1枚のタイル(XY中心、Zは厚みの半分だけ上げて「xy平面上」に乗せる)
base_tile = translate(
cube([tile_x, tile_y, tile_z], center=True),
[0, 0, tile_z / 2.0]
)
# グリッドを原点中心に配置するためのオフセット
x0 = -((cols - 1) * pitch_x) / 2.0
y0 = ((rows - 1) * pitch_y) / 2.0
result = None
for i, name in enumerate(colors):
c = i % cols
r = i // cols
x = x0 + c * pitch_x
y = y0 - r * pitch_y
one = translate(color(base_tile, name), [x, y, 0])
result = one if result is None else (result + one)
show(result)
※もし「すき間なし(ぴったり隣接)」が良ければ、gap = 0.0 にしてください。
左上から順に並んでいます。
04. 高さ30, 幅120, 奥行55、各辺は、面取りC5のブロック
完成コード(PythonSCAD)
# ==========================================
# C5 面取りブロック
# 作成日: 2026/08/17
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
width = 120.0 # 幅(X方向)
depth = 55.0 # 奥行き(Y方向)
height = 30.0 # 高さ(Z方向)
chamfer = 5.0 # 面取り C寸法(C5)
# --- 関数(モジュール)定義 ---
def octahedron(c):
"""
面取り用の「八面体」(L1ボール)。
minkowski(直方体, 八面体) にすると、全エッジが45°で均一に面取りされます。
"""
pts = [
[ c, 0, 0], # 0
[-c, 0, 0], # 1
[0, c, 0], # 2
[0, -c, 0], # 3
[0, 0, c], # 4
[0, 0, -c], # 5
]
faces = [
[4, 0, 2],
[4, 2, 1],
[4, 1, 3],
[4, 3, 0],
[5, 2, 0],
[5, 1, 2],
[5, 3, 1],
[5, 0, 3],
]
return polyhedron(points=pts, faces=faces)
def chamfered_block(w, d, h, c):
"""
目標外形 (w,d,h) のC面取りブロックを作る。
外形を狙い通りにするため、芯の直方体は各方向 2*c 小さくしてから minkowski します。
"""
core_w = w - 2.0 * c
core_d = d - 2.0 * c
core_h = h - 2.0 * c
if core_w <= 0 or core_d <= 0 or core_h <= 0:
raise ValueError("chamfer が大きすぎます。w,d,h に対して 2*chamfer 未満にしてください。")
core = cube([core_w, core_d, core_h], center=True)
bevel_tool = octahedron(c)
return minkowski(core, bevel_tool)
# --- メイン処理 ---
result = chamfered_block(width, depth, height, chamfer)
show(result)
(直方体を八面体でMinkowski)だと全エッジが均一に45°面取りになり、角(頂点)も自然に面取り面が付きます。

05. 「角(頂点)は面取りしない」版
完成コード(PythonSCAD)
# ==========================================
# 角(頂点)を残す「止まり面取り(C面取り)」ブロック
# 作成日: 2026/08/17
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
width = 120.0 # 幅(X方向)
depth = 55.0 # 奥行き(Y方向)
height = 30.0 # 高さ(Z方向)
chamfer = 4.0 # 面取り C寸法(C5)
setback = 0 # 頂点から面取りを止める距離(これを >0 にすると「頂点は面取りしない」になる)
eps = 0.05 # チラつき防止&貫通保証の微小値
# --- 関数(モジュール)定義 ---
def tri_prism_along_axis(c, L, axis, d1, d2):
"""
45°面取り用の「直角三角形プリズム」カッターを作る(中心配置)。
axis: 'x'/'y'/'z' ・・・プリズムの長手方向
d1, d2: 面取りが伸びる向き(内側方向)を決める符号付き量(例: -c, +c)
axisが'z'のとき d1=X方向, d2=Y方向
axisが'x'のとき d1=Y方向, d2=Z方向
axisが'y'のとき d1=X方向, d2=Z方向
"""
# 長手方向は中心基準
a0 = -L / 2.0
a1 = L / 2.0
if axis == "z":
# 右角頂点を(0,0)に置き、XとYへ d1, d2 伸ばす。Zに沿って伸ばす。
pts = [
[0, 0, a0],
[d1, 0, a0],
[0, d2, a0],
[0, 0, a1],
[d1, 0, a1],
[0, d2, a1],
]
elif axis == "x":
# Xに沿って伸ばし、断面はYZ
pts = [
[a0, 0, 0],
[a0, d1, 0],
[a0, 0, d2],
[a1, 0, 0],
[a1, d1, 0],
[a1, 0, d2],
]
elif axis == "y":
# Yに沿って伸ばし、断面はXZ
pts = [
[0, a0, 0],
[d1, a0, 0],
[0, a0, d2],
[0, a1, 0],
[d1, a1, 0],
[0, a1, d2],
]
else:
raise ValueError("axis must be 'x', 'y', or 'z'")
# 三角形プリズム(側面の四角は三角2枚に分割して安全に)
faces = [
# bottom / top
[0, 1, 2],
[3, 5, 4],
# side faces (triangulated)
[0, 1, 4], [0, 4, 3],
[1, 2, 5], [1, 5, 4],
[2, 0, 3], [2, 3, 5],
]
return polyhedron(points=pts, faces=faces)
def edge_chamfer_cutter(w, d, h, c, sb, eps_val):
"""
12本のエッジに対して「止まり面取り」カッターを全部まとめて返す。
sb(setback) > 0 にすると、頂点(8箇所)の直近は削られず、角が尖ったまま残る。
"""
# 有効寸法(少しだけ大きくして、面の一致によるチラつきを避ける)
c_eff = c + eps_val
Lx = w - 2.0 * sb
Ly = d - 2.0 * sb
Lz = h - 2.0 * sb
if Lx <= 0 or Ly <= 0 or Lz <= 0:
raise ValueError("setback が大きすぎます。各寸法に対して setback < 対応辺長/2 にしてください。")
# 端面まで確実に削るため、長さだけ少しだけ延ばす(setbackは eps より十分大きい想定)
Lx_cut = Lx + 2.0 * eps_val
Ly_cut = Ly + 2.0 * eps_val
Lz_cut = Lz + 2.0 * eps_val
cutter = None
# ---- Z方向のエッジ(4本):(x=±w/2, y=±d/2) ----
for sx in [-1.0, 1.0]:
for sy in [-1.0, 1.0]:
# 内側方向は -sx, -sy
d1 = (-sx) * c_eff # X方向
d2 = (-sy) * c_eff # Y方向
wedge = tri_prism_along_axis(c_eff, Lz_cut, "z", d1, d2)
# 右角頂点を「少し外側」にずらして、面一致を避ける
px = sx * (w / 2.0 + eps_val)
py = sy * (d / 2.0 + eps_val)
wedge = translate(wedge, [px, py, 0])
cutter = wedge if cutter is None else (cutter + wedge)
# ---- X方向のエッジ(4本):(y=±d/2, z=±h/2) ----
for sy in [-1.0, 1.0]:
for sz in [-1.0, 1.0]:
# 内側方向は -sy, -sz
d1 = (-sy) * c_eff # Y方向
d2 = (-sz) * c_eff # Z方向
wedge = tri_prism_along_axis(c_eff, Lx_cut, "x", d1, d2)
py = sy * (d / 2.0 + eps_val)
pz = sz * (h / 2.0 + eps_val)
wedge = translate(wedge, [0, py, pz])
cutter = cutter + wedge
# ---- Y方向のエッジ(4本):(x=±w/2, z=±h/2) ----
for sx in [-1.0, 1.0]:
for sz in [-1.0, 1.0]:
# 内側方向は -sx, -sz
d1 = (-sx) * c_eff # X方向
d2 = (-sz) * c_eff # Z方向
wedge = tri_prism_along_axis(c_eff, Ly_cut, "y", d1, d2)
px = sx * (w / 2.0 + eps_val)
pz = sz * (h / 2.0 + eps_val)
wedge = translate(wedge, [px, 0, pz])
cutter = cutter + wedge
return cutter
def make_block_with_edge_chamfer_only(w, d, h, c, sb, eps_val):
"""
「エッジはC面取りするが、頂点は残す」ブロック。
※ これは“面取りが頂点まで到達しない(止まり面取り)”という意味での「頂点を面取りしない」です。
"""
body = cube([w, d, h], center=True)
cutter = edge_chamfer_cutter(w, d, h, c, sb, eps_val)
return body - cutter
# --- メイン処理 ---
result = make_block_with_edge_chamfer_only(width, depth, height, chamfer, setback, eps)
show(result)
注意(設計として大事)
「エッジだけ面取りして、頂点は“完全にそのまま”」は、面取りが頂点まで届く限り幾何的に不可能です。なのでここでは機械加工でもよくある “止まり面取り(頂点の手前で面取りを止める)” として実装しています。
「setback を何mmにすべきか」を調整してみてください。
06. 高さ30, 幅120, 奥行55、上面、底面のコーナー面取りC6、他の辺は面取りC3のブロック
完成コード(PythonSCAD)
# ==========================================
# 2段面取りブロック(上面・底面C6、その他C3)
# 作成日: 2026/08/17
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
width = 120.0 # X方向
depth = 55.0 # Y方向
height = 30.0 # Z方向
c_top = 6.0 # 上面・底面の外周エッジ面取り(C6)
c_side = 3.0 # 縦エッジ等の面取り(C3)
eps = 0.15 # チラつき防止用マージン
fn_val = 60 # 今回は円弧なし(将来拡張用)
# --- 関数(モジュール)定義 ---
def sgn(v):
"""符号(+1 / -1)"""
return 1.0 if v >= 0 else -1.0
def wedge_along_x(leg, length_x, y_dir, z_dir):
"""
X方向エッジ用の面取りカッター(45°)
corner(原点)から (Y方向:y_dir) と (Z方向:z_dir) に leg だけ食い込む三角柱
"""
tri = polygon([
[0.0, 0.0],
[-z_dir * leg, 0.0], # 回転後 Z = -x になるので、x側でZ方向を制御
[0.0, y_dir * leg], # yは回転後もY方向
])
prism = linear_extrude(tri, height=length_x)
prism = translate(prism, [0.0, 0.0, -length_x / 2.0]) # 押し出し軸(元Z)でセンター化
prism = rotate(prism, [0.0, 90.0, 0.0]) # 押し出し軸をXへ
return prism
def wedge_along_y(leg, length_y, x_dir, z_dir):
"""
Y方向エッジ用の面取りカッター(45°)
corner(原点)から (X方向:x_dir) と (Z方向:z_dir) に leg だけ食い込む三角柱
"""
tri = polygon([
[0.0, 0.0],
[x_dir * leg, 0.0], # 回転後もX
[0.0, z_dir * leg], # 回転後 Z = y
])
prism = linear_extrude(tri, height=length_y)
prism = translate(prism, [0.0, 0.0, -length_y / 2.0])
prism = rotate(prism, [90.0, 0.0, 0.0]) # 押し出し軸をYへ(符号は対称なのでOK)
return prism
def wedge_along_z(leg, length_z, x_dir, y_dir):
"""
Z方向(縦エッジ)用の面取りカッター(45°)
corner(原点)から (X方向:x_dir) と (Y方向:y_dir) に leg だけ食い込む三角柱
"""
tri = polygon([
[0.0, 0.0],
[x_dir * leg, 0.0],
[0.0, y_dir * leg],
])
prism = linear_extrude(tri, height=length_z)
prism = translate(prism, [0.0, 0.0, -length_z / 2.0])
return prism
def create_body(w, d, h):
"""本体(足す形状)"""
return cube([w, d, h], center=True)
def create_cutter(w, d, h, c6, c3, eps):
"""面取り用カッター(引く形状)を + で1つにまとめる"""
cutter = None
# エッジ長(カッターは少し長めにして確実に貫通させる)
len_x = w + 2.0 * eps
len_y = d + 2.0 * eps
# --- 上面(Z=+h/2)外周エッジ:C6 ---
z_top = +h / 2.0
z_dir_top = -1.0 # 上面から内側へは -Z
# X方向エッジ(Y=±d/2, Z=+h/2)
for y_edge in [+d / 2.0, -d / 2.0]:
y_dir = -sgn(y_edge) # 外側から内側へ
wdg = wedge_along_x(c6, len_x, y_dir=y_dir, z_dir=z_dir_top)
wdg = translate(wdg, [0.0, y_edge, z_top])
cutter = wdg if cutter is None else (cutter + wdg)
# Y方向エッジ(X=±w/2, Z=+h/2)
for x_edge in [+w / 2.0, -w / 2.0]:
x_dir = -sgn(x_edge)
wdg = wedge_along_y(c6, len_y, x_dir=x_dir, z_dir=z_dir_top)
wdg = translate(wdg, [x_edge, 0.0, z_top])
cutter = cutter + wdg
# --- 底面(Z=-h/2)外周エッジ:C6 ---
z_bot = -h / 2.0
z_dir_bot = +1.0 # 底面から内側へは +Z
# X方向エッジ(Y=±d/2, Z=-h/2)
for y_edge in [+d / 2.0, -d / 2.0]:
y_dir = -sgn(y_edge)
wdg = wedge_along_x(c6, len_x, y_dir=y_dir, z_dir=z_dir_bot)
wdg = translate(wdg, [0.0, y_edge, z_bot])
cutter = cutter + wdg
# Y方向エッジ(X=±w/2, Z=-h/2)
for x_edge in [+w / 2.0, -w / 2.0]:
x_dir = -sgn(x_edge)
wdg = wedge_along_y(c6, len_y, x_dir=x_dir, z_dir=z_dir_bot)
wdg = translate(wdg, [x_edge, 0.0, z_bot])
cutter = cutter + wdg
# --- 縦エッジ(Z方向の4本):C3 ---
# 上下面のC6領域に食い込みすぎないよう、縦方向のカッター長を「中央の帯」に制限
mid_len_z = (h - 2.0 * c6)
if mid_len_z <= 0:
# 高さが低すぎて「上下面C6」が干渉する場合は、安全側で縦面取りを無効化
mid_len_z = 0.0
len_z = mid_len_z + 2.0 * eps # わずかに余裕
if len_z > 0:
for x_edge in [+w / 2.0, -w / 2.0]:
for y_edge in [+d / 2.0, -d / 2.0]:
x_dir = -sgn(x_edge)
y_dir = -sgn(y_edge)
wdg = wedge_along_z(c3, len_z, x_dir=x_dir, y_dir=y_dir)
wdg = translate(wdg, [x_edge, y_edge, 0.0]) # 中央帯なのでZ=0中心
cutter = cutter + wdg
return cutter
# --- メイン処理 ---
body = create_body(width, depth, height)
cutter = create_cutter(width, depth, height, c_top, c_side, eps)
result = body - cutter
show(result)
07. previewすると、上面と底面にかぶせた感じで、各コーナーは庇のように、直角に出ています。各コーナーの面取りに合わせて、出っ張りをカットする
完成コード(PythonSCAD)※コーナーの「庇」をカットする版
上面/底面のC6エッジ面取りだけだと、**角(頂点)が未加工で直角の出っ張り(庇)**が残ります。
なので **上下面の4隅(計8頂点)に「頂点用の面取りカッター(四面体)」**を追加して、角もC6に揃えてカットします。
# ==========================================
# 2段面取りブロック(上面・底面C6、他エッジC3)
# コーナー(頂点)の庇を頂点カッターで除去
# 作成日: 2026/08/17
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
width = 120.0 # X方向
depth = 55.0 # Y方向
height = 30.0 # Z方向
c_top = 6.0 # 上面・底面のエッジ面取り(C6)
c_side = 3.0 # その他(主に縦エッジ)の面取り(C3)
eps = 0.15 # チラつき防止用マージン(カッターを少しはみ出させる)
# --- 関数(モジュール)定義 ---
def sgn(v):
"""符号(+1 / -1)"""
return 1.0 if v >= 0 else -1.0
def wedge_along_x(leg, length_x, y_dir, z_dir):
"""
X方向エッジ用の面取りカッター(45°)
corner(原点)から (Y方向:y_dir) と (Z方向:z_dir) に leg だけ食い込む三角柱
"""
tri = polygon([
[0.0, 0.0],
[-z_dir * leg, 0.0], # 回転後 Z = -x になるので、x側でZ方向を制御
[0.0, y_dir * leg],
])
prism = linear_extrude(tri, height=length_x)
prism = translate(prism, [0.0, 0.0, -length_x / 2.0])
prism = rotate(prism, [0.0, 90.0, 0.0]) # 押し出し軸をXへ
return prism
def wedge_along_y(leg, length_y, x_dir, z_dir):
"""
Y方向エッジ用の面取りカッター(45°)
corner(原点)から (X方向:x_dir) と (Z方向:z_dir) に leg だけ食い込む三角柱
"""
tri = polygon([
[0.0, 0.0],
[x_dir * leg, 0.0],
[0.0, z_dir * leg],
])
prism = linear_extrude(tri, height=length_y)
prism = translate(prism, [0.0, 0.0, -length_y / 2.0])
prism = rotate(prism, [90.0, 0.0, 0.0]) # 押し出し軸をYへ
return prism
def wedge_along_z(leg, length_z, x_dir, y_dir):
"""
Z方向(縦エッジ)用の面取りカッター(45°)
corner(原点)から (X方向:x_dir) と (Y方向:y_dir) に leg だけ食い込む三角柱
"""
tri = polygon([
[0.0, 0.0],
[x_dir * leg, 0.0],
[0.0, y_dir * leg],
])
prism = linear_extrude(tri, height=length_z)
prism = translate(prism, [0.0, 0.0, -length_z / 2.0])
return prism
def corner_tetra(leg, x_in, y_in, z_in):
"""
頂点(コーナー)用の面取りカッター:四面体(テトラ)
原点(頂点)から、内側方向 x_in/y_in/z_in に leg 進んだ3点で作る
"""
pts = [
[0.0, 0.0, 0.0],
[x_in * leg, 0.0, 0.0],
[0.0, y_in * leg, 0.0],
[0.0, 0.0, z_in * leg],
]
faces = [
[0, 2, 1],
[0, 1, 3],
[0, 3, 2],
[1, 2, 3],
]
return polyhedron(points=pts, faces=faces)
def create_body(w, d, h):
"""本体(足す形状)"""
return cube([w, d, h], center=True)
def create_cutter(w, d, h, c6, c3, eps):
"""面取り用カッター(引く形状)を + で1つにまとめる"""
cutter = None
# エッジ長(カッターは少し長めにして確実に貫通)
len_x = w + 2.0 * eps
len_y = d + 2.0 * eps
len_z = h + 2.0 * eps
# --- 上面(Z=+h/2)外周エッジ:C6 ---
z_top = +h / 2.0
z_dir_top = -1.0 # 上面から内側へは -Z
# X方向エッジ(Y=±d/2, Z=+h/2)
for y_edge in [+d / 2.0, -d / 2.0]:
y_in = -sgn(y_edge)
wdg = wedge_along_x(c6, len_x, y_dir=y_in, z_dir=z_dir_top)
wdg = translate(wdg, [0.0, y_edge, z_top])
cutter = wdg if cutter is None else (cutter + wdg)
# Y方向エッジ(X=±w/2, Z=+h/2)
for x_edge in [+w / 2.0, -w / 2.0]:
x_in = -sgn(x_edge)
wdg = wedge_along_y(c6, len_y, x_dir=x_in, z_dir=z_dir_top)
wdg = translate(wdg, [x_edge, 0.0, z_top])
cutter = cutter + wdg
# --- 底面(Z=-h/2)外周エッジ:C6 ---
z_bot = -h / 2.0
z_dir_bot = +1.0 # 底面から内側へは +Z
# X方向エッジ(Y=±d/2, Z=-h/2)
for y_edge in [+d / 2.0, -d / 2.0]:
y_in = -sgn(y_edge)
wdg = wedge_along_x(c6, len_x, y_dir=y_in, z_dir=z_dir_bot)
wdg = translate(wdg, [0.0, y_edge, z_bot])
cutter = cutter + wdg
# Y方向エッジ(X=±w/2, Z=-h/2)
for x_edge in [+w / 2.0, -w / 2.0]:
x_in = -sgn(x_edge)
wdg = wedge_along_y(c6, len_y, x_dir=x_in, z_dir=z_dir_bot)
wdg = translate(wdg, [x_edge, 0.0, z_bot])
cutter = cutter + wdg
# --- 縦エッジ(Z方向の4本):C3(高さ方向に全部)---
# 「他の辺はC3」なので、縦エッジは全高に適用しておく方が自然です
for x_edge in [+w / 2.0, -w / 2.0]:
for y_edge in [+d / 2.0, -d / 2.0]:
x_in = -sgn(x_edge)
y_in = -sgn(y_edge)
wdg = wedge_along_z(c3, len_z, x_dir=x_in, y_dir=y_in)
wdg = translate(wdg, [x_edge, y_edge, 0.0])
cutter = cutter + wdg
# --- ★追加:上下面の「頂点(コーナー)」用C6カッター(庇を消す本命)---
# 角の一点が残ると、プレビューで「直角の出っ張り」に見えます
for z_face, z_in in [(+h / 2.0, -1.0), (-h / 2.0, +1.0)]:
for x_edge in [+w / 2.0, -w / 2.0]:
for y_edge in [+d / 2.0, -d / 2.0]:
x_in = -sgn(x_edge)
y_in = -sgn(y_edge)
tet = corner_tetra(c6, x_in=x_in, y_in=y_in, z_in=z_in)
# カッターが「外側にも少し」出るように頂点をepsだけ外へ逃がす
corner_pos = [
x_edge - x_in * eps,
y_edge - y_in * eps,
z_face - z_in * eps,
]
tet = translate(tet, corner_pos)
cutter = cutter + tet
return cutter
# --- メイン処理 ---
body = create_body(width, depth, height)
cutter = create_cutter(width, depth, height, c_top, c_side, eps)
result = body - cutter
show(result)
2. 何が変わったか
-
以前:上面/底面の「エッジ」だけC6 → 頂点(角の一点)が残って庇っぽい直角が出る
-
今回:頂点用の四面体カッターも追加 → 上面/底面の角もスパッと落ちて、見た目が自然になります
-
カッター作成 : cutter = create_cutter(width, depth, height, c_top, c_side, eps)

c_top = 3.0 # 上面・底面のエッジ面取り(C3)
c_side = 6.0 # その他(主に縦エッジ)の面取り(C6)
08. 例:カッター作成・確認する
from pythonscad import *
def octahedron(c):
"""
面取り用の「八面体」(L1ボール)。
minkowski(直方体, 八面体) にすると、全エッジが45°で均一に面取りされます。
"""
pts = [
[ c, 0, 0], # 0
[-c, 0, 0], # 1
[0, c, 0], # 2
[0, -c, 0], # 3
[0, 0, c], # 4
[0, 0, -c], # 5
]
faces = [
[4, 0, 2],
[4, 2, 1],
[4, 1, 3],
[4, 3, 0],
[5, 2, 0],
[5, 1, 2],
[5, 3, 1],
[5, 0, 3],
]
return polyhedron(points=pts, faces=faces)
c=6
bevel_tool = octahedron(c)
show(bevel_tool)
09. cube(5)を間隔3で、xy方向にカラフルな色で、3 x 3で並べる
1. 完成コード(PythonSCAD)
# ==========================================
# 3x3 カラフルキューブ配列
# 作成日: 2026/08/17
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
cube_size = 5.0 # 1個の立方体の一辺
gap_xy = 3.0 # 立方体どうしの「すき間」
step = cube_size + gap_xy # 中心間ピッチ
z0 = 0.0
colors_9 = [
"tomato", "gold", "limegreen",
"deepskyblue", "royalblue", "violet",
"orange", "springgreen", "hotpink",
]
# --- メイン処理 ---
result = None
idx = 0
for ix in [-1, 0, 1]:
for iy in [-1, 0, 1]:
x = ix * step
y = iy * step
block = cube([cube_size, cube_size, cube_size], center=True)
block = translate(block, [x, y, z0])
block = color(block, colors_9[idx])
result = block if result is None else (result + block)
idx += 1
show(result)
2. 完成コード(PythonSCAD)
# ==========================================
# 3x3 カラフルキューブ配列(XY方向)
# 作成日: 2026/07/25
# ==========================================
from pythonscad import *
# --- パラメータ設定 (単位: mm) ---
cube_size = 5 # 立方体の一辺
gap = 3 # 立方体どうしの「すき間」
n_x = 3 # X方向の個数
n_y = 3 # Y方向の個数
# 配置ピッチ(中心-中心の距離)
pitch = cube_size + gap
# カラーパレット(9色)
# ※ color(obj, [R,G,B]) は 0.0〜1.0 の範囲で指定します
palette = [
[1.0, 0.2, 0.2], # 赤
[1.0, 0.6, 0.2], # オレンジ
[1.0, 1.0, 0.2], # 黄
[0.2, 1.0, 0.2], # 緑
[0.2, 1.0, 1.0], # シアン
[0.2, 0.6, 1.0], # 水色
[0.2, 0.2, 1.0], # 青
[0.7, 0.2, 1.0], # 紫
[1.0, 0.2, 0.7], # ピンク
]
# --- メイン処理 ---
result = None
idx = 0
for ix in range(n_x):
for iy in range(n_y):
# 1) 立方体(center=True で原点中心の形状にする)
one = cube([cube_size, cube_size, cube_size], center=True)
# 2) 色を付ける(9個なので palette を順番に割り当て)
one = color(one, palette[idx % len(palette)])
# 3) XY方向へ等間隔に並べる(全体が原点中心になるようにオフセット)
x = (ix - (n_x - 1) / 2) * pitch
y = (iy - (n_y - 1) / 2) * pitch
one = translate(one, [x, y, 0])
# 4) 形状を足し合わせて集合にする(+ 演算子で結合)
result = one if result is None else (result + one)
idx += 1
# 3Dプレビュー表示
show(result)
必要なら、「色を規則的(X方向が赤→青のグラデーション等)」にするなど、考えてみましょう。

参考資料









