13

ベジエ曲線 があるとしましょう。パラメーターを一定の割合でB(u)インクリメントuすると、曲線に沿って一定速度の移動がu得られません。これは、パラメーターと曲線を評価して得られたポイントとの関係が線形ではないためです。

David Eberly の記事を読んで実装しました。パラメトリック曲線に沿って一定速度で移動する方法を説明します。

F(t)時間の値を入力として受け取る関数と、 timeでの速度の値を返すt速度関数があるとします。一定の割合で t パラメータを変化させて、曲線に沿って一定速度の移動を取得できます。sigmatB(F(t))

私が使用している記事のコアは、次の関数です。

float umin, umax; // The curve parameter interval [umin,umax].
Point Y (float u); // The position Y(u), umin <= u <= umax.
Point DY (float u); // The derivative dY(u)/du, umin <= u <= umax.
float LengthDY (float u) { return Length(DY(u)); }
float ArcLength (float t) { return Integral(umin,u,LengthDY()); }
float L = ArcLength(umax); // The total length of the curve.
float tmin, tmax; // The user-specified time interval [tmin,tmax]
float Sigma (float t); // The user-specified speed at time t.

float GetU (float t) // tmin <= t <= tmax
{
  float h = (t - tmin)/n; // step size, `n' is application-specified
  float u = umin; // initial condition
  t = tmin; // initial condition
  for (int i = 1; i <= n; i++)
  {
    // The divisions here might be a problem if the divisors are
    // nearly zero.
    float k1 = h*Sigma(t)/LengthDY(u);
    float k2 = h*Sigma(t + h/2)/LengthDY(u + k1/2);
    float k3 = h*Sigma(t + h/2)/LengthDY(u + k2/2);
    float k4 = h*Sigma(t + h)/LengthDY(u + k3);
    t += h;
    u += (k1 + 2*(k2 + k3) + k4)/6;
  }
  return u;
}

提供された時間とシグマ関数uを使用して計算された曲線パラメーターを取得できます。tこれで、速度シグマが一定の場合に関数が正常に機能します。シグマが一様な加速を表している場合、それから間違った値が得られます。

これは、直線ベジエ曲線の例です。ここで、P0 と P1 はコントロール ポイントで、T0 T1 は接線です。曲線の定義:

[x,y,z]= B(u) =(1–u)3P0 + 3(1–u)2uT0 + 3(1–u)u2T1 + u3P2 

ここに画像の説明を入力

time での曲線に沿った位置を知りたいとしましょうt = 3。速度が一定の場合:

float sigma(float t)
{
  return 1f;
}

および次のデータ:

V0 = 1;
V1 = 1;
t0 = 0;
L = 10;

位置を分析的に計算できます。

px = v0 * t = 1 * 3 = 3

ベジエ スプラインと上記のアルゴリズムを使用して同じ方程式を解くと、次のようになりますn =5

px = 3.002595;

数値近似を考慮すると、値は非常に正確です (私はそれについて多くのテストを行いました。詳細は省略しますが、ベジエ曲線の実装は問題なく、曲線自体の長さはGaussian Quadratureを使用して非常に正確に計算されます)。

ここで、sigma を一様な加速関数として定義しようとすると、悪い結果が得られます。次のデータを検討してください。

V0 = 1;
V1 = 2;
t0 = 0;
L = 10;

線形運動方程式を使用して、粒子が P1 に到達する時間を計算できます。

L = 0.5 * (V0 + V1) * t1 =>
t1 = 2 * L / (V1 + V0) = 2 * 10 / 3 = 6.6666666

私は加速度をt計算することができます:

a = (V1 - V0) / (t1 - t0) = (2 - 1) / 6.6666666  = 0.15

シグマ関数を定義するためのすべてのデータがあります。

float sigma (float t)
{
  float speed = V0 + a * t;
}

これを解析的に解決すると、時間後の粒子の速度は次のようになると予想されますt =3

Vx = V0 + a * t = 1 + 0.15 * 3 = 1.45

位置は次のようになります。

px = 0.5 * (V0 + Vx) * t = 0.5 * (1 + 1.45) * 3 = 3.675

しかし、上記のアルゴリズムで計算すると、位置は次のようになります。

px = 4.358587

それは私が期待しているものとはかなり異なります。

長文失礼しました、どなたか読んでいただけると嬉しいです。

何か提案はありますか?何が欠けていますか?誰が私が間違っているのか教えてくれますか?


編集: 3D ベジエ曲線を試しています。次のように定義します。

public Vector3 Bezier(float t)
{
    float a = 1f - t;
    float a_2 = a * a;
    float a_3 = a_2 *a;

    float t_2 = t * t;

    Vector3 point = (P0 * a_3) + (3f * a_2 * t * T0) + (3f * a * t_2 * T1) + t_2 * t * P1 ;

    return point;
}

