GDI坐标系统(上)

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);

	. . .
}












 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值