在这个神奇的国度里,我们总得学习一些有中国特色的东东,例如“火星坐标”。也许有人还不知道这是什么玩意,我就简要介绍一下吧。      如果你有带GPS模块的智能手机,打开定位功能,然后访问Google地图。只要你身处中国大陆,你就会发现定位不准,大概有几百米的偏差。然而运行一些导航软件,你又会发现定位很准确,说明手机的GPS模块确实是正常的。      这种现象是怎么造成的呢?答案是人为造成的。简单来说,GPS模块获取到的坐标是WGS84坐标系的,中国政府出于种种目的的考虑,不允许中国的地图使用国际通用的WGS84坐标系,而非要加上一些偏移,这样的坐标系就俗称“火星坐标系”。而Google地图采用的也是加偏移过的火星坐标系,但GPS模块传给它的坐标却没有加偏移,于是就出现几百米的偏差了。这样的后果就是没法做需要很高精度的地理位置的应用了,就像那个悲剧的Google地图一样,你迷路时无法指望它告诉你正确的位置。      经过不懈的努力, 终于发现一位牛人用C语言写了一个算法, 不过他要用到一个数据文件, 而且比较大, 放在手机客户端一跑就内存崩溃了, 所以觉得不可取, 于是把他的C代码转化为C#的WebService服务. 代码如下, 供大家参考.希望对大家有所帮助!

