现在的位置: 首页 > 综合 > 正文

GDI坐标系统(下)

2017年12月11日 ⁄ 综合 ⁄ 共 5806字 ⁄ 字号 评论关闭

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

   如果使用第一个版本,第一个参数cx指定了水平轴逻辑转化乘子。第二个参数cy指定了竖直轴逻辑转化乘子。如果你想使用SIZE对角指定逻辑宽和高,便 可以使用第二个版本的函数。(译注:cx,cy应该是指定了缩放框的大小。Windows根据绽放框的大小计算出缩放比例)

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
}

【上篇】
【下篇】

抱歉!评论已关闭.