0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今回はOpenSCADからPythonSCADへの変換です。
OpenSCADコミュニティ・著者に感謝申し上げます。ありがとうございます。
以下のOpenSCADのkindle本を参考にしました。
初心者に理解しやすい、コンパクトにまとめてある本です。3Dプリンターで製作するところまで詳しく書かれています。高評価の本です。

参考kindle本:
Leithauser, David. Creating 3D Models for 3D Printing Using OpenSCAD (English Edition) . Leithauser Research. Kindle 版.

以下、記事内のコードをPythonSCADにコピペして、previewしてみてください。renderボタンでも確認してみてください。
Pythonの繰り返し構文forについても、またモデルを作成していくうえでの注意点など、解説しています。くりかえし、くりかえし、やっていきましょう。ありがとうございます

1. ステップ状に並ぶキューブ

  • OpenSCAD
for(X = [10:10:50]) translate([X,0,0]) cube([10,10, 2 * X]);

OpenSCADの for ループは、3Dモデルを規則的に並べるときにとても便利です。PythonSCAD(Python)でも for ループを使うと、より柔軟にプログラミングの制御を学ぶことができます。

Pythonで3Dパーツを並べる場合は、「ループの中でパーツを作ってリストに集め、最後に +(結合)演算子でまとめる」 という流れにするのが基本です。

1. 完成コード(PythonSCAD)

# ==========================================
# [ステップ状に並ぶキューブ]
# 作成日: 2026/08/13
# ==========================================

from pythonscad import *
from math import pi, sin, cos  # 数学関数・定数のインポート(ルールにより必須)

# --- パラメータ設定 (単位: mm) ---
start_x = 10   # Xの開始値
end_x = 50     # Xの終了値
step_x = 10    # Xの増加量

cube_w = 10    # キューブの幅(X方向)
cube_d = 10    # キューブの奥行き(Y方向)

# --- メイン処理 ---

# 作成したパーツを一時的に保存するリスト
parts = []

# Pythonのrange関数で 10, 20, 30, 40, 50 の値を生成する
# ※rangeは指定した「終了値」を含まないため、+ step_x をして 60 未満まで回します
for X in range(start_x, end_x + step_x, step_x):
    
    # 1. 基本となるキューブを原点 [0,0,0] 中心に作成
    # 高さは X の2倍 (2 * X)
    c = cube([cube_w, cube_d, 2 * X], center=True)
    
    # 2. キューブを X 軸方向に X mm移動させる
    # PythonSCADでは translate(対象オブジェクト, [x, y, z]) の順に書きます
    moved_c = translate(c, [X, 0, 0])
    
    # 3. 完成したキューブをリストに追加
    parts.append(moved_c)

# --- 結合処理 ---
# OpenSCADのfor文は自動で union (結合) されますが、
# PythonSCADではリストに集めたパーツを「+」演算子で結合します

result = parts[0]
for i in range(1, len(parts)):
    result = result + parts[i]

# 3Dプレビュー表示
show(result)


2. 解説とポイント

  1. for文と range() の使い方
    OpenSCADの for(X = [10:10:50]) は「10から50まで10刻み」という意味ですが、Pythonの range(開始, 終了, 刻み幅)終了値を含まないというルールがあります。そのため、range(10, 60, 10)(変数で end_x + step_x)として「60の手前、つまり50まで」回すように工夫しています。
  2. パーツの結合(+ 演算子)
    OpenSCADでは for 文を書くだけで自動的にすべての形がくっつきます(暗黙のUnion)が、PythonSCADでは明示的に結合する必要があります。
    今回は、空のリスト parts = [] を用意し、ループ内で append(追加)していき、最後に + を使ってひとつのオブジェクトにまとめ上げる手法を取りました。
  3. center = True による原点基準の統一
    cube は原点(0,0,0)を中心として作成しています。OpenSCADのデフォルト(左下隅が基準)とは見え方が少し異なるかもしれませんが、3D CADや機械製図の世界では「常に重心や中心を原点に合わせて設計する」のがミスを防ぐ鉄則です。

