在贝塞尔曲线中绘制每个点的切线

Jie*_*eng 4 c++ opengl glut

我设法绘制了一条贝塞尔曲线,如:

glColor3f(0,1,0);
glBegin(GL_LINE_STRIP);
for (int i = 3; i < nPt; i+=3) {
    glColor3f(0,0,0);
    for (float k = 0; k < NLINESEGMENT+1; k++) {
        float x = pow(1.0-k/NLINESEGMENT,3)*ptList[i-3].x +
            3*(k/NLINESEGMENT)*pow(1.0-k/NLINESEGMENT, 2) * ptList[i-2].x +
            3*(1.0-k/NLINESEGMENT)*pow(k/NLINESEGMENT, 2) * ptList[i-1].x +
            pow(k/NLINESEGMENT, 3)*ptList[i].x;
        float y = pow(1.0-k/NLINESEGMENT,3)*ptList[i-3].y +
            3*(k/NLINESEGMENT)*pow(1.0-k/NLINESEGMENT, 2) * ptList[i-2].y +
            3*(1.0-k/NLINESEGMENT)*pow(k/NLINESEGMENT, 2) * ptList[i-1].y +
            pow(k/NLINESEGMENT, 3)*ptList[i].y;
        glVertex2d(x,y);
    }
}
glEnd();
Run Code Online (Sandbox Code Playgroud)

现在我想为每个点添加切线箭头,我该怎么做?我有一个绘制箭头的功能.所以我相信我需要旋转参考框架并绘制该箭头.但是我如何计算旋转?我想我需要区分方程式,但问题仍然存在,我该如何使用它?

UPDATE

在此输入图像描述

每放入第4个点,就会绘制一条曲线.

我应该实现类似下面的东西

在此输入图像描述

完整来源

更新2

好的,我试图画出像这样的切线:

glColor3f(0,1,0);
for (int i = 3; i < nPt; i+=3) {
    for (int n = 0; n < NOBJECTONCURVE; n++) {
        float t = (float)n/NOBJECTONCURVE;
        float x0 = points[i-3].x,
                x1 = points[i-2].x,
                x2 = points[i-1].x, 
                x3 = points[i].x;
        float y0 = points[i-3].y,
                y1 = points[i-2].y,
                y2 = points[i-1].y, 
                y3 = points[i].y;

        float x = pow(1.0-t, 3) * points[i-3].x +
            3 * t * pow(1.0 - t, 2) * points[i-2].x +
            3 * (1.0 - t) * pow(t, 2) * points[i-1].x +
            pow(t, 3)*points[i].x;
        float y = pow(1.0-t, 3) * points[i-3].y +
            3 * t * pow(1.0 - t, 2) * points[i-2].y +
            3 * (1.0 - t) * pow(t, 2) * points[i-1].y +
            pow(t, 3)*points[i].y;

        float dx = -3*(1-t)*x0 + 3*x1*((2*t)*(t-1)+pow((1-t),2)) + 3*x2*(2*t*(1-t)-pow(t,2)) + 3*pow(t,2)*x3;
        float dy = -3*(1-t)*y0 + 3*y1*((2*t)*(t-1)+pow((1-t),2)) + 3*y2*(2*t*(1-t)-pow(t,2)) + 3*pow(t,2)*y3;
        float angle = atan(dy/dx);

        glPushMatrix();
        glTranslatef(x, y, 0);
        glRotatef(angle * 180 / 3.14159265, 0, 0, 1);
        drawRightArrow();
        glPopMatrix();
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但正如您所看到的那样,切线似乎不正确,特别是在贝塞尔曲线的中间?

Nic*_*ler 5

因为我们不想中断线条,所以制作另一个绘制箭头的循环是合理的.在这个循环中,我们可以跳过一些步骤,因为我们可能不希望在每一步之后使用箭头.箭头可以绘制为"GL_LINES"原语.

为了便于阅读,我建议t将内循环中的参数定义为

float t = (float)k/NLINESEGMENT;
Run Code Online (Sandbox Code Playgroud)

现在我们需要计算曲线的导数t.可以独立地为每个坐标计算该导数.看起来这个问题是一个功课,所以我会把它留给你

float dx = ... //derivative of x-component with respect to t
float dy = ... //derivative of y-component with respect to t
Run Code Online (Sandbox Code Playgroud)

我们还需要曲线点.理想情况下,您已将其保存在前一个循环中的数组或类似结构中.

所以我们可以绘制箭头的基线(其中s是自定义比例因子):

glVertex2d(x, y);
glVertex2d(x + s * dx, y + s * dy);
Run Code Online (Sandbox Code Playgroud)

我们还需要实际的箭头.箭头方向的正交矢量是(-dy, dx).所以我们可以将方向和正交方向组合起来得到箭头:

glVertex2d(x + s * dx, y + s * dy);
glVertex2d(x + 0.9 * s * dx - 0.1 * dy, y + 0.9 * s * dy + 0.1 * dx);
glVertex2d(x + s * dx, y + s * dy);
glVertex2d(x + 0.9 * s * dx + 0.1 * dy, y + 0.9 * s * dy - 0.1 * dx);
Run Code Online (Sandbox Code Playgroud)

这将产生90°箭头.您可以通过调整系数(0.9和0.1)来改变角度.

更新

您的衍生产品更接近实际解决方案,但仍然包含一些错误: 贝齐尔衍生物

此外,在计算角度时,请使用此atan2功能.这允许您获得大于的角度PI/2:

float angle = atan2(dy,dx);
Run Code Online (Sandbox Code Playgroud)