地图坐标转换
@(iOS)[iOS, 地图]
简介
- 各地图API坐标系统比较与转换;
- WGS84坐标系:即地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系,
- 谷歌地图采用的是WGS84地理坐标系(中国范围除外);
- GCJ02坐标系:即火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。
- 谷歌中国地图和搜搜中国地图采用的是GCJ02地理坐标系; BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系;
- 搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。
自定义一个类来实现
#import <Foundation/Foundation.h>
@interface BaiduMapTransform : NSObject
/// 百度转火星坐标系
+ (NSString *)Gps_bd09_To_Gcj02Lat:(double )bd_lat lon:(double )bd_lon;
/// 火星转谷歌
+ (NSString *)Gps_gcj_To_Gps84Lat:(double )lat lon:(double )lon;
/// 百度转谷歌 (WGS84)
+ (NSString *)Gps_bd09_To_Gps84Lat:(double )bd_lat lon:(double )bd_lon;
@end
- 代码实现
#import "BaiduMapTransform.h"
#import <math.h>
const double a = 6378245.0;
const double ee = 0.00669342162296594323;
@implementation BaiduMapTransform
#pragma mark - 百度地图转换
/// 百度转火星坐标系
+ (NSString *)Gps_bd09_To_Gcj02Lat:(double )bd_lat lon:(double )bd_lon
{
double x = bd_lon - 0.0065, y = bd_lat - 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);
double gg_lon = z * cos(theta);
double gg_lat = z * sin(theta);
NSLog(@"火星gps %@", [NSString stringWithFormat:@"%lf,%lf",gg_lon,gg_lat]);
return [NSString stringWithFormat:@"%lf,%lf",gg_lat,gg_lon];
}
/// 火星转谷歌
+ (NSString *)Gps_gcj_To_Gps84Lat:(double )lat lon:(double )lon {
NSString *str = [self transform:lat lon:lon];
NSArray *gpsStr = [str componentsSeparatedByString:@","];
double lontitude = lon * 2 - [gpsStr[1] doubleValue];
double latitude = lat * 2 - [gpsStr[0] doubleValue];
NSLog(@"谷歌gps %@", [NSString stringWithFormat:@"%lf,%lf",lontitude,latitude]);
return [NSString stringWithFormat:@"%lf,%lf",latitude,lontitude];
}
/// 百度转谷歌(WGS84)
+ (NSString *)Gps_bd09_To_Gps84Lat:(double )bd_lat lon:(double )bd_lon {
NSString *gcj02 = [self Gps_bd09_To_Gcj02Lat:bd_lat lon:bd_lon];
NSArray *gpsStr = [gcj02 componentsSeparatedByString:@","];
NSString *map84 = [self Gps_gcj_To_Gps84Lat:[gpsStr[0] doubleValue] lon:[gpsStr[1] doubleValue]];
// NSLog(@"谷歌gps %@", [NSString stringWithFormat:@"%lf,%lf",lontitude,latitude]);
return map84;
}
// 下面都是一些固定算法
+ (double)transformLatX:(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(fabs(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) transformLonX:(double)x y:(double)y {
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
* sqrt(fabs(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;
}
+ (BOOL)outOfChina:(double )lat lon:(double )lon {
if (lon < 72.004 || lon > 137.8347)
return true;
if (lat < 0.8293 || lat > 55.8271)
return true;
return false;
}
+ (NSString *)transform:(double )lat lon:(double )lon {
if ( [self outOfChina:lat lon:lon]) {
return [NSString stringWithFormat:@"%lf,%lf",lat,lon];
}
double dLat = [self transformLatX:(lon-105.0) y:(lat-35.0)];
double dLon = [self transformLonX:(lon-105.0) y:(lat-35.0)];
// double dLat = transformLatX(lon - 105.0, lat - 35.0);
// double dLon = transformLonX(lon - 105.0, lat - 35.0);
double radLat = lat / 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);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return [NSString stringWithFormat:@"%lf,%lf",mgLat,mgLon];
}
@end
精度测试
-
首先通过百度获取当前地址
百度 113.151028,23.037077
-
然后直接转成谷歌,也就是
WGS84
,中间会先转成火星坐标系,再转成谷歌火星 113.144468,23.031382
谷歌 113.139012,23.033961
-
测试网站
总结
- 项目中用到百度地图,而服务端需要标准地图的话,可以很方便的进行转换。
- 而且转换结果还是相当精确的,目前测试的误差,保守估计10m左右.