Backend: Refactor maps and osm packages
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
52b57e9fba
commit
1d0b1f8533
|
@ -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 != "" {
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue