你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS開發:GPS糾偏

iOS開發:GPS糾偏

編輯:IOS開發基礎
  • 為什麼要糾偏?

    GCJ-02是由中國國家測繪局制訂的地理信息系統的坐標系統。
    它是一種對經緯度數據的加密算法,即加入隨機的偏差。
    國內出版的各種地圖系統(包括電子形式),必須至少采用GCJ-02對地理位置進行首次加密。

簡而言之就是WGS-84坐標系是GPS定位獲得的真實經緯度,GCJ-02坐標系是中國因國防需要在WGS-84基礎上進行過加密的坐標系,兩者存在隨機偏差;由GPS獲得的經緯度並不能適用於國內的地圖。

  • 糾偏方式?
    其實就是利用iOS自帶的地圖定位獲得GCJ-02坐標系。測試過網上流傳的坐標轉換算法,結果該怎麼偏還是怎麼偏,換了個方位偏而已。

上代碼
首先要在info.plist文件中添加定位問詢
Key:

//允許App運行期間定位
Privacy - Location When In Use Usage Description
//允許一直定位
Privacy - Location Always Usage Description

Value:

如果要適配iOS10,Value必須非空,否則會crash;只適配iOS8-9允許為空

地圖和定位要用到的庫

#import #import

設置代理

@interface LocationViewController ()
{
    MKMapView *_mapView;//全局地圖對象
}
//定位服務的入口點,設置成屬性
@property(nonatomic,strong)CLLocationManager *locationManager;

@property(nonatomic,copy)NSString *latitude;//緯度
@property(nonatomic,copy)NSString *longitude;//經度
- (void)viewDidLoad {
    [super viewDidLoad];
    //判斷是否開啟定位服務,GPS傳感器是否可用
    if ([CLLocationManager locationServicesEnabled]) {//是否開啟定位服務
        if ([CLLocationManager headingAvailable]) {//傳感器是否可用
            self.locationManager=[[CLLocationManager alloc] init];
            self.locationManager.delegate=self;
            self.locationManager.desiredAccuracy=kCLLocationAccuracyBest;//最高精度
            self.locationManager.headingFilter=kCLHeadingFilterNone;//設置濾波器不工作(過濾器用於過濾更新信號,默認為1,這裡我們使其不工作,即接受所有更新信號,達到最精准模式)

            //iOS8以後加入了問詢用戶是否開啟定位權限,這裡需要判斷操作系統版本,如果要兼容iOS7及以下,需要自己判斷版本
            if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
                [self.locationManager requestWhenInUseAuthorization];
            }
            else {
                NSLog(@"版本不匹配");
            }
        }
        else {
            NSLog(@"傳感器不可用");
        }
    }
    else {
        UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"未開啟定位服務"
                                                      message:@"請至設置-隱私-定位服務中開啟定位服務"
                                                     delegate:self
                                            cancelButtonTitle:@"確定"
                                            otherButtonTitles:nil, nil];
        [alert setAlertViewStyle:UIAlertViewStyleDefault];
        [alert show];
    }

    //初始化地圖,如果只想獲得坐標不要地圖,可以將frame設置在視圖外,初始化後隱藏
    _mapView=[[MKMapView alloc] init];
    _mapView.frame=CGRectMake(0, 0, self.view.frame.size.width, height/3);
    _mapView.delegate=self;
    _mapView.mapType=MKMapTypeStandard;//地圖標准模式
    _mapView.showsUserLocation=YES;//顯示當前位置
    _mapView.userTrackingMode=MKUserTrackingModeFollow;//跟隨
    [self.view addSubview:_mapView];
//    _mapView.hidden=YES;
}

開始定位需要用調用startUpdatingLocation,結束定位需要調用stopUpdatingLocation,可以自己選擇何時開始/結束定位。

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];    //開始定位
    [self.locationManager startUpdatingLocation];
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];    //停止定位
    [self.locationManager stopUpdatingLocation];
}
//默認點擊地圖當前位置的藍點只會顯示"當前位置"四個字,如果要顯示當前地址需要設置藍點的title,不想顯示地圖的可以不用實現這個代理方法
#pragma mark MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
    //當前的坐標,反編碼
    CLGeocoder *geo = [[CLGeocoder alloc] init];
    [geo reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray *placemarks, NSError *error) {
        //取出標記
        CLPlacemark *pm = [placemarks lastObject];
        //賦值
        userLocation.title = pm.name;
    }];
}
#pragma mark - CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    //獲取WGS-84坐標的對象,兩者選其一
    CLLocation *location=[locations lastObject];
    CLLocationCoordinate2D coords=location.coordinate;
    //獲取GCJ-02坐標的對象,兩者選其一
    CLLocationCoordinate2D coords=_mapView.userLocation.location.coordinate;
    //獲得經緯度
    NSLog(@"緯度%f,經度%f",coords.latitude,coords.longitude);

    //經緯方向
    NSString *latitudeDirection=nil;
    NSString *longitudeDirection=nil;
    if (coords.latitude>=0) {
        latitudeDirection=@"N";
    }
    else if (coords.latitude=0) {
        longitudeDirection=@"E";
    }
    else if (coords.longitude<0) {
        longitudeDirection=@"W";
    }
    //經緯度拼接方向
    self.latitude=[NSString stringWithFormat:@"%f%@",coords.latitude,latitudeDirection];//緯度
    self.longitude=[NSString stringWithFormat:@"%f%@",coords.longitude,longitudeDirection];//經度

    //這個代理方法會每秒執行一次,如果你只想定位成功一次就結束定位,需要判斷定位成功後在此處調用stopUpdatingLocation結束定位。
}

-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    if (error.code==kCLErrorDenied) {
        //提示出錯原因
    }
}

附:經緯度十進制(小數)轉六十進制(度分秒)的方法

#pragma mark - 經緯度單位轉換
- (NSString *)stringWithCoordinateString:(NSString *)coordinateString{
    //示例:118.815033
    /** 將經度或緯度整數部分提取出來 */
    int latNumber = [coordinateString intValue];//118

    /** 取出小數點後面兩位(為轉化成'分'做准備) */
    NSArray *array = [coordinateString componentsSeparatedByString:@"."];
    /** 小數點後面部分 */
    NSString *minuteCompnetString = [array lastObject];

    /** 拼接字字符串(將字符串轉化為0.xxxx形式) */
    NSString *str1 = [NSString stringWithFormat:@"0.%@", minuteCompnetString];

    /** 將字符串轉換成float類型以便計算 */
    float minuteNum = [str1 floatValue];   //0.815033

    /** 將小數點後數字轉化為'分'(minuteNum * 60) */
    float minuteNum1 = minuteNum * 60;    //0.815033*60=48.90198

    /** 將轉化後的float類型轉化為字符串類型 */
    NSString *latStr = [NSString stringWithFormat:@"%f", minuteNum1];

    /** 取整數部分即為緯度或經度'分' */
    int latMinute = [latStr intValue]; //48

    //取秒
    /** 取出小數點後面兩位(為轉化成'秒'做准備) */
    NSArray *secondArr = [latStr componentsSeparatedByString:@"."];
    /** 小數點後面部分 */
    NSString *lastCompnetString = [secondArr lastObject];

    /** 拼接字字符串(將字符串轉化為0.xxxx形式) */
    NSString *str2 = [NSString stringWithFormat:@"0.%@", lastCompnetString];

    /** 將字符串轉換成float類型以便計算 */
    float secondNum = [str2 floatValue];   //0.90198

    /** 將小數點後數字轉化為'分'(minuteNum * 60) */
    float secondNum1 = secondNum * 60;    //0.90198*60=54.1188

    /** 將轉化後的float類型轉化為字符串類型 */
    NSString *latStr2 = [NSString stringWithFormat:@"%f", secondNum1];

    /** 取整數部分即為緯度或經度'分' */
    int latSecond = [latStr2 intValue]; //54

    /** 將經度或緯度字符串合並為(xx°xx')形式 */
    NSString *string = [NSString stringWithFormat:@"%d°%d'%d''", latNumber, latMinute, latSecond];

    return string;
}


文章轉自 傅邑的簡書

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved