Bezier 曲线 2D

Bezier 曲线于 1962 年由法国雪铁龙汽车公司的工程师 Bezier 所发表,主要应用于汽车的外形设计。虽然 Bezier 曲线早在 1959 年便由法国雷诺汽车公司的 De Casteljau 运用递推算法开发成功,但是 Bezier 却给出了曲线的详细的曲线计算公式。所以,命名为 Bezier 曲线.
Bezier 曲线由控制多边形唯一定义。
控制多边形的第一个顶点和最后一个顶点位于曲线上,多边形的第一条边和最后一条边表示了曲线在起点和终点的切矢量方向,其顶点则用于定义曲线的导数,阶次和形状。曲线的形状趋近于控制多边形并位于多边形所构成的土包内,改变控制多边形的顶点位置就会改变曲线的形状。
Bezier 曲线的直观交互性使得对设计对象的逼近达到了直接的集合化程度,使得起来非常方便。

Bezier 曲线的定义

给定 n + 1 n+1 n+1 个控制点 P i ( i = 0 , 1 , 2 , ⋯ n ) P_i (i=0, 1, 2, \cdots n) Pi(i=0,1,2,n),则 n n n次Bezier 曲线的定义为
P ( t ) = ∑ i = 0 n P i B i , n ( t ) , t ∈ [ 0 , 1 ] P(t) = \sum_{i=0}{n}P_i B_{i, n}(t), t\in[0, 1] P(t)=i=0nPiBi,n(t),t[0,1]
P i ( i = 0 , 1 , 2 , ⋯   , n ) P_i(i=0, 1, 2, \cdots, n) Pi(i=0,1,2,,n) 是控制多边形的 n + 1 n+1 n+1 个控制点. B i , n ( t ) B_{i, n}(t) Bi,n(t)是 Bernstein 基函数,其表达式为

B i , n ( t ) = n ! i ! ( n − i ) ! t i ( 1 − t ) n − i = C n i t i ( 1 − t ) n − i , i = 0 , 1 , 2 , ⋯ n \begin{equation} B_{i, n}(t) = \frac{n!}{i!(n-i)!}t^{i}(1-t)^{n-i} = C_{n}^{i}t^{i}(1-t)^{n-i}, \quad i=0, 1, 2, \cdots n \end{equation} Bi,n(t)=i!(ni)!n!ti(1t)ni=Cniti(1t)ni,i=0,1,2,n

Bezier 函数是控制点关于 Bernstein 基函数的加权和,Bezier 曲线的次数为 n , 需要 n+1 个顶点来定义。
在工程项目中,最常见的是三次Bezier 曲线,其次数是二次Bezier 曲线,高次Bezier 曲线一般很少用

一次 Bezier 曲线, 当 n=1 时,Bezier 曲线的控制多边形有两个控制点 P 0 P_0 P0 P 1 P_1 P1, Bezier 曲线是一次多项式,称为一次 Bezier 曲线,

P ( t ) = ∑ i = 0 1 P i B i , 1 ( t ) = ( 1 − t ) P 0 + t P 1 P(t) = \sum_{i=0}^{1}P_i B_{i, 1}(t) = (1-t)P_0 + tP_{1} P(t)=i=01PiBi,1(t)=(1t)P0+tP1

二次 Bezier 曲线,当 n=2 时,Bezier 曲线的控制多边形有 3 个控制点, KaTeX parse error: Expected group after '_' at position 2: P_̲$ 、 P 1 P_1 P1 P 2 P_2 P2, Bezier 曲线是二次多项式,称为二次 Bezier 曲线,

P ( t ) = ∑ i = 0 2 P i B i , 2 ( t ) = ( 1 − t ) 2 P 0 + 2 t ( 1 − t ) P 1 + t 2 P 2 P(t) = \sum_{i=0}^{2}P_i B_{i, 2}(t) = (1-t)^2P_0 + 2t(1-t)P_{1} + t^2P_2 P(t)=i=02PiBi,2(t)=(1t)2P0+2t(1t)P1+t2P2
三次 Bezier 曲线,当 n=3 时,Bezier 曲线控制多边形有 4 个控制点, P 0 P_0 P0 P 1 P_1 P1 P 2 P_2 P2 P 3 P_3 P3, Bezier 曲线是三次多项式,称为三次 Bezier 曲线

P ( t ) = ∑ i = 0 3 P i B i , 3 ( t ) = ( 1 − t ) 3 P 0 + 3 t ( 1 − t ) 2 P 1 + 3 t 2 ( 1 − t ) P 2 + t 3 P 3 = ( − t 3 + 3 t 2 − 3 t + 1 ) P 0 + ( 3 t 3 − 6 t 2 + 3 t ) P 1 + ( − 3 t 3 + 3 t 2 ) P 2 + t 3 P 3 P(t) = \sum_{i=0}^{3}P_i B_{i, 3}(t) = (1-t)^3 P_0 + 3t(1-t)^2P_{1} + 3t^2(1-t)P_2 + t^3P_3 = (-t^3 + 3t^2 -3t+1)P_0 + (3t^3 -6t^2 + 3t)P_1 + (-3t^3+3t^2)P_2 + t^3P_3 P(t)=i=03PiBi,3(t)=(1t)3P0+3t(1t)2P1+3t2(1t)P2+t3P3=(t3+3t23t+1)P0+3t36t2+3tP1+(3t3+3t2)P2+t3P3

写成矩阵的形式为

