VS2019MFC使用映射模式函数自建坐标系绘图

本文介绍了如何在MFC环境下,通过改变映射模式(如MM_ANISOTROPIC)来调整坐标系统,并在OnDraw函数中实现绘制三角形。首先,设置映射模式、窗口范围、视图区范围和原点,然后根据坐标变换关系计算顶点坐标,最终绘制出位于客户区中心的三角形。此外,还提供了一种不改变映射模式的解决方案,通过坐标偏移实现相同效果。
摘要由CSDN通过智能技术生成

1.需要解决问题

原点位于窗体视图区中心(视图区大小与窗口大小相等),x轴为水平,向右为正,y轴为垂直,向上为负,要绘制三角形的顶点坐标为(-200,-100)、(200,-100)、(0,200)。(tip:MFC的设备坐标水平方向为x轴,垂直方向为y轴)

2.映射模式(MapMode)

模式代码宏定义值坐标系特征
MM_TEXT1每个逻辑单位被转换为1个设备像素,正x向右,正y向下
MM_LOMETRIC2每个逻辑单位被转换为0.1毫米,正x向右,正y向上
MM_HIMETRIC3每个逻辑单位被转换为0.01毫米,正x向右,正y向上
MM_LOENGLISH4每个逻辑单位被转换为0.01英寸,正x向右,正y向上
MM_HIENGLISH5每个逻辑单位被转换为0.001英寸,正x向右,正y向上
MM_TWIPS6每个逻辑单位被转换为1/20点(一点是1/72英寸,一个twip是1/1440英寸),正x向右,正y向上
MM_ISOTROPIC7在保证x轴和y轴比例相等的情况下,逻辑单位被转换为任意的单位,且方向可以独立设置
MM_ANISOTROPIC8逻辑单位被转换为任意的单位,x轴和y轴的方向和比例独立设置

3.映射模式函数

3.1设置映射模式

函数原型:

virtual int SetMapMode(int nMapMode);

nMapMode取值即为上表,当取MM_ANISOTROPIC时,窗口范围和设备范围可以任意改变,必须使用SetWindowExt函数设置窗口的范围,使用SetViewPortExt设置视图区的范围

3.2设置窗口范围

函数原型:

virtual CSize SetWindowExt(int cx,int cy);

cx是窗口x范围的逻辑单位,cy是窗口y范围的逻辑单位

3.3设置视图区范围

函数原型:

virtual CSize SetViewPortExt(int cx,int cy);

cx是视图区x范围的设备单位,cy是视图区y范围的设备单位

3.4设置视图区原点

函数原型:

virtual CSize SetViewPortOrg(int x,int y);

x,y是视图区新坐标原点的设备坐标

4.MFC编程实现

到工程的view派生类的Ondraw函数中,去掉参数处的注释,然后编程(tip:对于不懂的基类,将光标置于类名上,右键Go To Definition查看该类的定义),需要自己实现的代码如下:

void CExample1View::OnDraw(CDC* pDC)
{
	CExample1Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// 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相对于客户区的位置发生改变,
	//位于客户区新坐标原点右上方,可以将其平移恢复与客户区重合
	//否则后续如果需要继续使用rect属性会出错
	rect.OffsetRect(-rect.Width() / 2, -rect.Height() / 2);//往x负、y负偏移

	CPoint p0(-200, -100), p1(200, -100), p2(0, 200);
	pDC->MoveTo(p0);
	pDC->LineTo(p1);//此时起点变为p1
	pDC->LineTo(p2);//此时起点变为p2
	pDC->LineTo(p0);//所以绘制的前两条边为e01,e12,还需要画e20
}

5.补充解法

不改变坐标映射模式,仅使用坐标变换关系。推算方法:绘图原点对应的设备坐标加上相对于绘图原点的偏移量;比如:设客户区宽w高h,以点(200,-100)为例,绘图原点为(w/2,h/2),绘图坐标系x正与设备坐标系x正同向,所以200即绘图原点在设备坐标系x正方向上偏移200,绘图坐标系y正与设备坐标系y正反向,所以-100即绘图原点在设备坐标系y负方向上偏移100,即坐标变换后的点为(w/2+200,h/2-(-200))。(同向直接加、反向直接减)

void CExample1View::OnDraw(CDC* pDC)
{
	CExample1Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	CRect rect;
	GetClientRect(rect);
	int nClientHeight = rect.Height();
	int nClientWidth = rect.Width();
	int nWidth = nClientWidth / 2;//客户区半宽
	int nHeight = nClientHeight / 2;//客户区半高

	CPoint p0(-200, -100), p1(200, -100), p2(0, 200);
	pDC->MoveTo(nWidth + p0.x, nHeight - p0.y);
	pDC->LineTo(nWidth + p1.x, nHeight - p1.y);
	pDC->LineTo(nWidth + p2.x, nHeight - p2.y);
	pDC->LineTo(nWidth + p0.x, nHeight - p0.y);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赴星辰大海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值