Screenshot 2026-08-13 18.51.24.png

  1. translate 関数の書き方(重要)
    OpenSCAD特有の translate([X,0,0])(cube) といった「カッコを2つ並べる書き方」は、Pythonではエラー(TypeError)になってしまいます。必ず translate(動かしたいモノ, [X, Y, Z]) というように、モノを第一引数に渡す書き方に慣れていきましょう。

この構造をマスターすれば、階段状のパーツやギアの歯など、規則的に並ぶ複雑な3D形状もPythonのパワーを使って簡単にプログラムできるようになります。

3. 別の書き方(if文を使う方法)

# ==========================================
# OpenSCAD for/translate/cube の変換例
# 作成日: 2026/08/12
# ==========================================

from pythonscad import *

# --- パラメータ設定 (単位: mm) ---
x_start = 10
x_end   = 50
x_step  = 10

cube_w = 10.0   # cube のXサイズ
cube_d = 10.0   # cube のYサイズ
h_mul  = 2.0    # 高さ = h_mul * X

# --- 関数(モジュール)定義 ---
def create_column(x):
    """OpenSCAD: translate([x,0,0]) cube([10,10,2*x]); 相当"""
    col = cube([cube_w, cube_d, h_mul * x], center=False)  # OpenSCADのcubeはcenter=false相当
    col = translate(col, [x, 0, 0])
    return col

# --- メイン処理 ---
result = None
for x in range(x_start, x_end + 1, x_step):
    part = create_column(x)
    result = part if result is None else (result + part)

show(result)

Screenshot 2026-08-13 18.53.01.png

このコードは、OpenSCAD の

for(X = [10:10:50]) translate([X,0,0]) cube([10,10, 2 * X]);

と同じく、X=10,20,30,40,50 の位置に「高さが 2*X」の角柱を並べます。


前のコード(リストを使った方法)と、今回のresult = Noneif 文を使った方法の動作自体は全く同じ(同じ形ができます)ですが、「なぜそのように書くのか」「どちらが理解しやすいか」に少し違いがあります。

高校生に向けたプログラミングの授業として、それぞれの考え方の違いを解説しますね!


今回のコード(if文を使う方法)の特徴

# --- メイン処理 ---
result = None
for x in range(x_start, x_end + 1, x_step):
    part = create_column(x)
    result = part if result is None else (result + part)

この書き方は、「雪だるま式」 にパーツをくっつけていく考え方です。

  1. result = None
    最初は「まだ何もないよ(空っぽ)」という印(None)を result という箱に入れておきます。
  2. for x in ...(ループ開始)
  • 1回目のループ(X=10):パーツ(part)を作ります。
  • result = part if result is None else ...
    ここがポイントです。「もし result が空っぽ(None)だったら、今作った part をそのまま result にしてね。そうじゃなかったら、今の result に新しい part を足し合わせてね(+)」という意味です。
  • 1回目は空っぽなので、result は「最初のパーツ」になります。
  • 2回目(X=20):パーツを作ります。今度は result は空っぽじゃないので、else の後の (result + part) が実行され、「最初のパーツ + 2番目のパーツ」になります。
  • 3回目以降も、どんどん新しいパーツが足されていきます。

メリットとデメリット

  • メリット: メモリ(コンピュータの作業スペース)を少し節約できる場合があります(リストという入れ物を作らないため)。プロのプログラマーは「無駄な変数(リスト)を作らない」ために好んで使うことがあります。
  • デメリット: パッと見たときに if result is None else ... という条件分岐(三項演算子と呼ばれる少し高度な書き方)が複雑で、初心者には「何をしているのか」直感的に分かりにくいです。「足し算(結合)」と「最初の設定」がごちゃまぜになってしまっています。

前回のコード(リストを使う方法)の特徴

# --- メイン処理 ---
parts = [] # 空のリスト(箱)を用意

for X in range(start_x, end_x + step_x, step_x):
    # パーツを作る処理...
    parts.append(moved_c) # 箱にパーツをポンポン入れていく

# --- 結合処理 ---
result = parts[0] # 箱の1番目を取り出す
for i in range(1, len(parts)):
    result = result + parts[i] # 2番目以降を順番にくっつける

