在贝塞尔曲线中绘制每个点的切线 [英] Drawing tangent lines for each point in bezier curve

查看:1147
本文介绍了在贝塞尔曲线中绘制每个点的切线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我设法绘制一个贝塞尔曲线如下:

I managed to draw a bezier curve like:

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

现在我想为每个点添加切线箭头,我该如何做?我给了一个绘制箭头的函数。所以我相信我只需要旋转参考框架并绘制箭头。但是如何计算旋转?我想我需要区分方程,但问题仍然存在,我该如何使用?

Now I want to add tangent arrows for each point, how can I do that? I am given a function that draws an arrow. So I believe I need to just rotate the reference frame and draw that arrow. But how do I compute the rotation? I think I need to differenciate the equations, but the question still remains, how do I use that?

UPDATE

每放置4个点,绘制曲线。

As every 4th point is put, a curve is drawn.

我应该实现以下类似的操作

I am supposed to achieve something like below

完整来源

更新2

我尝试绘制如下的切线:

Ok I made an attempt at drawing the tangents like:

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

但是你可以看到切线似乎不正确,特别是在中间贝塞尔曲线?

But as you can see the tangents appear to be incorrect especially in the middle of a bezier curve?

推荐答案

因为我们不想中断线条,所以合理的做一个绘制箭头的循环。在这个循环中,我们可以跳过一些步骤,因为我们可能在每个步骤后都不需要箭头。箭头可以绘制为GL_LINES原语。

Because we don't want to interrupt the line strip, it is reasonable to make another loop that draws the arrows. In this loop, we can skip some steps, because we probably don't want arrows after each step. The arrows can be drawn as a 'GL_LINES' primitive.

为了可读性,我建议定义参数 t in the inner loop as

For readability I'd recommend to define the parameter t in the inner loop as

float t = (float)k/NLINESEGMENT;

现在我们需要计算曲线对于 t 。可以独立地为每个坐标计算这个导数。看起来这个问题是一个作业,所以我会把它留给你。

Now we need to calculate the derivative of the curve with respect to t at this point. This derivative can be calculated for each coordinate independently. It looks like this question is a homework, so I'll leave that to you

float dx = ... //derivative of x-component with respect to t
float dy = ... //derivative of y-component with respect to t

我们还需要曲线点。

因此,我们可以绘制箭头的基线(其中 s

So we can draw the arrow's base line (where s is a custom scale factor):

glVertex2d(x, y);
glVertex2d(x + s * dx, y + s * dy);

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

We will also need the actual arrow. An orthogonal vector to the arrow direction is (-dy, dx). So we can just combine the direction and the orthogonal direction to get the arrow:

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)更改角度。

This will result in a 90° arrow. You can change the angle by adjusting the coefficients (0.9 and 0.1).

到实际的解决方案,但仍然包含一些错误:

Your derivative is closer to the actual solution, but still contains some mistakes:

此外,当计算角度时,使用 atan2 函数。这允许你获得大于 PI / 2 的角度:

Furthermore, when calculating the angle, use the atan2 function. This allows you to get angles greater than PI/2:

float angle = atan2(dy,dx);

这篇关于在贝塞尔曲线中绘制每个点的切线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