[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
過去ログ
投稿順に表示
スレッドごとに表示
キーワード
タイトル
投稿者
編集パスワード
コメント
添付
Re[508]: ロープ形状作成スクリプト
2007年02月12日 (月) 01時22分
kenslab
返信
匠弥 さま

本スクリプトのPython版復活をお願いしたkenslabと申します。
早速のPythonスクリプトの開発ありがとうございました。
Shade9.01で試してみたところ、問題なく希望するロープ形状が作成でき、描画速度も全く気になりません。描く長さにもよるのかも知れませんが。
これからいろいろとパラメータ設定を変えて最適化を検討したいと思いますが、先ずは私の希望する形状作成がShade9で可能になったことをお知らせしてお礼に代えさせていただきます。ありがとうございました。
ロープ形状作成スクリプト
2007年02月11日 (日) 15時42分
匠弥
返信
お世話になります。

Pythonとベジエ曲線の勉強もかねて、ロープ作成スクリプトに挑戦していたのですが、
先ほど、動作するものが出来ましたのホームページにアップしました。
ただ、非常に重たいので、使っているとストレスが溜まるかもしれません。

動作確認は8.5で行なっています。
7は動きません。
Pythonは2.3のリファレンスを参考にしています。
Re[506]: ロープ形状作成スクリプトのための ウンチク
2007年02月07日 (水) 23時09分
でった☆
返信
ありがとうございますー。
じっくり読ませていただきます。ほんと助かりますです。
ロープ形状作成スクリプトのための ウンチク
2007年02月07日 (水) 18時38分
加藤俊明
返信
ふうっ、やっとこ書き終えました。
「 これじゃ何を意味しているのかわからんぞ 」「 なんでそうしなきゃいけないの? 」等々、疑問, 質問 なぞありましたなら、どんどんつっこみを入れてくださいね。



1. Bezier 曲線をN分割する
  1.1 bezier parameter の扱いについて( 01/31 )
  1.2 曲線の全長を求める( 01/31 )
  1.3 N分割する点の bezier parameter を求める( 01/31 )
  1.4 bezier parameter t() に従ってアンカーポイントを追加( 01/31 )
  1.5 BL_Length(p, t) の擬似コード( 02/02 )
  1.6 BL_Param(p0, p1, p2, p3, lineL, targetL) の擬似コード( 02/05 )

2. 断面形状を線形状の始端にセットし掃引する
  2.1 線形状の接線ベクトルを求める( 02/03 修正 )
  2.2 BL_Tangent(p, t) の擬似コード( 02/03 )
  2.3 接線ベクトルの緯度経度を求める( 02/03 )
  2.4 断面形状を線形状の始端位置にセットする( 02/03 修正 )

3. ロープ形状を作成する
  3.1 ロープの種類とロープ形状を決定するパラメータ( 02/07 )
  3.2 ロープ形状作成の一案( 02/07 )
  3.3 アンカーポイント座標取得のルール( 02/07 )
  3.4 巻き数 n と、分割数 N との関係( 02/07 )

ロープ形状作成スクリプトのための ウンチク( その6 )
2007年02月07日 (水) 18時37分
加藤俊明
返信
【 3. ロープ形状を作成する 】

与えられた線形状に沿ってロープ形状を作成する方法はいくつも考えられますが、大きく分けると次の二つのアプローチに分類されます。

1)座標値を自前で計算する
2)可能な限り script command を利用して Shade 上に中間形状を作成し、そこから得られる座標値を利用して作成する。

1)の方がすっきりしますが、ここでは理解しやすい 2)の方法の一案を提示します。
あくまでも一案ですので、他にいろいろ工夫して作ることもできるでしょう。


《 3.1 ロープの種類とロープ形状を決定するパラメータ 》

ロープの種類としては、数本を束ねて捩ったものや、三つ編みなどいろいろ考えられますが、ここでは基本形として3本を捩ってできるロープを作成するとして話を進めます。
( これを modify すれば三つ編みも全く同じ手続きで作ることができます )

また、対象は開いた線形状に限るものとしますが、少しだけ手を加えれば閉じた線形状を対象にすることも可能です。

