首页 > 代码库 > 经纬度纠偏的一些经验

经纬度纠偏的一些经验

  手机上报的经纬度,并不是所有的都是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             try100             {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 GPS51                 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_offsetfrom(    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);

 

经纬度纠偏的一些经验