BlenderでPython使って最速降下曲線を描いてみる
背景
多摩六都科学館にいって、ボールを転がし、どの斜面が一番ボールが早く落ちるかを調べる実験する展示があり、 これの説明にサイクロイド曲線が使われている旨の説明があり、最速降下曲線と呼ばれるものらしい。
曲線の数式がわかったので、曲面を算出してそれをBlenderの物理シミュレーションでやってみようと思った。
そんな訳で、GWは家族で、科学館や、自然博物館めぐりをしていた@kjunichiです。
Blenderで最速降下曲面をつくる
曲線をプロットする
最終的には立体化する必要があるが、これは押し出し機能を使えば出来そうと思い、 2次元の平面に最速降下曲線をプロットすることにした。
x = t - sin(t)
y = 1 + cos(t)
Blenderでの座標はWikiPediaとはy座標系が上下逆なので、1-cos(t)をこれに合わせて、変形している。
PythonにはC風のfor文がない件
算数が苦手なので、これにハマった。 ステップ数を指定して、1,2,3と整数を生成させ、これを元にプロットしたい変数tの最小値から最大値を取るように 計算させる必要があった。
tmin = 0.0 tmax = 3.1 step = 25 for i in range(0, step): t = i*((tmax - tmin)/(step - 1)) + tmin
こんな感じで、何とか、意図した値のtを得ることが出来た。
これを元に最速降下曲線プロットするコードが以下。
import bpy import math meshName = 'CurveMeshByData' objName = 'CurveObjectByData' mesh = bpy.data.meshes.new(meshName) obj = bpy.data.objects.new(objName, mesh) bpy.context.scene.objects.link(obj) tmin = 0 tmax = 3.1 step = 25 vertices=[] for i in range(0,step): t = i*((tmax-tmin)/(step-1))+tmin vertex = (t-math.sin(t), 1+math.cos(t), 0.0) vertices.append(vertex) mesh.from_pydata(vertices, [], []) mesh.update()
Blenderの画面は以下。
立体化の準備
曲線をプロットできたので、これを押し出して立体化できるように、面を構成出来るようにプロットする頂点を追加する。
import bpy import math meshName = 'CurveMeshByData' objName = 'CurveObjectByData' mesh = bpy.data.meshes.new(meshName) obj = bpy.data.objects.new(objName, mesh) bpy.context.scene.objects.link(obj) tmin = 0 tmax = 3.1 step = 25 vertices=[] for i in range(0,step): for y in range(0,2): t = i*((tmax-tmin)/(step-1))+tmin vertex = (t-math.sin(t), (1+math.cos(t))*y, 0.0) vertices.append(vertex) mesh.from_pydata(vertices, [], []) mesh.update()
面の作成
import bpy import math meshName = 'CurveMeshByData' objName = 'CurveObjectByData' mesh = bpy.data.meshes.new(meshName) obj = bpy.data.objects.new(objName, mesh) bpy.context.scene.objects.link(obj) tmin = 0 tmax = 3.1 step = 25 vertices=[] for i in range(0,step): for y in range(0,2): t = i*((tmax-tmin)/(step-1))+tmin vertex = (t-math.sin(t), (1+math.cos(t))*y, 0.0) vertices.append(vertex) faces=[] for i in range(0,step-1): idx=i*2 face = (idx, idx+1, idx+3, idx+2) faces.append(face) mesh.from_pydata(vertices, [], faces) mesh.update()
2次元図形を立体化する
描画した2次元図形を選択して編集モードに切り替え、bpy.ops.mesh.extrude_region_moveを実行することで立体化出来る。 (直前に描画した2次元図形は選択状態ではないので、ここで選択する必要があった。)
import bpy import math meshName = 'CurveMeshByData' objName = 'CurveObjectByData' mesh = bpy.data.meshes.new(meshName) obj = bpy.data.objects.new(objName, mesh) bpy.context.scene.objects.link(obj) tmin = 0 tmax = 3.1 step = 25 vertices=[] for i in range(0,step): for y in range(0,2): t = i*((tmax-tmin)/(step-1))+tmin vertex = (t-math.sin(t), (1+math.cos(t))*y, 0.0) vertices.append(vertex) faces=[] for i in range(0,step-1): idx=i*2 face = (idx, idx+1, idx+3, idx+2) faces.append(face) mesh.from_pydata(vertices, [], faces) mesh.update() bpy.context.scene.objects.active = bpy.data.objects[objName] bpy.ops.object.editmode_toggle() bpy.ops.mesh.extrude_region_move(MESH_OT_extrude_region={"mirror":False}, TRANSFORM_OT_translate={"value":(0, 0, -3), "constraint_axis":(False, False, True), "constraint_orientation":'NORMAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "texture_space":False, "remove_on_cancel":False, "release_confirm":False})
試しにボールを転がしてみた
最速降下曲線に斜面、円弧を並べて、Blenderで剛体シミュレーションしてみた。
真ん中が今回作成した最速降下曲線の斜面。手前は円弧の一部を使った斜面。
関連記事
- OSXのBlenderでctypesを試した
- BlenderでエクスポートしたJSONがThree.jsで変な色になる問題が解決
- Blenderで初めてのアドオンを作るまで ~その1~
- Blenderで初めてのアドオンを作るまで ~その2~
- DockerでIPython Notebookを動かして、数え上げおねえさんを救う
- node.jsで大きな数を扱う
- 東大の入試問題をNode.jsに解かせてみた
- 東大の過去問をPerlに解かせようとしたらbignumとbigintの違いを知った
- 1/7がつくる楕円をJulia言語でプロットする
- 15歳の天才少女が書いたPython3のコードを読ん事を学んだこと
- 陰関数の仮想3D空間へのプロットあるいは、ラズパイ版マインクラフトにたけのこの里を出す