Backend: Refactor maps and osm packages

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2019-12-20 12:04:26 +01:00
parent 52b57e9fba
commit 1d0b1f8533
4 changed files with 125 additions and 58 deletions

View file

@ -1,48 +1,70 @@
package maps package maps
import ( import (
"errors"
"strings" "strings"
olc "github.com/google/open-location-code/go" olc "github.com/google/open-location-code/go"
"github.com/photoprism/photoprism/internal/maps/osm" "github.com/photoprism/photoprism/internal/maps/osm"
) )
const SourceOSM = "osm"
// Photo location // Photo location
type Location struct { type Location struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
Lat float64 LocLat float64
Lng float64 LocLng float64
Title string LocTitle string
City string LocCity string
Suburb string LocSuburb string
State string LocState string
Country string LocCountry string
Region string LocRegion string
Label string LocLabel string
LocSource string
} }
func (l *Location) FromOSM(o osm.Location) { func (l *Location) Query(lat, lng float64) error {
l.Lat = o.Latitude() return l.QueryOpenStreetMap(lat, lng)
l.Lng = o.Longitude() }
if l.Unknown() { func (l *Location) QueryOpenStreetMap(lat, lng float64) error {
log.Warnf("maps: unknown location") o, err := osm.FindLocation(lat, lng)
l.Label = "unknown"
return if err != nil {
return err
} }
l.ID = olc.Encode(l.Lat, l.Lng, 11) return l.OpenStreetMap(o)
l.Title = o.Title() }
l.City = o.City()
l.Suburb = o.Suburb()
l.State = o.State() func (l *Location) OpenStreetMap(o osm.Location) error {
l.Country = o.Country() l.LocSource = SourceOSM
l.Region = l.region()
l.Label = o.Label() l.LocLat = o.Latitude()
l.LocLng = o.Longitude()
if l.Unknown() {
l.LocLabel = "unknown"
return errors.New("maps: unknown location")
}
l.ID = olc.Encode(l.LocLat, l.LocLng, 11)
l.LocTitle = o.Title()
l.LocCity = o.City()
l.LocSuburb = o.Suburb()
l.LocState = o.State()
l.LocCountry = o.Country()
l.LocRegion = l.region()
l.LocLabel = o.Label()
return nil
} }
func (l *Location) Unknown() bool { func (l *Location) Unknown() bool {
if l.Lng == 0.0 && l.Lat == 0.0 { if l.LocLng == 0.0 && l.LocLat == 0.0 {
return true return true
} }
@ -54,17 +76,17 @@ func (l *Location) region() string {
return "Unknown" return "Unknown"
} }
var countryName = Countries[l.Country] var countryName = Countries[l.LocCountry]
var loc []string var loc []string
shortCountry := len([]rune(countryName)) <= 20 shortCountry := len([]rune(countryName)) <= 20
shortCity := len([]rune(l.City)) <= 20 shortCity := len([]rune(l.LocCity)) <= 20
if shortCity && l.City != "" { if shortCity && l.LocCity != "" {
loc = append(loc, l.City) loc = append(loc, l.LocCity)
} }
if shortCountry && l.State != "" && l.City != l.State { if shortCountry && l.LocState != "" && l.LocCity != l.LocState {
loc = append(loc, l.State) loc = append(loc, l.LocState)
} }
if countryName != "" { if countryName != "" {

View file

@ -7,7 +7,39 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestFindLocation(t *testing.T) { func TestLocation_Query(t *testing.T) {
t.Run("BerlinFernsehturm", func(t *testing.T) {
lat := 52.5208
lng := 13.40953
var l Location
if err := l.Query(lat, lng); err != nil {
t.Fatal(err)
}
assert.Equal(t, "Fernsehturm Berlin", l.LocTitle)
assert.Equal(t, "Berlin, Germany", l.LocRegion)
})
}
func TestLocation_QueryOpenStreetMap(t *testing.T) {
t.Run("BerlinFernsehturm", func(t *testing.T) {
lat := 52.5208
lng := 13.40953
var l Location
if err := l.QueryOpenStreetMap(lat, lng); err != nil {
t.Fatal(err)
}
assert.Equal(t, "Fernsehturm Berlin", l.LocTitle)
assert.Equal(t, "Berlin, Germany", l.LocRegion)
})
}
func TestLocation_OpenStreetMap(t *testing.T) {
t.Run("BerlinFernsehturm", func(t *testing.T) { t.Run("BerlinFernsehturm", func(t *testing.T) {
lat := 52.5208 lat := 52.5208
lng := 13.40953 lng := 13.40953
@ -18,7 +50,6 @@ func TestFindLocation(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
assert.False(t, o.Cached)
assert.Equal(t, 189675302, o.PlaceID) assert.Equal(t, 189675302, o.PlaceID)
assert.Equal(t, "Fernsehturm Berlin", o.Name) assert.Equal(t, "Fernsehturm Berlin", o.Name)
assert.Equal(t, "10178", o.Address.Postcode) assert.Equal(t, "10178", o.Address.Postcode)
@ -28,10 +59,12 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "Fernsehturm Berlin", l.Title) assert.Equal(t, "Fernsehturm Berlin", l.LocTitle)
assert.Equal(t, "Berlin, Germany", l.Region) assert.Equal(t, "Berlin, Germany", l.LocRegion)
}) })
t.Run("SantaMonica", func(t *testing.T) { t.Run("SantaMonica", func(t *testing.T) {
@ -54,10 +87,12 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "Santa Monica Pier", l.Title) assert.Equal(t, "Santa Monica Pier", l.LocTitle)
assert.Equal(t, "Santa Monica, California, USA", l.Region) assert.Equal(t, "Santa Monica, California, USA", l.LocRegion)
}) })
t.Run("AirportZurich", func(t *testing.T) { t.Run("AirportZurich", func(t *testing.T) {
@ -81,10 +116,12 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "Airport", l.Title) assert.Equal(t, "Airport", l.LocTitle)
assert.Equal(t, "Kloten, Zurich, Switzerland", l.Region) assert.Equal(t, "Kloten, Zurich, Switzerland", l.LocRegion)
}) })
t.Run("AirportTegel", func(t *testing.T) { t.Run("AirportTegel", func(t *testing.T) {
@ -108,10 +145,12 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "Airport", l.Title) assert.Equal(t, "Airport", l.LocTitle)
assert.Equal(t, "Berlin, Germany", l.Region) assert.Equal(t, "Berlin, Germany", l.LocRegion)
}) })
t.Run("PinkBeach", func(t *testing.T) { t.Run("PinkBeach", func(t *testing.T) {
@ -135,11 +174,13 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "8G757G9P+R5C", l.ID) assert.Equal(t, "8G757G9P+R5C", l.ID)
assert.Equal(t, "Pink Beach", l.Title) assert.Equal(t, "Pink Beach", l.LocTitle)
assert.Equal(t, "Crete, Greece", l.Region) assert.Equal(t, "Crete, Greece", l.LocRegion)
}) })
t.Run("NewJersey", func(t *testing.T) { t.Run("NewJersey", func(t *testing.T) {
@ -163,11 +204,13 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "87G7PXV2+4G9", l.ID) assert.Equal(t, "87G7PXV2+4G9", l.ID)
assert.Equal(t, "", l.Title) assert.Equal(t, "", l.LocTitle)
assert.Equal(t, "Jersey City, New Jersey, USA", l.Region) assert.Equal(t, "Jersey City, New Jersey, USA", l.LocRegion)
}) })
t.Run("SouthAfrica", func(t *testing.T) { t.Run("SouthAfrica", func(t *testing.T) {
@ -191,10 +234,12 @@ func TestFindLocation(t *testing.T) {
var l Location var l Location
l.FromOSM(o) if err := l.OpenStreetMap(o); err != nil {
t.Fatal(err)
}
assert.Equal(t, "4GWF24FX+F5H", l.ID) assert.Equal(t, "4GWF24FX+F5H", l.ID)
assert.Equal(t, "Route R411", l.Title) assert.Equal(t, "Route R411", l.LocTitle)
assert.Equal(t, "Eastern Cape, South Africa", l.Region) assert.Equal(t, "Eastern Cape, South Africa", l.LocRegion)
}) })
} }

