基于Visual C++的GDI常用坐标系统及应用(二)

转自http://sdntw.blog.163.com/blog/static/208234174201261110543128/

 

四、自定义坐标系统

目 前为止,我们使用的映射模式可以允许我们选择坐标轴的方向,但仅仅是Y轴的方向。而且,我们不能更改坐标系统的单位,这是因为各种映射模式 (MM_TEXT, MM_HIENGLISH, MM_LOENGLISH, MM_HIMETRIC, MM_LOMETRIC, and MM_TWIPS)有固定的属性集,例如坐标轴的方向和坐标单位等。在CAD应用程序中,如果你需要灵活设置坐标轴方向及坐标单位的话,应该怎么做呢?

仔细研究下面的OnDraw()代码,它绘制了一个200X200像素大小的红边、浅绿色背景的正方形,这个正方形的顶点在(-100,-100)处,右底端位于(100,100)处。同时,从坐标原点处绘制一个45度的直线。

  1. void CGraphicView::OnDraw(CDC* pDC)  
  2. {  
  3.     CGraphicDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     if (!pDoc)  
  6.         return;  
  7.     CPen PenRed(PS_SOLID, 1, RGB(25500));  
  8.     CBrush BrushAqua(RGB(0255255));  
  9.   
  10.     pDC->SelectObject(PenRed);  
  11.     pDC->SelectObject(BrushAqua);  
  12.     // Draw a square with a red border and an aqua background  
  13.     pDC->Rectangle(-100-100100100);  
  14.   
  15.     CPen BluePen(PS_SOLID, 1, RGB(00255));  
  16.     pDC->SelectObject(BluePen);  
  17.     // Diagonal line at 45 degrees starting at the origin (00)  
  18.     pDC->MoveTo(00);  
  19.     pDC->LineTo(200200);  
  20.   
  21. }  

image

图十七、代码效果图

正如你所看到的,我们只得到了正方形的右下部分,同时直线指向时钟的三点到六点之间的方向。假定你想将坐标原点设置与窗口中央位置,或者是更精确一点,设 置于点(340, 220)处,我们已经知道可以使用CDC::SetViewportOrg()(记住,这个函数只用来更改坐标原点,它并不影响坐标轴的方向及坐标单位。 同时,需要注意的是,它使用的坐标单位是像素)函数,下面是一个例子(我们没有规定映射模式,所以程序使用的是默认的MM_TEXT映射模式)。

  1. void CGraphicView::OnDraw(CDC* pDC)  
  2.     {  
  3.         CGraphicDoc* pDoc = GetDocument();  
  4.         ASSERT_VALID(pDoc);  
  5.         if (!pDoc)  
  6.             return;  
  7.         pDC->SetViewportOrg(340, 220);  
  8.   
  9.         CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));  
  10.        .................  
  11.     }  

image

 

图十八、代码效果图

为了控制你自己应用程序中的坐标系统单位,坐标轴的方向,可以使用MM_ISOTROPIC 或MM_ANISOTROPIC映射模式。第一件事是调用CDC::SetMapMode()函数,并在两个常量中选择一个(MM_ISOTROPIC或 MM_ANISOTROPIC)。下面是例子代码

  1. void CGraphicView::OnDraw(CDC* pDC)  
  2.     {  
  3.         CGraphicDoc* pDoc = GetDocument();  
  4.         ASSERT_VALID(pDoc);  
  5.         if (!pDoc)  
  6.             return;  
  7.   
  8.         pDC->SetMapMode(MM_ISOTROPIC);  
  9.   
  10.         pDC->SetViewportOrg(340, 220);  
  11.   
  12.         CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));  
  13.     ..................  
  14.   
  15.     }  

image

图十九、代码效果图

先抛开上面的图片。当调用CDC::SetMapMode(),并使用MM_ISOTROPIC或 MM_ANISOTROPIC作为参数后,并没有结束,这两种映射方式允许我们改变坐标轴的正方向及坐标单位。这两种映射方式的区别在 于:MM_ISOTROPIC映射方式中水平、垂直坐标轴的单位相等,MM_ANISOTROPIC映射方式可以随意控制水平及垂直方向的坐标单位长度。

所以,在调用SetMapMode()函数并规定了MM_ISOTROPIC或MM_ANISOTROPIC映射模式后,你必须调用CDC:SetWindowExt()函数,这个函数用来计算老的或默认的坐标系中一个单位的长度。这个函数有两个版本:

  1. CSize SetWindowExt(int cx, int cy);  
  2. CSize SetWindowExt(SIZE size);  

如果使用第一版本,第一个参数CX说明了水平坐标轴上按照新的逻辑单位代表的长度,CY代表了垂直坐标轴上按照新的逻辑单位代表的长度。