および導関数:

public Vector3 Derivative(float t)
{
    float a = 1f - t;
    float a_2 = a * a;
    float t_2 = t * t;
    float t6 = 6f*t;

    Vector3 der = -3f * a_2 * P0 + 3f * a_2 * T0 - t6 * a * T0 - 3f* t_2 * T1 + t6 * a * T1 + 3f * t_2 * P1;

    return der;
}
4

2 に答える 2

1

私の推測では、n=5目前の問題に対して十分な精度が得られないだけです。一定速度の場合に問題がないという事実は、一定加速度の場合にも問題がないことを意味するものではありません。n残念ながら、ニーズとリソースに合った価値を提供する妥協点を自分で定義する必要があります。

とにかく、十分な精度で機能する一定速度のパラメーター化Xt (u(t)) が実際にある場合は、この「時間」パラメーターの名前を「空間」(距離) パラメーターsに変更して、実際にXになるようにすることができます。 (s) であり、必要な s(t) をプラグインするだけで済みます: X (s(t))。あなたの場合(一定の加速度)、s(t)= s 0 + ut + at 2 / 2で、uとaは入力データから簡単に決定されます。

于 2013-03-17T00:20:45.543 に答える
1

実装に表示されていない関数 Y と DY のどこかにタイプミスがあるだけだと思います。P0 = 0、T0 = 1、T1 = 9、P1 = 10 で 1 次元曲線を試してみたところ、n=5 で 3.6963165 になり、n=30 で 3.675044、n=100 で 3.6750002 に改善されました。

実装が 2 次元の場合は、P0 = (0, 0)、T0 = (1, 0)、T1 = (9, 0)、および P1 = (10, 0) で試してください。次に、P0 = (0, 0)、T0 = (0, 1)、T1 = (0, 9)、および P1 = (0, 10) で再試行します。

C を使用している場合、^ 演算子は指数を意味しないことに注意してください。u の立方体を取得するには、pow(u, 3) または u*u*u を使用する必要があります。

各反復でできるだけ多くのものの値を出力してみてください。これが私が得たものです:

i=1
    h=0.6
    t=0.0
    u=0.0
    LengthDY(u)=3.0
    sigma(t)=1.0
    k1=0.2
    sigma(t+h/2)=1.045
    LengthDY(u+k1/2)=6.78
    k2=0.09247787
    LengthDY(u+k2/2)=4.8522377
    k3=0.12921873
    sigma(t+h)=1.09
    LengthDY(u+k3)=7.7258916
    k4=0.08465043
    t_new=0.6
    u_new=0.12134061
i=2
    h=0.6
    t=0.6
    u=0.12134061
    LengthDY(u)=7.4779167
    sigma(t)=1.09
    k1=0.08745752
    sigma(t+h/2)=1.135
    LengthDY(u+k1/2)=8.788503
    k2=0.0774876
    LengthDY(u+k2/2)=8.64721
    k3=0.078753725
    sigma(t+h)=1.1800001
    LengthDY(u+k3)=9.722377
    k4=0.07282171
    t_new=1.2
    u_new=0.20013426
i=3
    h=0.6
    t=1.2
    u=0.20013426
    LengthDY(u)=9.723383
    sigma(t)=1.1800001
    k1=0.072814174
    sigma(t+h/2)=1.225
    LengthDY(u+k1/2)=10.584761
    k2=0.069439456
    LengthDY(u+k2/2)=10.547299
    k3=0.069686085
    sigma(t+h)=1.27
    LengthDY(u+k3)=11.274727
    k4=0.06758479
    t_new=1.8000001
    u_new=0.26990926
i=4
    h=0.6
    t=1.8000001
    u=0.26990926
    LengthDY(u)=11.276448
    sigma(t)=1.27
    k1=0.06757447
    sigma(t+h/2)=1.315
    LengthDY(u+k1/2)=11.881528
    k2=0.06640561
    LengthDY(u+k2/2)=11.871877
    k3=0.066459596
    sigma(t+h)=1.36
    LengthDY(u+k3)=12.375444
    k4=0.06593703
    t_new=2.4
    u_new=0.3364496
i=5
    h=0.6
    t=2.4
    u=0.3364496
    LengthDY(u)=12.376553
    sigma(t)=1.36
    k1=0.06593113
    sigma(t+h/2)=1.405
    LengthDY(u+k1/2)=12.7838
    k2=0.06594283
    LengthDY(u+k2/2)=12.783864
    k3=0.0659425
    sigma(t+h)=1.45
    LengthDY(u+k3)=13.0998535
    k4=0.06641296
    t_new=3.0
    u_new=0.4024687

大量の変数を出力し、それぞれの値を手で計算し、それらが同じであることを確認するだけで、このような多くのプログラムをデバッグしてきました。

于 2013-03-17T05:48:30.167 に答える