Goutil.go -rw-r--r-- 2.9 KiB
1package main
2
3import (
4 "encoding/csv"
5 "fmt"
6 "io"
7 "math"
8 "os"
9 "strconv"
10 "strings"
11)
12
13const d2r = (math.Pi / 180.0)
14
15// Haversine calculates linear distance between two pairs
16func Haversine(start, dest [2]float64) float64 {
17 dlong := (dest[1] - start[1]) * d2r
18 dlat := (dest[0] - start[0]) * d2r
19 a := math.Pow(math.Sin(dlat/2.0), 2) + math.Cos(start[0]*d2r)*math.Cos(dest[0]*d2r)*math.Pow(math.Sin(dlong/2.0), 2)
20 c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
21 distance := 6367 * c
22 return distance
23}
24
25func GetDistance(start, dest Airport) float64 {
26 return Haversine([2]float64{start.Latitude, start.Longitude}, [2]float64{dest.Latitude, dest.Longitude})
27}
28
29func NearBy(threshold float64, start Airport, airports AirportMap) []Airport {
30 nearby := []Airport{}
31 for _, dest := range airports {
32 if GetDistance(start, dest) <= threshold {
33 if dest.Code != start.Code {
34 nearby = append(nearby, dest)
35 }
36 }
37 }
38 return nearby
39}
40
41func FindRoutes(threshold float64, airports map[string]Airport, departure, arrival Airport) ([]Airport, []Airport) {
42 return NearBy(threshold, departure, airports), NearBy(threshold, arrival, airports)
43}
44
45// icao_code,iata_code,name,city,country,lat_deg,lat_min,lat_sec,lat_dir,lon_deg,lon_min,lon_sec,lon_dir,altitude,lat_decimal,lon_decimal
46// AYGA:GKA:GOROKA:GOROKA:PAPUA NEW GUINEA:006:004:054:S:145:023:030:E:01610:-6.082:145.392
47func parseAirport(row []string) *Airport {
48 if len(row) != 16 {
49 return nil
50 }
51 if row[1] == "N/A" {
52 return nil
53 }
54 latitude, _ := strconv.ParseFloat(row[14], 64)
55 longitude, _ := strconv.ParseFloat(row[15], 64)
56 if latitude == 0 || longitude == 0 {
57 return nil
58 }
59 airport := &Airport{
60 Code: row[1],
61 Name: row[2],
62 City: row[3],
63 Country: row[4],
64 Latitude: latitude,
65 Longitude: longitude,
66 }
67 return airport
68}
69
70//2B,410,AER,2965,KZN,2990,,0,CR2
71func parseRoute(airports AirportMap, row []string) *Route {
72 if len(row) != 9 {
73 return nil
74 }
75 start, end := row[2], row[4]
76 if airports.HasCode(start) && airports.HasCode(end) {
77 if start != end {
78 return &Route{
79 to: airports.Airport(end),
80 from: airports.Airport(start),
81 }
82 } else {
83 return nil
84 }
85 } else {
86 return nil
87 }
88}
89
90func Airports() AirportMap {
91 airports := map[string]Airport{}
92 reader := csv.NewReader(strings.NewReader(airportData))
93 reader.Comma = ':'
94 for {
95 row, err := reader.Read()
96 if err == io.EOF {
97 return airports
98 }
99 airport := parseAirport(row)
100 if airport != nil {
101 airports[airport.Code] = *airport
102 }
103 }
104}
105
106func Routes(airports AirportMap) []Route {
107 var routes []Route
108 reader := csv.NewReader(strings.NewReader(routeData))
109 reader.Comma = ','
110 for {
111 row, err := reader.Read()
112 if err == io.EOF {
113 return routes
114 }
115 route := parseRoute(airports, row)
116 if route != nil {
117 routes = append(routes, *route)
118 }
119 }
120}
121
122func maybe(err error) {
123 if err != nil {
124 fmt.Printf("Error: %s\n", err)
125 os.Exit(1)
126 }
127}