http://blog.csdn.net/wwei466/article/details/2912468
關於坐標系操作不錯的總結:
我總結的,有點亂,請大家批評,指正.
1、 基礎知識
坐標系統分為三類:全局坐標系統、頁面坐標系統和設備坐標系統。頁面坐標系與設備坐標系都是以設備的左上角為坐標原點,X水平向右為正,Y垂直向下為正。頁面坐標與設備坐標系的差異在於X,Y的單位不同:頁面坐標系中的X,Y單位可以任意設定,如英寸、毫米等;而設備坐標系中,只有一種單位,那就是點或者像素。
全局坐標系就是我們日常工作的坐標系,缺省情況下x軸正方向水平向右,Y軸正方向垂直向下;我們可以將其進行旋轉、平移等操作。
頁面坐標系是不能更改的,它是一個參照標准,將全局坐標最終轉換為設備坐標。
設備坐標系跟具體的設備有關,在顯示器中,基本的單位是像素,在打印機中,基本單位是點(point)。
myGraphics.TranslateTransform(2, 0.5F)
myGraphics.SetPageUnit(UnitInch);
myGraphics.DrawLine(&myPen, 0, 0, 2, 1)
全局 (0, 0) 到 (2, 1)
頁 (2, 0.5) 到 (4, 1.5)
設備 (192, 48) 到 (384, 144)
我們調用GDI+裡的graphics進行操作時,輸入的坐標為在全局坐標系統中的坐標,而在屏幕或者打印機上顯示的是設備坐標系統中的值。因此,從全局坐標系統中的坐標到設備坐標系統中的坐標需要經過全局坐標到頁面坐標的全局變形(world transformation),從頁面坐標到設備坐標的頁面變形(page transformation)。全局變形通過transform來實現;頁面變形通過setpageunit和setpagescale。Setpageunit()指定繪圖單位,參數分別為
typedef enum {
UnitWorld = 0,
UnitDisplay = 1,
UnitPixel = 2,
UnitPoint = 3,
UnitInch = 4,
UnitDocument = 5,
UnitMillimeter = 6
} Unit;
對於不同的單位,可能轉換為設備坐標的時候就有不同的結果。但是頁面變形需要由setpageunit和setpagescale這兩個函數共同來決定。即
graphics.SetPageUnit(UnitInch);//英寸
graphics.SetPageScale(1.0f);
和
graphics.SetPageUnit(UnitMillimeter );//毫米
graphics.SetPageScale(25.4f);
這兩種設置方式的結果是一樣的。在這裡假定25.4毫米=1英寸
同理,其他幾種模式下(除UnitWorld外,在這種模式下沒有物理單位,缺省情況下為該模式),設備坐標系的設置也是可以相互轉換的。
並且在同一函數段中可以隨時改變設備坐標設置。而不會相互影響,見下面程序段所示:
Graphics graphics(hdc);
// Set the page units to pixels, and draw a rectangle.
graphics.SetPageUnit(UnitPixel);
Pen blackPen(Color(255, 0, 0, 0), 0.0f);
graphics.DrawRectangle(&blackPen, 0, 0, 100, 100);
// Set the page units to inches, and draw a rectangle.
graphics.SetPageUnit(UnitInch);
Pen bluePen(Color(255, 0, 0, 255), 0.0f);
graphics.DrawRectangle(&bluePen, 2, 0, 1, 1);
全局變形:忽略單位,將坐標值進行轉換,下一節詳細說明。
頁面變形:根據單位將坐標值。頁面坐標中,具體的單位是根據基本單位和比例來進行設置的,計算公式為:具體單位=基本單位*比例。
2、 全局變形的換算關系
根據第一節的講解,我們對於這三種坐標系有了一個基本的認識。但對於實際程序開發工作是遠遠不夠的。下面就對所有的變形進行探討。
(1) 基本變換:平移及旋轉
平移及旋轉變換是最基本的全局變換,可以通過如下幾種方式進行實現:graphics::translatetransform,graphics::settransform
其中,translatetransform(int x,int y);如果x>0則表示正方向移動,反之,向反方向移動。
(2) 改變坐標系,使Y軸垂直向上為正
這種轉換,需要利用matrix來進行,稱為仿射變形。
Matrix matrix(1.0f,0.0f,0.0f,-1.0f,x,y);
Graphics.SetTransform(&matrix);//即可將Y軸轉變成垂直向上為正
且平移(x,y)的距離。注,平移坐標轉換是在新的全局坐標系下進行的,即操作的都是全局坐標系。
Matrix matrix(1.0f,0.0f,0.0f,-1.0f,0.0f,0.0f);
graphics.SetTransform(&matrix);
graphics.TranslateTransform(0,-100.0f);//平移是在新的全局坐標系下進行的,平移的也是全局坐標系本身,與頁面坐標系沒有關系
graphics.DrawLine(&pen1,0,0,100,100);
如果在matrix中指定的x的比例不是1.0f的話,那就是全局坐標系中,x軸的比例發生了變化,如果大於1,則進行了放大,即相同大小的數值表示的長度增長。反之,則縮小。
(3)縮放並平移與縮放後平移的效果是不一樣的,即此時的平移還是在原有的基礎上進行的,因此,還是向下為正,即100。
GraphicsContainer container3=graphics.BeginContainer();
//X方向放大2倍,並平移100個單位
Matrix matrix(2.0f,0.0f,0.0f,-1.0f,100.0f,100.0f);
graphics.SetTransform(&matrix);
graphics.DrawLine(&pen1,0,0,100,0);
graphics.EndContainer(container3);
GraphicsContainer container4=graphics.BeginContainer();
//X方向放大2倍,然後再平移100個單位,這時,新的全局坐標系已經變為向上為正,所以向下為負,即-200。此時
Matrix matrix1(2.0f,0.0f,0.0f,-1.0f,0.0f,0.0f);
graphics.SetTransform(&matrix1);
graphics.TranslateTransform(100,-200.0f);
graphics.DrawLine(&pen1,0,0,100,0);
graphics.EndContainer(container4);
輸出結果如下圖所示:
3、 鼠標輸入坐標到全局坐標的轉換
鼠標輸入的坐標都是設備坐標,要轉換為全局坐標,就是一個從全局坐標轉換到設備坐標的逆向過程。即相當於Point1*[Matrix]=point2,其中[Matix]為轉換矩形,在已知point2的情況下,來求point1。這也就是我們進行坐標轉換的真正目的。
轉換方式為:
point1=point2*[Matrix]-1
在實際的操作中,是這樣進行的:
Matrix matrix(2.0f,0.0f,0.0f,-1.0f,100.0f,0.0f);//定義了一個轉換矩陣,轉換坐標系
graphics.SetTransform(&matrix);
Matrix *pmatrix1=matrix.Clone();
pmatrix1->Invert();
pmatrix1->TransformPoints(&m_pt);//m_pt是從屏幕上獲得的一個值,經過轉換以後成為全局坐標系下的一個值,在屏幕上與取值位置是相一致的。
delete pmatrix1;
graphics.DrawLine(&pen,0,0,m_pt.X,m_pt.Y);
上述操作是在一個默認條件下進行的,即頁面坐標系與設備坐標系是同一個坐標系。當這兩個坐標系不同裡,還需要從頁面坐標系坐標以設備坐標系坐標的轉換,轉換過程中,根據設置的單位不同,但總的轉換關系為:
頁面坐標*每單位包括的像素點=設備坐標