绘制贝塞尔曲线

原理

具体内容见 课本 P237

这里直接给出 Bezier 曲线的坐标生成的表达式 \(\left \{\begin{array}{ll} {x(t) = \sum_{k=0}^{n}x_k BEN_{k,n}(t)} & {} \\ {y(t) = \sum_{k=0}^{n}y_k BEN_{k,n}(t)} & {t\in[0,1]} \\ {z(t) = \sum_{k=0}^{n}z_k BEN_{k,n}(t)} & {} \end{array} \right.\)

其中 $(x_k,y_k,z_k)$ 是输入点的坐标 \(\begin{align*} BEN_{k,n}(t) &= \frac{n!}{k!(n-k)!} t^k (1-t)^{n-k}\\ &= C_n^k t^k (1-t)^{n-k} \end{align*}\) 其中 $t = \frac{i}{m}$ ,$i$ 是线成点的第 $i$ 个点,$m$ 是把线分成 $m$ 个点来画。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <windows.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <bits/stdc++.h>
using namespace std;
#include <stdlib.h>
const double PI = acos(-1.0);

class Pt3D{
    public :
        GLfloat x, y, z;
};
void GetCnk(GLint n, GLint *c){
    // c[k] = C_n^k
    GLint i, k;
    for(k=0; k<=n; k++){
        c[k] = 1;
        for(i=n; i>=k+1; i--) c[k] = c[k]*i;
        for(i=n-k; i>=2; i--) c[k] = c[k]/i;
    }
}
void GetPointPr(GLint *c, GLfloat t, Pt3D *Pt, int ControlN, Pt3D *ControlP){
    GLint k, n=ControlN-1;
    GLfloat Bernstein;
    Pt->x = Pt->y = Pt->z = 0;
    for(k=0; k<ControlN; k++){
        Bernstein = c[k] * pow(t, k) * pow(1-t, n-k);
        Pt->x += ControlP[k].x * Bernstein;
        Pt->y += ControlP[k].y * Bernstein;
        Pt->z += ControlP[k].z * Bernstein;
    }
}
void BezierCcurve(GLint m, GLint ControlN, Pt3D *ControlP){
    GLint *C, i;
    Pt3D CurvePt;
    C = new GLint[ControlN];
    GetCnk(ControlN-1, C);
    glBegin(GL_POINTS);
        for(i=0; i<=m; i++){
            GetPointPr(C, (GLfloat)i/(GLfloat)m, &CurvePt, ControlN, ControlP);
            glVertex2f(CurvePt.x, CurvePt.y);
        }
    glEnd();
    delete []C;
}
void Initial(void){
    glClearColor(1, 1, 1, 0);
}

int n;
Pt3D ControlP[100];
void Display(void){
    glClear(GL_COLOR_BUFFER_BIT);
    GLint ControlN = n, m = 500;
    glPointSize(2);
    glColor3f(0, 0, 0);
    BezierCcurve(m, ControlN, ControlP);
    glBegin(GL_LINE_STRIP);
        for(GLint i=0; i<ControlN; i++)
            glVertex3f(ControlP[i].x, ControlP[i].y, ControlP[i].z);
    glEnd();
    glFlush();
}
void Reshape(GLint w, GLint h){
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-100, 100, -100, 100);
}
int main(int argc, char** argv){

    puts("输入点的个数:"); cin >> n;
    puts("输入点坐标(x,y,z):");
    for(int i=0; i<n; i++) cin >> ControlP[i].x >> ControlP[i].y >> ControlP[i].z;

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("Bezier");

    Initial();
    glutDisplayFunc(Display);
    glutReshapeFunc(Reshape);
    glutMainLoop();
}
/*
4
-80 -40 0
-10 90 0
10 -90 0
80 40 0
*/

# 使用单$作为行内数学公式分界符