Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Added EquidistantCylindricalConversion(and PlateCaree alias) and LambertCylindricalEqualAreaScaleConversion #516

Merged
merged 3 commits into from Jan 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/api/crs/coordinate_operation.rst
Expand Up @@ -41,6 +41,14 @@ AzumuthalEquidistantConversion
:special-members: __new__


EquidistantCylindricalConversion
--------------------------------
.. autoclass:: pyproj.crs.coordinate_operation.EquidistantCylindricalConversion
:members:
:show-inheritance:
:special-members: __new__


GeostationarySatelliteConversion
--------------------------------

Expand Down Expand Up @@ -84,6 +92,12 @@ LambertCylindricalEqualAreaConversion
:show-inheritance:
:special-members: __new__

.. autoclass:: pyproj.crs.coordinate_operation.LambertCylindricalEqualAreaScaleConversion

:members:
:show-inheritance:
:special-members: __new__


MercatorAConversion
--------------------
Expand Down Expand Up @@ -120,6 +134,14 @@ OrthographicConversion
:special-members: __new__


PlateCareeConversion
--------------------------------
.. autoclass:: pyproj.crs.coordinate_operation.PlateCareeConversion
:members:
:show-inheritance:
:special-members: __new__


PolarStereographicAConversion
-----------------------------