さらに、ロープは与えられた線形状の全長にわたって作成するものとします。
これも手を加えれば、任意の区間内にロープを作成することも可能です。


ロープ形状を指定するパラメータとしては次のものが考えられます。
ユーザー入力項目はこれを参考として決定するといいでしょう。

ピッチ数:np as integer
進行方向に捻れたロープが一回転する区間をピッチととらえ、与えられた線形状に対して何ピッチのロープを作成するか。

巻きの向き:clockWise as boolean
進行方向に向かって右巻きか左巻きか( 三つ編みの場合は不要 )

巻き数:n as integer
何本を捩ってロープを作成するか( ここでは 巻き数 = 3とする )

素材径:r as float
ロープを構成する一本の紐の半径

ピッチ径:rp as float
ロープ断面から見て、ロープを構成する紐の中心が並ぶ円の半径
ロープ全体の半径 = ピッチ径 + 素材径


《 3.2 ロープ形状作成の一案 》

1)原点を中心として X-Y 平面内にピッチ径 rp に外接する六角形を作成する。

巻きの向きが右回りならアンカーポイントの並び順が右回りの六角形を、左回りなら左回りの六角形を描く

2)ロープ中心線形状をコピーし、これを N分割する( 第1章参照 )

N はピッチ数の6倍 N = np*6 とする( 三つ編みの場合は N = np*12 )

3)N分割した中心線形状の始端に正六角形をセットして掃引する( 三つ編みの場合は 正12角形 )( 第2章参照 )

4)掃引して得られた自由曲面を選択して 3.3項で述べるルールに従って3組のアンカーポイント座標を取得していく

5)得られた3組のアンカーポイント座標をそれぞれ結ぶ3本の折れ線を Shade 上に作成する

6)3本の折れ線にスムースをかける

7)3本の線それぞれについて、素材径 r の円形の線形状をその始端にセットして掃引きする( 第2章参照 )

これで3本を捻ったロープができあがります。


《 3.3 アンカーポイント座標取得のルール 》

取得するアンカーポイント座標は掃引で得られた自由曲面の U方向線形状毎に調べていきますが、全ての U方向線形状ではなく 始端と終端それに N分割によってオリジナルの線形状に追加されたアンカーポイント位置に相当する U方向線形状のみがその対象となります。

つまり、オリジナルの開いた線形状のアンカーポイント数が noap であったとすると、N分割によってアンカーポイント数は noap + N - 1 に増えており、掃引によって作成される自由曲面の U方向線形状の数も noap + N - 1 になっています。

このうち始端と終端を除くオリジナルのアンカーポイント位置に相当する U方向線形状はアンカーポイント座標取得において不要ですので、これを予め削除しておいた方が以降の操作が簡単になります。

何番目の U方向線形状が不要であるかを知るには、1.3項で N分割のために得た bezier parameter リストを利用するといいでしょう。
1.4項で script で連続してアンカーポイント追加するために modify した bezier parameter リストではないことに注意してください。


3.3.1 不要なU方向線形状の Iindex を取得

///////////////////////////////////////////////////
bezier parameter リストから不要なU方向線形状の
index を取得する擬似コード
///////////////////////////////////////////////////

dim t() as float // 1.3 項で得られた bezier parmeter list
dim nt as integer // t() の配列数( 0基数 )
dim noap as integer // N分割を受ける前のオリジナルの線形状のアンカーポイント数
dim k as integer

nt = Ubound(t) // t() の配列数( 0基数 )
dim indexL(noap - 3) as integer // 不要なU方向線形状の index を格納

k = 0
for i = 1 to noap - 2
 if k <= nt then
  if t(k) < i then
   do
    k = k + 1
    if k > nt then
     exit // do ループを抜ける
    end if
   Loop until t(k) >= i
  end if
 end if
 indexL(i - 1) = i + k
next

オリジナルのアンカーポイントが10個( index = 0〜9 )で、bezier parameter リスト が { 0.2, 0.6, 1.2, 2.0, 4.5 } であるとすると、N分割後のアンカーポイント数は 10 + 5 = 15( index = 0〜14 )であり、indexL には { 3, 5, 7, 8, 10, 11, 12, 13 } が返されることになります。
これが 始端と終端を除く 10 - 2 = 8 個のオリジナル線形状のアンカーポイントの N分割後の index を示しています。


