57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
package geo
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/leaktechnologies/skyfeed/internal/config"
|
|
)
|
|
|
|
// Town represents a Canadian town record (loaded from towns.json).
|
|
type Town struct {
|
|
Name string `json:"name"`
|
|
Province string `json:"province"`
|
|
Lat float64 `json:"lat"`
|
|
Lon float64 `json:"lon"`
|
|
}
|
|
|
|
// FindNearestTown loads the cached towns.json and finds the closest town to given coordinates.
|
|
func FindNearestTown(lat, lon float64) (Town, error) {
|
|
townsPath := filepath.Join(config.DataDir, "towns.json")
|
|
|
|
data, err := os.ReadFile(townsPath)
|
|
if err != nil {
|
|
return Town{}, fmt.Errorf("failed to read town index: %w", err)
|
|
}
|
|
|
|
var towns []Town
|
|
if err := json.Unmarshal(data, &towns); err != nil {
|
|
return Town{}, fmt.Errorf("failed to parse towns.json: %w", err)
|
|
}
|
|
|
|
if len(towns) == 0 {
|
|
return Town{}, fmt.Errorf("no towns found in index")
|
|
}
|
|
|
|
minDist := math.MaxFloat64
|
|
var nearest Town
|
|
|
|
for _, t := range towns {
|
|
d := Haversine(lat, lon, t.Lat, t.Lon) // ✅ use shared helper from stations.go
|
|
if d < minDist {
|
|
minDist = d
|
|
nearest = t
|
|
}
|
|
}
|
|
|
|
if nearest.Name == "" {
|
|
return Town{}, fmt.Errorf("no nearby town found")
|
|
}
|
|
|
|
fmt.Printf("[geo] Nearest town: %s, %s (%.2f km)\n", nearest.Name, nearest.Province, minDist)
|
|
return nearest, nil
|
|
}
|