geocode: if Google returns a whole-world geometry, use its viewport instead

Change-Id: Iec4abf2ad117ab37a3f23fedc12e6e7b3943fc4e
This commit is contained in:
Brad Fitzpatrick 2014-01-25 09:26:18 -08:00
parent 9abba638a0
commit 466f166817
2 changed files with 98 additions and 16 deletions

View File

@ -88,7 +88,8 @@ type googleResult struct {
} }
type googleGeometry struct { type googleGeometry struct {
Bounds *Rect `json:"bounds"` Bounds *Rect `json:"bounds"`
Viewport *Rect `json:"viewport"`
} }
func decodeGoogleResponse(r io.Reader) (rects []Rect, err error) { func decodeGoogleResponse(r io.Reader) (rects []Rect, err error) {
@ -98,7 +99,17 @@ func decodeGoogleResponse(r io.Reader) (rects []Rect, err error) {
} }
for _, res := range resTop.Results { for _, res := range resTop.Results {
if res.Geometry != nil && res.Geometry.Bounds != nil { if res.Geometry != nil && res.Geometry.Bounds != nil {
rects = append(rects, *res.Geometry.Bounds) r := res.Geometry.Bounds
if r.NorthEast.Lat == 90 && r.NorthEast.Long == 180 &&
r.SouthWest.Lat == -90 && r.SouthWest.Long == -180 {
// Google sometimes returns a "whole world" rect for large addresses (like "USA")
// so instead use the viewport in that case.
if res.Geometry.Viewport != nil {
rects = append(rects, *res.Geometry.Viewport)
}
} else {
rects = append(rects, *r)
}
} }
} }
return return

View File

@ -24,22 +24,45 @@ import (
) )
func TestDecodeGoogleResponse(t *testing.T) { func TestDecodeGoogleResponse(t *testing.T) {
rects, err := decodeGoogleResponse(strings.NewReader(googleRes)) tests := []struct {
if err != nil { name string
t.Fatal(err) res string
} want []Rect
want := []Rect{ }{
Rect{ {
NorthEast: LatLong{pf("56.009657"), pf("37.945661")}, name: "moscow",
SouthWest: LatLong{pf("55.48992699999999"), pf("37.319329")}, res: googleMoscow,
want: []Rect{
Rect{
NorthEast: LatLong{pf("56.009657"), pf("37.945661")},
SouthWest: LatLong{pf("55.48992699999999"), pf("37.319329")},
},
Rect{
NorthEast: LatLong{pf("46.758882"), pf("-116.962068")},
SouthWest: LatLong{pf("46.710912"), pf("-117.039698")},
},
},
}, },
Rect{ {
NorthEast: LatLong{pf("46.758882"), pf("-116.962068")}, name: "usa",
SouthWest: LatLong{pf("46.710912"), pf("-117.039698")}, res: googleUSA,
want: []Rect{
Rect{
NorthEast: LatLong{pf("49.38"), pf("-66.94")},
SouthWest: LatLong{pf("25.82"), pf("-124.39")},
},
},
}, },
} }
if !reflect.DeepEqual(rects, want) { for _, tt := range tests {
t.Errorf("wrong rects\n Got %#v\nWant %#v", rects, want) rects, err := decodeGoogleResponse(strings.NewReader(tt.res))
if err != nil {
t.Errorf("Decoding %s: %v", tt.name, err)
continue
}
if !reflect.DeepEqual(rects, tt.want) {
t.Errorf("Test %s: wrong rects\n Got %#v\nWant %#v", tt.name, rects, tt.want)
}
} }
} }
@ -52,7 +75,7 @@ func pf(s string) float64 {
return v return v
} }
var googleRes = ` var googleMoscow = `
{ {
"results" : [ "results" : [
{ {
@ -165,3 +188,51 @@ var googleRes = `
"status" : "OK" "status" : "OK"
} }
` `
// Response for "usa".
// Note the geometry bounds covering the whole world. In this case, use the viewport instead.
var googleUSA = `
{
"results" : [
{
"address_components" : [
{
"long_name" : "United States",
"short_name" : "US",
"types" : [ "country", "political" ]
}
],
"formatted_address" : "United States",
"geometry" : {
"bounds" : {
"northeast" : {
"lat" : 90,
"lng" : 180
},
"southwest" : {
"lat" : -90,
"lng" : -180
}
},
"location" : {
"lat" : 37.09024,
"lng" : -95.712891
},
"location_type" : "APPROXIMATE",
"viewport" : {
"northeast" : {
"lat" : 49.38,
"lng" : -66.94
},
"southwest" : {
"lat" : 25.82,
"lng" : -124.39
}
}
},
"types" : [ "country", "political" ]
}
],
"status" : "OK"
}
`