Shade3D 公式

07 Bezier line 長さ [ Shade Labo ]


#1

関連記事 :
  • 06 Bezier line 基礎

07 - 1 長さの求め方


bezier 曲線を P(t) t : bezier parameter 0~1 とすると、bezier parameter t1 ~ t2 における長さ L は次の積分で求められます。
          [ 式 07 - 1 ]

#2

07 - 2 被積分関数


被積分関数 | dP( t )/dt | は次のようになります。

bezier 曲線の導関数については [ 式 06 - 02 ] を参照


[ script 07 - 01 ]

#  bezier_abs_derivative( bz as vec3 list, t as float ) as float
#
#	コントロールポイント座標 list bz で与えられる bezier 曲線の
#	パラメータ t における微分ベクトル の絶対値を返す

def bezier_abs_derivative(bz, t) :
	v = (-3*(1 - t)**2)*bz[0] + 3*(1 - t)*(1 - 3*t)*bz[1] + 3*t*(2 - 3*t)*bz[2] + (3*t**2)*bz[3]
	return v.abs()

	#	マトリックス演算で表せば、	
	#	T = labo.bezier_t_derivative(t)
	#	M = labo.bezier_m()
	#	v = T*M*bz
	#	return v.abs()

#3

07 - 3 数値積分


この積分は簡単な数値積分で精度良くもとめられます。

bezier 諸量に関する積分を求める関数として module labo の中に関数 bezier_simpson( ) を次のように定めています。


[ script 07 - 02 ]

#  bezier_simpson(func as function,t1 as float, t2 as float, bz as vec3 list, simpsonN as int) as float
#
#	Simpson法による関数 func の区間 t1~ t2 の積分値を返す
#
#	func :		関数 func( bz, t ) as float
#
#				bz :	vec3 list	bezier control point 座標
#				t : 	float		bezier parameter
#
#	t1, t2		float		積分区間
#	bz :			vec3 list	func( ) 内で使用される bezier control point 座標
#	simpsonN :	int			分割数

def bezier_simpson(func, bz, t1, t2, simpsonN = 30) :
	sN = int(math.ceil((t2 - t1)*simpsonN))
	sN = min(simpsonN, sN)
	sN2 = 2*sN
	h = (t2 - t1)/float(sN2)
	
	f = []
	n = 2*sN + 1
	for i in range(n) :
		tt = t1 + i*h
		f.append(func(bz, tt))
		
	a = 0
	n = sN + 1
	for i in range(1, n) :
		a += f[2*i - 1]
	a = 4*a
	
	b = 0
	for i in range(1, sN) :
		b += f[2*i]
	b = 2*b
	
	return (f[0] + f[sN2] + a + b)*h/3

#4

07 - 4 bezier line の長さを測る


次の script では Shade 上で選択された線形状の長さを求め、レポートします。

数値積分は labo.bezier_simpson( ) を用い、最大分割数 simpsonN はデフォルト値 30 としてます。


[ script 07 - 03 ]     Shade 上で線形状を選択して実行

import math
import labo


#	コントロールポイント座標 list bz で与えられる bezier 曲線の
#	パラメータ t における微分ベクトル の絶対値を返す

def bezier_abs_derivative(bz, t) :
	v = (-3*(1 - t)**2)*bz[0] + 3*(1 - t)*(1 - 3*t)*bz[1] + 3*t*(2 - 3*t)*bz[2] + (3*t**2)*bz[3]
	return v.abs()

		

#  線形状全データ取得		bZs = [bz, bz, bz, …]   bz = [vec3, vec3, vec3, vec3] transposed
bZs = labo.get_bezier(xshade, -1)

						
# total, brL, sL
total = 0		#  Bezier line 全長
bcL = []		#  各ブロック毎の線長
	
for bz in bZs :
	r = labo.bezier_simpson(bezier_abs_derivative, bz, 0, 1)	#  parameter 区間 0~1 で線長を求める
	total += r
	bcL.append(r)

#  report
print 'total line length = ' + str(total)
n = len(bcL)
for i in range(n) :
	print '#', i, '     ', bcL[i]