http://www.functionx.com/visualc/gdi/gdicoord.htm
自定义单位与坐标系
到目前为止,这些映射模式允许我们设置坐标轴朝向。但我们不能设置单位长度。因为每一种模式(MM_TEXT, MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, and MM_TWIPS) 都已经设置好了坐标轴朝向、单位长度等属性。如果你想自定义它们,应该怎么做呢(你使用过AutoCAD么)?
思考事件处理函数OnPaint。它绘制了200x200像素的方形,红色边框,浅绿色背景。为了更好的表示,此函数绘制了一条对角线,起点为原点(0,0)。
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
- CBrush BrushAqua(RGB(0, 255, 255));
- dc.SelectObject(PenRed);
- dc.SelectObject(BrushAqua);
- // Draw a square with a red border and an aqua background
- dc.Rectangle(-100, -100, 100, 100);
- CPen BluePen(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(BluePen);
- // Diagonal line at 45 degrees starting at the origin (0, 0)
- dc.MoveTo(0, 0);
- dc.LineTo(200, 200);
- }
如你所见,我们能看见右下角的部分方形。直线在第四象限内。
设想原点(0,0)点位于窗体中心。即将原点放在(340,220)处。你已经会使用CDC::SetViewportOrg()方法来指定原点。请看下面的例子(我们没有指定映射模式,因为MM_TEXT是默认映射模式)
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- dc.SetViewportOrg(340, 220);
- CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
- CBrush BrushAqua(RGB(0, 255, 255));
- dc.SelectObject(PenRed);
- dc.SelectObject(BrushAqua);
- // Draw a square with a red border and an aqua background
- dc.Rectangle(-100, -100, 100, 100);
- CPen BluePen(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(BluePen);
- // Diagonal line at 45 degrees starting at the origin (0, 0)
- dc.MoveTo(0, 0);
- dc.LineTo(200, 200);
- }
为了自定义你自己的坐标系,包括坐标轴的朝向和单位长度。可以使用MM_ISOTROPIC或MM_ANISOTROPIC模式。首先,你要调用CDC::SetMapMode()函数来指定其中一个(MM_ISOTROPIC或MM_ANISOTROPIC)。例子如下:
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- dc.SetMapMode(MM_ISOTROPIC);
- dc.SetViewportOrg(340, 220);
- CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
- CBrush BrushAqua(RGB(0, 255, 255));
- dc.SelectObject(PenRed);
- dc.SelectObject(BrushAqua);
- // Draw a square with a red border and an aqua background
- dc.Rectangle(-100, -100, 100, 100);
- CPen BluePen(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(BluePen);
- // Diagonal line at 45 degrees starting at the origin (0, 0)
- dc.MoveTo(0, 0);
- dc.LineTo(200, 200);
- }
别认为,在传入参数MM_ISOTROPIC或MM_ANISOTROPIC参数调用CDC::SetMapMode()之后,就完毕了,别被上面图骗了。这两个模式的目的是让你控制坐标由的朝向或单位长度。
两种模式的不同之处在于,当使用MM_ISOTROPIC模式时,水平轴的单位长度与竖直轴的单位长度相等。这里没有列举MM_ANISOTROPIC模式。此模式可使你为水平轴竖直轴设置不同的单位长度。
所以,在使用MM_ISOTROPIC或MM_ANISOTROPIC参数调用SetMapMode之后,你必须调用函数CDC::SetWindowExt()。此函数决定了新单位长度的多少。新单位长度将与旧的或默认的单位长度相乘。CDC::SetWindowsExt()有两个版本。语法如下:
- CSize SetWindowExt(int cx, int cy);
- CSize SetWindowExt(SIZE size);
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- dc.SetMapMode(MM_ISOTROPIC);
- dc.SetViewportOrg(340, 220);
- dc.SetWindowExt(480, 480);
- CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
- CBrush BrushAqua(RGB(0, 255, 255));
- dc.SelectObject(PenRed);
- dc.SelectObject(BrushAqua);
- // Draw a square with a red border and an aqua background
- dc.Rectangle(-100, -100, 100, 100);
- CPen BluePen(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(BluePen);
- // Diagonal line at 45 degrees starting at the origin (0, 0)
- dc.MoveTo(0, 0);
- dc.LineTo(200, 200);
- }
在调用SetWindowExt()函数之后,你可以调用SetViewporExt()函数。它的作用是指定水平轴和竖直轴的单位长度。语法如下:
- CSize SetViewportExt(int cx, int cy);
- CSize SetViewportExt(SIZE size);
为了使用第一个版本的函数,你必须提供水平轴的转化因子cx和竖直轴的转化因子cy。如果你知道高宽比,你可以使用第二个版本的函数。(译注:很明显SetWiewport是视口有关的函数)
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- dc.SetMapMode(MM_ISOTROPIC);
- dc.SetViewportOrg(340, 220);
- dc.SetWindowExt(480, 480);
- dc.SetViewportExt(440, -680);
- CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));
- CBrush BrushAqua(RGB(0, 255, 255));
- dc.SelectObject(PenRed);
- dc.SelectObject(BrushAqua);
- // Draw a square with a red border and an aqua background
- dc.Rectangle(-100, -100, 100, 100);
- CPen BluePen(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(BluePen);
- // Diagonal line at 45 degrees starting at the origin (0, 0)
- dc.MoveTo(0, 0);
- dc.LineTo(200, 200);
- }
坐标轴箭头例子
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- CBrush bgBrush(BLACK_BRUSH);
- dc.SelectObject(bgBrush);
- dc.Rectangle(Recto);
- dc.SetMapMode(MM_ISOTROPIC);
- dc.SetViewportOrg(0, 440);
- dc.SetWindowExt(480, 480);
- dc.SetViewportExt(440, -680);
- CPen PenWhite(PS_SOLID, 1, RGB(255, 255, 255));
- dc.SelectObject(PenWhite);
- dc.MoveTo(21, 20);
- dc.LineTo(21, 75);
- // Up arrow
- dc.MoveTo(16, 75);
- dc.LineTo(21, 90);
- dc.LineTo(26, 75);
- dc.LineTo(16, 75);
- dc.MoveTo(21, 22);
- dc.LineTo(75, 22);
- // Right arrow
- dc.MoveTo(75, 17);
- dc.LineTo(90, 22);
- dc.LineTo(75, 27);
- dc.LineTo(75, 17);
- dc.SetBkMode(TRANSPARENT);
- dc.SetTextColor(RGB(255, 255, 255));
- dc.TextOut(16, 114, 'Y');
- dc.TextOut(100, 32, 'X');
- dc.Rectangle(15, 15, 30, 30);
- }
绘制线状网格
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- CRect Recto;
- GetClientRect(&Recto);
- CBrush bgBrush(BLACK_BRUSH);
- dc.SelectObject(bgBrush);
- dc.Rectangle(Recto);
- CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(PenBlue);
- for(int x = 0; x < Recto.Width(); x += 20)
- {
- dc.MoveTo(x, 0);
- dc.LineTo(x, Recto.Height());
- }
- for(int y = 0; y < Recto.Height(); y += 20)
- {
- dc.MoveTo(0, y);
- dc.LineTo(Recto.Width(), y);
- }
- }
绘制点状网格
- void CExoDraw1View::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- CRect Recto;
- GetClientRect(&Recto);
- CBrush bgBrush(BLACK_BRUSH);
- dc.SelectObject(bgBrush);
- dc.Rectangle(Recto);
- for(int x = 0; x < Recto.Width(); x += 20)
- {
- for(int y = 0; y < Recto.Height(); y += 20)
- {
- dc.SetPixel(x, y, RGB(255, 255, 255));
- }
- }
- }
绘制正弦曲线
- void CExoView::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- // TODO: Add your message handler code here
- dc.SetMapMode(MM_ANISOTROPIC);
- dc.SetViewportOrg(340, 220);
- dc.SetWindowExt(1440, 1440);
- dc.SetViewportExt(-1440, -220);
- CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));
- dc.SelectObject(PenBlue);
- // Axes
- dc.MoveTo(-300, 0);
- dc.LineTo( 300, 0);
- dc.MoveTo( 0, -1400);
- dc.LineTo( 0, 1400);
- // I am exaggerating with the PI value here but why not?
- const double PI = 3.141592653589793238462643383279;
- // The following two values were chosen randomly by me.
- // You can chose other values you like
- const int MultiplyEachUnitOnX = 50;
- const int MultiplyEachUnitOnY = 250;
- for(double i = -280; i < 280; i += 0.01)
- {
- double j = sin(PI / MultiplyEachUnitOnX * i) * MultiplyEachUnitOnY;
- dc.SetPixel(i, j, RGB(255, 0, 0));
- }
- // Do not call CView::OnPaint() for painting messages
- }