您的位置:首页 > 编程语言 > C语言/C++

VC++图形编程中的坐标映射模式

2013-01-15 16:25 302 查看
前段时间自己在研究Windows的GDI(图形设备接口)编程。刚开始时被其中的坐标映射方式搞得晕头转向,后来经过反复实践终于恍然大悟有所启迪,现总结如下,以避免朋友们遇到此类问题走弯路。
Windows的GDI支持两种坐标系,即逻辑坐标系和物理设备坐标系。必须明确逻辑坐标系对应于平时所说的窗口(Window),而设备坐标系才对应视口 (Viewport)。Ondraw中的CDC类所有的绘图方法都是基于逻辑坐标而言的,GDI通过映射模式将逻辑窗口中的图形输出到物理设备上来的。
由逻辑窗口到物理视口的映射过程我们可以这样理解:我们在窗口坐标系(一般是X轴向右递增,Y轴向上递增,即与笛卡尔坐标系一致,而坐标单位是用户自定义的)上绘图,然后要在视口坐标系(一般坐标原点在屏幕视图的左上角,X轴向右递增,Y轴向下为正方向)下显示,坐标映射方式则规定了窗口和视口的范围,各轴的相对方向、原点或缩放比例等。
对这种映射简单打个比方,如图1,假如我们设定某种映射方式后,规定窗口坐标系的Y轴向上为正方向,视口坐标系的Y轴方向相反,视口坐标系的原点位于窗口坐标系中的(x0, y0)处,那么视图区所覆盖的窗口系中的图形部分将会显示在屏幕上,其余图形则不会显示,所以我们可以把视图区看作一个裁剪窗口,只是这个裁剪窗口随不同的映射方式位置不同而已罢了。

[align=center]图 1[/align]
针对不同的用途,Windows提供三类、共八种标准的映射方式,以便绘图操作:
一 MM_TEXT(默认的坐标映射方式)
[align=center]图 2[/align]
窗口坐标系和视口坐标系完全重合,同为上图,坐标原点对应视图的左上角。此方式下可以把视口系统看作是窗口系统的子区间,并映射为像素单位,即1逻辑单位=1像素,取值范围取决于屏幕的像素分辨率。
[align=left]pDC->SetMapMode(MM_TEXT);[/align]
[align=left]pDC->Rectangle(0, 0, 100, 100);[/align]
pDC->Rectangle(100, 100, 200, 200);
上面代码输出结果为:
[align=center]图 3[/align]
再看以下代码:
[align=left]pDC->SetMapMode(MM_TEXT);[/align]
[align=left]pDC->Rectangle(-100, -100, 100, 100);[/align]
[align=left]pDC->MoveTo(0, 0);[/align]
pDC->LineTo(200, 200);
上面代码仅显示图形的右下部分,如下图:
[align=center]图 4[/align]
我们希望看到图形的全部,或者想让逻辑坐标系的原点位于视图区的中央或更精确的如(200, 200)坐标处,则要用到函数SetWindowOrg或SetViewportOrg。
CPoint SetWindowOrg(int x, int y) //平移视口坐标系,使其原点与窗口坐标系中的坐标(x, y)重合
CPoint SetViewportOrg(int x, int y)//平移窗口坐标系,使其原点与视口坐标系的坐标(x, y)重合
[align=left]pDC->SetMapMode(MM_TEXT);[/align]
[align=left]pDC->SetViewportOrg(200, 200);[/align]
[align=left]// pDC->SetViewportOrg(-200, -200);[/align]
[align=left]pDC->Rectangle(-100, -100, 100, 100);[/align]
[align=left]pDC->MoveTo(0, 0);[/align]
[align=left]pDC->LineTo(200, 200);[/align]
[align=left]绘制效果如下:[/align]
[align=left][/align]
[align=center]图 5[/align]
二 MM_HIENGLISH(高精度英制坐标系) 1单位 = 0.001英寸
MM_LOENGLISH(低精度英制坐标系) 1单位 = 0.01英寸
MM_HIMETRIC(高精度公制坐标系) 1 单位 = 0.01毫米
MM_LOMETRIC(低精度公制坐标系) 1 单位 = 0.1毫米
MM_TWIPS(排版坐标系) 1 单位 = 1缇 = 1/1440英寸
这五种映射方式都规定窗口坐标系的X轴向右,Y轴向上为正方向,区别在于1逻辑单位与1设备单位的换算关系不同。此时仍然可以把视图区看作是逻辑坐标系的一个子区间,只是它位于逻辑坐标系的第四象限。
[align=center]图 6[/align]
如果想显示图3的类似绘制效果,那么须修改代码如下:
[align=left]pDC->SetMapMode(MM_LOENGLISH);[/align]
[align=left]pDC->Rectangle(0, 0, 100, -100);[/align]
pDC->Rectangle(100, -100, 200, -200);
三 MM_ISOTROPIC(各向同性坐标系,x与y单位相等)
MM_ANISOTROPIC(各向异性坐标系,x与y单位不等)
在以上两种方式下,还需要额外设置窗口和视口的范围、,各轴的相对方向、原点及缩放比例。
SetWindowExt(int Lwidth, int Lheight) //参数的单位为逻辑单位(Logical);
SetViewportExt(int Pwidth, int Pheight) //参数的单位为像素(Pixel);
虽然这两个函数是设置窗口和视口范围的函数,但真正意义是设定两坐标单位刻度比。即
pDC->SetMapMode(MM_ISOTROPIC);

