2013-03-06 11 views
12

Diciamo ho un Bezier curveB(u), se Incremento u parametro a una velocità costante non ottengo un movimento velocità costante lungo la curva, perché il rapporto tra u parametro e il punto ottenuto valutando la curva non è lineare.Bezier curve cubiche: muove con accelerazione uniforme

Ho letto e implementato il article di David Eberly. Spiega come muoversi a velocità costante lungo una curva parametrica.

Supponiamo Ho una funzione F(t) che prende in ingresso un valore di tempo t e una funzione di velocità sigma che restituisce il valore della velocità al momento t, che possono ottenere un movimento velocità costante lungo la curva, parametro che varia t a velocità costante : B(F(t))

il nucleo di questo articolo che sto utilizzando è il seguente funzione:

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; 
} 

mi permette di ottenere il parametro della curva u calcolato usando il tempo in dotazione t e funzione sigma. Ora la funzione funziona correttamente quando la sigma della velocità è costante. Se sigma rappresenta un'accelerazione uniforme, ricevo valori sbagliati.

Ecco un esempio di curva lineare di Bézier, dove P0 e P1 sono i punti di controllo, T0 T1 la tangente. La curva è definita:

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

enter image description here

Diciamo che voglio conoscere la posizione lungo la curva al momento t = 3. Se una velocità costante:

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

ed i seguenti dati:

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

posso analiticamente calcolare la posizione:

px = v0 * t = 1 * 3 = 3 

Se risolvere la stessa equazione utilizzando la spline Bezier e l'algoritmo sopra con n =5 ottengo:

px = 3.002595; 

Considerando l'approssimazione numerica il valore è abbastanza preciso (ho fatto un sacco di test su questo. Tralascio i dettagli ma Bezier l'implementazione delle mie curve va bene e la lunghezza della curva è calcolata in modo abbastanza preciso usando Gaussian Quadrature).

Ora se provo a definire sigma come funzione di accelerazione uniforme, ottengo risultati negativi. consideri i seguenti dati:

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

posso calcolare il tempo una particella raggiungerà P1 utilizzando le equazioni di movimento lineare:

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

Avendo t posso calcolare l'accelerazione:

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

Ho tutti i dati per definire la mia funzione sigma:

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

Se analiticamente risolvere questo mi aspetto le seguenti velocità di una particella dopo il tempo t =3:

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

e la posizione sarà:

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

Ma se calcolarlo con il Aloritmo sopra, i risultati di posizione:

px = 4.358587 

che è abbastanza diverso da om che cosa mi aspetto

Scusate per il post lungo, se qualcuno ha abbastanza pazienza per leggerlo, sarei felice.

Avete qualche suggerimento? Cosa mi sto perdendo? Qualcuno può dirmi cosa sto facendo male?


EDIT: Sto cercando con curva di Bezier 3D. Definito in questo modo:

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; 
} 

e la derivata:

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; 
} 
+0

e cosa ti dà l'algoritmo per t = 6.6666 ...? È il valore 10, cioè L o un altro? – lmsteffan

risposta

1

mia ipotesi è che n=5 semplicemente non ti dà una precisione sufficiente per il problema in questione. Il fatto che sia OK per il caso di velocità costante non implica che sia anche per il caso di accelerazione costante. Sfortunatamente dovrai definire te stesso il compromesso che fornisce il valore per n che si adatta alle tue esigenze e risorse.

In ogni caso, se davvero hanno una parametrizzazione velocità costante X (u (t)) che funziona con sufficiente precisione, allora si può rinominare questo "tempo" parametro t uno "spazio" (distanza) parametro s, così che quello che hai veramente è un (s), e devi solo collegare la s (t) di cui hai bisogno: X (s (t)). Nel tuo caso (accelerazione costante), s (t) = s + u t + a t /2, dove u e a sono facilmente determinati dai dati di input.

1

Penso che abbiate semplicemente un errore di battitura da qualche parte nelle funzioni non mostrate nella vostra implementazione, Y e DY. Ho provato una curva unidimensionale con P0 = 0, T0 = 1, T1 = 9, P1 = 10 e ottenuto 3,66916165 con n = 5, che è migliorato a 3,675044 con n = 30 e 3,6750002 con n = 100.

Se l'implementazione è bidimensionale, provare con P0 = (0, 0), T0 = (1, 0), T1 = (9, 0) e P1 = (10, 0). Quindi riprovare con P0 = (0, 0), T0 = (0, 1), T1 = (0, 9) e P1 = (0, 10).

Se si utilizza C, ricordare che l'operatore^NON significa esponente. Devi usare pow (u, 3) o u * u * u per ottenere il cubo di u.

Provare a stampare i valori di quante più cose possibile in ogni iterazione. Ecco quello che ho ottenuto:

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 

ho il debug un sacco di programmi come questo semplicemente stampare una tonnellata di variabili, per determinare ogni valore a mano, e fare in modo che siano la stessa cosa.

+0

grazie per i dati. Proverò a fare altri esperimenti. In realtà sto usando le curve 3D di Bezier. Modificherò il post con il codice. – Heisenbug

Problemi correlati