2013-03-06 7 views
12

Sagen wir, ich habe eine Bezier curveB(u), wenn ich u Parameter mit einer konstanten Rate erhöht Ich habe keinen costant Geschwindigkeit Bewegung entlang der Kurve erhalten, da die Beziehung zwischen u Parameter und dem Punkt Die Auswertung der Kurve ist nicht linear.Bezier Cubic Kurven: mit gleichmäßiger Beschleunigung bewegen

Ich habe gelesen und implementiert ein David Eberly article. Es erklärt, wie man sich mit konstanter Geschwindigkeit entlang einer parametrischen Kurve bewegt.

glaube, ich habe eine Funktion F(t), die einen Zeitwert t als Eingabe nimmt und eine Geschwindigkeitsfunktion sigma, die den Drehzahlwert zum Zeitpunkt kehrt t, I eine costant Geschwindigkeitsbewegung entlang der Kurve erhalten, t Parameter mit einer konstanten Rate unterschiedlichen : B(F(t))

der Kern des Artikels ist verwende ich die folgende Funktion:

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

Es erlaubt mir, die Kurvenparameter u berechnet zu bekommen die mitgelieferte Zeit mit t und Sigma-Funktion. Jetzt funktioniert die Funktion, wenn die Geschwindigkeit sigma ist costant. Wenn Sigma eine gleichförmige Beschleunigung darstellt, erhalte ich falsche Werte.

Hier ist ein Beispiel einer geraden Bezier-Kurve, wobei P0 und P1 die Kontrollpunkte sind, T0 T1 die Tangente. Die Kurve ist definiert:

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

enter image description here

Lassen Sie uns sagen, dass ich die Position entlang der Kurve zum Zeitpunkt t = 3 wissen wollen. Wenn ich eine konstante Geschwindigkeit:

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

und die folgenden Daten:

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

ich die Position analytisch berechnen kann:

px = v0 * t = 1 * 3 = 3 

Wenn ich lösen die gleiche Gleichung mit meinem Bezierspline und der obige Algorithmus mit n =5 erhalte ich:

px = 3.002595; 

Betrachtet man die numerische Approximation, ist der Wert ziemlich genau (ich habe eine Menge Tests durchgeführt). Ich lasse Details weg, aber Bézier meine Kurven Implementierung ist in Ordnung und die Länge der Kurve selbst wird ziemlich genau mit Gaussian Quadrature berechnet).

Wenn ich jetzt versuche, Sigma als eine einheitliche Beschleunigungsfunktion zu definieren, bekomme ich schlechte Ergebnisse. Betrachten Sie die folgenden Daten:

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

ich die Zeit ein Teilchen das P1 unter Verwendung eines linearen Bewegungsgleichungen erreicht berechnen kann:

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

Mit t I Beschleunigung berechnen:

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

Ich habe alle Daten, um meine Sigma-Funktion zu definieren:

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

Wenn ich analytisch dieses Problem lösen würde ich die folgende Geschwindigkeit eines Teilchens nach der Zeit erwarten t =3:

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

und die Position wird:

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

Aber wenn ich berechnen sie mit der Alorithmus oben, die Position Ergebnisse:

px = 4.358587 

das ist ziemlich anders fr om was ich erwarte.

Sorry für die lange Post, wenn jemand genug Geduld hat, um es zu lesen, würde ich mich freuen.

Haben Sie einen Vorschlag? Was vermisse ich? Jeder kann mir sagen, was ich falsch mache?


EDIT: ich mit 3D-Bezier-Kurve bin versucht. Definiert auf diese Weise:

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

und die Ableitung:

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

und was gibt der Algorithmus für t = 6.6666 ...? Ist es der Wert 10, d. H. L, oder ein anderer? – lmsteffan

Antwort

1

Meine Vermutung ist, dass n=5 einfach nicht, dass Sie für das Problem bei der Hand eine ausreichende Genauigkeit nicht geben. Die Tatsache, dass es für den Fall konstanter Geschwindigkeit in Ordnung ist, bedeutet nicht, dass es auch für den Fall konstanter Beschleunigung ist. Leider müssen Sie sich den Kompromiss definieren, der den Wert für n liefert, der Ihren Bedürfnissen und Ressourcen entspricht.

Wie auch immer, wenn Sie wirklich eine konstante Geschwindigkeit Parametrisierung X (u (t)), die mit ausreichender Genauigkeit funktioniert, dann können Sie diese Parameter „Zeit“ t ein „Raum“ (Abstand) Parameter s, umbenennen, so das, was Sie wirklich haben, ist ein X (s), und Sie müssen nur die s (t) einstecken, die Sie benötigen: X (s (t)). In Ihrem Fall (konstante Beschleunigung), s (t) = s + t + a t /2, wo u und a sind leicht aus Ihren Eingabedaten bestimmt.

1

Ich denke, Sie haben einfach einen Tippfehler irgendwo in den Funktionen nicht in Ihrer Implementierung gezeigt, Y und DY. Ich probierte eine eindimensionale Kurve mit P0 = 0, T0 = 1, T1 = 9, P1 = 10 und erhielt 3.6963165 mit n = 5, was sich zu 3.675044 mit n = 30 und 3.6750002 mit n = 100 verbesserte.

Wenn Ihre Implementierung zweidimensional ist, versuchen Sie mit P0 = (0, 0), T0 = (1, 0), T1 = (9, 0) und P1 = (10, 0). Versuchen Sie es dann erneut mit P0 = (0, 0), T0 = (0, 1), T1 = (0, 9) und P1 = (0, 10).

Wenn Sie C verwenden, denken Sie daran, dass der^Operator NICHT den Exponenten bedeutet. Sie müssen pow (u, 3) oder u * u * u verwenden, um den Würfel von u zu erhalten.

Versuchen Sie, die Werte von so viel Zeug wie möglich in jeder Iteration auszudrucken. Hier ist, was ich habe:

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 

Ich habe viele Programme wie dieses debuggt nur um eine Tonne Variablen auszudrucken, dann jeden Wert von Hand zu berechnen, und sicherstellen, dass sie gleich sind.

+0

danke für die Daten. Ich werde versuchen, weitere Experimente zu machen. Eigentlich verwende ich 3D Bezier-Kurven. Ich werde den Beitrag mit dem Code bearbeiten. – Heisenbug

Verwandte Themen