mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
Places: Use float64 for all coordinates to avoid rounding errors #3953
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
82
frontend/package-lock.json
generated
82
frontend/package-lock.json
generated
@@ -2886,9 +2886,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/regexpp": {
|
||||
"version": "4.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz",
|
||||
"integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==",
|
||||
"version": "4.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz",
|
||||
"integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
|
||||
@@ -3576,9 +3576,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
|
||||
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
|
||||
"version": "22.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
||||
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
@@ -3621,42 +3621,42 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.4.tgz",
|
||||
"integrity": "sha512-oNwn+BAt3n9dK9uAYvI+XGlutwuTq/wfj4xCBaZCqwwVIGtD7D6ViihEbyYZrDHIHTDE3Q6oL3/hqmAyFEy9DQ==",
|
||||
"version": "3.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.5.tgz",
|
||||
"integrity": "sha512-ZrxcY8JMoV+kgDrmRwlDufz0SjDZ7jfoNZiIBluAACMBmgr55o/jTbxnyrccH6VSJXnFaDI4Ik1UFCiq9r8i7w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.25.3",
|
||||
"@vue/shared": "3.5.4",
|
||||
"@vue/shared": "3.5.5",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.4.tgz",
|
||||
"integrity": "sha512-yP9RRs4BDLOLfldn6ah+AGCNovGjMbL9uHvhDHf5wan4dAHLnFGOkqtfE7PPe4HTXIqE7l/NILdYw53bo1C8jw==",
|
||||
"version": "3.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.5.tgz",
|
||||
"integrity": "sha512-HSvK5q1gmBbxRse3S0Wt34RcKuOyjDJKDDMuF3i7NC+QkDFrbAqw8NnrEm/z7zFDxWZa4/5eUwsBOMQzm1RHBA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.5.4",
|
||||
"@vue/shared": "3.5.4"
|
||||
"@vue/compiler-core": "3.5.5",
|
||||
"@vue/shared": "3.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.4.tgz",
|
||||
"integrity": "sha512-P+yiPhL+NYH7m0ZgCq7AQR2q7OIE+mpAEgtkqEeH9oHSdIRvUO+4X6MPvblJIWcoe4YC5a2Gdf/RsoyP8FFiPQ==",
|
||||
"version": "3.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.5.tgz",
|
||||
"integrity": "sha512-MzBHDxwZhgQPHrwJ5tj92gdTYRCuPDSZr8PY3+JFv8cv2UD5/WayH5yo0kKCkKfrtJhc39jNSMityHrkMSbfnA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.25.3",
|
||||
"@vue/compiler-core": "3.5.4",
|
||||
"@vue/compiler-dom": "3.5.4",
|
||||
"@vue/compiler-ssr": "3.5.4",
|
||||
"@vue/shared": "3.5.4",
|
||||
"@vue/compiler-core": "3.5.5",
|
||||
"@vue/compiler-dom": "3.5.5",
|
||||
"@vue/compiler-ssr": "3.5.5",
|
||||
"@vue/shared": "3.5.5",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.11",
|
||||
"postcss": "^8.4.44",
|
||||
@@ -3664,14 +3664,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.4.tgz",
|
||||
"integrity": "sha512-acESdTXsxPnYr2C4Blv0ggx5zIFMgOzZmYU2UgvIff9POdRGbRNBHRyzHAnizcItvpgerSKQbllUc9USp3V7eg==",
|
||||
"version": "3.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.5.tgz",
|
||||
"integrity": "sha512-oFasHnpv/upubjJEmqiTKQYb4qS3ziJddf4UVWuFw6ebk/QTrTUc+AUoTJdo39x9g+AOQBzhOU0ICCRuUjvkmw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.4",
|
||||
"@vue/shared": "3.5.4"
|
||||
"@vue/compiler-dom": "3.5.5",
|
||||
"@vue/shared": "3.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/component-compiler-utils": {
|
||||
@@ -3749,9 +3749,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.4.tgz",
|
||||
"integrity": "sha512-L2MCDD8l7yC62Te5UUyPVpmexhL9ipVnYRw9CsWfm/BGRL5FwDX4a25bcJ/OJSD3+Hx+k/a8LDKcG2AFdJV3BA==",
|
||||
"version": "3.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.5.tgz",
|
||||
"integrity": "sha512-0KyMXyEgnmFAs6rNUL+6eUHtUCqCaNrVd+AW3MX3LyA0Yry5SA0Km03CDKiOua1x1WWnIr+W9+S0GMFoSDWERQ==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
@@ -6441,9 +6441,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.22",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.22.tgz",
|
||||
"integrity": "sha512-tKYm5YHPU1djz0O+CGJ+oJIvimtsCcwR2Z9w7Skh08lUdyzXY5djods3q+z2JkWdb7tCcmM//eVavSRAiaPRNg==",
|
||||
"version": "1.5.23",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.23.tgz",
|
||||
"integrity": "sha512-mBhODedOXg4v5QWwl21DjM5amzjmI1zw9EPrPK/5Wx7C8jt33bpZNrC7OhHUG3pxRtbLpr3W2dXT+Ph1SsfRZA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
@@ -8089,9 +8089,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/flow-remove-types": {
|
||||
"version": "2.245.2",
|
||||
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.245.2.tgz",
|
||||
"integrity": "sha512-p4rWHk20Vp8/pu9MOVi26r+r8hYpZ1vk+9OsFcJnKc/oUYJBxmTL8/fBlIo4/LJ9aLOrAeHwO1PnSsU6Z7gVsw==",
|
||||
"version": "2.246.0",
|
||||
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-2.246.0.tgz",
|
||||
"integrity": "sha512-x3nZU+07+jRha9IK0Ooym60zpo5DIO4hTc09MTLd5ZPHs/hQ4cKUHNArSrNJSI2agNTY0lMRsV0t7VrGNmAqww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hermes-parser": "0.23.1",
|
||||
@@ -11648,9 +11648,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.45",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.45.tgz",
|
||||
"integrity": "sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==",
|
||||
"version": "8.4.47",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
|
||||
"integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -11668,8 +11668,8 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.7",
|
||||
"picocolors": "^1.0.1",
|
||||
"source-map-js": "^1.2.0"
|
||||
"picocolors": "^1.1.0",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
|
||||
@@ -407,18 +407,6 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// Expand the GPS coordinates if they represent a point or line:
|
||||
// https://github.com/photoprism/photoprism/issues/3953
|
||||
if (latNorth === latSouth) {
|
||||
latNorth = latNorth + 0.0003;
|
||||
latSouth = latSouth - 0.0003;
|
||||
}
|
||||
|
||||
if (lngEast === lngWest) {
|
||||
lngEast = lngEast + 0.0003;
|
||||
lngWest = lngWest - 0.0003;
|
||||
}
|
||||
|
||||
this.selectClusterByCoords(latNorth, lngEast, latSouth, lngWest);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -48,10 +48,10 @@ func CreateUnknownLocation() {
|
||||
}
|
||||
|
||||
// NewCell creates a location using a token extracted from coordinate
|
||||
func NewCell(lat, lng float32) *Cell {
|
||||
func NewCell(lat, lng float64) *Cell {
|
||||
result := &Cell{}
|
||||
|
||||
result.ID = s2.PrefixedToken(float64(lat), float64(lng))
|
||||
result.ID = s2.PrefixedToken(lat, lng)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -183,4 +183,10 @@ var DialectMySQL = Migrations{
|
||||
Stage: "pre",
|
||||
Statements: []string{"ALTER IGNORE TABLE auth_sessions RENAME COLUMN auth_domain TO auth_issuer;"},
|
||||
},
|
||||
{
|
||||
ID: "20240915-000001",
|
||||
Dialect: "mysql",
|
||||
Stage: "main",
|
||||
Statements: []string{"ALTER TABLE photos MODIFY photo_lat DOUBLE;", "ALTER TABLE photos MODIFY photo_lng DOUBLE;"},
|
||||
},
|
||||
}
|
||||
|
||||
2
internal/entity/migrate/mysql/20240915-000001.sql
Normal file
2
internal/entity/migrate/mysql/20240915-000001.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE photos MODIFY photo_lat DOUBLE;
|
||||
ALTER TABLE photos MODIFY photo_lng DOUBLE;
|
||||
@@ -65,8 +65,8 @@ type Photo struct {
|
||||
CellID string `gorm:"type:VARBINARY(42);index;default:'zz'" json:"CellID" yaml:"-"`
|
||||
CellAccuracy int `json:"CellAccuracy" yaml:"CellAccuracy,omitempty"`
|
||||
PhotoAltitude int `json:"Altitude" yaml:"Altitude,omitempty"`
|
||||
PhotoLat float32 `gorm:"type:FLOAT;index;" json:"Lat" yaml:"Lat,omitempty"`
|
||||
PhotoLng float32 `gorm:"type:FLOAT;index;" json:"Lng" yaml:"Lng,omitempty"`
|
||||
PhotoLat float64 `gorm:"type:DOUBLE;index;" json:"Lat" yaml:"Lat,omitempty"`
|
||||
PhotoLng float64 `gorm:"type:DOUBLE;index;" json:"Lng" yaml:"Lng,omitempty"`
|
||||
PhotoCountry string `gorm:"type:VARBINARY(2);index:idx_photos_country_year_month;default:'zz'" json:"Country" yaml:"-"`
|
||||
PhotoYear int `gorm:"index:idx_photos_ymd;index:idx_photos_country_year_month;" json:"Year" yaml:"Year"`
|
||||
PhotoMonth int `gorm:"index:idx_photos_ymd;index:idx_photos_country_year_month;" json:"Month" yaml:"Month"`
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
)
|
||||
|
||||
// SetCoordinates changes the photo lat, lng and altitude if not empty and from an acceptable source.
|
||||
func (m *Photo) SetCoordinates(lat, lng float32, altitude float64, source string) {
|
||||
func (m *Photo) SetCoordinates(lat, lng, altitude float64, source string) {
|
||||
m.SetAltitude(altitude, source)
|
||||
|
||||
if lat == 0.0 && lng == 0.0 {
|
||||
@@ -60,15 +60,15 @@ func (m *Photo) SetPosition(pos geo.Position, source string, force bool) {
|
||||
return
|
||||
}
|
||||
|
||||
if m.CellID != UnknownID && pos.InRange(float64(m.PhotoLat), float64(m.PhotoLng), geo.Meter*50) {
|
||||
if m.CellID != UnknownID && pos.InRange(m.PhotoLat, m.PhotoLng, geo.Meter*50) {
|
||||
log.Debugf("photo: %s keeps position %f, %f", m.String(), m.PhotoLat, m.PhotoLng)
|
||||
} else {
|
||||
if pos.Estimate {
|
||||
pos.Randomize(geo.Meter * 5)
|
||||
}
|
||||
|
||||
m.PhotoLat = float32(pos.Lat)
|
||||
m.PhotoLng = float32(pos.Lng)
|
||||
m.PhotoLat = pos.Lat
|
||||
m.PhotoLng = pos.Lng
|
||||
m.PlaceSrc = source
|
||||
m.CellAccuracy = pos.Accuracy
|
||||
m.SetAltitude(pos.Altitude, source)
|
||||
@@ -261,7 +261,7 @@ func (m *Photo) LoadPlace() error {
|
||||
// Position returns the coordinates as geo.Position.
|
||||
func (m *Photo) Position() geo.Position {
|
||||
return geo.Position{Name: m.String(), Time: m.TakenAt.UTC(),
|
||||
Lat: float64(m.PhotoLat), Lng: float64(m.PhotoLng), Altitude: float64(m.PhotoAltitude)}
|
||||
Lat: m.PhotoLat, Lng: m.PhotoLng, Altitude: float64(m.PhotoAltitude)}
|
||||
}
|
||||
|
||||
// HasLatLng checks if the photo has a latitude and longitude.
|
||||
|
||||
@@ -104,44 +104,44 @@ func TestPhoto_SetAltitude(t *testing.T) {
|
||||
t.Run("ViaSetCoordinates", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(0, 0, 5, SrcManual)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("Update", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetAltitude(5, SrcManual)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("SkipUpdate", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetAltitude(5, SrcEstimate)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("UpdateEmptyAltitude", func(t *testing.T) {
|
||||
m := Photo{ID: 1, PlaceSrc: SrcMeta, PhotoLat: float32(1.234), PhotoLng: float32(4.321), PhotoAltitude: 0}
|
||||
m := Photo{ID: 1, PlaceSrc: SrcMeta, PhotoLat: float64(1.234), PhotoLng: float64(4.321), PhotoAltitude: 0}
|
||||
|
||||
m.SetAltitude(-5, SrcAuto)
|
||||
assert.Equal(t, 0, m.PhotoAltitude)
|
||||
@@ -153,7 +153,7 @@ func TestPhoto_SetAltitude(t *testing.T) {
|
||||
assert.Equal(t, -5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("ZeroAltitudeManual", func(t *testing.T) {
|
||||
m := Photo{ID: 1, PlaceSrc: SrcManual, PhotoLat: float32(1.234), PhotoLng: float32(4.321), PhotoAltitude: 5}
|
||||
m := Photo{ID: 1, PlaceSrc: SrcManual, PhotoLat: 1.234, PhotoLng: 4.321, PhotoAltitude: 5}
|
||||
|
||||
m.SetAltitude(0, SrcManual)
|
||||
assert.Equal(t, 0, m.PhotoAltitude)
|
||||
@@ -164,78 +164,78 @@ func TestPhoto_SetCoordinates(t *testing.T) {
|
||||
t.Run("empty coordinates", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(0, 0, 5, SrcManual)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("same source new values", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(5.555, 5.555, 5, SrcMeta)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLat)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLng)
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("different source lower priority", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(5.555, 5.555, 5, SrcName)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("different source equal priority", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(5.555, 5.555, 5, SrcKeyword)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLat)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLng)
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("different source higher priority", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo21")
|
||||
assert.Equal(t, SrcEstimate, m.PlaceSrc)
|
||||
assert.Equal(t, float32(0), m.PhotoLat)
|
||||
assert.Equal(t, float32(0), m.PhotoLng)
|
||||
assert.Equal(t, 0.0, m.PhotoLat)
|
||||
assert.Equal(t, 0.0, m.PhotoLng)
|
||||
assert.Equal(t, 0, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(5.555, 5.555, 5, SrcMeta)
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLat)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLng)
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
t.Run("different source highest priority (manual)", func(t *testing.T) {
|
||||
m := PhotoFixtures.Get("Photo15")
|
||||
assert.Equal(t, SrcMeta, m.PlaceSrc)
|
||||
assert.Equal(t, float32(1.234), m.PhotoLat)
|
||||
assert.Equal(t, float32(4.321), m.PhotoLng)
|
||||
assert.Equal(t, float32(1.234), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(4.321), float32(m.PhotoLng))
|
||||
assert.Equal(t, 3, m.PhotoAltitude)
|
||||
|
||||
m.SetCoordinates(5.555, 5.555, 5, SrcManual)
|
||||
assert.Equal(t, SrcManual, m.PlaceSrc)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLat)
|
||||
assert.Equal(t, float32(5.555), m.PhotoLng)
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLat))
|
||||
assert.Equal(t, float32(5.555), float32(m.PhotoLng))
|
||||
assert.Equal(t, 5, m.PhotoAltitude)
|
||||
})
|
||||
}
|
||||
@@ -408,8 +408,8 @@ func TestUpdateLocation(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "Mexico", m.CountryName())
|
||||
assert.Equal(t, "mx", m.PhotoCountry)
|
||||
assert.Equal(t, float32(0.0), m.PhotoLat)
|
||||
assert.Equal(t, float32(0.0), m.PhotoLng)
|
||||
assert.Equal(t, 0.0, m.PhotoLat)
|
||||
assert.Equal(t, 0.0, m.PhotoLng)
|
||||
assert.Equal(t, "mx:VvfNBpFegSCr", m.PlaceID)
|
||||
assert.Equal(t, SrcEstimate, m.PlaceSrc)
|
||||
})
|
||||
@@ -430,8 +430,8 @@ func TestUpdateLocation(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "Germany", m.CountryName())
|
||||
assert.Equal(t, "de", m.PhotoCountry)
|
||||
assert.Equal(t, float32(0.0), m.PhotoLat)
|
||||
assert.Equal(t, float32(0.0), m.PhotoLng)
|
||||
assert.Equal(t, 0.0, m.PhotoLat)
|
||||
assert.Equal(t, 0.0, m.PhotoLng)
|
||||
assert.Equal(t, UnknownID, m.PlaceID)
|
||||
assert.Equal(t, SrcManual, m.PlaceSrc)
|
||||
})
|
||||
|
||||
@@ -63,7 +63,8 @@ func TestSavePhotoForm(t *testing.T) {
|
||||
assert.Equal(t, true, m.PhotoFavorite)
|
||||
assert.Equal(t, true, m.PhotoPrivate)
|
||||
assert.Equal(t, "image", m.PhotoType)
|
||||
assert.Equal(t, float32(7.9999), m.PhotoLat)
|
||||
assert.InEpsilon(t, 7.9999, m.PhotoLat, 0.0001)
|
||||
assert.InEpsilon(t, 8.8888, m.PhotoLng, 0.0001)
|
||||
assert.NotNil(t, m.EditedAt)
|
||||
|
||||
t.Log(m.GetDetails().Keywords)
|
||||
|
||||
@@ -703,7 +703,7 @@ func searchPhotos(f form.SearchPhotos, sess *entity.Session, resultCols string)
|
||||
}
|
||||
|
||||
// Filter by GPS Longitude range (from -180 to +180 degrees)
|
||||
if lngE, lngW, lngErr := clean.GPSLngRange(f.Lng, f.Dist); lngErr == nil {
|
||||
if lngE, lngW, lngErr := clean.GPSLngRange(f.Lat, f.Lng, f.Dist); lngErr == nil {
|
||||
s = s.Where("photos.photo_lng BETWEEN ? AND ?", lngW, lngE)
|
||||
}
|
||||
|
||||
|
||||
@@ -600,7 +600,7 @@ func UserPhotosGeo(f form.SearchPhotosGeo, sess *entity.Session) (results GeoRes
|
||||
}
|
||||
|
||||
// Filter by GPS Longitude range (from -180 to +180 degrees).
|
||||
if lngE, lngW, lngErr := clean.GPSLngRange(f.Lng, f.Dist); lngErr == nil {
|
||||
if lngE, lngW, lngErr := clean.GPSLngRange(f.Lat, f.Lng, f.Dist); lngErr == nil {
|
||||
s = s.Where("photos.photo_lng BETWEEN ? AND ?", lngW, lngE)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ type GeoResult struct {
|
||||
ID string `json:"-" select:"photos.id"`
|
||||
PhotoUID string `json:"UID" select:"photos.photo_uid"`
|
||||
PhotoType string `json:"Type,omitempty" select:"photos.photo_type"`
|
||||
PhotoLat float32 `json:"Lat" select:"photos.photo_lat"`
|
||||
PhotoLng float32 `json:"Lng" select:"photos.photo_lng"`
|
||||
PhotoLat float64 `json:"Lat" select:"photos.photo_lat"`
|
||||
PhotoLng float64 `json:"Lng" select:"photos.photo_lng"`
|
||||
PhotoTitle string `json:"Title" select:"photos.photo_title"`
|
||||
PhotoDescription string `json:"Description,omitempty" select:"photos.photo_description"`
|
||||
PhotoFavorite bool `json:"Favorite,omitempty" select:"photos.photo_favorite"`
|
||||
@@ -28,12 +28,12 @@ type GeoResult struct {
|
||||
|
||||
// Lat returns the position latitude.
|
||||
func (photo GeoResult) Lat() float64 {
|
||||
return float64(photo.PhotoLat)
|
||||
return photo.PhotoLat
|
||||
}
|
||||
|
||||
// Lng returns the position longitude.
|
||||
func (photo GeoResult) Lng() float64 {
|
||||
return float64(photo.PhotoLng)
|
||||
return photo.PhotoLng
|
||||
}
|
||||
|
||||
// IsPlayable returns true if the photo has a related video/animation that is playable.
|
||||
|
||||
@@ -23,7 +23,8 @@ func TestGeoResult_Lat(t *testing.T) {
|
||||
FileHeight: 0,
|
||||
TakenAtLocal: time.Time{},
|
||||
}
|
||||
assert.Equal(t, 7.775000095367432, geo.Lat())
|
||||
|
||||
assert.InEpsilon(t, 7.775, geo.Lat(), 0.000001)
|
||||
}
|
||||
|
||||
func TestGeoResult_Lng(t *testing.T) {
|
||||
@@ -39,7 +40,8 @@ func TestGeoResult_Lng(t *testing.T) {
|
||||
FileHeight: 0,
|
||||
TakenAtLocal: time.Time{},
|
||||
}
|
||||
assert.Equal(t, 8.774999618530273, geo.Lng())
|
||||
|
||||
assert.InEpsilon(t, 8.774999618530273, geo.Lng(), 0.000001)
|
||||
}
|
||||
|
||||
func TestGeoResults_GeoJSON(t *testing.T) {
|
||||
@@ -95,7 +97,7 @@ func TestGeoResults_GeoJSON(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := []byte("{\"type\":\"FeatureCollection\",\"bbox\":[-5.775000095367432,-1.774999976158142,100.7750015258789,7.775000095367432]")
|
||||
expected := []byte("{\"type\":\"FeatureCollection\",\"bbox\":[-5.775,-1.775,100.775,7.775]")
|
||||
|
||||
assert.Truef(t, bytes.Contains(b, expected), "GeoJSON not as expected")
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ type Photo struct {
|
||||
LensMake string `json:"LensMake,omitempty" select:"lenses.lens_model"`
|
||||
LensModel string `json:"LensModel,omitempty" select:"lenses.lens_make"`
|
||||
PhotoAltitude int `json:"Altitude,omitempty" select:"photos.photo_altitude"`
|
||||
PhotoLat float32 `json:"Lat" select:"photos.photo_lat"`
|
||||
PhotoLng float32 `json:"Lng" select:"photos.photo_lng"`
|
||||
PhotoLat float64 `json:"Lat" select:"photos.photo_lat"`
|
||||
PhotoLng float64 `json:"Lng" select:"photos.photo_lng"`
|
||||
CellID string `json:"CellID" select:"photos.cell_id"` // Cell
|
||||
CellAccuracy int `json:"CellAccuracy,omitempty" select:"photos.cell_accuracy"`
|
||||
PlaceID string `json:"PlaceID" select:"photos.place_id"`
|
||||
|
||||
@@ -693,8 +693,8 @@ func TestPhotos(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, p := range photos {
|
||||
assert.GreaterOrEqual(t, float32(49.519234), p.PhotoLat)
|
||||
assert.LessOrEqual(t, float32(33.45343166666667), p.PhotoLat)
|
||||
assert.GreaterOrEqual(t, 49.519234, p.PhotoLat)
|
||||
assert.LessOrEqual(t, 33.45343166666667, p.PhotoLat)
|
||||
}
|
||||
|
||||
assert.LessOrEqual(t, 2, len(photos))
|
||||
@@ -714,10 +714,10 @@ func TestPhotos(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, p := range photos {
|
||||
assert.GreaterOrEqual(t, float32(49.519234), p.PhotoLat)
|
||||
assert.LessOrEqual(t, float32(0.00), p.PhotoLat)
|
||||
assert.GreaterOrEqual(t, float32(9.1001234), p.PhotoLng)
|
||||
assert.LessOrEqual(t, float32(-30.123), p.PhotoLng)
|
||||
assert.GreaterOrEqual(t, 49.519234, p.PhotoLat)
|
||||
assert.LessOrEqual(t, 0.00, p.PhotoLat)
|
||||
assert.GreaterOrEqual(t, 9.1001234, p.PhotoLng)
|
||||
assert.LessOrEqual(t, -30.123, p.PhotoLng)
|
||||
}
|
||||
|
||||
assert.LessOrEqual(t, 10, len(photos))
|
||||
|
||||
@@ -45,8 +45,8 @@ type Photo struct {
|
||||
PhotoScan bool `json:"Scan"`
|
||||
PhotoPanorama bool `json:"Panorama"`
|
||||
PhotoAltitude int `json:"Altitude"`
|
||||
PhotoLat float32 `json:"Lat"`
|
||||
PhotoLng float32 `json:"Lng"`
|
||||
PhotoLat float64 `json:"Lat"`
|
||||
PhotoLng float64 `json:"Lng"`
|
||||
PhotoIso int `json:"Iso"`
|
||||
PhotoFocalLength int `json:"FocalLength"`
|
||||
PhotoFNumber float32 `json:"FNumber"`
|
||||
|
||||
@@ -51,8 +51,8 @@ func TestNewPhoto(t *testing.T) {
|
||||
assert.Equal(t, false, r.PhotoPrivate)
|
||||
assert.Equal(t, "image", r.PhotoType)
|
||||
assert.Equal(t, int8(1), r.PhotoStack)
|
||||
assert.Equal(t, float32(9.9999), r.PhotoLat)
|
||||
assert.Equal(t, float32(8.8888), r.PhotoLng)
|
||||
assert.Equal(t, 9.9999, r.PhotoLat)
|
||||
assert.Equal(t, 8.8888, r.PhotoLng)
|
||||
assert.Equal(t, 2, r.PhotoAltitude)
|
||||
assert.Equal(t, 5, r.PhotoIso)
|
||||
assert.Equal(t, 10, r.PhotoFocalLength)
|
||||
|
||||
@@ -20,8 +20,8 @@ type TestForm struct {
|
||||
Photo bool `form:"photo"`
|
||||
Archived bool `form:"archived"`
|
||||
Error bool `form:"error"`
|
||||
Lat float32 `form:"lat"`
|
||||
Lng float32 `form:"lng"`
|
||||
Lat float64 `form:"lat"`
|
||||
Lng float64 `form:"lng"`
|
||||
Dist uint `form:"dist"`
|
||||
Color string `form:"color"`
|
||||
Chroma int16 `form:"chroma"`
|
||||
|
||||
@@ -62,8 +62,8 @@ type Data struct {
|
||||
GPSPosition string `meta:"GPSPosition"`
|
||||
GPSLatitude string `meta:"GPSLatitude"`
|
||||
GPSLongitude string `meta:"GPSLongitude"`
|
||||
Lat float32 `meta:"-"`
|
||||
Lng float32 `meta:"-"`
|
||||
Lat float64 `meta:"-"`
|
||||
Lng float64 `meta:"-"`
|
||||
Altitude float64 `meta:"GlobalAltitude,GPSAltitude"`
|
||||
Width int `meta:"ImageWidth,PixelXDimension,ExifImageWidth,SourceImageWidth"`
|
||||
Height int `meta:"ImageHeight,ImageLength,PixelYDimension,ExifImageHeight,SourceImageHeight"`
|
||||
|
||||
@@ -261,8 +261,8 @@ func (data *Data) Exif(fileName string, fileFormat fs.Type, bruteForce bool) (er
|
||||
|
||||
if data.Lat != 0 && data.Lng != 0 {
|
||||
zones, err := tz.GetZone(tz.Point{
|
||||
Lat: float64(data.Lat),
|
||||
Lon: float64(data.Lng),
|
||||
Lat: data.Lat,
|
||||
Lon: data.Lng,
|
||||
})
|
||||
|
||||
if err == nil && len(zones) > 0 {
|
||||
|
||||
@@ -26,8 +26,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "Adobe Photoshop CC 2014 (Windows)", data.Software)
|
||||
assert.Equal(t, 1050, data.Height)
|
||||
assert.Equal(t, 2100, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "", data.Exposure)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
@@ -54,8 +54,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "Adobe Photoshop CC 2017 (Windows)", data.Software)
|
||||
assert.Equal(t, 1050, data.Height)
|
||||
assert.Equal(t, 2100, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "", data.Exposure)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
@@ -84,8 +84,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "Adobe Photoshop 21.0 (Macintosh)", data.Software)
|
||||
assert.Equal(t, 540, data.Height)
|
||||
assert.Equal(t, 720, data.Width)
|
||||
assert.Equal(t, float32(52.45969), data.Lat)
|
||||
assert.Equal(t, float32(13.321832), data.Lng)
|
||||
assert.InEpsilon(t, 52.45969, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.321832, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/50", data.Exposure)
|
||||
assert.Equal(t, "HUAWEI", data.CameraMake)
|
||||
@@ -118,8 +118,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 540, data.Height)
|
||||
assert.Equal(t, 720, data.Width)
|
||||
assert.Equal(t, float32(51.254852), data.Lat)
|
||||
assert.Equal(t, float32(7.389468), data.Lng)
|
||||
assert.InEpsilon(t, 51.254852, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 7.389468, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/125", data.Exposure)
|
||||
assert.Equal(t, "Canon", data.CameraMake)
|
||||
@@ -150,8 +150,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 180, data.Height)
|
||||
assert.Equal(t, 240, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/2462", data.Exposure)
|
||||
assert.Equal(t, "GoPro", data.CameraMake)
|
||||
@@ -180,8 +180,8 @@ func TestExif(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "2018-09-10T03:16:13Z", data.TakenAt.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, "2018-09-10T12:16:13Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, float32(34.79745), data.Lat)
|
||||
assert.Equal(t, float32(134.76463), data.Lng)
|
||||
assert.InEpsilon(t, 34.79745, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 134.76463, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/4000", data.Exposure)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
@@ -209,8 +209,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 0, data.Height)
|
||||
assert.Equal(t, 0, data.Width)
|
||||
assert.Equal(t, float32(-38.405193), data.Lat)
|
||||
assert.Equal(t, float32(144.18896), data.Lng)
|
||||
assert.InEpsilon(t, -38.405193, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 144.18896, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "", data.Exposure)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
@@ -246,8 +246,8 @@ func TestExif(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "2020-05-15T10:25:45Z", data.TakenAt.Format("2006-01-02T15:04:05Z")) // TODO
|
||||
assert.Equal(t, "2020-05-15T10:25:45Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z")) // TODO
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/1100", data.Exposure)
|
||||
assert.Equal(t, "SAMSUNG", data.CameraMake)
|
||||
@@ -268,8 +268,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "2019-05-12T15:13:53Z", data.TakenAt.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, "2019-05-12T17:13:53Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, 955677000, data.TakenNs)
|
||||
assert.Equal(t, float32(53.12349), data.Lat)
|
||||
assert.Equal(t, float32(18.00152), data.Lng)
|
||||
assert.InEpsilon(t, 53.12349, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 18.00152, data.Lng, 0.00001)
|
||||
assert.Equal(t, 63, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/100", data.Exposure)
|
||||
assert.Equal(t, "Xiaomi", data.CameraMake)
|
||||
@@ -361,8 +361,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "2020-06-16T16:52:46Z", data.TakenAt.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, "2020-06-16T18:52:46Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, 695326000, data.TakenNs)
|
||||
assert.Equal(t, float32(48.302776), data.Lat)
|
||||
assert.Equal(t, float32(8.9275), data.Lng)
|
||||
assert.InEpsilon(t, 48.302776, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 8.9275, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/110", data.Exposure)
|
||||
assert.Equal(t, "HUAWEI", data.CameraMake)
|
||||
@@ -391,8 +391,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 3600, data.Height)
|
||||
assert.Equal(t, 7200, data.Width)
|
||||
assert.Equal(t, float32(59.84083), data.Lat)
|
||||
assert.Equal(t, float32(30.51), data.Lng)
|
||||
assert.InEpsilon(t, 59.84083, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 30.51, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/1250", data.Exposure)
|
||||
assert.Equal(t, "SAMSUNG", data.CameraMake)
|
||||
@@ -423,8 +423,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 43, data.Height)
|
||||
assert.Equal(t, 65, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "", data.Exposure)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
@@ -455,8 +455,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 2448, data.Height)
|
||||
assert.Equal(t, 3264, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/387", data.Exposure)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
@@ -489,8 +489,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 2736, data.Height)
|
||||
assert.Equal(t, 3648, data.Width)
|
||||
assert.Equal(t, float32(52.46052), data.Lat)
|
||||
assert.Equal(t, float32(13.331402), data.Lng)
|
||||
assert.InEpsilon(t, 52.46052, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.331402, data.Lng, 0.00001)
|
||||
assert.Equal(t, 84, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/50", data.Exposure)
|
||||
assert.Equal(t, "HUAWEI", data.CameraMake)
|
||||
@@ -515,8 +515,8 @@ func TestExif(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 3000, data.Height)
|
||||
assert.Equal(t, 4000, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/24", data.Exposure)
|
||||
assert.Equal(t, "HMD Global", data.CameraMake)
|
||||
@@ -536,8 +536,8 @@ func TestExif(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 3072, data.Height)
|
||||
assert.Equal(t, 4608, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/1600", data.Exposure)
|
||||
assert.Equal(t, "OLYMPUS IMAGING CORP.", data.CameraMake)
|
||||
@@ -584,8 +584,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "Nicolas Cornet", data.Copyright)
|
||||
assert.Equal(t, 400, data.Height)
|
||||
assert.Equal(t, 600, data.Width)
|
||||
assert.Equal(t, float32(65.05558), data.Lat)
|
||||
assert.Equal(t, float32(-16.625702), data.Lng)
|
||||
assert.InEpsilon(t, 65.05558, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, -16.625702, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/8", data.Exposure)
|
||||
assert.Equal(t, "NIKON CORPORATION", data.CameraMake)
|
||||
@@ -616,8 +616,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "Nicolas Cornet", data.Copyright)
|
||||
assert.Equal(t, 400, data.Height)
|
||||
assert.Equal(t, 600, data.Width)
|
||||
assert.Equal(t, float32(65.05558), data.Lat)
|
||||
assert.Equal(t, float32(-16.625702), data.Lng)
|
||||
assert.InEpsilon(t, 65.05558, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, -16.625702, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/8", data.Exposure)
|
||||
assert.Equal(t, "NIKON CORPORATION", data.CameraMake)
|
||||
@@ -651,8 +651,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "2021-10-29 13:42:00 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "", data.TimeZone) // Local Time
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
})
|
||||
|
||||
t.Run("buggy_panorama.jpg", func(t *testing.T) {
|
||||
@@ -666,8 +666,8 @@ func TestExif(t *testing.T) {
|
||||
assert.Equal(t, "2022-04-24 02:35:53 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Asia/Shanghai", data.TimeZone) // Local Time
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(33.640007), data.Lat)
|
||||
assert.Equal(t, float32(103.48), data.Lng)
|
||||
assert.InEpsilon(t, 33.640007, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 103.48, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
})
|
||||
|
||||
@@ -678,8 +678,8 @@ func TestExif(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, float32(45.75285), data.Lat)
|
||||
assert.Equal(t, float32(33.221977), data.Lng)
|
||||
assert.InEpsilon(t, 45.75285, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 33.221977, data.Lng, 0.00001)
|
||||
assert.InEpsilon(t, 4294967284, data.Altitude, 1000)
|
||||
assert.Equal(t, 0, clean.Altitude(data.Altitude))
|
||||
})
|
||||
|
||||
@@ -107,13 +107,13 @@ func ParseFloat(s string) float64 {
|
||||
}
|
||||
|
||||
// NormalizeGPS normalizes the longitude and latitude of the GPS position to a generally valid range.
|
||||
func NormalizeGPS(lat, lng float64) (float32, float32) {
|
||||
func NormalizeGPS(lat, lng float64) (float64, float64) {
|
||||
if lat < LatMax || lat > LatMax || lng < LngMax || lng > LngMax {
|
||||
// Clip the latitude. Normalise the longitude.
|
||||
lat, lng = clipLat(lat), normalizeLng(lng)
|
||||
}
|
||||
|
||||
return float32(lat), float32(lng)
|
||||
return lat, lng
|
||||
}
|
||||
|
||||
func clipLat(lat float64) float64 {
|
||||
|
||||
@@ -127,8 +127,8 @@ func (data *Data) GPhoto(jsonData []byte) (err error) {
|
||||
|
||||
if p.Geo.Exists() {
|
||||
if data.Lat == 0 && data.Lng == 0 {
|
||||
data.Lat = float32(p.Geo.Lat)
|
||||
data.Lng = float32(p.Geo.Lng)
|
||||
data.Lat = p.Geo.Lat
|
||||
data.Lng = p.Geo.Lng
|
||||
}
|
||||
|
||||
if data.Altitude == 0 {
|
||||
|
||||
@@ -34,8 +34,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 3024, data.ActualWidth())
|
||||
assert.Equal(t, 4032, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(35.42307), data.Lat)
|
||||
assert.Equal(t, float32(-78.65212), data.Lng)
|
||||
assert.InEpsilon(t, 35.42307, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, -78.65212, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Google", data.CameraMake)
|
||||
assert.Equal(t, "Pixel 2", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -65,8 +65,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 3024, data.ActualWidth())
|
||||
assert.Equal(t, 4032, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(35.778152), data.Lat)
|
||||
assert.Equal(t, float32(-78.63687), data.Lng)
|
||||
assert.InEpsilon(t, 35.778152, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, -78.63687, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Google", data.CameraMake)
|
||||
assert.Equal(t, "Pixel 4a", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -96,8 +96,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 4032, data.ActualWidth())
|
||||
assert.Equal(t, 2268, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(48.610027), data.Lat)
|
||||
assert.Equal(t, float32(8.861558), data.Lng)
|
||||
assert.InEpsilon(t, 48.610027, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 8.861558, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Google", data.CameraMake)
|
||||
assert.Equal(t, "Pixel 6", data.CameraModel)
|
||||
assert.Equal(t, "Pixel 6 back camera 6.81mm f/1.85", data.LensModel)
|
||||
@@ -127,8 +127,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 4080, data.ActualWidth())
|
||||
assert.Equal(t, 3072, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(52.70636), data.Lat)
|
||||
assert.Equal(t, float32(-2.7605944), data.Lng)
|
||||
assert.InEpsilon(t, 52.70636, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, -2.7605944, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Google", data.CameraMake)
|
||||
assert.Equal(t, "Pixel 7 Pro", data.CameraModel)
|
||||
assert.Equal(t, "Pixel 7 Pro back camera 19.0mm f/3.5", data.LensModel)
|
||||
@@ -159,8 +159,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 3024, data.ActualWidth())
|
||||
assert.Equal(t, 4032, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "samsung", data.CameraMake)
|
||||
assert.Equal(t, "SM-G780F", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -190,8 +190,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 1080, data.ActualWidth())
|
||||
assert.Equal(t, 1440, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(48.4565), data.Lat)
|
||||
assert.Equal(t, float32(35.072), data.Lng)
|
||||
assert.InEpsilon(t, 48.4565, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 35.072, data.Lng, 0.00001)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
assert.Equal(t, "", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -221,8 +221,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 3024, data.ActualWidth())
|
||||
assert.Equal(t, 4032, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(51.433468), data.Lat)
|
||||
assert.Equal(t, float32(12.110732), data.Lng)
|
||||
assert.InEpsilon(t, 51.433468, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 12.110732, data.Lng, 0.00001)
|
||||
assert.Equal(t, "samsung", data.CameraMake)
|
||||
assert.Equal(t, "SM-G781B", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -253,8 +253,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 4000, data.ActualWidth())
|
||||
assert.Equal(t, 2252, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "samsung", data.CameraMake)
|
||||
assert.Equal(t, "SM-G998B", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -285,8 +285,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 1920, data.ActualWidth())
|
||||
assert.Equal(t, 1080, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
assert.Equal(t, "", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -317,8 +317,8 @@ func TestJSON_Motion(t *testing.T) {
|
||||
assert.Equal(t, 3468, data.ActualWidth())
|
||||
assert.Equal(t, 4624, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Samsung", data.CameraMake)
|
||||
assert.Equal(t, "Galaxy A71", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
|
||||
@@ -35,8 +35,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1920, data.ActualWidth())
|
||||
assert.Equal(t, 1440, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(52.5035), data.Lat)
|
||||
assert.Equal(t, float32(13.4098), data.Lng)
|
||||
assert.InEpsilon(t, 52.5035, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.4098, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 12 mini", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -65,8 +65,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1080, data.ActualWidth())
|
||||
assert.Equal(t, 1920, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(52.4587), data.Lat)
|
||||
assert.Equal(t, float32(13.4593), data.Lng)
|
||||
assert.InEpsilon(t, 52.4587, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.4593, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone SE", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -173,8 +173,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 270, data.ActualWidth())
|
||||
assert.Equal(t, 480, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
assert.Equal(t, "", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -200,8 +200,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1920, data.ActualHeight())
|
||||
assert.Equal(t, float32(0.56), data.AspectRatio())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(52.4596), data.Lat)
|
||||
assert.Equal(t, float32(13.3218), data.Lng)
|
||||
assert.InEpsilon(t, 52.4596, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.3218, data.Lng, 0.00001)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
assert.Equal(t, "", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -225,8 +225,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1920, data.Width)
|
||||
assert.Equal(t, 1080, data.Height)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(52.4649), data.Lat)
|
||||
assert.Equal(t, float32(13.3148), data.Lng)
|
||||
assert.InEpsilon(t, 52.4649, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.3148, data.Lng, 0.00001)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
assert.Equal(t, "", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -264,8 +264,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "photoshop.xmp", data.FileName)
|
||||
assert.Equal(t, CodecXMP, data.Codec)
|
||||
assert.Equal(t, "0s", data.Duration.String())
|
||||
assert.Equal(t, float32(52.45969), data.Lat)
|
||||
assert.Equal(t, float32(13.321831), data.Lng)
|
||||
assert.InEpsilon(t, 52.45969, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.321831, data.Lng, 0.00001)
|
||||
assert.Equal(t, "2020-01-01 16:28:23 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "2020-01-01 17:28:23 +0000 UTC", data.TakenAtLocal.String())
|
||||
assert.Equal(t, 899614000, data.TakenNs)
|
||||
@@ -383,8 +383,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 3024, data.Width)
|
||||
assert.Equal(t, 4032, data.Height)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(48.300003), data.Lat)
|
||||
assert.Equal(t, float32(8.929067), data.Lng)
|
||||
assert.InEpsilon(t, 48.300003, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 8.929067, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone SE", data.CameraModel)
|
||||
assert.Equal(t, "iPhone SE back camera 4.15mm f/2.2", data.LensModel)
|
||||
@@ -409,8 +409,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1024, data.Width)
|
||||
assert.Equal(t, 1365, data.Height)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(48.300003), data.Lat)
|
||||
assert.Equal(t, float32(8.929067), data.Lng)
|
||||
assert.InEpsilon(t, 48.300003, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 8.929067, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone SE", data.CameraModel)
|
||||
assert.Equal(t, "iPhone SE back camera 4.15mm f/2.2", data.LensModel)
|
||||
@@ -435,8 +435,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1125, data.Width)
|
||||
assert.Equal(t, 1500, data.Height)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(48.300003), data.Lat)
|
||||
assert.Equal(t, float32(8.929067), data.Lng)
|
||||
assert.InEpsilon(t, 48.300003, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 8.929067, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone SE", data.CameraModel)
|
||||
assert.Equal(t, "iPhone SE back camera 4.15mm f/2.2", data.LensModel)
|
||||
@@ -466,8 +466,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2015-12-06 16:18:30 +0000 UTC", data.TakenAtLocal.String())
|
||||
assert.Equal(t, "2015-12-06 15:18:30 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Europe/Berlin", data.TimeZone)
|
||||
assert.Equal(t, float32(52.508522), data.Lat)
|
||||
assert.Equal(t, float32(13.443206), data.Lng)
|
||||
assert.InEpsilon(t, 52.508522, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.443206, data.Lng, 0.00001)
|
||||
assert.Equal(t, 40, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, 0, data.Views)
|
||||
|
||||
@@ -495,8 +495,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2019-05-18 12:06:45 +0000 UTC", data.TakenAtLocal.String())
|
||||
assert.Equal(t, "2019-05-18 10:06:45 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Europe/Berlin", data.TimeZone)
|
||||
assert.Equal(t, float32(52.510796), data.Lat)
|
||||
assert.Equal(t, float32(13.456387), data.Lng)
|
||||
assert.InEpsilon(t, 52.510796, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.456387, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, 1118, data.Views)
|
||||
})
|
||||
@@ -513,8 +513,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2011-11-07 21:34:34 +0000 UTC", data.TakenAtLocal.String())
|
||||
assert.Equal(t, "2011-11-07 21:34:34 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "", data.TimeZone)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, 177, data.Views)
|
||||
})
|
||||
@@ -531,8 +531,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2012-12-11 00:07:15 +0000 UTC", data.TakenAtLocal.String())
|
||||
assert.Equal(t, "2012-12-10 23:07:15 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Europe/Berlin", data.TimeZone)
|
||||
assert.Equal(t, float32(52.49967), data.Lat)
|
||||
assert.Equal(t, float32(13.422334), data.Lng)
|
||||
assert.InEpsilon(t, 52.49967, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.422334, data.Lng, 0.00001)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, 0, data.Views)
|
||||
})
|
||||
@@ -573,8 +573,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 3600, data.Height)
|
||||
assert.Equal(t, 7200, data.Width)
|
||||
assert.Equal(t, float32(59.84083), data.Lat)
|
||||
assert.Equal(t, float32(30.51), data.Lng)
|
||||
assert.InEpsilon(t, 59.84083, data.Lat, 0.00001)
|
||||
assert.Equal(t, 30.51, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/1250", data.Exposure)
|
||||
assert.Equal(t, "SAMSUNG", data.CameraMake)
|
||||
@@ -604,8 +604,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 1080, data.Height)
|
||||
assert.Equal(t, 1920, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "", data.Exposure)
|
||||
assert.Equal(t, "OLYMPUS DIGITAL CAMERA", data.CameraMake)
|
||||
@@ -660,8 +660,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 375, data.Height)
|
||||
assert.Equal(t, 500, data.Width)
|
||||
assert.Equal(t, float32(52.46052), data.Lat)
|
||||
assert.Equal(t, float32(13.331403), data.Lng)
|
||||
assert.InEpsilon(t, 52.46052, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 13.331403, data.Lng, 0.00001)
|
||||
assert.Equal(t, 84, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/50", data.Exposure)
|
||||
assert.Equal(t, "HUAWEI", data.CameraMake)
|
||||
@@ -691,8 +691,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1080, data.ActualWidth())
|
||||
assert.Equal(t, 1920, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(55.5636), data.Lat)
|
||||
assert.Equal(t, float32(37.9824), data.Lng)
|
||||
assert.InEpsilon(t, 55.5636, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 37.9824, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 6 Plus", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -716,8 +716,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1920, data.ActualWidth())
|
||||
assert.Equal(t, 1080, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(55.7579), data.Lat)
|
||||
assert.Equal(t, float32(37.6197), data.Lng)
|
||||
assert.InEpsilon(t, 55.7579, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 37.6197, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 6 Plus", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -740,8 +740,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1080, data.ActualWidth())
|
||||
assert.Equal(t, 1920, data.ActualHeight())
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 8", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -760,8 +760,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2019-12-13 01:47:21 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "America/New_York", data.TimeZone)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(40.7696), data.Lat)
|
||||
assert.Equal(t, float32(-73.9964), data.Lng)
|
||||
assert.InEpsilon(t, 40.7696, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, -73.9964, data.Lng, 0.00001)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone X", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -781,8 +781,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2021-10-27 10:43:46 +0200 UTC+02:00", data.TakenAt.String())
|
||||
assert.Equal(t, "", data.TimeZone) // Local Time
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
})
|
||||
|
||||
t.Run("MVI_1724.MOV.json", func(t *testing.T) {
|
||||
@@ -798,8 +798,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2022-06-25 04:50:58 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "UTC+2", data.TimeZone) // Local Time
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Canon", data.CameraMake)
|
||||
assert.Equal(t, "Canon PowerShot G15", data.CameraModel)
|
||||
assert.Equal(t, "6.1", data.LensModel)
|
||||
@@ -823,8 +823,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 4608, data.ActualWidth())
|
||||
assert.Equal(t, 3072, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "OLYMPUS IMAGING CORP.", data.CameraMake)
|
||||
assert.Equal(t, "TG-830", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -849,8 +849,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 4608, data.ActualWidth())
|
||||
assert.Equal(t, 3072, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "OLYMPUS IMAGING CORP.", data.CameraMake)
|
||||
assert.Equal(t, "TG-830", data.CameraModel)
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
@@ -874,8 +874,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 4032, data.ActualWidth())
|
||||
assert.Equal(t, 3024, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 6s", data.CameraModel)
|
||||
assert.Equal(t, "iPhone 6s back camera 4.15mm f/2.2", data.LensModel)
|
||||
@@ -900,8 +900,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 4032, data.ActualWidth())
|
||||
assert.Equal(t, 3024, data.ActualHeight())
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 6s", data.CameraModel)
|
||||
assert.Equal(t, "iPhone 6s back camera 4.15mm f/2.2", data.LensModel)
|
||||
@@ -929,8 +929,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "© 2011 PhotoPrism", data.Copyright)
|
||||
assert.Equal(t, 567, data.Height)
|
||||
assert.Equal(t, 850, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 30, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/6", data.Exposure)
|
||||
assert.Equal(t, "Canon", data.CameraMake)
|
||||
@@ -975,8 +975,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2012-07-11 05:16:01 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Europe/Paris", data.TimeZone)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(43.5683), data.Lat)
|
||||
assert.Equal(t, float32(4.5645), data.Lng)
|
||||
assert.InEpsilon(t, 43.5683, data.Lat, 0.00001)
|
||||
assert.InEpsilon(t, 4.5645, data.Lng, 0.00001)
|
||||
})
|
||||
|
||||
t.Run("quicktimeutc_off.json", func(t *testing.T) {
|
||||
@@ -992,8 +992,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2012-07-11 05:16:01 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Europe/Paris", data.TimeZone)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(43.5683), data.Lat)
|
||||
assert.Equal(t, float32(4.5645), data.Lng)
|
||||
assert.Equal(t, float32(43.5683), float32(data.Lat))
|
||||
assert.Equal(t, float32(4.5645), float32(data.Lng))
|
||||
})
|
||||
|
||||
t.Run("video_num_on.json", func(t *testing.T) {
|
||||
@@ -1009,8 +1009,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2012-07-11 05:16:01 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Europe/Paris", data.TimeZone)
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(43.5683), data.Lat)
|
||||
assert.Equal(t, float32(4.5645), data.Lng)
|
||||
assert.Equal(t, float32(43.5683), float32(data.Lat))
|
||||
assert.Equal(t, float32(4.5645), float32(data.Lng))
|
||||
})
|
||||
|
||||
t.Run("cr2_num_off.json", func(t *testing.T) {
|
||||
@@ -1026,8 +1026,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2015-02-13 16:14:11.91", data.TakenGps.Format("2006-01-02 15:04:05.999999999"))
|
||||
assert.Equal(t, 3648, data.Height)
|
||||
assert.Equal(t, 5472, data.Width)
|
||||
assert.Equal(t, float32(32.843544), data.Lat)
|
||||
assert.Equal(t, float32(-117.28025), data.Lng)
|
||||
assert.Equal(t, float32(32.843544), float32(data.Lat))
|
||||
assert.Equal(t, float32(-117.28025), float32(data.Lng))
|
||||
assert.Equal(t, 18, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/500", data.Exposure)
|
||||
assert.Equal(t, "Canon", data.CameraMake)
|
||||
@@ -1050,8 +1050,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2015-02-13T18:14:40Z", data.TakenAtLocal.Format("2006-01-02T15:04:05Z"))
|
||||
assert.Equal(t, 3648, data.Height)
|
||||
assert.Equal(t, 5472, data.Width)
|
||||
assert.Equal(t, float32(32.843544), data.Lat)
|
||||
assert.Equal(t, float32(-117.28025), data.Lng)
|
||||
assert.Equal(t, float32(32.843544), float32(data.Lat))
|
||||
assert.Equal(t, float32(-117.28025), float32(data.Lng))
|
||||
assert.Equal(t, 18, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "0.002", data.Exposure)
|
||||
assert.Equal(t, "Canon", data.CameraMake)
|
||||
@@ -1075,8 +1075,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, time.UTC.String(), data.TimeZone)
|
||||
assert.Equal(t, 1080, data.Height)
|
||||
assert.Equal(t, 1920, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
})
|
||||
@@ -1093,8 +1093,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, time.UTC.String(), data.TimeZone)
|
||||
assert.Equal(t, 1080, data.Height)
|
||||
assert.Equal(t, 1920, data.Width)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
})
|
||||
@@ -1117,8 +1117,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "Nicolas Cornet", data.Copyright)
|
||||
assert.Equal(t, 400, data.Height)
|
||||
assert.Equal(t, 600, data.Width)
|
||||
assert.Equal(t, float32(65.05558), data.Lat)
|
||||
assert.Equal(t, float32(-16.625702), data.Lng)
|
||||
assert.Equal(t, float32(65.05558), float32(data.Lat))
|
||||
assert.Equal(t, float32(-16.625702), float32(data.Lng))
|
||||
assert.Equal(t, 30, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/8", data.Exposure)
|
||||
assert.Equal(t, "NIKON CORPORATION", data.CameraMake)
|
||||
@@ -1150,8 +1150,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "Nicolas Cornet", data.Copyright)
|
||||
assert.Equal(t, 400, data.Height)
|
||||
assert.Equal(t, 600, data.Width)
|
||||
assert.Equal(t, float32(65.05558), data.Lat)
|
||||
assert.Equal(t, float32(-16.625702), data.Lng)
|
||||
assert.Equal(t, float32(65.05558), float32(data.Lat))
|
||||
assert.Equal(t, float32(-16.625702), float32(data.Lng))
|
||||
assert.Equal(t, 30, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "0.125", data.Exposure)
|
||||
assert.Equal(t, "NIKON CORPORATION", data.CameraMake)
|
||||
@@ -1183,8 +1183,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "Nicolas Cornet", data.Copyright)
|
||||
assert.Equal(t, 400, data.Height)
|
||||
assert.Equal(t, 600, data.Width)
|
||||
assert.Equal(t, float32(65.05558), data.Lat)
|
||||
assert.Equal(t, float32(-16.625702), data.Lng)
|
||||
assert.Equal(t, float32(65.05558), float32(data.Lat))
|
||||
assert.Equal(t, float32(-16.625702), float32(data.Lng))
|
||||
assert.Equal(t, 30, clean.Altitude(data.Altitude))
|
||||
assert.Equal(t, "1/8", data.Exposure)
|
||||
assert.Equal(t, "NIKON CORPORATION", data.CameraMake)
|
||||
@@ -1217,8 +1217,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 1917, data.Width)
|
||||
assert.Equal(t, 34, data.Frames)
|
||||
assert.Equal(t, "49.5s", data.Duration.String())
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "", data.Exposure)
|
||||
assert.Equal(t, "", data.CameraMake)
|
||||
@@ -1265,8 +1265,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 4032, data.Width)
|
||||
assert.Equal(t, 3024, data.Height)
|
||||
assert.Equal(t, 6, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 6s", data.CameraModel)
|
||||
assert.Equal(t, "iPhone 6s back camera 4.15mm f/2.2", data.LensModel)
|
||||
@@ -1290,8 +1290,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 4032, data.Width)
|
||||
assert.Equal(t, 3024, data.Height)
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 14 Pro Max", data.CameraModel)
|
||||
assert.Equal(t, "iPhone 14 Pro Max back triple camera 9mm f/2.8", data.LensModel)
|
||||
@@ -1312,8 +1312,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, "2022-04-24 02:35:53 +0000 UTC", data.TakenAt.String())
|
||||
assert.Equal(t, "Asia/Shanghai", data.TimeZone) // Local Time
|
||||
assert.Equal(t, 1, data.Orientation)
|
||||
assert.Equal(t, float32(33.640007), data.Lat)
|
||||
assert.Equal(t, float32(103.48), data.Lng)
|
||||
assert.Equal(t, float32(33.640007), float32(data.Lat))
|
||||
assert.Equal(t, float32(103.48), float32(data.Lng))
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
})
|
||||
|
||||
@@ -1325,8 +1325,8 @@ func TestJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(t, "", data.LensModel)
|
||||
assert.Equal(t, float32(45.75285), data.Lat)
|
||||
assert.Equal(t, float32(33.221977), data.Lng)
|
||||
assert.Equal(t, float32(45.75285), float32(data.Lat))
|
||||
assert.Equal(t, float32(33.221977), float32(data.Lng))
|
||||
assert.InEpsilon(t, 4294967284, data.Altitude, 1000)
|
||||
assert.Equal(t, 0, clean.Altitude(data.Altitude))
|
||||
})
|
||||
@@ -1346,8 +1346,8 @@ func TestJSON(t *testing.T) {
|
||||
assert.Equal(t, 568000000, data.TakenNs)
|
||||
assert.Equal(t, "UTC+2", data.TimeZone)
|
||||
assert.Equal(t, "+02:00", data.TimeOffset)
|
||||
assert.Equal(t, float32(0), data.Lat)
|
||||
assert.Equal(t, float32(0), data.Lng)
|
||||
assert.Equal(t, 0.0, data.Lat)
|
||||
assert.Equal(t, 0.0, data.Lng)
|
||||
assert.Equal(t, "Apple", data.CameraMake)
|
||||
assert.Equal(t, "iPhone 13", data.CameraModel)
|
||||
assert.Equal(t, "iPhone 13 back dual wide camera 5.1mm f/1.6", data.LensModel)
|
||||
|
||||
@@ -71,8 +71,8 @@ func TestMediaFile_HEIC(t *testing.T) {
|
||||
assert.Equal(t, "1/4000", jpegInfo.Exposure)
|
||||
assert.Equal(t, float32(1.696), jpegInfo.Aperture)
|
||||
assert.Equal(t, 20, jpegInfo.Iso)
|
||||
assert.Equal(t, float32(34.79745), jpegInfo.Lat)
|
||||
assert.Equal(t, float32(134.76463), jpegInfo.Lng)
|
||||
assert.Equal(t, float32(34.79745), float32(jpegInfo.Lat))
|
||||
assert.Equal(t, float32(134.76463), float32(jpegInfo.Lng))
|
||||
assert.Equal(t, 0.0, jpegInfo.Altitude)
|
||||
assert.Equal(t, 4032, jpegInfo.Width)
|
||||
assert.Equal(t, 3024, jpegInfo.Height)
|
||||
@@ -132,8 +132,8 @@ func TestMediaFile_HEIC(t *testing.T) {
|
||||
assert.Equal(t, "1/60", jpegInfo.Exposure)
|
||||
assert.Equal(t, float32(2.275), jpegInfo.Aperture)
|
||||
assert.Equal(t, 400, jpegInfo.Iso)
|
||||
assert.Equal(t, float32(52.459606), jpegInfo.Lat)
|
||||
assert.Equal(t, float32(13.321841), jpegInfo.Lng)
|
||||
assert.InEpsilon(t, 52.459605, jpegInfo.Lat, 0.0001)
|
||||
assert.InEpsilon(t, 13.3218416, jpegInfo.Lng, 0.0001)
|
||||
assert.Equal(t, 50.0, jpegInfo.Altitude)
|
||||
assert.Equal(t, 3024, jpegInfo.Width)
|
||||
assert.Equal(t, 4032, jpegInfo.Height)
|
||||
|
||||
@@ -185,8 +185,8 @@ func TestMediaFile_Exif_JPEG(t *testing.T) {
|
||||
assert.Equal(t, float32(6.644), data.Aperture)
|
||||
assert.Equal(t, float32(10), data.FNumber)
|
||||
assert.Equal(t, 200, data.Iso)
|
||||
assert.Equal(t, float32(-33.45347), data.Lat)
|
||||
assert.Equal(t, float32(25.764645), data.Lng)
|
||||
assert.Equal(t, float32(-33.45347), float32(data.Lat))
|
||||
assert.Equal(t, float32(25.764645), float32(data.Lng))
|
||||
assert.Equal(t, 190.0, data.Altitude)
|
||||
assert.Equal(t, 497, data.Width)
|
||||
assert.Equal(t, 331, data.Height)
|
||||
@@ -267,8 +267,8 @@ func TestMediaFile_Exif_JPEG(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 3600, data.Height)
|
||||
assert.Equal(t, 7200, data.Width)
|
||||
assert.Equal(t, float32(59.84083), data.Lat)
|
||||
assert.Equal(t, float32(30.51), data.Lng)
|
||||
assert.Equal(t, float32(59.84083), float32(data.Lat))
|
||||
assert.Equal(t, float32(30.51), float32(data.Lng))
|
||||
assert.Equal(t, 0.0, data.Altitude)
|
||||
assert.Equal(t, "1/1250", data.Exposure)
|
||||
assert.Equal(t, "SAMSUNG", data.CameraMake)
|
||||
@@ -304,8 +304,8 @@ func TestMediaFile_Exif_JPEG(t *testing.T) {
|
||||
assert.Equal(t, "", data.Copyright)
|
||||
assert.Equal(t, 375, data.Height)
|
||||
assert.Equal(t, 500, data.Width)
|
||||
assert.Equal(t, float32(52.46052), data.Lat)
|
||||
assert.Equal(t, float32(13.331402), data.Lng)
|
||||
assert.Equal(t, float32(52.46052), float32(data.Lat))
|
||||
assert.Equal(t, float32(13.331402), float32(data.Lng))
|
||||
assert.Equal(t, 84.0, data.Altitude)
|
||||
assert.Equal(t, "1/50", data.Exposure)
|
||||
assert.Equal(t, "HUAWEI", data.CameraMake)
|
||||
@@ -347,8 +347,8 @@ func TestMediaFile_Exif_DNG(t *testing.T) {
|
||||
assert.Equal(t, "1/60", info.Exposure)
|
||||
assert.Equal(t, float32(4.971), info.Aperture)
|
||||
assert.Equal(t, 1000, info.Iso)
|
||||
assert.Equal(t, float32(0), info.Lat)
|
||||
assert.Equal(t, float32(0), info.Lng)
|
||||
assert.Equal(t, 0.0, info.Lat)
|
||||
assert.Equal(t, 0.0, info.Lng)
|
||||
assert.Equal(t, 0.0, info.Altitude)
|
||||
assert.Equal(t, false, info.Flash)
|
||||
assert.Equal(t, "", info.Description)
|
||||
|
||||
@@ -2,25 +2,24 @@ package clean
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/photoprism/photoprism/pkg/geo"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
// gpsCeil converts a GPS coordinate to a rounded float32 for use in queries.
|
||||
func gpsCeil(f float64) float32 {
|
||||
return float32((math.Ceil(f*10000) / 10000) + 0.0001)
|
||||
// GPSBoundsDefaultPadding specifies the default padding of the GPS coordinates in meters.
|
||||
const GPSBoundsDefaultPadding = 5.0
|
||||
|
||||
// GPSBounds parses the GPS bounds (Lat N, Lng E, Lat S, Lng W)
|
||||
// and returns the coordinates with default padding.
|
||||
func GPSBounds(bounds string) (latN, lngE, latS, lngW float64, err error) {
|
||||
return GPSBoundsWithPadding(bounds, GPSBoundsDefaultPadding)
|
||||
}
|
||||
|
||||
// gpsFloor converts a GPS coordinate to a rounded float32 for use in queries.
|
||||
func gpsFloor(f float64) float32 {
|
||||
return float32((math.Floor(f*10000) / 10000) - 0.0001)
|
||||
}
|
||||
|
||||
// GPSBounds parses the GPS bounds (Lat N, Lng E, Lat S, Lng W) and returns the coordinates if any.
|
||||
func GPSBounds(bounds string) (latN, lngE, latS, lngW float32, err error) {
|
||||
// GPSBoundsWithPadding parses the GPS bounds (Lat N, Lng E, Lat S, Lng W)
|
||||
// and returns the coordinates with a custom padding in meters.
|
||||
func GPSBoundsWithPadding(bounds string, padding float64) (latN, lngE, latS, lngW float64, err error) {
|
||||
// Bounds string not long enough?
|
||||
if len(bounds) < 7 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("no coordinates found")
|
||||
@@ -29,19 +28,19 @@ func GPSBounds(bounds string) (latN, lngE, latS, lngW float32, err error) {
|
||||
// Trim whitespace and invalid characters.
|
||||
bounds = strings.Trim(bounds, " |\\<>\n\r\t\"'#$%!^*()[]{}")
|
||||
|
||||
// Split string into values.
|
||||
// Split bounding box string into coordinate values.
|
||||
values := strings.SplitN(bounds, ",", 5)
|
||||
found := len(values)
|
||||
|
||||
// Invalid number of values?
|
||||
// Return error if number of coordinates is invalid.
|
||||
if found != 4 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("invalid number of coordinates")
|
||||
}
|
||||
|
||||
// Parse floating point coordinates.
|
||||
// Convert coordinate strings to floating point values.
|
||||
latNorth, lngEast, latSouth, lngWest := txt.Float(values[0]), txt.Float(values[1]), txt.Float(values[2]), txt.Float(values[3])
|
||||
|
||||
// Latitudes (from +90 to -90 degrees).
|
||||
// Latitudes have a valid range of +90 to -90 degrees.
|
||||
if latNorth > 90 {
|
||||
latNorth = 90
|
||||
} else if latNorth < -90 {
|
||||
@@ -54,12 +53,12 @@ func GPSBounds(bounds string) (latN, lngE, latS, lngW float32, err error) {
|
||||
latSouth = -90
|
||||
}
|
||||
|
||||
// latSouth must be smaller.
|
||||
// Make sure latSouth is smaller than latNorth.
|
||||
if latSouth > latNorth {
|
||||
latNorth, latSouth = latSouth, latNorth
|
||||
}
|
||||
|
||||
// Longitudes (from -180 to +180 degrees).
|
||||
// Longitudes have a valid range of -180 to +180 degrees.
|
||||
if lngEast > 180 {
|
||||
lngEast = 180
|
||||
} else if lngEast < -180 {
|
||||
@@ -72,17 +71,20 @@ func GPSBounds(bounds string) (latN, lngE, latS, lngW float32, err error) {
|
||||
lngWest = -180
|
||||
}
|
||||
|
||||
// lngWest must be smaller.
|
||||
// Make sure lngWest is smaller than lngEast.
|
||||
if lngWest > lngEast {
|
||||
lngEast, lngWest = lngWest, lngEast
|
||||
}
|
||||
|
||||
// Return rounded coordinates.
|
||||
return gpsCeil(latNorth), gpsCeil(lngEast), gpsFloor(latSouth), gpsFloor(lngWest), nil
|
||||
// Calculate the latitude and longitude padding in degrees.
|
||||
dLat, dLng := geo.Deg((latNorth+latSouth)/2.0, padding)
|
||||
|
||||
// Return the coordinates of the bounding box with padding applied.
|
||||
return latNorth + dLat, lngEast + dLng, latSouth - dLat, lngWest - dLng, nil
|
||||
}
|
||||
|
||||
// GPSLatRange returns a range based on the specified latitude and distance in km, or an error otherwise.
|
||||
func GPSLatRange(lat float64, km float64) (latN, latS float32, err error) {
|
||||
func GPSLatRange(lat float64, km float64) (latN, latS float64, err error) {
|
||||
// Latitude (from +90 to -90 degrees).
|
||||
if lat == 0 || lat < -90 || lat > 90 {
|
||||
return 0, 0, fmt.Errorf("invalid latitude")
|
||||
@@ -93,8 +95,10 @@ func GPSLatRange(lat float64, km float64) (latN, latS float32, err error) {
|
||||
|
||||
// Approximate longitude range,
|
||||
// see https://en.wikipedia.org/wiki/Decimal_degrees
|
||||
latN = gpsCeil(lat + geo.Deg(r))
|
||||
latS = gpsFloor(lat - geo.Deg(r))
|
||||
dLat, _ := geo.DegKm(lat, r)
|
||||
|
||||
latN = lat + dLat
|
||||
latS = lat - dLat
|
||||
|
||||
if latN > 90 {
|
||||
latN = 90
|
||||
@@ -108,7 +112,7 @@ func GPSLatRange(lat float64, km float64) (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 float64) (lngE, lngW float32, err error) {
|
||||
func GPSLngRange(lat, lng float64, km float64) (lngE, lngW float64, err error) {
|
||||
// Longitude (from -180 to +180 degrees).
|
||||
if lng == 0 || lng < -180 || lng > 180 {
|
||||
return 0, 0, fmt.Errorf("invalid longitude")
|
||||
@@ -119,8 +123,10 @@ func GPSLngRange(lng float64, km float64) (lngE, lngW float32, err error) {
|
||||
|
||||
// Approximate longitude range,
|
||||
// see https://en.wikipedia.org/wiki/Decimal_degrees
|
||||
lngE = gpsCeil(lng + geo.Deg(r))
|
||||
lngW = gpsFloor(lng - geo.Deg(r))
|
||||
_, dLng := geo.DegKm(lat, r)
|
||||
|
||||
lngE = lng + dLng
|
||||
lngW = lng - dLng
|
||||
|
||||
if lngE > 180 {
|
||||
lngE = 180
|
||||
|
||||
@@ -6,77 +6,97 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGPSBoundsWithPadding(t *testing.T) {
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBoundsWithPadding("41.87760543823242,-87.62521362304688,41.89404296875,-87.6215591430664", 1000)
|
||||
assert.InEpsilon(t, 41.903036, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, -87.609479, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, 41.868612, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, -87.637294, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGPSBounds(t *testing.T) {
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("41.87760543823242,-87.62521362304688,41.89404296875,-87.6215591430664")
|
||||
assert.Equal(t, float32(41.8942), latNorth)
|
||||
assert.Equal(t, float32(41.8775), latSouth)
|
||||
assert.Equal(t, float32(-87.6254), lngWest)
|
||||
assert.Equal(t, float32(-87.6214), lngEast)
|
||||
assert.InEpsilon(t, 41.8942, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, -87.6214, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, 41.8775, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, -87.6254, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("China", func(t *testing.T) {
|
||||
// Actual postion: Lat 39.8922, Lng 116.315
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("39.8922004699707,116.31500244140625,39.8922004699707,116.31500244140625")
|
||||
assert.InEpsilon(t, 39.8924, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, 116.3152, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, 39.8921, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, 116.3149, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("FlippedLat", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("41.89404296875,-87.62521362304688,41.87760543823242,-87.6215591430664")
|
||||
assert.Equal(t, float32(41.8942), latNorth)
|
||||
assert.Equal(t, float32(41.8775), latSouth)
|
||||
assert.Equal(t, float32(-87.6254), lngWest)
|
||||
assert.Equal(t, float32(-87.6214), lngEast)
|
||||
assert.InEpsilon(t, 41.8942, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, -87.6214, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, 41.8775, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, -87.6254, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("FlippedLng", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("41.87760543823242,-87.6215591430664,41.89404296875,-87.62521362304688")
|
||||
assert.Equal(t, float32(41.8942), latNorth)
|
||||
assert.Equal(t, float32(41.8775), latSouth)
|
||||
assert.Equal(t, float32(-87.6254), lngWest)
|
||||
assert.Equal(t, float32(-87.6214), lngEast)
|
||||
assert.InEpsilon(t, 41.8942, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, -87.6214, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, 41.8775, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, -87.6254, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Empty", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("")
|
||||
assert.Equal(t, float32(0), latNorth)
|
||||
assert.Equal(t, float32(0), lngEast)
|
||||
assert.Equal(t, float32(0), latSouth)
|
||||
assert.Equal(t, float32(0), lngWest)
|
||||
assert.Equal(t, 0.0, latNorth)
|
||||
assert.Equal(t, 0.0, lngEast)
|
||||
assert.Equal(t, 0.0, latSouth)
|
||||
assert.Equal(t, 0.0, lngWest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("One", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("41.87760543823242")
|
||||
assert.Equal(t, float32(0), latNorth)
|
||||
assert.Equal(t, float32(0), lngEast)
|
||||
assert.Equal(t, float32(0), latSouth)
|
||||
assert.Equal(t, float32(0), lngWest)
|
||||
assert.Equal(t, 0.0, latNorth)
|
||||
assert.Equal(t, 0.0, lngEast)
|
||||
assert.Equal(t, 0.0, latSouth)
|
||||
assert.Equal(t, 0.0, lngWest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("Three", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("41.87760543823242,-87.62521362304688,41.89404296875")
|
||||
assert.Equal(t, float32(0), latNorth)
|
||||
assert.Equal(t, float32(0), lngEast)
|
||||
assert.Equal(t, float32(0), latSouth)
|
||||
assert.Equal(t, float32(0), lngWest)
|
||||
assert.Equal(t, 0.0, latNorth)
|
||||
assert.Equal(t, 0.0, lngEast)
|
||||
assert.Equal(t, 0.0, latSouth)
|
||||
assert.Equal(t, 0.0, lngWest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("Five", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("41.87760543823242,-87.62521362304688,41.89404296875,-87.6215591430664,41.89404296875")
|
||||
assert.Equal(t, float32(0), latNorth)
|
||||
assert.Equal(t, float32(0), lngEast)
|
||||
assert.Equal(t, float32(0), latSouth)
|
||||
assert.Equal(t, float32(0), lngWest)
|
||||
assert.Equal(t, 0.0, latNorth)
|
||||
assert.Equal(t, 0.0, lngEast)
|
||||
assert.Equal(t, 0.0, latSouth)
|
||||
assert.Equal(t, 0.0, lngWest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("95.87760543823242,-197.62521362304688,98.89404296875,-197.6215591430664")
|
||||
assert.Equal(t, float32(90.0001), latNorth)
|
||||
assert.Equal(t, float32(89.9999), latSouth)
|
||||
assert.Equal(t, float32(-180.0001), lngWest)
|
||||
assert.Equal(t, float32(-179.9999), lngEast)
|
||||
assert.InEpsilon(t, 90.000045, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, -179.974236, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, 89.999955, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, -180.025764, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Invalid2", func(t *testing.T) {
|
||||
latNorth, lngEast, latSouth, lngWest, err := GPSBounds("-95.87760543823242,197.62521362304688,-98.89404296875,197.6215591430664")
|
||||
assert.Equal(t, float32(-89.9999), latNorth)
|
||||
assert.Equal(t, float32(-90.0001), latSouth)
|
||||
assert.Equal(t, float32(179.9999), lngWest)
|
||||
assert.Equal(t, float32(180.0001), lngEast)
|
||||
assert.InEpsilon(t, -89.999955, latNorth, 0.00001)
|
||||
assert.InEpsilon(t, 180.025764, lngEast, 0.00001)
|
||||
assert.InEpsilon(t, -90.000045, latSouth, 0.00001)
|
||||
assert.InEpsilon(t, 179.974236, lngWest, 0.00001)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
@@ -84,29 +104,41 @@ func TestGPSBounds(t *testing.T) {
|
||||
func TestGPSLatRange(t *testing.T) {
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
latNorth, latSouth, err := GPSLatRange(41.87760543823242, 2)
|
||||
assert.Equal(t, float32(41.8913), latNorth)
|
||||
assert.Equal(t, float32(41.8639), latSouth)
|
||||
assert.Equal(t, float32(41.891094), float32(latNorth))
|
||||
assert.Equal(t, float32(41.864117), float32(latSouth))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Zero", func(t *testing.T) {
|
||||
latNorth, latSouth, err := GPSLatRange(0, 2)
|
||||
assert.Equal(t, float32(0), latNorth)
|
||||
assert.Equal(t, float32(0), latSouth)
|
||||
assert.Equal(t, 0.0, latNorth)
|
||||
assert.Equal(t, 0.0, latSouth)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGPSLngRange(t *testing.T) {
|
||||
t.Run("Valid", func(t *testing.T) {
|
||||
lngEast, lngWest, err := GPSLngRange(-87.62521362304688, 2)
|
||||
assert.Equal(t, float32(-87.6389), lngWest)
|
||||
assert.Equal(t, float32(-87.6116), lngEast)
|
||||
t.Run("Lat0", func(t *testing.T) {
|
||||
lngEast, lngWest, err := GPSLngRange(0.0, -87.62521362304688, 2)
|
||||
assert.Equal(t, float32(-87.6387), float32(lngWest))
|
||||
assert.Equal(t, float32(-87.611725), float32(lngEast))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Lat45", func(t *testing.T) {
|
||||
lngEast, lngWest, err := GPSLngRange(45.0, -87.62521362304688, 2)
|
||||
assert.Equal(t, float32(-87.644295), float32(lngWest))
|
||||
assert.Equal(t, float32(-87.60613), float32(lngEast))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Lat67", func(t *testing.T) {
|
||||
lngEast, lngWest, err := GPSLngRange(67.0, -87.62521362304688, 2)
|
||||
assert.Equal(t, float32(-87.65974), float32(lngWest))
|
||||
assert.Equal(t, float32(-87.59069), float32(lngEast))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Zero", func(t *testing.T) {
|
||||
lngEast, lngWest, err := GPSLngRange(0, 2)
|
||||
assert.Equal(t, float32(0), lngEast)
|
||||
assert.Equal(t, float32(0), lngWest)
|
||||
lngEast, lngWest, err := GPSLngRange(0, 0, 2)
|
||||
assert.Equal(t, 0.0, lngEast)
|
||||
assert.Equal(t, 0.0, lngWest)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,10 +10,35 @@ const (
|
||||
DefaultDist float64 = 2
|
||||
)
|
||||
|
||||
// Deg returns the approximate distance in decimal degrees,
|
||||
// see https://en.wikipedia.org/wiki/Decimal_degrees.
|
||||
func Deg(km float64) float64 {
|
||||
return 0.009009009 * km
|
||||
// Deg returns the distance in decimal degrees based on the specified distance in meters and the latitude,
|
||||
// see https://en.wikipedia.org/wiki/Decimal_degrees#Precision.
|
||||
func Deg(lat, meter float64) (dLat, dLng float64) {
|
||||
if meter <= 0.0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Calculate latitude distance in degrees.
|
||||
dLat = (meter / AverageEarthRadiusMeter) * (180.0 / math.Pi)
|
||||
|
||||
// Do not calculate the exact longitude distance in
|
||||
// degrees if the latitude is zero or out of range.
|
||||
if lat == 0.0 {
|
||||
return dLat, dLat
|
||||
} else if lat < -89.9 {
|
||||
lat = -89.9
|
||||
} else if lat > 89.9 {
|
||||
lat = 89.9
|
||||
}
|
||||
|
||||
// Calculate longitude distance in degrees.
|
||||
dLng = (meter / AverageEarthRadiusMeter) * (180.0 / math.Pi) / math.Cos(lat*math.Pi/180.0)
|
||||
|
||||
return dLat, dLng
|
||||
}
|
||||
|
||||
// DegKm returns the distance in decimal degrees based on the specified distance in kilometers and the latitude.
|
||||
func DegKm(lat, km float64) (dLat, dLng float64) {
|
||||
return Deg(lat, km*1000.0)
|
||||
}
|
||||
|
||||
// DegToRad converts a value from degrees to radians.
|
||||
@@ -40,5 +65,5 @@ func Km(p, q Position) (km float64) {
|
||||
|
||||
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
|
||||
|
||||
return c * EarthRadiusKm
|
||||
return c * AverageEarthRadiusKm
|
||||
}
|
||||
|
||||
@@ -7,8 +7,76 @@ import (
|
||||
)
|
||||
|
||||
func TestDeg(t *testing.T) {
|
||||
t.Run("10km", func(t *testing.T) {
|
||||
assert.Equal(t, 0.09009009, Deg(10))
|
||||
t.Run("Lat0", func(t *testing.T) {
|
||||
dLat, dLng := Deg(0.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000100, dLng, 0.01)
|
||||
})
|
||||
t.Run("Lat23", func(t *testing.T) {
|
||||
dLat, dLng := Deg(23.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000108, dLng, 0.01)
|
||||
})
|
||||
t.Run("Lat45", func(t *testing.T) {
|
||||
dLat, dLng := Deg(45.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000141, dLng, 0.01)
|
||||
})
|
||||
t.Run("Lat67", func(t *testing.T) {
|
||||
dLat, dLng := Deg(67.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000255, dLng, 0.01)
|
||||
})
|
||||
t.Run("ZeroMeters", func(t *testing.T) {
|
||||
dLat, dLng := Deg(50.0, 0.0)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.Equal(t, 0.0, dLat)
|
||||
assert.Equal(t, 0.0, dLng)
|
||||
})
|
||||
t.Run("LatOutOfRange", func(t *testing.T) {
|
||||
dLat, dLng := Deg(123.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.057195, dLng, 0.01)
|
||||
dLat, dLng = Deg(-600.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.057195, dLng, 0.01)
|
||||
dLat, dLng = Deg(-600.0, 11.1)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.057195, dLng, 0.01)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDegKm(t *testing.T) {
|
||||
t.Run("Lat0", func(t *testing.T) {
|
||||
dLat, dLng := DegKm(0.0, 0.0111)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000100, dLng, 0.01)
|
||||
})
|
||||
t.Run("Lat23", func(t *testing.T) {
|
||||
dLat, dLng := DegKm(23.0, 0.0111)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000108, dLng, 0.01)
|
||||
})
|
||||
t.Run("Lat45", func(t *testing.T) {
|
||||
dLat, dLng := DegKm(45.0, 0.0111)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000141, dLng, 0.01)
|
||||
})
|
||||
t.Run("Lat67", func(t *testing.T) {
|
||||
dLat, dLng := DegKm(67.0, 0.0111)
|
||||
t.Logf("dLat: %f, dLng: %f", dLat, dLng)
|
||||
assert.InEpsilon(t, 0.000100, dLat, 0.01)
|
||||
assert.InEpsilon(t, 0.000255, dLng, 0.01)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -25,5 +25,8 @@ Additional information can be found in our Developer Guide:
|
||||
package geo
|
||||
|
||||
const (
|
||||
EarthRadiusKm = 6371 // Earth radius in km
|
||||
AverageEarthRadiusKm = 6371.0 // Global-average earth radius in km
|
||||
AverageEarthRadiusMeter = AverageEarthRadiusKm * 1000.0 // Global-average earth radius in m
|
||||
WGS84EarthRadiusKm = 6378.137 // WGS84 earth radius in km
|
||||
WGS84EarthRadiusMeter = WGS84EarthRadiusKm * 1000.0 // WGS84 earth radius in m
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user