All files / core/systems/maidenhead maidenhead.ts

96.77% Statements 30/31
80% Branches 4/5
100% Functions 3/3
100% Lines 28/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64        2059x 2059x 2059x 2059x           2059x 8235x 8235x 8235x 8235x 8235x 8235x 8235x   2059x       9018x                   1002x 1002x 1002x           1002x 1002x 1002x 1002x 1002x 4006x 4006x 4006x 4006x 4006x   1002x                
/** Maidenhead locator (amateur radio grid squares). */
import type { LatLon } from '../../geo/ellipsoid'
 
export function toMaidenhead({ lat, lon }: LatLon, pairs = 4): string {
  let x = Math.min(359.9999999, lon + 180)
  let y = Math.min(179.9999999, lat + 90)
  let out = ''
  const sizes: [number, number, string][] = [
    [20, 10, 'A'],
    [2, 1, '0'],
    [5 / 60, 2.5 / 60, 'a'],
    [0.5 / 60, 0.25 / 60, '0'],
  ]
  for (let i = 0; i < pairs && i < sizes.length; i++) {
    const [w, h, base] = sizes[i]!
    const cx = Math.floor(x / w)
    const cy = Math.floor(y / h)
    const code = base.charCodeAt(0)
    out += String.fromCharCode(code + cx) + String.fromCharCode(code + cy)
    x -= cx * w
    y -= cy * h
  }
  return out
}
 
export function isMaidenhead(s: string): boolean {
  return /^[A-R]{2}(\d{2}([A-X]{2}(\d{2})?)?)?$/i.test(s)
}
 
export function fromMaidenhead(loc: string): {
  center: LatLon
  west: number
  south: number
  east: number
  north: number
} {
  const s = loc.toUpperCase()
  Iif (!isMaidenhead(s)) throw new Error(`Invalid Maidenhead locator "${loc}"`)
  const sizes: [number, number, string][] = [
    [20, 10, 'A'],
    [2, 1, '0'],
    [5 / 60, 2.5 / 60, 'A'],
    [0.5 / 60, 0.25 / 60, '0'],
  ]
  let west = -180
  let south = -90
  let w = 360
  let h = 180
  for (let i = 0; i < s.length / 2; i++) {
    const [sw, sh, base] = sizes[i]!
    west += (s.charCodeAt(i * 2) - base.charCodeAt(0)) * sw
    south += (s.charCodeAt(i * 2 + 1) - base.charCodeAt(0)) * sh
    w = sw
    h = sh
  }
  return {
    center: { lat: south + h / 2, lon: west + w / 2 },
    west,
    south,
    east: west + w,
    north: south + h,
  }
}