1. 程式人生 > >經緯度糾偏的一些經驗

經緯度糾偏的一些經驗

.bat .ashx war 次數 stat foreach 全面 rgs ogre

  手機上報的經緯度,並不是所有的都是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);

經緯度糾偏的一些經驗