94 lines
2.2 KiB
Go
94 lines
2.2 KiB
Go
package geo
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
// ExtractGeoPoint takes an arbitrary interface{} and tries it's best to
|
|
// interpret it is as geo point
|
|
func ExtractGeoPoint(thing interface{}) (lon, lat float64, success bool) {
|
|
var foundLon, foundLat bool
|
|
// is it a map
|
|
if l, ok := thing.(map[string]interface{}); ok {
|
|
if lval, ok := l["lon"]; ok {
|
|
lon, foundLon = extractNumericVal(lval)
|
|
} else if lval, ok := l["lng"]; ok {
|
|
lon, foundLon = extractNumericVal(lval)
|
|
}
|
|
if lval, ok := l["lat"]; ok {
|
|
lat, foundLat = extractNumericVal(lval)
|
|
}
|
|
return lon, lat, foundLon && foundLat
|
|
}
|
|
|
|
// now try reflection on struct fields
|
|
thingVal := reflect.ValueOf(thing)
|
|
thingTyp := thingVal.Type()
|
|
if thingVal.IsValid() && thingVal.Kind() == reflect.Struct {
|
|
for i := 0; i < thingVal.NumField(); i++ {
|
|
field := thingTyp.Field(i)
|
|
fieldName := field.Name
|
|
if strings.HasPrefix(strings.ToLower(fieldName), "lon") {
|
|
if thingVal.Field(i).CanInterface() {
|
|
fieldVal := thingVal.Field(i).Interface()
|
|
lon, foundLon = extractNumericVal(fieldVal)
|
|
}
|
|
}
|
|
if strings.HasPrefix(strings.ToLower(fieldName), "lng") {
|
|
if thingVal.Field(i).CanInterface() {
|
|
fieldVal := thingVal.Field(i).Interface()
|
|
lon, foundLon = extractNumericVal(fieldVal)
|
|
}
|
|
}
|
|
if strings.HasPrefix(strings.ToLower(fieldName), "lat") {
|
|
if thingVal.Field(i).CanInterface() {
|
|
fieldVal := thingVal.Field(i).Interface()
|
|
lat, foundLat = extractNumericVal(fieldVal)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// last hope, some interfaces
|
|
// lon
|
|
if l, ok := thing.(loner); ok {
|
|
lon = l.Lon()
|
|
foundLon = true
|
|
} else if l, ok := thing.(lnger); ok {
|
|
lon = l.Lng()
|
|
foundLon = true
|
|
}
|
|
// lat
|
|
if l, ok := thing.(later); ok {
|
|
lat = l.Lat()
|
|
foundLat = true
|
|
}
|
|
|
|
return lon, lat, foundLon && foundLat
|
|
}
|
|
|
|
// extract numeric value (if possible) and returna s float64
|
|
func extractNumericVal(v interface{}) (float64, bool) {
|
|
switch v := v.(type) {
|
|
case float64:
|
|
return v, true
|
|
case float32:
|
|
return float64(v), true
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// various support interfaces which can be used to find lat/lon
|
|
type loner interface {
|
|
Lon() float64
|
|
}
|
|
|
|
type later interface {
|
|
Lat() float64
|
|
}
|
|
|
|
type lnger interface {
|
|
Lng() float64
|
|
}
|