原文地址:http://m.oschina.net/blog/619183?ref=myread

其原理是这样的:保密局开发了一个系统,能将实际的坐标转换成虚拟的坐标。所有在中国销售的数字地图必须使用这个系统进行坐标转换之后方可上市。这是生产环节,这种电子地图被称为火星地图。在使用环节,GPS终端设备必须集成保密局提供的加密算法(集成工作由保密局完成),把从GPS卫星那里得到的坐标转换成虚拟坐标,然后再去火星地图上查找,这样就在火星坐标系上完成了地图的匹配。 所以大家所用的百度,高德等地图定位准是偏差几百米

名词总结:

地球坐标:指WGS84坐标系统

火星坐标:指使用国家保密插件人为偏移后的坐标
地球地图:指与地球坐标对应的客观真实的地图
火星地图:指经过加密偏移后的,与火星坐标对应的地图

坐标系转换算法

1.GCJ-02(火星坐标系)和BD-09转换

  1. // GCJ-02 坐标转换成 BD-09 坐标
  2. + (CLLocationCoordinate2D)MarsGS2BaiduGS:(CLLocationCoordinate2D)coordinate
  3. {
  4. double x_pi = PI * 3000.0 / 180.0;
  5. double x = coordinate.longitude, y = coordinate.latitude;
  6. double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
  7. double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);
  8. double bd_lon = z * cos(theta) + 0.0065;
  9. double bd_lat = z * sin(theta) + 0.006;
  10. return CLLocationCoordinate2DMake(bd_lat, bd_lon);
  11. }
  12. // BD-09 坐标转换成 GCJ-02 坐标
  13. + (CLLocationCoordinate2D)BaiduGS2MarsGS:(CLLocationCoordinate2D)coordinate
  14. {
  15. double x_pi = PI * 3000.0 / 180.0;
  16. double x = coordinate.longitude - 0.0065, y = coordinate.latitude - 0.006;
  17. double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);
  18. double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);
  19. double gg_lon = z * cos(theta);
  20. double gg_lat = z * sin(theta);
  21. return CLLocationCoordinate2DMake(gg_lat, gg_lon);
  22. }

2WGS-84(地球坐标系)和BD-09(百度坐标)转换

  1. // WGS-84 坐标转换成 BD-09 坐标
  2. + (CLLocationCoordinate2D)WorldGS2BaiduGS:(CLLocationCoordinate2D)coordinate
  3. {
  4. CLLocationCoordinate2D mars = [ALDGeocoder WorldGS2MarsGS:coordinate];
  5. CLLocationCoordinate2D baidu = [ALDGeocoder MarsGS2BaiduGS:mars];
  6. return baidu;
  7. }
  8. // BD-09 坐标转换成 WGS-84 坐标
  9. + (CLLocationCoordinate2D)BaiduGS2WorldGS:(CLLocationCoordinate2D)coordinate
  10. {
  11. CLLocationCoordinate2D mars = [ALDGeocoder BaiduGS2MarsGS:coordinate];
  12. CLLocationCoordinate2D world = [ALDGeocoder MarsGS2WorldGS:mars];
  13. return world;
  14. }

3.WGS-84和sogou坐标转换

  1. // WGS-84 坐标转换成 Sogou 坐标
  2. + (CLLocationCoordinate2D)WorldGS2SogouGS:(CLLocationCoordinate2D)coordinate
  3. {
  4. const double ee = 0.082271854224939184;
  5. double lon = coordinate.longitude;
  6. double lat = coordinate.latitude;
  7. double dlon = [ALDGeocoder rad:CLIP(lon, -360, 360)];
  8. double dlat = [ALDGeocoder rad:CLIP(lat, -90, 90)];
  9. dlon = 6378206.4 * dlon;
  10. double sinphi = sin(dlat);
  11. double temp1, temp2;
  12. if((temp1 = 1.0 + sinphi) == 0.0){
  13. dlat = -1000000000;
  14. }else if((temp2 = 1.0 - sinphi) == 0.0){
  15. dlat = 1000000000;
  16. }else{
  17. double esinphi = ee * sinphi;
  18. dlat = 3189103.2000000002 * log((temp1 / temp2) * pow((1.0 - esinphi) / (1.0 + esinphi), ee));
  19. }
  20. return CLLocationCoordinate2DMake(dlat, dlon);
  21. }
  22. // Sogou 坐标转换成 WGS-84 坐标
  23. + (CLLocationCoordinate2D)SogouGS2WorldGS:(CLLocationCoordinate2D)coordinate
  24. {
  25. const double ee = 1.5707963267948966;
  26. const double aa = 0.0033938814110493522;
  27. double lon = coordinate.longitude;
  28. double lat = coordinate.latitude;
  29. double dlon = lon / 6378206.4;
  30. double temp = -lat / 6378206.4;
  31. double chi;
  32. if(temp < -307){
  33. chi = ee;
  34. }else if(temp > 308){
  35. chi = -ee;
  36. }else{
  37. chi = ee - 2 * atan(exp(temp));
  38. }
  39. double chi2 = 2 * chi;
  40. double coschi2 = cos(chi2);
  41. double dlat = chi + sin(chi2) * (aa + coschi2 * (1.3437644537757259E-005 + coschi2 * (7.2964865099246009E-008 + coschi2 * 4.4551470401894685E-010)));
  42. double rlon = CLIP([ALDGeocoder deg:dlon], -360, 360);
  43. double rlat = CLIP([ALDGeocoder deg:dlat], -90, 90);
  44. return CLLocationCoordinate2DMake(rlat, rlon);
  45. }

4火星坐标和地球坐标转换

  1. // World Geodetic System ==> Mars Geodetic System
  2. + (CLLocationCoordinate2D)WorldGS2MarsGS:(CLLocationCoordinate2D)coordinate
  3. {
  4. // a = 6378245.0, 1/f = 298.3
  5. // b = a * (1 - f)
  6. // ee = (a^2 - b^2) / a^2;
  7. const double a = 6378245.0;
  8. const double ee = 0.00669342162296594323;
  9. if (outOfChina(coordinate.latitude, coordinate.longitude))
  10. {
  11. return coordinate;
  12. }
  13. double wgLat = coordinate.latitude;
  14. double wgLon = coordinate.longitude;
  15. double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
  16. double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
  17. double radLat = wgLat / 180.0 * PI;
  18. double magic = sin(radLat);
  19. magic = 1 - ee * magic * magic;
  20. double sqrtMagic = sqrt(magic);
  21. dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
  22. dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * PI);
  23. return CLLocationCoordinate2DMake(wgLat + dLat, wgLon + dLon);
  24. }
  25. // Mars Geodetic System ==> World Geodetic System
  26. + (CLLocationCoordinate2D)MarsGS2WorldGS:(CLLocationCoordinate2D)coordinate
  27. {
  28. double gLat = coordinate.latitude;
  29. double gLon = coordinate.longitude;
  30. CLLocationCoordinate2D marsCoor = [ALDGeocoder WorldGS2MarsGS:coordinate];
  31. double dLat = marsCoor.latitude - gLat;
  32. double dLon = marsCoor.longitude - gLon;
  33. return CLLocationCoordinate2DMake(gLat - dLat, gLon - dLon);
  34. }

5WGS-84 和 墨卡托 坐标转换

  1. //WGS-84 坐标转换成 墨卡托 坐标
  2. + (CLLocationCoordinate2D)WorldGS2Mercator:(CLLocationCoordinate2D)coordinate
  3. {
  4. double lon = coordinate.longitude*20037508.34/180;
  5. double lat = log(tan((90+coordinate.latitude)*M_PI/360))/(M_PI/180);
  6. lat = lat*20037508.34/180;
  7. return CLLocationCoordinate2DMake(lat, lon);
  8. }
  9. //墨卡托 坐标转换成 WGS-84 坐标
  10. + (CLLocationCoordinate2D)Mercator2WorldGS:(CLLocationCoordinate2D)mercator
  11. {
  12. double lon = mercator.longitude/20037508.34*180;
  13. double lat = mercator.latitude/20037508.34*180;
  14. lat = 180/M_PI*(2*atan(exp(lat*M_PI/180))-M_PI/2);
  15. return CLLocationCoordinate2DMake(lat, lon);
  16. }

