文档章节

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

刀客445
 刀客445
发布于 2016/02/23 11:25
字数 1165
阅读 1664
收藏 3

其原理是这样的:保密局开发了一个系统,能将实际的坐标转换成虚拟的坐标。所有在中国销售的数字地图必须使用这个系统进行坐标转换之后方可上市。这是生产环节,这种电子地图被称为火星地图。在使用环节,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) 时注意相应使用相应地图商的坐标系

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









© 著作权归作者所有

刀客445
粉丝 2
博文 47
码字总数 10222
作品 0
杭州
私信 提问
加载中

评论(1)

猫猫666
猫猫666
写得棒棒哒!博主,我们做了一个帮助博主推广博客的app叫同行说,只需复制文章链接即可发布给更多程序员同行们看到哦,欢迎体验哈,一起发扬分享精神~
iOS7上地球坐标系到火星坐标系转换算法

2013年01月31日 ⁄ 综合 ⁄ 共 2595字 ⁄ 字号 小 中 大 ⁄ 评论关闭 今天在一个项目中需要用到地球坐标系到火星坐标系的转换,找了好几种实现方法,但都无法在iOS6以上的系统中使用,最后找...

andyhe91
2014/11/07
1K
1
DLA新增函数发布:身份证、星座、拼音、Json数组、经纬度城市查询、互联网坐标系经纬度转换等

概述 本月,Data Lake Analytics(https://et.aliyun.com/bdad/datalake)发布了一批新增的内置函数,涉及身份证地域查询、星座查询、中文拼音转换、Json数组内容字段提取、经纬度城市查询、...

javainthinking
06/21
0
0
iOS地图上WGS84、GCJ-02、BD-09互转解决方案

iOS地图上WGS84、GCJ-02、BD-09互转解决方案 标签(空格分隔): 常用封装 名词解释 (地球坐标)WGS84 火星坐标(GCJ-02) 百度坐标(BD-09) 对于国内地图而言,使用LocationManager定位所获得经...

袁俊亮技术博客
2016/08/03
0
0
IOS 应用内打开三方地图app直接导航

简书 当然因为有需求喽。 疯狂试探 常用地图应用的url Scheme: 苹果地图不需要,iOS API提供了一个跳转打开方法。 注意IOS9之后,plist里面设置url scheme白名单 在下用的是高德坐标 高德转...

Apple_JinlongLu
2017/05/10
0
0
iOS 实现输入框跟随键盘自动上移

场景还原 有些时候在包含输入框的页面中,点击输入框输入会因键盘弹起而遮挡住一部分输入框,影响用户体验。iOS在默认情况下并不会处理这种问题,不过我们可以自己实现键盘弹起输入框自动上移...

还是不够辣
2017/04/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周六乱弹 —— 不要在领导修风扇的时候打开电扇

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @巴拉迪维 :《Whats Up》 主唱妹子 Lina Perry 的嗓音实在太有力了,收放自如的自信才能唱出这么优秀的歌吧!#今日歌曲推荐# 《Whats Up》-...

小小编辑
今天
7
0
SpringBoot集成Elasticsearch并进行增删改查操作

一、创建工程 使用IntelliJ创建SpringBoot工程 SpringBoot版本为2.0.4 ElasticSearch为5.6.10 删掉蓝框中的文件(如上) 最后我们的目录结构(如下) 下面pom文件主要修改的是把spring boot从Int...

一字见心
今天
5
0
x001-版本介绍

python版本介绍 目前有2 和 3 有很多企业用的代码是2版本,随着技术的发展,以后用3的会成为大趋势 python3的安装 yum -y install wget gcc zlib-devel bzip2-devel openssl-devel ncurses-d...

侠客行之石头
今天
5
0
聊聊rocketmq的TransientStorePool

序 本文主要研究一下rocketmq的TransientStorePool TransientStorePool rocketmq-all-4.6.0-source-release/store/src/main/java/org/apache/rocketmq/store/TransientStorePool.java publi......

go4it
昨天
6
0
笔记

场外借贷, 质押 ,托管, 永续合约. 场外借贷,n签合同. 新功能 证券交易组负责中信证券机构及个人投资交易相关系统,服务机构及个人投资客户, 涉及到两融、期权、 期货、做市等境内境外创新业...

MtrS
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部