程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> SharpMap深度分析:地圖渲染、坐標和比例尺

SharpMap深度分析:地圖渲染、坐標和比例尺

編輯:關於.NET

上篇對SharpMap的分析文章裡,一個重點就是地圖的渲染流程和機制,這裡就不專門介紹這個問題了 ,只是就坐標的一些細節問題分析一下。

地圖都有一個單位(Unit)、比例尺(Zoom)的概念,還有投影的問題。對於Unit,一般使用Km、m或 者經緯度來表示。一幅地圖,在其所有數據的Unit和投影都一致的情況下,在繪制這些對象到地圖時,就 要根據比例尺進行坐標轉換;同時,在進行地圖的縮放、移動、拾取等操作的時候,鼠標的坐標是桌面的 坐標系統,也要轉換到地圖坐標系統(一般稱為World Coordinates System,簡稱WCS)。

首先來看比例(Zoom)在Map類裡的定義:

private double _Zoom;

public double Zoom

{

    get { return _Zoom; }

    set {

        if (value < _MinimumZoom)

            _Zoom = _MinimumZoom;

        else if (value > _MaximumZoom)

            _Zoom = _MaximumZoom;

        else

            _Zoom = value;

        if (MapViewOnChange != null)

            MapViewOnChange();

    }

}

這個Zoom表示使用地圖Unit表示的地圖寬度。例如地圖單位是Km,那麼如果目前地圖的寬度是500Km, Zoom就是500。這個和Mapinfo中Zoom的概念是一致的。

那麼在渲染的時候,就要對所有對象進行坐標轉換,轉換為要渲染的圖片的坐標系統,然後調用GDI+ 進行渲染。

對於對象的渲染,定義在Layer的名稱空間裡,在VectorLayer類的Render方法裡,根據Geometry對象 的層次依次遍歷各個對象,然後調用Rendering名稱空間的VectorRenderer的各個方法來渲染不同的點、 線、面等對象。

在渲染具體對象時,我們看到這些方法都調用了一個TransformToImage的方法,而這個方法定義在不 同的Geometry名稱空間的不同類裡,目的是由空間對象經過坐標變換後返回一個.net的繪圖對象。

我們把這個流程整理如下:

Map對象GetMap方法→GetMap方法遍歷其Layer,調用Layer的Render方法→各個Layer開始渲染自己, 對於柵格和WMS層,返回范圍內的圖片即可,主要是VectorLayer的渲染→VectorLayer調用自己 DataSource Provider的GetFeaturesInView方法,返回范圍內的對象到一個列表→依次遍歷列表的各個對 象,調用Rendering名稱空間的VectorRenderer的各個方法來渲染不同的點、線、面等對象→渲染這些對 象前,調用幾何對象的TransformToImage方法,返回一個.net的繪圖對象→GDI+根據Style渲染

在最後一步,各個對象調用的TransformToImage方法其實是逐次轉換這個對象的各個點。而點的坐標 轉換定義在Utilities.Transform下,有2個方法:

public static System.Drawing.PointF WorldtoMap(SharpMap.Geometries.Point p, 

SharpMap.Map map)

public static SharpMap.Geometries.Point MapToWorld(System.Drawing.PointF p, 

SharpMap.Map map)

分別轉換WCS坐標到Image坐標和轉換Image坐標到WCS坐標。

這是轉換代碼:

System.Drawing.PointF result = new System.Drawing.Point();

double Height = (map.Zoom * map.Size.Height) / map.Size.Width;

double left = map.Center.X - map.Zoom/2;

double top = map.Center.Y + Height/2;

double pxSize = map.Zoom / map.Size.Width;

result.X = (float)Math.Round(((p.X - left) / pxSize), 0);

result.Y = (float)Math.Round(((top - p.Y) / pxSize), 0);

return result;

left和top表示當前地圖的左上角坐標,Height是高度,需要通過Zoom和Height來換算一下,也許寫作 map.Zoom * (map.Size.Height / map.Size.Width)更好理解一點。pxSize相當於在最終的圖片上的一個 單位相當於WCS的多少單位,這樣,(p.X - left) / pxSize就是橫坐標,縱坐標由於圖片y軸相反,因此 是(top - p.Y) / pxSize。有過Dos或者Windows圖形編程經驗的人對於這樣的代碼應該是非常熟悉。

這段代碼的計算left、height、top、pxSize這些參數的語句其實應該在Map每次更改Zoom時計算比較 好,因為這個函數會被調用非常多次(每個點都要轉換坐標),不過這些都是優化的話了,可以放在系統 穩定以後。

不同的地圖單位和投影下的地圖渲染操作

SharpMap目前還沒有Unit的問題,在Map和Layer裡也沒有定義Unit,投影在新版0.90的beta裡有部分 代碼。象ArcGIS和Mapinfo都支持動態投影,也就是對Map定義一個Unit和投影,對不同的Layer定義一個 投影和Unit,他可以自動的轉換這些Layer的Unit到地圖,然後疊加顯示。

這樣的話,在顯示(渲染)時,就需要對所有對象都要進行投影和尺度變換。雖然似乎在打開數據的 時候進行轉換,但是由於對於空間數據庫,一次打開所有數據已經越來越不可能,而且對數據作分析的時 候,如果數據打開時轉換了數據的Unit,那麼分析結果也會出現問題。因此,這類實現應該是在地圖渲染 時進行投影和變換。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved