English 中文(简体)
计算弯曲面的地平线?
原标题:
  • 时间:2009-02-21 17:20:30
  •  标签:

我需要找到一个弯曲面的视觉地平线的2个点。

我有:

  • XYZ of the 4 corner points
  • XYZ of the 2 curved edge bezier points

我需要计算:

  • XY of the horizon points
  • XYZ of the horizon points
最佳回答

首先,您需要将您的3D贝塞尔曲线转换为2D。如果我没记错的话,只需像渲染3D点一样投影曲线即可。

之后,您必须找到曲线的极值。

A small HowTo:

将您的贝塞尔曲线从贝塞尔表示形式转换为形式为多项式的方式

  x(t) = a*t^3 + b*t^2 + c*t + d
  y(t) = e*t^3 + f*t^2 + g*t + g

  Here t is your interpolation variable that goes from 0 to 1.
  a to d are the coefficients for the curve along the x-axis
  e to g are the coefficients for the curve along the y-axis.

Now you build the first derivation of the curve (easy as it s a polynomail). This will give you a quadratic equation. Solve these for the roots and discard all roots that are outside the 0..1 range. Again finding the roots is easy as it s just a quadratic polynomial.

您有一堆根。将这些全部插入原始贝塞尔曲线中,评估它们的位置,您将得到一堆点。如果存在,则极值将在这些点之间。

现在你需要做的就是寻找具有最高(或最低 - 不知道你的坐标系长什么样)y坐标的那一个。

请注意,您可能根本不会得到极值。如果您的贝塞尔曲线例如是一条直线,就会发生这种情况。在这些情况下,您可能还想在寻找极值时包含第一个和最后一个贝塞尔控制点。


编辑:

你问如何将贝塞尔曲线转换为多项式。那么,你可以从普通的贝塞尔曲线方程出发:

 x(t) = x0 * (1-t)³ + 3*x1*(1-t)²*t + 3*x2*(1-t)*t² +x3*t³

(x0 到 x3 是曲线的四个控制点的 x 值)。

然后你逐一乘出所有项,并按t的幂次排序。不幸的是,我的计算机上没有我的数学软件运行,而且我懒得在纸上做:-)因此,如果有人正在运行mathlab,请编辑此答案并添加扩展版本。

无论如何,既然您并不真正关心多项式,而只是它的导数,事情就变得更容易了。您可以直接获得系数(这里仅显示x的系数):

A = 3.0f*(x[1] - x[0]);
B = 6.0f*(x[2] - 2.0f*x[1] + x[0]);
C = 3.0f*(x[3] - 3.0f*x[2] + 3.0f *x[1] - x[0]);

使用这三个值(A、B、C),一阶导数的多项式看起来是这样的:

  x(t) = A*t^2 + B*t + C

现在将A、B和C插入二次多项式求根求解器中,你就完成了。请参考我使用的以下求解器C代码:

int GetQuadraticRoots (float A, float B, float C, float *roots)
{
  if ((C < -FLT_EPSILON) || (C > FLT_EPSILON))
  {
    float d,p;
    // it is a cubic:
    p = B*B - 4.0f * C*A;
    d = 0.5f / C;
    if (p>=0)
    {
      p = (float) sqrt(p);
      if ((p < -FLT_EPSILON) || (p > FLT_EPSILON))
      {
        // two single roots:
        roots[0] = (-B + p)*d;
        roots[1] = (-B - p)*d;
        return 2;
      } 
      // one double root:
      roots[0] = -B*d;
      return 1;
    } else {
      // no roots:
      return 0;
    }
  } 
  // it is linear:
  if ((B < -FLT_EPSILON) || (B > FLT_EPSILON))
  {
    // one single root:
    roots[0] = -A/B;
    return 1;
  }
  // it is constant, so .. no roots.
  return 0;
}
问题回答

暂无回答




相关问题
热门标签