P ( t ) = [ t 3 t 2 t 1 ] [ − 1 3 − 3 1 3 − 6 3 0 − 3 3 0 0 1 0 0 0 ] [ P 0 P 1 P 2 P 3 ] P(t) = \begin{bmatrix} t^3 & t^2 & t & 1 \end{bmatrix} \begin{bmatrix} -1 & 3 &-3 & 1\\ 3 & -6 &3 & 0\\ -3 & 3 &0 & 0\\ 1 & 0 & 0 & 0\\ \end{bmatrix} \begin{bmatrix} P_0 \\ P_1 \\ P_2 \\ P_3 \\ \end{bmatrix} P(t)=[t3t2t1] 1331363033001000 P0P1P2P3

B 0 , 3 ( t ) = ( 1 − t ) 3 B 1 , 3 ( t ) = 3 t ( 1 − t ) 2 B 2 , 3 ( t ) = 3 t 2 ( 1 − t ) B 3 , 3 ( t ) = t 3 B_{0, 3}(t) = (1-t)^3 \\ B_{1, 3}(t) = 3t(1-t)^2 \\ B_{2, 3}(t) = 3t^2(1-t) \\ B_{3, 3}(t) = t^3 B0,3(t)=(1t)3B1,3(t)=3t(1t)2B2,3(t)=3t2(1t)B3,3(t)=t3

下面给出 QT + OPENGL 的二次的代码

#include <QtWidgets>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>

class BezierCurveWidget : public QOpenGLWidget, protected QOpenGLFunctions {
public:
    BezierCurveWidget(QWidget* parent = nullptr)
        : QOpenGLWidget(parent) {}

protected:
    void initializeGL() override {
        initializeOpenGLFunctions();
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    }

    void resizeGL(int w, int h) override {
        glViewport(0, 0, w, h);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, w, h, 0, -1, 1);
        glMatrixMode(GL_MODELVIEW);
    }

    void paintGL() override {
        glClear(GL_COLOR_BUFFER_BIT);

        // 控制点坐标
        QPoint p0(100, 300);
        QPoint p1(300, 100);
        QPoint p2(500, 300);

        // 设置线的颜色
        glColor3f(0.0f, 0.0f, 1.0f); // Blue color for lines

        // 绘制Bezier曲线
        glBegin(GL_LINE_STRIP);
        for (float t = 0.0f; t <= 1.0f; t += 0.01f) {
            QPoint p = calculateBezierPoint(t, p0, p1, p2);
            glVertex2i(p.x(), p.y());
        }
        glEnd();

        // 绘制控制点
        glPointSize(5.0f);
        glColor3f(1.0f, 0.0f, 0.0f);
        glBegin(GL_POINTS);
        glVertex2i(p0.x(), p0.y());
        glVertex2i(p1.x(), p1.y());
        glVertex2i(p2.x(), p2.y());
        glEnd();

        // 绘制连接线
        glBegin(GL_LINES);
        glVertex2i(p0.x(), p0.y());
        glVertex2i(p1.x(), p1.y());
        glVertex2i(p1.x(), p1.y());
        glVertex2i(p2.x(), p2.y());
        glEnd();
    }

    QPoint calculateBezierPoint(float t, const QPoint& p0, const QPoint& p1, const QPoint& p2) {
        float u = 1 - t;
        float tt = t * t;
        float uu = u * u;

        float x = uu * p0.x() + 2 * u * t * p1.x() + tt * p2.x();
        float y = uu * p0.y() + 2 * u * t * p1.y() + tt * p2.y();

        return QPoint(x, y);
    }
};

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QMainWindow window;
    BezierCurveWidget* bezierWidget = new BezierCurveWidget(&window);

    window.setCentralWidget(bezierWidget);
    window.resize(600, 400);
    window.show();

    return a.exec();
}

在这里插入图片描述

这里只需要替换一次和三次的计算部分即可。

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Bezier曲线是一种平滑的曲线,它可以由一系列控制点和曲线度数来定义。在动态绘制Bezier曲线时,我们可以使用JavaScript和HTML5的Canvas元素来实现。 以下是一个简单的示例,演示如何使用Canvas和JavaScript动态绘制Bezier曲线: ```html <!DOCTYPE html> <html> <head> <title>动态绘制Bezier曲线</title> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body> <canvas id="myCanvas"></canvas> <script type="text/javascript"> // 获取canvas元素和上下文 var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); // 定义控制点 var controlPoints = [ {x: 100, y: 150}, {x: 200, y: 50}, {x: 300, y: 250}, {x: 400, y: 150} ]; // 绘制控制点 for (var i = 0; i < controlPoints.length; i++) { ctx.beginPath(); ctx.arc(controlPoints[i].x, controlPoints[i].y, 5, 0, 2 * Math.PI); ctx.fill(); } // 绘制Bezier曲线 ctx.lineWidth = 3; ctx.strokeStyle = "blue"; ctx.beginPath(); ctx.moveTo(controlPoints[0].x, controlPoints[0].y); for (var t = 0; t <= 1; t += 0.01) { var point = getBezierPoint(controlPoints, t); ctx.lineTo(point.x, point.y); } ctx.stroke(); // 计算Bezier曲线上的点 function getBezierPoint(points, t) { if (points.length == 1) { return points[0]; } else { var newPoints = []; for (var i = 0; i < points.length - 1; i++) { var x = points[i].x + (points[i + 1].x - points[i].x) * t; var y = points[i].y + (points[i + 1].y - points[i].y) * t; newPoints.push({x: x, y: y}); } return getBezierPoint(newPoints, t); } } </script> </body> </html> ``` 在这个示例中,我们首先定义了四个控制点,然后绘制了这些控制点。接下来,我们使用函数`getBezierPoint`来计算Bezier曲线上的点,然后使用Canvas的`lineTo`方法将这些点连接起来,最终绘制出Bezier曲线。可以通过修改控制点的坐标来改变Bezier曲线的形状。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值