3.3.2 不用なU方向線形状を削除

1)掃引で得られた自由曲面を選択
2)一番上にある子オブジェクト( 最初のU方向線形状 )を選択
3)script property ordinal によって、この最上位のオブジェクトの ordinal No.( 序数 )を取得する。
4)3.3.1 で求めた不要U方向線形状の index list( 0基数 )の各要素に 3)で取得した ordinal No. を加えると、削除するオブジェクトの ordinal list( 序数リスト )が得られる
5)この ordinal list を用いて script property set ordinal list で削除対象となる線形状を選択状態にし、script command clear で削除する。


3.3.3 3組のアンカーポイント座標を取得

3.3.2項の処理で得られた自由曲面を選択します。
掃引で得られた自由曲面の中から一部のU方向線形状を削除したので、形はいびつになっていますが、六角形の U方向線形状は掃引中心線に沿って N分割された等間隔に並んでいます。
ここで自由曲面内の各U方向線形状毎にアンカーポイントを一つづつずらしながらその座標値を取得します。

1)最初のU方向線形状では ancor point No. 0 の座標を取得
2)次のU方向線形状では anchor point No. 1 の座標を取得
3)以下同様

U方向線形状は六角形ですから6個取得すれば六角形を一回り、つまりロープ断面の円周方向一回り分に相当します。
一方、最初にオリジナル線形状を N分割する際に、ロープのピッチ数 np の6倍を分割数としていますから( N = 6*np )、上記の6個分の座標値を取得すると、それはロープの捻れが一回りする進行方向1ピッチにちょうど一致することになります。

この操作を繰り返して N + 1 個の座標値を取得すると、ロープを構成する捻れた紐一本分の中心線座標を得ることになります。

ここでは3本の紐を捻ったロープを考えていますから、残りの二本分の紐の中心座標もアンカーポイント位置をそれぞれ2つづつずらしながら取得すればいいことになります。

三つ編みの場合もアンカーポイントの取得順ルールを変更すれば同様に作成することができますので、興味のある方は考えてみてください。
なお、 三つ編みの場合は正12角形のアンカーポイント座標以外に、途中で正12角形の中心の座標も取得する必要があります。( Mac をお使いの方は 043.Distributor の中に三つ編みのサンプルが納められていますからそれを参考にするといいでしょう )


《 3.4 巻き数 n と、分割数 N との関係 》

以上では、巻き数 n = 3 として話を進めてきました。
では、巻き数が n > 3 の場合はどうすればいいでしょうか?

ロープの進行方向1ピッチ分の分割数は 6 あるいは 8 が適切です。( 三つ編みの場合は12 )
これよりも少なければ、捻れた紐の中心線を表す線形状に smooth をかけても綺麗な形にはなりませんし、多すぎても無意味です。

1ピッチ分の分割数を 6 に固定すると考えると、ロープ中心線に沿って最初に掃引する断面形状は正6m角形( m >= 1 なる整数 )でなければなりません。

ですから、巻き数 n の場合には、最初に掃引する断面は n と 6 との最小公倍数にする必要があります( n = 4 ならば正12角形、n = 5 ならば正30角形 )。

ちと、面倒ですね。
でもここで紹介したように、自前で座標値を計算するのではなく、極力 Shade 側に作らせるという方法を採ろうとすれば、残念ながらこういった面倒さは避けて通れないものです。
ロープ形状作成スクリプトのための ウンチク( その5 )
2007年02月05日 (月) 02時43分
加藤俊明
返信
《 1.6 BL_Param(p0, p1, p2, p3, lineL, targetL) の擬似コード 》
 
BL_Param(p0, p1, p2, p3, lineL, targetL) は、bezier 制御点座標 p0〜p3 で与える区間内で( 区間長 lineL )、始端から targetL の長さの位置を与える bezier parameter t を返す。

与えられた線長から bezier parameter t を逆算するには trial & error の反復計算を用いる。

