iOS 根據(jù)兩個(gè)經(jīng)緯度計(jì)算與地理北極夾角

滴滴打車車輛轉(zhuǎn)彎的,歷史軌跡運(yùn)動(dòng)可能都需要這個(gè)功能吧.

頭幾天偶然看見了這個(gè)https://www.douban.com/group/topic/38478506/?author=1&start=0,作為程序員都身同感受吧,但是可惜沒找到下文,所以今天我們來完成這個(gè)功能

讓我指向像你

這是他的圖片

不想看我墨跡一些沒營養(yǎng)的下面有地址demo~~

實(shí)現(xiàn)思路

  • 1 不管手機(jī)怎么移動(dòng),我的紅心手將指向你,所以這應(yīng)該是一個(gè)指南針
  • 2 但是我不想指向北方,所以我們之間和北極應(yīng)該有個(gè)角度,找到這個(gè)角度,我就找到你了
  • 3 應(yīng)該還有個(gè)距離. 這個(gè)百度代碼很多~~~

好的,我們首先先做個(gè)指南針.

1.導(dǎo)入頭文件 #import <CoreLocation/CoreLocation.h>這個(gè)框架
簽好協(xié)議<CLLocationManagerDelegate>和私有屬性@property (nonatomic, strong) CLLocationManager *locationM;
2.然后懶加載

#pragma mark - 懶加載
- (CLLocationManager *)mgr
{
    if (!_mgr) {
        _mgr = [[CLLocationManager alloc] init];
    }
    return _mgr;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.mgr startUpdatingHeading];
}

3.實(shí)現(xiàn)協(xié)議

// 當(dāng)獲取到用戶方向時(shí)就會(huì)調(diào)用
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    /*
     magneticHeading 設(shè)備與磁北的相對(duì)角度
     trueHeading 設(shè)置與真北的相對(duì)角度, 必須和定位一起使用, iOS需要設(shè)置的位置來計(jì)算真北
     真北始終指向地理北極點(diǎn)
     */
    // 1.將獲取到的角度轉(zhuǎn)為弧度 = (角度 * π) / 180;
    CGFloat angle = newHeading.magneticHeading * M_PI / 180;
    // 2.旋轉(zhuǎn)圖片
    /*
     順時(shí)針 正
     逆時(shí)針 負(fù)數(shù)
     */
    // 因?yàn)槿绻麤]有動(dòng)畫的話旋轉(zhuǎn)的時(shí)候回出現(xiàn)卡頓的現(xiàn)象,為了更流暢,我們給它加個(gè)動(dòng)畫
    [UIView animateWithDuration:0.1 animations:^{
        // 旋轉(zhuǎn)圖片
        self.compasspointer.transform = CGAffineTransformMakeRotation(-a);
    }];
    
    
}

這個(gè)協(xié)議方法是一直調(diào)用的,不信你打印一下試試,所以最好不要在這里寫任何耗時(shí)的事,self.compasspointer是一個(gè)圖片,這里為了減少資源損耗就不畫圓了,用圖片是一樣的.

  1. 這樣就是一個(gè)正經(jīng)八經(jīng)的指南針了.下面只要求出來我們之間的角度,就完成了.

好的,我們找角度

1.根據(jù)百度的坐標(biāo)提取系統(tǒng)我們可以知道任意兩個(gè)點(diǎn)之間的坐標(biāo)
    //我在大連的
    float lat1 = 38.927431;
    float lng1 = 121.650592;
   // 這是北京(假設(shè)就是北京)往下一點(diǎn) 116.650592,38.927431
    float lat2 = 38.927431;
    float lng2 = 116.650592;
2. 求出兩個(gè)經(jīng)緯度之間的角度
//兩個(gè)經(jīng)緯度之間的角度
-(double)getBearingWithLat1:(double)lat1 whitLng1:(double)lng1 whitLat2:(double)lat2 whitLng2:(double)lng2{
    
    double d = 0;
    double radLat1 =  [self radian:lat1];
    double radLat2 =  [self radian:lat2];
    double radLng1 = [self radian:lng1];
    double radLng2 =  [self radian:lng2];
    d = sin(radLat1)*sin(radLat2)+cos(radLat1)*cos(radLat2)*cos(radLng2-radLng1);
    d = sqrt(1-d*d);
    d = cos(radLat2)*sin(radLng2-radLng1)/d;
    d = [self angle:asin(d)];
    return d;
}
//根據(jù)角度計(jì)算弧度
-(double)radian:(double)d{
    
    return d * M_PI/180.0;
}
//根據(jù)弧度計(jì)算角度
-(double)angle:(double)r{
    
    return r * 180/M_PI;
}

