高德離線地圖瓦片坐標偏移糾偏

来源:https://www.cnblogs.com/s0611163/archive/2019/12/13/12034779.html

對於地圖坐標偏移,以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>
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();
        }

        /// <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++)
        }

    }
}
View Code

輔助類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());
        }
    }
}
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個小時左右能處理完。

糾偏後的地圖做最佳路徑分析,顯示的路徑和道路基本吻合,略有誤差。

 


您的分享是我們最大的動力!

更多相關文章
  • 場景 JPA入門簡介與搭建HelloWorld(附代碼下載): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 JPA中實現單向多對一的關聯關係: https://blog.csdn.net/BADAO_LIUM ...
  • 一、Task類簡介: Task類是在.NET Framework 4.0中提供的新功能,主要用於非同步操作的控制。它比Thread和ThreadPool提供了更為強大的功能,並且更方便使用。 Task和Task<TResult>類:前者接收的是Action委托類型;後者接收的是Func<TResult ...
  • 問題 在開發一款應用的過程中,我們開發者很難考慮到所有問題,往往會忘記處理一些可能發生的異常。隨之而來的結果就是用戶使用過程中接連不斷的崩潰。所以,我們有必要處理所有未被我們處理的異常。 思路 我們需要做的是,在錯誤發生時保存用戶數據,然後將錯誤直接展示在用戶界面上。 解決 首先,我們打開項目中的 ...
  • 比如我們需要ASP.NET Core 中需要通過PDF來進行某些簡單的報表開發,隨著這並不難,但還是會手忙腳亂的去搜索一些資料,那麼恭喜您,這篇帖子會幫助到您,我們就不會再去浪費一些寶貴的時間。 在本文中我們將要使用DinkToPDF來處理我們在.NET Core Web 程式中進行構建PDF文檔! ...
  • EulerOS其實出來有一段時間了,一直在關註,單是僅僅也只是停留在觀望的階段,目前還沒有接入的打算;正好看到園子里的兄弟分享了華為雲免費試用的活動後,難捺激動的心情,我馬上去申請試用了一臺伺服器。 ...
  • 如果要在程式中使用DbContext,則需要先在Nuget中安裝Microsoft.EntityFrameworkCore.SqlServer ...
  • 原文:https://blogs.msdn.microsoft.com/mazhou/2017/12/12/c-7-series-part-7-ref-returns/ 背景 有兩種方法可以將一個值傳遞給一個方法: 例如,FCL(.NET Framework Class Library)中的Arra ...
  • 引用類庫 1.Install-Package Microsoft.Extensions.Caching.Memory MemoryCacheOptions 緩存配置 1.ExpirationScanFrequency 獲取或設置對過期項的連續掃描之間的最短時間間隔 2.SizeLimit 緩存是沒有 ...
一周排行
  • C#實現(Delegate)的委托就不多說了,直接上代碼,看代碼中的註釋: namespace Delegate { delegate void DGSayiHi(string name);//聲明委托 delegate void DGDo(string name); class Program { ...
  • C#實現的從小到大的冒泡排序: public void BubbleSort(int[] array) { int length = array.Length; for (int i = 0; i < length - 1; i++) { for (int j = length - 1; j > i ...
  • string aa = DateTime.Now.ToShortDateString();//"2019/9/23" string bb = DateTime.Now.ToShortTimeString();//"上午 10:21" string ff = DateTime.Now.ToLongDa ...
  • 1. 什麼是,以及怎麼用畫中畫 Windows 10 Creators Update以後UWP提供了一個新的視圖模式CompactOverlay,中文翻譯成 緊湊的覆蓋層 ?反正大部分時間我們都會稱它為 畫中畫模式 。 上圖中右上角即為進入畫中畫模式的微軟“電影和電視”應用。 可以調用 "Appli ...
  • C#實現的對兩個Table進行Merge,兩表必須存在至少一個公共欄位作為連接項,否則連接就失去了意義。如下是對兩個table進行Merge的詳細代碼: private void button1_Click(object sender, EventArgs e)//Button點擊觸發事件 { #r ...
  • 在很多時候,我們做一些非常規化的界面的時候,往往需要創建一些用戶控制項,在其中繪製好一些基礎的界面塊,作為後續重覆使用的一個單元,用戶控制項同時也可以封裝處理一些簡單的邏輯。在開發Winform各種類型項目,我都時不時需要定製一些特殊的用戶控制項,以方便在界面模塊中反覆使用。我們一般是在自定義的用戶控制項里... ...
  • 第一部分:面向對象 封裝 繼承(里氏轉換) 多態第二部分:值類型、引用類型、字元串操作第三部分:集合文件操作第四部分:正則表達式第五部分:XML操作第六部分:委托、事件第七部分:反射。 //存儲著我們當前正在運行的進程//Process[] pro = Process.GetProcesses(); ...
  • 程式處理存放圖片的幾種方式 我的理解有4個: 1:放在項目本身得文件夾中,直接部署到伺服器上 2:存放在磁碟中,然後資料庫中存放路徑,讀取得時候傳路徑。這個適合小項目 3:將圖片轉換成二進位文件,但是不建議這樣做,因為會給資料庫造成壓力。 4:存放在雲存儲器上,也是在資料庫上存地址,不過是雲地址,使 ...
  • 什麼是AutoMapper?AutoMapper是一個簡單的小型庫,用於解決一個看似複雜的問題 - 擺脫將一個對象映射到另一個對象的代碼。這種類型的代碼是相當沉悶和無聊的寫,所以為什麼不發明一個工具來為我們做? 我們來看看在.netcore3.1中怎樣使用AutoMapper9.0。 Profile ...
  • Teigha中實體旋轉 代碼: using (var trans = database.TransactionManager.StartTransaction()) { Entity ent = trans.GetObject(entityId, OpenMode.ForWrite) asEntit ...
x