GPS、百度地圖恋沃、高德地圖經(jīng)緯度坐標的轉換

常用地圖坐標系介紹:

WGS-84:是國際標準必搞,GPS坐標(Google Earth使用、或者GPS模塊)
GCJ-02:中國坐標偏移標準囊咏,Google地圖恕洲、高德塔橡、騰訊使用
BD-09 :百度坐標偏移標準,Baidu地圖使用
我們經(jīng)常在常用的這幾種地圖中進行坐標轉換霜第,或用于第三方地圖的導航葛家,或用于后臺下發(fā)地址的打點等等場景。雖然百度和高德都提供相應的api泌类,但是他們都只提供向自家坐標系轉化的api癞谒,需要連網(wǎng)請求才能得到轉化后的結果。(前提還得申請他們開放平臺的appKey)

#import <Foundation/Foundation.h>

@interface YQLocationTransform : NSObject

@property (nonatomic, assign) double latitude;
@property (nonatomic, assign) double longitude;

- (id)initWithLatitude:(double)latitude andLongitude:(double)longitude;

/*
   坐標系:
     WGS-84:是國際標準刃榨,GPS坐標(Google Earth使用弹砚、或者GPS模塊)
     GCJ-02:中國坐標偏移標準,Google Map枢希、高德桌吃、騰訊使用
     BD-09 :百度坐標偏移標準,Baidu Map使用
 */

#pragma mark - 從GPS坐標轉化到高德坐標
- (id)transformFromGPSToGD;

#pragma mark - 從高德坐標轉化到百度坐標
- (id)transformFromGDToBD;

#pragma mark - 從百度坐標到高德坐標
- (id)transformFromBDToGD;

#pragma mark - 從高德坐標到GPS坐標
- (id)transformFromGDToGPS;

#pragma mark - 從百度坐標到GPS坐標
- (id)transformFromBDToGPS;

@end
YQLocationTransform.m文件
#import "YQLocationTransform.h"
#import <CoreLocation/CoreLocation.h>

static const double a = 6378245.0;
static const double ee = 0.00669342162296594323;
static const double pi = M_PI;
static const double xPi = M_PI  * 3000.0 / 180.0;

@implementation YQLocationTransform

- (id)initWithLatitude:(double)latitude andLongitude:(double)longitude {
    if (self = [super init]) {
        self.latitude = latitude;
        self.longitude = longitude;
    }
    return self;
}

- (id)transformFromGPSToGD {
    CLLocationCoordinate2D coor = [ECLocationTransform transformFromWGSToGCJ:CLLocationCoordinate2DMake(self.latitude, self.longitude)];
    return [[ECLocationTransform alloc] initWithLatitude:coor.latitude andLongitude:coor.longitude];
}

- (id)transformFromGDToBD {
    CLLocationCoordinate2D coor = [ECLocationTransform transformFromGCJToBaidu:CLLocationCoordinate2DMake(self.latitude, self.longitude)];
    return [[ECLocationTransform alloc] initWithLatitude:coor.latitude andLongitude:coor.longitude];
}

- (id)transformFromBDToGD {
    CLLocationCoordinate2D coor = [ECLocationTransform transformFromBaiduToGCJ:CLLocationCoordinate2DMake(self.latitude, self.longitude)];
    return [[ECLocationTransform alloc] initWithLatitude:coor.latitude andLongitude:coor.longitude];
}

- (id)transformFromGDToGPS {
    CLLocationCoordinate2D coor = [ECLocationTransform transformFromGCJToWGS:CLLocationCoordinate2DMake(self.latitude, self.longitude)];
    return [[ECLocationTransform alloc] initWithLatitude:coor.latitude andLongitude:coor.longitude];
}

- (id)transformFromBDToGPS {
    //先把百度轉化為高德
    CLLocationCoordinate2D start_coor = [ECLocationTransform transformFromBaiduToGCJ:CLLocationCoordinate2DMake(self.latitude, self.longitude)];
    CLLocationCoordinate2D end_coor = [ECLocationTransform transformFromGCJToWGS:CLLocationCoordinate2DMake(start_coor.latitude, start_coor.longitude)];
    return [[ECLocationTransform alloc] initWithLatitude:end_coor.latitude andLongitude:end_coor.longitude];
}

+ (CLLocationCoordinate2D)transformFromWGSToGCJ:(CLLocationCoordinate2D)wgsLoc {
    CLLocationCoordinate2D adjustLoc;
    if([self isLocationOutOfChina:wgsLoc]) {
        adjustLoc = wgsLoc;
    }
    else {
        double adjustLat = [self transformLatWithX:wgsLoc.longitude - 105.0 withY:wgsLoc.latitude - 35.0];
        double adjustLon = [self transformLonWithX:wgsLoc.longitude - 105.0 withY:wgsLoc.latitude - 35.0];
        long double radLat = wgsLoc.latitude / 180.0 * pi;
        long double magic = sin(radLat);
        magic = 1 - ee * magic * magic;
        long double sqrtMagic = sqrt(magic);
        adjustLat = (adjustLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
        adjustLon = (adjustLon * 180.0) / (a / sqrtMagic * cos(radLat) * pi);
        adjustLoc.latitude = wgsLoc.latitude + adjustLat;
        adjustLoc.longitude = wgsLoc.longitude + adjustLon;
    }
    return adjustLoc;
}

+ (double)transformLatWithX:(double)x withY:(double)y {
    double lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x));

    lat += (20.0 * sin(6.0 * x * pi) + 20.0 *sin(2.0 * x * pi)) * 2.0 / 3.0;
    lat += (20.0 * sin(y * pi) + 40.0 * sin(y / 3.0 * pi)) * 2.0 / 3.0;
    lat += (160.0 * sin(y / 12.0 * pi) + 320 * sin(y * pi / 30.0)) * 2.0 / 3.0;
    return lat;
}

+ (double)transformLonWithX:(double)x withY:(double)y {
    double lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x));
    lon += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
    lon += (20.0 * sin(x * pi) + 40.0 * sin(x / 3.0 * pi)) * 2.0 / 3.0;
    lon += (150.0 * sin(x / 12.0 * pi) + 300.0 * sin(x / 30.0 * pi)) * 2.0 / 3.0;
    return lon;
}

+ (CLLocationCoordinate2D)transformFromGCJToBaidu:(CLLocationCoordinate2D)p {
    long double z = sqrt(p.longitude * p.longitude + p.latitude * p.latitude) + 0.00002 * sqrt(p.latitude * pi);
    long double theta = atan2(p.latitude, p.longitude) + 0.000003 * cos(p.longitude * pi);
    CLLocationCoordinate2D geoPoint;
    geoPoint.latitude  = (z * sin(theta) + 0.006);
    geoPoint.longitude = (z * cos(theta) + 0.0065);
    return geoPoint;
}

+ (CLLocationCoordinate2D)transformFromBaiduToGCJ:(CLLocationCoordinate2D)p {
    double x = p.longitude - 0.0065, y = p.latitude - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * xPi);
    double theta = atan2(y, x) - 0.000003 * cos(x * xPi);
    CLLocationCoordinate2D geoPoint;
    geoPoint.latitude  = z * sin(theta);
    geoPoint.longitude = z * cos(theta);
    return geoPoint;
}

+ (CLLocationCoordinate2D)transformFromGCJToWGS:(CLLocationCoordinate2D)p {
    double threshold = 0.00001;

    // The boundary
    double minLat = p.latitude - 0.5;
    double maxLat = p.latitude + 0.5;
    double minLng = p.longitude - 0.5;
    double maxLng = p.longitude + 0.5;

    double delta = 1;
    int maxIteration = 30;
    // Binary search
    while(true) {
        CLLocationCoordinate2D leftBottom  = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = minLat,.longitude = minLng}];
        CLLocationCoordinate2D rightBottom = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = minLat,.longitude = maxLng}];
        CLLocationCoordinate2D leftUp      = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = maxLat,.longitude = minLng}];
        CLLocationCoordinate2D midPoint    = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = ((minLat + maxLat) / 2),.longitude = ((minLng + maxLng) / 2)}];
        delta = fabs(midPoint.latitude - p.latitude) + fabs(midPoint.longitude - p.longitude);

        if(maxIteration-- <= 0 || delta <= threshold) {
            return (CLLocationCoordinate2D){.latitude = ((minLat + maxLat) / 2),.longitude = ((minLng + maxLng) / 2)};
        }

        if(isContains(p, leftBottom, midPoint)) {
            maxLat = (minLat + maxLat) / 2;
            maxLng = (minLng + maxLng) / 2;
        } else if(isContains(p, rightBottom, midPoint)) {
            maxLat = (minLat + maxLat) / 2;
            minLng = (minLng + maxLng) / 2;
        } else if(isContains(p, leftUp, midPoint)) {
            minLat = (minLat + maxLat) / 2;
            maxLng = (minLng + maxLng) / 2;
        } else {
            minLat = (minLat + maxLat) / 2;
            minLng = (minLng + maxLng) / 2;
        }
    }

}

#pragma mark - 判斷某個點point是否在p1和p2之間
static bool isContains(CLLocationCoordinate2D point, CLLocationCoordinate2D p1, CLLocationCoordinate2D p2) {
    return (point.latitude >= MIN(p1.latitude, p2.latitude) && point.latitude <= MAX(p1.latitude, p2.latitude)) && (point.longitude >= MIN(p1.longitude,p2.longitude) && point.longitude <= MAX(p1.longitude, p2.longitude));
}

#pragma mark - 判斷是不是在中國
+ (BOOL)isLocationOutOfChina:(CLLocationCoordinate2D)location {
    if (location.longitude < 72.004 || location.longitude > 137.8347 || location.latitude < 0.8293 || location.latitude > 55.8271)
        return YES;
    return NO;
}

@end

用法如下:

YQLocationTransform *beforeLocation = [[YQLocationTransform alloc] initWithLatitude:22.549522 andLongitude:113.947933];
//百度轉化為GPS
YQLocationTransform *afterLocation = [beforeLocation transformFromBDToGPS];
NSLog(@"轉化后:%f, %f", afterLocation.latitude, afterLocation.longitude);
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末苞轿,一起剝皮案震驚了整個濱河市茅诱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搬卒,老刑警劉巖让簿,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異秀睛,居然都是意外死亡尔当,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門蹂安,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椭迎,“玉大人,你說我怎么就攤上這事田盈⌒蠛牛” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵允瞧,是天一觀的道長简软。 經(jīng)常有香客問我,道長述暂,這世上最難降的妖魔是什么痹升? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮畦韭,結果婚禮上疼蛾,老公的妹妹穿的比我還像新娘。我一直安慰自己艺配,他們只是感情好察郁,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布衍慎。 她就那樣靜靜地躺著,像睡著了一般皮钠。 火紅的嫁衣襯著肌膚如雪稳捆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天麦轰,我揣著相機與錄音眷柔,去河邊找鬼。 笑死原朝,一個胖子當著我的面吹牛驯嘱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播喳坠,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼鞠评,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了壕鹉?” 一聲冷哼從身側響起剃幌,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晾浴,沒想到半個月后负乡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡脊凰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年抖棘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狸涌。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡切省,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帕胆,到底是詐尸還是另有隱情朝捆,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布懒豹,位于F島的核電站芙盘,受9級特大地震影響,放射性物質發(fā)生泄漏脸秽。R本人自食惡果不足惜儒老,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望豹储。 院中可真熱鬧贷盲,春花似錦淘这、人聲如沸剥扣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钠怯。三九已至佳魔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晦炊,已是汗流浹背鞠鲜。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留断国,地道東北人贤姆。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像稳衬,于是被迫代替她去往敵國和親霞捡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容