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
 | 
					debug = True
 | 
				
			||||||
application_directory = '{}/.elodie'.format(path.expanduser('~'))
 | 
					application_directory = '{}/.elodie'.format(path.expanduser('~'))
 | 
				
			||||||
hash_db = '{}/hash.json'.format(application_directory)
 | 
					hash_db = '{}/hash.json'.format(application_directory)
 | 
				
			||||||
 | 
					location_db = '{}/location.json'.format(application_directory)
 | 
				
			||||||
script_directory = path.dirname(path.dirname(path.abspath(__file__)))
 | 
					script_directory = path.dirname(path.dirname(path.abspath(__file__)))
 | 
				
			||||||
exiftool_config = '%s/configs/ExifTool_config' % script_directory
 | 
					exiftool_config = '%s/configs/ExifTool_config' % script_directory
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import sys
 | 
				
			|||||||
import urllib
 | 
					import urllib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from elodie import constants
 | 
					from elodie import constants
 | 
				
			||||||
 | 
					from elodie.localstorage import Db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Fraction(fractions.Fraction):
 | 
					class Fraction(fractions.Fraction):
 | 
				
			||||||
    """Only create Fractions from floats.
 | 
					    """Only create Fractions from floats.
 | 
				
			||||||
@ -84,17 +85,31 @@ def get_key():
 | 
				
			|||||||
    return config.get('MapQuest', 'key')
 | 
					    return config.get('MapQuest', 'key')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def place_name(lat, lon):
 | 
					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)
 | 
					    geolocation_info = reverse_lookup(lat, lon)
 | 
				
			||||||
    if(geolocation_info is not None):
 | 
					    if(geolocation_info is not None):
 | 
				
			||||||
        if('address' in geolocation_info):
 | 
					        if('address' in geolocation_info):
 | 
				
			||||||
            address = geolocation_info['address']
 | 
					            address = geolocation_info['address']
 | 
				
			||||||
            if('city' in address):
 | 
					            if('city' in address):
 | 
				
			||||||
                return address['city']
 | 
					                lookup_place_name = address['city']
 | 
				
			||||||
            elif('state' in address):
 | 
					            elif('state' in address):
 | 
				
			||||||
                return address['state']
 | 
					                lookup_place_name = address['state']
 | 
				
			||||||
            elif('country' in address):
 | 
					            elif('country' in address):
 | 
				
			||||||
                return address['country']
 | 
					                lookup_place_name = address['country']
 | 
				
			||||||
    return None
 | 
					
 | 
				
			||||||
 | 
					    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):
 | 
					def reverse_lookup(lat, lon):
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import hashlib
 | 
					import hashlib
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					from math import radians, cos, sqrt
 | 
				
			||||||
from elodie import constants
 | 
					from elodie import constants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Db(object):
 | 
					class Db(object):
 | 
				
			||||||
@ -25,6 +25,21 @@ class Db(object):
 | 
				
			|||||||
            except ValueError:
 | 
					            except ValueError:
 | 
				
			||||||
                pass
 | 
					                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):
 | 
					    def add_hash(self, key, value, write=False):
 | 
				
			||||||
        self.hash_db[key] = value
 | 
					        self.hash_db[key] = value
 | 
				
			||||||
        if(write == True):
 | 
					        if(write == True):
 | 
				
			||||||
@ -55,3 +70,44 @@ class Db(object):
 | 
				
			|||||||
                buf = f.read(blocksize)
 | 
					                buf = f.read(blocksize)
 | 
				
			||||||
            return hasher.hexdigest()
 | 
					            return hasher.hexdigest()
 | 
				
			||||||
        return None
 | 
					        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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user