开发时所面临的现状

获取经纬度(GPS)

  • 火星坐标

    • MKMapView

  • 地球坐标

    • CLLocationManager

显示经纬度(地图)

  • 火星坐标

    • iOS 地图

    • Gogole地图

    • 搜搜、阿里云、高德地图

  • 地球坐标

    • Google 卫星地图(国外地图应该都是……)

  • 百度坐标

    • 百度地图

推荐的解决方案:

    • 既然是在国内,存储一律用火星坐标,这样在使用国内地图显示时最方便(用百度地图显示时可以一次转换取得)

    • CLLocationManager 拿到的 CLLocation 转为火星坐标,MKMapView 不用处理

    • 使用地图 API 进行 地址解析/逆地址解析(Geocoding) 时注意相应使用相应地图商的坐标系

    • 部分地图商支持多个坐标系输入,如高德支持地球、火星坐标(这个一直有变动,具体只能参考厂商最新文档了

iOS开发中的火星坐标系及各种坐标系转换算法的更多相关文章

  1. [转]iOS开发中的火星坐标系及各种坐标系转换算法

     iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183   其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...

  2. IOS开发中与设计沟通之字体大小转换

    px:相对长度单位.像素(Pixel).pt:绝对长度单位.点(Point).1in = 2.54cm = 25.4 mm = 72pt = 6pc 具体换算是: Points Pixels Ems ...

  3. iOS开发中关于UIImage的知识点总结

    UIImage是iOS中层级比较高的一个用来加载和绘制图像的一个类,更底层的类还有 CGImage,以及iOS5.0以后新增加的CIImage.今天我们主要聊一聊UIImage的三个属性: image ...

  4. IOS开发中的CGFloat、CGPoint、CGSize和CGRect

    IOS开发中的CGFloat.CGPoint.CGSize和CGRect http://developer.apple.com/library/ios/#documentation/GraphicsI ...

  5. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  6. iOS开发中静态库之".framework静态库"的制作及使用篇

    iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...

  7. iOS开发中静态库制作 之.a静态库制作及使用篇

    iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...

  8. ios开发中的小技巧

    在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...

  9. IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法

    在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...

随机推荐

  1. Java8 lambda表达式10个示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Ja ...

  2. 【Oracle】Oracle约束的总结

    你对ORACLE约束的了解如何?比较模糊还是相当透彻?如果你对下面几个问题了如指掌的话,恭喜你,你已经对约束掌握得比较好了,不用看这篇文章了.ORACLE的约束有啥功能作用? 有哪些类型约束(不同版本 ...

  3. 使用SQL Server发送邮件时遇到的诡异事件

    最近公司要实现一个邮件群发的功能,因此设计时就考虑用SQL Server的邮件发送功能直接推送邮件算了. 可是在实现的过程中,邮件内容中有一个表格的内容要展现,于是就编排了一个表格来实现. 具体实现如 ...

  4. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  5. Easyui combobox 始终选择第一个的问题

    //必须指定 id 和 text $('#contact_city').combobox({ valueField:'id', textField:'text', });

  6. nodejs的Express框架源码分析、工作流程分析

    nodejs的Express框架源码分析.工作流程分析 1.Express的编写流程 2.Express关键api的使用及其作用分析 app.use(middleware); connect pack ...

  7. Java Nashorn--Part 4

    Nashorn 和 javax.script 包 Nashorn 并不是第一个在 Java 平台上运行的脚本语言.在Java 6 就提供了 javax.script java 包,它为脚本语言引擎提供 ...

  8. mysql 主从同步遇到的问题(1032)

    event_scheduler对主从的影响: 1 对于已经存在的主从, 新建立events没有影响. 2 对于新建立的主从,如果有events ,那么需要在从库上把event_scheduler设置为 ...

  9. Install OpenCV3.0 on Eclipse

     Neste artigo veremos como usar o OpenCV com Eclipse. Usaremos as versões mais recentes:OpenCV 3.0 ...

  10. jqgrid 设置为每行单选

    jqgrid 不支持单选,自己自带了多选multiselect 那么单选怎么做呢,可以参考如下配置 multiselect: true, multiboxonly:true, gridComplete ...