pDC->SetWindowExt(10240,7680);

pDC->SetViewportExt(1024,768);

pDC->Rectangle(0,0,100,100); 和下面代码
pDC->SetMapMode(MM_ISOTROPIC);

pDC->SetWindowExt(102400,76800);

pDC->SetViewportExt(10240,7680);

pDC->Rectangle(0,0,100,100); 绘制效果完全相同。
SetWindowExt和SetViewportExt还确定了两坐标系中X轴和Y轴相对方向。如果Lwidth与Pwidth同号,逻辑坐标的x轴方向与设备坐标系中的x轴方向相同,否则相反。需要说明的是设备坐标系保持X轴向右,Y轴向下为正方向。
pDC->SetMapMode(MM_ISOTROPIC);

pDC->SetWindowExt(10240,-7680);//逻辑坐标Y轴的方向与设备坐标系Y轴方向相反,即向上为正方向,

pDC->SetViewportExt(1024,768);//1逻辑单位=0.1设备单位

此外,当使用MM_ISOTROPIC模式时,如果通过计算window与viewport范围的比值得到两个方向的单位刻度比值不同时,那么将会以较小的那个为准。即
pDC->SetMapMode(MM_ISOTROPIC);

pDC->SetWindowExt(10240,7680);
// pDC->SetWindowExt(1024,7680);
// pDC->SetWindowExt(10240,768);

pDC->SetViewportExt(1024,768);

pDC->Rectangle(0,0,100,100);
绘制效果完全相同。
下面是一段完整的绘制代码,输出如图7
[align=left] CRect cRect;//客户区矩形[/align]
[align=left] int i, j;[/align]
[align=left] pDC->SetMapMode(MM_ISOTROPIC);//设定映射方式[/align]
[align=left] pDC->SetWindowExt(4000, 3000);[/align]
[align=left] AfxGetMainWnd()->GetClientRect(cRect);//获取主窗口客户区矩形[/align]
[align=left] pDC->SetViewportExt(cRect.Width(), -cRect.Height());//将整个客户区作为视图区,同时改变窗口坐标系Y轴方向,即向上为正方向[/align]
[align=left] pDC->SetViewportOrg(cRect.Width() / 2, cRect.Height() / 2);//将窗口坐标系的原点平移到视图区的中央[/align]
[align=left] pDC->TextOut(-850, 1400, "The first Windows Application");//输出黑色标题文字[/align]
[align=left] //画坐标轴[/align]
[align=left] pDC->MoveTo(-4000, 0);[/align]
[align=left] pDC->LineTo(4000, 0);[/align]
[align=left] pDC->MoveTo(0, -3000);[/align]
[align=left] pDC->LineTo(0, 3000);[/align]
[align=left] //绘制图形[/align]
[align=left] for (i = 10; i > 0; i --)[/align]
[align=left] {[/align]
[align=left] j = 20 - (2 * i);[/align]
[align=left] pDC->Ellipse(j, j, 100 * i, 100 * i);[/align]
[align=left] pDC->Rectangle(-j, -j, -100 * i, -100 * i);[/align]
}
[align=center]图 7[/align]

总结
第一、二类映射模式MM_TEXT, MM_LOENGLISH、MM_HIENGLISH、MM_ANISOTROPIC、MM_HIMETRIC, MM_ISOTROPIC、 MM_LOMETRIC, MM_TWIPS属于固定映射模式,该类映射模式已经固定了坐标轴的方向和坐标单位长度,如MM_TEXT规定Y轴向下,后面五种规定Y轴方向向上。第三类映射模式则允许用户自定义坐标系统,包括坐标轴方向和单位刻度值,也更加灵活。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: