2012-07-12 92 views
5

我使用bezier曲線作爲我的太空飛船沿着它們進入碼頭的路徑。我有一個簡單的算法來計算,由船舶應在時間t沿三次Bezier曲線:立方貝塞爾曲線:最大梯度和避免碰撞?

public class BezierMovement{ 
    public BezierMovement(){ 
     // start docking straight away in this test version 
     initDocking(); 
    } 

    private Vector3 p0; 
    private Vector3 p1; 
    private Vector3 p2; 
    private Vector3 p3; 

    private double tInc = 0.001d; 
    private double t = tInc; 

    protected void initDocking(){ 

     // get current location 
     Vector3 location = getCurrentLocation(); 

     // get docking point 
     Vector3 dockingPoint = getDockingPoint(); 

     // ship's normalised direction vector 
     Vector3 direction = getDirection(); 

     // docking point's normalised direction vector 
     Vector3 dockingDirection = getDockingDirection(); 

     // scalars to multiply normalised vectors by 
     // The higher the number, the "curvier" the curve 
     float curveFactorShip = 10000.0f; 
     float curveFactorDock = 2000.0f; 

     p0 = new Vector3(location.x,location.y,location.z); 

     p1 = new Vector3(location.x + (direction.x * curveFactorShip), 
         location.y + (direction.y * curveFactorShip), 
         location.z + (direction.z * curveFactorShip)); 

     p2 = new Vector3(dockingPoint.x + (dockingDirection.x * curveFactorDock), 
         dockingPoint.y + (dockingDirection.y * curveFactorDock), 
         dockingPoint.z + (dockingDirection.z * curveFactorDock)); 

     p3 = new Vector3(dockingPoint.x, dockingPoint.y, dockingPoint.z); 


    } 

    public void incrementPosition() { 

     bezier(p0, p1, p2, p3, t, getCurrentLocation()); 

     // make ship go back and forth along curve for testing    
     t += tInc; 

     if(t>=1){ 
      tInc = 0-tInc; 
     } else if(t<0){ 
      tInc = 0-tInc; 
     } 

    } 

    protected void bezier(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, double t, Vector3 outputVector){ 

     double a = (1-t)*(1-t)*(1-t); 
     double b = 3*((1-t)*(1-t))*t; 
     double c = 3*(1-t)*(t*t); 
     double d = t*t*t; 

     outputVector.x = a*p0.x + b*p1.x + c*p2.x + d*p3.x; 
     outputVector.y = a*p0.y + b*p1.y + c*p2.y + d*p3.y; 
     outputVector.z = a*p0.z + b*p1.z + c*p2.z + d*p3.z; 

    } 
} 

曲線起點是飛船的位置,終點是入口處停靠站(紅點在圖上)。飛船的方向有一個歸一化的矢量,而對接艙有另一個歸一化的矢量,用於指示船隻必須駛入的方向,以便當它到達時直接對準塢站(圖中的黃線)

綠線是宇宙飛船的可能路徑,紫色圓圈是宇宙飛船的半徑。最後,黑匣子是該站的邊框。

enter image description here

我有兩個問題:

  1. 的飛船應該只能夠把以每秒
  2. 飛船不能通過站飛[R弧度

我認爲這可以翻譯爲:

a)。找到將給出船舶不必轉得太緊的路徑的「曲線因素」(控制點長度)

b)。找到無法避免與車站碰撞的太空船位置/方向(並創建一條路徑指引它離開該狀態,因此它可以與a部分相連))

但是,對於這兩者,我沒有多少運氣找到解決方案。我已經有了檢測向量,方框,點和球體之間交點的代碼,但是還沒有貝塞爾曲線。我也有功能讓我找到兩點之間的距離。

任何幫助將非常感激

謝謝, 詹姆斯

回答

3

找到一個三次Bezier曲線的交點準確解決包括一個5或第6次多項式。更可行的解決方案是使用數值方法,或細分貝塞爾曲線。

protected void subdivide(
     Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, 
     Vector3 q0, Vector3 q1, Vector3 q2, Vector3 q3, 
     Vector3 q4, Vector3 q5, Vector3 q6) { 

    q0.x = p0.x; q0.y = p0.y; q0.z = p0.z; 
    q6.x = p3.x; q6.y = p3.y; q6.z = p3.z; 

    q1.x = (p0.x + p1.x) * 0.5; 
    q1.y = (p0.y + p1.y) * 0.5; 
    q1.z = (p0.z + p1.z) * 0.5; 

    q5.x = (p2.x + p3.x) * 0.5; 
    q5.y = (p2.y + p3.y) * 0.5; 
    q5.z = (p2.z + p3.z) * 0.5; 

    double x3 = (p1.x + p2.x) * 0.5; 
    double y3 = (p1.y + p2.y) * 0.5; 
    double z3 = (p1.z + p2.z) * 0.5; 

    q2.x = (q1.x + x3) * 0.5; 
    q2.y = (q1.y + y3) * 0.5; 
    q2.z = (q1.z + z3) * 0.5; 

    q4.x = (x3 + q1.x) * 0.5; 
    q4.y = (y3 + q1.y) * 0.5; 
    q4.z = (z3 + q1.z) * 0.5; 

    q3.x = (q2.x + q4.x) * 0.5; 
    q3.y = (q2.y + q4.y) * 0.5; 
    q3.z = (q2.z + q4.z) * 0.5; 
} 

q1 .. q3變爲第一段。 q3 .. q6成爲第二部分。

將曲線細分2-5次,並將控制點用作折線。


curvature可以在各段的端點來計算:

protected double curvatureAtStart(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { 
    double dx1 = p1.x - p0.x; 
    double dy1 = p1.y - p0.y; 
    double dz1 = p1.z - p0.z; 

    double A = dx1 * dx1 + dy1 * dy1 + dz1 * dz1; 

    double dx2 = p0.x - 2*p1.x + p2.x; 
    double dy2 = p0.y - 2*p1.y + p2.y; 
    double dz2 = p0.z - 2*p1.z + p2.z; 

    double B = dx1 * dx2 + dy1 * dy2 + dz1 * dz2; 

    double Rx = (dx2 - dx1*B/A)/A*2/3; 
    double Ry = (dy2 - dy1*B/A)/A*2/3; 
    double Rz = (dz2 - dz1*B/A)/A*2/3; 

    return Math.sqrt(Rx * Rx + Ry * Ry + Rz * Rz); 
} 

爲了解決問題1,細分曲線幾次,並計算曲率在每個分段的端點。這只是一個近似值,但是您可以選擇性地細分高曲率段以在該區域中獲得更好的近似值。


爲了解決問題2,可以細分三條曲線:

  • 一個以速度零在兩個端點(C0)。這將產生一條直線。
  • 一個在第一個端點處速度爲零,另一個在第二個端點(C1)。
  • 一個在第一個端點處速度爲1,第二個爲零(C2)。

如果以相同方式細分所有曲線,則可以快速評估最終曲線的控制點。你融入相應的控制點,在終點由速度參數化:

C[i] = C0[i] + (C1[i] - C0[i])*v1 + (C2[i] - C0[i])*v2 

您可以用此找到有效的參數範圍內,所以沒有段(評價直線段)相交站。 (v1v2可以高於1.0)。

+0

謝謝!並抱歉花了這麼久回到你身邊。我將問題標記爲正確的,儘管最終我採用了不同的方法,在繼續進入停靠點之前,我使用了一個'側點',如果車站在路上,那麼它將首先進入船舶。 – 2012-07-19 12:47:54