经纬度纠偏的一些经验

Posted yy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了经纬度纠偏的一些经验相关的知识,希望对你有一定的参考价值。

  手机上报的经纬度,并不是所有的都是GPS格式的,有的是GCJ02、有的是Baidu等等,那么如何才能针对一个城市的数据进行全面的纠偏呢?首先需要建立一个纠偏库,之后使用纠偏库实现纠偏。

  以GCJ02纠偏库需要以下步骤:

  • 一、建立纠GCJ02纠偏为GPS的偏库

1)选择一个城市的范围,找到最大最小经度、纬度的范围,设置需要纠偏的精确度,比如我选择A城市做为示例设置其纠偏范围

double leftUpLng = 121.0127;
double leftUpLat = 31.0850;
double rightDownLng = 121.392234;
double rightDownLat = 31.446334;

精确度:0.0001(以米为单位)

 long lngOffsetScope = (long)((rightDownLng - leftUpLng) / 0.0001);
 long latOffsetScope = (long)((rightDownLat - leftUpLat) / 0.0001);

3)选纠偏函数

技术分享
  1         private void DoOffset(List<LatLngOffsetStruct> items)
  2         {
  3             string lats = string.Join(";", items.Select(m => m.GCJ02Lat).ToArray());
  4             string lngs = string.Join(";", items.Select(m => m.GCJ02Lng).ToArray());
  5 
  6             /**
  7 批量纠偏接口(POST)
  8 接口地址 http://api.zdoz.net/transmore.ashx
  9 接口说明 
 10 批量纠偏,一次最大可纠偏1000个坐标点
 11 参数
 12 lats:维度,多个维度用“;”隔开
 13 lngs:经度,多个经度用“;”隔开(要注意经纬度个数相等)
 14 type:转换类型 【1.WGS -> GCJ】 【2.GCJ -> WGS】 【3.GCJ -> BD】 【4.BD -> GCJ】 【5.WGS -> BD】 【6.BD -> WGS】
 15 返回值JSON
 16 根据次序返回一个json格式的数组
 17 演示
 18 参数:lats=34.123;34.332;55.231&lngs=113.123;112.213;115.321&type=1
 19 
 20 返回:[{"Lng":113.12942937312582,"Lat":34.121761850760855},{"Lng":112.21911710957568,"Lat":34.3306763095054}, {"Lng":115.33036232125529,"Lat":55.232930158541052}]
 21 */
 22             string requestUri = "http://api.zdoz.net/transmore.ashx";
 23             string parameter = string.Format("lats={0}&lngs={1}&type=2", lats, lngs);
 24             int cursor = 0;
 25 
 26             GOTO_AGAIN:
 27             try
 28             {
 29                 cursor++;
 30 
 31                 string httpContext = GetRequesetContext(requestUri, parameter);
 32                 // 返回:[{"Lng":113.12942937312582,"Lat":34.121761850760855},{"Lng":112.21911710957568,"Lat":34.3306763095054}, {"Lng":115.33036232125529,"Lat":55.232930158541052}]
 33                 string[] splitItems = httpContext.Split(new string[] { "[", "},{", "]" }, StringSplitOptions.RemoveEmptyEntries);
 34 
 35                 if (splitItems.Length < items.Count)
 36                 {
 37                     logger.Warn("出现拆分出的lat,lng的组合长度不够" + items.Count + "!!!");
 38                 }
 39 
 40                 int itemsNumber = splitItems.Length;
 41                 if (splitItems.Length > items.Count)
 42                 {
 43                     itemsNumber = items.Count;
 44                 }
 45 
 46                 for (var i = 0; i < itemsNumber; i++)
 47                 {
 48                     string[] lngLat = splitItems[i].Split(new string[] { "{", "}", "\"Lng\":", ",\"Lat\":" }, StringSplitOptions.RemoveEmptyEntries);
 49                     if (lngLat.Length != 2)
 50                     {
 51                         logger.Warn("出现" + splitItems[i] + "拆分出的lat,lng格式不正确!!!");
 52                     }
 53 
 54                     double lng = double.Parse(lngLat[0]);
 55                     double lat = double.Parse(lngLat[1]);
 56 
 57                     LatLngOffsetStruct item = items[i];
 58                     item.GpsLng = lng;
 59                     item.GpsLat = lat;
 60                     item.LatOffset = (item.GCJ02Lat - item.GpsLat).ToString();
 61                     item.LngOffset = (item.GCJ02Lng - item.GpsLng).ToString();
 62                 }
 63             }
 64             catch (Exception ex)
 65             {
 66                 if (cursor < 5)
 67                 {
 68                     goto GOTO_AGAIN;
 69                 }
 70 
 71                 logger.Error("DoOffset失败次数超过5次:\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
 72             }
 73         }
 74 
 75         private string GetRequesetContext(string requestUri, string parameter)
 76         {
 77             HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
 78             request.Method = "post";
 79             request.ContentType = "application/x-www-form-urlencoded";
 80 
 81             byte[] payload = System.Text.Encoding.UTF8.GetBytes(parameter);
 82             request.ContentLength = payload.Length;
 83 
 84             Stream writer;
 85             try
 86             {
 87                 writer = request.GetRequestStream();
 88             }
 89             catch (Exception)
 90             {
 91                 writer = null;
 92                 Console.Write("连接服务器失败!");
 93             }
 94 
 95             writer.Write(payload, 0, payload.Length);
 96             writer.Close();
 97 
 98             HttpWebResponse response;
 99             try
100             {
101                 response = (HttpWebResponse)request.GetResponse();
102             }
103             catch (WebException ex)
104             {
105                 response = ex.Response as HttpWebResponse;
106             }
107 
108             string httpContext = string.Empty;
109 
110             using (Stream stream = response.GetResponseStream())
111             {
112                 using (StreamReader reader = new StreamReader(stream))
113                 {
114                     httpContext = reader.ReadToEnd();
115                 }
116             }
117 
118             response.Close();
119 
120             return httpContext;
121         }
View Code

 定义纠偏结构体类:

public class LatLngOffsetStruct
{
    public double GCJ02Lng { get; set; }
    public double GCJ02Lat { get; set; }

    public double GpsLng { get; set; }
    public double GpsLat { get; set; }

    public string LngOffset { get; set; }
    public string LatOffset { get; set; }
}

4)就行纠偏的主要业务逻辑

技术分享
 1         public static void main(String[] args)
 2         {
 3             double leftUpLng = 121.0127;
 4             double leftUpLat = 31.0850;
 5             double rightDownLng = 121.392234;
 6             double rightDownLat = 31.446334;
 7 
 8             long lngOffsetScope = (long)((rightDownLng - leftUpLng) / 0.0001);
 9             long latOffsetScope = (long)((rightDownLat - leftUpLat) / 0.0001);
10             long totalCalculateNumbers = lngOffsetScope * latOffsetScope;
11             long cursor = 0;
12 
13             int previousProgress = 0;
14             List<LatLngOffsetStruct> items = new List<LatLngOffsetStruct>();
15             List<LatLngOffsetStruct> tempitems = new List<LatLngOffsetStruct>();
16             for (double lng = leftUpLng; lng < rightDownLng; lng += 0.0001)
17             {
18                 for (double lat = leftUpLat; lat < rightDownLat; lat += 0.0001)
19                 {
20                     cursor++;
21 
22                     tempitems.Add(new LatLngOffsetStruct() { GCJ02Lat = lat, GCJ02Lng = lng });
23 
24                     if (tempitems.Count == 1000)
25                     {
26                         DoOffset(tempitems);                       //批量GCJ02坐标转化为GPS坐标
27 
28                         items.AddRange(tempitems);
29 
30                         tempitems = new List<LatLngOffsetStruct>();
31 
32                         if (items.Count > 100000)
33                         {
34                             DoInsert(items);                           //批量插入纠偏结果。
35                             items = new List<LatLngOffsetStruct>();
36                         }
37                     }
38 
39                     int progress = (int)(cursor * 100 / totalCalculateNumbers);
40                     if (progress > previousProgress)
41                     {
42                         previousProgress = progress;
43                         this.backgroundWorker.ReportProgress(progress, "已经开始执行进度:" + progress + "%");
44                     }
45                 }
46             }
47 
48             if (tempitems.Count > 0)
49             {
50                 DoOffset(tempitems);             //纠偏GCJ02 to GPS
51                 items.AddRange(tempitems);
52                 DoInsert(items);                     //入库
53             }
54         }
View Code

