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?

【PythonSCAD】メソッドチェーンを使って、トーラス(ドーナツ型)や、バネのような形を作りたい

0
Last updated at Posted at 2026-08-09

PythonSCADコミュニティ・開発者に感謝申し上げます。ありがとうございます。

  • rotate_extrude
    Extrude a 2D shape by rotating it around the Z axis.

  • Syntax:

rotate_extrude(obj, convexity=1, scale=1.0, angle=360, twist=None,
origin=None, offset=None, v=None, method=None)
obj.rotate_extrude(...)

今回は、メソッドチェーンをつかって、トーラス(torus)や、ばねのような形をつくるために、rotate_extrude()(回転押し出し)を使います。ろくろを回すように2D図形から立体を作る機能で、滑らかな曲線を持つパーツを作るのに大活躍します。

3D CADの世界では「回転」に関する押し出し方は大きく2つに分かれます。

  • その場でぐるぐる回す(トーラスなど) = rotate_extrude()

  • 上に引き伸ばしながら回す(ばね・スクリューなど) = linear_extrude(twist=...)

1. トーラス(ドーナツ)とバネの生成

完成コード(PythonSCAD)

# ==========================================
# トーラス(ドーナツ)とバネの生成(メソッドチェーン記法)
# 作成日: 2026/08/03
# ==========================================

from pythonscad import *
from math import pi, sin, cos  # 数学関数(今回は直接使いませんが、円の計算の基礎としてインポートしておきます)

# --- パラメータ設定 (単位: mm) ---
fn_val = 60          # 円・球の滑らかさ(3Dプリントでも十分綺麗に出る数値)

# 1. トーラス(ドーナツ)用パラメータ
torus_r_main = 20    # ドーナツ全体の半径(中心から輪の中心まで)
torus_r_sub  = 5     # 断面(食べる部分)の半径

# 2. ばね用パラメータ
spring_r = 15        # ばね全体の半径
wire_r   = 2         # ばねの線の半径
spring_h = 50        # ばねの全体の高さ
coils    = 5         # ばねの巻き数
twist_angle = 360 * coils  # ひねる合計角度(360度 × 巻き数)
spring_slices = 200  # 押し出し時の分割数(バネを滑らかにするため多めに設定)

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

# 【形状1】 トーラス(ドーナツ型)
# 手順:
# 1. circle() で断面の円を作る
# 2. translate() で原点からX方向に「ドーナツの半径分」ずらす
# 3. rotate_extrude() で原点(Z軸)を中心にぐるっと360度回転させて押し出す
# 4. 見やすいように色を付け、左側(X: -30)に移動させる
torus = (
    circle(r=torus_r_sub, fn=fn_val)
    .translate([torus_r_main, 0, 0])
    .rotate_extrude(angle=360, fn=fn_val)
    .color("orange")
    .translate([-30, 0, 0])
)

# 【形状2】 ばね(スパイラル型)
# 手順:
# 1. circle() でバネの線の円を作る
# 2. translate() で原点からX方向に「ばねの半径分」ずらす
# 3. linear_extrude(twist=...) で上に押し出しながら指定角度分ひねる!
# 4. 見やすいように色を付け、右側(X: 30)に移動させる
spring = (
    circle(r=wire_r, fn=fn_val)
    .translate([spring_r, 0, 0])
    .linear_extrude(height=spring_h, twist=twist_angle, slices=spring_slices)
    .color("silver")
    .translate([30, 0, 0])
)

# --- 結合と表示 ---
# 2つのパーツを足し算で1つのシーンにまとめ、最後に1回だけ表示します
result = torus + spring
show(result)

スクリーンショット 2026-08-09 152037.png


解説ポイント 💡

1. トーラスの作り方(rotate_extrude

rotate_extrude() は、2D図形(今回は円)を Z軸を中心に ぐるっと回して3Dにする関数です。
注意点として、回すための2D図形がZ軸(原点)に重なっていると自分自身にぶつかってエラーになってしまいます。そのため、translate([torus_r_main, 0, 0]) を使って、あらかじめ原点から少し離れた位置(X軸方向)に図形をずらしておくのがコツです。

2. ばねの作り方(linear_extrude + twist

「ばね」のように高さを出しながら回転させる形状は、実は rotate_extrude ではなく、直線押し出しの linear_extrudetwist(ひねり角度) というパラメータを追加して作ります。
Z軸から少し離れた位置に置いた円を、上に引っ張り上げながら雑巾を絞るようにグルグルとひねることで、綺麗なバネ形状(ヘリカル形状)になります。

3. メソッドチェーンの改行テクニック

今回のコードでは、カッコ () で全体を囲むことで、メソッドチェーンを改行して記述しました。

torus = (
    circle()
    .translate()
    .rotate_extrude()
)

2. ばねは、平たい、厚みがないまま、回転しています。circleをrotx(obj, 90) # rotate around X axisが必要だと思いますが。

本当のバネ(真円の断面)を作るには、円の断面を進行方向に向けて立てる(X軸周りに90度回転させる)必要があります。

しかし、ここに3D CAD特有の少し厄介なルールがあります。
linear_extrude(押し出し)は、XY平面にペタッと置かれた2D図形(circle)しか押し出せない」のです。そのため、circlerotate(obj, [0, 90, 0]) のように3D空間で立ててしまうと、エラーになってしまうか、うまくモデリングできません。

spring = (
    circle(r=wire_r, fn=fn_val)
    .rotate([0, 90, 0]) #回転
    .translate([spring_r, 0, 0])
    .linear_extrude(height=spring_h, twist=twist_angle, slices=spring_slices)
    .color("silver")
    .translate([30, 0, 0])
)

スクリーンショット 2026-08-09 161305.png

そこで今回は、CADの制限を突破するために「Pythonのプログラミングの力(繰り返し処理 for と、数学の sin cos)」を使って、真円のバネを作る実践的な方法を使います。


完成コード(PythonSCAD)

# ==========================================
# 真円断面のスパイラルばね(球の連続配置)
# 作成日: 2026/08/03
# ==========================================

from pythonscad import *
from math import pi, sin, cos  # 円周の計算(三角関数)に必須の数学モジュール

# --- パラメータ設定 (単位: mm) ---
spring_r = 15      # ばね全体の半径
wire_r   = 2       # ばねの線の半径 (真円)
spring_h = 50      # ばねの全体の高さ
coils    = 5       # ばねの巻き数

fn_val   = 16      # 球の滑らかさ (数が多いと重くなるため少なめに設定)
steps    = 40      # 1巻きあたりの分割数(どれくらい細かく球を置くか)

# --- 関数(モジュール)定義 ---

# 1. 完璧な真円断面のバネを生成する関数
def true_spring(radius, wire_radius, height, turns, resolution, fn):
    segments = []  # 繋いだパーツを一時的に保存するリスト(箱)
    
    total_steps = turns * resolution
    height_per_step = height / total_steps
    
    # 1つ前の球を記憶しておくための変数
    prev_sphere = None
    
    # for文(繰り返し)を使って、らせん階段のように少しずつ上りながら球を配置する
    for i in range(total_steps + 1):
        # 進行度合いから、現在の角度(ラジアン)を計算
        angle = (i / resolution) * 2 * pi
        
        # 三角関数を使って円周上の座標(X, Y)を計算
        x = radius * cos(angle)
        y = radius * sin(angle)
        
        # 現在の高さ(Z)を計算
        z = height_per_step * i
        
        # 現在の地点 [x, y, z] に 3Dの球(sphere)を配置
        # center=True の代わりに sphere はデフォルトで原点中心に作られます
        current_sphere = translate(sphere(r=wire_radius, fn=fn), [x, y, z])
        
        # 最初の1回目以外は、前の球と今の球を「hull(包む)」で繋いで隙間を埋める
        if prev_sphere is not None:
            # hull関数は、2つの図形にラップをかけるように滑らかに繋ぐ魔法の機能です
            segment = hull(prev_sphere, current_sphere)
            segments.append(segment)
        
        # 今の球を「前の球」として上書き記憶し、次のループへ進む
        prev_sphere = current_sphere
        
    # リストに溜まったたくさんの短い円柱を、+演算子で1つのパーツに合体させる
    result_spring = segments[0]
    for seg in segments[1:]:
        result_spring = result_spring + seg
        
    return result_spring

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

# バネ関数の呼び出し
my_spring = true_spring(spring_r, wire_r, spring_h, coils, steps, fn_val)

# 見やすいように色を付ける
final_model = color(my_spring, "gold")

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

スクリーンショット 2026-08-09 153024.png


解説ポイント 💡

1. CADの限界を「Pythonのループ」で突破する

2D図形を引き伸ばす機能が使えないなら、「3Dの球(sphere)をらせん状にたくさん並べて、隙間を埋めればいいじゃないか」というのが、このプログラムの考え方です。
for 文を使うことで、手作業なら何百回も書かなければならない計算を、たった数行で終わらせています。これがプログラミングでものづくりをする最大のメリットです。

2. 三角関数(sincos)の実用例

高校の数学で習うサイン・コサインですが、「これ、一体何に使うの?」と思ったことはありませんか?
実は、3Dグラフィックスやゲームプログラミングでは「円を描くための最強の道具」です。

  • x = 半径 * cos(角度)
  • y = 半径 * sin(角度)
    この公式を使うだけで、コンピュータが自動で綺麗な円周上の座標を計算してくれます。

3. 便利なラッピング関数 hull()

点をたくさん置くだけだと「点線」のような隙間だらけのバネになってしまいます。そこで登場するのが hull(a, b) という関数です。
これは、2つの図形(今回は2つの球)の外側をピタッとラップで包み込んで、一つの滑らかなカプセル形状(円柱)にしてくれる超便利機能です。

Pythonのループ処理や数学を使った高度なモデリング手法に踏み込むことができました。プレビュー画面で、断面が綺麗な「真円」になっているか、ぜひ確認してみてください。

3. なめらかな描画限界に挑戦

ノートi9-12900Hマシンですが、

fn_val   = 64      # 球の滑らかさ (数が多いと重くなるため少なめに設定)
steps    = 100      # 1巻きあたりの分割数(どれくらい細かく球を置くか)

約20秒ほどで、描画レンダリングできました。滑らかです。3Dプリンター用のファイルstl形式を出力すると、ファイルサイズ大きくなるでしょうか、

スクリーンショット 2026-08-09 153533.png

1. STLのファイルサイズが大きくなる

  • STLデータは「三角形の集まり」
    STL形式は、どんなに滑らかな球や円柱であっても、表面を「無数の平らな三角形(ポリゴン)」のパッチワークとして保存する仕組みになっています。
  • 解像度=三角形の数
    fn_val(滑らかさ)や steps(分割数)の数値を上げると、この表面の三角形の数が指数関数的に(爆発的に)増えます。そのため、比例してファイルサイズが数MBから数十MB、時には数百MBへと巨大化してしまうのです。

2. プロも使う「賢いモデリング」のコツ(最適化)

データが重すぎると、3Dプリンタ用のスライサーソフト(印刷データに変換するソフト)がフリーズしてしまうことがあります。そこで、実社会のものづくりでは以下のような工夫をします。

  • 作業中と本番で数値を使い分ける
    プログラムの最初で変数を定義したメリットがここで活きます!形を作っている最中(プレビュー時)は fn_val = 16 などにして計算を軽くし、いざSTLを出力する最後の瞬間だけ fn_val = 60 に書き換えて出力するのが鉄則です。
  • 3Dプリンタの限界を知る
    実は、一般的な3Dプリンタのノズル(樹脂が出る穴)の太さは0.4mm程度です。そのため、fn を100や200にして画面上で完璧にツルツルにしても、実際のプラスチックの造形物にはほとんど違いが出ません。目安として fn_val = 60 前後あれば、工業部品としても十分綺麗な仕上がりになります。

4. 【重要】 1行のメソッドチェーンで美しいバネ作り

ドキュメントに一行で書けるのがありました。すごいです。angleは360の倍数を入れていきます。

from pythonscad import *

circle(3).right(10).rotate_extrude(v=[0, 0, 40], angle=1440).show()

v=[0, 0, 40] を使う方法は、前回の「バネの断面が潰れてしまう問題」を、複雑な数学(sin, cos)や for ループを使わずに一発で解決できる最強の必殺技です。

rotate_extrude は本来「その場でろくろを回す」関数ですが、v パラメータを渡すことで「回転しながら指定した方向(今回はZ軸方向に40mm)へ引っ張り上げる」という動きに進化します。これにより、断面の円が潰れることなく綺麗な真円のままスパイラルを描けるのです。また、.right(10) という .translate([10, 0, 0]) のスマートな省略記法も素晴らしいです。

以下、他の高校生たちもこの「必殺技」を使えるように、パラメータを変数に置き換えた設計図(パラメトリック設計)として清書しました。

完成コード(PythonSCAD)

# ==========================================
# 1行で書くスパイラルばね(rotate_extrude + vパラメータ)
# 作成日: 2026/08/03
# ==========================================

from pythonscad import *

# --- パラメータ設定 (単位: mm) ---
wire_r = 2          # ばねの線の半径
spring_r = 15       # ばね全体の半径(中心からの距離)
coils = 4           # 巻き数
total_angle = 360 * coils  # 合計回転角度 (360度 × 4回転 = 1440度)
lift_z = 40         # Z方向への引っ張り上げ距離 (vパラメータ用)
fn_val = 60         # 円の滑らかさ(印刷時は60程度で十分綺麗です)

# --- メイン処理 ---
# circle() で円を作り、
# .right() で右(X方向)にずらし、
# .rotate_extrude() で上に引き上げながら回転させます!
spring = (
    circle(r=wire_r, fn=fn_val)
    .right(spring_r)
    .rotate_extrude(angle=total_angle, v=[0, 0, lift_z], fn=fn_val)
    .color("cyan")
)

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

スクリーンショット 2026-08-09 154733.png


解説ポイント 💡

  • angle は360の倍数で自由自在
    1440度(360度 × 4)のように大きな角度を指定することで、何周も巻き上がるスパイラルを作ることができます。変数 coils(巻き数)を作っておけば、「今日は5巻きのバネが欲しいな」と思った時に一瞬で変更できて便利です。
  • .right() は直感的で便利
    translate([10, 0, 0]) と書く代わりに .right(10).up(20) などの方向を示すメソッドを使うと、英語の文章を読んでいるようにスラスラとプログラムが読めます。
  • 計算量が少なくPCに優しい
    前の for 文で球をたくさん繋ぐ方法(前回描画に約20秒かかりました)に比べて、この1行の書き方はCADソフトの得意な計算方法を使っているため、パソコンへの負荷が軽く、一瞬でプレビューが表示されます。

複雑なロジックを自分で組み上げる力(前回のループ処理)と、ソフトの便利な機能を調べて使いこなす力(今回の1行コード)。この両方を手に入れました。

おわりに

この強力なスパイラル技術を使えば、ただのバネだけでなく「ボルトのネジ山」や「スクリュープロペラ」のような機械部品も作れそうです。
いろいろ試して、どのようにつくるか、たくさんためしてみましょう。やったもんがちです。おもしろくなります。一歩一歩です。ありがとうございます。

0
0
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
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?