o
    Ďi5(                     @   s  d Z ddlmZ dZddlZddlZddlZejdkr!ed neej	 ddl
Z
ddlmZ ddlmZ ddlZd	Zd
ZdZdZi ddddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0Zddddd1Zg d2Zd3Zd4Zd5Zd6d7 ZeG d8d9 d9eZd:d; Z d<d= Z!dJd?d@Z"dJdAdBZ#e$dCkre%dD dEZ&e%dF e"e&Z'e%e' e%dG g dHZ(e%dIe)e(  e#e(Z*e%e* dS dS )Kz A Fast, Offline Reverse Geocoder in Python

A Python library for offline reverse geocoding. It improves on an existing library
called reverse_geocode developed by Richard Penman.
    )print_functionzAjay ThampiNwin32i)cKDTree)
cKDTree_MPz)http://download.geonames.org/export/dump/
cities1000zadmin1CodesASCII.txtzadmin2Codes.txt	geoNameIdname   	asciiName   alternateNames   latitude   	longitude   featureClass   featureCode   countryCode   cc2	   
admin1Code
   
admin2Code   
admin3Code   
admin4Code   
population   	elevation   dem         )timezonemodificationDate)concatCodesr   r
   r   latlonr   admin1admin2cczrg_cities1000.csvgn#@gk{?c                    s   i  fdd}|S )z@
    Function to get single instance of the RGeocoder class
    c                     s"    vr di |  <   S )zI
        Creates a new RGeocoder instance if not created already
        N r3   )kwargscls	instancesr3   U/home/jeff/fluffinator/venv/lib/python3.10/site-packages/reverse_geocoder/__init__.pygetinstanceS   s   zsingleton.<locals>.getinstancer3   )r6   r9   r3   r5   r8   	singletonN   s   r:   c                   @   s2   e Zd ZdZdddZdd Zd	d
 Zdd ZdS )	RGeocoderz)
    The main reverse geocoder class
    r   TNc                 C   s\   || _ || _|r| |\}| _n
| tt\}| _|dkr&t|| _dS t	
|| _dS )aZ   Class Instantiation
        Args:
        mode (int): Library supports the following two modes:
                    - 1 = Single-threaded K-D Tree
                    - 2 = Multi-threaded K-D Tree (Default)
        verbose (bool): For verbose output, set to True
        stream (io.StringIO): An in-memory stream of a custom data source
        r	   N)modeverboseload	locationsextractrel_pathRG_FILEKDTreetree	KDTree_MPr   )selfr<   r=   streamcoordinatesr3   r3   r8   __init__a   s   	zRGeocoder.__init__c                    sF    j dkr jj|dd\}}n
 jj|dd\}} fdd|D S )z
        Function to query the K-D tree to find the nearest city
        Args:
        coordinates (list): List of tuple coordinates, i.e. [(latitude, longitude)]
        r	   )kc                    s   g | ]} j | qS r3   )r?   ).0indexrF   r3   r8   
<listcomp>   s    z#RGeocoder.query.<locals>.<listcomp>)r<   rD   querypquery)rF   rH   _indicesr3   rM   r8   rO   v   s   
zRGeocoder.queryc                 C   st   t j|dd}|j}|tkrt dddt  d g g }}|D ]}||d |d f || q#||fS )aA  
        Function that loads a custom data source
        Args:
        stream (io.StringIO): An in-memory stream of a custom data source.
                              The format of the stream must be a comma-separated file
                              with header containing the columns defined in RG_COLUMNS.
        ,	delimiterz<Input must be a comma-separated file with header containing z2the following columns - %s. For more help, visit: z-https://github.com/thampiman/reverse-geocoderr.   r/   )csv
DictReader
fieldnames
RG_COLUMNSErrorjoinappend)rF   rG   stream_readerheader
geo_coordsr?   rowr3   r3   r8   r>      s   
zRGeocoder.loadc                 C   s  t j|r| jrtd tt|d}nNtt	 d }tt
 }tt }t	d }t	d }t j|su| jr:td zddl}|j|| |j|t
 |j|t W n tyt   ddl}||| ||t
 ||t Y nw | jr|td tt|d	}	t|d
|	| | jrtd i }
tjtt
ddd}|D ]}|td  |
|td  < q| jrtd i }tjttdddD ]}|td  ||td  < q| jrtd tjt|dtd}g }tjt|ddtjdD ]Z}|td  }|td  }|td  }|td  }|td  }|td  }|d | }|d | d | }d}d}||
v r7|
| }||v r@|| }||||||d}|| q|  || | jr`td t | g g }}|D ]}||d |d f || ql||fS ) z
        Function loads the already extracted GeoNames cities file or downloads and extracts it if
        it doesn't exist locally
        Args:
        local_filename (str): Path to local RG_FILE
        z"Loading formatted geocoded file...rtz.zipz.txtz!Downloading files from Geoname...r   NzExtracting cities1000...rbwbzLoading admin1 codes...	rT   r
   r,   zLoading admin2 codes...z#Creating formatted geocoded file...wt)rX   )rU   quotingr   r   r   r   r   . r-   z.Removing extracted cities1000 to save space...r.   r/   )ospathexistsr=   printrV   rW   openGN_URLGN_CITIES1000	GN_ADMIN1	GN_ADMIN2urllib.requestrequesturlretrieveImportErrorurllibzipfileZipFilewritereadreaderADMIN_COLUMNS
DictWriterrY   
QUOTE_NONE
GN_COLUMNSr\   writeheader	writerowsremove)rF   local_filenamerowsgn_cities1000_urlgn_admin1_urlgn_admin2_urlcities1000_zipfilenamecities1000_filenamerv   _z
admin1_mapt_rowsr`   
admin2_mapwriterr.   r/   r   r2   admin1_cadmin2_c	cc_admin1	cc_admin2r0   r1   	write_rowr_   r?   r3   r3   r8   r@      s   





zRGeocoder.extract)r   TN)__name__
__module____qualname____doc__rI   rO   r>   r@   r3   r3   r3   r8   r;   \   s    
r;   c           	      C   s   t | t j} | d d df }| d d df }t |}t |}tt dtt |d    }|t 	| t 	| }|t 	| t | }|dt  t | }t 
|||gS )Nr   r	   r   )npasarrayastypefloatradiansAsqrtE2sincoscolumn_stack)	r_   r.   r/   lat_rlon_rnormalxyzr3   r3   r8   geodetic_in_ecef   s   

 r   c                 C   s   t jt  t jt| S )z:
    Function that gets relative path to the filename
    )ri   rj   r[   getcwddirname__file__)filenamer3   r3   r8   rA     s   rA   Tc                 C   s<   t | trt | d tstdt||d}|| gd S )z3
    Function to query for a single coordinate
    r   zExpecting a tupler<   r=   )
isinstancetupler   	TypeErrorr;   rO   )	geo_coordr<   r=   _rgr3   r3   r8   get  s   r   c                 C   sF   t | tst | tstdt | d ts| g} t||d}|| S )z5
    Function to query for a list of coordinates
    z+Expecting a tuple or a tuple/list of tuplesr   r   )r   r   listr   r;   rO   )r_   r<   r=   r   r3   r3   r8   search  s   
r   __main__z(Testing single coordinate through get...)g?:uB@g5!^zReverse geocoding 1 city...zTesting coordinates...))gv)I@g֫#ƿ)g?#@g衶S@)gvOjB@gAc]^zReverse geocoding %d cities...)r   T)+r   
__future__r   
__author__ri   sysrV   platformfield_size_limitmaxsizerw   scipy.spatialr   rC   reverse_geocoderr   rE   numpyr   rn   ro   rp   rq   r   r|   rY   rB   r   r   r:   objectr;   r   rA   r   r   r   rl   cityresultcitieslenresultsr3   r3   r3   r8   <module>   s    
	

  