この書き方は、「材料集め」と「組み立て」を分ける 考え方です。

  1. parts = []
    最初にパーツを入れるための「大きな箱(リスト)」を用意します。
  2. 最初の for ループ(材料集め)
    パーツを作っては、ひたすら箱の中(parts)に放り込んでいきます(append)。この時点では、パーツはまだバラバラです。
  3. 次の for ループ(組み立て)
    箱に入っているパーツを全部取り出して、+ でくっつけていきます。

メリットとデメリット

  • メリット: 「何をしているか」がとても分かりやすいです。「部品を作ってリストに集める作業」と「集めた部品を合体させる作業」が完全に分かれているので、頭の中でイメージしやすく、後から「部品の数だけ確認したい」といった変更もしやすいです。プログラミングの基礎である「リスト(配列)」の使い方の良い練習にもなります
  • デメリット: 一度リストにすべて保存するため、膨大な数のパーツ(何万個など)を作る場合は、コンピュータのメモリを少し多く使うことになります(通常の高校の課題レベルであれば全く問題ありません)

先生からのアドバイス(どちらを使うべきか?)

高校の授業などで初めてPythonSCADに触れる生徒さんには、圧倒的に「リストを使う方法(前回)」をおすすめします!

理由は以下の通りです。

  1. 「集める」→「くっつける」という現実のものづくり(プラモデルなど)の工程に近いため、イメージしやすい
  2. append(リストに追加)という、Pythonで非常によく使う重要な命令を自然に学べる。
  3. 複雑な条件分岐(if ... None)を見なくて済むので、「どうやって形を作るか(Xの値の計算など)」に集中できる

今回の result = None を使う方法は、「少しカッコいい(プロっぽい)書き方」ですが、まずはリストを使った「分かりやすい、確実な書き方」をマスターしてから、ステップアップとして挑戦するのが良いでしょう。

4. center=Falsecenter=True の違い

プログラミングや3D CADを学ぶ上で、その「基準がどこにあるか(原点の位置)」に気にしてほしいところです。ものすごく重要です。
OpenSCADの cube(および cylinder など)は、何も指定しないと center=false(Pythonでは False)が基本仕様になっています。

center の違いによって、プレビュー画面(原点を示すXYZの線)との位置関係がどう変わるのか

1. center=False (OpenSCADのデフォルト)

原点 [0, 0, 0] を「左下の隅っこ(スタート地点)」として、そこからプラスの方向(X, Y, Z方向)に向かって箱が伸びていきます。

  • イメージ: 部屋の角(コーナー)にぴったり箱を置くような感覚です。
  • メリット: 「端から何ミリのところに穴を開ける」といった、端を基準にした計算がしやすいです。

2. center=True (推奨している書き方)

原点 [0, 0, 0] を箱の「おへそ(ど真ん中・重心)」として、前後左右・上下に均等に広がって箱が作られます。

  • イメージ: 部屋のど真ん中に、バランスよく箱を置く感覚です。
  • メリット: 車のタイヤやロボットの胴体など、「左右対称」なものを作るときに計算が圧倒的にラクになります!

なぜ先生は center=True を基本ルールにしているの?

前回のコードで、cube(..., center=True) と書いたり、「center=True に統一する」というルールを入れているのには、機械設計や3Dモデリングのプロの世界の鉄則が関係しています。

ものづくり(とくに3D CAD)では、「モノの中心(重心)を、空間の中心(原点)に合わせる」のが基本中の基本なんです。

たとえば、車を作るとき。

  • 車体を原点中心(center=True)で作っておけば、右タイヤを X = 50 の位置に置いたら、左タイヤは X = -50 と、マイナスをつけるだけで反対側に置けます
  • もし center=False で車体を作ってしまうと、「車体の幅が 100 だから、中心は 50 で、そこから 50 離して……」と、頭の中で複雑な足し算・引き算をしなければならず、バグ(設計ミス)の原因になってしまいます

PythonSCAD での書き方の注意点(大文字・小文字)

ちなみに、OpenSCADでは小文字で center=false / center=true と書きますが、Pythonの文法では**必ず大文字始まりの False / True** になります。ここもPythonを学ぶ上での大事なポイントです!

自分で形を作るとき、「この部品は端っこ基準がいいかな? ど真ん中基準がいいかな?」と考えながら center を使い分けられるようになると、モデリングの腕がグッと上がります。

5. ステップ状に並ぶ球体

  • OpenSCAD
