C++ 为bezier曲线中的每个点绘制切线

C++ 为bezier曲线中的每个点绘制切线,c++,opengl,glut,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/NLINESE

我画了一条贝塞尔曲线,如:

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();
glColor3f(0,1,0);
glBegin(GL_线_带);
对于(int i=3;i
现在我想为每个点添加相切箭头,如何才能做到这一点?我得到了一个绘制箭头的函数。所以我认为我需要旋转参考坐标系并画出箭头。但是如何计算旋转呢?我想我需要对方程进行微分,但问题仍然存在,我如何使用它

更新

每放置第四个点,就会绘制一条曲线

我应该做到以下几点

更新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();
    }
}
glColor3f(0,1,0);
对于(int i=3;i


但你可以看到,切线看起来是不正确的,特别是在Bezier曲线的中间? 因为我们不想中断线条带,所以制作另一个绘制箭头的循环是合理的。在这个循环中,我们可以跳过一些步骤,因为我们可能不希望在每个步骤之后都有箭头。箭头可以绘制为“GL_线”原语

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

float t = (float)k/NLINESEGMENT;
现在我们需要计算曲线在这一点上相对于
t
的导数。该导数可以独立地为每个坐标计算。看起来这个问题是家庭作业,所以我把它留给你

float dx = ... //derivative of x-component with respect to t
float dy = ... //derivative of y-component with respect to t
我们还需要曲线点。理想情况下,您已经将其保存在数组或类似结构的上一个循环中

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

我们还需要实际的箭头。与箭头方向正交的向量为
(-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);
这将导致90°箭头。可以通过调整系数(0.9和0.1)来更改角度

更新 您的导数更接近实际解,但仍包含一些错误:

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

float angle = atan2(dy,dx);

在这类问题中,你所做的截图可以让问题变得更好。@JiewMeng在
x0,y0
中的切线角度是
ang=arctan(dy/dx)
。箭头的坐标(长度为
l
)然后:
(x0,y0)-(l*cos(ang),l*sin(ang))
@PetrBudnik:如果你马上把一个角度转换成向量,为什么还要计算它呢?@NicoSchertler,因为角度与
dx
dy
无关,通常,因点而异。
dx
dy
通常因点而异。在这种情况下,箭头将具有不同的长度。除非在
sqrt(dx*dx+dy*dy)
上进行规格化。我的意图是使箭头的长度与导数的长度成比例。当然,这取决于任务,这不会使它们与“导数长度”成比例。导数是
dy/dx
(实际上是
lim-dy/dx和dx->0
)。例如,
dx=1,dy=0.5
dx=10000,dy=5000
的值相同,等于
0.5
。但在这种情况下,箭头的长度会相差10000倍。这就是为什么你必须以这样或那样的方式处理角度(如果你愿意,你可以使用
dy/dx=tan(ang)
),我说的是
x
y
相对于
t
dx/dt
dy/dt
)的导数。
y
相对于
x
的导数更难计算,并且可能包含不连续性(对于垂直线部分)。因此,使用它来显示切线向量不是一个好主意。此外,
y
通常不能描述为
x
的函数。给定的
x
可能有多个
y
-值。IMHO,您不需要

float angle = atan2(dy,dx);