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);