打造地图拼接利器(六)GMap.net内动态显示和更新经纬网络

地图下载工具初步完成后,有网友提出需要加入经纬网络,看了文档,没有找到相关内容。那就自己动手,丰衣足食吧。最终效果如下图所示:


可以显示经纬网络和动态调整

具体思路是,根据地图界面显示的经纬网络范围,确定一个合理的参数,结合地图层级,将经纬网络分别生成并显示出来,同时在周围显示具体数据,当鼠标拖动地图、地图放大缩小时,自动计算和更新经纬网络。比如,第3层,经度范围-180到180,可以平均为8份制定经线,纬度范围-90至90(实则为85°),可以平分为6份。
经过测算,不同层级内,经纬度平分参数如下:


image.png
代码为:
 public static int[] lngsplit = { 
                                        2,
                                        6,
                                        8,
                                        12,
                                        24,
                                        60,
                                        120,
                                        240,
                                        360,
                                        720,
                                        1440,
                                        2160,
                                        4320,
                                        9600,
                                        21600,
                                        43200,
                                        64800,
                                        129600,
                                        259200,
                                        648000,
                                        1296000
                                       };
        public static int[] latsplit = { 
                                        2,
                                        4,
                                        6,
                                        10,
                                        15,
                                        45,
                                        90,
                                        180,
                                        270,
                                        540,
                                        1080,
                                        2160,
                                        3600,
                                        7200,
                                        21600,
                                        43200,
                                        64800,
                                        129600,
                                        324000,
                                        648000,
                                        1296000
                                       };

具体实现步骤为,新建一个类LngLatGrid,构造函数传入参数GMapControl control,同时,动态添加一个层,用来放置经纬线和刻度值文本。具体代码如下

  public LngLatGrid(GMapControl control)
        {
            this.control = control;

            InitOverlay();

            InitEvent();

        }

        /// 
        /// 初始化经纬网层
        /// 
        private void InitOverlay()
        {
            bool haslnglatgrid = false;
            foreach (GMapOverlay overlay in control.Overlays)
            {
                if (overlay.Id.Equals("lnglatgrid"))
                {
                    haslnglatgrid = true;
                    this.gridOverlay = overlay;
                    continue;
                }
            }
            if (!haslnglatgrid)
            {
                gridOverlay = new GMapOverlay("lnglatgrid");
                control.Overlays.Add(gridOverlay);
            }

        }

        /// 
        /// 初始化事件
        /// 
        private void InitEvent()
        {
            control.MouseDown += control_MouseDown;
            control.MouseUp += control_MouseUp;
            control.MouseMove += control_MouseMove;
            control.OnMapZoomChanged += control_OnMapZoomChanged;
        }

        void control_OnMapZoomChanged()
        {
            UpdateLngLat();
        }

        void control_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (isDrag)
            {
                UpdateLngLat();
            }
        }

        void control_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            isDrag = false; UpdateLngLat();
        }


        void control_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            isDrag = true;
        }

        internal void ClearLngLat()
        {
            gridOverlay.Clear();
        }

经纬网计算函数为:
这里要强调一下,过细的拆分可能出现浮点数而变得不准确,需要先将范围扩大,所以我们可以把经度×3600,相当于把度换算成秒,这样平均计算时就不会有太大误差。

        public void UpdateLngLat()
        {

            if (GlobalConfig.isshowLnglatGird)
            {
                int zoom = (int)control.Zoom;
                if (zoom > GlobalConfig.lngsplit.Length)
                    return;
                gridOverlay.Clear();
                Rectangle m = control.ClientRectangle;

                PointLatLng p1 = control.FromLocalToLatLng(m.X, m.Y);
                PointLatLng p2 = control.FromLocalToLatLng(m.Width, m.Height);

                double latn = p1.Lat < 90 ? p1.Lat : 90;
                double lats = p2.Lat > -90 ? p2.Lat : -90;
                double lnge = p2.Lng < 180 ? p2.Lng : 180;
                double lngw = p1.Lng > -180 ? p1.Lng : -180;

                double lngsplit = 360d * 3600 / GlobalConfig.lngsplit[zoom - 1] ;
                double latsplit = 180d * 3600 / GlobalConfig.latsplit[zoom - 1] ;

                double mx = Convert.ToInt32(lngw * 3600 / lngsplit) * lngsplit;
                double nx = Convert.ToInt32(lats * 3600 / latsplit) * latsplit;

                for (double i = mx; i < lnge*3600; )
                {
                    double cdeg = i / 3600;
                    GMapPolygon p = new GMapPolygon(new List()
                {
                    new PointLatLng(lats,cdeg),
                    new PointLatLng(latn,cdeg)
                }, "lng" + cdeg.ToString().PadLeft(3, '0'));
                    i += lngsplit;
                    p.Stroke = new Pen(new SolidBrush(Color.Black), 2);
                    gridOverlay.Polygons.Add(p);

                    GMapMarker markern = new LabelMarker(new PointLatLng(latn, cdeg), Tools.ToDegreeStr(cdeg,"lng"), Color.Black);
                    gridOverlay.Markers.Add(markern);
                    GPoint slatp = control.FromLatLngToLocal(new PointLatLng(lats, cdeg));
                    PointLatLng slat = control.FromLocalToLatLng((int)slatp.X, (int)(slatp.Y - 40));
                    GMapMarker markerw = new LabelMarker(slat, Tools.ToDegreeStr(cdeg, "lng"), Color.Black);
                    gridOverlay.Markers.Add(markerw);
                }

                for (double i = nx; i <= latn * 3600; )
                {
                    double cdeg = i / 3600;
                    GMapPolygon p = new GMapPolygon(new List()
                {
                    new PointLatLng(cdeg,lngw),
                    new PointLatLng(cdeg,lnge)
                }, "lat" + cdeg.ToString().PadLeft(3, '0'));
                    i += latsplit;
                    p.Stroke = new Pen(new SolidBrush(Color.Red), 2);
                    gridOverlay.Polygons.Add(p);

                    GPoint elngp = control.FromLatLngToLocal(new PointLatLng(cdeg, lnge));
                    PointLatLng elng = control.FromLocalToLatLng((int)elngp.X - 140, (int)(elngp.Y));
                    GMapMarker markere = new LabelMarker(elng, Tools.ToDegreeStr(cdeg,"lat"), Color.Red);
                    gridOverlay.Markers.Add(markere);

                    GMapMarker markerw = new LabelMarker(new PointLatLng(cdeg, lngw), Tools.ToDegreeStr(cdeg, "lat"), Color.Red);
                    gridOverlay.Markers.Add(markerw);
                }
                control.Invalidate();
            }
            else
            {
                gridOverlay.Clear();
            }

        }

因为GMap.net中并未提供直接标注文字的功能,所以我们要改造一个marker,用Graphics进行文本绘制,

using GMap.NET.WindowsForms;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;

namespace Mapmerger.Utils
{
    class LabelMarker:GMapMarker
    {
          private string text;

            public string Text
            {
              get { return text; }
              set { text = value; }
            }
       
        private Color defaultColor;
        public LabelMarker(GMap.NET.PointLatLng p, string text,Color color)
            : base(p)
        {
            this.text = text;
            this.defaultColor = color;
        }

        public override void OnRender(Graphics g)
        {
            RectangleF rect = new RectangleF(LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
            Font font = new Font("宋体", 18);
            StringFormat format = StringFormat.GenericTypographic;
            float dpi = g.DpiY;
            using (GraphicsPath path = GetStringPath(text, dpi, rect, font, format))
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;//设置字体质量
                g.DrawPath(Pens.White, path);//绘制轮廓(描边)
                g.FillPath(new SolidBrush(defaultColor), path);//填充轮廓(填充)
            }
        }
        GraphicsPath GetStringPath(string s, float dpi, RectangleF rect, Font font, StringFormat format)
        {
            GraphicsPath path = new GraphicsPath();
            float emSize = dpi * font.SizeInPoints / 72;
            path.AddString(s, font.FontFamily, (int)font.Style, emSize, rect, format);

            return path;
        }
        public override void Dispose()
        {

            base.Dispose();
        }
    }
  
}

相关功能测试效果较好,效率也很好,因为动态更新且经纬网和注记数量较少,运行速度很快。完工。

你可能感兴趣的:(打造地图拼接利器(六)GMap.net内动态显示和更新经纬网络)