• 经纬度纠偏的一些经验


      手机上报的经纬度,并不是所有的都是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次:
    {0}
    {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("入库失败:
    {0}
    {1}", ex.Message, ex.StackTrace);
    40             }
    41         }
    View Code

    全亮代码:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Net;
      6 using System.IO;
      7 using System.Diagnostics;
      8 using NLog;
      9 using System.Configuration;
     10 
     11 namespace gcj02_baidu_offset_lib
     12 {
     13     public class LatLngOffsetStruct
     14     {
     15         public double GCJ02Lng { get; set; }
     16         public double GCJ02Lat { get; set; }
     17 
     18         public double GpsLng { get; set; }
     19         public double GpsLat { get; set; }
     20 
     21         public string LngOffset { get; set; }
     22         public string LatOffset { get; set; }
     23     }
     24 
     25     public class Program
     26     {
     27         static string fileWriteFilePath = string.Empty;
     28         static Logger logger = LogManager.GetCurrentClassLogger();
     29 
     30         public static void Main(String[] args)
     31         {
     32             fileWriteFilePath = ConfigurationManager.AppSettings.Get("fileWriteFilePath");// "D:\gcj02_offset_wenzhou.csv";
     33             double leftUpLng = double.Parse(ConfigurationManager.AppSettings.Get("leftUpLng"));// 121.0127;
     34             double leftUpLat = double.Parse(ConfigurationManager.AppSettings.Get("leftUpLat"));//31.0850;
     35             double rightDownLng = double.Parse(ConfigurationManager.AppSettings.Get("rightDownLng"));// 121.392234;
     36             double rightDownLat = double.Parse(ConfigurationManager.AppSettings.Get("rightDownLat"));// 31.446334;
     37 
     38             long lngOffsetScope = (long)((rightDownLng - leftUpLng) / 0.0001);
     39             long latOffsetScope = (long)((rightDownLat - leftUpLat) / 0.0001);
     40             long totalCalculateNumbers = lngOffsetScope * latOffsetScope;
     41             long cursor = 0;
     42 
     43             int previousProgress = 0;
     44             List<LatLngOffsetStruct> items = new List<LatLngOffsetStruct>();
     45             List<LatLngOffsetStruct> tempitems = new List<LatLngOffsetStruct>();
     46 
     47             for (double lng = leftUpLng; lng < rightDownLng; lng += 0.0001)
     48             {
     49                 for (double lat = leftUpLat; lat < rightDownLat; lat += 0.0001)
     50                 {
     51                     cursor++;
     52 
     53                     tempitems.Add(new LatLngOffsetStruct() { GCJ02Lat = lat, GCJ02Lng = lng });
     54 
     55                     if (tempitems.Count == 1000)
     56                     {
     57                         DoOffset(tempitems);                            //批量GCJ02坐标转化为GPS坐标
     58 
     59                         items.AddRange(tempitems);
     60 
     61                         tempitems = new List<LatLngOffsetStruct>();
     62 
     63                         if (items.Count > 100000)
     64                         {
     65                             DoInsert(items);                           //批量插入纠偏结果。
     66                             items = new List<LatLngOffsetStruct>();
     67                         }
     68                     }
     69 
     70                     int progress = (int)(cursor * 100 / totalCalculateNumbers);
     71                     if (progress > previousProgress)
     72                     {
     73                         previousProgress = progress;
     74                         Debug.WriteLine("已经开始执行进度:" + progress + "%");
     75                     }
     76                 }
     77             }
     78 
     79             if (tempitems.Count > 0)
     80             {
     81                 DoOffset(tempitems);                                //纠偏GCJ02 to GPS
     82                 items.AddRange(tempitems);
     83                 DoInsert(items);                                    //入库
     84             }
     85         }
     86 
     87         static void DoInsert(List<LatLngOffsetStruct> tempitems)
     88         {
     89             try
     90             {
     91                 foreach (var item in tempitems)
     92                 {
     93                     using (StreamWriter writer = new StreamWriter(fileWriteFilePath, true))
     94                     {
     95                         writer.WriteLine(string.Concat(item.GCJ02Lng, ",", item.GCJ02Lat, ",", item.LngOffset, ",", item.LatOffset));
     96                     }
     97                 }
     98             }
     99             catch (Exception ex)
    100             {
    101                 logger.Debug("入库失败:
    {0}
    {1}", ex.Message, ex.StackTrace);
    102             }
    103         }
    104 
    105         static void DoOffset(List<LatLngOffsetStruct> items)
    106         {
    107             string lats = string.Join(";", items.Select(m => m.GCJ02Lat).ToArray());
    108             string lngs = string.Join(";", items.Select(m => m.GCJ02Lng).ToArray());
    109 
    110             /**
    111             批量纠偏接口(POST)
    112             接口地址 http://api.zdoz.net/transmore.ashx
    113             接口说明 
    114             批量纠偏,一次最大可纠偏1000个坐标点
    115             参数
    116             lats:维度,多个维度用“;”隔开
    117             lngs:经度,多个经度用“;”隔开(要注意经纬度个数相等)
    118             type:转换类型 【1.WGS -> GCJ】 【2.GCJ -> WGS】 【3.GCJ -> BD】 【4.BD -> GCJ】 【5.WGS -> BD】 【6.BD -> WGS】
    119             返回值JSON
    120             根据次序返回一个json格式的数组
    121             演示
    122             参数:lats=34.123;34.332;55.231&lngs=113.123;112.213;115.321&type=1
    123 
    124             返回:[{"Lng":113.12942937312582,"Lat":34.121761850760855},{"Lng":112.21911710957568,"Lat":34.3306763095054}, {"Lng":115.33036232125529,"Lat":55.232930158541052}]
    125             */
    126             string requestUri = "http://api.zdoz.net/transmore.ashx";
    127             string offsetType = ConfigurationManager.AppSettings.Get("offsetType");
    128             string parameter = string.Format("lats={0}&lngs={1}&type=" + offsetType, lats, lngs);
    129             int cursor = 0;
    130 
    131         GOTO_AGAIN:
    132             try
    133             {
    134                 cursor++;
    135 
    136                 string httpContext = GetRequesetContext(requestUri, parameter);
    137                 // 返回:[{"Lng":113.12942937312582,"Lat":34.121761850760855},{"Lng":112.21911710957568,"Lat":34.3306763095054}, {"Lng":115.33036232125529,"Lat":55.232930158541052}]
    138                 string[] splitItems = httpContext.Split(new string[] { "[", "},{", "]" }, StringSplitOptions.RemoveEmptyEntries);
    139 
    140                 if (splitItems.Length < items.Count)
    141                 {
    142                     logger.Warn("出现拆分出的lat,lng的组合长度不够" + items.Count + "!!!");
    143                 }
    144 
    145                 int itemsNumber = splitItems.Length;
    146                 if (splitItems.Length > items.Count)
    147                 {
    148                     itemsNumber = items.Count;
    149                 }
    150 
    151                 for (var i = 0; i < itemsNumber; i++)
    152                 {
    153                     string[] lngLat = splitItems[i].Split(new string[] { "{", "}", ""Lng":", ","Lat":" }, StringSplitOptions.RemoveEmptyEntries);
    154                     if (lngLat.Length != 2)
    155                     {
    156                         logger.Warn("出现" + splitItems[i] + "拆分出的lat,lng格式不正确!!!");
    157                     }
    158 
    159                     double lng = double.Parse(lngLat[0]);
    160                     double lat = double.Parse(lngLat[1]);
    161 
    162                     LatLngOffsetStruct item = items[i];
    163                     item.GpsLng = lng;
    164                     item.GpsLat = lat;
    165                     item.LatOffset = (item.GCJ02Lat - item.GpsLat).ToString();
    166                     item.LngOffset = (item.GCJ02Lng - item.GpsLng).ToString();
    167                 }
    168             }
    169             catch (Exception ex)
    170             {
    171                 if (cursor < 5)
    172                 {
    173                     goto GOTO_AGAIN;
    174                 }
    175 
    176                 logger.Error("DoOffset失败次数超过5次:
    {0}
    {1}", ex.Message, ex.StackTrace);
    177             }
    178         }
    179 
    180         static string GetRequesetContext(string requestUri, string parameter)
    181         {
    182             HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
    183             request.Method = "post";
    184             request.ContentType = "application/x-www-form-urlencoded";
    185 
    186             byte[] payload = System.Text.Encoding.UTF8.GetBytes(parameter);
    187             request.ContentLength = payload.Length;
    188 
    189             Stream writer;
    190             try
    191             {
    192                 writer = request.GetRequestStream();
    193             }
    194             catch (Exception)
    195             {
    196                 writer = null;
    197                 Console.Write("连接服务器失败!");
    198             }
    199 
    200             writer.Write(payload, 0, payload.Length);
    201             writer.Close();
    202 
    203             HttpWebResponse response;
    204             try
    205             {
    206                 response = (HttpWebResponse)request.GetResponse();
    207             }
    208             catch (WebException ex)
    209             {
    210                 response = ex.Response as HttpWebResponse;
    211             }
    212 
    213             string httpContext = string.Empty;
    214 
    215             using (Stream stream = response.GetResponseStream())
    216             {
    217                 using (StreamReader reader = new StreamReader(stream))
    218                 {
    219                     httpContext = reader.ReadToEnd();
    220                 }
    221             }
    222 
    223             response.Close();
    224 
    225             return httpContext;
    226         }
    227     }
    228 }
    View Code

    配置文件:

    <?xml version="1.0"?>
    <configuration>
      <configSections>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" restartOnExternalChanges="false" />
      </configSections>
      <appSettings>
        <!-- 
        double leftUpLng = 121.0127;
        double leftUpLat = 31.0850;
        double rightDownLng = 121.392234;
        double rightDownLat = 31.446334;
        A经纬度范围:东经120°55'至122°16',北纬28°51'至30°33'
        B经纬度范围:东经119°37′-121°18′、北纬27°03′-28°36′
        -->
        <add key="leftUpLng" value="120.54"/>
        <add key="leftUpLat" value="28.50"/>
        <add key="rightDownLng" value="122.17"/>
        <add key="rightDownLat" value="30.34"/>
        <!--【1.WGS -> GCJ】 【2.GCJ -> WGS】 【3.GCJ -> BD】 【4.BD -> GCJ】 【5.WGS -> BD】 【6.BD -> WGS】-->
        <add key="offsetType" value="2"/>
        <add key="fileWriteFilePath" value="D:\gcj02_offset_ningbo.csv"/>
        
      </appSettings>
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <targets>
          <target name="exceptionFile" type="File" fileName="${basedir}/Log/${shortdate}/${logger}_${level}.txt" layout="${longdate}|${level:uppercase=true}|${logger}${newline}${message}${newline}"/>
          <target name="console" xsi:type="ColoredConsole" layout="${date:format=HH:mm:ss}|${level}|${stacktrace}|${message}"/>
        </targets>
        <rules>
          <logger name="*" minlevel="Debug" writeTo="exceptionFile"/>
          <logger name="*" minlevel="Info" writeTo="console"/>
          <logger name="*" minlevel="Trace" writeTo="console"/>
          <logger name="*" minlevel="Fatal" writeTo="exceptionFile"/>
          <logger name="*" minlevel="Error" writeTo="exceptionFile"/>
          <logger name="*" minlevel="Warn" writeTo="exceptionFile"/>
        </rules>
      </nlog>
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
      </startup>
    </configuration>
    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');
  • 相关阅读:
    首页效果
    vue 资源精选
    webpack
    常用代码
    超炫效果
    TJ 大神 与 node
    fis webpack 原理对比
    前端自动化测试
    非常强的用户体验的网站功能
    蔡康永: 说话之道
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/7129239.html
Copyright © 2020-2023  润新知