经纬度纠偏的一些经验
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 }
定义纠偏结构体类:
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 }
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 }
- 二、如何使用纠偏库实现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‘);
以上是关于经纬度纠偏的一些经验的主要内容,如果未能解决你的问题,请参考以下文章