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):
 | 
			
		||||
@ -25,6 +25,21 @@ class Db(object):
 | 
			
		||||
            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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user