http://www.functionx.com/visualc/gdi/gdicoord.htm
当在Windows上绘图时,绘图区的坐标系统的原点位于屏幕左上角。在屏幕上的所有东西要参照此点来定位。此点可称作笛卡尔坐标系原点(0,0),水平轴(注:x轴)沿(0,0)点向右,竖直轴(注:y轴)沿(0,0)向下。
此原点为操作系统默认坐标原点。如果你调用Ellipse(-100, -100, 100, 100)画图形。可画出一个圆。圆心在屏幕左上角。在此例中,只有右下方的3/4圆可见。
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
CPen PenBlue;
// Blue solid pen width = 1
PenBlue.CreatePen(PS_SOLID, 1, RGB(0, 12, 255));
dc.SelectObject(&pPen);
dc.Ellipse(-100, -100, 100, 100);
}
同样,你可以使用CPaintDC来绘制几何图形或非几何图形。例如,下面的代码,在窗体的中心绘制垂直和水平的两条直线:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect Recto;
CPen PenBlue;
PenBlue.CreatePen(PS_SOLID, 1, RGB(0, 12, 255));
dc.SelectObject(&PenBlue);
dc.Ellipse(-100, -100, 100, 100);
CPen PenBlack;
PenBlack.CreatePen(PS_SOLID, 1, BLACK_PEN);
dc.SelectObject(&PenBlack);
// Retrive the size of the drawing area
GetClientRect(&Recto);
dc.MoveTo(Recto.Width() / 2, 0);
dc.LineTo(Recto.Width() / 2, Recto.Height());
dc.MoveTo(0, Recto.Height() / 2);
dc.LineTo(Recto.Width(), Recto.Height() / 2);
}
改变坐标系
如下所示,默认坐标第它的原点在屏幕的左上角。水平轴从原点向右。竖直轴从原点向下。为了描述此坐标系,我们画一个圆,圆心为原点(0,0)。半径为50个单位。再画一条直线,(0,0)到(100,100):
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
// A circle whose center is at the origin (0, 0)
dc.Ellipse(-50, -50, 50, 50);
// A line that starts at (0, 0) and ends at (100, 100)
dc.MoveTo(0, 0);
dc.LineTo(100, 100);
}
This default origin is fine for most, if not all regular, operations performed on graphics applications.例如,绝大多数的图形程序,包括Paint Shop Pro,都使用此种坐标系。有时,你需要控制坐标系的原点。例如,绝大多数CAD程序,包括AutoCAD,都允许用户设置坐标系原点。
MFC提供多种函数来处理坐标系原点位置,并扩展到了绘图区。包括用于设置坐标系原点的函数。由于你在一个device context上绘图,你所要做的只是简单地调用CDC::SetViewportOrg()方法。它有两个重载版本,它可以使用你使用X和Y值或点来指定原点。函数语法如下:
SetViewportOrg(int X, int Y);
SetViewportOrg(CPoint Pt);
当调用此函数时,要指定一个新的原点。如果使用第二个版本,则参数为POINT或MFC的TPoint类。为了查看此函数的效果,我们将原点在x轴的正方向上移动200个单位,在y轴的正方向上移动150个单位。不改变圆和直线。OnPaint事件处理函数如下:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetViewportOrg(200, 150);
// A circle whose center is at the origin (0, 0)
dc.Ellipse(-50, -50, 50, 50);
// A line that starts at (0, 0) and ends at (100, 100)
dc.MoveTo(0, 0);
dc.LineTo(100, 100);
}
你也可以参照窗体客户区的尺寸来确定原点的位置。如下所示:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect Recto;
// Retrieve the size of the drawing area
GetClientRect(&Recto);
dc.SetViewportOrg(Recto.Width() / 2, Recto.Height() / 2);
// A circle whose center is at the origin (0, 0)
dc.Ellipse(-50, -50, 50, 50);
// A line that starts at (0, 0) and ends at (100, 100)
dc.MoveTo(0, 0);
dc.LineTo(100, 100);
}
现在我们知道如何控件坐标系原点,我们将固定坐标原点,坐标为380,220。我们也可以画出笛卡尔坐标系坐标轴:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect Recto;
dc.SetViewportOrg(380, 220);
// Use a red pen
CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
dc.SelectObject(PenRed);
// A circle whose center is at the origin (0, 0)
dc.Ellipse(-100, -100, 100, 100);
// Use a blue pen
CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));
dc.SelectObject(PenBlue);
// Horizontal axis
dc.MoveTo(-380, 0);
dc.LineTo(380, 0);
// Vertical axis
dc.MoveTo(0, -220);
dc.LineTo(0, 220);
}
如上所见, SetViewportOrg()方法用于改变device context的原点。它也可以用于有方向的坐标轴,可以使水平轴从(0,0)向右正向移动,竖直轴沿正向从(0,0)点向下移动。
为了直观的描述清楚,我们画一条从原点出发的45度的直线:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetViewportOrg(380, 220);
// Use a red pen
CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
dc.SelectObject(PenRed);
// A circle whose center is at the origin (0, 0)
dc.Ellipse(-100, -100, 100, 100);
// Use a blue pen
CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));
dc.SelectObject(PenBlue);
// Horizontal axis
dc.MoveTo(-380, 0);
dc.LineTo(380, 0);
// Vertical axis
dc.MoveTo(0, -220);
dc.LineTo(0, 220);
// An orange pen
CPen PenOrange(PS_SOLID, 1, RGB(255, 128, 0));
dc.SelectObject(PenOrange);
// A diagonal line at 45 degrees
dc.MoveTo(0, 0);
dc.LineTo(120, 120);
}
正如你所看到的,此直线不是45度。它没有在第一象限,而是在第四象限里。这是因为坐标系默认朝向的缘故。
映射模式
为了控制device context的坐标轴的朝向,你可以使用CDC的SetMapMode()方法。语法如下:
int SetMapMode(int nMapMode);
正如你所看到的,此方法依赖于参数值,实现两种功能:一可控制你的程序的坐标系朝向;二可设置你想使用的坐标轴单位。
映射模式的参数为int常量。参数值如下:MM_TEXT,MM_LOENGLISH, MM_HIENGLISH, MM_ANISOTROPIC, MM_HIMETRIC, MM_ISOTROPIC, MM_LOMETRIC, 和 MM_TWIPS.
使用此模式,CDC函数设定的尺寸保持原样。默认的映射模式为MM_TEXT。也就是说,如果你没有指定其它值,你的程序就使用MM_TEXT。此坐标轴水平轴从(0,0)点向右。竖直轴从(0,0)点向下。例如,OnPaint事件可按如下代码重写,效果是一样的。
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetMapMode(MM_TEXT);
dc.SetViewportOrg(380, 220);
// Use a red pen
CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
dc.SelectObject(PenRed);
// A circle whose center is at the origin (0, 0)
dc.Ellipse(-100, -100, 100, 100);
// Use a blue pen
CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));
dc.SelectObject(PenBlue);
// Horizontal axis
dc.MoveTo(-380, 0);
dc.LineTo(380, 0);
// Vertical axis
dc.MoveTo(0, -220);
dc.LineTo(0, 220);
// An orange pen
CPen PenOrange(PS_SOLID, 1, RGB(255, 128, 0));
dc.SelectObject(PenOrange);
// A diagonal line at 45 degrees
dc.MoveTo(0, 0);
dc.LineTo(120, 120);
}
效果相同,如同没有指定映射模式一样。
MM_LOENGLISH与其它映射模式相似(MM_TEXT除外),它实现两种功能。一、它改变了竖直轴的朝向:y坐标的正方向从(0,0)点向上。
二、单位长度要乘以0.01英寸。即单位长度要除以100(注:1英寸约为2.54厘米)。观察MM_LOENGLISH映射模式的影响:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetMapMode(MM_LOENGLISH);
dc.SetViewportOrg(380, 220);
. . .
}
如你所见,现在,在真正的笛卡尔坐标系中绘制出了这些直线(译注:橙色直线在第一象限内)。同时,图形尺寸也缩减了;圆变小了且直线也变短了。
与MM_LOENGLISH模式相似,MM_HIENGLISH设置竖直轴从(0,0)点向上。与MM_LOENGLISH不同,MM_HIENGLISH模式单位为0.001英寸。效果如下(译注:LOENGLISH=LOW ENGLISH HIENGLISH=HIGHT ENGLISH)
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetMapMode(MM_HIENGLISH);
dc.SetViewportOrg(380, 220);
. . . Same as previous
}
注意,直线和圆的尺寸没有变。
MM_LOMETRIC映射模式的坐标轴朝向与前两种模式相现。MM_LOMETRIC的单位长度乘以0.1毫米。如下所示:(译注:LOMETRIC=LOW METRIC)毫米。
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetMapMode(MM_LOMETRIC);
dc.SetViewportOrg(380, 220);
. . .
}
MM_HIMETRIC映射模式的坐标轴朝向与以上三种相同。但它的单位为0.01毫米。如下所示:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
dc.SetMapMode(MM_HIMETRIC);
dc.SetViewportOrg(380, 220);
. . . Same as previous
}
MM_TWIPS模式单位长度除以20.相当于1/1440英寸。其坐标轴与前几种相同。如下所示:
void CExoDraw1View::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect Recto;
dc.SetMapMode(MM_TWIPS);
dc.SetViewportOrg(380, 220);
. . .
}