1)初期解 t を仮定し、区間 0 〜 t が与える線長を求める
2)計算された線長と目標とする始端からの線長 targetL との誤差を計算する
3)誤差が許容範囲 allow に収まっているなら、その時の t を答えとして返す。
4)許容範囲を超えているなら、bezier parameter t に修正を加えて、再度線長を計算する。
5)計算された線長が許容誤差範囲内に収まるまで、この計算を繰り返す。
6)誤差が許容範囲内に収まったなら、その時の t を答えとして返す。
7)安全のために、繰り返し計算回数に上限 maxN を設けておき、許容範囲内に収まらなくても、計算回数が maxN に達したなら、その時の t を答えとして返す。

ここで、許容誤差範囲 allow, 最大繰り返し計算回数 maxN, さらに、このメソッド内から呼び出される BL_Length()( 1.5 項参照 )内で使用される simpsonN、この三つのパラメターは重要であり、その値はバランスがとれるように慎重に定めなければならない。( 誤差 =|計算された線長 - 目標とする線長|/目標とする線長 と定義する)

一般に BL_Length() において、simpsonN を大きくすればより精度の高い線長が求まる。
一方、線長から bezier parameter を逆算するBL_Param() では、許容誤差 allow を小さくすればより精度は高まる。

このとき、最大繰り返し計算回数 maxN も allow の大きさに応じて調整しなければ意味をなさない。
maxN は無限回の計算ループに落ち込むのを防ぐための安全処置であるが、いくら allow を小さくしても頻繁に計算回数が maxN に達してしまえば、それによって得られる解は許容誤差を満足しないものであるので、allow の大きさに見合った精度は得られない。

simpsonN を大きくし、allow を小さくして maxN を大きくすれば、理論的には精度の高い解が得られるが、次のことに留意されたい。

1)反復計算なので計算時間が多く必要とされる

2)float の精度に起因する丸め誤差以上に、収束計算の仕組みそのものに起因する誤差を含むため、解の収束はかなり遅く、誤差を小さくしようとすると、必要とされる計算時間が指数関数的に増大してしまう。

3)allow を小さく、maxN を大きく設定して、解の誤差を小さくしようとしても、BL_Length() の中で用いられる simpsonN が大きいと、誤差は大きなままに留まってしまい、場合によっては解が収束しない( 振動を起こす )。
逆に小さすぎれば、必要以上に余計な計算時間を費やすことになる。

このように simpsonN, allow, maxN の値の大きさはバランスよく選ばなければならい。
実験を繰り返し、途中結果を記録して、各自で見つけられたい。

そもそもロープ形状を作成するのに、いかほどの精度があればいいのかをよく考えること。
いきなり、むやみに高い精度を得ようとしてもなかなかうまくいかない。
最初は低い精度から始めて、バランスのとれた simpsonN, allow, maxN を求め、そこから所要の精度に達するまで、simpsonN, allow, maxN を調整していくという方法をとることを推奨する。


引数
  p0〜p3:Bezier 制御点座標
  p0:anchor point i
  p1:out handle i
  p2:in handle i + 1
  p3:anchor point i + 1

  lineL:当該区間の bezier 曲線全長
  targetL:始端からの線長( 0 <= targetL <= lineL )
返り値
  始端からの線長 targetL の位置を与える bezier parameter t( 0 <= t <= 1)

dim p(3) as vec3 // Bezier 制御点座標
dim alow as float // 許容誤差
dim maxN as integer // 最大繰り返し計算回数
dim dsdt as float // 収束計算用の補正係数、bL_Length() により計算される
dim calculatedL as float // bezier parameter 0 〜 t で与えれる区間の線長                   bL_Length() により計算される
dim t as float // bezier parameter( 返り値 )

p(0) = p0
p(1) = p1
p(2) = p2
p(3) = p3
dsdt = 1
t = targetL/lineL
calculatedL = targetL

for i = 0 to maxN
 t = t + (targetL - calculatedL)/dsdt     // i = 0 のとき、t = targetL/lineL
 { calculatedL, dsdt } = BL_Length(p, t) // calculatedL, dsdt を求める
 if Abs((targetL - calculatedL)/targetL) < allow then
  return t     // 誤差が許容範囲内であった
 end if
next

return t     // 許容範囲内に収束しなかったが、ここで計算を打ち切る
ロープ形状作成スクリプトのための ウンチク( その3 - 改訂 )
2007年02月03日 (土) 11時43分
加藤俊明
返信
二カ所の記述ミスを修正の上、再掲します。( 旧記述は削除しました )

-------------------------------------------------------------

【 2. 断面形状を線形状の始端にセットし掃引する 】

1)正面図の原点を中心にして断面形状を作成する
2)線形状の始端の接線ベクトルを求める
3)接線ベクトル方向の緯度経度を求める
4)接線ベクトルの緯度経度を基に断面形状を回転し、線形状の始端位置に移動する。
  これにより線形状始端位置に線形状の接線方向に垂直な面内に断面形状をセットすることができる
5)script command を用いて断面形状を掃引する


《 2.1 線形状の接線ベクトルを求める 》

anchor point と anchor point に挟まれた一つの区間毎に bezier parameter t( 0 <= t <= 1 )によって与えられる位置での接線単位ベクトルを求める。
t = 0 でその区間の始端での接線方向が、t = 1 でその区間の終端での接線方向が求まる。

接線単位ベクトルを与える BL_Tangent(p() as vec3, t as float) as vec3 は 2.2 項を参照のこと。


2.1.1 ハンドル長さがない場合の求め方

ここでハンドルが出ていない bezier 曲線の場合、bezier parameter 基準では端点での接線ベクトルを求めることができない

この場合、t = 0 あるいは t = 1 として求めずに、t = epsilon, t = 1 - epsilon( epsilon は微小の数 )として終端近傍の接線ベクトルを求め、終端の接線ベクトルの代用とする。

epsilon は次のように考えて色々と自分で実験して適切な大きさを見つけなければならない。

a )期待される真の接線ベクトルの方向を実用上問題のない精度内で近似できるほどに小さいこと
b )数値の丸め誤差によってあらぬ方向の接線ベクトルに計算されてしまわないほどに大きいこと

特に b )の条件には十分な注意が必要。

ハンドル長さがない線形状に対して t = 0 or 1 として求めると、後述する接線ベクトルを求める計算では 長さ = 0 のベクトル として計算され、単位ベクトル化の段階で 分母 = 0 となってエラーとなる。

一方、 ハンドル長さがない線形状に対して t = epsilon or t = 1 - epsilon としても epsilon が過度に小さい場合、分母が 0 になることはないものの、float の精度から避けられない数値の丸め誤差によって、とんでもない方向の接線ベクトルが計算されてしまう。

epsilon の大きさは、意外に大きな値にしなければならないが、それでも a )の条件を満たす epsilon は得られる。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - 
色々なケースで実験して御自分で見つけてください。
自分で納得のいく数値が見つかれば、それが「 正解 」です。
「 ハンドル長さがないのなら直線なんだから簡単な話じゃないの 」とは思わないでね。
inhandle には長さが無く、outhandle には長さがあるケースも考えなきゃいけませんから。
こうゆう実験は面倒だけど、bezier を扱ったツールを作ろうと思えば避けて通れないことです。
つまり、プログラミング上での言わずもがなの「 常識 」とみなされているわけでして、ロジックを解説しているどんな書籍やサイトでも、わざわざこのことに触れているのにお目にかかったことはありませんです。ハイ
- - - - - - - - - - - - - - - - - - - - - - - - - - - - 


///////////////////////////////////////////////////
接線単位ベクトルを求める擬似コード
///////////////////////////////////////////////////

BL_Tangent(p, t) ( 2.2項参照 )により接線単位ベクトルが与えられる。

dim p(3) as vec3    // 四つの制御点座標
dim v as vec3
dim t as float // bzier parameter t( 0 <= t <= 1 )
dim epsilon as float // bezier parameter 補正項
dim tanV as vec3 // 接線単位ベクトル

v = p(1) - p(0)
if v.x = 0 and v.y = 0 and v.z = 0 then // inhandle 長さがなかった
 t = Max(t, epsilon) // Max() は二つの引数の内、大なる方を返す関数
end if

v = p(2) - p(3)
if v.x = 0 and v.y = 0 and v.z = 0 then // outhandle 長さがなかった
 t = Min(t, 1 - epsilon)) // Min() は二つの引数の内、小なる方を返す関数
end if

tanV = BL_Tangent(p, t)



《 2.2 BL_Tangent(p, t) の擬似コード 》
 
BL_Tangent(p() as vec3, t as float) as vec3 は bzier parameter t( 0 <= t <= 1 )における接線単位ベクトルを返す。

引数
  p(0)〜p(3):Bezier 制御点座標
  p(0):anchor point i
  p(1):out handle i
  p(2):in handle i + 1
  p(3):anchor point i + 1

  t:bezier parameter( 0 <= t <= 1 )
返り値
  接線単位ベクトル


dim J0, J1, J2, J3 as float
dim v as vec3 // 接線単位ベクトル( 返り値 )
dim length as float

J0 = -3*(1 - t)^2
J1 = 3(1 - t)^2 - 6*t*(1 - t)
J2 = 6*t*(1 - t) - 3*t^2
J3 = 3*t^2

v.x = J0*p(0).x + J1*p(1).x + J2*p(2).x + J3*p(3).x
v.y = J0*p(0).y + J1*p(1).y + J2*p(2).y + J3*p(3).y
v.z = J0*p(0).z + J1*p(1).z + J2*p(2).z + J3*p(3).z

length = Sqrt(v.x^2 + v.y^2 + v.z^2)
v.x = v.x/length // 単位ベクトル化
v.y = v.y/length
v.z = v.z/length

return v



《 2.3 接線ベクトルの緯度経度を求める 》
 
単位ベクトル v の方向を表す緯度経度を求める。
緯度経度の定義は次の通り
 ・原点を中心とした球を考え、X-Z 平面と球との交差線が赤道
 ・球とY-Z 平面の +Z 側の面との交差線が子午線
 ・緯度:北緯が + 方向
 ・経度:東経が + 方向

///////////////////////////////////////////////////
緯度経度を求める擬似コード
///////////////////////////////////////////////////

LatitudeLongitude(v as vec3) as float, as float は 単位ベクトル v の方向を表す緯度経度( radian 角 )を返す。

引数
  v:単位ベクトル
返り値
  経度と緯度

dim latitude, longitude as float // 緯度, 経度( 返り値 )
dim L as float

if v.x = 0 and v.z = 0 then // Y軸上にある場合
 longitude = 0 // 経度
 if v.y > 0 then                 // Yが正方向なら
  latitude = pi/2 // 緯度
 else
  latitude = -pi/2                 // Yが負方向なら
 end if
else
 L = Sqrt(v.x*v.x + v.z*v.z)
 longitude = Acos(v.z/L) // 経度
 if v.x < 0 then                 // Xが負ならば
  longitude = -longitude
 end if
 latitude = Asin(v.y) // 緯度
end if

return latitude, longitude


《 2.4 断面形状を線形状の始端位置にセットする 》

1)掃引断面形状を原点を中心として X-Y 平面上に作成する
2)掃引中心線線形状の始端における接線単位ベクトルの緯度経度を求める。
3)緯度経度にもとづいて、掃引断面形状を script command で回転する
4)掃引中心線線形状の始端位置まで掃引断面形状を script command で移動する
5) script command で掃引を実行する

1)において掃引断面形状が閉じている場合、その面法線の向きが必ず +Z 方向を向くように作成しておきます。

3)の回転では、X-Y 平面に描いた断面形状の「 -Z 」方向を掃引中心線始端の接線ベクトルの向きに一致させます。

上記の二つのルールは重要です、こうしておけば、掃引体の面法線は必ず外側を向くように統一することができます。

3)では script command で次のように操作します。
 ・最初に原点を中心として X 軸まわりに「 - 緯度 」回転( 符号に注意 )
 ・ついで原点を中心として Y 軸まわりに 「 経度 + π(180度)」回転

4)では掃引中心線線形状始端のアンカーポイント座標を求めて、3 )で回転された掃引断面形状を script command で座標値分だけ移動します。
これにより、掃引中心線始端位置に1)で掃引断面形状を描いたときの原点位置を持ってくることになります。
ロープ形状作成スクリプトのための ウンチク( その4 )
2007年02月02日 (金) 22時42分
加藤俊明
返信
《 1.5 BL_Length(p, t) の擬似コード 》
 
