2018年7月16日(月) 10:04 JST

2016年度第5回GDL講習会

  • 2016年5月31日(火) 11:36 JST
  • 投稿者:
    ゲストユーザ

第5回ではGDLプログラミングマニュアルの五章「大屋根のモデリング」をやってもらいました。具体的には、CALLであらかじめ作成した部材のGDLファイルを呼び出すことや、外積による法線ベクトルの計算を行いました。これらの方法を用いて正八面体の生成と、その各面から正四面体を生成するようなモデルを作成してみましょう。

image image

曲面にPLANEを張る

ここで少し振り返るかたちになりますが、ワイヤーフレームのように線分(GDLではLIN_コマンド)で描かれた曲面に面をはる方法を紹介します。前回のGDL講習会で行ったシェルコンテストの作品紹介ではこのような方法で面をはっています。

!!シェルのパラメータ
w = 10 : d = 5!! 幅
Qw = 40 : Qd = 20!! 幅の分割数

!! 配列の宣言
DIM x[ ], y[ ], z[ ][ ]!!z は二次元配列として宣言する

!! 値の格納
FOR i = 1 TO Qw + 1
	x[ i ] = ( i - 1) * w / Qw - w / 2
NEXT i

FOR j = 1 TO Qd + 1
	y[ j ] = ( j - 1) * d / Qd - d / 2
NEXT j

!!z[ i ][ j ] の値がx[ i ]とy[ j ] によって決まるよう値を格納していく 

FOR j = 1 TO Qd + 1
	FOR i = 1 TO Qw + 1
		z[ i ][ j ] = ( 1 / 20) * x[ i ] ^ 2 + ( 1 / 10) * y[ j ] ^ 2
	NEXT i
NEXT j 

!!x(w) 方向に伸びる線
FOR j = 1 TO Qd + 1
	FOR i = 1 TO Qw
		LIN_ x[ i ], y[ j ], z[ i ][ j ], x[ i + 1], y[ j ], z[ i + 1 ][ j ]
	NEXT i
NEXT j

!!y(d) 方向に伸びる線
FOR j = 1 TO Qd
	FOR i = 1 TO Qw + 1
		LIN_ x[ i ], y[ j ], z[ i ][ j ],x[ i ], y[ j + 1], z[ i ][ j + 1 ]
	NEXT i
NEXT j

ここまでは第3回で学習したやり方通りですね。配列 x[ ], y[ ], z[ ][ ]に格納した座標を用いて、LIN_によって線を引いています。次にこれに面を張っていきましょう。使うコマンドはPLANEです。

!!三角形を張る ①
FOR j = 1 TO Qd
	FOR i = 1 TO Qw
		PLANE 3,  x[ i ], y[ j ], z[ i ][ j ],
				x[ i  + 1], y[ j ], z[ i + 1 ][ j ],
				x[ i ], y[ j + 1], z[ i ][ j + 1 ]
	NEXT i
NEXT j

!!三角形を張る ②
FOR j = 1 TO Qd
	FOR i = 1 TO Qw
		PLANE 3,  x[ i + 1 ], y[ j + 1 ], z[ i + 1 ][ j + 1],
				x[ i  + 1], y[ j ], z[ i + 1 ][ j ],
				x[ i ], y[ j + 1], z[ i ][ j + 1 ]
	NEXT i
NEXT j

①、②と三角形に分割してPLANEを生成しています。四角形ですと、同一平面上に四点がなく、面がうまく生成できない可能性がありますが、三角形ならその心配はありません。また、PLANEコマンドの場合、ポリゴンの表裏は余り意識されませんが、プリミティブ要素(コマンド)をもちいたモデリングや、あるいは他のCADではポリゴンの表裏(や頂点の指定順も意識しておこなう必要があります。ここでは一応右ねじの法則、反時計回り方向が正(CCW:Counter Clock Wise)となるようにしています。


正八面体

では次に正八面体を作ります。ここでは内接する球の半径をパラメータとして扱います。

r = 1	!!!外接円の半径

!!!底面の点
DIM point[][3]	!!!正八面体用配列

div = 4	!!!円周の分割数
alpha = 360/div	!!!4分割後の角度

!!!配列に底面の点を格納
FOR i = 1 to div+1
	point[i][1] = r*cos(alpha*(i-1)) 
	point[i][2] = r*sin(alpha*(i-1)) 
	point[i][3] = 0
NEXT i

n = VARDIM1(point)	!!!配列長さ取得

!!!上下点格納
point[n + 1][1] = 0
point[n + 1][2] = 0
point[n + 1][3] = r

point[n + 2][1] = 0
point[n + 2][2] = 0
point[n + 2][3] = -r

n = VARDIM1(point)	!!!配列長さ取得

MATERIAL 45

!!!頂点に球格納
FOR i = 1 to n
	ADD point[i][1],point[i][2],point[i][3]
	SPHERE 0.1
	DEL 1
NEXT i

!!!頂点同士を部材で結ぶ
FOR i = 1 to div
	CALL "trussrod" PARAMETERS sx = point[n][1],sy = point[n][2],sz = point[n][3],
					fx = point[i][1],fy = point[i][2],fz = point[i][3]
	CALL "trussrod" PARAMETERS sx = point[n-1][1],sy = point[n-1][2],sz = point[n-1][3],
					fx = point[i][1],fy = point[i][2],fz = point[i][3]
	CALL "trussrod" PARAMETERS sx = point[i][1],sy = point[i][2],sz = point[i][3],
					fx = point[i+1][1],fy = point[i+1][2],fz = point[i+1][3]
		
NEXT i	

これまでのように配列pointに座標を格納しているのですが、少々形が異なっているのに気づきましたか?二次元配列の列側が3列と定義され、X,Y,Z座標としての役割を持っています。
では次に、各面から正四面体を生成します。外積を用いると、ある平面に対する法線ベクトルを求められるのは今回学習しましたね。


正四面体の追加

!!!新しい頂点用の配列
DIM newPoint[][]

!!!一辺の長さから正四面体の高さを求めます。
vec_x = point[2][1] - point[1][1]
vec_y = point[2][2] - point[1][2]
vec_z = point[2][3] - point[1][3]
trasLen = sqr(vec_x^2+vec_y^2+vec_z^2)
height = sqr(2/3*trasLen^2 )

!!!底面より上
FOR i = 1 to div
	!!!各面の重心求める
	vec1_x = (point[i+1][1] + point[i][1])/2
	vec1_y = (point[i+1][2] + point[i][2])/2
	vec1_z = (point[i+1][3] + point[i][3])/2
	center_x = (point[n-1][1]*1 + vec1_x*2)/3
	center_y = (point[n-1][2]*1 + vec1_y*2)/3
	center_z = (point[n-1][3]*1 + vec1_z*2)/3

	!!!各面の法線求める
	vecA_x = point[i+1][1] - point[i][1]
	vecA_y = point[i+1][2] - point[i][2]
	vecA_z = point[i+1][3] - point[i][3]
	vecB_x = point[n-1][1] - point[i][1]
	vecB_y = point[n-1][2] - point[i][2]
	vecB_z = point[n-1][3] - point[i][3]

	nVec0_x = vecA_y*vecB_z-vecA_z*vecB_y
	nVec0_y = vecA_z*vecB_x-vecA_x*vecB_z
	nVec0_z = vecA_x*vecB_y-vecA_y*vecB_x
	nVecLen = sqr(nVec0_x^2+nVec0_y^2+nVec0_z^2)

	!!!法線正規化
	nVec_x = nVec0_x/nVecLen 
	nVec_y = nVec0_y/nVecLen 
	nVec_z = nVec0_z/nVecLen

	!!頂点を配列に格納	
	newPoint[i][1] = center_x + height *nVec_x
	newPoint[i][2] = center_y + height *nVec_y
	newPoint[i][3] = center_z + height *nVec_z
NEXT i

newN = VARDIM1(newPoint)	!!!新頂点用配列の長さ取得

!!!底面より下の面も同様に
FOR i = 1 to div
	!!!底面の重心求める
	vec1_x = (point[i+1][1] + point[i][1])/2
	vec1_y = (point[i+1][2] + point[i][2])/2
	vec1_z = (point[i+1][3] + point[i][3])/2
	center_x = (point[n][1]*1 + vec1_x*2)/3
	center_y = (point[n][2]*1 + vec1_y*2)/3
	center_z = (point[n][3]*1 + vec1_z*2)/3

	!!!底面の法線求める
	vecA_x = point[i+1][1] - point[i][1]
	vecA_y = point[i+1][2] - point[i][2]
	vecA_z = point[i+1][3] - point[i][3]
	vecB_x = point[n][1] - point[i][1]
	vecB_y = point[n][2] - point[i][2]
	vecB_z = point[n][3] - point[i][3]

	nVec0_x = vecA_y*vecB_z-vecA_z*vecB_y
	nVec0_y = vecA_z*vecB_x-vecA_x*vecB_z
	nVec0_z = vecA_x*vecB_y-vecA_y*vecB_x
	nVecLen = sqr(nVec0_x^2+nVec0_y^2+nVec0_z^2)

	!!!法線正規化	
	!!!さっきと面の向き逆(-1かける)
	nVec_x = -nVec0_x/nVecLen 
	nVec_y = -nVec0_y/nVecLen 
	nVec_z = -nVec0_z/nVecLen 

	!!!頂点を配列に格納
	newPoint[div+i][1] = center_x + height *nVec_x
	newPoint[div+i][2] = center_y + height *nVec_y
	newPoint[div+i][3] = center_z + height *nVec_z
NEXT i

MATERIAL 164

!!!頂点に球格納
FOR i = 1 to n + 1
	ADD newPoint[i][1],newPoint[i][2],newPoint[i][3]
	SPHERE 0.1
	DEL 1
NEXT i

!!!頂点同士を部材で結ぶ
FOR i = 1 to div
	CALL "trussrod" PARAMETERS sx = newPoint[i][1],sy = newPoint[i][2],sz = newPoint[i][3],
					fx = point[n-1][1],fy = point[n-1][2],fz = point[n-1][3]
	CALL "trussrod" PARAMETERS sx = newPoint[i][1],sy = newPoint[i][2],sz = newPoint[i][3],
					fx = point[i][1],fy = point[i][2],fz = point[i][3]
	CALL "trussrod" PARAMETERS sx = newPoint[i][1],sy = newPoint[i][2],sz = newPoint[i][3],
					fx = point[i+1][1],fy = point[i+1][2],fz = point[i+1][3]
NEXT i

FOR i = 1 to div
	CALL "trussrod" PARAMETERS sx = newPoint[div+i][1],sy = newPoint[div+i][2],sz = newPoint[div+i][3],
					fx = point[n][1],fy = point[n][2],fz = point[n][3]
	CALL "trussrod" PARAMETERS sx = newPoint[div+i][1],sy = newPoint[div+i][2],sz = newPoint[div+i][3],
					fx = point[i][1],fy = point[i][2],fz = point[i][3]
	CALL "trussrod" PARAMETERS sx = newPoint[div+i][1],sy = newPoint[div+i][2],sz = newPoint[div+i][3],
					fx = point[i+1][1],fy = point[i+1][2],fz = point[i+1][3]
NEXT i