我們緯度是一樣的,根據(jù)上面的公式求出 北京 大連 北極之間的角度

角度
3 why? 口算都算出來了,應(yīng)該是九十度啊?這怎么事八十八度?還是負(fù)數(shù)?后來我百度了一下真北,磁北,坐標(biāo)北 ,我就不管這點(diǎn)誤差了,當(dāng)然這是可以處理的.

負(fù)數(shù)的問題,取個(gè)絕對(duì)值就好了,先不管這多為啥是負(fù)數(shù)
5231524215272_.pic.jpg

好了,變正數(shù)了,正數(shù)也可以一個(gè)人一個(gè)做法,不要吐槽我~

4 接下來為了驗(yàn)證正確性,我們把坐標(biāo)改成山東東營,
 //  獲取地理位置坐標(biāo)的代碼就不貼了,我在大連中山廣場(chǎng), 這是我的坐標(biāo) 121.650592,38.927431
    float lat1 = 38.927431;
    float lng1 = 121.650592;
   // 山東 東營
    float lat2 = 37.588364;
    float lng2 = 118.593547;

按地圖上來看角度應(yīng)該是一百多度吧,但是打印出來的結(jié)果是
2018-04-20 17:14:06.029517+0800 angle[3667:1273780] -61.798896
2018-04-20 17:14:06.029610+0800 angle[3667:1273780] 61.798896
所以我又寫了兩行代碼

if(lat2 < lat1){
        s = 180-s;
   }

這回打印結(jié)果
2018-04-20 17:14:06.029637+0800 angle[3667:1273780] 118.201104

好像對(duì)上
但是旋轉(zhuǎn)圖片的

        self.compasspointer.transform = CGAffineTransformMakeRotation(-a);

-a 是根據(jù)弧度計(jì)算的,值是0 到 2*π, 這個(gè)"我指向你的角度"就是 a弧度減去我求出來的角度

//宏定義
#define DEGREES_TO_RADIANS(angle) ( M_PI / 180 * (angle))

self.f =  DEGREES_TO_RADIANS(s);
    if (lng2 < lng1) {
        _f = (M_PI*2 - _f);
    }

打印出來2018-04-20 17:14:06.029687+0800 angle[3667:1273780] 4.220187

最后

// 當(dāng)獲取到用戶方向時(shí)就會(huì)調(diào)用
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    /*
     magneticHeading 設(shè)備與磁北的相對(duì)角度
     trueHeading 設(shè)置與真北的相對(duì)角度, 必須和定位一起使用, iOS需要設(shè)置的位置來計(jì)算真北
     真北始終指向地理北極點(diǎn)
     */
    // 1.將獲取到的角度轉(zhuǎn)為弧度 = (角度 * π) / 180;
    CGFloat angle = newHeading.magneticHeading * M_PI / 180;
    // 2.旋轉(zhuǎn)圖片
    /*
     順時(shí)針 正
     逆時(shí)針 負(fù)數(shù)
     */
    CGFloat a = 0;
    a = angle - _f;
    // 因?yàn)槿绻麤]有動(dòng)畫的話旋轉(zhuǎn)的時(shí)候回出現(xiàn)卡頓的現(xiàn)象,為了更流暢,我們給它加個(gè)動(dòng)畫
    [UIView animateWithDuration:0.1 animations:^{
        // 旋轉(zhuǎn)圖片
        self.compasspointer.transform = CGAffineTransformMakeRotation(-a);
    }];
    
    
}
效果圖
正北
北京

墨跡完了,我也不知道我做的對(duì)不對(duì),有問題一起探討
下面是項(xiàng)目地址

demo (記得用真機(jī))

Xcode9.3 以下打開會(huì)有問題???

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容