iOS7上地球坐标系到火星坐标系转换算法


2013年01月31日 ⁄ 综合 ⁄ 共 2595字 ⁄ 字号    ⁄ 评论关闭html

今天在一个项目中须要用到地球坐标系到火星坐标系的转换,找了好几种实现方法,但都没法在iOS6以上的系统中使用,最后找到了一个C#的转换算法,对照着写了一个iOS版的,在这里分享给你们。git

地球坐标和火星坐标的具体含义能够见:http://blog.sina.com.cn/s/blog_7581a4c301015230.html算法

目前网上的方法主要有如下几种:数据库

1.在iOS4.3以前的系统上经过私有类MKLocationManager中的_applyChinaLocationShift来转换地球坐标到火星坐标。这种方法有两个问题,一个是调用了私有api,另外一个是在iOS5以后的系统不能用了。api

2.利用MKMapView中的isShowUserLocation进行定位,这种方法也有两个问题,一个是必需要建立MKMapView才行,二是没法实现后台定位。app

3.利用MapABC API中的GPSToOffSetByPoint:方法进行坐标转换,本人并无对这种方法进行尝试,由于实现起来比较麻烦,还得申请API Key。spa

4.对地球坐标系与火星坐标系创建一一映射关系,并将这个关系存到数据库中,经过数据库进行转换。这种方法的问题是数据库体积较大,不适用于移动客户端程序.net

5.利用高德、百度地图提供的在线api进行转换,这种方法的问题是不能离线进行转换,实用性不强。code

6.利用已有的算法将地球坐标系转换到火星坐标系orm

本人最后采用的是第六种方法,参考的C#算法连接以下:https://on4wp7.codeplex.com/SourceControl/changeset/view/21483#353936

转换获得的OC代码以下:

const double a = 6378245.0;
const double ee = 0.00669342162296594323;

+ (CLLocation *)transformToMars:(CLLocation *)location {
    //是否在中国大陆以外
    if ([[self class] outOfChina:location]) {
        return location;
    }
    double dLat = [[self class] transformLatWithX:location.coordinate.longitude - 105.0 y:location.coordinate.latitude - 35.0];
    double dLon = [[self class] transformLonWithX:location.coordinate.longitude - 105.0 y:location.coordinate.latitude - 35.0];
    double radLat = location.coordinate.latitude / 180.0 * M_PI;
    double magic = sin(radLat);
    magic = 1 - ee * magic * magic;
    double sqrtMagic = sqrt(magic);
    dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * M_PI);
    dLon = (dLon * 180.0) / (a / sqrtMagic * cos(radLat) * M_PI);
    return [[CLLocation alloc] initWithLatitude:location.coordinate.latitude + dLat longitude:location.coordinate.longitude + dLon];
}

+ (BOOL)outOfChina:(CLLocation *)location {
    if (location.coordinate.longitude < 72.004 || location.coordinate.longitude > 137.8347) {
        return YES;
    }
    if (location.coordinate.latitude < 0.8293 || location.coordinate.latitude > 55.8271) {
        return YES;
    }
    return NO;
}

+ (double)transformLatWithX:(double)x y:(double)y {
    double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(abs(x));
    ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
    ret += (20.0 * sin(y * M_PI) + 40.0 * sin(y / 3.0 * M_PI)) * 2.0 / 3.0;
    ret += (160.0 * sin(y / 12.0 * M_PI) + 320 * sin(y * M_PI / 30.0)) * 2.0 / 3.0;
    return ret;
}

+ (double)transformLonWithX:(double)x y:(double)y {
    double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(abs(x));
    ret += (20.0 * sin(6.0 * x * M_PI) + 20.0 * sin(2.0 * x * M_PI)) * 2.0 / 3.0;
    ret += (20.0 * sin(x * M_PI) + 40.0 * sin(x / 3.0 * M_PI)) * 2.0 / 3.0;
    ret += (150.0 * sin(x / 12.0 * M_PI) + 300.0 * sin(x / 30.0 * M_PI)) * 2.0 / 3.0;
    return ret;
}

将以上代码放到任意一个类中,使用静态方法transformToMars:对地球坐标进行转换便可。

如下为最后转换的结果:

mapkit获得的坐标:40.006498, 116.328022
CLLocationManager获得的坐标:40.005196, 116.321890
算法转换出来的坐标:40.006500, 116.328023

由以上结果能够看出该算法的精度比较高,偏差在10米以内。

若是你们以为对本身有帮助的话,还但愿能帮顶一下,谢谢:)

我的博客:http://blog.csdn.net/zhaoxy2850

本文地址:http://blog.csdn.net/zhaoxy_thu/article/details/17033347

转载请注明出处,谢谢!

相关文章
相关标签/搜索