Ensure non-US countries with less airport codes get sufficient choices
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
7f0c60b392
commit
ba0a727150
175
airports.go
175
airports.go
@ -24,6 +24,10 @@ type Airport struct {
|
||||
data *alphafoxtrot.Airport
|
||||
}
|
||||
|
||||
type Finder struct {
|
||||
f *alphafoxtrot.AirportFinder
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
var dataDir = flag.String("data-dir", "./data", "Data cache directory")
|
||||
@ -32,7 +36,9 @@ func main() {
|
||||
|
||||
validateData(*dataDir)
|
||||
|
||||
finder := alphafoxtrot.NewAirportFinder()
|
||||
finder := &Finder{
|
||||
f: alphafoxtrot.NewAirportFinder(),
|
||||
}
|
||||
|
||||
// LoadOptions come with preset filepaths
|
||||
options := alphafoxtrot.PresetLoadOptions(*dataDir)
|
||||
@ -41,10 +47,47 @@ func main() {
|
||||
filter := alphafoxtrot.AirportTypeRunways
|
||||
|
||||
// Load the data into memory
|
||||
if err := finder.Load(options, filter); len(err) > 0 {
|
||||
if err := finder.f.Load(options, filter); len(err) > 0 {
|
||||
log.Println("errors:", err)
|
||||
}
|
||||
|
||||
if args := flag.Args(); len(args) > 0 {
|
||||
if len(args) != 4 {
|
||||
fmt.Printf("[cc] [lat] [lng] [radius]\n")
|
||||
os.Exit(2)
|
||||
}
|
||||
cc := strings.ToUpper(args[0])
|
||||
|
||||
latitude, err := strconv.ParseFloat(args[1], 64)
|
||||
if err != nil {
|
||||
fmt.Printf("could not parse %s as latitude: %s", args[1], err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
longitude, err := strconv.ParseFloat(args[2], 64)
|
||||
if err != nil {
|
||||
fmt.Printf("could not parse %s as longitude: %s", args[2], err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
radiusKM, err := strconv.ParseFloat(args[3], 64)
|
||||
if err != nil {
|
||||
fmt.Printf("could not parse %s as radius: %s", args[3], err)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
airports, err := finder.GetAirports(cc, radiusKM, latitude, longitude)
|
||||
if err != nil {
|
||||
fmt.Printf("GetAirports error: %s\n", err)
|
||||
}
|
||||
|
||||
for _, a := range airports {
|
||||
fmt.Printf("%s\t%s (%0f)\n", a.Code, a.Name, a.Distance)
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
e := echo.New()
|
||||
|
||||
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
|
||||
@ -63,13 +106,15 @@ func main() {
|
||||
|
||||
radiusString := c.QueryParam("radius")
|
||||
|
||||
var radiusKM int
|
||||
var radiusKM float64
|
||||
if len(radiusString) > 0 {
|
||||
radiusKM, _ = strconv.Atoi(radiusString)
|
||||
radiusKM, _ = strconv.ParseFloat(radiusString, 64)
|
||||
}
|
||||
|
||||
if radiusKM < 10 {
|
||||
radiusKM = 100
|
||||
if radiusKM < 150 {
|
||||
radiusKM = 150
|
||||
} else {
|
||||
radiusKM = radiusKM * 1.5
|
||||
}
|
||||
|
||||
latitude, longitude, err := getLatLng(c)
|
||||
@ -77,64 +122,82 @@ func main() {
|
||||
return c.String(http.StatusBadRequest, fmt.Sprintf("invalid lat or lng: %s", err))
|
||||
}
|
||||
|
||||
ipLocation := s2.LatLngFromDegrees(latitude, longitude)
|
||||
|
||||
maxResults := 100
|
||||
radiusInMeters := float64(radiusKM) * 1000
|
||||
airportsRaw := finder.FindNearestAirportsByCountry(countryISOCode, latitude, longitude, radiusInMeters, maxResults, filter)
|
||||
|
||||
airports := []*alphafoxtrot.Airport{}
|
||||
for _, ap := range airportsRaw {
|
||||
if len(ap.IATACode) == 0 {
|
||||
continue
|
||||
}
|
||||
airports = append(airports, ap)
|
||||
airports, err := finder.GetAirports(countryISOCode, radiusKM, latitude, longitude)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
llCache := map[int]s2.LatLng{}
|
||||
for i, ap := range airports {
|
||||
ll := s2.LatLngFromDegrees(ap.LatitudeDeg, ap.LongitudeDeg)
|
||||
llCache[i] = ll
|
||||
}
|
||||
|
||||
r := []*Airport{}
|
||||
|
||||
for i, airport := range airports {
|
||||
// fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
|
||||
|
||||
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
|
||||
|
||||
distance := float64(ipLocation.Distance(llCache[i])) * 6371.01
|
||||
|
||||
a := &Airport{
|
||||
Name: airport.Name,
|
||||
Code: code,
|
||||
Distance: distance,
|
||||
data: airport,
|
||||
}
|
||||
r = append(r, a)
|
||||
}
|
||||
|
||||
sort.Slice(r, func(i, j int) bool {
|
||||
if r[i].data.Type == r[j].data.Type {
|
||||
return r[i].Distance < r[j].Distance
|
||||
}
|
||||
return airports[i].Type < airports[j].Type
|
||||
})
|
||||
|
||||
if len(r) > 10 {
|
||||
r = r[0:10]
|
||||
}
|
||||
|
||||
fmt.Printf("got %d airports, filtered to %d, returning %d\n", len(airportsRaw), len(airports), len(r))
|
||||
|
||||
return c.JSON(http.StatusOK, r)
|
||||
return c.JSON(http.StatusOK, airports)
|
||||
})
|
||||
|
||||
e.Logger.Fatal(e.Start(":8000"))
|
||||
|
||||
}
|
||||
|
||||
func (f *Finder) GetAirports(cc string, radiusKM, latitude, longitude float64) ([]*Airport, error) {
|
||||
|
||||
log.Printf("GetAirports(%s %.2f %.4f %.4f)", cc, radiusKM, latitude, longitude)
|
||||
|
||||
ipLocation := s2.LatLngFromDegrees(latitude, longitude)
|
||||
|
||||
maxResults := 500 // some countries have a lot of airports without local codes
|
||||
radiusInMeters := radiusKM * 1000
|
||||
airportsRaw := f.f.FindNearestAirportsByCountry(
|
||||
cc,
|
||||
latitude, longitude,
|
||||
radiusInMeters,
|
||||
maxResults,
|
||||
alphafoxtrot.AirportTypeAll, // filtered at load time
|
||||
)
|
||||
|
||||
airports := []*alphafoxtrot.Airport{}
|
||||
for _, ap := range airportsRaw {
|
||||
if len(ap.IATACode) == 0 {
|
||||
continue
|
||||
}
|
||||
airports = append(airports, ap)
|
||||
}
|
||||
|
||||
llCache := map[int]s2.LatLng{}
|
||||
for i, ap := range airports {
|
||||
ll := s2.LatLngFromDegrees(ap.LatitudeDeg, ap.LongitudeDeg)
|
||||
llCache[i] = ll
|
||||
}
|
||||
|
||||
r := []*Airport{}
|
||||
|
||||
for i, airport := range airports {
|
||||
fmt.Printf("%d %s: %+v\n", i, airport.Name, airport)
|
||||
|
||||
code := strings.ToLower(airport.Country.ISOCode + airport.IATACode)
|
||||
|
||||
distance := float64(ipLocation.Distance(llCache[i])) * 6371.01
|
||||
|
||||
a := &Airport{
|
||||
Name: airport.Name,
|
||||
Code: code,
|
||||
Distance: distance,
|
||||
data: airport,
|
||||
}
|
||||
r = append(r, a)
|
||||
}
|
||||
|
||||
sort.Slice(r, func(i, j int) bool {
|
||||
if r[i].data.Type == r[j].data.Type {
|
||||
return r[i].Distance < r[j].Distance
|
||||
}
|
||||
return airports[i].Type < airports[j].Type
|
||||
})
|
||||
|
||||
if len(r) > 15 {
|
||||
r = r[0:15]
|
||||
}
|
||||
|
||||
fmt.Printf("got %d airports, filtered to %d, returning %d\n", len(airportsRaw), len(airports), len(r))
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func validateData(dataDir string) {
|
||||
downloadFiles := false
|
||||
for _, filename := range alphafoxtrot.OurAirportsFiles {
|
||||
|
8
go.mod
8
go.mod
@ -16,9 +16,9 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 // indirect
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 // indirect
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
)
|
||||
|
8
go.sum
8
go.sum
@ -31,8 +31,12 @@ golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNy
|
||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921 h1:iU7T1X1J6yxDr0rda54sWGkHgOp5XJrqm79gcNlC2VM=
|
||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3 h1:EN5+DfgmRMvRUrMGERW2gQl3Vc+Z7ZMnI/xdEpPSf0c=
|
||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -40,12 +44,16 @@ golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0P
|
||||
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw=
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
|
Loading…
x
Reference in New Issue
Block a user