View file

@ -29,13 +29,13 @@ var ReverseLookupURL = "https://nominatim.openstreetmap.org/reverse?lat=%f&lon=%
// API docs see https://wiki.openstreetmap.org/wiki/Nominatim#Reverse_Geocoding // API docs see https://wiki.openstreetmap.org/wiki/Nominatim#Reverse_Geocoding
func FindLocation(lat, lng float64) (result Location, err error) { func FindLocation(lat, lng float64) (result Location, err error) {
if lat == 0.0 || lng == 0.0 { if lat == 0.0 || lng == 0.0 {
return result, fmt.Errorf("osm: skipping lat %f / lng %f", lat, lng) return result, fmt.Errorf("osm: skipping lat %f, lng %f", lat, lng)
} }
point := geocache.GeoPoint{Latitude: lat, Longitude: lng} point := geocache.GeoPoint{Latitude: lat, Longitude: lng}
if hit, ok := geoCache.Get(point); ok { if hit, ok := geoCache.Get(point); ok {
log.Debugf("osm: cache hit for lat %f / lng %f", lat, lng) log.Debugf("osm: cache hit for lat %f, lng %f", lat, lng)
result = hit.(Location) result = hit.(Location)
result.Cached = true result.Cached = true
return result, nil return result, nil

View file

@ -73,7 +73,7 @@ func TestFindLocation(t *testing.T) {
t.Fatal("err should not be nil") t.Fatal("err should not be nil")
} }
assert.Equal(t, "osm: skipping lat 0.000000 / lng 0.000000", err.Error()) assert.Equal(t, "osm: skipping lat 0.000000, lng 0.000000", err.Error())
assert.False(t, l.Cached) assert.False(t, l.Cached)
}) })
} }