C#代码  
  1. class Program
  2. {
  3. const double M_PI = 3.14159265358979323846264338327950288;
  4. const double M_E = 2.71828182845904523536028747135266250;
  5. public class MapCoord
  6. {
  7. public int lng { set; get; }    //12151表示121.51
  8. public int lat { set; get; }    //3130表示31.30
  9. public int x_off { set; get; }  //地图x轴偏移像素值
  10. public int y_off { set; get; }  //地图y轴偏移像素值
  11. }
  12. /// <summary>
  13. /// 自定义比较类
  14. /// </summary>
  15. public class myReverserClass : IComparer
  16. {
  17. public int Compare(object x, object y)
  18. {
  19. MapCoord data1 = (MapCoord)x, data2 = (MapCoord)y;
  20. int det_lng = data1.lng - data2.lng;
  21. if (det_lng != 0)
  22. return det_lng;
  23. else
  24. return data1.lat - data2.lat;
  25. }
  26. }
  27. //这就需要一个把经纬度转换成地图xy轴坐标的算法:
  28. private static double lngToPixel(double lng, int zoom)
  29. {
  30. return (lng + 180) * (256L << zoom) / 360;
  31. }
  32. private static double latToPixel(double lat, int zoom)
  33. {
  34. double siny = Math.Sin(lat * M_PI / 180);
  35. double y = Math.Log((1 + siny) / (1 - siny));
  36. return (128 << zoom) * (1 - y / (2 * M_PI));
  37. }
  38. //xy轴坐标加上对应的地图xy轴的偏移量,最后还要反过来将最终正确的地图xy轴坐标转换成正确的经纬度
  39. private static double pixelToLng(double pixelX, int zoom)
  40. {
  41. return pixelX * 360 / (256L << zoom) - 180;
  42. }
  43. private static double pixelToLat(double pixelY, int zoom)
  44. {
  45. double y = 2 * M_PI * (1 - pixelY / (128 << zoom));
  46. double z = Math.Pow(M_E, y);
  47. double siny = (z - 1) / (z + 1);
  48. return Math.Asin(siny) * 180 / M_PI;
  49. }
  50. /// <summary>
  51. /// 将字节转化为具体的数据对象
  52. /// </summary>
  53. /// <param name="buf"></param>
  54. /// <returns></returns>
  55. private static MapCoord getMapCoordFromBytes(byte[] buf)
  56. {
  57. //数据文档结构是八字节为一个坐标及其偏移量,分别为经度,纬度,x偏移量,y偏移量; 每两字节为一个数据
  58. MapCoord coord = new MapCoord();
  59. byte[] b1 = new byte[2], b2 = new byte[2], b3 = new byte[2], b4 = new byte[2];
  60. Array.Copy(buf, 0, b1, 0, 2);
  61. Array.Copy(buf, 2, b2, 0, 2);
  62. Array.Copy(buf, 4, b3, 0, 2);
  63. Array.Copy(buf, 6, b4, 0, 2);
  64. coord.lng = System.BitConverter.ToInt16(b1, 0);
  65. coord.lat = System.BitConverter.ToInt16(b2, 0);
  66. coord.x_off = System.BitConverter.ToInt16(b3, 0);
  67. coord.y_off = System.BitConverter.ToInt16(b4, 0);
  68. return coord;
  69. }
  70. /// <summary>
  71. /// WGS84(GPS)坐标转火星坐标
  72. /// </summary>
  73. /// <param name="lat">纬度</param>
  74. /// <param name="lng">经度</param>
  75. public static void WGS2Mars(double lat, double lng)
  76. {
  77. //读取数据文件
  78. //这里读取文件的地方可以单独提出来, 读一次之后保存到内存里, 读取时比较耗时间. 或者放到数据库中去.
  79. FileStream fs = new FileStream("offset.dat", FileMode.OpenOrCreate, FileAccess.Read);
  80. BinaryReader br = new BinaryReader(fs);
  81. int size = (int)fs.Length / 8;
  82. ArrayList array = new ArrayList();
  83. for (int i = 0; i < size; i ++)
  84. {
  85. //按八个字节八个字节来读取, 放在MapCoord对象中,并添加到ArrayList中
  86. byte[] source = br.ReadBytes(8);
  87. array.Add(getMapCoordFromBytes(source));
  88. }
  89. br.Close();
  90. fs.Close();
  91. //将要查找的坐标放置在MapCoord对象中
  92. MapCoord search = new MapCoord();
  93. search.lat = (int)(lat * 100);
  94. search.lng = (int)(lng * 100);
  95. myReverserClass rc = new myReverserClass();
  96. //执行查找, 查询结果将返回array中的索引值
  97. int x = array.BinarySearch(0, array.Count, search, rc);
  98. //取得查找到的结果并进行计算
  99. MapCoord ret = (MapCoord)array[x];
  100. double pixY = latToPixel(lat, 18);
  101. double pixX = lngToPixel(lng, 18);
  102. pixY += ret.y_off;
  103. pixX += ret.x_off;
  104. lat = pixelToLat(pixY, 18);
  105. lng = pixelToLng(pixX, 18);
  106. //输出校正后的结果
  107. Console.WriteLine("欢迎来到火星,坐标: lat:{0},lng:{1} !!!", lat, lng);
  108. }
  109. static void Main(string[] args)
  110. {
  111. //测试一下
  112. WGS2Mars(30.283780,120.116356);
  113. Console.ReadLine();
  114. }
  115. }
