Last active
December 9, 2021 10:17
-
-
Save kenguish/efc2c0626018a5c0e08c2c6a463733db to your computer and use it in GitHub Desktop.
Conversion of Amateur Radio Maidenhead Grid code to latitude longitutde coordinate in Swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
class HamGridMaidenheadConversion { | |
private let upper = "ABCDEFGHIJKLMNOPQRSTUVWX" | |
private let lower = "abcdefghijklmnopqrstuvwx" | |
private func ord(_ value:UnicodeScalar) -> Int { | |
return Int(( value as UnicodeScalar).value) | |
} | |
// Original by Paul King at StackExchange | |
// https://ham.stackexchange.com/questions/221/how-can-one-convert-from-lat-long-to-grid-square | |
public func gridFromCoordinate(latitude: Double, longitude: Double) -> String { | |
var lonDegrees: Double = 360 | |
var latDegrees: Double = 180 | |
var lon = longitude + 180.0 | |
var lat = latitude + 90.0 | |
var lonRemainder = lon | |
var latRemainder = lat | |
func gridPair(divisions: Double) -> (Double, Double) { | |
lonDegrees = lonDegrees/divisions | |
latDegrees = latDegrees/divisions | |
lon = lonRemainder/lonDegrees | |
lonRemainder = lonRemainder.truncatingRemainder(dividingBy: lonDegrees) //lonRemainder % lonDegrees | |
lat = latRemainder / latDegrees | |
latRemainder = latRemainder.truncatingRemainder(dividingBy: latDegrees) //latRemainder % latDegrees | |
return (lon, lat) | |
} | |
let (gridLonField, gridLatField) = gridPair(divisions: 18) | |
let (gridLonSquare, gridLatSquare) = gridPair(divisions: 10) | |
let (gridLonSubSquare, gridLatSubSquare) = gridPair(divisions: 24) | |
let (gridLonExtSquare, gridLatExtSquare) = gridPair(divisions: 10) | |
let (gridLonSubExtSquare, gridLatSubExtSquare) = gridPair(divisions: 24) | |
let x1 = Array(upper)[ Int(gridLonField) ] //upper[ Int(gridLonField) ] | |
let x2 = Array(upper)[ Int(gridLatField) ] //upper[Int(gridLatField)] | |
let x3 = Array(lower)[ Int(gridLonSubSquare) ] //lower[Int(gridLonSubSquare)] | |
let x4 = Array(lower)[ Int(gridLatSubSquare) ] //lower[Int(gridLatSubSquare)] | |
let x5 = Array(lower)[ Int(gridLonSubExtSquare) ] // lower[Int(gridLonSubExtSquare)] | |
let x6 = Array(lower)[ Int(gridLatSubExtSquare) ] // lower[Int(gridLatSubExtSquare)] | |
return "\(x1)\(x2)\(Int(gridLonSquare))\(Int(gridLatSquare))\(x3)\(x4)\(Int(gridLonExtSquare))\(Int(gridLatExtSquare))\(x5)\(x6)"//.uppercased() | |
} | |
// Swift port of the maidenhead python code: | |
// https://github.com/space-physics/maidenhead/blob/main/src/maidenhead/to_location.py | |
// If true, return the center of provided maidenhead grid square, | |
// instead of default south-west corner | |
// Default value = False needed to maidenhead full backward compatibility of this module. | |
public func coordinateFromGrid( grid: String, center: Bool = false) -> ( Double, Double) { | |
let maiden = grid.uppercased() | |
let N = maiden.count | |
// Stripe the maiden | |
let Oa = ord("A") | |
var lon = -180.0 | |
var lat = -90.0 | |
// First pair | |
let x0 = UnicodeScalar(maiden[0])! | |
let x1 = UnicodeScalar(maiden[1])! | |
lon += Double( ord(x0) - Oa) * 20 | |
lat += Double( ord(x1) - Oa) * 10 | |
// Secondpair | |
if N >= 4 { | |
lon += Double(maiden[2])! * 2 | |
lat += Double(maiden[3])! * 1 | |
} | |
// Second pair | |
if N >= 6 { | |
let x4 = UnicodeScalar(maiden[4])! | |
let x5 = UnicodeScalar(maiden[5])! | |
lon += Double((ord(x4) - Oa)) * 5.0 / 60 | |
lat += Double((ord(x5) - Oa)) * 2.5 / 60 | |
} | |
// No problem until here | |
// Secondpair | |
if N >= 8 { | |
let x6 = maiden[6] | |
let x7 = maiden[7] | |
lon += Double(x6)! * 5.0 / 600 | |
lat += Double(x7)! * 2.5 / 600 | |
} | |
if center { | |
if N == 2 { | |
lon += 20 / 2 | |
lat += 10 / 2 | |
} else if N == 4 { | |
lon += 2 / 2 | |
lat += 1.0 / 2 | |
} else if N == 6 { | |
lon += 5.0 / 60 / 2 | |
lat += 2.5 / 60 / 2 | |
} else if N >= 8 { | |
lon += 5.0 / 600 / 2 | |
lat += 2.5 / 600 / 2 | |
} | |
} | |
return ( lat, lon ) | |
} | |
} | |
extension String { | |
subscript(i: Int) -> String { | |
return String(self[index(startIndex, offsetBy: i)]) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment