MFC绘制三次Cardinal曲线
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6f00f324501e09ba58a940d0efdc9407.png)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/867dcc28288209817e0ffb746501d39b.png)
参考《计算几何算法与实现》–孔令德
给定12个型值点,绘制Cardinal曲线:
1、新建MFC单文档程序
2、添加二维点类:
#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)
添加变量
CP2 P[14];//型值点
CP2 Point[4];//矩阵运算的点
int n;//型值点最大值
添加函数
void ReadPoint(void);//读取点
void MultiplyMatrix(double M[4][4],CP2 P[4],int n);//矩阵计算
void DrawDataPoint(CDC*pDC);//加粗型值点
void DrawCardinalCurve(CDC*pDC);//绘制曲线
void CDrawCardinalCurveView::ReadPoint(void)
{
P[0].x =-500, P[0].y =0;
P[1].x =-450, P[1].y =-100;
P[2].x =-350, P[2].y =-250;
P[3].x =-250, P[3].y = 200;
P[4].x =-150, P[4].y = 100;
P[5].x =-50, P[5].y = 150;
P[6].x = 40, P[6].y = 10;
P[7].x = 100, P[7].y = -60;
P[8].x = 150, P[8].y = 80;
P[9].x = 200, P[9].y = 70;
P[10].x =230,P[10].y =-10;
P[11].x =300,P[11].y =-200;
P[12].x =400,P[12].y = 150;
P[13].x =520,P[13].y = 250;
}
void CDrawCardinalCurveView::MultiplyMatrix(double M[4][4],CP2 P[4],int n)
{
for(int i=0;i<4;i++)
{
Point[i]=M[i][0]*P[n]+M[i][1]*P[n+1]+M[i][2]*P[n+2]+M[i][3]*P[n+3];
}
}
void CDrawCardinalCurveView::DrawDataPoint(CDC*pDC)//绘制型值点
{
CBrush NewBrush, *pOldBrush;
NewBrush.CreateSolidBrush(RGB(0, 0, 0));
pOldBrush = pDC->SelectObject(&NewBrush);
for( int i = 1; i < 13; i++)
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);
pDC->Ellipse(ROUND(P[0].x - 5), ROUND(P[0].y - 5), ROUND(P[0].x + 5), ROUND(P[0].y + 5));
pDC->Ellipse(ROUND(P[13].x - 5), ROUND(P[13].y - 5), ROUND(P[13].x + 5), ROUND(P[13].y + 5));
}
void CDrawCardinalCurveView::DrawCardinalCurve(CDC*pDC)
{
double M[4][4];
double u=1;
double s=(1-u)/2;
CP2 p;
M[0][0]=-s ,M[0][1]=2-s,M[0][2]= s-2 ,M[0][3]= s;//Mc矩阵
M[1][0]=2*s,M[1][1]=s-3,M[1][2]=3-2*s,M[1][3]=-s;
M[2][0]=-s ,M[2][1]= 0 ,M[2][2]= s ,M[2][3]= 0;
M[3][0]= 0 ,M[3][1]= 1 ,M[3][2]= 0 ,M[3][3]= 0;
double t3,t2,t1,t0;
CPen pen(PS_SOLID,2,RGB(0,0,0));
CPen*pOldPen=pDC->SelectObject(&pen);
pDC->MoveTo(ROUND(P[1].x),ROUND(P[1].y));
for(int i=0;i<11;i++)
{
Point[0]=P[i],Point[1]=P[i+1],Point[2]=P[i+2],Point[3]=P[i+3];
MultiplyMatrix(M,P,i);
double tStep=0.001;
for(double t=0.0;t<1.0;t+=tStep)
{
t3=t*t*t,t2=t*t,t1=t,t0=1;
p=t3*Point[0]+t2*Point[1]+t1*Point[2]+t0*Point[3];
pDC->LineTo(ROUND(p.x),ROUND(p.y));
}
}
pDC->SelectObject(pOldPen);
}
最后在OnDraw中添加
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();
DrawDataPoint(pDC);
DrawCardinalCurve(pDC);