Swift:精确度损失在Swift中将SVY21转换为LatLon

时间:2017-10-01 05:33:52

标签: ios swift

我正在开发一个iOS应用程序,该应用程序进行API调用以提取SVY21格式的停车场位置。然后我将SVY21格式转换为WGS84格式,以便我可以删除MapKit上的引脚。

我引用了以下github post并将现有代码转换为Swift。转换是在代码中正确完成的(使用Python语言中的任意northings / eastings对我的Swift版本进行了验证)并且意识到当我将它固定在地图上时会有一些精度损失。

我使用在线calculator确认了这一点,此计算器似乎可以产生更准确的结果。

左上角是在线计算器的结果,而右下角是使用github帖子的转换。这里使用的北/东是31045.6165,31694.0055。

enter image description here

//Conversion SVY21 to LatLon in Swift that I converted from other 
//languages

precedencegroup PowerPrecedence { higherThan: MultiplicationPrecedence }
infix operator ^^ : PowerPrecedence
func ^^ (radix: Double, power: Double) -> Double {
    return Double(pow(Double(radix), Double(power)))
}

class Convenience: NSObject {

    static let sharedInstance = Convenience()

    let a = 6378137.0
    let f = 1 / 298.257223563

    let oLat = 1.366666 // origin's lat in degrees
    let oLon = 103.833333 // origin's lon in degrees
    let oN = 38744.572 // false Northing
    let oE = 28001.642 // false Easting
    let k = 1.0 // scale factor

    var e2: Double!
    var e4: Double!
    var e6: Double!
    var A0: Double!
    var A2: Double!
    var A4: Double!
    var A6: Double!

    override init() {
        super.init()
    }

    func convertSVY21(N: Double, E: Double) -> CLLocationCoordinate2D {

        let b = a * (1.0 - f)
        e2 = (2.0 * f) - (f * f)
        let e4 = e2 * e2
        let e6 = e4 * e2
        A0 = 1 - (e2 / 4) - (3 * e4 / 64) - (5 * e6 / 256)
        A2 = (3 / 8) * (e2 + (e4 / 4) + (15 * e6 / 128))
        A4 = (15 / 256) * (e4 + (3 * e6 / 4))
        A6 = 35 * e6 / 3072

        let Nprime = N - oN
        let Mo = calcM(lat: oLat)
        let Mprime = Mo + (Nprime / k)
        let n = (a - b) / (a + b)
        let n2 = n * n
        let n3 = n2 * n
        let n4 = n2 * n2
        let G = a * (1 - n) * (1 - n2) * (1 + (9 * n2 / 4) + (225 * n4 / 64)) * (Double.pi / 180)
        let sigma = (Mprime * Double.pi) / (180 * G)

        let latPrimeT1 = ((3 * n / 2) - (27 * n3 / 32)) * sin(2 * sigma)
        let latPrimeT2 = ((21 * n2 / 16) - (55 * n4 / 32)) * sin(4 * sigma)
        let latPrimeT3 = (151 * n3 / 96) * sin(6 * sigma)
        let latPrimeT4 = (1097 * n4 / 512) * sin(8 * sigma)
        let latPrime = sigma + latPrimeT1 + latPrimeT2 + latPrimeT3 + latPrimeT4;

        let sinLatPrime = sin(latPrime)
        let sin2LatPrime = sinLatPrime * sinLatPrime

        let rhoPrime = calcRho(sin2Lat: sin2LatPrime)
        let vPrime = calcV(sin2Lat: sin2LatPrime)
        let psiPrime = vPrime / rhoPrime
        let psiPrime2 = psiPrime * psiPrime
        let psiPrime3 = psiPrime2 * psiPrime
        let psiPrime4 = psiPrime3 * psiPrime
        let tPrime = tan(latPrime)
        let tPrime2 = tPrime * tPrime
        let tPrime4 = tPrime2 * tPrime2
        let tPrime6 = tPrime4 * tPrime2
        let Eprime = E - oE
        let x = Eprime / (k * vPrime)
        let x2 = x * x
        let x3 = x2 * x
        let x5 = x3 * x2
        let x7 = x5 * x2

        //Compute Lat
        let latFactor = tPrime / (k * rhoPrime)
        let latTerm1 = latFactor * ((Eprime * x) / 2)
        let latTerm2 = latFactor * ((Eprime * x3) / 24) * ((-4 * psiPrime2) + (9 * psiPrime) * (1 - tPrime2) + (12 * tPrime2))
        let latTerm3 = latFactor * ((Eprime * x5) / 720) * ((8 * psiPrime4) * (11 - 24 * tPrime2) - (12 * psiPrime3) * (21 - 71 * tPrime2) + (15 * psiPrime2) * (15 - 98 * tPrime2 + 15 * tPrime4) + (180 * psiPrime) * (5 * tPrime2 - 3 * tPrime4) + 360 * tPrime4)
        let latTerm4 = latFactor * ((Eprime * x7) / 40320) * (1385 - 3633 * tPrime2 + 4095 * tPrime4 + 1575 * tPrime6)
        let lat = latPrime - latTerm1 + latTerm2 - latTerm3 + latTerm4

        // Compute Long
        let secLatPrime = 1 / cos(lat)
        let lonTerm1 = x * secLatPrime
        let lonTerm2 = ((x3 * secLatPrime) / 6) * (psiPrime + 2 * tPrime2)
        let lonTerm3 = ((x5 * secLatPrime) / 120) * ((-4 * psiPrime3) * (1 - 6 * tPrime2) + psiPrime2 * (9 - 68 * tPrime2) + 72 * psiPrime * tPrime2 + 24 * tPrime4);
        let lonTerm4 = ((x7 * secLatPrime) / 5040) * (61 + 662 * tPrime2 + 1320 * tPrime4 + 720 * tPrime6)
        let lon = (oLon * Double.pi / 180) + lonTerm1 - lonTerm2 + lonTerm3 - lonTerm4

        return CLLocationCoordinate2D(latitude: lat / (Double.pi / 180), longitude: lon / (Double.pi / 180))

    }

    func calcM(lat: Double) -> Double {
        let latR = lat * Double.pi / 180
        let term1 = A0 * latR
        let term2 = A2 * sin(2 * latR)
        let term3 = A4 * sin(4 * latR)
        let term4 = A6 * sin(6 * latR)
        return a * (term1 - term2 + term3 - term4)
    }

    func calcRho(sin2Lat: Double) -> Double {
        let num = a * (1.0 - e2)
        let denom = (1 - e2 * sin2Lat) ^^ (3.0 / 2.0)
        return num / denom
    }

    func calcV(sin2Lat: Double) -> Double {
        let poly = 1 - e2 * sin2Lat
        return a / poly.squareRoot()
    }
}

我想知道是否有人使用更可靠的转换工具将SVY21转换为latlon,以便我们可以更准确地将引脚放到谷歌地图或MapKit上。

0 个答案:

没有答案