在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);
}
