2012-07-12 93 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