坐標轉(zhuǎn)換



import UIKit

import Foundation
import CoreLocation

@objcMembers
public class HTMCoorTransform: NSObject{
    
    static let shared = HTMCoorTransform.init()
    
    //WGS-84:是國際標準瓶您,GPS坐標(Google Earth使用麻捻、或者GPS模塊)
    //GCJ-02:中國坐標偏移標準,Google Map呀袱、高德贸毕、騰訊使用
    //BD-09: 百度坐標偏移標準,Baidu Map使用
    
    let  a = 6378245.0;
    let  ee = 0.00669342162296594323;
    let  pi = 3.1415926535897932384626;
    let  xPi = Double.pi * 3000.0 / 180.0;
    
    //WGS-84 --> GCJ-02
    public static func transformFromWGSToGCJ(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D{
        return shared.transformFromWGSToGCJ(wgsLoc)
    }
    func transformFromWGSToGCJ(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D
    {
        var adjustLoc=CLLocationCoordinate2D();
        if( isLocationOutOfChina(location: wgsLoc))
        {
            adjustLoc = wgsLoc;
        }
        else
        {
            var adjustLat = transformLatWithX(wgsLoc.longitude - 105.0 ,wgsLoc.latitude - 35.0);
            var adjustLon = transformLonWithX(wgsLoc.longitude - 105.0 ,wgsLoc.latitude - 35.0);
            let radLat = wgsLoc.latitude / 180.0 * pi;
            var magic = sin(radLat);
            magic = 1 - ee * magic * magic;
            let 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;
    }
    
    func transformLatWithX(_ x:Double,_ y:Double)->Double
    {
        var lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y ;
        lat += 0.2 * sqrt(fabs(x));
        
        lat += (20.0 * sin(6.0 * x * pi)) * 2.0 / 3.0;
        lat += (20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
        lat += (20.0 * sin(y * pi)) * 2.0 / 3.0;
        lat += (40.0 * sin(y / 3.0 * pi)) * 2.0 / 3.0;
        lat += (160.0 * sin(y / 12.0 * pi)) * 2.0 / 3.0;
        lat += (320 * sin(y * pi / 30.0)) * 2.0 / 3.0;
        return lat;
    }
    
    func transformLonWithX(_ x:Double,_ y:Double)->Double
    {
        var lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y ;
        lon +=  0.1 * sqrt(fabs(x));
        lon += (20.0 * sin(6.0 * x * pi)) * 2.0 / 3.0;
        lon += (20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
        lon += (20.0 * sin(x * pi)) * 2.0 / 3.0;
        lon += (40.0 * sin(x / 3.0 * pi)) * 2.0 / 3.0;
        lon += (150.0 * sin(x / 12.0 * pi)) * 2.0 / 3.0;
        lon += (300.0 * sin(x / 30.0 * pi)) * 2.0 / 3.0;
        return lon;
    }
    
    //GCJ-02 --> BD-09
    public static func transformFromGCJToBaidu(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D{
        return shared.transformFromGCJToBaidu(wgsLoc)
    }
    func transformFromGCJToBaidu(_ p:CLLocationCoordinate2D) -> CLLocationCoordinate2D
    {
        let z = sqrt(p.longitude * p.longitude + p.latitude * p.latitude) + 0.00002 * sqrt(p.latitude * pi);
        let theta = atan2(p.latitude, p.longitude) + 0.000003 * cos(p.longitude * pi);
        var geoPoint=CLLocationCoordinate2D();
        geoPoint.latitude  = (z * sin(theta) + 0.006);
        geoPoint.longitude = (z * cos(theta) + 0.0065);
        return geoPoint;
    }
    
    
    //BD-09 --> GCJ-02
    public static func transformFromBaiduToGCJ(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D{
        return shared.transformFromBaiduToGCJ(wgsLoc)
    }
    func transformFromBaiduToGCJ(_ p:CLLocationCoordinate2D)-> CLLocationCoordinate2D
    {
        let x = p.longitude - 0.0065, y = p.latitude - 0.006;
        let z = sqrt(x * x + y * y) - 0.00002 * sin(y * xPi);
        let theta = atan2(y, x) - 0.000003 * cos(x * xPi);
        var geoPoint = CLLocationCoordinate2D();
        geoPoint.latitude  = z * sin(theta);
        geoPoint.longitude = z * cos(theta);
        return geoPoint;
    }
    
    //GCJ-02 --> WGS-84
    public static func transformFromGCJToWGS(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D{
        return shared.transformFromGCJToWGS(wgsLoc)
    }
    func transformFromGCJToWGS(_ p:CLLocationCoordinate2D) -> CLLocationCoordinate2D
    {
        let threshold = 0.00001;
        
        // The boundary
        var minLat = p.latitude - 0.5;
        var maxLat = p.latitude + 0.5;
        var minLng = p.longitude - 0.5;
        var maxLng = p.longitude + 0.5;
        
        var delta = 1.0;
        let maxIteration = 30;
        // Binary search
        while(true)
        {
            let leftBottom  = transformFromWGSToGCJ(CLLocationCoordinate2D(latitude: minLat,longitude: minLng));
            let rightBottom = transformFromWGSToGCJ(CLLocationCoordinate2D(latitude : minLat,longitude : maxLng));
            let leftUp      = transformFromWGSToGCJ(CLLocationCoordinate2D(latitude : maxLat,longitude : minLng));
            let midPoint    = transformFromWGSToGCJ(CLLocationCoordinate2D(latitude : ((minLat + maxLat) / 2),longitude : ((minLng + maxLng) / 2)));
            delta = fabs(midPoint.latitude - p.latitude) + fabs(midPoint.longitude - p.longitude);
            
            if(maxIteration <= 1 || delta <= threshold)
            {
                return CLLocationCoordinate2D(latitude: (minLat + maxLat) / 2, longitude: (minLng + maxLng) / 2);
                
            }
            
            if(isContains(p, p1: leftBottom, p2: midPoint))
            {
                maxLat = (minLat + maxLat) / 2;
                maxLng = (minLng + maxLng) / 2;
            }
            else if(isContains(p, p1: rightBottom, p2: midPoint))
            {
                maxLat = (minLat + maxLat) / 2;
                minLng = (minLng + maxLng) / 2;
            }
            else if(isContains(p, p1: leftUp, p2: midPoint))
            {
                minLat = (minLat + maxLat) / 2;
                maxLng = (minLng + maxLng) / 2;
            }
            else
            {
                minLat = (minLat + maxLat) / 2;
                minLng = (minLng + maxLng) / 2;
            }
        }
        
    }
    
    //WGS-84 --> BD-09
    public static func transformFromWGSToBaidu(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D{
        return shared.transformFromWGSToBaidu(wgsLoc)
    }
    func transformFromWGSToBaidu(_ p:CLLocationCoordinate2D) -> CLLocationCoordinate2D
    {
        let gcj = transformFromWGSToGCJ(p);
        let bd = transformFromGCJToBaidu(gcj)
        return bd;
    }
    
    //BD-09 --> WGS-84
    public static func transformFromBaiduToWGS(_ wgsLoc:CLLocationCoordinate2D)->CLLocationCoordinate2D{
        return shared.transformFromBaiduToWGS(wgsLoc)
    }
    func transformFromBaiduToWGS(_ p:CLLocationCoordinate2D) -> CLLocationCoordinate2D
    {
        let gcj = transformFromBaiduToGCJ(p)
        let wgs = transformFromGCJToWGS(gcj)
        return wgs;
    }
    
    //判斷點是否在p1和p2之間
    //point: 點
    //p1:    左上角
    //p2:    右下角
    func isContains(_ point:CLLocationCoordinate2D , p1:CLLocationCoordinate2D, p2:CLLocationCoordinate2D)->Bool
    {
        
        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));
    }
    
    
    //是否在中國以外
    func isLocationOutOfChina(location:CLLocationCoordinate2D) -> Bool
    {
        if (location.longitude < 72.004 || location.longitude > 137.8347 || location.latitude < 0.8293 || location.latitude > 55.8271){
            return true;
        }else{
            return false;
        }
        
    }
    
    ///獲取兩點之間的距離
    public static func distanceByPoint(lat1:Double,lat2 :Double,lng1 :Double,lng2:Double)->Double{
        let dd = Double.pi/180;
        let x1=lat1*dd;
        let x2=lat2*dd;
        let y1=lng1*dd;
        let y2=lng2*dd;
        let R = 6371004;
        
        let temp = 2 - 2 * cos(x1) * cos(x2) * cos(y1-y2) - 2 * sin(x1) * sin(x2);
        
        let distance = Double(2) * Double(R) * asin(sqrt(temp)/2);
        
        //返回 m
        return   distance;
        
    }
    
    ///獲取兩點之間的距離
    public static  func distanceByPoint(point1:CLLocationCoordinate2D,point2:CLLocationCoordinate2D)->Double{
        return distanceByPoint(lat1: point1.latitude, lat2: point2.latitude, lng1: point1.longitude, lng2: point2.longitude);
        
    }
}


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載夜赵,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者明棍。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市寇僧,隨后出現(xiàn)的幾起案子摊腋,更是在濱河造成了極大的恐慌,老刑警劉巖婉宰,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歌豺,死亡現(xiàn)場離奇詭異,居然都是意外死亡心包,警方通過查閱死者的電腦和手機类咧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟹腾,“玉大人痕惋,你說我怎么就攤上這事⊥拗常” “怎么了值戳?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長炉爆。 經(jīng)常有香客問我堕虹,道長,這世上最難降的妖魔是什么芬首? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任赴捞,我火速辦了婚禮,結(jié)果婚禮上郁稍,老公的妹妹穿的比我還像新娘赦政。我一直安慰自己,他們只是感情好耀怜,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布恢着。 她就那樣靜靜地躺著桐愉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掰派。 梳的紋絲不亂的頭發(fā)上从诲,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音碗淌,去河邊找鬼盏求。 笑死,一個胖子當著我的面吹牛亿眠,可吹牛的內(nèi)容都是我干的碎罚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纳像,長吁一口氣:“原來是場噩夢啊……” “哼荆烈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起竟趾,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤憔购,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后岔帽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玫鸟,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年犀勒,在試婚紗的時候發(fā)現(xiàn)自己被綠了屎飘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡贾费,死狀恐怖钦购,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情褂萧,我是刑警寧澤押桃,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站导犹,受9級特大地震影響唱凯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谎痢,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一波丰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舶得,春花似錦、人聲如沸爽蝴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至九孩,卻和暖如春先馆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躺彬。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工煤墙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宪拥。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓仿野,卻偏偏與公主長得像,于是被迫代替她去往敵國和親她君。 傳聞我的和親對象是個殘疾皇子脚作,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

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