我正在开发一个iOS应用程序,该应用程序进行API调用以提取SVY21格式的停车场位置。然后我将SVY21格式转换为WGS84格式,以便我可以删除MapKit上的引脚。
我引用了以下github post并将现有代码转换为Swift。转换是在代码中正确完成的(使用Python语言中的任意northings / eastings对我的Swift版本进行了验证)并且意识到当我将它固定在地图上时会有一些精度损失。
我使用在线calculator确认了这一点,此计算器似乎可以产生更准确的结果。
左上角是在线计算器的结果,而右下角是使用github帖子的转换。这里使用的北/东是31045.6165,31694.0055。
//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上。