Skip to content

Instantly share code, notes, and snippets.

@kenguish
Last active December 9, 2021 10:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenguish/efc2c0626018a5c0e08c2c6a463733db to your computer and use it in GitHub Desktop.
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
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