MFC绘制键盘控制动画

MFC绘制键盘控制动画


在这里插入图片描述

参考孔令德老师的《计算几何算法与实现》

使用双缓冲机制绘制中心位于窗口客户区中心的立方体线框模型,可以使用键盘上的方向键旋转立方体。

1、创建MFC单文档项目;
2、添加三维点类CP3

#pragma once
class CP3
{
public:
	CP3(void);
	~CP3(void);
	CP3(double x,double y,double z);
public:
	double x;
	double y;
	double z;
    double w;
};
#include "StdAfx.h"
#include "P3.h"


CP3::CP3(void)
{
     w=1;
}


CP3::~CP3(void)
{
}

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

3、添加几何变换算法类CTransform3,实现物体顶点的平移和旋转变换

#pragma once
#include"P3.h"
#include"math.h"
#define PI 3.1415926

class CTransform3
{
public:
	CTransform3(void);
	~CTransform3(void);
	void SetMatrix(CP3*P,int ptNumber);
	void Identity();//初始变换单位矩阵
	void Translate(double tx,double ty,double tz);//平移变换矩阵
	void RotateX(double beta);//绕x轴旋转变换矩阵
	void RotateY(double beta);//绕x轴旋转变换矩阵
	void RotateZ(double beta);//绕x轴旋转变换矩阵
	void MultiplyMatrix();//变换矩阵左乘顶点列阵
public:
	double T[4][4];//三维变换矩阵
	CP3*P;//动态数组定义顶点列阵
	int ptNumber;//顶点个数
};

#include "StdAfx.h"
#include "Transform3.h"


CTransform3::CTransform3(void)
{
}


CTransform3::~CTransform3(void)
{
}

void CTransform3::SetMatrix(CP3*P,int ptNumber)
{
	this->P=P;
	this->ptNumber=ptNumber;
}
void CTransform3::Identity()
{
	T[0][0]=1.0;T[0][1]=0;T[0][2]=0;T[0][3]=0;
	T[1][0]=0;T[1][1]=1.0;T[1][2]=0;T[1][3]=0;
	T[2][0]=0;T[2][1]=0;T[2][2]=1.0;T[2][3]=0;
	T[3][0]=0;T[3][1]=0;T[3][2]=0;T[3][3]=1.0;
}

void CTransform3::Translate(double tx,double ty,double tz)
{
	Identity();
	T[0][3]=tx;
	T[1][3]=ty;
	T[2][3]=tz;
	MultiplyMatrix();
}

void CTransform3::RotateX(double beta)
{
	Identity();
	double rad=beta*PI/180;
	T[1][1]=cos(rad);T[1][2]=-sin(rad);
	T[2][1]=sin(rad);T[1][2]=cos(rad);
	MultiplyMatrix();
}

void CTransform3::RotateY(double beta)
{
	Identity();
	double rad=beta*PI/180;
	T[0][0]=cos(rad);T[0][2]=sin(rad);
	T[2][0]=-sin(rad);T[2][2]=cos(rad);
	MultiplyMatrix();
}

void CTransform3::RotateZ(double beta)
{
	Identity();
	double rad=beta*PI/180;
	T[0][0]=cos(rad);T[0][1]=-sin(rad);
	T[1][0]=sin(rad);T[1][1]=cos(rad);
	MultiplyMatrix();
}

void CTransform3::MultiplyMatrix()
{
	CP3*PTemp=new CP3[ptNumber];
	for(int i=0;i<ptNumber;i++)
		PTemp[i]=P[i];
	for(int j=0;j<ptNumber;j++)
	{
		P[j].x=T[0][0]*PTemp[j].x+T[0][1]*PTemp[j].y+T[0][2]*PTemp[j].z+T[0][3]*PTemp[j].w;
		P[j].y=T[1][0]*PTemp[j].x+T[1][1]*PTemp[j].y+T[1][2]*PTemp[j].z+T[1][3]*PTemp[j].w;
		P[j].z=T[2][0]*PTemp[j].x+T[2][1]*PTemp[j].y+T[2][2]*PTemp[j].z+T[2][3]*PTemp[j].w;
		P[j].w=T[3][0]*PTemp[j].x+T[3][1]*PTemp[j].y+T[3][2]*PTemp[j].z+T[3][3]*PTemp[j].w;
	}
	delete [] PTemp;
}

4、立方体共有8顶点,6个面,在View类中添加函数读取立方体网格的点表和面表
首先添加面表类CFacet

#pragma once
class CFacet
{
public:
	CFacet(void);
	~CFacet(void);
public:
	int pNumber;//表面顶点数
	int pIndex[4];//表面顶点索引号
};

#include "StdAfx.h"
#include "Facet.h"


CFacet::CFacet(void)
{
}


CFacet::~CFacet(void)
{
}

在View类中包含头文件

#include"P3.h"
#include"Facet.h"
#include"Transform3.h"

添加成员变量

	CP3 P[8];//点表
	CFacet F[6];//面表
	double Alpha,Beta;//绕x轴旋转角α,绕y轴旋转角β
	CTransform3 tran;//变换对象

