m_prnDC.SetMapMode(MM_LOMETRIC);
m_iPrnX = m_prnDC.GetDeviceCaps(HORZRES);
m_iPrnY = m_prnDC.GetDeviceCaps(VERTRES);
m_iPrnX為寬,m_iPrnY為高。
//獲取打印機設備的橫方向和縱方向的分辨率
//即每英寸像素點數
int xPixPerInch = pDC->GetDeviceCaps(LOGPIXELSX);
int yPixPerInch = pDC->GetDeviceCaps(LOGPIXELSY);
如果pDC是打印機DC,那么xPixPerInch =yPixPerInch =600
如果pDC是屏幕DC,那么xPixPerInch =yPixPerInch =96
virtual int SetMapMode( int nMapMode );
函數功能描述:該函數設置指定設備環境的映射方式,映射方式定義了將邏輯單位轉換為設備單位的度量單位,並定義了設備的X、Y軸的方向。
nMapMode:指定新的映射方式,此參數可以是下面列出的任何一個值。
MM_ANISOTROPIC:邏輯單位轉換成具有任意比例軸的任意單位,用SetWindowExtEx和SetViewportExtEx函數可指定單位、方向和比例。
MM_HIENGLISH:每個邏輯單位轉換為0.001英寸,X的正方面向右,Y的正方向向上。
MM_HIMETRIC:每個邏輯單位轉換為0.01毫米,X正方向向右,Y的正方向向上。
MM_ISOTROPIC:邏輯單位轉換成具有均等比例軸的任意單位,即沿X軸的一個單位等於沿Y軸的一個單位,用和函數可以指定該軸的單位和方向。圖形設備界面(GDI)需要進行調整,以保證X和Y的單位保持相同大小(當設置窗口范圍時,視口將被調整以達到單位大小相同)。
MM_LOENGLISH:每個邏輯單位轉換為0.1英寸,X正方向向右,Y正方向向上。
MM_LOMETRIC:每個邏輯單位轉換為0.1毫米,X正方向向右,Y正方向向上。
MM_TEXT:每個邏輯單位轉換為一個圖素,X正方向向右,Y正方向向下。
MM_TWIPS;每個邏輯單位轉換為打印點的1/20(即1/1400英寸),X正方向向右,Y方向向上。
備注:
MM_TEXT方式允許應用程序以設備像素為單位來工作,像素的大小根據設備不同而不同。MM_HIENLISH, MM_HIMETRIC, MM_LOENGLISH, MM_LOMETRIC和MM_TWIPS方式對必須用物理意義單位(如英寸或毫米)制圖的應用程序是非常有用的。MM_ISOTROPIC方式保證了1:1的縱橫比。MM_HIENLISH方式允許對X和Y坐標分別進行調整。
按習慣,(0,0)就原點,原點就是(0,0),但是如果用此來理解windows的map mode,就會走彎路。其實,稍微改變一下觀念,windows的map mode就比較好理解了。舉例說明:
page space---->device space
pDC->SetMapMode(MM_LOMETRIC);
pDC->SetWindowOrg(40,0); //這句“設定”page space的原點為(40,0),注意,
//這時(40,0)就是原點,原點就是(40,0)這個點,其實,(0,0)與原點沒有必然聯系。這
//一句對下面的畫圖函數在page space中所作的圖不會有任何影響。一句話:SetWindowOrg
//就是指定一下,page space中哪個點為原點。
pDC->Rectangle(0,0,100,-100);
pDC->Rectangle(0,-100,50,-200);
同理,SetViewportOrg也是指定一下,device space中哪個點為原點, 兩個坐標系映射時,兩個原點重合。
SetWindowExt設定page space的大小,SetViewportOrg設定device space的大小,其實,真正有意義的只是兩者的比例關系,例如,在一個1024*768的顯示屏上:
pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetWindowExt(10240,7680);
pDC->SetViewportExt(1024,768);
pDC->Rectangle(0,0,100,100);//給出的是邏輯單位,但是具體繪制出來要轉化為設備單位,轉化比例由模式確定
就會畫一個10 pixels*10 pixels的矩形。其本質就是,X方向,每個邏輯單位有1024/10240個象素,Y方向每個邏輯單位有768/7680個象素。因此,下面的代碼有相同的作用:
pDC->SetMapMode(MM_ISOTROPIC);
pDC->SetWindowExt(102400,76800);
pDC->SetViewportExt(10240,7680);
pDC->Rectangle(0,0,100,100);
兩者本質一樣,前者更易於理解。
================================
SetWindowOrg和SetViewportOrg這兩個函數比較難搞懂,經過本人的google和實踐終於弄明白了這兩個函數的本質區別。
1.SetWindowOrg(x, y) 是把設備坐標的原點(視口)映射到邏輯坐標的(X, Y)處
2.SetViewportOrg(x, y) 是把邏輯坐標的原點(窗口)映射到設備坐標的(X, Y)處
3. 設備原點永遠是客戶區的左上角頂點(upper left corner of the client area)。
(后面的一幅圖顯示了這兩個函數的意義)
注意設備坐標和邏輯坐標的區別:
1.設備坐標的X, Y軸方向是固定的,單位也是固定的,X軸向右遞增,Y向下遞增,單位都是像素。
2.邏輯坐標的X, Y軸方向不固定,單位也不固定,根據選擇的映射模式而變化。
有了以上的解釋,相信大家應該能明白為什么下面的代碼的現實結果會是這樣的了吧。
void CEx05aView::OnDraw(CDC* pDC)
{
pDC->SetMapMode(MM_LOMETRIC);
pDC->SetWindowOrg(100, 100);
pDC->Rectangle(0, 0, 200, 200);
pDC->SetViewportOrg(100, 100);
pDC->SelectStockObject(GRAY_BRUSH);
pDC->Rectangle(0, 0, 200, 200);
}

建立一個合適的坐標系可以為我們的繪圖帶來很大的方便 。下面介紹一下如何在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英寸。