mirror of
https://github.com/imjasonh/staticmaps
synced 2026-07-09 03:15:09 +00:00
Add geocode and reverse geocode
This commit is contained in:
parent
3486e9bff9
commit
c986c5df38
4 changed files with 160 additions and 1 deletions
|
|
@ -178,6 +178,10 @@ type Bounds struct {
|
|||
Southwest LatLng `json:"southwest"`
|
||||
}
|
||||
|
||||
func (b Bounds) String() string {
|
||||
return fmt.Sprintf("%s|%s", b.Northeast, b.Southwest)
|
||||
}
|
||||
|
||||
type Duration struct {
|
||||
Value int64 `json:"value"`
|
||||
Text string `json:"text"`
|
||||
|
|
|
|||
|
|
@ -68,6 +68,6 @@ type ElevationResponse struct {
|
|||
Elevation float64 `json:"elevation"`
|
||||
Location LatLng `json:"location"`
|
||||
Resolution float64 `json:"resolution"`
|
||||
}
|
||||
} `json:"results"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
|
|
|||
134
geocode.go
Normal file
134
geocode.go
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
package maps
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
ComponentRoute = "route"
|
||||
ComponentLocality = "locality"
|
||||
ComponentAdministrativeArea = "administrative_area"
|
||||
ComponentPostalCode = "postal_code"
|
||||
ComponentCountry = "country"
|
||||
|
||||
LocationTypeRooftop = "ROOFTOP"
|
||||
LocationTypeRangeInterpolated = "RANGE_INTERPOLATED"
|
||||
LocationTypeGeometricCenter = "GEOMETRIC_CENTER"
|
||||
LocationTypeApproximate = "APPROXIMATE"
|
||||
|
||||
// TODO: enums for https://developers.google.com/maps/documentation/geocoding/#Types
|
||||
)
|
||||
|
||||
func (c Client) Geocode(opts *GeocodeOpts) (*GeocodeResponse, error) {
|
||||
var r GeocodeResponse
|
||||
if err := c.doDecode(baseURL+geocode(opts), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func geocode(opts *GeocodeOpts) string {
|
||||
p := url.Values{}
|
||||
opts.update(p)
|
||||
return "geocode/json?" + p.Encode()
|
||||
}
|
||||
|
||||
type GeocodeOpts struct {
|
||||
Address Address
|
||||
Components []Component
|
||||
Language, Region string
|
||||
Bounds *Bounds
|
||||
}
|
||||
|
||||
type Component struct {
|
||||
Key, Value string
|
||||
}
|
||||
|
||||
func (c Component) encode() string {
|
||||
return fmt.Sprintf("%s:%s", c.Key, c.Value)
|
||||
}
|
||||
|
||||
func encodeComponents(cs []Component) string {
|
||||
s := make([]string, len(cs))
|
||||
for i, c := range cs {
|
||||
s[i] = c.encode()
|
||||
}
|
||||
return strings.Join(s, "|")
|
||||
}
|
||||
|
||||
func (g *GeocodeOpts) update(p url.Values) {
|
||||
if g == nil {
|
||||
return
|
||||
}
|
||||
if string(g.Address) != "" {
|
||||
p.Set("address", g.Address.Location())
|
||||
}
|
||||
if g.Components != nil {
|
||||
p.Set("components", encodeComponents(g.Components))
|
||||
}
|
||||
if g.Language != "" {
|
||||
p.Set("language", g.Language)
|
||||
}
|
||||
if g.Region != "" {
|
||||
p.Set("region", g.Region)
|
||||
}
|
||||
if g.Bounds != nil {
|
||||
p.Set("bounds", g.Bounds.String())
|
||||
}
|
||||
}
|
||||
|
||||
type GeocodeResponse struct {
|
||||
Results []struct {
|
||||
AddressComponents []struct {
|
||||
LongName string `json:"long_name"`
|
||||
ShortName string `json:"short_name"`
|
||||
Types []string `json:"types"`
|
||||
} `json:"address_components"`
|
||||
PostcodeLocalities []string `json:"postcode_localities"`
|
||||
FormattedAddress string `json:"formatted_address"`
|
||||
Geometry struct {
|
||||
Location LatLng `json:"location"`
|
||||
LocationType string `json:"location_type"`
|
||||
Viewport Bounds `json:"viewport"`
|
||||
Bounds Bounds `json:"bounds"`
|
||||
} `json:"geometry"`
|
||||
Types []string `json:"types"`
|
||||
PartialMatch string `json:"partial_match"`
|
||||
} `json:"results"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (c Client) ReverseGeocode(ll LatLng, opts *ReverseGeocodeOpts) (*GeocodeResponse, error) {
|
||||
var r GeocodeResponse
|
||||
if err := c.doDecode(baseURL+reversegeocode(ll, opts), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
type ReverseGeocodeOpts struct {
|
||||
Language string
|
||||
ResultTypes []string
|
||||
LocationTypes []string
|
||||
}
|
||||
|
||||
func (r *ReverseGeocodeOpts) update(p url.Values) {
|
||||
if r == nil {
|
||||
return
|
||||
}
|
||||
if r.ResultTypes != nil {
|
||||
p.Set("result_type", strings.Join(r.ResultTypes, "|"))
|
||||
}
|
||||
if r.LocationTypes != nil {
|
||||
p.Set("location_type", strings.Join(r.LocationTypes, "|"))
|
||||
}
|
||||
}
|
||||
|
||||
func reversegeocode(ll LatLng, opts *ReverseGeocodeOpts) string {
|
||||
p := url.Values{}
|
||||
p.Set("latlng", ll.String())
|
||||
opts.update(p)
|
||||
return "geocode/json?" + p.Encode()
|
||||
}
|
||||
21
maps_test.go
21
maps_test.go
|
|
@ -138,3 +138,24 @@ func TestElevation(t *testing.T) {
|
|||
}
|
||||
t.Logf("%v", r)
|
||||
}
|
||||
|
||||
func TestGeocode(t *testing.T) {
|
||||
c := NewClient("")
|
||||
opts := &GeocodeOpts{
|
||||
Address: Address("1600 Amphitheatre Parkway, Mountain View, CA"),
|
||||
}
|
||||
t.Logf("%s", baseURL+geocode(opts))
|
||||
r, err := c.Geocode(opts)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("%v", r)
|
||||
|
||||
ll := LatLng{40.714224, -73.961452}
|
||||
t.Logf("%s", baseURL+reversegeocode(ll, nil))
|
||||
r, err = c.ReverseGeocode(ll, nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
t.Logf("%v", r)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue