Skip to content

Commit 703098c

Browse files
authored
ENH: Azimuthal rotation for Orthographic projection (#2504)
* Added support for azimuthal rotation of Orthographic projection
1 parent 4566fbc commit 703098c

File tree

2 files changed

+40
-9
lines changed

2 files changed

+40
-9
lines changed

lib/cartopy/crs.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,9 +2094,14 @@ class Orthographic(Projection):
20942094
_handles_ellipses = False
20952095

20962096
def __init__(self, central_longitude=0.0, central_latitude=0.0,
2097-
globe=None):
2097+
azimuth=0.0, globe=None):
20982098
proj4_params = [('proj', 'ortho'), ('lon_0', central_longitude),
2099-
('lat_0', central_latitude)]
2099+
('lat_0', central_latitude), ('alpha', azimuth)]
2100+
if pyproj.__proj_version__ < '9.5.0' and azimuth != 0.0:
2101+
warnings.warn(
2102+
'Setting azimuth is not supported with PROJ versions < 9.5.0. '
2103+
'Assuming azimuth=0. '
2104+
'Current PROJ version: %s' % pyproj.__proj_version__)
21002105
super().__init__(proj4_params, globe=globe)
21012106

21022107
# TODO: Let the globe return the semimajor axis always.

lib/cartopy/tests/crs/test_orthographic.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import numpy as np
1111
from numpy.testing import assert_almost_equal
12+
import pyproj
1213
import pytest
1314

1415
import cartopy.crs as ccrs
@@ -17,7 +18,7 @@
1718

1819
def test_default():
1920
ortho = ccrs.Orthographic()
20-
other_args = {'a=6378137.0', 'lon_0=0.0', 'lat_0=0.0'}
21+
other_args = {'a=6378137.0', 'lat_0=0.0', 'lon_0=0.0', 'alpha=0.0'}
2122
check_proj_params('ortho', ortho, other_args)
2223

2324
# WGS84 radius * 0.99999
@@ -30,7 +31,7 @@ def test_default():
3031
def test_sphere_globe():
3132
globe = ccrs.Globe(semimajor_axis=1000, ellipse=None)
3233
ortho = ccrs.Orthographic(globe=globe)
33-
other_args = {'a=1000', 'lon_0=0.0', 'lat_0=0.0'}
34+
other_args = {'a=1000', 'lat_0=0.0', 'lon_0=0.0', 'alpha=0.0'}
3435
check_proj_params('ortho', ortho, other_args)
3536

3637
assert_almost_equal(ortho.x_limits, [-999.99, 999.99])
@@ -44,7 +45,7 @@ def test_ellipse_globe():
4445
ortho = ccrs.Orthographic(globe=globe)
4546
assert len(w) == 1
4647

47-
other_args = {'ellps=WGS84', 'lon_0=0.0', 'lat_0=0.0'}
48+
other_args = {'ellps=WGS84', 'lat_0=0.0', 'lon_0=0.0', 'alpha=0.0'}
4849
check_proj_params('ortho', ortho, other_args)
4950

5051
# Limits are the same as default since ellipses are not supported.
@@ -60,7 +61,7 @@ def test_eccentric_globe():
6061
ortho = ccrs.Orthographic(globe=globe)
6162
assert len(w) == 1
6263

63-
other_args = {'a=1000', 'b=500', 'lon_0=0.0', 'lat_0=0.0'}
64+
other_args = {'a=1000', 'b=500', 'lat_0=0.0', 'lon_0=0.0', 'alpha=0.0'}
6465
check_proj_params('ortho', ortho, other_args)
6566

6667
# Limits are the same as spheres since ellipses are not supported.
@@ -73,7 +74,7 @@ def test_eccentric_globe():
7374
def test_central_params(lon, lat):
7475
ortho = ccrs.Orthographic(central_latitude=lat, central_longitude=lon)
7576
other_args = {f'lat_0={lat}', f'lon_0={lon}',
76-
'a=6378137.0'}
77+
'a=6378137.0', 'alpha=0.0'}
7778
check_proj_params('ortho', ortho, other_args)
7879

7980
# WGS84 radius * 0.99999
@@ -90,7 +91,7 @@ def test_grid():
9091
ortho = ccrs.Orthographic(globe=globe)
9192
geodetic = ortho.as_geodetic()
9293

93-
other_args = {'a=1.0', 'b=1.0', 'lon_0=0.0', 'lat_0=0.0'}
94+
other_args = {'a=1.0', 'b=1.0', 'lon_0=0.0', 'lat_0=0.0', 'alpha=0.0'}
9495
check_proj_params('ortho', ortho, other_args)
9596

9697
assert_almost_equal(np.array(ortho.x_limits),
@@ -143,7 +144,7 @@ def test_sphere_transform():
143144
globe=globe)
144145
geodetic = ortho.as_geodetic()
145146

146-
other_args = {'a=1.0', 'b=1.0', 'lon_0=-100.0', 'lat_0=40.0'}
147+
other_args = {'a=1.0', 'b=1.0', 'lon_0=-100.0', 'lat_0=40.0', 'alpha=0.0'}
147148
check_proj_params('ortho', ortho, other_args)
148149

149150
assert_almost_equal(np.array(ortho.x_limits),
@@ -156,3 +157,28 @@ def test_sphere_transform():
156157

157158
inverse_result = geodetic.transform_point(result[0], result[1], ortho)
158159
assert_almost_equal(inverse_result, [-110.0, 30.0])
160+
161+
def test_sphere_rotate():
162+
globe = ccrs.Globe(semimajor_axis=1.0, semiminor_axis=1.0,
163+
ellipse=None)
164+
ortho = ccrs.Orthographic(central_latitude=40.0, central_longitude=-100.0,
165+
azimuth=180.0, globe=globe)
166+
geodetic = ortho.as_geodetic()
167+
168+
other_args = {'a=1.0', 'b=1.0', 'lon_0=-100.0', 'lat_0=40.0',
169+
'alpha=180.0'}
170+
check_proj_params('ortho', ortho, other_args)
171+
172+
assert_almost_equal(np.array(ortho.x_limits),
173+
[-0.99999, 0.99999])
174+
assert_almost_equal(np.array(ortho.y_limits),
175+
[-0.99999, 0.99999])
176+
177+
result = ortho.transform_point(-110.0, 30.0, geodetic)
178+
if pyproj.__proj_version__ >= '9.5.0': # support for alpha (azimuthal rotation)
179+
assert_almost_equal(result, np.array([ 0.1503837, 0.1651911]))
180+
else:
181+
assert_almost_equal(result, np.array([-0.1503837, -0.1651911]))
182+
183+
inverse_result = geodetic.transform_point(result[0], result[1], ortho)
184+
assert_almost_equal(inverse_result, [-110.0, 30.0])

0 commit comments

Comments
 (0)