费尔南多托雷斯:VC中坐标系的建立 zz -

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 20:30:54
VC中坐标系的建立 zz

建立一个合适的 

坐标系可以为我们的绘图带来很大的方便 。下面介绍一下如何在VC中建立我们想要的坐标系。
一 设备坐标和逻辑坐标
  设备坐标(Device Coordinate)又称为物理坐标(Physical Coordinate),是指输出设备上的坐标。通常将屏幕上的设备坐标称为屏幕坐标。设备坐标用对象距离窗口左上角的水平距离和垂直距离来指定对象的位置,是以像素为单位来表示的,设备坐标的X轴向右为正,Y轴向下为正,坐标原点位于窗口的左上角。
  逻辑坐标(Logical Coordinate)是系统用作记录的坐标。在缺省的模式(MM_TEXT)下,逻辑坐标的方向和单位与设备坐标的方向和单位相同,也是以像素为单位来表示的,X轴向右为正,Y轴向下为正,坐标原点位于窗口的左上角。逻辑坐标和设备坐标即使在缺省模式下其数值也未必一致,除了在以下两种情况下:
  1. 窗口为非滚动窗口
  2. 窗口为滚动窗口,但垂直滚动条位于滚动边框的最上端,水平滚动条位于最左端,但如果移动了滚动条这两种坐标就不一致了。
  在VC中鼠标坐标的坐标位置用设备坐标表示,但所有GDI绘图都用逻辑坐标表示,所以用鼠标绘图时,那么必须将设备坐标转换为逻辑坐标,可以使用CDC 函数DptoLP()将设备坐标转化为逻辑坐标,同样可以用LptoDP()将逻辑坐标转化为设备坐标。

  二 坐标模式
  为了在不同的领域使用逻辑坐标,Windows提供了以下8种坐标模式:
  分别为MM_TEXT、MM_HIENGLISH、MM_LOENGLISH、MM_HIMETRIC、MM_LOMETRIC、MM_TWIPS、MM_ANISOTROPIC和MM_ISOTROPIC。 

  三 实例解析
  (一) 建立以左上角为原点,X轴和Y轴为1000的坐标,如下图
  我们可以用以下代码:
  void CTtView::OnDraw(CDC* pDC)
   {
    CTtDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    CRect rect;
    GetClientRect(&rect);

    pDC->SetMapMode(MM_ANISOTROPIC);
    pDC->SetViewportOrg(0,0);
    pDC->SetViewportExt(rect.right,rect.bottom);

    pDC->SetWindowOrg(0,0);
    pDC->SetWindowExt(1000,1000);

    pDC->MoveTo(50,50);
    pDC->LineTo(50,950);
    pDC->LineTo(950,950);
    pDC->LineTo(50,50);
   }
  代码分析:
  1. GetClientRect(&rect); 取得客户区矩形区域,将其存放在rect中
  2. 用pDC->SetMapMode(MM_ANISOTROPIC); 设置映射模式
  3. 通过pDC->SetViewportOrg(0,0);设置逻辑坐标的原点。
  4. 通过pDC->SetViewportExt(rect.right,rect.bottom);和 
pDC->SetWindowExt(1000,1000);来确定逻辑坐标下和设备坐标下的尺寸对应关系
  5. 在MM_ANISOTROPIC模式下,X轴单位和Y轴单位可以不相同
  6. 坐标方向的确定方法是如果逻辑窗范围和视口范围符号相同,则逻辑坐标的方向和视口的方向相同,即X轴向右为正,Y轴向下为正。
  7. 如果将显示模式改为MM_ISOTROPIC,那么X轴单位和Y轴单位一定相同,感兴趣的读者可以自己使一下。
  (二) 建立以视窗中心为原点的坐标,如下:
  用如下代码:
  void CTtView::OnDraw(CDC* pDC)
   {
    CTtDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    CRect rect;
    GetClientRect(&rect);

    pDC->SetMapMode(MM_ANISOTROPIC);
    pDC->SetViewportOrg(rect.right/2,rect.bottom/2);
    pDC->SetViewportExt(rect.right,rect.bottom);

    pDC->SetWindowOrg(0,0);
    pDC->SetWindowExt(1000,-1000);

    pDC->MoveTo(150,150);
    pDC->LineTo(-150,-200);
    pDC->LineTo(150,-150);
    pDC->LineTo(150,150);
   }
 代码分析:
  1. 用 pDC->SetViewportOrg(rect.right/2,rect.bottom/2); 设置视口的原点。
2. 用pDC->SetViewportExt(rect.right,rect.bottom);和pDC->SetWindowExt(1000,-1000);来确定设备坐标和逻辑坐标的单位对应关系。
  3. 因为逻辑窗范围和视口范围的符号不一致,纵坐标取反,所以Y轴向上为正。

