在GMap.NET 當中,我們可以自定義Marker,進行畫圓形、矩形和多邊形等操作,這個功能在GPS軟件中很重要,需要基於此功能設置區域,就是我們常說的電子圍欄。但是很多人做的時候,是基於窗口像素來進行畫圖操作,這樣會造成畫圖的時候,嚴重失真,因為同一個像素長度,在不同的Zoom比例尺下,換算成地圖距離是不一樣的。這樣會造成畫出來的電子圍欄非常不准確,再次打開地圖重新加載的時候,圍欄可能變大或者變小。
所以我們在保存圖元的時候,例如保存一個圓,需要一個圓心和半徑,半徑需要保存的不是像素長度,而是地圖距離,然后再加載圖元的時候,在圖元渲染函數里,將距離根據當前地圖的Zoom值換算成像素長度,這樣圖元就可以根據不同的Zoom而縮放了。
如下是圓形Marker的源碼:
namespace GpsNET.Marker { [Serializable] public class GMapMarkerCircle : GMapMarker, ISerializable { /// <summary> /// 距離,單位為米 /// </summary> public int Radius; /// <summary> /// specifies how the outline is painted /// </summary> [NonSerialized] public Pen Stroke = new Pen(Color.FromArgb(155, Color.MidnightBlue)); /// <summary> /// background color /// </summary> [NonSerialized] public Brush Fill = new SolidBrush(Color.FromArgb(155, Color.AliceBlue)); /// <summary> /// is filled /// </summary> public bool IsFilled = true; public GMapMarkerCircle(PointLatLng p, int _raidus) : base(p) { Radius = _raidus; // 100m IsHitTestVisible = false; } public override void OnRender(Graphics g) { //將距離轉換成像素長度 int R = (int)((Radius) / Overlay.Control.MapProvider.Projection.GetGroundResolution((int)Overlay.Control.Zoom, Position.Lat)) * 2; if(IsFilled) { g.FillEllipse(Fill, new System.Drawing.Rectangle(LocalPosition.X - R / 2, LocalPosition.Y - R / 2, R, R)); } g.DrawEllipse(Stroke, new System.Drawing.Rectangle(LocalPosition.X - R / 2, LocalPosition.Y - R / 2, R, R)); } public override void Dispose() { if(Stroke != null) { Stroke.Dispose(); Stroke = null; } if(Fill != null) { Fill.Dispose(); Fill = null; } base.Dispose(); } #region ISerializable Members void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); // TODO: Radius, IsFilled } protected GMapMarkerCircle(SerializationInfo info, StreamingContext context) : base(info, context) { // TODO: Radius, IsFilled } #endregion } }
這樣我們在MouseMove事件中,需要不斷的換算出當前點和初始點之間的地圖距離,然后生成圖元,就隨着鼠標移動,而畫出不同大小的圓了。
if (MapClickAction == MAP_ACTION_ENCLOSURE_CIRCLE && e.Button == MouseButtons.Left) { //在鼠標移動的時候,畫矩形選擇框 int w = e.X - originX; int h = e.Y - originY; tempOverlay.Markers.Clear(); //擦出掉以前的marker //換算成以米為單位的距離 int radius = (int)distanceByMeter(lastPosition, latLng); lastCircleMarker = new GMapMarkerCircle(lastPosition, radius); tempOverlay.Markers.Add(lastCircleMarker); }