一、算法原理
如果说对于曲线来说只有一个参数,0=<t<=1,那么对于一个面来说,就应该有两个参数,分别设0=<ɑ<=1, 0=<β<=1。
首先规定一共4x4 = 16个控制点,其水平面位置如图中16个黑点所示(并未表示出高度,防止图形太乱),将这16个点分成4列,图中红色圈中的为一列的具体例子。
第1步 在这4个控制点之下利用第一个参数ɑ运用第一章的计算贝塞尔曲线的方法得到蓝色点,因为有4列,所以一共可以得到如图所示的4个蓝色点。(灰色曲线分别为每列4个点所对应的贝塞尔曲线)
第2步 在得到4个蓝色顶点之后,在这四个蓝色顶点的基础之下利用第二个参数β 便可以成功得出贝塞尔曲面上的正确一点
第3步 遍历所有的ɑ,β值就可以成功得到一个贝塞尔曲面。
设计的网格控制点及显示结果如下述两点所示。
二、代码实现
double fac1[20];
double Bernstein(int n, int i, double t) {
return fac1[n] / fac1[i] / fac1[n - i] * pow(t, i) * pow(1 - t, n - i);
}
void Bezierface(CDC* pDC) {
Point a[4][4] = { {{10,10},{30,120},{91,81},{100,51}},
{{10,61},{81,10},{80,10},{310,410}},
{{110,210},{140,100},{100,100},{120,100}},
{{51,100},{100,90},{140,41},{130,210}}
};
int i, j;
CPen m_newPen, * m_oldPen;
m_newPen.CreatePen(PS_SOLID, 1, RGB(255,186,199));
m_oldPen = pDC->SelectObject(&m_newPen);
double line, tmp, m, n;
for (m = 0; m <= 1; m = m + 0.01)
{
for (n = 0; n <= 1; n = n + 0.01)
{
line = 0; tmp = 0;
for (i = 0; i <= 3; i++)
{
double m = 0, n = 0;
for (j = 0; j <= 3; j++)
{
m += Bernstein(3, j, m) * a[i][j].x;
n += Bernstein(3, j, m) * a[i][j].y;
}
line += m * Bernstein(3, i, n);
tmp += n * Bernstein(3, i, n);
}
if (n == 0)
{
pDC->MoveTo(line, tmp);
}
pDC->LineTo(line, tmp);
}
}
}
OnDraw代码:
fac1[0] = 1.0;
for (int i = 1; i < 20; i++) {
fac1[i] = fac1[i - 1] * i;
}
Point p[4] = {
{280 , 50},
{300 , 200},
{350 , 250},
{400 , 50}
};
//DrawBezier(pDC, p, 3);
Bezierface(pDC);
三、算法结果