class Program
{
const double M_PI = 3.14159265358979323846264338327950288;
const double M_E = 2.71828182845904523536028747135266250;public class MapCoord
{public int lng { set; get; }    //12151表示121.51public int lat { set; get; }    //3130表示31.30public int x_off { set; get; }  //地图x轴偏移像素值public int y_off { set; get; }  //地图y轴偏移像素值
}/// <summary>
/// 自定义比较类
/// </summary>
public class myReverserClass : IComparer
{public int Compare(object x, object y){MapCoord data1 = (MapCoord)x, data2 = (MapCoord)y;int det_lng = data1.lng - data2.lng;if (det_lng != 0)return det_lng;elsereturn data1.lat - data2.lat;}
}//这就需要一个把经纬度转换成地图xy轴坐标的算法:private static double lngToPixel(double lng, int zoom)
{return (lng + 180) * (256L << zoom) / 360;
}private static double latToPixel(double lat, int zoom)
{double siny = Math.Sin(lat * M_PI / 180);double y = Math.Log((1 + siny) / (1 - siny));return (128 << zoom) * (1 - y / (2 * M_PI));
}//xy轴坐标加上对应的地图xy轴的偏移量,最后还要反过来将最终正确的地图xy轴坐标转换成正确的经纬度
private static double pixelToLng(double pixelX, int zoom)
{return pixelX * 360 / (256L << zoom) - 180;
}private static double pixelToLat(double pixelY, int zoom)
{double y = 2 * M_PI * (1 - pixelY / (128 << zoom));double z = Math.Pow(M_E, y);double siny = (z - 1) / (z + 1);return Math.Asin(siny) * 180 / M_PI;
}/// <summary>
/// 将字节转化为具体的数据对象
/// </summary>
/// <param name="buf"></param>
/// <returns></returns>
private static MapCoord getMapCoordFromBytes(byte[] buf)
{//数据文档结构是八字节为一个坐标及其偏移量,分别为经度,纬度,x偏移量,y偏移量; 每两字节为一个数据MapCoord coord = new MapCoord();byte[] b1 = new byte[2], b2 = new byte[2], b3 = new byte[2], b4 = new byte[2];Array.Copy(buf, 0, b1, 0, 2);Array.Copy(buf, 2, b2, 0, 2);Array.Copy(buf, 4, b3, 0, 2);Array.Copy(buf, 6, b4, 0, 2);coord.lng = System.BitConverter.ToInt16(b1, 0);coord.lat = System.BitConverter.ToInt16(b2, 0);coord.x_off = System.BitConverter.ToInt16(b3, 0);coord.y_off = System.BitConverter.ToInt16(b4, 0);return coord;
}/// <summary>
/// WGS84(GPS)坐标转火星坐标
/// </summary>
/// <param name="lat">纬度</param>
/// <param name="lng">经度</param>
public static void WGS2Mars(double lat, double lng)
{//读取数据文件//这里读取文件的地方可以单独提出来, 读一次之后保存到内存里, 读取时比较耗时间. 或者放到数据库中去.FileStream fs = new FileStream("offset.dat", FileMode.OpenOrCreate, FileAccess.Read);BinaryReader br = new BinaryReader(fs);int size = (int)fs.Length / 8;ArrayList array = new ArrayList();for (int i = 0; i < size; i ++){//按八个字节八个字节来读取, 放在MapCoord对象中,并添加到ArrayList中byte[] source = br.ReadBytes(8);array.Add(getMapCoordFromBytes(source));}br.Close();fs.Close();//将要查找的坐标放置在MapCoord对象中MapCoord search = new MapCoord();search.lat = (int)(lat * 100);search.lng = (int)(lng * 100);myReverserClass rc = new myReverserClass();//执行查找, 查询结果将返回array中的索引值int x = array.BinarySearch(0, array.Count, search, rc);//取得查找到的结果并进行计算MapCoord ret = (MapCoord)array[x];double pixY = latToPixel(lat, 18);double pixX = lngToPixel(lng, 18);pixY += ret.y_off;pixX += ret.x_off;lat = pixelToLat(pixY, 18);lng = pixelToLng(pixX, 18);//输出校正后的结果Console.WriteLine("欢迎来到火星,坐标: lat:{0},lng:{1} !!!", lat, lng);
}static void Main(string[] args)
{//测试一下WGS2Mars(30.283780,120.116356);Console.ReadLine();
}}

OK,大功告成,火星人民欢迎您!!

参考资料: 原C语言帖   http://xcodev.com/wordpress/?p=131

原文地址: http://freshflower.iteye.com/blog/1606960

  • offset.rar (2 MB)

转载于:https://www.cnblogs.com/lovewx/p/4146906.html

IOS中GPS定位偏移纠正(适用于Google地图)相关推荐

  1. GPS纠偏算法,适用于google,高德体系的地图

    GPS纠偏算法,适用于google,高德体系的地图,精确度还比较高.我试了一下比高德本身的纠偏还精确点. /*** gps纠偏算法,适用于google,高德体系的地图* @author Adminis ...

  2. LBS位置服务中GPS定位、基站定位、wifi定位的区别

    1.卫星定位 其原理是接收机接收卫星广播,通过解析可见卫星的位置.距离等信息以及相应算法得出自己的位置信息,误差在15米范围内,当前可视卫星数量将影响定位精度,可见卫星数量越多,精度越高,实际测试中在 ...

  3. android 百度坐标 gps,Android中gps定位不返回经纬度的解决方案

    定位,算是android应用中一个非常常见的功能了吧,并且大部分的应用里基本也都会用到地图,所以以前的做法基本都是直接接入了百度.高德这些第三方定位,也没遇到过什么问题. 然而,最近的工作基本上都是做 ...

  4. U880纯GPS定位综合解决方案,支持谷歌地图老虎地图百度地图

    一,背景篇 1. 在天国,我们都是不需要谷歌服务的,所有的国行都是没有谷歌服务的.但有太多的机油觉得也许天国之外的东西不一定坏,所以我们需要谷歌服务包(GMS). 我的第一个安卓机是摩托的里程碑,水货 ...

  5. 中国区GPS偏移纠正(适用于Google地图)

    在做iOS开发时,用到一个获取当前位置周边商家的功能.当时每次我在获取从iPhone里GPS返回过来的数据到Google Place API上获取时总是发现,获取的商家并不是最近的,而是几百米以外的. ...

  6. android app gps 定位权限,uniapp 打开[ios/安卓]GPS定位权限

    如何检测GPS有没有开启我是写在高德地图API接口中fail函数里的 openGps(){ let system = uni.getSystemInfoSync();// 获取系统信息 if (sys ...

  7. 在ios中fixed定位元素丢失,Date兼容NaN

    Aphorism Preface 差不多有半年没有更新blog了, 现在在新的公司适应了,最近喜得一千金,也慢慢适应了新的生活. 今天更新一篇关于最近遇到的 ios fixed定位元素丢失 bug i ...

  8. IOS将GPS定位经纬度转换为高德地图经纬度

    https://github.com/JackZhouCn/JZLocationConverter http://www.eoeandroid.com/forum.php?mod=viewthread ...

  9. uniapp | 打开iOS和Android实现GPS定位权限

    原来真的有人,删掉手机里所有的娱乐软件,不管不顾任何东西,没日没夜的学习,就只是为了回到原来那个眼里有光被赋予希望的自己. 你要坚信每一个你想学习的念头,都是未来在向你求救! 懒惰是一个特别奇怪的东西 ...

最新文章

  1. C# Trim 的使用
  2. 【POJ】3268 Silver Cow Party (将有向图的边反转)
  3. NOIP2011 提高组 Day1
  4. Google 发布浏览器3D插件 O3D API
  5. C++ Primer 5th笔记(9)chapter9 顺序容器 get insert delete
  6. JQUERY设置或返回属性值attr
  7. php mysql 云虚拟机_虚拟机+apache+php+mysql 环境安装配置
  8. jQuery入门:认识jQuery
  9. springboot 统一异常处理
  10. linux 进入shell命令,linux或者shell进入vi命令
  11. cocos2dx[3.2](21)——观察者模式NotificationCenter
  12. bzoj1997 [Hnoi2010]Planar——2-SAT
  13. 数据+人工智能+模型——北京市新一代交通仿真模型框架
  14. 那些一出口就很Low的话
  15. mysql 查询活跃人数_查询活跃用户的数量SQL
  16. Intel VT学习笔记(八)—— 开启EPT
  17. 无人驾驶车辆纵向速度PID控制
  18. 数字货币&区块链动态
  19. C语言结构体变量 指针以及对结构体成员的访问
  20. java gis地图开发视频_开源GIS视频教程

热门文章

  1. UIGestureRecognizer手势介绍
  2. (0028)iOS 开发之Xcode使用技巧
  3. 一张图搞定iOS学习路线
  4. linux 超级权限图标,Linux下使用iconv库出错,急!!!
  5. oracle建表权限问题和JSP连接oracle数据库基本操作
  6. Ubuntu15.04 网站服务器环境搭建,php/html/css等学习环境搭建教程
  7. .NET学习之Foreach……
  8. 【原创】BI解决方案选型之ETL数据整合工具对比
  9. hadoop过程中遇到的错误与解决方法
  10. 解决ssh登录linux速度慢的问题(以centos7为例)