1
0
Fork 0
mirror of https://github.com/imjasonh/staticmaps synced 2026-07-08 19:05:09 +00:00
staticmaps/geocode.go

134 lines
3.1 KiB
Go

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()
}