├── .gitignore ├── requirements.txt ├── setup.py ├── guessrs ├── __pycache__ │ ├── __init__.cpython-37.pyc │ └── __main__.cpython-37.pyc ├── __main__.py ├── __init__.py └── data │ └── regions.txt ├── README.md └── setup.cfg /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | *.egg-info 4 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools>=40 2 | pyproj>=2.2 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | setup() 3 | -------------------------------------------------------------------------------- /guessrs/__pycache__/__init__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fitnr/guessrs/master/guessrs/__pycache__/__init__.cpython-37.pyc -------------------------------------------------------------------------------- /guessrs/__pycache__/__main__.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fitnr/guessrs/master/guessrs/__pycache__/__main__.cpython-37.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # guessrs 2 | 3 | Tries to match source coordinates against state plane, UTM, and several national projections. 4 | 5 | Example: 6 | ``` 7 | $ guessrs 2180123.68 1167481.35 2344933.16 1259185.56 -90.583534 39.872503 -89.994405 40.125292 8 | 6457 NAD83(2011) / Illinois West (ftUS) -0.00190 0.00059 -0.00063 0.00092 9 | ``` 10 | 11 | The elements of the command are: 12 | * A bounding box in an unknown projection: `2180123.68 1167481.35 2344933.16 1259185.56` 13 | * The known bounding box (in geographic coordinates) of the mapped region: `-90.5835 39.8725 -89.9944 40.1252` 14 | 15 | The result is tab-delimited, with the following fields: EPSG code, projection name, the difference between the source coordinates and the target in this projection. 16 | 17 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = guessrs 3 | version = 0.1.0 4 | author = Neil Freeman 5 | author_email = contact@fakeisthenewreal.org 6 | description = Guess the spatial reference system for unknown coordinates (U.S.-only) 7 | license = GNU General Public License v3 (GPLv3) 8 | classifiers = 9 | Programming Language :: Python :: 3 10 | Programming Language :: Python :: 3.6 11 | Programming Language :: Python :: 3.7 12 | License :: OSI Approved :: GNU General Public License v3 (GPLv3) 13 | 14 | [options] 15 | zip_safe = True 16 | packages = find: 17 | include_package_data = True 18 | install_requires = 19 | setuptools>=40 20 | pyproj>=2.2 21 | 22 | [options.package_data] 23 | data = data/*.txt 24 | 25 | [options.entry_points] 26 | console_scripts = guessrs = guessrs.__main__:main 27 | -------------------------------------------------------------------------------- /guessrs/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import argparse 3 | from pyproj import Proj 4 | from . import get_regions, get_projections, intersect 5 | 6 | out_format = "{}\t{}\t{x[0]:.5f}\t{y[0]:.5f}\t{x[1]:.5f}\t{y[1]:.5f}" 7 | 8 | def main(): 9 | parser = argparse.ArgumentParser(prog='guessrs') 10 | parser.add_argument('source', nargs=4, type=float, help='bounding box in unknown projected coordinates') 11 | parser.add_argument('target', nargs=4, type=float, help='bounding box in geographic coordinates') 12 | 13 | args = parser.parse_args() 14 | 15 | target = args.target 16 | regions = list(get_regions(target)) 17 | projections = get_projections(*[r['region'] for r in regions]) 18 | 19 | for projection in projections: 20 | p = Proj(projection['wkt']) 21 | x, y = p(args.source[::2], args.source[1::2], inverse=True) 22 | if intersect((x[0], y[0], x[1], y[1]), target): 23 | xd, yd = (target[0] - x[0], target[2] - x[1]), (target[1] - y[0], target[3] - y[1]) 24 | print(out_format.format(projection['epsg'], p.crs.name, x=xd, y=yd), file=sys.stdout) 25 | 26 | 27 | if __name__ == '__main__': 28 | main() 29 | -------------------------------------------------------------------------------- /guessrs/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import pkg_resources 3 | from pyproj import Proj 4 | 5 | PROJECTIONS = 'data/projections.txt' 6 | REGIONS = 'data/regions.txt' 7 | 8 | 9 | def reader(path): 10 | with pkg_resources.resource_stream('guessrs', path) as f: 11 | fields = f.readline().decode('ascii').strip().split('\t') 12 | for line in f: 13 | values = line.decode('ascii').strip().split('\t') 14 | yield dict(zip(fields, values)) 15 | 16 | 17 | def get_regions(bbox): 18 | '''Given a bounding box in geographic coordinates, find regions that overlap with it''' 19 | for row in reader(REGIONS): 20 | row_box = tuple(float(t) for t in (row['x0'], row['y0'], row['x1'], row['y1'])) 21 | if intersect(bbox, row_box): 22 | yield row 23 | 24 | 25 | def get_projections(*regions): 26 | '''Given a set of region names, find projections that match it''' 27 | for row in reader(PROJECTIONS): 28 | if row['region'] in regions: 29 | yield row 30 | 31 | 32 | def inverse(srs_text, bbox): 33 | '''Given projectioned coordinates, inv-project to geographic coordinates.''' 34 | x, y = Proj(srs_text)(bbox[::2], bbox[1::2], inverse=True) 35 | return x[0], y[0], x[1], y[1] 36 | 37 | 38 | def project(srs_text, bbox): 39 | '''Given a projection and a bbox, project geographic coordinates to it''' 40 | x, y = Proj(srs_text)(bbox[::2], bbox[1::2]) 41 | return x[0], y[0], x[1], y[1] 42 | 43 | 44 | def intersect(a, b): 45 | '''Given two bboxes, check if they overlap.''' 46 | return not (a[2] < b[0] or a[0] > b[2] or a[3] < b[1] or a[1] > b[3]) 47 | -------------------------------------------------------------------------------- /guessrs/data/regions.txt: -------------------------------------------------------------------------------- 1 | region name x0 y0 x1 y1 2 | 54 West Virginia -82.644591 37.20154 -77.719519 40.638801 3 | 12 Florida -87.634896 24.396308 -79.974306 31.000968 4 | 17 Illinois -91.513079 36.970298 -87.019935 42.508481 5 | 27 Minnesota -97.239093 43.499361 -89.483385 49.384358 6 | 24 Maryland -79.487651 37.886605 -74.986282 39.723037 7 | 44 Rhode Island -71.907258 41.095834 -71.088571 42.018799 8 | 16 Idaho -117.243027 41.988182 -111.043495 49.000911 9 | 33 New Hampshire -72.557124 42.697042 -70.575094 45.305778 10 | 37 North Carolina -84.321821 33.752878 -75.400119 36.588137 11 | 50 Vermont -73.437905 42.726933 -71.465047 45.016659 12 | 09 Connecticut -73.727775 40.950943 -71.787239 42.050511 13 | 10 Delaware -75.789023 38.451132 -74.984165 39.839516 14 | 35 New Mexico -109.050431 31.332231 -103.002043 37.000233 15 | 06 California -124.482003 32.528832 -114.131211 42.009503 16 | 34 New Jersey -75.563586 38.788657 -73.88506 41.357423 17 | 55 Wisconsin -92.889433 42.49172 -86.249548 47.309822 18 | 41 Oregon -124.703541 41.992082 -116.463262 46.299099 19 | 31 Nebraska -104.053514 39.999932 -95.30829 43.001707 20 | 42 Pennsylvania -80.519851 39.719799 -74.689502 42.516072 21 | 53 Washington -124.848974 45.543541 -116.916071 49.002432 22 | 22 Louisiana -94.043352 28.855127 -88.758388 33.019543 23 | 13 Georgia -85.605165 30.355757 -80.751429 35.001303 24 | 01 Alabama -88.473227 30.144425 -84.888246 35.008028 25 | 49 Utah -114.052885 36.997657 -109.041572 42.001702 26 | 39 Ohio -84.820305 38.403423 -80.518705 42.327132 27 | 48 Texas -106.645646 25.837164 -93.508039 36.500704 28 | 08 Colorado -109.060204 36.992449 -102.041522 41.003444 29 | 45 South Carolina -83.353928 32.033454 -78.499301 35.21554 30 | 40 Oklahoma -103.002413 33.615787 -94.43101 37.002312 31 | 47 Tennessee -90.310298 34.982924 -81.6469 36.678255 32 | 56 Wyoming -111.054558 40.994772 -104.052245 45.005815 33 | 15 Hawaii -178.443593 18.86546 -154.755792 28.517269 34 | 38 North Dakota -104.049118 45.935072 -96.554411 49.000692 35 | 21 Kentucky -89.571203 36.497058 -81.964788 39.147732 36 | 69 Commonwealth of the Northern Mariana Islands 144.813338 14.036565 146.154418 20.616556 37 | 66 Guam 144.563426 13.182335 145.009167 13.706179 38 | 23 Maine -71.083928 42.917126 -66.885444 47.459854 39 | 36 New York -79.76259 40.477399 -71.777491 45.015865 40 | 32 Nevada -120.006473 35.001857 -114.039461 42.001842 41 | 02 Alaska -179.231086 51.175092 179.859681 71.439786 42 | 60 American Samoa -171.141907 -14.601813 -168.101612 -10.997203 43 | 26 Michigan -90.418392 41.696118 -82.122971 48.306063 44 | 05 Arkansas -94.617919 33.004106 -89.644395 36.499749 45 | 28 Mississippi -91.655009 30.139845 -88.097888 34.996099 46 | 29 Missouri -95.774704 35.995683 -89.098968 40.61364 47 | 30 Montana -116.049153 44.357915 -104.039694 49.0011 48 | 20 Kansas -102.051769 36.993016 -94.588387 40.003166 49 | 18 Indiana -88.097892 37.771728 -84.784592 41.761368 50 | 72 Puerto Rico -67.998751 17.831509 -65.168503 18.568002 51 | 46 South Dakota -104.057879 42.479686 -96.436472 45.945377 52 | 25 Massachusetts -73.50821 41.187053 -69.858861 42.886778 53 | 51 Virginia -83.675395 36.540852 -75.166435 39.466012 54 | 11 District of Columbia -77.119759 38.791645 -76.909393 38.995845 55 | 19 Iowa -96.639485 40.37544 -90.140061 43.501196 56 | 04 Arizona -114.816591 31.332177 -109.045172 37.003725 57 | 78 United States Virgin Islands -65.154118 17.623468 -64.512674 18.464984 58 | UTM00 UTM 00 -179.999988540844 -89 179.999988540844 89 59 | UTM01 UTM 01 -179.999988540844 -80.000000060536 -174.000000002794 84.000000086613 60 | UTM02 UTM 02 -174.000000002794 -80.000000060536 -168.000000005588 84.000000086613 61 | UTM03 UTM 03 -168.000000005588 -80.000000060536 -162.000000008382 84.000000086613 62 | UTM04 UTM 04 -162.000000008382 -80.000000060536 -156.000000011176 84.000000086613 63 | UTM05 UTM 05 -156.000000011176 -80.000000060536 -150.00000001397 84.000000086613 64 | UTM06 UTM 06 -150.00000001397 -80.000000060536 -144.000000016764 84.000000086613 65 | UTM07 UTM 07 -144.000000016764 -80.000000060536 -138.000000019558 84.000000086613 66 | UTM08 UTM 08 -138.000000019558 -80.000000060536 -132.000000022352 84.000000086613 67 | UTM09 UTM 09 -132.000000022352 -80.000000060536 -126.000000025146 84.000000086613 68 | UTM10 UTM 10 -126.000000025146 -80.000000060536 -120.00000002794 84.000000086613 69 | UTM11 UTM 11 -120.00000002794 -80.000000060536 -113.999999863096 84.000000086613 70 | UTM12 UTM 12 -113.999999863096 -80.000000060536 -107.99999986589 84.000000086613 71 | UTM13 UTM 13 -107.99999986589 -80.000000060536 -101.999999868684 84.000000086613 72 | UTM14 UTM 14 -101.999999868684 -80.000000060536 -95.9999998714775 84.000000086613 73 | UTM15 UTM 15 -95.9999998714775 -80.000000060536 -89.9999998742715 84.000000086613 74 | UTM16 UTM 16 -89.9999998742715 -80.000000060536 -83.9999998770654 84.000000086613 75 | UTM17 UTM 17 -83.9999998770654 -80.000000060536 -77.9999998798594 84.000000086613 76 | UTM18 UTM 18 -77.9999998798594 -80.000000060536 -71.9999998826534 84.000000086613 77 | UTM19 UTM 19 -71.9999998826534 -80.000000060536 -65.9999998854473 84.000000086613 78 | UTM20 UTM 20 -65.9999998854473 -80.000000060536 -59.9999998882413 84.000000086613 79 | UTM21 UTM 21 -59.9999998882413 -80.000000060536 -53.9999998910353 84.000000086613 80 | UTM22 UTM 22 -53.9999998910353 -80.000000060536 -47.9999998938292 84.000000086613 81 | UTM23 UTM 23 -47.9999998938292 -80.000000060536 -41.9999998966232 84.000000086613 82 | UTM59 UTM 59 168.000000340864 -80.000000060536 174.00000033807 84.000000086613 83 | UTM60 UTM 60 174.00000033807 -80.000000060536 179.999988540844 84.000000086613 84 | 00 USA -178.2176000000000045 18.9217818181818984 -66.9692749999999961 71.4062358181818979 85 | --------------------------------------------------------------------------------