代码改变世界

GMap.NET开发技巧- 开发可以根据地图放大缩小而缩放的图元

  GPS视频平台产品经理  阅读(4168)  评论(2编辑  收藏  举报

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

  

编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示