5)入库函数

技术分享
 1         private void DoInsert(List<LatLngOffsetStruct> tempitems)
 2         {
 3             try
 4             {
 5                 DataTable schema = new DataTable();
 6 
 7                 schema.Columns.Add("GCJ02Lng", typeof(string));
 8                 schema.Columns.Add("GCJ02Lat", typeof(string));
 9                 schema.Columns.Add("LngOffset", typeof(string));
10                 schema.Columns.Add("LatOffset", typeof(string));
11 
12                 foreach (var item in tempitems)
13                 {
14                     schema.Rows.Add(item.GCJ02Lng.ToString(), item.GCJ02Lat.ToString(), item.LngOffset, item.LatOffset);
15                 }
16 
17                 using (SqlConnection connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString))
18                 {
19                     connection.Open();
20                     using (SqlBulkCopy copy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, null))
21                     {
22                         copy.DestinationTableName = "dbo.Global_GCJ02_LngLatOffset";
23                         copy.BatchSize = 10000;
24                         copy.BulkCopyTimeout = 12 * 60 * 60;
25 
26                         copy.ColumnMappings.Clear();
27 
28                         copy.ColumnMappings.Add("GCJ02Lng", "GCJ02Lng");
29                         copy.ColumnMappings.Add("GCJ02Lat", "GCJ02Lat");
30                         copy.ColumnMappings.Add("LngOffset", "LngOffset");
31                         copy.ColumnMappings.Add("LatOffset", "LatOffset");
32 
33                         copy.WriteToServer(schema);
34                     }
35                 }
36             }
37             catch (Exception ex)
38             {
39                 logger.Debug("入库失败:\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
40             }
41         }
View Code
  • 二、如何使用纠偏库实现GCJ02纠偏为GPS

 1)首先需要根据经验建立一个库来记录下哪些host上报的经纬度是gcj02格式的经纬度,哪些host上报的经纬度是baidu坐标的经纬度等。

create table global_gcj02_host(
    host string
);
insert into global_gcj02_host(‘lbs.amap.com‘);
.....
insert into global_gcj02_host(‘api.amap.com‘);
.....

2)使用host坐标系类型经验库(g_gcj02_host )、纠偏库(g_gcj02_lnglatoffset )来实现纠偏

需求:有一个库中存储的是待纠偏的数据表http_latlng

create table temp_baidu_result_for20170704 as 
select t10.begintime,t10.host,t10.base_host,
    (case when isnotnull(t11.lngoffset) then (t10.longitude-t11.lngoffset) else t10.longitude end)as longitude_offset,
    (case when isnotnull(t11.latoffset) then (t10.latitude-t11.latoffset) else t10.latitude end) as latitude_offset
from
(
    select t10.begintime,t10.endtime,t10.host,t10.longitude,t10.latitude,t11.host as base_host 
    from http_latlng t10 inner join g_gcj02_host as t11 on t10.host=t11.host
) t10 
inner join g_gcj02_lnglatoffset t11 on rpad(t10.longitude,8,0)=rpad(t11.gcj02lng,8,0) and rpad(t10.latitude,7,0)=rpad(t11.gcj02lat,7,0);

 

以上是关于经纬度纠偏的一些经验的主要内容,如果未能解决你的问题,请参考以下文章

openlayers应用“三”:百度地图纠偏

纠偏控制系统分析

(译)计算距离方位和更多经纬度之间的点

微信小程序代码片段

你苦苦等待的轨迹纠偏地图定制开发秘籍到货啦,请查收!

获取经度和纬度