如果你知道按照新的坐标单位计算需要的逻辑尺寸的话,可以使用第二个版本的函数,例子代码如下:

  1. void CGraphicView::OnDraw(CDC* pDC)  
  2. {  
  3.     CGraphicDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     if (!pDoc)  
  6.         return;  
  7.   
  8.     pDC->SetMapMode(MM_ISOTROPIC);  
  9.   
  10.     pDC->SetViewportOrg(340, 220);  
  11.     pDC->SetWindowExt(480, 480);  
  12.   
  13.     CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));  
  14.   ............................  
  15.   
  16. }  

image

图二十、代码效果图

调 用SetWindowExt()函数后,紧接着应调用SetViewportExt()函数,它的任务是规定水平及垂直坐标轴的单位。我们可以这样认 为,SetWindowExt()函数对应着“窗口”,SetViewportExt()函数对应着“视口”。SetViewportExt()函数有两 个版本:

  1. CSize SetViewportExt(int cx, int cy);  
  2. CSize SetViewportExt(SIZE size);  

上述两个函数中的参数与“窗口”中的尺寸是相互对应的,它的单位是像素。为了进一步说明这两个函数的使用,我对这两个函数进行了重新说明:

  1. SetWindowExt(int Lwidth, int Lheight) //参数的单位为逻辑单位(Logical);  
  2.    
  3. SetViewportExt(int Pwidth, int Pheight) //参数的单位为像素(Pixel);  

以 x轴为例(y轴类似),逻辑坐标系中的x轴的单位刻度=| Pwidth | / | Lwidth |。这表示x轴上一个逻辑单位等于多少个像素。比如我们先通过GetDeviceCap(LOGPIXELSX)获得在我们的显示器上每英寸等于多少个像 素,设为p,然后我们将它赋给Pwidth,将Lwidth赋成2,即Pwidth / Lwidth=p / 2。那么,此时逻辑坐标系x轴上的单位刻度就是p / 2个像素;又由于p个像素是代表一个英寸的,所以此时的逻辑坐标系x轴上的单位刻度同时也是半个英寸。还有一点要注意的是,如果Lwidth与 Pwidth同号,逻辑坐标的x轴方向与设备坐标系中的x轴方向相同,否则相反。

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

下面是一个例子:

  1. void CGraphicView::OnDraw(CDC* pDC)  
  2.     {  
  3.         CGraphicDoc* pDoc = GetDocument();  
  4.         ASSERT_VALID(pDoc);  
  5.         if (!pDoc)  
  6.             return;  
  7.   
  8.         pDC->SetMapMode(MM_ISOTROPIC);  
  9.   
  10.         pDC->SetViewportOrg(340, 220);  
  11.         pDC->SetWindowExt(480, 480);  
  12.         pDC->SetViewportExt(440,-680);  
  13.   
  14.         CPen PenRed(PS_SOLID, 1, RGB(255, 0, 0));  
  15.         CBrush BrushAqua(RGB(0, 255, 255));  
  16.   
  17.         pDC->SelectObject(PenRed);  
  18.         pDC->SelectObject(BrushAqua);  
  19.         // Draw a square with a red border and an aqua background  
  20.         pDC->Rectangle(-100, -100, 100, 100);  
  21.   
  22.         CPen BluePen(PS_SOLID, 1, RGB(0, 0, 255));  
  23.         pDC->SelectObject(BluePen);  
  24.         // Diagonal line at 45 degrees starting at the origin (0, 0)  
  25.         pDC->MoveTo(0, 0);  
  26.         pDC->LineTo(200, 200);  
  27.   
  28.     }  

image

图二十一、代码效果图

五、实例代码


为了灵活使用逻辑坐标系,下面给出了几个例子代码:

例1:绘制带箭头的坐标轴

  1. void CGraphicView::OnDraw(CDC* pDC)  
  2. {  
  3.     CGraphicDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     if (!pDoc)  
  6.         return;  
  7.   
  8.     CBrush bgBrush(BLACK_BRUSH);  
  9.     pDC->SelectObject(bgBrush);  
  10.     CRect Recto;  
  11.     GetClientRect(&Recto);  
  12.     pDC->Rectangle(Recto);  
  13.   
  14.     pDC->SetMapMode(MM_ISOTROPIC);  
  15.     pDC->SetViewportOrg(0, 440);  
  16.     pDC->SetWindowExt(480, 480);  
  17.     pDC->SetViewportExt(440, -680);  
  18.   
  19.     CPen PenWhite(PS_SOLID, 1, RGB(255, 255, 255));  
  20.     pDC->SelectObject(PenWhite);  
  21.   
  22.     pDC->MoveTo(21, 20);  
  23.     pDC->LineTo(21, 75);  
  24.     // Up arrow  
  25.     pDC->MoveTo(16, 75);  
  26.     pDC->LineTo(21, 90);  
  27.     pDC->LineTo(26, 75);  
  28.     pDC->LineTo(16, 75);  
  29.   
  30.     pDC->MoveTo(21, 22);  
  31.     pDC->LineTo(75, 22);  
  32.     // Right arrow  
  33.     pDC->MoveTo(75, 17);                               
  34.     pDC->LineTo(90, 22);  
  35.     pDC->LineTo(75, 27);  
  36.     pDC->LineTo(75, 17);  
  37.   
  38.     pDC->SetBkMode(TRANSPARENT);  
  39.     pDC->SetTextColor(RGB(255, 255, 255));  
  40.     pDC->TextOut(16,114,_T("Y"));  
  41.     pDC->TextOut(100,32,_T("X"));  
  42.     pDC->Rectangle(15,15,30,30);  
  43. }  

image

例2:绘制网格

  1. // CGraphicView drawing  
  2.   
  3. void CGraphicView::OnDraw(CDC* pDC)  
  4. {  
  5.     CGraphicDoc* pDoc = GetDocument();  
  6.     ASSERT_VALID(pDoc);  
  7.     if (!pDoc)  
  8.         return;  
  9.   
  10.     CRect Recto;  
  11.   
  12.     GetClientRect(&Recto);  
  13.   
  14.     CBrush bgBrush(BLACK_BRUSH);  
  15.     pDC->SelectObject(bgBrush);  
  16.     pDC->Rectangle(Recto);  
  17.   
  18.     CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));  
  19.     pDC->SelectObject(PenBlue);  
  20.   
  21.     for(int x = 0; x < Recto.Width(); x += 20)  
  22.     {  
  23.         pDC->MoveTo(x, 0);  
  24.         pDC->LineTo(x, Recto.Height());  
  25.     }  
  26.   
  27.     for(int y = 0; y < Recto.Height(); y += 20)  
  28.     {  
  29.         pDC->MoveTo(0, y);  
  30.         pDC->LineTo(Recto.Width(), y);  
  31.     }  
  32.   
  33. }  

image

例3:点状网格

  1. // CGraphicView drawing  
  2.   
  3. void CGraphicView::OnDraw(CDC* pDC)  
  4. {  
  5.     CGraphicDoc* pDoc = GetDocument();  
  6.     ASSERT_VALID(pDoc);  
  7.     if (!pDoc)  
  8.         return;  
  9.   
  10.     CRect Recto;  
  11.   
  12.     GetClientRect(&Recto);  
  13.   
  14.     CBrush bgBrush(BLACK_BRUSH);  
  15.     pDC->SelectObject(bgBrush);  
  16.     pDC->Rectangle(Recto);  
  17.   
  18.     for(int x = 0; x < Recto.Width(); x += 20)  
  19.     {  
  20.         for(int y = 0; y < Recto.Height(); y += 20)  
  21.         {  
  22.             pDC->SetPixel(x, y, RGB(255, 255, 255));  
  23.         }  
  24.     }  
  25. }  

image

例4:正弦图形

  1. // CGraphicView drawing  
  2.   
  3. void CGraphicView::OnDraw(CDC* pDC)  
  4. {  
  5.     CGraphicDoc* pDoc = GetDocument();  
  6.     ASSERT_VALID(pDoc);  
  7.     if (!pDoc)  
  8.         return;  
  9.   
  10.     pDC->SetMapMode(MM_ANISOTROPIC);  
  11.     pDC->SetViewportOrg(340, 220);  
  12.     pDC->SetWindowExt(1440, 1440);  
  13.     pDC->SetViewportExt(-1440, -220);  
  14.   
  15.     CPen PenBlue(PS_SOLID, 1, RGB(0, 0, 255));  
  16.     pDC->SelectObject(PenBlue);  
  17.   
  18.     // Axes  
  19.     pDC->MoveTo(-300,     0);  
  20.     pDC->LineTo( 300,     0);  
  21.     pDC->MoveTo(   0, -1400);  
  22.     pDC->LineTo(   0,  1400);  
  23.   
  24.     // I am exaggerating with the PI value here but why not?  
  25.     const double PI = 3.141592653589793238462643383279;  
  26.   
  27.     // The following two values were chosen randomly by me.  
  28.     // You can chose other values you like  
  29.     const int MultiplyEachUnitOnX = 50;  
  30.     const int MultiplyEachUnitOnY = 250;  
  31.   
  32.     for(double i = -280; i < 280; i += 0.01)  
  33.     {  
  34.         double j = sin(PI / MultiplyEachUnitOnX * i) * MultiplyEachUnitOnY;  
  35.         pDC->SetPixel(i, j, RGB(255, 0, 0));  
  36.     }  
  37.   
  38. }  

image

posted @ 2013-01-07 13:10  魏桐  阅读(277)  评论(0)    收藏  举报