def test_from_cf_transverse_mercator(towgs84_test): crs = CRS.from_cf({ "grid_mapping_name": "transverse_mercator", "latitude_of_projection_origin": 0, "longitude_of_central_meridian": 15, "false_easting": 2520000, "false_northing": 0, "reference_ellipsoid_name": "intl", "towgs84": towgs84_test, "unit": "m", }) expected_cf = { "semi_major_axis": 6378388.0, "semi_minor_axis": crs.ellipsoid.semi_minor_metre, "inverse_flattening": 297.0, "reference_ellipsoid_name": "International 1909 (Hayford)", "longitude_of_prime_meridian": 0.0, "prime_meridian_name": "Greenwich", "grid_mapping_name": "transverse_mercator", "latitude_of_projection_origin": 0.0, "longitude_of_central_meridian": 15.0, "false_easting": 2520000.0, "false_northing": 0.0, "scale_factor_at_central_meridian": 1.0, } cf_dict = crs.to_cf() assert cf_dict.pop("crs_wkt").startswith("BOUNDCRS[") assert_almost_equal(cf_dict.pop("towgs84"), _try_list_if_string(towgs84_test)) assert cf_dict == expected_cf # test roundtrip expected_cf["towgs84"] = _try_list_if_string(towgs84_test) _test_roundtrip(expected_cf, "BOUNDCRS[")
def parse(val): if val.lower() == "true": return True elif val.lower() == "false": return False try: return int(val) except ValueError: pass try: return float(val) except ValueError: pass return _try_list_if_string(val)
def from_cf(in_cf: dict, errcheck=False) -> "CRS": """ .. versionadded:: 2.2.0 This converts a Climate and Forecast (CF) Grid Mapping Version 1.8 dict to a :obj:`pyproj.crs.CRS` object. .. warning:: Parameters may be lost if a mapping from the CF parameter is not found. For best results store the WKT of the projection in the crs_wkt attribute. Parameters ---------- in_cf: dict CF version of the projection. errcheck: bool, optional This parameter is for backwards compatibility with the old version. It currently does nothing when True or False. Returns ------- CRS """ unknown_names = ("unknown", "undefined") if "crs_wkt" in in_cf: return CRS(in_cf["crs_wkt"]) elif "spatial_ref" in in_cf: # for previous supported WKT key return CRS(in_cf["spatial_ref"]) grid_mapping_name = in_cf.get("grid_mapping_name") if grid_mapping_name is None: raise CRSError( "CF projection parameters missing 'grid_mapping_name'") # build datum if possible datum = _horizontal_datum_from_params(in_cf) # build geographic CRS try: geographic_conversion_method = _GEOGRAPHIC_GRID_MAPPING_NAME_MAP[ grid_mapping_name] # type: Optional[Callable] except KeyError: geographic_conversion_method = None geographic_crs_name = in_cf.get("geographic_crs_name") if datum: geographic_crs = GeographicCRS( name=geographic_crs_name or "undefined", datum=datum, ) # type: CRS elif geographic_crs_name and geographic_crs_name not in unknown_names: geographic_crs = CRS(geographic_crs_name) else: geographic_crs = GeographicCRS() if grid_mapping_name == "latitude_longitude": return geographic_crs if geographic_conversion_method is not None: return DerivedGeographicCRS( base_crs=geographic_crs, conversion=geographic_conversion_method(in_cf), ) # build projected CRS try: conversion_method = _GRID_MAPPING_NAME_MAP[grid_mapping_name] except KeyError: raise CRSError( "Unsupported grid mapping name: {}".format(grid_mapping_name)) projected_crs = ProjectedCRS( name=in_cf.get("projected_crs_name", "undefined"), conversion=conversion_method(in_cf), geodetic_crs=geographic_crs, ) # build bound CRS if exists bound_crs = None if "towgs84" in in_cf: bound_crs = BoundCRS( source_crs=projected_crs, target_crs="WGS 84", transformation=ToWGS84Transformation( projected_crs.geodetic_crs, *_try_list_if_string(in_cf["towgs84"])), ) if "geopotential_datum_name" not in in_cf: return bound_crs or projected_crs # build Vertical CRS vertical_crs = VerticalCRS( name="undefined", datum=in_cf["geopotential_datum_name"], geoid_model=in_cf.get("geoid_name"), ) # build compound CRS return CompoundCRS( name="undefined", components=[bound_crs or projected_crs, vertical_crs])
def from_cf( in_cf: dict, ellipsoidal_cs: Any = None, cartesian_cs: Any = None, vertical_cs: Any = None, errcheck=False, ) -> "CRS": """ .. versionadded:: 2.2.0 .. versionadded:: 3.0.0 ellipsoidal_cs, cartesian_cs, vertical_cs This converts a Climate and Forecast (CF) Grid Mapping Version 1.8 dict to a :obj:`pyproj.crs.CRS` object. :ref:`build_crs_cf` Parameters ---------- in_cf: dict CF version of the projection. ellipsoidal_cs: Any, optional Input to create an Ellipsoidal Coordinate System. Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` or an Ellipsoidal Coordinate System created from :ref:`coordinate_system`. cartesian_cs: Any, optional Input to create a Cartesian Coordinate System. Anything accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` or :class:`pyproj.crs.coordinate_system.Cartesian2DCS`. vertical_cs: Any, optional Input to create a Vertical Coordinate System accepted by :meth:`pyproj.crs.CoordinateSystem.from_user_input` or :class:`pyproj.crs.coordinate_system.VerticalCS` errcheck: bool, optional This parameter is for backwards compatibility with the old version. It currently does nothing when True or False. Returns ------- CRS """ unknown_names = ("unknown", "undefined") if "crs_wkt" in in_cf: return CRS(in_cf["crs_wkt"]) elif "spatial_ref" in in_cf: # for previous supported WKT key return CRS(in_cf["spatial_ref"]) grid_mapping_name = in_cf.get("grid_mapping_name") if grid_mapping_name is None: raise CRSError( "CF projection parameters missing 'grid_mapping_name'") # build datum if possible datum = _horizontal_datum_from_params(in_cf) # build geographic CRS try: geographic_conversion_method = _GEOGRAPHIC_GRID_MAPPING_NAME_MAP[ grid_mapping_name] # type: Optional[Callable] except KeyError: geographic_conversion_method = None geographic_crs_name = in_cf.get("geographic_crs_name") if datum: geographic_crs = GeographicCRS( name=geographic_crs_name or "undefined", datum=datum, ellipsoidal_cs=ellipsoidal_cs, ) # type: CRS elif geographic_crs_name and geographic_crs_name not in unknown_names: geographic_crs = CRS(geographic_crs_name) if ellipsoidal_cs is not None: geographic_crs_json = geographic_crs.to_json_dict() geographic_crs_json[ "coordinate_system"] = CoordinateSystem.from_user_input( ellipsoidal_cs).to_json_dict() geographic_crs = CRS(geographic_crs_json) else: geographic_crs = GeographicCRS(ellipsoidal_cs=ellipsoidal_cs) if grid_mapping_name == "latitude_longitude": return geographic_crs if geographic_conversion_method is not None: return DerivedGeographicCRS( base_crs=geographic_crs, conversion=geographic_conversion_method(in_cf), ellipsoidal_cs=ellipsoidal_cs, ) # build projected CRS try: conversion_method = _GRID_MAPPING_NAME_MAP[grid_mapping_name] except KeyError: raise CRSError( f"Unsupported grid mapping name: {grid_mapping_name}") projected_crs = ProjectedCRS( name=in_cf.get("projected_crs_name", "undefined"), conversion=conversion_method(in_cf), geodetic_crs=geographic_crs, cartesian_cs=cartesian_cs, ) # build bound CRS if exists bound_crs = None if "towgs84" in in_cf: bound_crs = BoundCRS( source_crs=projected_crs, target_crs="WGS 84", transformation=ToWGS84Transformation( projected_crs.geodetic_crs, *_try_list_if_string(in_cf["towgs84"])), ) if "geopotential_datum_name" not in in_cf: return bound_crs or projected_crs # build Vertical CRS vertical_crs = VerticalCRS( name="undefined", datum=in_cf["geopotential_datum_name"], geoid_model=in_cf.get("geoid_name"), vertical_cs=vertical_cs, ) # build compound CRS return CompoundCRS( name="undefined", components=[bound_crs or projected_crs, vertical_crs])