MFC绘制Bezier曲线

MFC绘制Bezier曲线

MFC绘制Bezier曲线_第1张图片
参考《计算几何算法与实现》–孔令德

绘制的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);

你可能感兴趣的:(计算几何算法与实现)