method BL_Length(p(), t) as float, as float は、制御点座標 p(0)〜p(3) なる bezier 曲線における bezier parameter 0〜t で与えられる区間の線長を返す。

線長を求める数値積分は Simpson の式を用いており、単純な区分求積法に比べて少ない分割数で高い精度の積分値を得る。
Simpson の式の解説についてはここでは詳述しない。

なお、下記の擬似コードの中で、分割数 simpsonN は必要に応じて適当な数字を割り当てる。
一般に、simpsonN が大きくなるほど、より正確な線長が得られるが、計算時間も必要とされる。

むやみに大きな数字を割り当てるのではなく、小さな数から出発して徐々に値を大きくし、計算される線長がどのようなカーブで収束していくかを確認した上で、適当と判断される大きさを採用すればよい。

なお、1.6 項で述べる線長から bezier parameter を逆算する method 内では、trial & error によって本 method が繰り返し何度も呼び出される。

このため simpsonN に不用意に大きな値を与えると、1.6 項の計算に長大な計算時間を要することになる。

1.6 項での計算における精度と simpsonN との間には関係があるのでそのバランスに注意を要するが、このことについては 1.6 項の中で詳述する。

また返り値として、線長の他に dsdt as float が返されるが、これは 1.6 項での計算に必要とされるものであり、単に線長を求めるだけであるなら、dsdt を返す必要はない。

引数
  p(0)〜p(3):Bezier 制御点座標
  p(0):anchor point i
  p(1):out handle i
  p(2):in handle i + 1
  p(3):anchor point i + 1

  t:bezier parameter( 0 <= t <= 1 )
返り値
  length as float:bezier parameter 0〜t で与えられる区間の線長
  dsdt as float:逆算に必要な係数

dim simpspnN as integer // simpson の式で用いる分割数
dim simpson2N as integer // 実質的な分割数( simpson2N = 2*simpsonN )
dim h as float
dim aa, bb as float
dim J0, J1, J2, J3 as float
dim v as vec3
dim t as float
dim length as float // 線長( 返り値 )
dim dsdt as float // 逆算に必要な係数( 返り値 )

simpsonN = ○○( 実験の上決定のこと )
simpson2N = 2*simpsonN
h = t/simpson2N
dim f(simpson2N) as float

for i = 0 to simpson2N
 t = i*h
 J0 = -3*(1 - t)^2
 J1 = 3(1 - t)^2 - 6*t*(1 - t)
 J2 = 6*t*(1 - t) - 3*t^2
 J3 = 3*t^2
 v.x = J0*p(0).x + J1*p(1).x + J2*p(2).x + J3*p(3).x
 v.y = J0*p(0).y + J1*p(1).y + J2*p(2).y + J3*p(3).y
 v.z = J0*p(0).z + J1*p(1).z + J2*p(2).z + J3*p(3).z
 f(i) = Sqrt(v.x^2 + v.y^2 + v.z^2)
next

aa = 0
for i = 1 to simpsonN
 aa = aa + f(2*i - 1)
next
aa = 4*aa

bb = 0
for i = 1 to simpsonN - 1
 bb = bb + f(2*i)
next
bb = 2*bb

dsdt = f(simpson2N)
length = (f(0) + f(simpson2N) + aa + bb)*h/3

return length, dsdt
Re[491]: ロープ形状作成スクリプトのための ウンチク( その2 )
2007年01月31日 (水) 22時05分
でった☆
返信
あ、脳みそから煙でた(・д・)

まずはHDDに保存しました。。じっくり読ませていただきます。
Re[488]: 確認 - その2
2007年01月31日 (水) 22時02分
でった☆
返信
> python の計算で分母が 0 になってオーバーフローしてしまった場合、エラーとなってストップしますか ?
> それとも、INF のような形でオーバーフローしたまま計算は続行されてしまいますか ?

ストップします。
エラーを見越した構造にすることで回避します。
try:
        1/0
except:
        エラー処理
エラー処理に基づいて処理を継続

という流れです。
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
過去ログ
投稿順に表示
スレッドごとに表示