高德离线地图瓦片坐标偏移纠偏

对于地图坐标偏移,以leaflet为例,有如下解决办法

方法1、修改leaflet源码,解决地图坐标偏移问题

方法2、将点位真实的经纬度经过偏移算法,添加到加密的地图上

方法3、直接对离线地图瓦片进行纠偏

方法1需要修改源码

方法2有缺陷,地图依然是偏移的,如果把地图经纬度显示出来,经纬度也是不对的

我使用的是方法3,原理是:虽然偏移不是线性的,我也不知道纠偏算法,但是在市级或者县级区域,偏移近似线性的,所以对于市级或县级地图应用,可以对地图瓦片进行简单的纠编,优点是得到的地图瓦片可以认为是没有偏移的。

我用C#写了一个高德地图瓦片纠偏程序,代码如下:

1、配置文件

xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  startup>
  <appSettings>
    <add key="inputPath" value="D:\_临时文件\GISMap\1818940751"/>
    <add key="outputPath" value="D:\_临时文件\GISMapOutput\1818940751"/>
    <add key="deltaPixcelX" value="1031"/>
    <add key="deltaPixcelY" value="421"/>
    <add key="fromMapZoom" value="1"/>
    <add key="toMapZoom" value="16"/>
  appSettings>
configuration>
View Code

deltaPixcelX和deltaPixcelY根据不同城市而不同,单位是像素,在太乐地图下载器上,开启网络,放大到18级,使用下载器的纠偏计算,定位点位和纠偏后的点位,基本用眼可以看出来,差一个格就是256像素,不足一格的自己算一下,就把deltaPixcelX和deltaPixcelY参数算出来了。

2、纠偏代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Utils;

namespace TileProcess
{
    public partial class Form1 : Form
    {
        private int _count = 0;
        private int _deltaPixcelX;
        private int _deltaPixcelY;
        private string _inputPath;
        private string _outputPath;
        private int _fromMapZoom;
        private int _toMapZoom;

        private DateTime _startTime;
        private int _lastCount;

        private object _lock = new object();

        public Form1()
        {
            InitializeComponent();

            _deltaPixcelX = Convert.ToInt32(ConfigurationManager.AppSettings["deltaPixcelX"]);
            _deltaPixcelY = Convert.ToInt32(ConfigurationManager.AppSettings["deltaPixcelY"]);
            _inputPath = ConfigurationManager.AppSettings["inputPath"];
            _outputPath = ConfigurationManager.AppSettings["outputPath"];
            _fromMapZoom = Convert.ToInt32(ConfigurationManager.AppSettings["fromMapZoom"]);
            _toMapZoom = Convert.ToInt32(ConfigurationManager.AppSettings["toMapZoom"]);
        }

        private void btnTileProcess_Click(object sender, EventArgs e)
        {
            this.btnTileProcess.Enabled = false;

            Task.Factory.StartNew(() =>
            {
                LogUtil.Log("开始处理");
                Process();
            });

            Thread thread = new Thread(new ThreadStart(() =>
            {
                int sleepInterval = 1000;
                while (true)
                {
                    Thread.Sleep(sleepInterval);
                    this.BeginInvoke(new Action(() =>
                    {
                        double totalSeconds = DateTime.Now.Subtract(_startTime).TotalSeconds;
                        int avg = (int)(_count / totalSeconds);
                        lblMsg.Text = string.Format("已处理 {0} 张瓦片图", _count);
                        if (_count - _lastCount > 0)
                        {
                            lblSpeed.Text = string.Format("当前速度:{0} 张/每秒,平均速度:{1} 张/每秒", (_count - _lastCount) * 1000.0 / sleepInterval, avg);
                        }
                        _lastCount = _count;
                    }));
                }
            }));
            thread.IsBackground = true;
            thread.Start();
        }

        /// 
        /// 瓦片纠偏处理
        /// 
        private void Process()
        {
            _startTime = DateTime.Now;
            Regex regex = new Regex(@"\\(\d+)\\(\d+).png", RegexOptions.IgnoreCase);
            for (int i = _fromMapZoom; i <= _toMapZoom; i++)
            {
                int deltaPixcelX = (int)Math.Round(_deltaPixcelX / Math.Round(Math.Pow(2, 18 - i)));
                int deltaPixcelY = (int)Math.Round(_deltaPixcelY / Math.Round(Math.Pow(2, 18 - i)));

                string[] fileArr = Directory.GetFiles(_inputPath + "\\" + i, "*.*", SearchOption.AllDirectories);
                foreach (string file in fileArr)
                {
                    ThreadData data = new ThreadData();
                    data.File = file;
                    data.I = i;
                    data.DeltaPixcelX = deltaPixcelX;
                    data.DeltaPixcelY = deltaPixcelY;

                    ThreadUtil.Run((obj) =>
                    {
                        ThreadData d = obj as ThreadData;

                        Match match = regex.Match(d.File);
                        if (match.Success)
                        {
                            int x = Convert.ToInt32(match.Groups[1].Value);
                            int y = Convert.ToInt32(match.Groups[2].Value);

                            string pathTarget = string.Format(string.Format(@"{0}\{1}\{2}\{3}.png", _outputPath, d.I, x, y));
                            if (!File.Exists(pathTarget))
                            {
                                if (!Directory.Exists(Path.GetDirectoryName(pathTarget)))
                                {
                                    Directory.CreateDirectory(Path.GetDirectoryName(pathTarget));
                                }
                                Bitmap bmpNew = new Bitmap(256, 256, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                                bmpNew.SetResolution(96, 96);
                                Graphics graph = Graphics.FromImage(bmpNew);

                                int deltaX = data.DeltaPixcelX / 256;
                                int deltaY = data.DeltaPixcelY / 256;

                                //临时变量定义
                                string pathSource = null;
                                FileStream fs = null;
                                byte[] bArr = null;
                                MemoryStream ms = null;
                                Bitmap bmpSource = null;

                                //起始
                                pathSource = string.Format(@"{0}\{1}\{2}\{3}.png", _inputPath, d.I, x + deltaX, y + deltaY);
                                if (File.Exists(pathSource))
                                {
                                    fs = new FileStream(pathSource, FileMode.Open, FileAccess.Read);
                                    bArr = new byte[fs.Length];
                                    int readCount = fs.Read(bArr, 0, bArr.Length);
                                    ms = new MemoryStream(bArr, 0, readCount);
                                    bmpSource = new Bitmap(ms);
                                    bmpSource.SetResolution(96, 96);
                                    graph.DrawImage(bmpSource, 0, 0, new RectangleF(data.DeltaPixcelX % 256, data.DeltaPixcelY % 256, 256 - data.DeltaPixcelX % 256, 256 - data.DeltaPixcelY % 256), GraphicsUnit.Pixel);
                                    graph.Flush();

                                    fs.Close();
                                    fs = null;
                                    ms.Close();
                                    ms = null;
                                    bmpSource.Dispose();
                                    bmpSource = null;
                                }

                                //
                                pathSource = string.Format(@"{0}\{1}\{2}\{3}.png", _inputPath, d.I, x + deltaX + 1, y + deltaY);
                                if (File.Exists(pathSource) && (data.DeltaPixcelX > 0 || data.DeltaPixcelY > 0))
                                {
                                    fs = new FileStream(pathSource, FileMode.Open, FileAccess.Read);
                                    bArr = new byte[fs.Length];
                                    int readCount = fs.Read(bArr, 0, bArr.Length);
                                    ms = new MemoryStream(bArr, 0, readCount);
                                    bmpSource = new Bitmap(ms);
                                    bmpSource.SetResolution(96, 96);
                                    graph.DrawImage(bmpSource, 256 - data.DeltaPixcelX % 256, 0, new RectangleF(0, data.DeltaPixcelY % 256, data.DeltaPixcelX % 256, 256 - data.DeltaPixcelY % 256), GraphicsUnit.Pixel);
                                    graph.Flush();

                                    fs.Close();
                                    fs = null;
                                    ms.Close();
                                    ms = null;
                                    bmpSource.Dispose();
                                    bmpSource = null;
                                }

                                //
                                pathSource = string.Format(@"{0}\{1}\{2}\{3}.png", _inputPath, d.I, x + deltaX, y + deltaY + 1);
                                if (File.Exists(pathSource) && (data.DeltaPixcelX > 0 || data.DeltaPixcelY > 0))
                                {
                                    fs = new FileStream(pathSource, FileMode.Open, FileAccess.Read);
                                    bArr = new byte[fs.Length];
                                    int readCount = fs.Read(bArr, 0, bArr.Length);
                                    ms = new MemoryStream(bArr, 0, readCount);
                                    bmpSource = new Bitmap(ms);
                                    bmpSource.SetResolution(96, 96);
                                    graph.DrawImage(bmpSource, 0, 256 - data.DeltaPixcelY % 256, new RectangleF(data.DeltaPixcelX % 256, 0, 256 - data.DeltaPixcelX % 256, data.DeltaPixcelY % 256), GraphicsUnit.Pixel);
                                    graph.Flush();

                                    fs.Close();
                                    fs = null;
                                    ms.Close();
                                    ms = null;
                                    bmpSource.Dispose();
                                    bmpSource = null;
                                }

                                //右下
                                pathSource = string.Format(@"{0}\{1}\{2}\{3}.png", _inputPath, d.I, x + deltaX + 1, y + deltaY + 1);
                                if (File.Exists(pathSource) && (data.DeltaPixcelX > 0 || data.DeltaPixcelY > 0))
                                {
                                    fs = new FileStream(pathSource, FileMode.Open, FileAccess.Read);
                                    bArr = new byte[fs.Length];
                                    int readCount = fs.Read(bArr, 0, bArr.Length);
                                    ms = new MemoryStream(bArr, 0, readCount);
                                    bmpSource = new Bitmap(ms);
                                    bmpSource.SetResolution(96, 96);
                                    graph.DrawImage(bmpSource, 256 - data.DeltaPixcelX % 256, 256 - data.DeltaPixcelY % 256, new RectangleF(0, 0, data.DeltaPixcelX % 256, data.DeltaPixcelY % 256), GraphicsUnit.Pixel);
                                    graph.Flush();

                                    fs.Close();
                                    fs = null;
                                    ms.Close();
                                    ms = null;
                                    bmpSource.Dispose();
                                    bmpSource = null;
                                }

                                bmpNew.Save(pathTarget);
                                //bmpNew.Save("d:\\_临时文件\\1234.png"); //测试用

                                bmpNew.Dispose();
                                bmpNew = null;
                                graph.Dispose();
                                graph = null;
                            } //end if (!File.Exists(pathTarget))

                            lock (_lock)
                            {
                                _count++;
                            }
                        } //end if (match.Success)
                    }, data, (ex) =>
                    {
                        this.BeginInvoke(new Action(() =>
                        {
                            lblErrorMsg.Text = "出错:" + ex.Message + "\r\n" + ex.StackTrace;
                            LogUtil.LogError(ex, "出错");
                        }));
                    }); //end ThreadUtil.Run
                } //end foreach (string file in fileArr)
            } //end for (int i = _fromMapZoom; i <= _toMapZoom; i++)
        }

    }
}
View Code

辅助类ThreadUtil:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Utils
{
    /// 
    /// 线程工具类
    /// 
    public class ThreadUtil
    {
        /// 
        /// 使用的逻辑处理器数
        /// 
        private static int _ProcessorCount;
        private static Semaphore _semaphore;
        private static List _TaskList = new List();
        private static object _lock = new object();

        static ThreadUtil()
        {
            _ProcessorCount = Environment.ProcessorCount * 2 / 4; //使用的逻辑处理器数
            if (_ProcessorCount < 1) _ProcessorCount = 1;
            _semaphore = new Semaphore(_ProcessorCount, _ProcessorCount);
        }

        public static void Run(Action<object> doWork, object arg, Action errorAction)
        {
            Task task = null;
            task = Task.Factory.StartNew((obj) =>
            {
                _semaphore.WaitOne();

                try
                {
                    doWork(obj);
                }
                catch (Exception ex)
                {
                    errorAction(ex);
                }

                _semaphore.Release();

                lock (_lock)
                {
                    _TaskList.Remove(task);
                }
            }, arg);

            lock (_lock)
            {
                _TaskList.Add(task);
            }
        }

        public static void WaitAll()
        {
            Task.WaitAll(_TaskList.ToArray());
        }
    }
}
View Code

辅助类ThreadData:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TileProcess
{
    public class ThreadData
    {
        public int I { get; set; }
        public string File { get; set; }
        public int DeltaPixcelX { get; set; }
        public int DeltaPixcelY { get; set; }
    }
}
View Code

写日志工具类就不贴了,可以用其它日志工具代替

处理速度大约每称300张瓦片,具体根据电脑性能不同,一个城市的瓦片大约1个小时左右能处理完。

纠偏后的地图做最佳路径分析,显示的路径和道路基本吻合,略有误差。

 

你可能感兴趣的:(高德离线地图瓦片坐标偏移纠偏)