GDLで再帰 -GDLメモ vol.8

本学建築学コースでは、三年生後期に建築情報処理としてC言語を学ぶ講義を開講しています。C言語の基礎からということでint型、float型などの変数と型、if文やforループなどの分岐や制御、関数、と一通りの基本を抑えます。が、それだけではどうしても味気なくなってしまうため、プログラミングで二次元のグラフィクスを描こうというグラフィクス回を設定し、フラクタル図形やローレンツアトラクタ、DLA: Diffusion Limited Aggregation(的なもの、簡単な解説はこちら)、などをプログラムするということをしています。

GDL講習会は2017年度から建築生産設計として講義化しており、こちらの講義は建築情報処理でC言語を学んだ上で三次元モデルをプログラミングでつくる方法や考え方を学ぶということをテーマの一つにしています(他、ArchiCADでBIMの基本を学ぶのもテーマ)。教科書どおり立体トラスまで学んだあとの+αを試行錯誤しているのですが、今年度は建築情報処理のグラフィクス回で扱ったフラクタルを、GDLで三次元化する、というネタをやってみました。今回のGDLメモではこれについて簡単に紹介したいと思います。

まずは基本?のコッホ曲線から。下記ようにパラメータ設定と3Dスクリプトを書き込み、オブジェクトを「koch」として保存します。CALL文のところで自分自身を呼び出すことで再帰しています。CALLの際にite=ite-1とすることでカウントをデクリメントしていて、ite<1になったら線分を描いておしまい、というプログラムです。

一応、注意点を二点。再帰あるあるではありますが、カウントをデクリメントしていなかったり、再帰を抜ける判定をミスしていると、再帰から帰ってこなくなります。GDLの場合、ArchiCADごと無限の再帰から帰ってこなくなります。また、こちらも再帰あるあるですが、必ずしもフラクタル図形を再帰プログラミングで描くのが最適かというとそういうわけではありません。コッホ曲線は再帰でなくても描けます。この方法については記事を改めて紹介したいと思います。

IF ite < 1 THEN
	LIN_ 0, 0, 0,
		len, 0, 0
ELSE
	CALL "koch" PARAMETERS len = len / 3, ite = ite - 1
	ADDX len / 3
	ROTZ 60
	CALL "koch" PARAMETERS len = len / 3, ite = ite - 1
	ADDX len / 3
	ROTZ -120
	CALL "koch" PARAMETERS len = len / 3, ite = ite - 1
	ADDX len / 3
	ROTZ 60
	CALL "koch" PARAMETERS len = len / 3, ite = ite - 1
ENDIF

上記のコッホ曲線は二次元ですので、次はシェルピンスキーのギャスケットを四面体ベースにしたものを例に、三次元のフラクタル図形を描いてみます。下記のようなパラメータ設定と3Dスクリプトをもつオブジェクト「sierpinski」を作成します。再帰の考え方はコッホ曲線と同じです。四面体の各辺の中点を求め、それを使って新たな四面体を四つ作るべく、自分自身を四回CALLしています。

IF ite < 1 THEN
	MATERIAL mat
	PLANE 3, x0, y0, z0, x1, y1, z1, x2, y2, z2
	MATERIAL mat
	IF RND(1) > 0.5 THEN
		MATERIAL mat1
	ENDIF
	PLANE 3, x0, y0, z0, x1, y1, z1, x3, y3, z3
	MATERIAL mat
	IF RND(1) > 0.5 THEN
		MATERIAL mat1
	ENDIF
	PLANE 3, x2, y2, z2, x1, y1, z1, x3, y3, z3

	MATERIAL mat
	IF RND(1) > 0.5 THEN
		MATERIAL mat1
	ENDIF
	
		PLANE 3, x0, y0, z0, x2, y2, z2, x3, y3, z3
ELSE
	x01 = (x0 + x1) / 2: y01 = (y0 + y1) / 2: z01 = (z0 + z1) / 2
	x02 = (x0 + x2) / 2: y02 = (y0 + y2) / 2: z02 = (z0 + z2) / 2
	x03 = (x0 + x3) / 2: y03 = (y0 + y3) / 2: z03 = (z0 + z3) / 2
	x12 = (x1 + x2) / 2: y12 = (y1 + y2) / 2: z12 = (z1 + z2) / 2
	x13 = (x1 + x3) / 2: y13 = (y1 + y3) / 2: z13 = (z1 + z3) / 2
	x23 = (x2 + x3) / 2: y23 = (y2 + y3) / 2: z23 = (z2 + z3) / 2

	CALL "sierpinski" PARAMETERS ite = ite - INT(1 + RND(3)),
		x0 = x0, y0 = y0, z0 = z0,
		x1 = x01, y1 = y01, z1 = z01,
		x2 = x02, y2 = y02, z2 = z02,
		x3 = x03, y3 = y03, z3 = z03, mat = mat, mat1 = mat1
		
	CALL "sierpinski" PARAMETERS ite = ite - INT(1 + RND(3)),
		x0 = x01, y0 = y01, z0 = z01,
		x1 = x1, y1 = y1, z1 = z1,
		x2 = x12, y2 = y12, z2 = z12,
		x3 = x13, y3 = y13, z3 = z13, mat = mat, mat1 = mat1

	CALL "sierpinski" PARAMETERS ite = ite - INT(1 + RND(3)),
		x0 = x02, y0 = y02, z0 = z02,
		x1 = x12, y1 = y12, z1 = z12,
		x2 = x2, y2 = y2, z2 = z2,
		x3 = x23, y3 = y23, z3 = z23, mat = mat, mat1 = mat1

	CALL "sierpinski" PARAMETERS ite = ite - INT(1 + RND(3)),
		x0 = x03, y0 = y03, z0 = z03,
		x1 = x13, y1 = y13, z1 = z13,
		x2 = x23, y2 = y23, z2 = z23,
		x3 = x3, y3 = y3, z3 = z3, mat = mat, mat1 = mat1
ENDIF

CALLのところで、カウントのデクリメントがite=ite-1となっている部分をite=ite - INT(1 + RND(3))などとするとカウントの減り方にばらつきが生じ、結果として粗密のある三次元モデルを得ることができます。他にも正方形ベースで再帰させてみたりすることももちろん可能です。ちなみに過去のGDL発表会では、今回扱ったのと同じ方法で、町並みを作ってみたりやりがい君(ロマネスコ)を描いてみたりしています。なかなか面白いものができますので是非皆さんもチャレンジしてみてください。


HLAB
http://www.hlab-arch.jp/article.php/20190706105913363