雰囲気データサイエンティストの備忘録

Atmosphere Data Scientist's Memorandum


Solid Pythonで簡単な3Dモデルを作る
Python
3Dモデル

概要

3Dプリンター便利ですよね。
日常用途でもちょっとした部品を作りたいとき,よく使います。
自分が持っているのはEntina Tina2SというAmazonで2万ちょっとで変えたものなのですが,
ホビー用3Dプリンターが出たばかりの5-6年前と比べて,低価格でそこそこの精度が出るものが増えた気がします。
https://www.entina3d.com/en-jp/products/entina-tina2s-3d-printershttps://www.entina3d.com/en-jp/products/entina-tina2s-3d-printers

一方で,3D-CADをどう調達するかが悩みどころです。
自分は仕事で使う有償ソフトで慣れきってしまい,なかなか合うものが見つからない状況でした。
(個人利用無償のFusion360を覚えるのが一番良いのですが)

パラメトリックにモデルを作りたい

一方で,仕事と違ってホビー用途でモデルを作る場合,意外と本格的な3D-CADソフトは適さない状況もあるように感じます。
基本的には図面がない中で作るので,現物を印刷した後でハマらないことに気が付いたり,使っているうちに改善点に気が付いて作り直しになったり...

こういった時に,いちいちCADを開いて,寸法を調整して,STLにエクスポートして,印刷設定して…等々やると大変です。

SolidPython/OpenSCAD

そこで,単純な部品はPythonで生成ロジックを書けると便利です。
SolidPythonを使うと,直方体や円柱,球などの基本的なオブジェクトの作成,移動やスケーリングなどの操作,ブーリアン演算が簡単に行えます。

rudder.py
import subprocess
import numpy as np
import solid as sl

# 支柱
base1 = sl.cube((0.1, 0.1, 3), (0, 0, 0))
base2 = sl.translate([0, 0.8, 0])(base1)
base = base1 + base2

# 段差
steps = []
for z in np.arange(0, 3, 0.5):
    step = sl.cube((0.1, 0.8, 0.1))
    step_t = sl.translate(v=(0.05, 0, z + 0.25))(step)
    steps.append(step_t)

# baseとstepを結合
rudder = base + sum(steps)

# 傾斜
rudder_t = sl.rotate(-20, [0, 1, 0])(rudder)

# 保存
sl.scad_render_to_file(rudder_t, "output.scad")

# openscadでstlに変換する
subprocess.run(["openscad", "-o",  "output.stl", "output.scad"])

基本図形の作成

以下のように直方体を配置できます。第1引数は(x, y, z)方向の寸法,第2引数は原点です。

base1 = sl.cube((0.1, 0.1, 3), (0, 0, 0))

幾何変換

平行移動などの変換も簡単です。以下はbase1というオブジェクトをベクトルvだけ移動した新規オブジェクトbase_2を作成しています。

base2 = sl.translate([0, 0.8, 0])(base1)

ブーリアン演算

オブジェクト同士の四則演算でブーリアン演算ができます。これは便利ですね!

# `base1`と`base2`の和
sum = base1 + base2
# 差
diff = base1 - base2

ループ処理

Pythonの基本文法なので言うまでもないですが,以下のようにforループに組み込むことで,繰り返し形状を作成できます。

# 段差
steps = []
for z in np.arange(0, 3, 0.5):
    step = sl.cube((0.1, 0.8, 0.1))
    step_t = sl.translate(v=(0.05, 0, z + 0.25))(step)
    steps.append(step_t)

# baseとstepを結合
rudder = base + sum(steps)

出来上がったもの

梯子ができました。
梯子

パラメータを少し変えてみると,
梯子

パラメータ化しておくと,このような変更もささっとできるのがいいですね。

螺旋階段

ループ処理の微変更で以下のような形状も作ることができます。

stairs.py
import subprocess
import numpy as np
import solid as sl

# 支柱
base = sl.cylinder(0.1, 6)

# 段差
steps = []
for i, z in enumerate(np.arange(0, 6, 0.2)):
    step = sl.cube((0.5, 1.6, 0.1))
    step_t = sl.translate(v=(0.05, 0, z + 0.1))(step)
    step_r = sl.rotate(30*i, [0, 0, 1])(step_t)
    steps.append(step_r)

# baseとstepを結合
rudder = base + sum(steps)

# 保存
sl.scad_render_to_file(rudder, "output.scad")

# openscadでstlに変換する
subprocess.run(["openscad", "-o",  "output.stl", "output.scad"])

螺旋階段

まとめ

3D-CAD自動化はソフトごとの独自色が強く,基本形状であっても学習のハードルが高いのですが,
SolidPythonであれば,形状作成のロジックさえ固めてしまえば想像以上に短いコードで書けると思います。

そのうちViewerと連携したアプリとか,形状最適化とかもやってみたいと思います。