添加正方体点表、面表函数

void CtestView::ReadPoint(void)
{
	double a=160;//立方体边长为2a,中心点在几何体心
	P[0].x=-a;P[0].y=-a;P[0].z=-a;//定义所有的点坐标,注意点要按照顺序进行赋值连接
	P[1].x=+a;P[1].y=-a;P[1].z=-a;
	P[2].x=+a;P[2].y=+a;P[2].z=-a;
	P[3].x=-a;P[3].y=+a;P[3].z=-a;
	P[4].x=-a;P[4].y=-a;P[4].z=+a;
	P[5].x=+a;P[5].y=-a;P[5].z=+a;
	P[6].x=+a;P[6].y=+a;P[6].z=+a;
	P[7].x=-a;P[7].y=+a;P[7].z=+a;
}


void CtestView::ReadFacet(void)
{
	F[0].pIndex[0]=4;F[0].pIndex[1]=5;F[0].pIndex[2]=6;F[0].pIndex[3]=7;//每个面按照序号最小顶点依次逆时针连接
	F[1].pIndex[0]=0;F[1].pIndex[1]=3;F[1].pIndex[2]=2;F[1].pIndex[3]=1;
	F[2].pIndex[0]=0;F[2].pIndex[1]=4;F[2].pIndex[2]=7;F[2].pIndex[3]=3;
	F[3].pIndex[0]=1;F[1].pIndex[1]=2;F[3].pIndex[2]=6;F[3].pIndex[3]=5;
	F[4].pIndex[0]=2;F[4].pIndex[1]=3;F[4].pIndex[2]=7;F[4].pIndex[3]=6;
	F[5].pIndex[0]=0;F[5].pIndex[1]=1;F[5].pIndex[2]=5;F[5].pIndex[3]=4;
}

构造函数初始化:

	// TODO: add construction code here
	Alpha=0;
	Beta=0;
	ReadPoint();
	ReadFacet();
	tran.SetMatrix(P,8);

添加双缓冲函数DoubleBuffer:

void CTestView::DoubleBuffer(CDC* pDC)//双缓冲
{
	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);//客户区中心为原点
	CDC memDC;//内存DC
	memDC.CreateCompatibleDC(pDC);//创建一个与显示pDC兼容的内存memDC
	CBitmap NewBitmap,*pOldBitmap;//内存中承载的临时位图 
	NewBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());//创建兼容位图 
	pOldBitmap=memDC.SelectObject(&NewBitmap);//将兼容位图选入memDC 
	memDC.FillSolidRect(rect,pDC->GetBkColor());//按原来背景填充客户区,否则是黑色
	memDC.SetMapMode(MM_ANISOTROPIC);//memDC自定义坐标系
	memDC.SetWindowExt(rect.Width(),rect.Height());
	memDC.SetViewportExt(rect.Width(),-rect.Height());
	memDC.SetViewportOrg(rect.Width()/2,rect.Height()/2);
	rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
	DrawGraph(&memDC);//向memDC绘制图形
	pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,-rect.Width()/2,-rect.Height()/2,SRCCOPY);//将内存memDC中的位图拷贝到显示pDC中
	memDC.SelectObject(pOldBitmap);//恢复位图
	NewBitmap.DeleteObject();//删除位图
	memDC.DeleteDC();//删除memDC
}

添加绘制立方体线框函数DrawGraph:

void CTestView::DrawGraph(CDC* pDC)//绘制立方体线框
{
	CPoint ScreenP[4];	
	for(int nFacet=0;nFacet<6;nFacet++)//面循环
	{		
		for(int nPoint=0;nPoint<4;nPoint++)//顶点循环
		{
			ScreenP[nPoint].x=P[F[nFacet].pIndex[nPoint]].x;
			ScreenP[nPoint].y=P[F[nFacet].pIndex[nPoint]].y;
		}
		pDC->MoveTo(ScreenP[0].x,ScreenP[0].y);
		pDC->LineTo(ScreenP[1].x,ScreenP[1].y);
		pDC->LineTo(ScreenP[2].x,ScreenP[2].y);
		pDC->LineTo(ScreenP[3].x,ScreenP[3].y);
		pDC->LineTo(ScreenP[0].x,ScreenP[0].y);//闭合多边形
	}
}

添加鼠标事件:

void CTestView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	// TODO: Add your message handler code here and/or call default
	switch(nChar)
	{
	case VK_UP:
		Alpha=+5;
		tran.RotateX(Alpha);
		break;
	case VK_DOWN:
		Alpha=-5;
		tran.RotateX(Alpha);
		break;
	case VK_LEFT:
		Beta=-5;
		tran.RotateY(Beta);
		break;
	case VK_RIGHT:
		Beta=5;
		tran.RotateY(Beta);
		break;
	default:
		break;			
	}
	Invalidate(false);
	CView::OnKeyDown(nChar, nRepCnt, nFlags);
}

最后,在OnDraw函数中调用DoubleBuffer函数:

	DoubleBuffer(pDC);
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值