Expand Down
130 changes: 130 additions & 0 deletions pyproj/crs/coordinate_operation.py
Expand Up @@ -539,6 +539,57 @@ def __new__(
return cls.from_json_dict(cea_json)


class LambertCylindricalEqualAreaScaleConversion(CoordinateOperation):
"""
.. versionadded:: 2.5.0

Class for constructing the Lambert Cylindrical Equal Area conversion.

This version uses the scale factor and differs from the official version.

The scale factor will be converted to the Latitude of 1st standard parallel (lat_ts)
when exporting to WKT in PROJ>=7.0.0. Previous version will export it as a
PROJ-based coordinate operation in the WKT.

https://proj.org/operations/projections/cea.html
"""

def __new__(
cls,
longitude_natural_origin=0.0,
false_easting=0.0,
false_northing=0.0,
scale_factor_natural_origin=1.0,
):
"""
Parameters
----------
longitude_natural_origin: float, optional
Longitude of projection center (lon_0). Defaults to 0.0.
false_easting: float, optional
False easting (x_0). Defaults to 0.0.
false_northing: float, optional
False northing (y_0). Defaults to 0.0.
scale_factor_natural_origin: float, optional
Scale factor at natural origin (k or k_0). Defaults to 1.0

"""
# hack due to: https://github.com/OSGeo/PROJ/issues/1881
# https://proj.org/operations/projections/cea.html
return cls.from_string(
"+proj=cea "
"+lon_0={longitude_natural_origin} "
"+x_0={false_easting} "
"+y_0={false_northing} "
"+k_0={scale_factor_natural_origin}".format(
longitude_natural_origin=longitude_natural_origin,
false_easting=false_easting,
false_northing=false_northing,
scale_factor_natural_origin=scale_factor_natural_origin,
)
)


class MercatorAConversion(CoordinateOperation):
"""
.. versionadded:: 2.5.0
Expand Down Expand Up @@ -1272,6 +1323,85 @@ def __new__(
return cls.from_json_dict(rot_latlon_json)


class EquidistantCylindricalConversion(CoordinateOperation):
"""
.. versionadded:: 2.5.0

Class for constructing the Equidistant Cylintrical (Plate Carrée) conversion.

https://proj.org/operations/projections/eqc.html
"""

def __new__(
cls,
latitude_first_parallel=0.0,
latitude_natural_origin=0.0,
longitude_natural_origin=0.0,
false_easting=0.0,
false_northing=0.0,
):
"""
Parameters
----------
latitude_first_parallel: float, optional
Latitude of 1st standard parallel (lat_ts). Defaults to 0.0.
latitude_natural_origin: float, optional
Longitude of projection center (lon_0). Defaults to 0.0.
longitude_natural_origin: float, optional
Longitude of projection center (lon_0). Defaults to 0.0.
false_easting: float, optional
False easting (x_0). Defaults to 0.0.
false_northing: float, optional
False northing (y_0). Defaults to 0.0.
"""
eqc_json = {
"$schema": "https://proj.org/schemas/v0.2/projjson.schema.json",
"type": "Conversion",
"name": "unknown",
"method": {
"name": "Equidistant Cylindrical",
"id": {"authority": "EPSG", "code": 1028},
},
"parameters": [
{
"name": "Latitude of 1st standard parallel",
"value": latitude_first_parallel,
"unit": "degree",
"id": {"authority": "EPSG", "code": 8823},
},
{
"name": "Latitude of natural origin",
"value": latitude_natural_origin,
"unit": "degree",
"id": {"authority": "EPSG", "code": 8801},
},
{
"name": "Longitude of natural origin",
"value": longitude_natural_origin,
"unit": "degree",
"id": {"authority": "EPSG", "code": 8802},
},
{
"name": "False easting",
"value": false_easting,
"unit": "metre",
"id": {"authority": "EPSG", "code": 8806},
},
{
"name": "False northing",
"value": false_northing,
"unit": "metre",
"id": {"authority": "EPSG", "code": 8807},
},
],
}
return cls.from_json_dict(eqc_json)


# Add an alias for PlateCaree
PlateCareeConversion = EquidistantCylindricalConversion


class ToWGS84Transformation(CoordinateOperation):
"""
.. versionadded:: 2.5.0
Expand Down
84 changes: 74 additions & 10 deletions test/crs/test_crs_coordinate_operation.py
Expand Up @@ -4,15 +4,18 @@
from pyproj.crs.coordinate_operation import (
AlbersEqualAreaConversion,
AzumuthalEquidistantConversion,
EquidistantCylindricalConversion,
GeostationarySatelliteConversion,
HotineObliqueMercatorBConversion,
LambertAzumuthalEqualAreaConversion,
LambertConformalConic1SPConversion,
LambertConformalConic2SPConversion,
LambertCylindricalEqualAreaConversion,
LambertCylindricalEqualAreaScaleConversion,
MercatorAConversion,
MercatorBConversion,
OrthographicConversion,
PlateCareeConversion,
PolarStereographicAConversion,
PolarStereographicBConversion,
RotatedLatitudeLongitudeConversion,
Expand Down Expand Up @@ -221,7 +224,7 @@ def test_lambert_conformat_conic_1sp_operation():
longitude_natural_origin=2,
false_easting=3,
false_northing=4,
scale_factor_natural_origin=5,
scale_factor_natural_origin=0.5,
)
assert aeaop.name == "unknown"
assert aeaop.method_name == "Lambert Conic Conformal (1SP)"
Expand All @@ -230,7 +233,7 @@ def test_lambert_conformat_conic_1sp_operation():
"Longitude of natural origin": 2.0,
"False easting": 3.0,
"False northing": 4.0,
"Scale factor at natural origin": 5.0,
"Scale factor at natural origin": 0.5,
}


Expand Down Expand Up @@ -282,7 +285,7 @@ def test_mercator_a_operation():
longitude_natural_origin=2,
false_easting=3,
false_northing=4,
scale_factor_natural_origin=5,
scale_factor_natural_origin=0.5,
)
assert aeaop.name == "unknown"
assert aeaop.method_name == "Mercator (variant A)"
Expand All @@ -291,7 +294,7 @@ def test_mercator_a_operation():
"Longitude of natural origin": 2.0,
"False easting": 3.0,
"False northing": 4.0,
"Scale factor at natural origin": 5.0,
"Scale factor at natural origin": 0.5,
}


