2013-03-06 27 views
12

Hãy nói rằng tôi có một Bezier curveB(u), nếu tôi tăng u tham số với một tốc độ không đổi Tôi không có được một tốc độ di chuyển costant dọc theo đường cong, bởi vì mối quan hệ giữa u tham số và điểm thu được đánh giá đường cong không phải là tuyến tính.Bezier Curves Cubic: di chuyển với tốc thống nhất

Tôi đã đọc và triển khai article của David Eberly. Nó giải thích làm thế nào để di chuyển ở tốc độ không đổi dọc theo một đường cong tham số.

Giả sử tôi có một hàm F(t) mà mất như là đầu vào một giá trị thời gian t và một chức năng tốc độ sigma mà trả về giá trị tốc độ lúc t, tôi có thể có được một tốc độ di chuyển costant dọc theo đường cong, thay đổi thông số t với một tốc độ không đổi : B(F(t))

Cốt lõi của bài viết tôi đang sử dụng là chức năng sau:

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

Nó cho phép tôi để có được những thông số đường cong u tính bằng thời gian cung cấp t và hàm sigma. Bây giờ chức năng hoạt động tốt khi sigma tốc độ là chi phí. Nếu sigma đại diện cho một sự tăng tốc đồng đều, tôi nhận được các giá trị sai từ nó.

Dưới đây là ví dụ về đường cong Bezier thẳng, trong đó P0 và P1 là các điểm điều khiển, T0 T1 tiếp tuyến. Các đường cong được định nghĩa:

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

enter image description here

Hãy nói rằng tôi muốn biết vị trí dọc theo đường cong lúc t = 3. Nếu tôi một vận tốc không đổi:

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

và các dữ liệu sau:

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

tôi analitically có thể tính toán vị trí:

px = v0 * t = 1 * 3 = 3 

Nếu tôi giải quyết phương trình tương tự sử dụng spline Bezier của tôi và thuật toán ở trên với n =5 Tôi nhận được:

px = 3.002595; 

Xem xét số lượng xấp xỉ giá trị khá chính xác (tôi đã thực hiện rất nhiều thử nghiệm về điều đó. Tôi bỏ qua chi tiết nhưng Bezier thực hiện đường cong của tôi là tốt và chiều dài của đường cong chính nó được tính toán khá chính xác bằng cách sử dụng Gaussian Quadrature).

Bây giờ Nếu tôi cố gắng xác định sigma là hàm tăng tốc đồng đều, tôi nhận được kết quả không tốt. Hãy xem xét các dữ liệu sau:

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

tôi có thể tính toán thời gian một hạt sẽ đạt P1 sử dụng phương trình chuyển động tuyến tính:

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

t tôi có thể tính toán khả năng tăng tốc:

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

Tôi có tất cả dữ liệu để xác định hàm sigma của mình:

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

Nếu tôi analitically giải quyết này tôi mong đợi vận tốc sau của một hạt sau thời gian t =3:

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

và vị trí sẽ là:

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

Nhưng nếu tôi tính toán nó với alorithm ở trên, kết quả vị trí:

px = 4.358587 

hoàn toàn khác fr om những gì tôi đang mong đợi.

Xin lỗi vì bài đăng dài, nếu có ai đủ kiên nhẫn để đọc nó, tôi sẽ rất vui.

Bạn có gợi ý gì không? Tôi đang thiếu gì? Bất kỳ ai cũng có thể cho tôi biết tôi đang làm gì sai?


EDIT: Tôi đang thử với đường cong 3D Bezier. Định nghĩa theo cách này:

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

và đạo hàm:

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

và thuật toán cung cấp cho bạn gì cho t = 6.6666 ...? Có phải đó là giá trị 10, tức là L hoặc một giá trị khác không? – lmsteffan

Trả lời

1

tôi đoán là n=5 đơn giản là không cung cấp cho bạn đầy đủ chính xác cho vấn đề trong tầm tay. Thực tế là nó là OK cho trường hợp vận tốc không đổi không ngụ ý nó là cho trường hợp tăng tốc không đổi quá. Thật không may, bạn sẽ phải xác định bản thân thỏa hiệp cung cấp giá trị cho n phù hợp với nhu cầu và nguồn lực của bạn.

Dù sao, nếu bạn thực sự có một parametrization vận tốc không đổi X (u (t)) làm việc với đầy đủ chính xác, sau đó bạn có thể đổi tên này "thời gian" tham số t một "không gian" (khoảng cách) tham số s, vì vậy rằng những gì bạn thực sự có là X (s) và bạn chỉ phải cắm (các) s mà bạn cần: X (s (t)). Trong trường hợp của bạn (gia tốc không đổi), s (t) = s + u t + a t /2, trong đó u và một cách dễ dàng được xác định từ dữ liệu đầu vào của bạn.

1

Tôi nghĩ bạn chỉ cần gõ lỗi ở đâu đó trong các chức năng không được hiển thị trong quá trình triển khai, Y và DY. Tôi đã thử một đường cong một chiều với P0 = 0, T0 = 1, T1 = 9, P1 = 10 và nhận được 3.6963165 với n = 5, được cải thiện thành 3.675044 với n = 30 và 3,6750002 với n = 100.

Nếu việc triển khai của bạn là hai chiều, hãy thử với P0 = (0, 0), T0 = (1, 0), T1 = (9, 0) và P1 = (10, 0). Sau đó thử lại với P0 = (0, 0), T0 = (0, 1), T1 = (0, 9) và P1 = (0, 10).

Nếu bạn đang sử dụng C, hãy nhớ rằng toán tử^KHÔNG có nghĩa là số mũ. Bạn phải sử dụng pow (u, 3) hoặc u * u * u để lấy khối lập phương của u.

Thử in các giá trị của càng nhiều thứ càng tốt trong mỗi lần lặp lại. Đây là những gì tôi nhận được:

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 

Tôi đã gỡ rối rất nhiều chương trình như thế này bằng cách in ra một tấn biến, sau đó tính toán từng giá trị bằng tay và đảm bảo chúng giống nhau.

+0

cảm ơn dữ liệu. Tôi sẽ cố gắng thực hiện thêm một số thử nghiệm. Thực ra tôi đang sử dụng đường cong 3D Bezier. Tôi sẽ chỉnh sửa bài đăng bằng mã. – Heisenbug