這個其實本身沒啥好研究的,但是曆史證明,我兩年前由於沒有明確直觀地對各個座標系統及其轉換關係進行定義,導致實際開發的時候非常混亂,好幾次座標轉換都是通過試錯的方式來完成的。為了這一次的重新開發順利,將座標系統定義整理在此。
首先說明涉及到的三個座標系統:Document,ZoomedDocument 及 Canvas。它們都是以像素為單位的,座標方向從左上至右下。
- Document:基於映像文檔本身實際像素,原點即映像左上方。所有的真實繪圖操作都應基於該座標系。
- ZoomedDocument:基於映像文檔在實際顯示比例下的顯示像素,原點也為映像左上方。這是一個過渡性質的座標系,用於聯絡真實文檔和螢幕顯示操作。
- Canvas:基於螢幕繪圖區域的顯示像素,原點為繪圖區域的左上方。所有的螢幕顯示和 UI 處理都應基於該座標系。
我們以一個 120 x 120 px 的映像為例,是基於其 Document 座標系本身的尺寸:
當映像文檔顯示在視窗中時,使用者實際操作的是繪圖視窗中的主地區,即畫布(Canvas)。顯示了在不同縮放比例下,基於 Canvas 座標系的一些常用值:
Canvas 座標系中,自身的長寬是由視窗尺寸決定的,原點位於畫布自身左上方。CanvasOffset 是相對於 ZoomedDocument 原點的位移參考值,並不影響 Canvas 的座標原點。之所以將這個位移參考值放在 Canvas 座標系中定義,是因為從概念上來說,文檔是不動的,而編輯視窗則是在整個文檔中四處移動的一個可見地區。
通過 Canvas 座標系和其位移量,我們可以得到相對於已經經過縮放的映像文檔座標系,ZoomedDocument:
該座標系由於表示的是已經經過縮放的文檔,因此其使用的也是實際的螢幕像素尺寸。其中,可見地區即為文檔出現在畫布內的地區,由於原點是文檔的左上方,因此它具有完整的邊界(Bounds)定義。
需要注意的是,可見地區並不等價於畫布。當文檔顯示尺寸大於畫布時(右),可見地區與畫布尺寸是相等的;但當文檔顯示尺寸小於畫布時(左),可見地區只是畫布中的一部分,不會超出文檔的顯示尺寸本身。
最後通過縮放比例,可以還原至文檔實際的座標系,也就是最開始的文檔尺寸定義使用的座標系:
可見,Document 座標系與 ZoomedDoc 座標系的全部區別即在於縮放係數。
下面列出了這些座標系的轉換計算。其中 DocSize、CanvasSize、ZoomRatio、ZoomedDocVisibleOffset 這四組值已經事先獲得或指定。由於寬度與高度概念在這裡是可以完全互換的,這裡只給出 x 方向上的計算:
ZoomedDocWidth := DocWidth * ZoomRatio;
ZoomedDocVisibleWidth := MIN ( CanvasWidth, ZoomedDocWidth );
DocVisibleWidth := ZoomedDocVisibleWidth / ZoomRatio;
DocVisibleLeft := ZoomedDocVisibleLeft / ZoomRatio;
在畫布自由平移模式下,使用者可以隨意在畫布中移動映像文檔,此時 CanvasOffset 的值可以認為是由外部指定的。當處於非自由平移模式下時,其計算方法為:
IF CanvasWidth > ZoomedDocWidth THEN
CanvasOffsetLeft := (CanvasWidth – ZoomedDocWidth) / 2;
ELSE
CanvasOffsetLeft := MIN ( ZoomedDocVisibleLeft, ZoomedDocWidth – CanvasWidth );
END IF
通過這些計算運算式,我們可以在三種座標系中隨意轉換。當 UI 接受到滑鼠操作時,首先得到的是 Canvas 座標,經過轉換可以得到 Document 座標以便進行實際的映像操作,處理結果再通過轉換還原為 Canvas 座標顯示出來。