1"""crs module tests""" 2 3import json 4import logging 5import os 6import subprocess 7 8import pytest 9 10import rasterio 11from rasterio._crs import _CRS 12from rasterio.env import env_ctx_if_needed, Env 13from rasterio.errors import CRSError 14 15from .conftest import requires_gdal21, requires_gdal22, requires_gdal_lt_3 16 17 18# Items like "D_North_American_1983" characterize the Esri dialect 19# of WKT SRS. 20ESRI_PROJECTION_STRING = ( 21 'PROJCS["USA_Contiguous_Albers_Equal_Area_Conic_USGS_version",' 22 'GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",' 23 'SPHEROID["GRS_1980",6378137.0,298.257222101]],' 24 'PRIMEM["Greenwich",0.0],' 25 'UNIT["Degree",0.0174532925199433]],' 26 'PROJECTION["Albers"],' 27 'PARAMETER["false_easting",0.0],' 28 'PARAMETER["false_northing",0.0],' 29 'PARAMETER["central_meridian",-96.0],' 30 'PARAMETER["standard_parallel_1",29.5],' 31 'PARAMETER["standard_parallel_2",45.5],' 32 'PARAMETER["latitude_of_origin",23.0],' 33 'UNIT["Meter",1.0],' 34 'VERTCS["NAVD_1988",' 35 'VDATUM["North_American_Vertical_Datum_1988"],' 36 'PARAMETER["Vertical_Shift",0.0],' 37 'PARAMETER["Direction",1.0],UNIT["Centimeter",0.01]]]') 38 39 40def test_from_dict(): 41 """Can create a _CRS from a dict""" 42 crs = _CRS.from_dict({'init': 'epsg:3857'}) 43 assert crs.to_dict()['proj'] == 'merc' 44 assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"' in crs.to_wkt() 45 46 47def test_from_dict_keywords(): 48 """Can create a CRS from keyword args, ignoring unknowns""" 49 crs = _CRS.from_dict(init='epsg:3857', foo='bar') 50 assert crs.to_dict()['proj'] == 'merc' 51 assert 'PROJCS["WGS 84 / Pseudo-Mercator",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"' in crs.to_wkt() 52 53 54def test_from_epsg(): 55 """Can create a CRS from EPSG code""" 56 crs = _CRS.from_epsg(4326) 57 assert crs.to_dict()['proj'] == 'longlat' 58 59 60@pytest.mark.parametrize('code', [0, -1, float('nan'), 1.3]) 61def test_from_epsg_error(code): 62 """Raise exception with invalid EPSG code""" 63 with pytest.raises(ValueError): 64 assert _CRS.from_epsg(code) 65 66 67@pytest.mark.parametrize('proj,expected', [({'init': 'epsg:4326'}, True), ({'init': 'epsg:3857'}, False)]) 68def test_is_geographic(proj, expected): 69 """CRS is or is not geographic""" 70 assert _CRS.from_dict(proj).is_geographic is expected 71 72 73@pytest.mark.parametrize('proj,expected', [({'init': 'epsg:4326'}, False), ({'init': 'epsg:3857'}, True)]) 74def test_is_projected(proj, expected): 75 """CRS is or is not projected""" 76 assert _CRS.from_dict(proj).is_projected is expected 77 78 79def test_equality(): 80 """CRS are or are not equal""" 81 _CRS.from_epsg(4326) == _CRS.from_proj4('+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs') 82 83 84def test_to_wkt(): 85 """CRS converts to WKT""" 86 assert _CRS.from_dict({'init': 'epsg:4326'}).to_wkt().startswith('GEOGCS["WGS 84",DATUM') 87 88 89@pytest.mark.parametrize('proj_string', ['+init=epsg:4326', '+proj=longlat +datum=WGS84 +no_defs']) 90def test_to_epsg(proj_string): 91 """CRS has EPSG code""" 92 assert _CRS.from_proj4(proj_string).to_epsg(confidence_threshold=20) == 4326 93 94 95@pytest.mark.parametrize('proj_string', [ESRI_PROJECTION_STRING]) 96def test_esri_wkt_to_epsg(proj_string): 97 """CRS has no EPSG code""" 98 assert _CRS.from_wkt(proj_string, morph_from_esri_dialect=True).to_epsg() is None 99 100 101def test_epsg_no_code_available(): 102 """CRS has no EPSG code""" 103 lcc_crs = _CRS.from_proj4('+lon_0=-95 +ellps=GRS80 +y_0=0 +no_defs=True +proj=lcc +x_0=0 +units=m +lat_2=77 +lat_1=49 +lat_0=0') 104 assert lcc_crs.to_epsg() is None 105 106 107def test_from_wkt_invalid(): 108 """Raise exception if input WKT is invalid""" 109 with pytest.raises(CRSError): 110 _CRS.from_wkt('bogus') 111 112 113@requires_gdal_lt_3 114@pytest.mark.parametrize('projection_string', [ESRI_PROJECTION_STRING]) 115def test_from_esri_wkt_no_fix(projection_string): 116 """Test ESRI CRS morphing with no datum fixing""" 117 with Env(): 118 crs = _CRS.from_wkt(projection_string) 119 assert 'DATUM["D_North_American_1983"' in crs.to_wkt() 120 121 122@requires_gdal_lt_3 123@pytest.mark.parametrize('projection_string', [ESRI_PROJECTION_STRING]) 124def test_from_esri_wkt_fix_datum(projection_string): 125 """Test ESRI CRS morphing with datum fixing""" 126 with Env(GDAL_FIX_ESRI_WKT='DATUM'): 127 crs = _CRS.from_wkt(projection_string, morph_from_esri_dialect=True) 128 assert 'DATUM["North_American_Datum_1983"' in crs.to_wkt() 129 130 131@requires_gdal_lt_3 132def test_to_esri_wkt_fix_datum(): 133 """Morph to Esri form""" 134 assert 'DATUM["D_North_American_1983"' in _CRS.from_dict(init='epsg:26913').to_wkt(morph_to_esri_dialect=True) 135 136 137def test_compound_crs(): 138 """Parse compound WKT""" 139 wkt = """COMPD_CS["unknown",GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433],AUTHORITY["EPSG","4326"]],VERT_CS["unknown",VERT_DATUM["unknown",2005],UNIT["metre",1.0,AUTHORITY["EPSG","9001"]],AXIS["Up",UP]]]""" 140 assert _CRS.from_wkt(wkt).to_wkt().startswith('COMPD_CS') 141 142 143def test_exception_proj4(): 144 """Get the exception message we expect""" 145 with pytest.raises(CRSError): 146 _CRS.from_proj4("+proj=bogus") 147 148 149def test_linear_units(): 150 """CRS linear units can be had""" 151 assert _CRS.from_epsg(3857).linear_units == 'metre' 152