绘制的Bezier曲线次数为3,四个控制节点
1、添加二维点类
#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;
}
2、view类中添加头文件
#include"P2.h"
#include"math.h"
#define ROUND(h) int((h)+0.5)//定义四舍五入
3、添加成员属性与成员函数
public:
int n;//曲线的次数
CP2 P[100];//曲线的控制点数组
void DrawBezier(CDC*pDC);//绘制Bezier曲线
int Cni(const int&n,const int&i);//计算C_ni
int Factorial(int n);//计算阶乘
void DrawControlPolygon(CDC*pDC);//绘制控制多边形
void CdrawBezierCurveView::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=t+tStep)
{
double x=0.0;double 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));
}
}
int CdrawBezierCurveView::Cni(const int&n,const int&i)
{
return (Factorial(n)/(Factorial(i)*Factorial(n-i)));
}
int CdrawBezierCurveView::Factorial(int n)
{
int factorial;
if(n==0||n==1)
factorial=1;
else
factorial=n*Factorial(n-1);
return factorial;
}
void CdrawBezierCurveView::DrawControlPolygon(CDC*pDC)
{
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);
}
}
4、构造函数初始化:
CdrawBezierCurveView::CdrawBezierCurveView()
{
// TODO: 在此处添加构造代码
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;
}
5、最后在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矩形与客户区重合
DrawControlPolygon(pDC);
DrawBezier(pDC);