Expand Down Expand Up @@ -350,7 +353,7 @@ def test_hotline_oblique_mercator_b_operation():
longitude_projection_centre=2,
azimuth_initial_line=3,
angle_from_rectified_to_skew_grid=4,
scale_factor_on_initial_line=5,
scale_factor_on_initial_line=0.5,
easting_projection_centre=6,
northing_projection_centre=7,
)
Expand All @@ -361,7 +364,7 @@ def test_hotline_oblique_mercator_b_operation():
"Longitude of projection centre": 2.0,
"Azimuth of initial line": 3.0,
"Angle from Rectified to Skew Grid": 4.0,
"Scale factor on initial line": 5.0,
"Scale factor on initial line": 0.5,
"Easting at projection centre": 6.0,
"Northing at projection centre": 7.0,
}
Expand Down Expand Up @@ -415,7 +418,7 @@ def test_polar_stereographic_a_operation():
longitude_natural_origin=2,
false_easting=3,
false_northing=4,
scale_factor_natural_origin=5,
scale_factor_natural_origin=0.5,
)
assert aeaop.name == "unknown"
assert aeaop.method_name == "Polar Stereographic (variant A)"
Expand All @@ -424,7 +427,7 @@ def test_polar_stereographic_a_operation():
"Longitude of natural origin": 2.0,
"False easting": 3.0,
"False northing": 4.0,
"Scale factor at natural origin": 5.0,
"Scale factor at natural origin": 0.5,
}


Expand Down Expand Up @@ -512,7 +515,7 @@ def test_transverse_mercator_operation():
longitude_natural_origin=2,
false_easting=3,
false_northing=4,
scale_factor_natural_origin=5,
scale_factor_natural_origin=0.5,
)
assert aeaop.name == "unknown"
assert aeaop.method_name == "Transverse Mercator"
Expand All @@ -521,7 +524,7 @@ def test_transverse_mercator_operation():
"Longitude of natural origin": 2.0,
"False easting": 3.0,
"False northing": 4.0,
"Scale factor at natural origin": 5.0,
"Scale factor at natural origin": 0.5,
}


Expand Down Expand Up @@ -580,6 +583,67 @@ def test_rotated_latitude_longitude_operation():
assert _to_dict(aeaop) == {"o_lat_p": 1.0, "o_lon_p": 2.0, "lon_0": 3.0}


def test_lambert_cylindrical_equidistant_scale_operation__defaults():
aeaop = LambertCylindricalEqualAreaScaleConversion()
assert aeaop.name == "PROJ-based coordinate operation"
assert aeaop.method_name == (
"PROJ-based operation method: +proj=cea +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k_0=1.0"
)
assert _to_dict(aeaop) == {}


def test_lambert_cylindrical_equidistant_scale_operation():
aeaop = LambertCylindricalEqualAreaScaleConversion(
longitude_natural_origin=2,
false_easting=3,
false_northing=4,
scale_factor_natural_origin=0.5,
)
assert aeaop.name == "PROJ-based coordinate operation"
assert aeaop.method_name == (
"PROJ-based operation method: +proj=cea +lon_0=2 +x_0=3 +y_0=4 +k_0=0.5"
)
assert _to_dict(aeaop) == {}


@pytest.mark.parametrize(
"eqc_class", [EquidistantCylindricalConversion, PlateCareeConversion]
)
def test_equidistant_cylindrical_conversion__defaults(eqc_class):
eqc = eqc_class()
assert eqc.name == "unknown"
assert eqc.method_name == "Equidistant Cylindrical"
assert _to_dict(eqc) == {
"Latitude of 1st standard parallel": 0.0,
"Latitude of natural origin": 0.0,
"Longitude of natural origin": 0.0,
"False easting": 0.0,
"False northing": 0.0,
}


@pytest.mark.parametrize(
"eqc_class", [EquidistantCylindricalConversion, PlateCareeConversion]
)
def test_equidistant_cylindrical_conversion(eqc_class):
eqc = eqc_class(
latitude_first_parallel=1.0,
latitude_natural_origin=2.0,
longitude_natural_origin=3.0,
false_easting=4.0,
false_northing=5.0,
)
assert eqc.name == "unknown"
assert eqc.method_name == "Equidistant Cylindrical"
assert _to_dict(eqc) == {
"Latitude of 1st standard parallel": 1.0,
"Latitude of natural origin": 2.0,
"Longitude of natural origin": 3.0,
"False easting": 4.0,
"False northing": 5.0,
}


def test_towgs84_transformation():
transformation = ToWGS84Transformation(GeographicCRS(), 1, 2, 3, 4, 5, 6, 7)
assert transformation.towgs84 == [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
Expand Down