All files / core/systems/gars grid.ts

91.83% Statements 45/49
80.76% Branches 21/26
100% Functions 4/4
94.59% Lines 35/37

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 65 66 67 68 69 70 71 72 73 74 75 76 77 78                            8x 5x 1x         8x 8x 8x 8x   5x 5x 5x 5x 5x 5x   5x 36x 36x 2x     5x 5x 21x 21x         5x 15x 15x           5x 8x 5x 16x 32x 32x 32x 32x               5x       6x 6x    
/** GARS cell lines and labels at 30, 15 or 5 minutes, by zoom level. */
import {
  type Box,
  type GridGeometry,
  type GridLabel,
  type GridPath,
  type Position,
  boxPath,
  densify,
} from '../../geo/geometry'
import { fromGars, toGars } from './gars'
 
/** GARS spacing in degrees for a zoom level, or 0 for none. */
export function garsSpacing(zoom: number): number {
  if (zoom < 4) return 0
  if (zoom < 7) return 0.5
  Eif (zoom < 9) return 0.25
  return 5 / 60
}
 
export function garsGrid(view: Box, zoom: number): GridGeometry {
  const spacing = garsSpacing(zoom)
  const paths: GridPath[] = []
  const labels: GridLabel[] = []
  if (!spacing) return { paths, labels }
 
  const [w, s, e, n] = view
  const x0 = Math.floor((w + 180) / spacing)
  const x1 = Math.ceil((e + 180) / spacing)
  const y0 = Math.floor((s + 90) / spacing)
  const y1 = Math.ceil((n + 90) / spacing)
  Iif (x1 - x0 + (y1 - y0) > 800) return { paths, labels }
 
  const widthFor = (deg: number) => {
    const minutes = Math.round(deg * 60)
    if (minutes % 30 === 0) return 1.6
    Eif (minutes % 15 === 0) return 1
    return 0.5
  }
  const step = Math.max(spacing, (n - s) / 32)
  for (let i = x0; i <= x1; i++) {
    const lon = -180 + i * spacing
    paths.push({
      path: densify([lon, s], [lon, n], step),
      width: widthFor(lon + 180),
    })
  }
  for (let j = y0; j <= y1; j++) {
    const lat = -90 + j * spacing
    paths.push({
      path: densify([w, lat], [e, lat], Math.max(spacing, (e - w) / 32)),
      width: widthFor(lat + 90),
    })
  }
 
  const precision = spacing === 0.5 ? 30 : spacing === 0.25 ? 15 : 5
  if ((x1 - x0) * (y1 - y0) <= 500) {
    for (let i = x0; i < x1; i++) {
      for (let j = y0; j < y1; j++) {
        const lon = -180 + (i + 0.5) * spacing
        const lat = -90 + (j + 0.5) * spacing
        Iif (lat < -90 || lat > 90 || lon < -180 || lon > 180) continue
        labels.push({
          position: [lon, lat],
          text: toGars({ lat, lon }, precision),
          size: 12,
        })
      }
    }
  }
  return { paths, labels }
}
 
export function garsCellOutline(code: string): Position[] {
  const c = fromGars(code)
  return boxPath([c.west, c.south, c.east, c.north], 0.05)
}