Skip to content

Commit 8860a81

Browse files
committed
Add an approx keyword arg to TransverseMercator.
Starting with Proj 6, the tmerc projection is implemented using the former etmerc code. This is more accurate, but breaks our existing expectations and tests. The new keyword argument will, if True, instruct Proj6 to use the older approximate code, and if False, the newer one. The default will change in the next release. Fixes #320.
1 parent 6522356 commit 8860a81

File tree

3 files changed

+50
-18
lines changed

3 files changed

+50
-18
lines changed

lib/cartopy/crs.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -803,7 +803,7 @@ class TransverseMercator(Projection):
803803
"""
804804
def __init__(self, central_longitude=0.0, central_latitude=0.0,
805805
false_easting=0.0, false_northing=0.0,
806-
scale_factor=1.0, globe=None):
806+
scale_factor=1.0, globe=None, approx=None):
807807
"""
808808
Parameters
809809
----------
@@ -818,15 +818,33 @@ def __init__(self, central_longitude=0.0, central_latitude=0.0,
818818
Y offset from the planar origin in metres. Defaults to 0.
819819
scale_factor: optional
820820
Scale factor at the central meridian. Defaults to 1.
821+
821822
globe: optional
822823
An instance of :class:`cartopy.crs.Globe`. If omitted, a default
823824
globe is created.
824825
826+
approx: optional
827+
Whether to use Proj's approximate projection (True), or the new
828+
Extended Transverse Mercator code (False). Defaults to True, but
829+
will change to False in the next release.
830+
825831
"""
832+
if approx is None:
833+
warnings.warn('The default value for the *approx* keyword '
834+
'argument to TransverseMercator will change '
835+
'from True to False after 0.18.',
836+
stacklevel=2)
837+
approx = True
826838
proj4_params = [('proj', 'tmerc'), ('lon_0', central_longitude),
827839
('lat_0', central_latitude), ('k', scale_factor),
828840
('x_0', false_easting), ('y_0', false_northing),
829841
('units', 'm')]
842+
if PROJ4_VERSION < (6, 0, 0):
843+
if not approx:
844+
proj4_params[0] = ('proj', 'etmerc')
845+
else:
846+
if approx:
847+
proj4_params += [('approx', None)]
830848
super(TransverseMercator, self).__init__(proj4_params, globe=globe)
831849

832850
@property
@@ -851,12 +869,19 @@ def y_limits(self):
851869

852870

853871
class OSGB(TransverseMercator):
854-
def __init__(self):
872+
def __init__(self, approx=None):
873+
if approx is None:
874+
warnings.warn('The default value for the *approx* keyword '
875+
'argument to OSGB will change from True to '
876+
'False after 0.18.',
877+
stacklevel=2)
878+
approx = True
855879
super(OSGB, self).__init__(central_longitude=-2, central_latitude=49,
856880
scale_factor=0.9996012717,
857881
false_easting=400000,
858882
false_northing=-100000,
859-
globe=Globe(datum='OSGB36', ellipse='airy'))
883+
globe=Globe(datum='OSGB36', ellipse='airy'),
884+
approx=approx)
860885

861886
@property
862887
def boundary(self):
@@ -874,15 +899,22 @@ def y_limits(self):
874899

875900

876901
class OSNI(TransverseMercator):
877-
def __init__(self):
902+
def __init__(self, approx=None):
903+
if approx is None:
904+
warnings.warn('The default value for the *approx* keyword '
905+
'argument to OSNI will change from True to '
906+
'False after 0.18.',
907+
stacklevel=2)
908+
approx = True
878909
globe = Globe(semimajor_axis=6377340.189,
879910
semiminor_axis=6356034.447938534)
880911
super(OSNI, self).__init__(central_longitude=-8,
881912
central_latitude=53.5,
882913
scale_factor=1.000035,
883914
false_easting=200000,
884915
false_northing=250000,
885-
globe=globe)
916+
globe=globe,
917+
approx=approx)
886918

887919
@property
888920
def boundary(self):

lib/cartopy/tests/crs/test_transverse_mercator.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# (C) British Crown Copyright 2013 - 2018, Met Office
1+
# (C) British Crown Copyright 2013 - 2019, Met Office
22
#
33
# This file is part of cartopy.
44
#
@@ -50,11 +50,11 @@ def test_osgb_vals(self):
5050
globe=ccrs.Globe(datum='OSGB36',
5151
ellipse='airy'))
5252
res = proj.transform_point(*self.point_a, src_crs=self.src_crs)
53-
np.testing.assert_array_almost_equal(res, (295971.28667707,
54-
93064.27666368))
53+
np.testing.assert_array_almost_equal(res, (295971.28668, 93064.27666),
54+
decimal=5)
5555
res = proj.transform_point(*self.point_b, src_crs=self.src_crs)
56-
np.testing.assert_array_almost_equal(res, (577274.98380140,
57-
69740.49227181))
56+
np.testing.assert_array_almost_equal(res, (577274.98380, 69740.49227),
57+
decimal=5)
5858

5959
def test_nan(self):
6060
proj = ccrs.TransverseMercator()
@@ -74,11 +74,11 @@ def setup_class(self):
7474
def test_default(self):
7575
proj = ccrs.OSGB()
7676
res = proj.transform_point(*self.point_a, src_crs=self.src_crs)
77-
np.testing.assert_array_almost_equal(res, (295971.28667707,
78-
93064.27666368))
77+
np.testing.assert_array_almost_equal(res, (295971.28668, 93064.27666),
78+
decimal=5)
7979
res = proj.transform_point(*self.point_b, src_crs=self.src_crs)
80-
np.testing.assert_array_almost_equal(res, (577274.98380140,
81-
69740.49227181))
80+
np.testing.assert_array_almost_equal(res, (577274.98380, 69740.49227),
81+
decimal=5)
8282

8383
def test_nan(self):
8484
proj = ccrs.OSGB()

lib/cartopy/tests/test_crs.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ def test_osgb(self):
9090
def test_epsg(self):
9191
uk = ccrs.epsg(27700)
9292
assert uk.epsg_code == 27700
93-
assert_almost_equal(
94-
uk.x_limits, (-118365.7408171, 751581.564796))
95-
assert_almost_equal(
96-
uk.y_limits, (-5268.1797977, 1272227.798124))
93+
assert_almost_equal(uk.x_limits, (-118365.7406176, 751581.5647514),
94+
decimal=3)
95+
assert_almost_equal(uk.y_limits, (-5268.1704980, 1272227.7987656),
96+
decimal=2)
9797
assert_almost_equal(uk.threshold, 8699.47, decimal=2)
9898
self._check_osgb(uk)
9999

0 commit comments

Comments
 (0)