iOS开发中的火星坐标系及各种坐标系转换算法
原文地址:http://m.oschina.net/blog/619183?ref=myread
其原理是这样的:保密局开发了一个系统,能将实际的坐标转换成虚拟的坐标。所有在中国销售的数字地图必须使用这个系统进行坐标转换之后方可上市。这是生产环节,这种电子地图被称为火星地图。在使用环节,GPS终端设备必须集成保密局提供的加密算法(集成工作由保密局完成),把从GPS卫星那里得到的坐标转换成虚拟坐标,然后再去火星地图上查找,这样就在火星坐标系上完成了地图的匹配。 所以大家所用的百度,高德等地图定位准是偏差几百米
名词总结:
地球坐标:指WGS84坐标系统
火星坐标:指使用国家保密插件人为偏移后的坐标
地球地图:指与地球坐标对应的客观真实的地图
火星地图:指经过加密偏移后的,与火星坐标对应的地图
坐标系转换算法
1.GCJ-02(火星坐标系)和BD-09转换
- // GCJ-02 坐标转换成 BD-09 坐标
- + (CLLocationCoordinate2D)MarsGS2BaiduGS:(CLLocationCoordinate2D)coordinate
- {
- double x_pi = PI * 3000.0 / 180.0;
- double x = coordinate.longitude, y = coordinate.latitude;
- double z = sqrt(x * x + y * y) + 0.00002 * sin(y * x_pi);
- double theta = atan2(y, x) + 0.000003 * cos(x * x_pi);
- double bd_lon = z * cos(theta) + 0.0065;
- double bd_lat = z * sin(theta) + 0.006;
- return CLLocationCoordinate2DMake(bd_lat, bd_lon);
- }
- // BD-09 坐标转换成 GCJ-02 坐标
- + (CLLocationCoordinate2D)BaiduGS2MarsGS:(CLLocationCoordinate2D)coordinate
- {
- double x_pi = PI * 3000.0 / 180.0;
- double x = coordinate.longitude - 0.0065, y = coordinate.latitude - 0.006;
- double z = sqrt(x * x + y * y) - 0.00002 * sin(y * x_pi);
- double theta = atan2(y, x) - 0.000003 * cos(x * x_pi);
- double gg_lon = z * cos(theta);
- double gg_lat = z * sin(theta);
- return CLLocationCoordinate2DMake(gg_lat, gg_lon);
- }
2WGS-84(地球坐标系)和BD-09(百度坐标)转换
- // WGS-84 坐标转换成 BD-09 坐标
- + (CLLocationCoordinate2D)WorldGS2BaiduGS:(CLLocationCoordinate2D)coordinate
- {
- CLLocationCoordinate2D mars = [ALDGeocoder WorldGS2MarsGS:coordinate];
- CLLocationCoordinate2D baidu = [ALDGeocoder MarsGS2BaiduGS:mars];
- return baidu;
- }
- // BD-09 坐标转换成 WGS-84 坐标
- + (CLLocationCoordinate2D)BaiduGS2WorldGS:(CLLocationCoordinate2D)coordinate
- {
- CLLocationCoordinate2D mars = [ALDGeocoder BaiduGS2MarsGS:coordinate];
- CLLocationCoordinate2D world = [ALDGeocoder MarsGS2WorldGS:mars];
- return world;
- }
3.WGS-84和sogou坐标转换
- // WGS-84 坐标转换成 Sogou 坐标
- + (CLLocationCoordinate2D)WorldGS2SogouGS:(CLLocationCoordinate2D)coordinate
- {
- const double ee = 0.082271854224939184;
- double lon = coordinate.longitude;
- double lat = coordinate.latitude;
- double dlon = [ALDGeocoder rad:CLIP(lon, -360, 360)];
- double dlat = [ALDGeocoder rad:CLIP(lat, -90, 90)];
- dlon = 6378206.4 * dlon;
- double sinphi = sin(dlat);
- double temp1, temp2;
- if((temp1 = 1.0 + sinphi) == 0.0){
- dlat = -1000000000;
- }else if((temp2 = 1.0 - sinphi) == 0.0){
- dlat = 1000000000;
- }else{
- double esinphi = ee * sinphi;
- dlat = 3189103.2000000002 * log((temp1 / temp2) * pow((1.0 - esinphi) / (1.0 + esinphi), ee));
- }
- return CLLocationCoordinate2DMake(dlat, dlon);
- }
- // Sogou 坐标转换成 WGS-84 坐标
- + (CLLocationCoordinate2D)SogouGS2WorldGS:(CLLocationCoordinate2D)coordinate
- {
- const double ee = 1.5707963267948966;
- const double aa = 0.0033938814110493522;
- double lon = coordinate.longitude;
- double lat = coordinate.latitude;
- double dlon = lon / 6378206.4;
- double temp = -lat / 6378206.4;
- double chi;
- if(temp < -307){
- chi = ee;
- }else if(temp > 308){
- chi = -ee;
- }else{
- chi = ee - 2 * atan(exp(temp));
- }
- double chi2 = 2 * chi;
- double coschi2 = cos(chi2);
- double dlat = chi + sin(chi2) * (aa + coschi2 * (1.3437644537757259E-005 + coschi2 * (7.2964865099246009E-008 + coschi2 * 4.4551470401894685E-010)));
- double rlon = CLIP([ALDGeocoder deg:dlon], -360, 360);
- double rlat = CLIP([ALDGeocoder deg:dlat], -90, 90);
- return CLLocationCoordinate2DMake(rlat, rlon);
- }
4火星坐标和地球坐标转换
- // World Geodetic System ==> Mars Geodetic System
- + (CLLocationCoordinate2D)WorldGS2MarsGS:(CLLocationCoordinate2D)coordinate
- {
- // a = 6378245.0, 1/f = 298.3
- // b = a * (1 - f)
- // ee = (a^2 - b^2) / a^2;
- const double a = 6378245.0;
- const double ee = 0.00669342162296594323;
- if (outOfChina(coordinate.latitude, coordinate.longitude))
- {
- return coordinate;
- }
- double wgLat = coordinate.latitude;
- double wgLon = coordinate.longitude;
- double dLat = transformLat(wgLon - 105.0, wgLat - 35.0);
- double dLon = transformLon(wgLon - 105.0, wgLat - 35.0);
- double radLat = wgLat / 180.0 * PI;
- double magic = sin(radLat);
- magic = 1 - ee * magic * magic;
- double sqrtMagic = sqrt(magic);
- dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
- dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * PI);
- return CLLocationCoordinate2DMake(wgLat + dLat, wgLon + dLon);
- }
- // Mars Geodetic System ==> World Geodetic System
- + (CLLocationCoordinate2D)MarsGS2WorldGS:(CLLocationCoordinate2D)coordinate
- {
- double gLat = coordinate.latitude;
- double gLon = coordinate.longitude;
- CLLocationCoordinate2D marsCoor = [ALDGeocoder WorldGS2MarsGS:coordinate];
- double dLat = marsCoor.latitude - gLat;
- double dLon = marsCoor.longitude - gLon;
- return CLLocationCoordinate2DMake(gLat - dLat, gLon - dLon);
- }
5WGS-84 和 墨卡托 坐标转换
- //WGS-84 坐标转换成 墨卡托 坐标
- + (CLLocationCoordinate2D)WorldGS2Mercator:(CLLocationCoordinate2D)coordinate
- {
- double lon = coordinate.longitude*20037508.34/180;
- double lat = log(tan((90+coordinate.latitude)*M_PI/360))/(M_PI/180);
- lat = lat*20037508.34/180;
- return CLLocationCoordinate2DMake(lat, lon);
- }
- //墨卡托 坐标转换成 WGS-84 坐标
- + (CLLocationCoordinate2D)Mercator2WorldGS:(CLLocationCoordinate2D)mercator
- {
- double lon = mercator.longitude/20037508.34*180;
- double lat = mercator.latitude/20037508.34*180;
- lat = 180/M_PI*(2*atan(exp(lat*M_PI/180))-M_PI/2);
- return CLLocationCoordinate2DMake(lat, lon);
- }
开发时所面临的现状
获取经纬度(GPS)
火星坐标
MKMapView
地球坐标
CLLocationManager
显示经纬度(地图)
火星坐标
iOS 地图
Gogole地图
搜搜、阿里云、高德地图
地球坐标
Google 卫星地图(国外地图应该都是……)
百度坐标
百度地图
推荐的解决方案:
既然是在国内,存储一律用火星坐标,这样在使用国内地图显示时最方便(用百度地图显示时可以一次转换取得)
CLLocationManager 拿到的 CLLocation 转为火星坐标,MKMapView 不用处理
使用地图 API 进行 地址解析/逆地址解析(Geocoding) 时注意相应使用相应地图商的坐标系
部分地图商支持多个坐标系输入,如高德支持地球、火星坐标(这个一直有变动,具体只能参考厂商最新文档了
iOS开发中的火星坐标系及各种坐标系转换算法的更多相关文章
- [转]iOS开发中的火星坐标系及各种坐标系转换算法
iOS开发中的火星坐标系及各种坐标系转换算法 源:https://my.oschina.net/u/2607703/blog/619183 其原理是这样的:保密局开发了一个系统,能将实际的坐标转 ...
- IOS开发中与设计沟通之字体大小转换
px:相对长度单位.像素(Pixel).pt:绝对长度单位.点(Point).1in = 2.54cm = 25.4 mm = 72pt = 6pc 具体换算是: Points Pixels Ems ...
- iOS开发中关于UIImage的知识点总结
UIImage是iOS中层级比较高的一个用来加载和绘制图像的一个类,更底层的类还有 CGImage,以及iOS5.0以后新增加的CIImage.今天我们主要聊一聊UIImage的三个属性: image ...
- IOS开发中的CGFloat、CGPoint、CGSize和CGRect
IOS开发中的CGFloat.CGPoint.CGSize和CGRect http://developer.apple.com/library/ios/#documentation/GraphicsI ...
- 总结iOS开发中的断点续传那些事儿
前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...
- iOS开发中静态库之".framework静态库"的制作及使用篇
iOS开发中静态库之".framework静态库"的制作及使用篇 .framework静态库支持OC和swift .a静态库如何制作可参照上一篇: iOS开发中静态库之" ...
- iOS开发中静态库制作 之.a静态库制作及使用篇
iOS开发中静态库之".a静态库"的制作及使用篇 一.库的简介 1.什么是库? 库是程序代码的集合,是共享程序代码的一种方式 2.库的类型? 根据源代码的公开情况,库可以分为2种类 ...
- ios开发中的小技巧
在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...
- IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法
在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...
随机推荐
- CentOS 7.0关闭默认firewall防火墙启用iptables防火墙
操作系统环境:CentOS Linux release 7.0.1406(Core) 64位CentOS 7.0默认使用的是firewall作为防火墙,这里改为iptables防火墙步骤. 1.关闭f ...
- 【Java】Swing中JTextPane中如何绘制行号
Oracle在JTextPane类中并没有直接提供显示行号的方法,所以这个功能应该由程序员自己来完成,笔者发现网上很多的显示行号的代码都存在一个问题,就是不准确,特别是在行数变多了以后. 笔者先贴出代 ...
- 【jsp】JSP中page指令isThreadSafe
<%@ page isThreadSafe="true|false" %> 默认值为true isThreadSafe=false模式表示它是以Singleton模式运 ...
- Charles 网络抓包工具
1.Charles 简介 Charles 是在 Mac.Linux 或 Windows 下常用的 http 协议网络包截取工具,在平常的测试与调式过程中,掌握此工具就基本可以不用其他抓包工具了.Cha ...
- 【C语言】练习1-23
题目来源:<The C programming language>中的习题 练习1-23: 写一个删除C语言程序中所有的注释语句.要正确处理带引号的字符串与字符常量.在C语言中,注释不 ...
- MySQL -- 外键创建失败
使用show engine innodb status\G 查看数据库状态的时候,发现以下报错信息: ------------------------ LATEST FOREIGN KEY ERROR ...
- C++中没有finally,那么应该在哪里关闭资源?
这是一篇有趣的帖子 原文链接: http://bbs.csdn.net/topics/90070457 楼主: C++中没有finally,那么应该在哪里关闭资源? C++的try{}catch(){ ...
- 转:zTree树控件key配置之title:zTree树节点名称过长如何省略显示且鼠标移入节点上能够显示全称
当树节点的名称有些很长时,全部显示出来显得很拥挤的情况下,我们会想到用省略节点名称来代替,当鼠标移入节点时能够显示该节点的全称.这样我们应该如何做呢? 首先,我们要在树的节点内多增加一个属性用于设置该 ...
- SpringBoot actuator 应用监控。
前言 : 今天在阅读 <SpringCloud微服务实战>一书时看到了SpringBoot actuator相关知识,并且自己也本地调试实践.觉得SpringBoot这一套监控还是挺有意思 ...
- Ucloud的自主研发的检测主机是否被入侵的agent
wget --timeout 3 -t 2 http://download.uhostsec.service.ucloud.cn:8090/ucloud-secagent-install.sh -O ...