Add geolocation cache for distances below 3km
By reusing lookup's the server need to be contacted a lot less Aslo names get a bit clustered and match together a bit better.
This commit is contained in:
parent
0c3cfa8e47
commit
8b30107a3e
|
@ -3,5 +3,6 @@ from os import path
|
|||
debug = True
|
||||
application_directory = '{}/.elodie'.format(path.expanduser('~'))
|
||||
hash_db = '{}/hash.json'.format(application_directory)
|
||||
location_db = '{}/location.json'.format(application_directory)
|
||||
script_directory = path.dirname(path.dirname(path.abspath(__file__)))
|
||||
exiftool_config = '%s/configs/ExifTool_config' % script_directory
|
||||
|
|
|
@ -9,6 +9,7 @@ import sys
|
|||
import urllib
|
||||
|
||||
from elodie import constants
|
||||
from elodie.localstorage import Db
|
||||
|
||||
class Fraction(fractions.Fraction):
|
||||
"""Only create Fractions from floats.
|
||||
|
@ -84,17 +85,31 @@ def get_key():
|
|||
return config.get('MapQuest', 'key')
|
||||
|
||||
def place_name(lat, lon):
|
||||
|
||||
# Try to get cached location first
|
||||
db = Db()
|
||||
# 3km distace radious for a match
|
||||
cached_place_name = db.get_location_name(lat, lon,3000)
|
||||
if(cached_place_name is not None):
|
||||
return cached_place_name
|
||||
|
||||
lookup_place_name = None;
|
||||
geolocation_info = reverse_lookup(lat, lon)
|
||||
if(geolocation_info is not None):
|
||||
if('address' in geolocation_info):
|
||||
address = geolocation_info['address']
|
||||
if('city' in address):
|
||||
return address['city']
|
||||
lookup_place_name = address['city']
|
||||
elif('state' in address):
|
||||
return address['state']
|
||||
lookup_place_name = address['state']
|
||||
elif('country' in address):
|
||||
return address['country']
|
||||
return None
|
||||
lookup_place_name = address['country']
|
||||
|
||||
if(lookup_place_name is not None):
|
||||
db.add_location(lat, lon, lookup_place_name)
|
||||
# TODO: Maybe this should only be done on exit and not for every write.
|
||||
db.update_location_db()
|
||||
return lookup_place_name
|
||||
|
||||
|
||||
def reverse_lookup(lat, lon):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import hashlib
|
||||
import json
|
||||
import os
|
||||
|
||||
from math import radians, cos, sqrt
|
||||
from elodie import constants
|
||||
|
||||
class Db(object):
|
||||
|
@ -24,7 +24,22 @@ class Db(object):
|
|||
self.hash_db = json.load(f)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
# If the location db doesn't exist we create it.
|
||||
# Otherwise we only open for reading
|
||||
if not os.path.isfile(constants.location_db):
|
||||
with open(constants.location_db, 'a'):
|
||||
os.utime(constants.location_db, None)
|
||||
|
||||
self.location_db = []
|
||||
|
||||
# We know from above that this file exists so we open it for reading only.
|
||||
with open(constants.location_db, 'r') as f:
|
||||
try:
|
||||
self.location_db = json.load(f)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def add_hash(self, key, value, write=False):
|
||||
self.hash_db[key] = value
|
||||
if(write == True):
|
||||
|
@ -55,3 +70,44 @@ class Db(object):
|
|||
buf = f.read(blocksize)
|
||||
return hasher.hexdigest()
|
||||
return None
|
||||
|
||||
# Location database
|
||||
# Currently quite simple just a list of long/lat pairs with a name
|
||||
# If it gets many entryes a lookup might takt to long and a better
|
||||
# structure might be needed. Some speed up ideas:
|
||||
# - Sort it and inter-half method can be used
|
||||
# - Use integer part of long or lat as key to get a lower search list
|
||||
# - Cache a smal number of lookups, photos is likey to be taken i clusters
|
||||
# around a spot during import.
|
||||
|
||||
def add_location(self, latitude, longitude, place, write=False):
|
||||
data = {}
|
||||
data['lat'] = latitude
|
||||
data['long'] = longitude
|
||||
data['name'] = place
|
||||
self.location_db.append(data)
|
||||
if(write == True):
|
||||
self.update_location_db()
|
||||
|
||||
def get_location_name(self, latitude, longitude,threshold_m):
|
||||
for data in self.location_db:
|
||||
# As threshold is quite smal use simple math
|
||||
# From http://stackoverflow.com/questions/15736995/how-can-i-quickly-estimate-the-distance-between-two-latitude-longitude-points
|
||||
# convert decimal degrees to radians
|
||||
|
||||
lon1, lat1, lon2, lat2 = map(radians, [longitude, latitude, data['long'], data['lat']])
|
||||
|
||||
R = 6371000 # radius of the earth in m
|
||||
x = (lon2 - lon1) * cos( 0.5*(lat2+lat1) )
|
||||
y = lat2 - lat1
|
||||
d = R * sqrt( x*x + y*y )
|
||||
# Use if closer then threshold_km reuse lookup
|
||||
if(d<=threshold_m):
|
||||
#print "Found in cached location dist: %d m" % d
|
||||
return data['name'];
|
||||
return None
|
||||
|
||||
|
||||
def update_location_db(self):
|
||||
with open(constants.location_db, 'w') as f:
|
||||
json.dump(self.location_db, f)
|
||||
|
|
Loading…
Reference in New Issue