MM_LOENGLISH、MM_HIENGLISH、MM_LOMETRIC、MM_HIMETRIC、MM_TWIPS这一组是Windows提供的重要的固定比例映射模式。 

它们都是x值向右方向递增,y值向下递减,并且无法改变。它们之间的区别在于比例因子见下:(我想书上P53页肯定是印错了,因为通过程序实验x值向右方向也是递增的) 

MM_LOENGLISH 0.01英寸 
MM_HIENGLISH 0.001英寸 
MM_LOMETRIC 0.1mm 
MM_HIMETRIC 0.01mm 
MM_TWIPS 1/1440英寸 //应用于打印机,一个twip相当于1/20磅,一磅又相当于1/72英寸。

 

在VC里, 准确的说是在Windows编程中,映射模式有:MM_TEXT,(设备坐标)
MM_HIMETRIC,(逻辑坐标)
MM_ISOTROPIC,MM_ANISOTROPIC,.....在的开发环境下,(Windows 默认的模式是MM_TEXT),我们可以通过SetMapMode()来改变当是的映射模式~
   MM_TEXT :X向右方向递增加,Y向下方向递增加,我们可以通过SetViewportOrg()和SetWindowOrg()来改变坐标原点的位置.
 void CInSide_VCView::OnDraw(CDC* pDC)
{
 pDC->TextOut (0,0,"TEST");
 pDC->SelectStockObject (GRAY_BRUSH);
 pDC->SetMapMode (MM_TEXT);
 //pDC->SetWindowOrg (100,100);  交替使用这两句看有什么现象
 //pDC->SetViewportOrg(CPoint(100,100));
 pDC->Ellipse (CRect(0,0,300,300));
 pDC->TextOut (0,0,"22");
 
}
   固定比例模式:X向右方向递减(我认为是增加),Y向下方向递减,MM_LOENGLISH(0.01英寸) MM_HIENGLISH(0.001英寸) MM_LOMETRIC(0.1mm) MM_HIMETRIC(0.01mm) MM_TWIPS(1/1400英寸,一般用于打印机)
   可变比例模式:M_ISOTROPIC(1:1),MM_ANISOTROPIC(可为任意比例),用SetWindowsExt() 和SetViewportExt()来设定比例,
void CInSide_VCView::OnDraw(CDC* pDC)
{
        CRect rectClient;
 GetClientRect(rectClient);
 pDC->SelectStockObject (m_nColor);
 pDC->SetMapMode (MM_ANISOTROPIC);
 pDC->SetWindowExt (1000,1000);
 pDC->SetViewportExt (rectClient.right,rectClient.bottom );
 pDC->SetViewportOrg (rectClient.right/2,rectClient.bottom/2);
 pDC->Ellipse (CRect(-500,-500,500,500));
}
  物理坐标,即我们现实中的尺寸,屏幕中一英寸是现实中的12英寸,如果我们使用MM_LOENGLISH(0.01英寸)的映射模式,那么26.75英寸将是电脑的26.75/12=2.23(英寸),在电脑里1个逻辑单位是0.01英寸,所以,26.75英寸转换为逻辑单位是223单位,但是这过程中有省略,为了防止这样的情况,我们可以使用物理坐标保存。

  转换函数;DPtoLP() 设备坐标到逻辑坐标; LPtoDP()逻辑坐标到设备坐标;物理坐标到逻辑坐标的转换全是由我们自己计算;

MFC 中一般情况下有下面的情况:
  CDC类中的所有成员函数用的是逻辑坐标做参数
  CWND类中的所有成员函数用的是设备坐标做参数
  所有的选中-测试(HIT-TEST)操作都是用的设备坐标,有些函数只能使用设备坐标如:CRect::PtInRect()
  所有要长期保存的值一般用逻辑坐标,用设备坐标则用户对窗口滚动就会改变,该坐标就会失效了;

 下一例子,测试鼠标左键点的区域是不是在指定的地方
void CMyView::OnLButtonDown(UINT uFlags,CPoint point)
{
     CRect rect=m_rect;
     CClientDC dc(this);
     dc.SetMapMode(MM_TEXT);
     dc.LPtoDP(rect);
     if(rect.PtInRect(point))
       {
          MessageBox("YES");
       }

}

一般设置映射模式在OnPrepareDC() 中比较合适~,OnPrepareDC在OnDraw前调用!
 

MFC 对140 种Windows 消息提供了直接的消息控制函数,特别注意下面5个:WM_CREATE,WM_CLOSE,WM_DESTROY,WM_NCDESTROY,WM_QUERYENDSESSION.

WM_CREATES 是WINDOWS 发送给视图的第一个消息,所以在OnCreate()中不能调用那写依赖窗口完全处于激活的WINDOWS函数!,一般来说可以在 OnInitialUpdate()中调用,如:设置映射模式~,但是必须注意,OnInitialUpdate()在视图生存之间可能被调用多次~