Places: Support sub-km distances when searching for locations #3558
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
d7e21f449f
commit
33bf0cede6
7 changed files with 39 additions and 16 deletions
|
@ -48,7 +48,7 @@ type SearchPhotos struct {
|
|||
Olc string `form:"olc" example:"olc:8FWCHX7W+" notes:"OLC Position (Open Location Code)"`
|
||||
Lat float64 `form:"lat" example:"lat:41.894043" notes:"GPS Position (Latitude)"`
|
||||
Lng float64 `form:"lng" example:"lng:-87.62448" notes:"GPS Position (Longitude)"`
|
||||
Dist uint `form:"dist" example:"dist:50" notes:"Distance to Position (km)"`
|
||||
Dist float64 `form:"dist" example:"dist:50" notes:"Distance to Position (km)"`
|
||||
Latlng string `form:"latlng" notes:"GPS Bounding Box (Lat N, Lng E, Lat S, Lng W)"`
|
||||
Fmin float32 `form:"fmin" notes:"F-number (min)"`
|
||||
Fmax float32 `form:"fmax" notes:"F-number (max)"`
|
||||
|
|
|
@ -46,7 +46,7 @@ type SearchPhotosGeo struct {
|
|||
Olc string `form:"olc" example:"olc:8FWCHX7W+" notes:"OLC Position (Open Location Code)"`
|
||||
Lat float64 `form:"lat" example:"lat:41.894043" notes:"GPS Position (Latitude)"`
|
||||
Lng float64 `form:"lng" example:"lng:-87.62448" notes:"GPS Position (Longitude)"`
|
||||
Dist uint `form:"dist" example:"dist:50" notes:"Distance to Position (km)"`
|
||||
Dist float64 `form:"dist" example:"dist:50" notes:"Distance to Position (km)"`
|
||||
Latlng string `form:"latlng" notes:"GPS Bounding Box (Lat N, Lng E, Lat S, Lng W)"`
|
||||
Person string `form:"person"` // Alias for Subject
|
||||
Subjects string `form:"subjects"` // Text
|
||||
|
|
|
@ -107,7 +107,7 @@ func TestSearchPhotosGeo(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "fooBar baz", form.Query)
|
||||
assert.Equal(t, time.Date(2019, 01, 15, 0, 0, 0, 0, time.UTC), form.Before)
|
||||
assert.Equal(t, uint(0x61a8), form.Dist)
|
||||
assert.Equal(t, 25000.0, form.Dist)
|
||||
assert.Equal(t, 33.45343166666667, form.Lat)
|
||||
})
|
||||
t.Run("valid query path empty folder not empty", func(t *testing.T) {
|
||||
|
@ -125,7 +125,7 @@ func TestSearchPhotosGeo(t *testing.T) {
|
|||
assert.Equal(t, "test", form.Path)
|
||||
assert.Equal(t, "", form.Folder)
|
||||
assert.Equal(t, time.Date(2019, 01, 15, 0, 0, 0, 0, time.UTC), form.Before)
|
||||
assert.Equal(t, uint(0x61a8), form.Dist)
|
||||
assert.Equal(t, 25000.0, form.Dist)
|
||||
assert.Equal(t, 33.45343166666667, form.Lat)
|
||||
})
|
||||
t.Run("valid query with filter", func(t *testing.T) {
|
||||
|
|
|
@ -82,14 +82,14 @@ func GPSBounds(bounds string) (latN, lngE, latS, lngW float32, err error) {
|
|||
}
|
||||
|
||||
// GPSLatRange returns a range based on the specified latitude and distance in km, or an error otherwise.
|
||||
func GPSLatRange(lat float64, km uint) (latN, latS float32, err error) {
|
||||
func GPSLatRange(lat float64, km float64) (latN, latS float32, err error) {
|
||||
// Latitude (from +90 to -90 degrees).
|
||||
if lat == 0 || lat < -90 || lat > 90 {
|
||||
return 0, 0, fmt.Errorf("invalid latitude")
|
||||
}
|
||||
|
||||
// Approximate range radius.
|
||||
r := float64(km) * 0.75
|
||||
r := km * 0.75
|
||||
|
||||
// Approximate longitude range,
|
||||
// see https://en.wikipedia.org/wiki/Decimal_degrees
|
||||
|
@ -108,14 +108,14 @@ func GPSLatRange(lat float64, km uint) (latN, latS float32, err error) {
|
|||
}
|
||||
|
||||
// GPSLngRange returns a range based on the specified longitude and distance in km, or an error otherwise.
|
||||
func GPSLngRange(lng float64, km uint) (lngE, lngW float32, err error) {
|
||||
func GPSLngRange(lng float64, km float64) (lngE, lngW float32, err error) {
|
||||
// Longitude (from -180 to +180 degrees).
|
||||
if lng == 0 || lng < -180 || lng > 180 {
|
||||
return 0, 0, fmt.Errorf("invalid longitude")
|
||||
}
|
||||
|
||||
// Approximate range radius.
|
||||
r := float64(km) * 0.75
|
||||
r := km * 0.75
|
||||
|
||||
// Approximate longitude range,
|
||||
// see https://en.wikipedia.org/wiki/Decimal_degrees
|
||||
|
|
|
@ -5,9 +5,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
DistLimit uint = 5000
|
||||
ScopeDistLimit uint = 50
|
||||
DefaultDist uint = 2
|
||||
DistLimit float64 = 5000
|
||||
ScopeDistLimit float64 = 50
|
||||
DefaultDist float64 = 2
|
||||
)
|
||||
|
||||
// Deg returns the approximate distance in decimal degrees,
|
||||
|
|
|
@ -3,9 +3,9 @@ package s2
|
|||
// DefaultLevel specifies the default S2 cell size.
|
||||
var DefaultLevel = 21
|
||||
|
||||
// Level returns the S2 cell level based on the approximate cell size in km.
|
||||
// see https://s2geometry.io/resources/s2cell_statistics.html
|
||||
func Level(km uint) (level int) {
|
||||
// Level returns the applicable cell level based on the search range in km,
|
||||
// see https://s2geometry.io/resources/s2cell_statistics.html.
|
||||
func Level(km float64) (level int) {
|
||||
switch {
|
||||
case km >= 7842:
|
||||
return 0
|
||||
|
@ -35,7 +35,21 @@ func Level(km uint) (level int) {
|
|||
return 12
|
||||
case km >= 1:
|
||||
return 13
|
||||
default:
|
||||
case km >= 0.425:
|
||||
return 14
|
||||
case km >= 0.212:
|
||||
return 15
|
||||
case km >= 0.106:
|
||||
return 16
|
||||
case km >= 0.053:
|
||||
return 17
|
||||
case km >= 0.027:
|
||||
return 18
|
||||
case km >= 0.013:
|
||||
return 19
|
||||
case km >= 0.007:
|
||||
return 20
|
||||
default:
|
||||
return DefaultLevel
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,8 +109,17 @@ func TestLevel(t *testing.T) {
|
|||
t.Run("150", func(t *testing.T) {
|
||||
assert.Equal(t, 6, Level(150))
|
||||
})
|
||||
t.Run("0.25", func(t *testing.T) {
|
||||
assert.Equal(t, 15, Level(0.25))
|
||||
})
|
||||
t.Run("0.1", func(t *testing.T) {
|
||||
assert.Equal(t, 17, Level(0.1))
|
||||
})
|
||||
t.Run("0", func(t *testing.T) {
|
||||
assert.Equal(t, 14, Level(0))
|
||||
assert.Equal(t, 21, Level(0))
|
||||
})
|
||||
t.Run("Negative", func(t *testing.T) {
|
||||
assert.Equal(t, 21, Level(-1))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue