chore: release v0.27.12
This commit is contained in:
@@ -11,6 +11,7 @@ package geo
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -118,3 +119,65 @@ func NeighbourGrids(lat, lon float64, ring int) []string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GridsWithin returns every Maidenhead square whose centre lies within km of
|
||||
// (lat, lon), nearest first, at most max of them.
|
||||
//
|
||||
// NeighbourGrids answers "the ring around here", which is the right shape for a
|
||||
// few hundred kilometres and the wrong one past that: a ring is a square, so
|
||||
// asking for 2000 km through it means 1369 squares, most of them further away
|
||||
// than the ones it left out. This measures instead, and the count then follows
|
||||
// the AREA asked for rather than the corner of a box.
|
||||
//
|
||||
// Nearest first because the caller has to be able to trim: these become one
|
||||
// broker subscription each, and when there are more than can be afforded, the
|
||||
// squares to keep are the close ones.
|
||||
func GridsWithin(lat, lon, km float64, max int) []string {
|
||||
if km <= 0 || max <= 0 {
|
||||
return nil
|
||||
}
|
||||
// One square is 1° of latitude and 2° of longitude. Sweep a box big enough
|
||||
// to hold the circle — a degree of latitude is ~111 km everywhere, and a
|
||||
// degree of longitude never MORE than that, so this cannot cut the circle.
|
||||
steps := int(km/111.0) + 1
|
||||
type cand struct {
|
||||
grid string
|
||||
d float64
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
out := []cand{}
|
||||
for dLat := -steps; dLat <= steps; dLat++ {
|
||||
for dLon := -2 * steps; dLon <= 2*steps; dLon++ {
|
||||
la := lat + float64(dLat)
|
||||
lo := lon + float64(dLon)*2
|
||||
if la > 90 || la < -90 {
|
||||
continue
|
||||
}
|
||||
g := LatLonToGrid(la, lo)
|
||||
if seen[g] {
|
||||
continue
|
||||
}
|
||||
// Measured to the square's own centre, not to the sample point, so
|
||||
// two samples landing in one square agree about how far it is.
|
||||
cLat, cLon, ok := GridToLatLon(g)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
d := HaversineKm(lat, lon, cLat, cLon)
|
||||
if d > km {
|
||||
continue
|
||||
}
|
||||
seen[g] = true
|
||||
out = append(out, cand{g, d})
|
||||
}
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].d < out[j].d })
|
||||
if len(out) > max {
|
||||
out = out[:max]
|
||||
}
|
||||
grids := make([]string, len(out))
|
||||
for i, c := range out {
|
||||
grids[i] = c.grid
|
||||
}
|
||||
return grids
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user