【问题标题】:iOS Swift3 - Convert coordinateiOS Swift3 - 转换坐标
【发布时间】:2017-06-19 11:03:30
【问题描述】:

我正在尝试从 geoJSON 文件在 MapKit 上创建注释,但问题是 geoJSON 文件提供的坐标与 MapKit 使用的坐标系不匹配。

问题:我如何转换读取geoJSON文件并转换坐标从``WGS84S

以下是geoJSON 文件的示例:

{"name":"MAPADDRESSPOINT","type":"FeatureCollection"
,"crs":{"type":"name","properties":{"name":"EPSG:3008"}}
,"features":[
{"type":"Feature","geometry":{
    "type":"Point","coordinates": [97973.4655999987,6219081.53249992,0]},
        "properties":{
            "ADDRESSAREA_resolved":"Sadelvägen",
            "multi_reader_id":1,
            "multi_reader_full_id":1,
            "BALSTATUS_resolved":"Gällande",
            "REMARKTYPE_resolved":"",
            "FARMADDRESSAREA_resolved":"",
            "geodb_type":"geodb_point",
            "multi_reader_keyword":"GEODATABASE_SDE_2",
            "DEVIATEFROMSTANDARD_resolved":"",
            "geodb_feature_is_simple":"yes",
            "STATUS_resolved":"Ingen information",
            "ADDRESSEDCONSTRUCTIONTYPE_resolved":"",
            "SUPPLIER_resolved":"",
            "multi_reader_type":"GEODATABASE_SDE",
            "geodb_oid":18396,
            "STAIRCASEIDENTIFIER_resolved":"",
            "LOCATIONADDRESSSTATUS_resolved":"Gällande",
            "POSITIONKIND_resolved":"Byggnad",
            "BALADDRESSTYPE_resolved":"Gatuadressplats",
            "COMMENTARY":"","
            DTYPE":"",
            "EXTERNALID":2,"GID":"{DEEA1685-2FF3-4BEB-823D-B9FA51E09F71}",
            "MODIFICATIONDATE":"20170301173751",
            "MODIFICATIONSIGN":"BAL service",
            "OBJECTID":18396,
            "REGDATE":"20110321151134",
            "REGSIGN":"BAL service",
            "STATUS":0,
            "ADDRESSEDCONSTRUCTIONVALUE":"",
            "LABELROTATIONANGLE":0,
            "POSTCODE":"25483",
            "POSITIONKIND":1,
            "REALPROPERTYKEY":"120320803",
            "BALSTATUS":2,
            "BALADDRESSTYPE":1,
            "BALID":"D5650F0B-EE54-4C4C-9C40-A8162118288C",
            "DESIGNATIONVALUE":"",
            "SYNCDATE":"20170301173751",
            "STREETNAME":"Sadelvägen",
            "ADDRESSAREA":554,
            "YARDSNAME":"",
            "PLACENAMEID":"",
            "ADDRESSLABEL":"Sadelvägen 6",
            "DESIGNATIONNUMBERLETTER":"",
            "LOCATIONADDRESSSTATUS":3,
            "CITY":"Helsingborg",
            "ENUMERATOR":"6",
            "SYMBOLROTATIONANGLE":0,
            "POPULARNAME":"",
            "geodb_feature_dataset":"Adress"
        }
    }
}]
}

【问题讨论】:

  • 您是如何生成/获取此 geoJSON 的?对于在 geoJSON 中使用什么坐标系没有通用规范,这似乎不是地理坐标。您应该了解这是什么坐标系,然后您可以将其转换为地理坐标。
  • 我已经更新了问题
  • 查看地理信息系统 StackExchange 页面上的 this 问题,他们推荐了一些可用于转换的工具。
  • 我查看了链接,但似乎没有一个工具与 Swift 兼容
  • 除非你能找到一种可以用 Swift 编码的算法来进行转换,否则我认为没有比使用在线工具更好的选择了。

标签: ios swift mapkit gis geojson


【解决方案1】:

https://en.m.wikipedia.org/wiki/Transverse_Mercator_projection

自然起源经度 0° 00' 00.000" N 13° 30' 00.000" E

自然原点的比例因子 1

假东移 150000 米

伪北向 0

最终(游乐场)版本

//: [Previous](@previous)

import Foundation

extension Double {
    var rad: Double {
        get {
            return .pi * self / 180.0
        }
    }
    var deg: Double {
        get {
            return 180.0 * self / .pi
        }
    }
}

// SWEREF99 13 30 (GRS80)
let φ0 = 0.0
let λ0 = 13.5.rad
let N0 = 0.0
let E0 = 150000.0
let k0 = 1.0

// GRS80
let a = k0 * 6378137.0
let b = k0 * 6356752.31414034
let n = (a - b)/(a + b)

let n2 = n * n
let n3 = n2 * n
let n4 = n3 * n
let a2 = a * a
let b2 = b * b
let e2 = (a2 - b2)/a2
let H0 = 1.0 + 1.0/4.0*n2 + 1.0/64.0*n4
let H2 = -3.0/2.0*n + 3.0/16.0*n3
let H4 = 15.0/16.0*n2 - 15.0/64.0*n4
let H6 = -35.0/48.0*n3
let H8 = 315.0/512.0*n4

let ν:(Double)->Double = { φ in
    return a/(sqrt(1.0 - e2 * sin(φ) * sin(φ)))
}

let ρ:(Double)->Double = { φ in
    return ν(φ) * (1.0 - e2) / (1.0 - e2 * sin(φ) * sin(φ))
}

let η2:(Double)->Double = { φ in
    return ν(φ) / ρ(φ) - 1.0
}
var arcMeridian1:(Double)->Double = { φ in
    let m = (a + b) / 2 * (H0 * φ + H2 * sin(2.0 * φ) + H4 * sin(4.0 * φ) + H6 * sin(6.0 * φ) + H8 * sin(8.0 * φ))
    return m
}

var arcMeridian:(Double, Double)->Double = { φ1, φ2 in
    return arcMeridian1(φ2) - arcMeridian1(φ1)
}

var cartografic:(Double,Double)->(Double,Double) = { φ, λ in
    let νφ = ν(φ)
    let ρφ = ρ(φ)
    let η2φ = νφ / ρφ - 1.0
    let s1 = sin(φ)
    let s2 = s1 * s1
    let c1 = cos(φ)
    let c2 = c1 * c1
    let c3 = c2 * c1
    let c5 = c3 * c2
    let t2 = s2/c2
    let t4 = t2 * t2

    let k1 = νφ * c1
    let k2 = νφ/2.0 * s1 * c1
    let k3 = νφ/6.0 * c3 * (νφ / ρφ - t2)
    let k4 = νφ/24.0 * s1 * c3 * (5.0 - t2 + 9.0 * η2φ)
    let k5 = νφ/120.0 * c5 * (5.0 - 18.0 * t2 + t4 + 14.0 * η2φ - 58.0 * t2 * η2φ)
    let k6 = νφ/720.0 * s1 * c5 * (61.0 - 58.0 * t2 + t4)

    let Δλ = λ - λ0
    let Δλ2 = Δλ * Δλ
    let Δλ3 = Δλ2 * Δλ
    let Δλ4 = Δλ3 * Δλ
    let Δλ5 = Δλ4 * Δλ
    let Δλ6 = Δλ4 * Δλ

    let N = arcMeridian(φ0,φ) + N0 + Δλ2 * k2 + Δλ4 * k4 + Δλ6 * k6
    let E = E0 + Δλ * k1 + Δλ3 * k3 + Δλ5 * k5

    return (N,E)
}

