Bezier曲线的拼接
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d911ed878862b349faa8cc632c5d5437.png)
使用四条三次Bezier曲线段逼近圆:
1、新建MFC项目;
2、添加二维点类CP2
#pragma once
//为了避免按照x和y方向进行重复运算,重载运算对象
class CP2
{
public:
CP2(void);
~CP2(void);
CP2(double x,double y);
friend CP2 operator+(const CP2&p0,const CP2&p1);//运算符重载
friend CP2 operator-(const CP2&p0,const CP2&p1);
friend CP2 operator-(double scalar,const CP2&p);
friend CP2 operator-(const CP2&p,double scalar);
friend CP2 operator*(const CP2&p,double scalar);
friend CP2 operator*(double scalar,const CP2&p);
friend CP2 operator/(const CP2&p0,const CP2&p1);
friend CP2 operator/(const CP2&p,double scalar);
public:
double x;
double y;
};
#include "StdAfx.h"
#include "P2.h"
#include"math.h"
CP2::CP2(void)
{
}
CP2::~CP2(void)
{
}
CP2::CP2(double x,double y)
{
this->x=x;
this->y=y;
}
CP2 operator+(const CP2&p0,const CP2&p1)//运算符重载
{
CP2 result;
result.x=p0.x+p1.x;
result.y=p0.y+p1.y;
return result;
}
CP2 operator-(const CP2&p0,const CP2&p1)
{
CP2 result;
result.x=p0.x-p1.x;
result.y=p0.y-p1.y;
return result;
}
CP2 operator-(double scalar,const CP2&p)
{
CP2 result;
result.x=scalar-p.x;
result.y=scalar-p.y;
return result;
}
CP2 operator-(const CP2&p,double scalar)
{
CP2 result;
result.x=p.x-scalar;
result.y=p.y-scalar;
return result;
}
CP2 operator*(const CP2&p,double scalar)
{
return CP2(p.x*scalar,p.y*scalar);
}
CP2 operator*(double scalar,const CP2&p)
{
return CP2(p.x*scalar,p.y*scalar);
}
CP2 operator/(const CP2&p0, CP2&p1)
{
if(fabs(p1.x)<1e-6)
{
p1.x=1.0;
}
if(fabs(p1.y)<1e-6)
{
p1.y=1.0;
}
CP2 result;
result.x=p0.x/p1.x;
result.y=p0.y/p1.y;
return result;
}
CP2 operator/(const CP2&p,double scalar)
{
if(fabs(scalar)<1e-6)
{
scalar=1.0;
}
if(fabs(scalar)<1e-6)
{
scalar=1.0;
}
CP2 result;
result.x=p.x/scalar;
result.y=p.y/scalar;
return result;
}
3、添加Bezier曲线绘制类
#pragma once
#include"P2.h"
#include"math.h"
#define ROUND(h) int((h)+0.5)//定义四舍五入
class DrawBezierCurve
{
public:
DrawBezierCurve(void);
DrawBezierCurve(CP2 *P,int ptNum);
~DrawBezierCurve(void);
void Draw(CDC*pDC);
void DrawControlPolygon(CDC*pDC);
private:
double Cni(const int&n,const int&i);
int Factorial(int n);
private:
CP2 P[4];
int n;
CPoint ctrP[4];
};
#include "StdAfx.h"
#include "DrawBezierCurve.h"
DrawBezierCurve::DrawBezierCurve(void)
{
}
DrawBezierCurve::~DrawBezierCurve(void)
{
}
DrawBezierCurve::DrawBezierCurve(CP2 *P,int ptNum)
{
for(int i=0;i<ptNum;i++)
{
this->P[i]=P[i];
}
n=ptNum-1;
}
void DrawBezierCurve::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;
for(double t=0.0;t<=1.0;t=t+tStep)
{
double x=0.0,y=0.0;
for(int i=0;i<=n;i++)
{
x+=P[i].x*Cni(n,i)*pow(t,i)*pow(1-t,n-i);
y+=P[i].y*Cni(n,i)*pow(t,i)*pow(1-t,n-i);
}
pDC->LineTo(ROUND(x),ROUND(y));
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
}
double DrawBezierCurve::Cni(const int&n,const int&i)
{
return(Factorial(n)/(Factorial(i)*Factorial(n-i)));
}
int DrawBezierCurve::Factorial(int n)
{
int factorial;
if(n==0||n==1)
{
factorial=1;
}
else
factorial=n*Factorial(n-1);
return factorial;
}
void DrawBezierCurve::DrawControlPolygon(CDC*pDC)
{
CBrush NewBrush,*pOldBrush;
pOldBrush=(CBrush*)pDC->SelectStockObject(BLACK_BRUSH);
pDC->MoveTo(ROUND(P[0].x),ROUND(P[0].y));
for(int i=0;i<=n;i++)
{
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);
}
4、在View类中添加头
#include"P2.h"
#include"DrawBezierCurve.h"
添加成员属性
public:
void ReadPoint(void);
CP2 P[12];
CP2 P1[4];
CP2 P2[4];
CP2 P3[4];
CP2 P4[4];
void CDrawSewBezierView::ReadPoint(void)
{
double m=0.5523;
double r=300;
P[0].x=r,P[0].y=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=r*m,P[10].y=-r;
P[11].x=r,P[11].y=-m*r;
}
OnDraw中进行绘制:
// TODO: 在此处为本机数据添加绘制代码
CRect rect;//定义客户区矩形
GetClientRect(&rect);//获得客户区矩形的信息
pDC->SetMapMode(MM_ANISOTROPIC);//自定义二维坐标系
pDC->SetWindowExt(rect.Width(), rect.Height());//设置窗口范围
pDC->SetViewportExt(rect.Width(), -rect.Height());//设置视区范围,且x轴水平向右为正,y轴垂直向上为正
pDC->SetViewportOrg(rect.Width() / 2, rect.Height() / 2);//设置客户区中心为二维坐标系原点
rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//rect矩形与客户区重合
ReadPoint();
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];
DrawBezierCurve Bezier1(P1,4);
Bezier1.Draw(pDC);
Bezier1.DrawControlPolygon(pDC);
DrawBezierCurve Bezier2(P2,4);
Bezier2.Draw(pDC);
Bezier2.DrawControlPolygon(pDC);
DrawBezierCurve Bezier3(P3,4);
Bezier3.Draw(pDC);
Bezier3.DrawControlPolygon(pDC);
DrawBezierCurve Bezier4(P4,4);
Bezier4.Draw(pDC);
Bezier4.DrawControlPolygon(pDC);
参考《计算几何算法与实现》–孔令德