欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-10-16 17:01:01
对于地图坐标偏移,以leaflet为例,有如下解决办法 方法1、修改leaflet源码,解决地图坐标偏移问题 方法2、将点位真实的经纬度经过偏移算法,添加到加密的地图上 方法3、直接对离线地图瓦片进行纠偏 方法1需要修改源码 方法2有缺陷,地图依然是偏移的,如果把地图经纬度显示出来,经纬度也是不对的 ......

对于地图坐标偏移,以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>

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

        /// <summary>
        /// 瓦片纠偏处理
        /// </summary>
        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++)
        }

    }
}

辅助类threadutil:

using system;
using system.collections.generic;
using system.linq;
using system.text;
using system.threading;
using system.threading.tasks;

namespace utils
{
    /// <summary>
    /// 线程工具类
    /// </summary>
    public class threadutil
    {
        /// <summary>
        /// 使用的逻辑处理器数
        /// </summary>
        private static int _processorcount;
        private static semaphore _semaphore;
        private static list<task> _tasklist = new list<task>();
        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<exception> 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());
        }
    }
}

辅助类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; }
    }
}

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

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

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