var geodetic:(Double,Double)->(Double,Double) = { N, E in
    var φ = (N - N0) / a + φ0
    var M = arcMeridian(φ0, φ)

    var diff = 1.0
    repeat {
        φ += (N - N0 - M) / a
        M = arcMeridian(φ0, φ)
        diff = N - N0 - M
    } while abs(diff) > 0.0000000001  // max 3 - 4 iterations
    let E1 = E - E0
    let E2 = E1 * E1
    let E3 = E2 * E1
    let E4 = E3 * E1
    let E5 = E4 * E1
    let E6 = E5 * E1
    let E7 = E6 * E1

    let νφ = ν(φ)
    let νφ3 = νφ * νφ * νφ
    let νφ5 = νφ3 * νφ * νφ
    let νφ7 = νφ5 * νφ * νφ
    let ρφ = ρ(φ)
    let η2φ = νφ / ρφ - 1.0
    let s1 = sin(φ)
    let s2 = s1 * s1
    let c1 = cos(φ)
    let t1 = s1 / c1
    let t2 = t1 * t1
    let t4 = t2 * t2
    let t6 = t4 * t2

    let k1 = 1.0 / (c1 * νφ)
    let k2 = t1 / (2.0 * ρφ * νφ)
    let k3 = 1.0 / (6.0 * νφ3) * (νφ / ρφ + 2.0 * t2)
    let k4 = (t1 / (24.0 * ρφ * νφ3)) * (5.0 + 3.0 * t2 + η2φ - 9.0 * t2 * η2φ)
    let k5 = 1.0 / (120.0 * νφ5) * (5.0 + 28.0 * t2 + 24.0 * t4)
    let k6 = (t1 / (720.0 * ρφ * νφ5)) * (61.0 + 90.0 * t2 + 45.0 * t4)
    let k7 = (t1 / (5040.0 * ρφ * νφ7)) * (61.0 + 662.0 * t2 + 1320.0 * t4 + 720.0 * t6)

    φ = φ - E2 * k2 + E4 * k4 - E6 * k6
    let λ = λ0 + E1 * k1 - E3 * k3 + E5 * k5 - E7 * k7
    return (φ, λ)
}

print("pecision check")
let carto0 = cartografic(55.0.rad, 12.75.rad)
print(carto0,"err:", carto0.0 - 6097487.637, carto0.1 - 102004.871)

let carto1 = cartografic(61.0.rad, 14.25.rad)
print(carto1,"err:", carto1.0 - 6765725.847, carto1.1 - 190579.995)
print()
print("given position: N 6219081.53249992, E 97973.4655999987")
let geo = geodetic(6219081.53249992, 97973.4655999987)
print("geodetic: φ =", geo.0.deg,"λ =", geo.1.deg)

//: [Next](@next)

打印

pecision check
(6097487.6372101102, 102004.87085248799) err: 0.00021011009812355 -0.000147512007970363
(6765725.8471242301, 190579.99493182387) err: 0.000124230049550533 -6.81761302985251e-05

given position: N 6219081.53249992, E 97973.4655999987
geodetic: φ = 56.0916410844269 λ = 12.6641326192406

地图上的位置

【讨论】:

  • 令人印象深刻的好答案!但是有没有可能做到和this在线转换器一样精确呢?
  • @J.Doe 当然,不幸的是,确切的例子太大了,无法在此处作为答案发布。
  • @J.Doe 抱歉,我的地理库在开源版本中不可用。我建议你先上网查一下,我很确定有很多关于如何计算的信息。
  • @J.Doe 我做了一个计算更精确的例子,你可以直接使用它,也可以修改它以满足你的需求。
  • 非常感谢!这真的很有帮助,也很有教育意义。谢谢。
【解决方案2】:

我不明白您到底在寻找什么,但我会做的是(因为您使用的是 swift)创建 MKPointAnnotation 的扩展并添加一个新的初始化器,该初始化器采用 geoJSON,解析它,获取坐标(以及任何数据您打算放入注释对象)并返回带有所需数据的 MKPointAnnotation 。 以防万一您不知道如何解析 JSON,这是一个示例:

do {
let dictionary = try JSONSerialization.jsonObject(with: geoJSON!,
    options:    JSONSerialization.ReadingOptions.mutableContainers) as! [String: AnyObject]
let features = dictionary["features"] as! [[String:AnyObject]]
let geometry = features[0]["geometry"] as! [String: AnyObject]
....
}catch{
//incase the json doesnt get parsed
}

继续前进,直到到达坐标..; 显然不要使用强制转换,以防你对一个值犹豫不决,而是使用 guard 或者 if let ....

【讨论】:

  • 问题是geoJSON文件提供的坐标与可用的MapKit坐标不匹配
  • 只需解析 JSON 并手动提取坐标,然后创建一个 CLLocationCoordinate2D,稍后将其分配给 MKPointAnnotation。以防万一您不知道如何解析它,首先将 json 转换为字典,例如 [String: Anyobject];然后继续深入那个字典,直到你提取值
  • 是的,但问题是 geoJSON 文件中的坐标看起来像这样“[97973.4655999987,6219081.53249992,0]”,而这些坐标在 MapKit 坐标系中不存在。而且我不知道如何检测geoJSON文件使用的是什么系统。
  • 哦该死的我什至没有注意到!显然这不是使用标准的长/纬度单位,您需要找到这些单位并将其转换回来
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多