for(X = [0 : 10 : 50]) translate([X, 0, 0]) sphere(5);

「リストを使う方法」を使って、球体(sphere)を等間隔に並べるプログラムを作ってみましょう。

for(X = [0 : 10 : 50]) ということは、「X座標が 0, 10, 20, 30, 40, 50 の位置に球を作る」ということになります。
Pythonの range 関数でこの数値のリストをどうやって作るかがポイントです。

1. 完成コード(PythonSCAD)

# ==========================================
# [ステップ状に並ぶ球体]
# 作成日: 2026/08/13
# ==========================================

from pythonscad import *

# --- パラメータ設定 (単位: mm) ---
start_x = 0     # Xの開始値
end_x   = 50    # Xの終了値
step_x  = 10    # Xの増加量

sphere_r = 5    # 球体の半径
fn_val   = 60   # 球の滑らかさ

# --- メイン処理 ---

# 作成したパーツを一時的に保存する空のリスト
parts = []

# Pythonのrange関数で 0, 10, 20, 30, 40, 50 の値を生成する
# ※rangeは指定した「終了値」を含まないため、+ step_x (10) をして 60 未満まで回します
for X in range(start_x, end_x + step_x, step_x):
    
    # 1. 基本となる球体を原点 [0,0,0] に作成
    # fn_val を指定して、表面を滑らかにします
    s = sphere(r=sphere_r, fn=fn_val)
    
    # 2. 球体を X 軸方向に X mm移動させる
    # translate(対象オブジェクト, [x, y, z]) の順で指定します
    moved_s = translate(s, [X, 0, 0])
    
    # 3. リストに移動済みの球体を追加
    parts.append(moved_s)

# --- 結合処理 ---
# リストに集めたすべてのパーツを「+」演算子で結合します
result = parts[0]
for i in range(1, len(parts)):
    result = result + parts[i]

# 3Dプレビュー表示
show(result)

Screenshot 2026-08-13 19.09.34.png


2. 解説とポイント

  1. range() 関数のおさらい
    前回のキューブのときと同じですね。range(0, 60, 10) とすることで、X には 0, 10, 20, 30, 40, 50 という数字が順番に入ってループが回ります。
  2. sphere() 関数の使い方
    OpenSCAD では sphere(5); と書きますが、PythonSCAD(そして私が指導するルール)では、どの数字が何を意味するのかを明確にするため r=5 のように名前(引数名)をつけて指定します。
    また、球体をカクカクさせずに綺麗に見せるため、fn=fn_val(今回は60)を追加しています。PythonSCADでは $fn=60 と書くとエラーになるので注意してくださいね。
  3. リストを使った結合(前回の復習)
    parts = [] という空の箱を用意して、ループの中で作った球体を append でどんどん投げ入れていきます。
    そして最後に、箱から一つずつ取り出して + でくっつける(結合・Union)処理をしています。この考え方は、3Dモデリングだけでなく、Pythonプログラミング全般でとてもよく使う強力なテクニックです。

原点(0)からスタートして、等間隔にポン、ポン、ポンと球体が並びます。

6. ステップ状に並ぶ球体、別の書き方(while文を使う方法)

# ==========================================
# OpenSCAD: for(X=[0:10:50]) translate([X,0,0]) sphere(5);
# を PythonSCAD に変換
# 作成日: 2026/08/12
# ==========================================

from pythonscad import *

# --- パラメータ設定 (単位: mm) ---
r_sphere = 5.0
x_start  = 0.0
x_end    = 50.0
x_step   = 10.0
fn_val   = 60  # 球の滑らかさ

# --- メイン処理 ---
result = None
x = x_start

# OpenSCADの [0:10:50] 相当(終点を含む)
while x <= x_end + 1e-9:
    s = translate(sphere(r=r_sphere, fn=fn_val), [x, 0, 0])
    result = s if result is None else (result + s)
    x += x_step

show(result)

Screenshot 2026-08-13 21.25.17.png


1. この書き方はよく使うの?

結論から言うと、科学技術計算、ゲーム開発、そして3D CAD(PythonSCADを含む)など、「小数」をループ(繰り返し)で扱うプログラミングの世界では、非常によく使うプロのテクニックです。

この 1e-9 (0.000000001 のこと)は、プログラミング用語で「許容誤差(イプシロン:$\epsilon$)」「安全マージン」と呼ばれます。

+ 1e-9 は「誤差対策のための小さな余裕」です。

なぜ必要?

Python の 0.10.01 みたいな小数は、内部では2進数で完全に表せないことが多く、足し算を繰り返すと

  • 本当は x == 50.0 になってほしいのに
  • 計算結果が 50.0000000000000149.99999999999999

のようにズレることがあります。

その結果、while x <= x_end: だと 最後の 50 が条件判定で外れて、球が 1個足りない…という事故が起きます。
そこで x_end + 1e-9 のように「ほんの少しだけ大きくして」最後を確実に含めます。

1e-9 ってどのくらい?

1e-9 = 0.000000001(10億分の1)で、mm単位のモデリングでは無視できるくらい小さい値です。
「見た目や寸法は変えずに、条件判定だけ安全にする」ための値です。

2. なぜ 1e-9 を足す必要があるの?(浮動小数点誤差の罠)

私たちが普段使っている「10進数」の世界では、$0.1 + 0.1 = 0.2$ ですよね。
しかし、コンピュータはすべての数字を「0」と「1」の「2進数」で計算しています。

実は、10進数の「0.1」のような小数を2進数に変換しようとすると、「0.0001100110011...」のように無限に続く小数(循環小数)になってしまいます。コンピュータのメモリは無限ではないので、途中で数値をバッサリと切り捨てます。

そのため、Pythonで小数の足し算を繰り返すと、以下のような「ごくわずかなズレ」が発生します。

# Pythonの内部で起きていることのイメージ
0.0 + 10.0 = 10.0
10.0 + 10.0 = 20.0
...
40.0 + 10.0 = 50.00000000000001  # ピッタリ50.0にならないことがある!

もし、コードを while x <= x_end:(つまり x <= 50.0)と書いていた場合、最後の計算結果が 50.00000000000001 になってしまうと……
「50.0を超えているから、このループはここで終わりにしよう!」とコンピュータが判断してしまい、X=50 の位置にあるはずの最後の球体が作られずに消えてしまうというバグ(不具合)が起きます。

これを防ぐために、while x <= 50.0 + 1e-9:(50.000000001 以下ならOK)と、ほんの少しだけ「判定のゴールラインを後ろにズラしてあげる」ことで、計算のズレを吸収しているのです。

3. 「今回の while文」と「前回の for文 + range」の違い

今回ご提示いただいたコードと、前回私が書いたコード(rangeを使用)には、それぞれ得意なことがあります。

forrange() を使う方法(前回の方法)

# 整数しか使えないが、絶対にズレない
for x in range(0, 60, 10):

  • 特徴: range 関数は「整数」しか扱えません。コンピュータは整数の計算なら絶対にズレを起こさないので、1e-9 のようなマージンを考える必要がなく、安全でスッキリ書けます
  • デメリット: 「1.5 mm 間隔で並べたい」といった小数のステップが使えません

while と 小数 を使う方法(今回提示していただいた方法)

# 小数ステップが使えるが、誤差対策が必要
x = 0.0
while x <= 50.0 + 1e-9:
    # 処理...
    x += 10.0

  • 特徴: x += 1.5 のように、細かい小数のステップでパーツを並べたいときに大活躍します。3Dモデリングでは小数の寸法を扱うことが多いので、この書き方が必要になる場面が必ず来ます
  • デメリット: 前述の通り、1e-9 のような誤差対策(安全マージン)を忘れると、最後の1個が消えるバグに悩まされることになります

先生からのまとめ

「コンピュータは計算ミスをしない」と思われがちですが、「小数の計算は少しだけ苦手(誤差が出る)」というのは、情報科や工業科でプログラミングを学ぶ上で絶対に知っておくべき超重要ポイントです。

  • 10mm, 20mm と「整数」で並べるとき は、前回学んだ for x in range(...) を使うのがバグが起きにくくてオススメです
  • 1.5mm, 2.2mm など「小数」で細かく並べるとき は、今回ご提示いただいた while1e-9 (安全マージン)のテクニックを使いましょう

0
0
3

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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?