# 一、Bezier曲线

## 1.1 Bezier曲线定义

Bi,n(t) 是Bernstein多项式，称为Bernstein基函数，其表达式为：

## 1.2 Bernstein基函数

### 1.2.3 三次Bezier基函数算法代码实现

``````void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;

// TODO: add draw code for native data here
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(), rect.Height());
pDC->SetViewportExt(rect.Width(), -rect.Height());
pDC->SetViewportOrg(rect.Width()/6,rect.Height()*0.9);
DrawUcs(pDC);
DrawBasisFun03(pDC);
DrawBasisFun13(pDC);
DrawBasisFun23(pDC);
DrawBasisFun33(pDC);
}

// 网格绘制
void CGeometricfiguretestView::DrawUcs(CDC *pDC)
{

pDC->MoveTo(0,0);
pDC->LineTo(0,300);
pDC->MoveTo(0,0);
pDC->LineTo(500,0);
pDC->MoveTo(500,300);
pDC->LineTo(0,300);
pDC->MoveTo(500,300);
pDC->LineTo(500,0);
for(int m=50;m<=250;m=m+50)
{

for(int n=100;n<=500;n=n+100)
{
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_DASH,1,RGB(0,0,0));
pOldPen=pDC->SelectObject(&NewPen);
pDC->MoveTo(0,m);
pDC->LineTo(n,m);
pDC->SelectObject(pOldPen);
}
}
for(int a=100;a<=400;a=a+100)
{

for(int b=50;b<=300;b=b+50)
{
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_DASH,1,RGB(0,0,0));
pOldPen=pDC->SelectObject(&NewPen);
pDC->MoveTo(a,0);
pDC->LineTo(a,b);
pDC->SelectObject(pOldPen);
}

}
}
void CGeometricfiguretestView::DrawBasisFun03(CDC *pDC)
{

CPen NewPen1, *pOldPen;
NewPen1.CreatePen(PS_SOLID,1,RGB(255,0,0));
pOldPen=pDC->SelectObject(&NewPen1);

ScaleX=500;
ScaleY=300;
for(double t=0;t<1;t+=0.01)
{
x=t*ScaleX;
y=(-pow(t,3)+3*pow(t,2)-3*t+1)*ScaleY;
if(t==0)
{
pDC->MoveTo(Round(x),Round(y));
}
else
{
pDC->LineTo(Round(x),Round(y));
}

}
pDC->SelectObject(pOldPen);
pDC->TextOut(-50, 300, L"B03(t)");
}
void CGeometricfiguretestView::DrawBasisFun13(CDC* pDC)
{

CPen NewPen2, *pOldPen;
NewPen2.CreatePen(PS_DASHDOT,1,RGB(0,255,0));
pOldPen=pDC->SelectObject(&NewPen2);
ScaleX=500;
ScaleY=300;
for(double t=0;t<1;t+=0.01)
{
x=t*ScaleX;
y=(3*pow(t,3)-6*pow(t,2)+3*t)*ScaleY;
if(t==0)
{
pDC->MoveTo(Round(x),Round(y));
}
else
{
pDC->LineTo(Round(x),Round(y));
}

}
pDC->SelectObject(pOldPen);
pDC->TextOut(140, 150, L"B13(t)");
}
void CGeometricfiguretestView::DrawBasisFun23(CDC *pDC)
{

CPen NewPen3, *pOldPen;
NewPen3.CreatePen(PS_DASH,1,RGB(0,0,255));
pOldPen=pDC->SelectObject(&NewPen3);
ScaleX=500;
ScaleY=300;
for(double t=0;t<1;t+=0.01)
{
x=t*ScaleX;
y=(-3*pow(t,3)+3*pow(t,2))*ScaleY;
if(t==0)
{
pDC->MoveTo(Round(x),Round(y));
}
else
{
pDC->LineTo(Round(x),Round(y));
}

}
pDC->SelectObject(pOldPen);
pDC->TextOut(330, 150, L"B23(t)");
}
void CGeometricfiguretestView::DrawBasisFun33(CDC *pDC)
{

CPen NewPen4, *pOldPen;
NewPen4.CreatePen(PS_DOT,1,RGB(0,255,255));
pOldPen=pDC->SelectObject(&NewPen4);
ScaleX=500;
ScaleY=300;
for(double t=0;t<1;t+=0.1)
{
x=t*ScaleX;
y=(pow(t,3))*ScaleY;
if(t==0)
{
pDC->MoveTo(Round(x),Round(y));
}
else
{
pDC->LineTo(Round(x),Round(y));
}
}
pDC->SelectObject(pOldPen);
pDC->TextOut(500, 300, L"B33(t)");
}
``````

## 1.4 Bezier曲线实现

### 1.4.1 一次Bezier曲线（Linear Curve）

#### 1.4.2.1 代码实现

``````CGeometricfiguretestView::CGeometricfiguretestView()
{
// TODO: add construction code here
ctrP[0].x = 200, ctrP[0].y = 500;
ctrP[1].x = 700, ctrP[1].y = 200;
ctrP[2].x = 800, ctrP[2].y = 500;
}

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc) return;
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(), rect.Height());
pDC->SetViewportExt(rect.Width(), rect.Height());
pDC->SetViewportOrg(rect.Width()/100, rect.Height()/100);
// TODO: add draw code for native data here
DrawPolygon(pDC);
Bezier_2(pDC);
}

//控制边绘制
void CGeometricfiguretestView::DrawPolygon(CDC* pDC)
{
CPen NewPen, *pOldPen;
NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
pOldPen = pDC->SelectObject(&NewPen);
CBrush NewBrush, *pOldBrush;
NewBrush.CreateSolidBrush(RGB(0, 0, 0));//控制点
pOldBrush = pDC->SelectObject(&NewBrush);
pDC->MoveTo(ctrP[0]);
pDC->Ellipse(ctrP[0].x - 5, ctrP[0].y - 5, ctrP[0].x + 5, ctrP[0].y + 5);//绘制控制多边形顶点
for (int i = 1;i < 3;i++)
{
pDC->LineTo(ctrP[i]);
pDC->Ellipse(ctrP[i].x - 5, ctrP[i].y - 5, ctrP[i].x + 5, ctrP[i].y + 5);//绘制控制多边形顶点
}
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}

//二次Bezier曲线绘制
void CGeometricfiguretestView::Bezier_2(CDC* pDC)
{
CPen NewPen, *pOldPen;
NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
pOldPen = pDC->SelectObject(&NewPen);
pDC->MoveTo(ctrP[0]);
double tSteP = 0.01;
for (double t = 0.0;t <= 1.0;t += tSteP)
{
double x = 0, y = 0;
x += (t*t - 2 * t + 1)*ctrP[0].x + (2 * t - 2 * t*t)*ctrP[1].x + t*t*ctrP[2].x;
y += (t*t - 2 * t + 1)*ctrP[0].y + (2 * t - 2 * t*t)*ctrP[1].y + t*t*ctrP[2].y;
pDC->LineTo(x, y);
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}
``````

### 1.4.3 三次Bezier曲线（Cubic Curve）

#### 1.4.3.1 代码实现

``````CGeometricfiguretestView::CGeometricfiguretestView()
{
// TODO: add construction code here
ctrP[0].x = 200, ctrP[0].y = 500;
ctrP[1].x = 400, ctrP[1].y = 200;
ctrP[2].x = 800, ctrP[2].y = 100;
ctrP[3].x = 900, ctrP[3].y = 600;
}

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;

// TODO: add draw code for native data here
DrawPolygon(pDC);
Bezier_3(pDC);
}

void CGeometricfiguretestView::DrawPolygon(CDC* pDC)
{
CPen NewPen, *pOldPen;
NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
pOldPen = pDC->SelectObject(&NewPen);
CBrush NewBrush, *pOldBrush;
NewBrush.CreateSolidBrush(RGB(0, 0, 0));//控制点颜色
pOldBrush = pDC->SelectObject(&NewBrush);
pDC->MoveTo(ctrP[0]);
pDC->Ellipse(ctrP[0].x - 5, ctrP[0].y - 5, ctrP[0].x + 5, ctrP[0].y + 5);//绘制控制多边形顶点
for (int i = 1;i < 4;i++)
{
pDC->LineTo(ctrP[i]);
pDC->Ellipse(ctrP[i].x - 5, ctrP[i].y - 5, ctrP[i].x + 5, ctrP[i].y + 5);//绘制控制多边形顶点
}
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}

void CGeometricfiguretestView::Bezier_3(CDC* pDC)
{
CPen NewPen, *pOldPen;
NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));
pOldPen = pDC->SelectObject(&NewPen);
pDC->MoveTo(ctrP[0]);
double tSteP = 0.01;
for (double t = 0.0;t <= 1.0;t += tSteP)
{
double x = 0, y = 0;
x += (-t*t*t + 3 * t*t - 3 * t + 1)*ctrP[0].x + (3 * t*t*t - 6 * t*t + 3 * t)*ctrP[1].x + (-3 * t*t*t + 3 * t*t)*ctrP[2].x + (t*t*t)*ctrP[3].x;
y += (-t*t*t + 3 * t*t - 3 * t + 1)*ctrP[0].y + (3 * t*t*t - 6 * t*t + 3 * t)*ctrP[1].y + (-3 * t*t*t + 3 * t*t)*ctrP[2].y + (t*t*t)*ctrP[3].y;
pDC->LineTo(x, y);
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}
``````

### 1.4.4 n次Bezier曲线

``````CGeometricfiguretestView::CGeometricfiguretestView()
{
// TODO: add construction code here
n=5;
P[0].x=-500,P[0].y=-200;
P[1].x=-300,P[1].y=100;
P[2].x=100, P[2].y=200;
P[3].x = 200, P[3].y = -200;
P[4].x = 400, P[4].y = -100;
P[5].x=600, P[5].y=200;
}

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(), rect.Height());
pDC->SetViewportExt(rect.Width(), -rect.Height());
pDC->SetViewportOrg(rect.Width() / 2,rect.Height() / 2);
DrawBezier(pDC);
DrawControlPolygon(pDC);
}

void CGeometricfiguretestView::DrawBezier(CDC* pDC)
{
pDC->MoveTo(ROUND(P[0].x),ROUND(P[0].y));
double tStep=0.01;//参数步长
for (double t=0.0; t<=1.0; t+=tStep)
{
double x=0.0, y=0.0;
for(int i=0;i<n+1;i++)
{
x+=P[i].x*Cni(n,i)*pow(t,i)*pow(1-t,n-i);//pow为幂函数
y+=P[i].y*Cni(n,i)*pow(t,i)*pow(1-t,n-i);
}
pDC->LineTo(ROUND(x), ROUND(y));
}
}
//组合数计算
double CGeometricfiguretestView::Cni(const int &n, const int &i)
{
return double(Factorial(n))/(Factorial(i)*Factorial(n-i));
}
//阶乘计算
int CGeometricfiguretestView::Factorial(int n)
{
int factorial;
if(n==0||n==1)
factorial=1;
else
factorial=n*Factorial(n-1);
return factorial;
}

//绘制控制多边形
void CGeometricfiguretestView::DrawControlPolygon(CDC* pDC)
{
for(int i=0;i<n+1;i++)
{
if(0==i)
{
pDC->MoveTo(ROUND(P[i].x),ROUND(P[i].y));
pDC->Ellipse(ROUND(P[i].x-5),ROUND(P[i].y)-5,ROUND(P[i].x+5),ROUND(P[i].y)+5);
}
else
{
pDC->LineTo(ROUND(P[i].x),ROUND(P[i].y));
pDC->Ellipse(ROUND(P[i].x)-5, ROUND(P[i].y)-5,ROUND(P[i].x)+5,ROUND(P[i].y)+5);
}
}
}
``````

# 二、Bezier曲线的de Casteljau算法

## 2.3 代码实现

``````CGeometricfiguretestView::CGeometricfiguretestView()
{
// TODO: add construction code here
n=3;
P[0].x=-400,P[0].y=-200;
P[1].x=-200,P[1].y=100;
P[2].x=200, P[2].y=200;
P[3].x=300, P[3].y=-200;
}

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(), rect.Height());
pDC->SetViewportExt(rect.Width(), -rect.Height());
pDC->SetViewportOrg(rect.Width() / 2,rect.Height() / 2);
DrawBezier(pDC);
DrawControlPolygon(pDC);
}

void CGeometricfiguretestView::DrawBezier(CDC* pDC)
{
pDC->MoveTo(ROUND(P[0].x),ROUND(P[0].y));
double tStep =0.01;//步长
for (double t=0.0;t<=1.0;t+=tStep)
{
deCasteljau(t);
pDC->LineTo(ROUND(pp[0][n].x),ROUND(pp[0][n].y));
}
}

void CGeometricfiguretestView::deCasteljau(double t)
{
for (int k=0;k<=n;k++)
{
pp[k][0].x=P[k].x;//将控制点一维数组赋给二维递归数组
pp[k][0].y=P[k].y;
}
for (int r=1;r<=n;r++)//Casteljau递推公式,使用二维数组
for(int i=0;i<=n-r;i++)
pp[i][r]=(1-t)*pp[i][r-1]+t*pp[i+1][r-1];
}

//绘制控制多边形
void CGeometricfiguretestView::DrawControlPolygon(CDC* pDC)
{
for(int i=0;i <n+1;i++)
{
if(0==i)
{
pDC->MoveTo(ROUND(P[i].x),ROUND(P[i].y));
pDC->Ellipse(ROUND(P[i].x)-5,ROUND(P[i].y)-5,ROUND(P[i].x)+5,ROUND(P[i].y)+5);
}
else
{
pDC->LineTo(ROUND(P[i].x),ROUND(P[i].y));
pDC->Ellipse(ROUND(P[i].x)-5,ROUND(P[i].y)-5,ROUND(P[i].x)+5,ROUND(P[i].y)+5);
}
}
}
``````

# 三、Bezier曲线拼接

## 3.1 曲线拼接

Bezier曲线的次数随着控制多边形顶点数量的增加而增加。使用高次Bezier曲线计算起来代价很高，且容易有数值的舍入误差。而工程中常用的是三次Bezier曲线。为了描述复杂物体的轮廓曲线，经常需要将多段Bezier曲线拼接起来，并在结合处满足一定的连续性条件。

## 3.2.1 CCubicBezierCurve类封装

``````#pragma once
#include "P2.h"

class CCubicBezierCurve
{
public:
CCubicBezierCurve(void);
CCubicBezierCurve(CP2* P,int ptNum);
~CCubicBezierCurve(void);
void Draw(CDC* pDC);//绘制三次Bezier曲线
void DrawControlPolygon(CDC* pDC);//绘制控制多边形
private:
double Cni(const int &n,const int &i);//Bernstein第一项组合
int Factorial(int n);//阶乘函数
private:
CP2 P[4];//控制点数组
int num;//曲线次数
};

``````
``````#include "StdAfx.h"
#include "CubicBezierCurve.h"
#include <math.h>
#define  ROUND(d) int(d+0.5)

CCubicBezierCurve::CCubicBezierCurve(void)
{
}

CCubicBezierCurve::CCubicBezierCurve(CP2* P,int ptNum)
{
for(int i=0;i< ptNum;i++)
this->P[i]=P[i];
num=ptNum-1;//曲线次数为控制点个数减一
}
CCubicBezierCurve::~CCubicBezierCurve(void)
{
}

void CCubicBezierCurve::Draw(CDC* pDC)
{
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_SOLID,1,RGB(0,0,255));//曲线颜色为蓝色
pOldPen = pDC->SelectObject(&NewPen);
pDC->MoveTo(ROUND(P[0].x),ROUND(P[0].y));
double tStep=0.01;//参数t的步长
for (double t=0.0;t<=1.0;t+=tStep)
{
CP2 p(0.0,0.0);
for (int i=0;i<=num;i++)
p+=P[i]*Cni(num,i)*pow(t,i)*pow(1-t,num-i);
pDC->LineTo(ROUND(p.x),ROUND(p.y));
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}

double CCubicBezierCurve::Cni(const int &n,const int &i)//Bernstein第一项组合
{
return double(Factorial(n))/(Factorial(i)*Factorial(n-i));
}

int CCubicBezierCurve::Factorial(int n)//阶乘函数
{
int factorial;
if (n==0||n==1)
factorial=1;
else
factorial=n*Factorial(n-1);
return factorial;
}

void CCubicBezierCurve::DrawControlPolygon(CDC* pDC)//绘制控制多边形
{
CBrush NewBrush,*pOldBrush;
pOldBrush=(CBrush*)pDC->SelectStockObject(BLACK_BRUSH);//选择黑色库画刷
for(int i=0;i<=num;i++)
{
if(0==i)
{
pDC->MoveTo(ROUND(P[i].x),ROUND(P[i].y));
pDC->Ellipse(ROUND(P[i].x)-5,ROUND(P[i].y)-5,ROUND(P[i].x)+5,ROUND(P[i].y)+5);
}
else
{
pDC->LineTo(ROUND(P[i].x),ROUND(P[i].y));
pDC->Ellipse(ROUND(P[i].x)-5,ROUND(P[i].y)-5,ROUND(P[i].x)+5,ROUND(P[i].y)+5);
}
}
pDC->SelectObject(pOldBrush);
}

``````

## 3.2.2 代码实现

``````void CGeometricfiguretestView::ReadPoint()
{
const double m = 0.5523;
double r = 200;
P[0].x = r,     P[0].y = 0.0;
P[1].x = r,     P[1].y = m * r;
P[2].x = m * r, P[2].y = r;
P[3].x = 0,     P[3].y = r;
P[4].x =-m * r, P[4].y = r;
P[5].x =-r,     P[5].y = m * r;
P[6].x =-r,     P[6].y = 0;
P[7].x =-r,     P[7].y =-m * r;
P[8].x =-m * r, P[8].y =-r;
P[9].x = 0,     P[9].y =-r;
P[10].x = m * r,P[10].y =-r;
P[11].x = r,    P[11].y =-m * r;
}

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(),rect.Height());
pDC->SetViewportExt(rect.Width(),-rect.Height());
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
p1[0] = P[0], p1[1] = P[1],  p1[2] = P[2],  p1[3] = P[3];
p2[0] = P[3], p2[1] = P[4],  p2[2] = P[5],  p2[3] = P[6];
p3[0] = P[6], p3[1] = P[7],  p3[2] = P[8],  p3[3] = P[9];
p4[0] = P[9], p4[1] = P[10], p4[2] = P[11], p4[3] = P[0];
CCubicBezierCurve Bezier1(p1,4);
Bezier1.Draw(pDC);
Bezier1.DrawControlPolygon(pDC);
CCubicBezierCurve Bezier2(p2,4);
Bezier2.Draw(pDC);
Bezier2.DrawControlPolygon(pDC);
CCubicBezierCurve Bezier3(p3,4);
Bezier3.Draw(pDC);
Bezier3.DrawControlPolygon(pDC);
CCubicBezierCurve Bezier4(p4,4);
Bezier4.Draw(pDC);
Bezier4.DrawControlPolygon(pDC);
}
``````

# 四、Bezier曲面

## 4.1 Bezier曲面定义

Bezier曲面由Bezier曲线拓广而来，它以两组正交的Bezier曲线控制点构造空间网格来，生成曲面. m x n次张量积形式的Bezier曲面的定义如下：

## 4.3 代码实现

### 4.3.1 P3/BicubicBezierPatch类封装

P3类：

``````#pragma once
#include "p2.h"
class CP3 :	public CP2
{
public:
CP3(void);
~CP3(void);
CP3(double x ,double y,double z);
friend CP3 operator +(const CP3 &p0, const CP3 &p1);//运算符重载
friend CP3 operator -(const CP3 &p0, const CP3 &p1);
friend CP3 operator *(const CP3 &p, double scalar);
friend CP3 operator *(double scalar,const CP3 &p);
friend CP3 operator /(const CP3 &p, double scalar);
public:
double z;
};
``````
``````#include "StdAfx.h"
#include "P3.h"
#include <math.h>

CP3::CP3(void)
{
z=0.0;
}

CP3::~CP3(void)
{
}

CP3::CP3(double x,double y,double z):CP2(x,y)
{
this->z=z;
}

CP3 operator +(const CP3 &p0, const CP3 &p1)//和
{
CP3 result;
result.x = p0.x + p1.x;
result.y = p0.y + p1.y;
result.z = p0.z + p1.z;
return result;
}

CP3 operator -(const CP3 &p0, const CP3 &p1)//差
{
CP3 result;
result.x = p0.x - p1.x;
result.y = p0.y - p1.y;
result.z = p0.z - p1.z;
return result;
}

CP3 operator *(const CP3 &p, double scalar)//点和常量的积
{
return CP3(p.x * scalar, p.y * scalar, p.z * scalar);
}

CP3 operator *(double scalar, const CP3 &p)//点和常量的积
{
return CP3(p.x * scalar, p.y * scalar, p.z * scalar);
}

CP3 operator /(const CP3 &p, double scalar)//数除
{
if(fabs(scalar)<1e-6)
scalar = 1.0;
CP3 result;
result.x = p.x / scalar;
result.y = p.y / scalar;
result.z = p.z / scalar;
return result;
}
``````

BicubicBezierPatch类：

``````#pragma once
#include "P3.h"

class CBicubicBezierPatch
{
public:
CBicubicBezierPatch(void);
~CBicubicBezierPatch(void);
void DrawCurvedPatch(CDC* pDC);//绘制双三次Bezier曲面片
void DrawControlGrid(CDC* pDC);//绘制控制网格
private:
void LeftMultiplyMatrix(double M[][4],CP3 P[][4]);//左乘顶点矩阵
void RightMultiplyMatrix(CP3 P[][4],double M[][4]);//右乘顶点矩阵
void TransposeMatrix(double M[][4]);//转置矩阵
CP2 ObliqueProjection(CP3 Point3);//斜二测投影
public:
CP3 P[4][4];//三维控制点
};

``````
``````#include "StdAfx.h"
#include "BicubicBezierPatch.h"
#include <math.h>
#define ROUND(d) int(d+0.5)

CBicubicBezierPatch::CBicubicBezierPatch(void)
{
}

CBicubicBezierPatch::~CBicubicBezierPatch(void)
{
}

{
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
this->P[i][j]=P[i][j];
}
void CBicubicBezierPatch::DrawCurvedPatch(CDC* pDC)
{
CPen NewPen, *pOldPen;
NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));//曲线颜色为蓝色
pOldPen = pDC->SelectObject(&NewPen);
double M[4][4];//系数矩阵Mbe
M[0][0]=-1;M[0][1]=3; M[0][2]=-3;M[0][3]=1;
M[1][0]=3; M[1][1]=-6;M[1][2]=3; M[1][3]=0;
M[2][0]=-3;M[2][1]=3; M[2][2]=0; M[2][3]=0;
M[3][0]=1; M[3][1]=0; M[3][2]=0; M[3][3]=0;
CP3 P3[4][4];//曲线计算用控制点数组
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
P3[i][j]=P[i][j];
LeftMultiplyMatrix(M,P3);//数字矩阵左乘三维点矩阵
TransposeMatrix(M);//计算转置矩阵
RightMultiplyMatrix(P3,M);//数字矩阵右乘三维点矩阵
double Step =0.1;//步长
double u0,u1,u2,u3,v0,v1,v2,v3;//u，v参数的幂
for(double u=0;u<=1;u+=Step)
for(double v=0;v<=1;v+=Step)
{
u3=u*u*u,u2=u*u,u1=u,u0=1;
v3=v*v*v,v2=v*v,v1=v,v0=1;
CP3 pt=(u3*P3[0][0]+u2*P3[1][0]+u1*P3[2][0]+u0*P3[3][0])*v3
+(u3*P3[0][1]+u2*P3[1][1]+u1*P3[2][1]+u0*P3[3][1])*v2
+(u3*P3[0][2]+u2*P3[1][2]+u1*P3[2][2]+u0*P3[3][2])*v1
+(u3*P3[0][3]+u2*P3[1][3]+u1*P3[2][3]+u0*P3[3][3])*v0;
CP2 Point2=ObliqueProjection(pt);//斜投影
if(v==0)
pDC->MoveTo(ROUND(Point2.x),ROUND(Point2.y));
else
pDC->LineTo(ROUND(Point2.x),ROUND(Point2.y));
}
for(double v=0;v<=1;v+=Step)
for(double u=0;u<=1;u+=Step)
{
u3=u*u*u;u2=u*u;u1=u;u0=1;v3=v*v*v;v2=v*v;v1=v;v0=1;
CP3 pt=(u3*P3[0][0]+u2*P3[1][0]+u1*P3[2][0]+u0*P3[3][0])*v3
+(u3*P3[0][1]+u2*P3[1][1]+u1*P3[2][1]+u0*P3[3][1])*v2
+(u3*P3[0][2]+u2*P3[1][2]+u1*P3[2][2]+u0*P3[3][2])*v1
+(u3*P3[0][3]+u2*P3[1][3]+u1*P3[2][3]+u0*P3[3][3])*v0;
CP2 Point2=ObliqueProjection(pt);//斜投影
if(0==u)
pDC->MoveTo(ROUND(Point2.x),ROUND(Point2.y));
else
pDC->LineTo(ROUND(Point2.x),ROUND(Point2.y));
}

pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}

void CBicubicBezierPatch::LeftMultiplyMatrix(double M[][4],CP3 P[][4])//左乘矩阵M*P
{
CP3 T[4][4];//临时矩阵
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
T[i][j]=M[i][0]*P[0][j]+M[i][1]*P[1][j]+M[i][2]*P[2][j]+M[i][3]*P[3][j];
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
P[i][j]=T[i][j];
}

void CBicubicBezierPatch::RightMultiplyMatrix(CP3 P[][4],double M[][4])//右乘矩阵P*M
{
CP3 T[4][4];//临时矩阵
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
T[i][j]=P[i][0]*M[0][j]+P[i][1]*M[1][j]+P[i][2]*M[2][j]+P[i][3]*M[3][j];
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
P[i][j]=T[i][j];
}

void CBicubicBezierPatch::TransposeMatrix(double M[][4])//转置矩阵
{
double T[4][4];//临时矩阵
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
T[j][i]=M[i][j];
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
M[i][j]=T[i][j];
}

CP2 CBicubicBezierPatch::ObliqueProjection(CP3 Point3)//斜二测投影
{
CP2 Point2;
Point2.x=Point3.x-Point3.z*sqrt(2.0)/2.0;
Point2.y=Point3.y-Point3.z*sqrt(2.0)/2.0;
return Point2;
}

void CBicubicBezierPatch::DrawControlGrid(CDC* pDC)//绘制控制网格
{
CP2 P2[4][4];//二维控制点
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
P2[i][j]=ObliqueProjection(P[i][j]);
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_SOLID,3,RGB(0,0,0));
pOldPen=pDC->SelectObject(&NewPen);
for(int i=0;i<4;i++)
{
pDC->MoveTo(ROUND(P2[i][0].x),ROUND(P2[i][0].y));
for(int j=1;j<4;j++)
pDC->LineTo(ROUND(P2[i][j].x),ROUND(P2[i][j].y));
}
for(int j=0;j<4;j++)
{
pDC->MoveTo(ROUND(P2[0][j].x),ROUND(P2[0][j].y));
for(int i=1;i<4;i++)
pDC->LineTo(ROUND(P2[i][j].x),ROUND(P2[i][j].y));
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}
``````

### 4.3.2 主函数调用

``````CP3 P[4][4];//控制点

void CGeometricfiguretestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CRect rect;//定义客户区矩形
GetClientRect(&rect);//获得客户区的大小
pDC->SetMapMode(MM_ANISOTROPIC);//pDC自定义坐标系
pDC->SetWindowExt(rect.Width(),rect.Height());//设置窗口范围
pDC->SetViewportExt(rect.Width(),-rect.Height());//设置视区范围,x轴水平向右，y轴垂直向上
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);//客户区中心为原点
DrawGraph(pDC);//绘制图形
}

{
P[0][0].x=20;  P[0][0].y=0;  P[0][0].z=200;
P[0][1].x=0;   P[0][1].y=100;P[0][1].z=150;
P[0][2].x=-130;P[0][2].y=100;P[0][2].z=50;
P[0][3].x=-250;P[0][3].y=50; P[0][3].z=0;
P[1][0].x=100; P[1][0].y=100;P[1][0].z=150;
P[1][1].x= 30; P[1][1].y=100;P[1][1].z=100;
P[1][2].x=-40; P[1][2].y=100;P[1][2].z=50;
P[1][3].x=-110;P[1][3].y=100;P[1][3].z=0;
P[2][0].x=280; P[2][0].y=90; P[2][0].z=140;
P[2][1].x=110; P[2][1].y=120;P[2][1].z=80;
P[2][2].x=0;   P[2][2].y=130;P[2][2].z=30;
P[2][3].x=-100;P[2][3].y=150;P[2][3].z=-50;
P[3][0].x=350; P[3][0].y=30; P[3][0].z=150;
P[3][1].x=200; P[3][1].y=150;P[3][1].z=50;
P[3][2].x=50;  P[3][2].y=200;P[3][2].z=0;
P[3][3].x=0;   P[3][3].y=100;P[3][3].z =-70;
}

void CGeometricfiguretestView::DrawGraph(CDC* pDC)//绘制图形
{
CBicubicBezierPatch patch;
patch.DrawCurvedPatch(pDC);
patch.DrawControlGrid(pDC);
}
``````

``````void CTestView::ReadPoint()//读入控制多边形顶点
{
P[0][0].x = 20;  P[0][0].y = 0;  P[0][0].z = 200;
P[0][1].x = 0;   P[0][1].y = 100; P[0][1].z = 150;
P[0][2].x = -130; P[0][2].y = 100; P[0][2].z = 50;
P[0][3].x = -250; P[0][3].y = 0; P[0][3].z = 0;
P[1][0].x = 100; P[1][0].y = 0; P[1][0].z = 150;
P[1][1].x = 30; P[1][1].y = 100; P[1][1].z = 100;
P[1][2].x = -40; P[1][2].y = 100; P[1][2].z = 50;
P[1][3].x = -110; P[1][3].y = 0; P[1][3].z = 0;
P[2][0].x = 280; P[2][0].y = 0; P[2][0].z = 140;
P[2][1].x = 110; P[2][1].y = 100; P[2][1].z = 80;
P[2][2].x = 0;   P[2][2].y = 100; P[2][2].z = 30;
P[2][3].x = -100; P[2][3].y = 0; P[2][3].z = -50;
P[3][0].x = 350; P[3][0].y = 0; P[3][0].z = 150;
P[3][1].x = 200; P[3][1].y = 100; P[3][1].z = 50;
P[3][2].x = 50;  P[3][2].y = 100; P[3][2].z = 0;
P[3][3].x = 0;   P[3][3].y = 0; P[3][3].z = -70;
}
``````