非常简单的golang小练习,这个问题最大的难点在于求两点的球面距离,所以这实际上是一道立体几何题,当然如果不记得公式咱们可以百度……废话不多说了,直接上代码。
city.go
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 79 80 81 82 83 84 85 86 87 88 89 90 91
| package city import ( "encoding/csv" "math" "os" "strconv" ) var ( radius = float64(6371000) rad = math.Pi / 180.0 ) type info struct { name string lng float64 lat float64 } type Manager struct { citys map[string]*info } func NewCityConfig(file string) (c *Manager, err error) { c = &Manager{} c.citys, err = c.parseCityInfo(file) if err != nil { return } return } func (c *Manager) GetDistance(city1 string, city2 string) (dist float64, err error) { c1 := c.citys[city1] c2 := c.citys[city2] if c1 == nil || c2 == nil { return 0.0, nil } dist = c.earthDistance(c1, c2) return } func (c *Manager) earthDistance(city1 *info, city2 *info) float64 { lng1 := city1.lng * rad lat1 := city1.lat * rad lng2 := city2.lng * rad lat2 := city2.lat * rad theta := lng2 - lng1 dist := math.Acos(math.Sin(lat1)*math.Sin(lat2) + math.Cos(lat1)*math.Cos(lat2)*math.Cos(theta)) return dist * radius } func (c *Manager) parseCityInfo(filepath string) (locations map[string]*info, err error) { f, err := os.Open(filepath) if err != nil { return nil, err } defer f.Close() reader := csv.NewReader(f) record, err := reader.ReadAll() if err != nil { return nil, err } locations = make(map[string]*info, 0) for _, a := range record { city := &info{name: a[0]} lng, err := strconv.ParseFloat(a[1], 64) if err == nil { city.lng = lng } lat, err := strconv.ParseFloat(a[2], 64) if err == nil { city.lat = lat } locations[city.name] = city } return locations, nil }
|
城市坐标使用csv格式存储:
city_info.csv
1 2 3 4 5 6 7 8 9 10 11
| 上海上海,121.48,31.22 上海嘉定,121.24,31.4 上海宝山,121.48,31.41 上海川沙,121.7,31.19 上海南汇,121.76,31.05 上海奉贤,121.46,30.92 上海松江,121.24,31 上海金山,121.16,30.89 上海青浦,121.1,31.15 上海崇明,121.4,31.73 ……
|
city_test.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package city import ( "fmt" "testing" ) func TestGetDistance(t *testing.T) { c, err := NewCityConfig("city_info.csv") if err != nil { t.Errorf("new city config failed, %v", err) } var dist float64 dist, err = c.GetDistance("广东深圳", "广东汕头") if err != nil { t.Errorf("GetDistance, %v", err) } fmt.Printf("distance of `广东深圳` and `广东汕头`: %.1f(m)\n", dist) }
|
go test
一下,得到如下结果:
1 2 3
| distance of `广东深圳` and `广东汕头`: 281492.0(m) PASS ok citydistant 0.410s
|
百度地图测距结果:
代码已放在github上:https://github.com/7byte/citydistant