Shade3D 公式

15 Bezier Line 分割 [ Shade Labo ]


#1

15 - 1 区分曲線( その1 )


control point 配列 [ **P** ] で構成される bezier line **P**( t ) の区分曲線 **P’**( t )( t1 <= t <= t2 )の control point 配列 [ **P’** ] を求めます。
まず最初に区間 0 <= t <= dt( 0 < d < 1 )の区分曲線を考えます。
          [ 式 15 - 1 ]

          [ fig 15 - 1 ]


[ 式 15 - 1 ], [ fig 15 - 1 ] より、control point 配列 [ **P’** ] で構成される区分曲線 **P’** を [ **P** ] を用いて表し、 [ **P** ] と [ **P’** ] との関係を調べると、
          [ 式 15 - 2 ]
よって、次の関係になります。

     

     [ 式 15 - 3 ]


#2

15 - 2 区分曲線( その2 )


次に、区間 dt <= t <= 1( 0 < d < 1 )の区分曲線を考えます。
          [ fig 15 - 2 ]
ここで、曲線 **P**( t ), **P’**( t ) の方向を反転した曲線 **Q**( s ), **Q’**( s ) を考えると、
          [ fig 15 - 3 ]

                    [ 式 15 - 4 ]


control point 配列 [ **Q** ] と [ **Q’** ] の関係は [ 式 15 - 3 ] と同じになりますから、

               [ 式 15 - 5 ]


一方 [ P ] と [ Q ] および [ P’ ] と [ Q’ ] は、それぞれの配列の方向を逆転させたものであり、それぞれ列方向に並んでいるとすると、matrix [ R ] を用いれば、


          [ 式 15 - 6 ]


ここで、[ R ] は 行や列を反転させる matrix で、次のような働きがあります。

     

     [ 式 15 - 7 ]


[ 式 15 - 6 ], [ 式 15 - 5 ] より、
          [ 式 15 - 8 ]
[ 式 15 - 7 ] より、 [ Sd* ] は [ Sd’ ] の行および列を反転させたものですから、

     

     [ 式 15 - 9 ]


#3

15 - 3 区分曲線( その3 )


[ 式 15 - 3 ], [ 式 15 - 9 ] より、control point 配列 [ **P** ] で構成される bezier line **P**( t ) の区分曲線 **P’**( t )( t1 <= t <= t2 )の control point 配列 [ **P’** ] は次式で求められます。

          [ 式 15 - 10 ]


これを区分曲線を求める関数として labo に登録してあります。

[ script 15 - 1 ]

#  bezier_line_subdivision( bz as vec3 list or vec3 matrix, t1 as float, t2 as float ) as vec3 list or vec3 matrix
#		bz : bezier control point 座標を格納した vec3 list or matrix
#		bezier line bz の parameter 区間 t1 ~ t2 における区分曲線の control point 座標配列を返す

def bezier_line_subdivision(bz, t1, t2) :
	if bz == None :
		return None
		
	if not isinstance(bz, matrix) :		#  bz : vec3 list
		p = matrix(True, bz)
	else :
		p = bz
		
	d = t2
	D1 = []
	D1.append([1, 			0, 				0, 				0])
	D1.append([1 - d, 		d, 				0, 				0])
	D1.append([(1 - d)**2, 	2*d*(1 - d),		d**2,			0])
	D1.append([(1 - d)**3, 	3*d*(1 - d)**2,	3*d**2*(1 - d),	d**3])
	D1 = matrix(D1)
	
	d = t1/t2
	D2 = []
	D2.append([(1 - d)**3, 	3*d*(1 - d)**2,	3*d**2*(1 - d),	d**3])
	D2.append([0,			(1 - d)**2, 		2*d*(1 - d),		d**2])
	D2.append([0,			0,				1 - d, 			d])
	D2.append([0, 			0, 				0, 				1])
	D2 = matrix(D2)

	bz1 = D2*D1*p
	
	if not isinstance(bz, matrix) :
		bz1 = list(bz1)				#  bz が vec3 list なら、返り値も vec3 list
		
	return bz1

次の script は、選択線形状の最初の区間を bezier parameter で3分割した3つの線形状を求め、出力します。
[ script 15 - 2 ]
import labo
	
scene = xshade.scene()

#  線形状データ取得
bz = labo.get_bezier(xshade, 0)

#  区分線
bz1 = labo.bezier_line_subdivision(bz, 0, 1./3)
bz2 = labo.bezier_line_subdivision(bz, 1./3, 2./3)
bz3 = labo.bezier_line_subdivision(bz, 2./3, 1)

#  区分線出力
scene.create_part('区分曲線')
labo.make_bezier_line(xshade, bz1)
labo.make_bezier_line(xshade, bz2)
labo.make_bezier_line(xshade, bz3)
scene.select_parent(1)