今回は再帰処理を使用して、上画像の様な球に沿った曲線を描いていこうと思います。Anemone というプラグインを使用したケースと Python を使用したケース 2 種類紹介しております。是非ご参考にしてください。Python の基礎については割愛しておりますが、非常に基本的な内容となっております。Anemone は
できます。こちらのチュートリアルは動画化しておりますので、動画の方がよい方は以下のリンクからどうぞ!
概要(Anemone を使用したケース)
上画像が Anemone を使用した場合のプログラム全体像となっております。
各ブロックごとに解説していきます。
球面に点を作成
- Sphere コンポーネントで原点(0,0,0)半径 100mm の球を作成します。
- Populate Geometory コンポーネントで作成した球面に点を発生させます。今回は 2000 点発生させました。
- List Item コンポーネントで発生させた点から 0 番目の点を取得します。
Anemone を使用して再帰処理を実装
- Loop Start ,Loop End コンポーネントを用意しつなぎます。Loop Start の入力端子 T には Button コンポーネントを接続し、繰り返し回数 N には、発生させた点の数から1を引いた 1999 を入力します。
- Loop Start と Loop End を拡大し、入力する値を D0 ~ D2 まで用意します。D0 には発生させた点から抽出した 0 番目の点を接続、D1 は空のブランチを生成したいので何も接続しません。D2 には発生させた 2000 点を接続します。
- Closest Point コンポーネントで 2000 点のなかから、D0 に入力された点に最も近い点を抽出し Loop End の D0 に値を返してあげます。
- Cull Index コンポーネントで 2000 点の中から探し出した D0 に最も近い点を削除し、Loop End の D2 にリストを返してあげます。
- D1 から空の値を抽出し Data コンポーネントに接続し空のブランチを作成します。
- Insert Item コンポーネントで空のブランチに先ほど探し出した D0 に最も近い点をブランチに挿入し Loop End の D1 にリストを返してあげます。
- Button コンポーネントを押して繰り返し処理を開始します。繰り返し処理が終われば、Loop End の出力端子 D1 から 2000 点のリストが取得できますが、0 番目に Null が入ってしまっているかと思います。Clean Tree コンポーネントで Null を削除します。
- Nurbs Curve コンポーネントで取得した点のリストをもとに Nurbs Curve を作成しいます。
- 最後に Custom Preview コンポーネントと Colour Swatch コンポーネントで色付けして完成です。
Anemone を使用した場合:おまけ
- Anemone はループの過程をプレビューしてくれるので、せっかくなので少しかっこよくします。Line コンポーネントで球の原点と D0 に最も近い点を直線で結びます。
- Perp Frame コンポーネントで作成した直線の終点に直行する平面を作成します。入力端子は Reparametraize して入力端子 t に 1.0 を入力します。
- Circle コンポーネントで直線の端点に先ほど作成した平面に円を作成し、Surface コンポーネントでサーフェイスを張ります。
- Custom Preview コンポーネントと Colour Swatch コンポーネントで直線と円のサーフェイスに色付けします。
- Loop Start に接続した Button コンポーネントを押せば、円が描かれる過程がプレビューできるかと思います。
- 以上で Anemone のケースを終わります。
Python を使用したケース : while loop
1import ghpythonlib.components as gh
2
3origin_point =gh.ConstructPoint(0,0,0)
4base_sphere = gh.Sphere(origin_point,100)
5number_of_cloudpoints = 2000
6cloud_points = gh.PopulateGeometry(base_sphere,number_of_cloudpoints,1)
7
8food_point = cloud_points[0]
9infection_points = []
10
11while len(infection_points) < number_of_cloudpoints:
12 closest_point = gh.ClosestPoint(food_point,cloud_points)
13 cloud_points = gh.CullIndex(cloud_points,closest_point["cp_index"],True)
14 infection_points.append(closest_point["closest_point"])
15 food_point = closest_point["closest_point"]
上のコードは Python で先ほどの球に沿った曲線を描くための点を抽出しております。まずは while 文を使用したケースから説明します。
- Grasshopper 上で GhPython Script コンポーネントを用意し、ダブルクリックでエディターを開きます。
- 1 行目で ghpythonlib.components というモジュールをインポートして gh という名前にしておきます。これで普段 grasshopper で使用しているコンポーネントを呼び出すことができます。
- 3 行目で変数 origin_point に点(0,0,0)を代入します。この点が球の原点となります。
- 4 行目で変数 base_sphere に原点を origin_point 半径を 100mm の球を代入しています。
- 5 行目は変数 number_of_cloudpoints に球状に発生させる点の数を代入しています。
- 6 行目で変数 cloud_points に PopulateGeometory で base_sphere 上に number_of_cloud_points の数だけ点を発生させて代入しています。第三引数の 1 は seed 値になります。
- 7 行目で変数 food_point(最も近い点を探し出すための点)に cloud_points[0]で 0 番目の点を代入します。
- 8 行目で探し出された点を格納するための空の配列 infection_points を作成します。
- 10 行目から繰り返し処理を書いていきます。while 文で infection_points のリストの数が number_of_cloudpoints の未満の間処理を繰り返しております。
- 11 行目で変数 closest_point に food_point に最も近い点を cloud_points から算出し代入しています。
- 12 行目 cloud_points から探し出した closest_point を削除します。closest_point は辞書型の値になっているので、closest_point["cp_index"]として index 番号を取得しています。第三引数は index をラップさせるかどうかを指定しますが True にしておきます。(※index 番号を範囲外の値を指定した際にラップさせるかどうかという値になります。)
- ⒔ 行目で空のリスト infection_points に探し出した closest_point を挿入します。closest_point は辞書型なので、closest_point["closest_point"]とすることで、Geometory を取得します。
- 14 行目で変数 food_point を探し出した点 closest_point に再代入します。
- 探し出すための点を定義(food_point)⇒ 点群(cloud_points)から近接点(closest_point)を取得 ⇒ 近接点(closest_point)を配列に格納し点群から削除 ⇒ 近接点の近接点をさらに探す・・・・といった処理になっております。
- Ghpython Script コンポーネントの出力端子を infection_points とし、エディターの OK ボタンを押します。
- Nurbs Curve コンポーネントで取得した点をもとに Nurbs Curve コンポーネントを生成して完了です。
Python を使用したケース : 再帰関数
ついでに再帰関数で実装したケースも書いておきます。
1import ghpythonlib.components as gh
2
3origin_point =gh.ConstructPoint(0,0,0)
4base_sphere = gh.Sphere(origin_point,100)
5number_of_cloudpoints = 2000
6cloud_points = gh.PopulateGeometry(base_sphere,number_of_cloudpoints,1)
7
8food_point = cloud_points[0]
9infection_points = []
10
11def loop(i):
12 i-=1
13 global food_point
14 global cloud_points
15 closest_point = gh.ClosestPoint(food_point,cloud_points)
16 cloud_points = gh.CullIndex(cloud_points,closest_point["cp_index"],True)
17 infection_points.append(closest_point["closest_point"])
18 food_point = closest_point["closest_point"]
19 if i:
20 return loop(i)
21 else:
22 return True
23
24loop(number_of_cloudpoints)
- 基本的な流れは同じですが、今回は loop という関数を定義しております。引数に i をとり、関数を実行するごとに i から 1 を引いていきます。
- 関数内で記述している global food_point と global cloud_points は global 変数なので、global 変数であることを宣言しています。
- if 文で、もし i が 0 でない(True)と loop 関数の引数に i を再代入して再度実行します。i が 0(False)のとき、True を返して再帰処理を終えます。
- 最終行 loop(number_of_cloudpoints)で作成した loop 関数を実行しています。
以上になります。今回は Anemone を使用して再帰処理を実行した場合と GHpython を使用した場合を記載しました。是非ご参考にしてみてください。