1.需要解决问题
原点位于窗体视图区中心(视图区大小与窗口大小相等),x轴为水平,向右为正,y轴为垂直,向上为负,要绘制三角形的顶点坐标为(-200,-100)、(200,-100)、(0,200)。(tip:MFC的设备坐标水平方向为x轴,垂直方向为y轴)
2.映射模式(MapMode)
模式代码 | 宏定义值 | 坐标系特征 |
MM_TEXT | 1 | 每个逻辑单位被转换为1个设备像素,正x向右,正y向下 |
MM_LOMETRIC | 2 | 每个逻辑单位被转换为0.1毫米,正x向右,正y向上 |
MM_HIMETRIC | 3 | 每个逻辑单位被转换为0.01毫米,正x向右,正y向上 |
MM_LOENGLISH | 4 | 每个逻辑单位被转换为0.01英寸,正x向右,正y向上 |
MM_HIENGLISH | 5 | 每个逻辑单位被转换为0.001英寸,正x向右,正y向上 |
MM_TWIPS | 6 | 每个逻辑单位被转换为1/20点(一点是1/72英寸,一个twip是1/1440英寸),正x向右,正y向上 |
MM_ISOTROPIC | 7 | 在保证x轴和y轴比例相等的情况下,逻辑单位被转换为任意的单位,且方向可以独立设置 |
MM_ANISOTROPIC | 8 | 逻辑单位被转换为任意的单位,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);
}