iOS 地图坐标转换

地图坐标转换

@(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左右.
posted @ 2019-05-19 16:16  struggle_time  阅读(173)  评论(0编辑  收藏  举报