【问题标题】:Convert MapKit latitude and longitude to DMS format将 MapKit 经纬度转换为 DMS 格式
【发布时间】:2022-01-06 03:08:20
【问题描述】:

我可以通过以下方法确定地图中心位置的纬度和经度:

func TargetGridReference(outletMapView_PrimaryTargetLocationMap: MKMapView, regionDidChangeAnimated animated: Bool) {

    let ThreatGridReference = outletMapView_PrimaryTargetLocationMap.centerCoordinate

    let mapLatitude = String(format:"%.13f",ThreatGridReference.latitude)

    let mapLongitude = String(format:"%.13f",ThreatGridReference.longitude)
    let latAndLong = "Lat: \(mapLatitude) \nLong: \(mapLongitude)"

    self.outletLabel_TargetGridReference.text = latAndLong

    tempThreatGridReference = ThreatGridReference
    tempThreatGridReferenceLat = mapLatitude
    tempThreatGridReferenceLon = mapLongitude

}

这给了我巴黎埃菲尔铁塔的纬度:

Lat:  48.8582487759147
Long:  2.2945180844931

如何在 Swift 中将上述内容转换为以下 DMS 格式?:

lat: 48° 51' 29.6956" N
long: 2° 17' 40.2651" E

MapKit 是否提供自动转换为各种坐标系(如 UTM、UPS、MGRS 等)的功能?

【问题讨论】:

    标签: ios swift mapkit


    【解决方案1】:

    很遗憾,没有自动转换,但您可以轻松地创建一个,如下所示:

    Swift 4 或更高版本

    func coordinateToDMS(latitude: Double, longitude: Double) -> (latitude: String, longitude: String) {
        let latDegrees = abs(Int(latitude))
        let latMinutes = abs(Int((latitude * 3600).truncatingRemainder(dividingBy: 3600) / 60))
        let latSeconds = Double(abs((latitude * 3600).truncatingRemainder(dividingBy: 3600).truncatingRemainder(dividingBy: 60)))
    
        let lonDegrees = abs(Int(longitude))
        let lonMinutes = abs(Int((longitude * 3600).truncatingRemainder(dividingBy: 3600) / 60))
        let lonSeconds = Double(abs((longitude * 3600).truncatingRemainder(dividingBy: 3600).truncatingRemainder(dividingBy: 60) ))
    
        return (String(format:"%d° %d' %.4f\" %@", latDegrees, latMinutes, latSeconds, latitude >= 0 ? "N" : "S"),
                String(format:"%d° %d' %.4f\" %@", lonDegrees, lonMinutes, lonSeconds, longitude >= 0 ? "E" : "W"))
    }
    

    let dms = coordinateToDMS(latitude: 48.8582487759147, longitude: 2.2945180844931)
    
    print(dms.latitude)  // "48° 51' 29.6956" N"
    print(dms.longitude) // "2° 17' 40.2651" E"
    

    您还可以扩展 CLLocationCoordinate2D 以获得您的纬度/经度 DMS 描述:

    import MapKit
    extension FloatingPoint {
        var minutes:  Self {
            return (self*3600)
                .truncatingRemainder(dividingBy: 3600)/60
        }
        var seconds:  Self {
            return (self*3600)
                .truncatingRemainder(dividingBy: 3600)
                .truncatingRemainder(dividingBy: 60)
        }
    }
    extension CLLocationCoordinate2D {
        var dms: (latitude: String, longitude: String) {
            return (String(format:"%d° %d' %.4f\" %@",
                           Int(abs(latitude)),
                           Int(abs(latitude.minutes)),
                           abs(latitude.seconds),
                           latitude >= 0 ? "N" : "S"),
                    String(format:"%d° %d' %.4f\" %@",
                           Int(abs(longitude)),
                           Int(abs(longitude.minutes)),
                           abs(longitude.seconds),
                           longitude >= 0 ? "E" : "W"))
        }
    }
    

    let coord = CLLocationCoordinate2D(latitude: 48.8582487759147, longitude: 2.2945180844931)
    
    coord.dms.latitude   // "48° 51' 29.6956" N"
    coord.dms.longitude  // "2° 17' 40.2651" E"
    

    【讨论】:

    • 完美运行!谢谢@Leo Dabus!
    • 我该如何做相反的事情(从 dms 到小数)?谢谢
    • 只需将度数与分钟除以 60 和秒除以 3600 相加即可。
    • coordinateToDMS(latitude: 12.99999999, longitude: 0.0) 返回纬度 12° 59' 60.0000" N
    【解决方案2】:

    我对这段代码进行了一些更新以使其在 Swift3 中工作(主要使用 .truncatingRemainder(dividingBy: ) 而不是 %)并将其扩展为输出 DMM,并包括将 DMM 和 DMS 转换为 DD 的函数!

    extension CLLocationCoordinate2D {
    
        var latitudeMinutes:  Double { return (latitude * 3600).truncatingRemainder(dividingBy: 3600) / 60 }
        var latitudeSeconds:  Double { return ((latitude * 3600).truncatingRemainder(dividingBy: 3600)).truncatingRemainder(dividingBy: 60) }
    
        var longitudeMinutes: Double { return (longitude * 3600).truncatingRemainder(dividingBy: 3600) / 60 }
        var longitudeSeconds: Double { return ((longitude * 3600).truncatingRemainder(dividingBy: 3600)).truncatingRemainder(dividingBy: 60) }
    
        var dms:(latitude: String, longitude: String) {
    
            return (String(format:"%d°%d'%.1f\"%@",
                           Int(abs(latitude)),
                           Int(abs(latitudeMinutes)),
                           abs(latitudeSeconds),
                           latitude >= 0 ? "N" : "S"),
                    String(format:"%d°%d'%.1f\"%@",
                           Int(abs(longitude)),
                           Int(abs(longitudeMinutes)),
                           abs(longitudeSeconds),
                           longitude >= 0 ? "E" : "W"))
        }
    
        var dmm: (latitude: String, longitude: String) {
            return (String(format:"%d°%.4f'%@",
                          Int(abs(latitude)),
                          abs(latitudeMinutes),
                          latitude >= 0 ? "N" : "S"),
                   String(format:"%d°%.4f'%@",
                          Int(abs(longitude)),
                          abs(longitudeMinutes),
                          longitude >= 0 ? "E" : "W"))
        }
    }
    
    var coord = CLLocationCoordinate2D(latitude: 41.40338, longitude: 2.17403)
    
    coord.latitude // 41.40338
    coord.longitude // 2.17403
    coord.latitudeMinutes // 24.20280000000009
    coord.latitudeSeconds // 12.16800000000512
    coord.longitudeMinutes // 10.44180000000001
    coord.longitudeSeconds // 26.50800000000072
    
    coord.dms.latitude   // "41°24'12.2"N"
    coord.dms.longitude  // "2°10'26.5"E"
    coord.dmm.latitude   // "41°24.2028'N"
    coord.dmm.longitude  // "2°10.4418'E"
    

    这些转换函数还允许输入不指示基本方向,而只是提供正或负:

    func DMStoDD(latDeg: Double, latMin: Double, latSec: Double, latDir: String?, longDeg: Double, longMin: Double, longSec: Double, longDir: String?) -> CLLocationCoordinate2D {
        var latitude = CLLocationDegrees()
        if latDeg > 0 {
            latitude = CLLocationDegrees(latDeg + ((latMin*60)/3600) + (latSec/3600))
            if latDir == "S" {latitude *= -1}
        }
        else{
            latitude = CLLocationDegrees((latDeg * -1) + ((latMin*60)/3600) + (latSec/3600))
            latitude *= -1
        }
    
        var longitude = CLLocationDegrees()
        if longDeg > 0 {
            longitude = CLLocationDegrees(longDeg + ((longMin*60)/3600) + (longSec/3600))
            if longDir == "W" {longitude *= -1}
        }
        else{
            longitude = CLLocationDegrees((longDeg * -1) + ((longMin*60)/3600) + (longSec/3600))
            longitude *= -1
        }
        return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }
    
    coord = DMStoDD(latDeg: 41, latMin: 24, latSec: 12.2, latDir: "", longDeg: 2, longMin: 10, longSec: 26.5, longDir: "")
    coord.latitude // 41.40338888888889
    coord.longitude // 2.174027777777777
    

    DMM 转 DD

    func DMMtoDD(latDeg: Double, latMin: Double, latDir: String?, longDeg: Double, longMin: Double, longDir: String?) -> CLLocationCoordinate2D {
        var latitude = CLLocationDegrees()
        if latDeg > 0 {
            latitude = CLLocationDegrees(latDeg + ((latMin*60)/3600))
            if latDir == "S" {latitude *= -1}
        }
        else{
            latitude = CLLocationDegrees((latDeg * -1) + ((latMin*60)/3600))
            latitude *= -1
        }
        var longitude = CLLocationDegrees()
        if longDeg > 0 {
            longitude = CLLocationDegrees(longDeg + ((longMin*60)/3600))
            if longDir == "W" {longitude *= -1}
        }
        else{
            longitude = CLLocationDegrees((longDeg * -1) + ((longMin*60)/3600))
            longitude *= -1
        }
        return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
    }
    
    coord = DMMtoDD(latDeg: 41, latMin: 24.2028, latDir: "N", longDeg: 2, longMin: 10.4418, longDir: "E")
    coord.latitude // 41.40338
    coord.longitude // 41.40338
    

    【讨论】:

      【解决方案3】:

      接受的答案的第一部分有一个轻微的错字:

      let latDegrees = abs(Int(lat))

      将始终产生正值latDegrees,因此返回部分 无论输入 lat: Double 符号如何,latDegrees >= 0 ? "N" : "S" 将始终生成 N

      只需要更改为 lat >= 0 ? "N" : "S")lon >= 0 ? "E" : "W") 直接评估输入值`符号。

      【讨论】:

        【解决方案4】:

        接受的答案有时会返回无效值,coordinateToDMS(latitude: 12.99999999, longitude: 0.0) 返回纬度 12° 59' 60.0000" N

        enum GeoFormat {
            case D
            case DM
            case DMS
        }
        func dms(value: Double, format: GeoFormat)->String {
            let sign = value < 0.0 ? -1 : 1
            let value = abs(value)
            switch format {
            case .D:
                return String(format: "%+15.10f°", value * Double(sign))
            case .DM:
                var deg = Int(value)
                var min = round((value - Double(deg)) * 60 * 10000000) * 0.0000001
                if min < 60.0 {} else {
                    min -= 60.0
                    deg += 1
                }
                return String(format: "%+4d°%010.7f′", deg * sign, min)
            case .DMS:
                var deg = Int(value)
                let _min = (value - Double(deg)) * 60
                var min = Int(_min)
                var sec = round((_min - Double(min)) * 60 * 10000) * 0.0001
                if sec < 60.0 {} else {
                    sec -= 60.0
                    min += 1
                }
                if min < 60 {} else {
                    min -= 60
                    deg += 1
                }
                return String(format: "%+4d°%02d′%07.4f″", deg * sign, min, sec)
            }
        }
        
        let value = -12.999999997222222
        print(dms(value: value, format: .D))
        print(dms(value: value, format: .DM))
        print(dms(value: value, format: .DMS))
        

        根据需要打印

         -12.9999999972°
         -12°59.9999998′
         -13°00′00.0000″
        

        【讨论】:

          【解决方案5】:

          斯威夫特 5 这是基于@Shō Ya Voorthuyzen 上面的回答。

          extension CLLocationCoordinate2D {
          
             var latitudeMinutes: Double { return (latitude * 3600).truncatingRemainder(dividingBy: 3600) / 60 }
             var latitudeSeconds: Double { return ((latitude * 3600).truncatingRemainder(dividingBy: 3600)).truncatingRemainder(dividingBy: 60) }
          
             var longitudeMinutes: Double { return (longitude * 3600).truncatingRemainder(dividingBy: 3600) / 60 }
             var longitudeSeconds: Double { return ((longitude * 3600).truncatingRemainder(dividingBy: 3600)).truncatingRemainder(dividingBy: 60) }
          
             var degrees: (latitude: String, longitude: String) {
              (String(format: "%.5f°", latitude), String(format: "%.5f°", longitude))
             }
          
             var dms: (latitude: String, longitude: String) {
              (String(format: "%d° %d' %.1f\" %@",
                      Int(abs(latitude)),
                      Int(abs(latitudeMinutes)),
                      abs(latitudeSeconds),
                      latitude >= 0 ? "N" : "S"),
               String(format: "%d° %d' %.1f\" %@",
                      Int(abs(longitude)),
                      Int(abs(longitudeMinutes)),
                      abs(longitudeSeconds),
                      longitude >= 0 ? "E" : "W"))
             }
          
             var ddm: (latitude: String, longitude: String) {
              (String(format: "%d° %.3f' %@",
                      Int(abs(latitude)),
                      abs(latitudeMinutes),
                      latitude >= 0 ? "N" : "S"),
               String(format: "%d° %.3f' %@",
                      Int(abs(longitude)),
                      abs(longitudeMinutes),
                      longitude >= 0 ? "E" : "W"))
             }
          }
          

          打印如下:

          十进制度:28.31668° -82.56701°

          度分秒:28° 19' 0.0" N 82° 34' 1.2" W

          度十进制分:28° 19.001' N 82° 34.020' W

          【讨论】:

            猜你喜欢
            • 2013-06-16
            • 2020-05-19
            • 1970-01-01
            • 2014-08-11
            • 2016-01-10
            • 2016-11-27
            • 1970-01-01
            • 2012-01-14
            • 1970-01-01
            相关资源
            最近更新 更多