近来开发的项目涉及地图位置分享模块,android组的同事先开工,用的是百度地图sdk,本人后面开工,用的是iOS SDK的mapkit做,之后问题来了,同一个经纬度坐标在iOS端和Android端出现了比较大偏差。查了下资料苹果地图在大陆的数据源是高德的,查了下高德采用GCJ-02, 百度map sdk 采用的是BD-09,只好写了个类在发送和接收时做好转换,略微蛋疼。Github上有人写了一个现成的转换类,可以参考参考传送门 ,其主要代码见下:
头文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | #import <foundation foundation.h="">#import <corelocation corelocation.h="">@interface JZLocationConverter : NSObject/** * @brief 世界标准地理坐标(WGS-84) 转换成 中国国测局地理坐标(GCJ-02)<火星坐标> * * ####只在中国大陆的范围的坐标有效,以外直接返回世界标准坐标 * * @param location 世界标准地理坐标(WGS-84) * * @return 中国国测局地理坐标(GCJ-02)<火星坐标> */+ (CLLocationCoordinate2D)wgs84ToGcj02:(CLLocationCoordinate2D)location;/** * @brief 中国国测局地理坐标(GCJ-02) 转换成 世界标准地理坐标(WGS-84) * * ####此接口有1-2米左右的误差,需要精确定位情景慎用 * * @param location 中国国测局地理坐标(GCJ-02) * * @return 世界标准地理坐标(WGS-84) */+ (CLLocationCoordinate2D)gcj02ToWgs84:(CLLocationCoordinate2D)location;/** * @brief 世界标准地理坐标(WGS-84) 转换成 百度地理坐标(BD-09) * * @param location 世界标准地理坐标(WGS-84) * * @return 百度地理坐标(BD-09) */+ (CLLocationCoordinate2D)wgs84ToBd09:(CLLocationCoordinate2D)location;/** * @brief 中国国测局地理坐标(GCJ-02)<火星坐标> 转换成 百度地理坐标(BD-09) * * @param location 中国国测局地理坐标(GCJ-02)<火星坐标> * * @return 百度地理坐标(BD-09) */+ (CLLocationCoordinate2D)gcj02ToBd09:(CLLocationCoordinate2D)location;/** * @brief 百度地理坐标(BD-09) 转换成 中国国测局地理坐标(GCJ-02)<火星坐标> * * @param location 百度地理坐标(BD-09) * * @return 中国国测局地理坐标(GCJ-02)<火星坐标> */+ (CLLocationCoordinate2D)bd09ToGcj02:(CLLocationCoordinate2D)location;/** * @brief 百度地理坐标(BD-09) 转换成 世界标准地理坐标(WGS-84) * * ####此接口有1-2米左右的误差,需要精确定位情景慎用 * * @param location 百度地理坐标(BD-09) * * @return 世界标准地理坐标(WGS-84) */+ (CLLocationCoordinate2D)bd09ToWgs84:(CLLocationCoordinate2D)location;@end</corelocation></foundation> |
实现文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #import JZLocationConverter.h#import <corelocation corelocation.h="">#define LAT_OFFSET_0(x,y) -100.0 +2.0 * x +3.0 * y + 0.2 * y * y +0.1 * x * y +0.2 * sqrt(fabs(x))#define LAT_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) +20.0 * sin(2.0 * x * M_PI)) *2.0 /3.0#define LAT_OFFSET_2 (20.0 * sin(y * M_PI) +40.0 * sin(y /3.0 * M_PI)) *2.0 / 3.0#define LAT_OFFSET_3 (160.0 * sin(y /12.0 * M_PI) +320 * sin(y * M_PI /30.0)) *2.0 /3.0#define LON_OFFSET_0(x,y)300.0 + x + 2.0 * y +0.1 * x * x +0.1 * x * y +0.1 * sqrt(fabs(x))#define LON_OFFSET_1 (20.0 * sin(6.0 * x * M_PI) +20.0 * sin(2.0 * x * M_PI)) *2.0 /3.0#define LON_OFFSET_2 (20.0 * sin(x * M_PI) +40.0 * sin(x /3.0 * M_PI)) *2.0 / 3.0#define LON_OFFSET_3 (150.0 * sin(x /12.0 * M_PI) +300.0 * sin(x /30.0 * M_PI)) * 2.0 /3.0#define RANGE_LON_MAX137.8347#define RANGE_LON_MIN72.004#define RANGE_LAT_MAX55.8271#define RANGE_LAT_MIN0.8293// jzA = 6378245.0, 1/f = 298.3// b = a * (1 - f)// ee = (a^2 - b^2) / a^2;#define jzA6378245.0#define jzEE0.00669342162296594323@implementation JZLocationConverter+ (double)transformLat:(double)x bdLon:(double)y{ double ret = LAT_OFFSET_0(x, y); ret += LAT_OFFSET_1; ret += LAT_OFFSET_2; ret += LAT_OFFSET_3; return ret;}+ (double)transformLon:(double)x bdLon:(double)y{ double ret = LON_OFFSET_0(x, y); ret += LON_OFFSET_1; ret += LON_OFFSET_2; ret += LON_OFFSET_3; return ret;}+ (BOOL)outOfChina:(double)lat bdLon:(double)lon{ if (lon < RANGE_LON_MIN || lon > RANGE_LON_MAX) return true; if (lat < RANGE_LAT_MIN || lat > RANGE_LAT_MAX) return true; return false;}+ (CLLocationCoordinate2D)gcj02Encrypt:(double)ggLat bdLon:(double)ggLon{ CLLocationCoordinate2D resPoint; double mgLat; double mgLon; if ([self outOfChina:ggLat bdLon:ggLon]) { resPoint.latitude = ggLat; resPoint.longitude = ggLon; return resPoint; } double dLat = [self transformLat:(ggLon -105.0)bdLon:(ggLat -35.0)]; double dLon = [self transformLon:(ggLon -105.0) bdLon:(ggLat -35.0)]; double radLat = ggLat /180.0 * M_PI; double magic = sin(radLat); magic =1 - jzEE * magic * magic; double sqrtMagic = sqrt(magic); dLat = (dLat *180.0) / ((jzA * (1 - jzEE)) / (magic * sqrtMagic) * M_PI); dLon = (dLon *180.0) / (jzA / sqrtMagic * cos(radLat) * M_PI); mgLat = ggLat + dLat; mgLon = ggLon + dLon; resPoint.latitude = mgLat; resPoint.longitude = mgLon; return resPoint;}+ (CLLocationCoordinate2D)gcj02Decrypt:(double)gjLat gjLon:(double)gjLon { CLLocationCoordinate2D gPt = [self gcj02Encrypt:gjLat bdLon:gjLon]; double dLon = gPt.longitude - gjLon; double dLat = gPt.latitude - gjLat; CLLocationCoordinate2D pt; pt.latitude = gjLat - dLat; pt.longitude = gjLon - dLon; return pt;}+ (CLLocationCoordinate2D)bd09Decrypt:(double)bdLat bdLon:(double)bdLon{ CLLocationCoordinate2D gcjPt; double x = bdLon -0.0065, y = bdLat -0.006; double z = sqrt(x * x + y * y) -0.00002 * sin(y * M_PI); double theta = atan2(y, x) -0.000003 * cos(x * M_PI); gcjPt.longitude = z * cos(theta); gcjPt.latitude = z * sin(theta); return gcjPt;}+(CLLocationCoordinate2D)bd09Encrypt:(double)ggLat bdLon:(double)ggLon{ CLLocationCoordinate2D bdPt; double x = ggLon, y = ggLat; double z = sqrt(x * x + y * y) +0.00002 * sin(y * M_PI); double theta = atan2(y, x) +0.000003 * cos(x * M_PI); bdPt.longitude = z * cos(theta) +0.0065; bdPt.latitude = z * sin(theta) +0.006; return bdPt;}+ (CLLocationCoordinate2D)wgs84ToGcj02:(CLLocationCoordinate2D)location{ return [self gcj02Encrypt:location.latitude bdLon:location.longitude];}+ (CLLocationCoordinate2D)gcj02ToWgs84:(CLLocationCoordinate2D)location{ return [self gcj02Decrypt:location.latitude gjLon:location.longitude];}+ (CLLocationCoordinate2D)wgs84ToBd09:(CLLocationCoordinate2D)location{ CLLocationCoordinate2D gcj02Pt = [self gcj02Encrypt:location.latitude bdLon:location.longitude]; return [self bd09Encrypt:gcj02Pt.latitude bdLon:gcj02Pt.longitude] ;}+ (CLLocationCoordinate2D)gcj02ToBd09:(CLLocationCoordinate2D)location{ return [self bd09Encrypt:location.latitude bdLon:location.longitude];}+ (CLLocationCoordinate2D)bd09ToGcj02:(CLLocationCoordinate2D)location{ return [self bd09Decrypt:location.latitude bdLon:location.longitude];}+ (CLLocationCoordinate2D)bd09ToWgs84:(CLLocationCoordinate2D)location{ CLLocationCoordinate2D gcj02 = [self bd09ToGcj02:location]; return [self gcj02Decrypt:gcj02.latitude gjLon:gcj02.longitude];}@end</corelocation> |
测试用例:
1 2 3 4 5 6 7 | CLLocationCoordinate2D gcj02 = CLLocationCoordinate2DMake(114.21892734521,29.575429778924);CLLocationCoordinate2D bd09 = [JZLocationConverter gcj02ToBd09:gcj02];NSLog(@%f,%f, bd09.latitude, bd09.longitude);// JZLocationConverter 测试数据: 114.21892734521,29.575429778924 ; 转化结果: 114.224960,29.581853// 百度api 测试数据: 114.21892734521,29.575429778924 ; 百度api转换结果: 114.22539195429,29.581585367458 |
总体来说,存在一点偏差,但跟处理前的效果比一下,相对可以接受了些。