Skip to content

Commit 908f98f

Browse files
authored
Merge pull request OSGeo#5339 from rouault/OSR_DEFAULT_AXIS_MAPPING_STRATEGY
Add a OSR_DEFAULT_AXIS_MAPPING_STRATEGY configuration option
2 parents efae63e + 15efb36 commit 908f98f

File tree

11 files changed

+103
-11
lines changed

11 files changed

+103
-11
lines changed

autotest/cpp/test_osr_ct.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,11 @@ namespace tut
180180
void object::test<4>()
181181
{
182182
OGRSpatialReference oSRSSource;
183+
oSRSSource.SetAxisMappingStrategy(OAMS_AUTHORITY_COMPLIANT);
183184
oSRSSource.importFromEPSG(4267);
184185

185186
OGRSpatialReference oSRSTarget;
187+
oSRSTarget.SetAxisMappingStrategy(OAMS_AUTHORITY_COMPLIANT);
186188
oSRSTarget.importFromEPSG(4269);
187189

188190
auto poCT = std::unique_ptr<OGRCoordinateTransformation>(

autotest/gcore/vrtmisc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,7 @@ def test_vrtmisc_write_srs():
509509
tmpfile = '/vsimem/test_vrtmisc_write_srs.vrt'
510510
ds = gdal.Translate(tmpfile, 'data/byte.tif', format='VRT')
511511
sr = osr.SpatialReference()
512+
sr.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
512513
sr.ImportFromEPSG(4326)
513514
ds.SetSpatialRef(sr)
514515
ds = None

autotest/ogr/ogr_geojson.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3126,6 +3126,7 @@ def test_ogr_geojson_export_geometry_axis_order():
31263126
# EPSG:4326 and lat,long data order
31273127
sr = osr.SpatialReference()
31283128
sr.ImportFromEPSG(4326)
3129+
sr.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
31293130
g = ogr.CreateGeometryFromWkt('POINT (49 2)')
31303131
g.AssignSpatialReference(sr)
31313132
before_wkt = g.ExportToWkt()
@@ -3157,6 +3158,7 @@ def test_ogr_geojson_export_geometry_axis_order():
31573158
# Projected CRS with northing, easting order
31583159
sr = osr.SpatialReference()
31593160
sr.ImportFromEPSG(2393)
3161+
sr.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
31603162
g = ogr.CreateGeometryFromWkt('POINT (49 2)')
31613163
g.AssignSpatialReference(sr)
31623164
assert json.loads(g.ExportToJson()) == { "type": "Point", "coordinates": [ 2.0, 49.0 ] }

autotest/ogr/ogr_gml_geom.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ def test_gml_write_gml3_srs():
12701270

12711271
srlatlong = osr.SpatialReference()
12721272
srlatlong.SetFromUserInput("EPSG:4326")
1273+
srlatlong.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
12731274

12741275
geom = ogr.CreateGeometryFromWkt('POINT(500000 4500000)')
12751276
geom.AssignSpatialReference(sr32631)

autotest/osr/osr_ct.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def test_osr_ct_2():
7979
utm_srs.SetWellKnownGeogCS('WGS84')
8080

8181
ll_srs = osr.SpatialReference()
82+
ll_srs.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
8283
ll_srs.SetWellKnownGeogCS('WGS84')
8384

8485
ct = osr.CoordinateTransformation(ll_srs, utm_srs)
@@ -353,8 +354,10 @@ def test_osr_ct_options_area_of_interest():
353354

354355
srs_nad27 = osr.SpatialReference()
355356
srs_nad27.SetFromUserInput("NAD27")
357+
srs_nad27.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
356358
srs_wgs84 = osr.SpatialReference()
357359
srs_wgs84.SetFromUserInput("WGS84")
360+
srs_wgs84.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
358361
options = osr.CoordinateTransformationOptions()
359362
assert not options.SetAreaOfInterest(-200,40,-99,41)
360363
assert not options.SetAreaOfInterest(-100,-100,-99,41)
@@ -543,8 +546,10 @@ def test_osr_ct_take_into_account_srs_coordinate_epoch():
543546

544547
s = osr.SpatialReference()
545548
s.SetFromUserInput("EPSG:7844") # GDA2020
549+
s.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
546550

547551
t_2020 = osr.SpatialReference()
552+
t_2020.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
548553
t_2020.SetFromUserInput("EPSG:9000") # ITRF2014
549554
t_2020.SetCoordinateEpoch(2020)
550555

@@ -556,6 +561,7 @@ def test_osr_ct_take_into_account_srs_coordinate_epoch():
556561
assert y == pytest.approx(150, abs=1e-10)
557562

558563
t_2030 = osr.SpatialReference()
564+
t_2030.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
559565
t_2030.SetFromUserInput("EPSG:9000") # ITRF2014
560566
t_2030.SetCoordinateEpoch(2030)
561567

@@ -595,6 +601,7 @@ def test_osr_ct_only_axis_order_different():
595601

596602
t = osr.SpatialReference()
597603
t.ImportFromEPSG(4326)
604+
t.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
598605

599606
ct = osr.CoordinateTransformation(s_wrong_axis_order, t)
600607
x, y, _ = ct.TransformPoint(2, 49, 0)
@@ -624,6 +631,7 @@ def test_osr_ct_wkt_non_consistent_with_epsg_definition():
624631

625632
t = osr.SpatialReference()
626633
t.ImportFromEPSG(4326)
634+
t.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
627635

628636
ct = osr.CoordinateTransformation(s_wrong_axis_order, t)
629637
x, y, _ = ct.TransformPoint(2, 49, 0)

autotest/osr/osr_ct_proj.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,12 @@ def test_proj(src_srs, src_xyz, src_error,
194194
pytest.skip(f'PROJ version < {proj_version_req}')
195195

196196
src = osr.SpatialReference()
197+
src.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
197198
assert src.SetFromUserInput(src_srs) == 0, \
198199
('SetFromUserInput(%s) failed.' % src_srs)
199200

200201
dst = osr.SpatialReference()
202+
dst.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
201203
assert dst.SetFromUserInput(dst_srs) == 0, \
202204
('SetFromUserInput(%s) failed.' % dst_srs)
203205

@@ -261,6 +263,7 @@ def test_proj(src_srs, src_xyz, src_error,
261263
)
262264
def test_transform_bounds_densify(density, expected):
263265
src = osr.SpatialReference()
266+
src.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
264267
assert src.ImportFromEPSG(4326) == 0
265268
dst = osr.SpatialReference()
266269
assert dst.ImportFromProj4(
@@ -316,6 +319,7 @@ def test_transform_bounds_densify_out_of_bounds__geographic_output():
316319
"+a=6370997 +b=6370997 +units=m +no_defs"
317320
) == 0
318321
dst = osr.SpatialReference()
322+
dst.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
319323
assert dst.ImportFromEPSG(4326) == 0
320324
ctr = osr.CoordinateTransformation(src, dst)
321325
assert ctr.TransformBounds(
@@ -325,8 +329,10 @@ def test_transform_bounds_densify_out_of_bounds__geographic_output():
325329

326330
def test_transform_bounds_antimeridian():
327331
src = osr.SpatialReference()
332+
src.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
328333
assert src.ImportFromEPSG(4167) == 0
329334
dst = osr.SpatialReference()
335+
dst.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
330336
assert dst.ImportFromEPSG(3851) == 0
331337
ctr = osr.CoordinateTransformation(src, dst)
332338
assert ctr.TransformBounds(
@@ -423,8 +429,10 @@ def test_transform_bounds__noop_geographic():
423429

424430
def test_transform_bounds__north_pole():
425431
src = osr.SpatialReference()
432+
src.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
426433
assert src.ImportFromEPSG(32661) == 0
427434
dst = osr.SpatialReference()
435+
dst.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
428436
assert dst.ImportFromEPSG(4326) == 0
429437
ctr = osr.CoordinateTransformation(src, dst)
430438
assert ctr.TransformBounds(
@@ -459,8 +467,10 @@ def test_transform_bounds__north_pole__xy():
459467

460468
def test_transform_bounds__south_pole():
461469
src = osr.SpatialReference()
470+
src.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
462471
assert src.ImportFromEPSG(32761) == 0
463472
dst = osr.SpatialReference()
473+
dst.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
464474
assert dst.ImportFromEPSG(4326) == 0
465475
ctr = osr.CoordinateTransformation(src, dst)
466476
assert ctr.TransformBounds(

autotest/osr/osr_esri.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ def test_osr_esri_30():
917917
'']
918918

919919
srs_prj = osr.SpatialReference()
920+
srs_prj.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
920921
srs_prj.ImportFromESRI(prj)
921922

922923
wkt = """GEOGCS["unknown",
@@ -926,6 +927,7 @@ def test_osr_esri_30():
926927
UNIT["degree",0.0174532925199433]]"""
927928

928929
srs_wkt = osr.SpatialReference(wkt=wkt)
930+
srs_wkt.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
929931

930932
assert srs_prj.IsSame(srs_wkt)
931933

autotest/osr/osr_ozi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def test_osr_ozi_2():
7979
def test_osr_ozi_3():
8080

8181
srs = osr.SpatialReference()
82+
srs.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
8283
srs.ImportFromOzi(["OziExplorer Map Data File Version 2.2",
8384
"Test_Map",
8485
"Test_Map.png",

autotest/pymod/gdaltest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,9 +858,11 @@ def user_srs_to_wkt(user_text):
858858

859859
def equal_srs_from_wkt(expected_wkt, got_wkt, verbose=True):
860860
expected_srs = osr.SpatialReference()
861+
expected_srs.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
861862
expected_srs.ImportFromWkt(expected_wkt)
862863

863864
got_srs = osr.SpatialReference()
865+
got_srs.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)
864866
got_srs.ImportFromWkt(got_wkt)
865867

866868
if got_srs.IsSame(expected_srs):

autotest/pyscripts/test_osr_util.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
import pytest
3232

33-
from osgeo import osr
33+
from osgeo import gdal, osr
3434

3535
# test that osgeo_utils and numpy are available, otherwise skip all tests
3636
pytest.importorskip('osgeo_utils')
@@ -40,7 +40,8 @@
4040

4141
def test_gis_order():
4242
pj4326_gis2 = osr_util.get_srs(4326) # tests the correct default
43-
assert pj4326_gis2.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
43+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
44+
assert pj4326_gis2.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
4445

4546
pj4326_auth = osr_util.get_srs(4326, axis_order=osr.OAMS_AUTHORITY_COMPLIANT)
4647
assert pj4326_auth.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
@@ -49,23 +50,26 @@ def test_gis_order():
4950
assert pj4326_gis.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER
5051

5152
assert not osr_util.are_srs_equivalent(pj4326_gis, pj4326_auth)
52-
assert osr_util.are_srs_equivalent(pj4326_auth, 4326)
53-
assert not osr_util.are_srs_equivalent(pj4326_gis, 4326)
53+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
54+
assert osr_util.are_srs_equivalent(pj4326_auth, 4326)
55+
assert not osr_util.are_srs_equivalent(pj4326_gis, 4326)
5456

5557
pj4326_str = osr_util.get_srs_pj(pj4326_auth)
5658
pj4326_str2 = osr_util.get_srs_pj(pj4326_gis)
5759

5860
# axis order is not reflected in proj strings
5961
assert isinstance(pj4326_str, str) and pj4326_str == pj4326_str2
6062

61-
assert osr_util.are_srs_equivalent(pj4326_str, 4326)
63+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
64+
assert osr_util.are_srs_equivalent(pj4326_str, 4326)
6265
assert osr_util.are_srs_equivalent(pj4326_auth, pj4326_str)
6366
assert not osr_util.are_srs_equivalent(pj4326_gis, pj4326_str)
6467

6568
osr_util.set_default_axis_order(osr.OAMS_TRADITIONAL_GIS_ORDER) # sets gis order
6669

6770
srs = osr_util.get_srs(4326) # check the the default was changed
68-
assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER
71+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
72+
assert srs.GetAxisMappingStrategy() == osr.OAMS_TRADITIONAL_GIS_ORDER
6973

7074
# check that srs object is not affected by default
7175
srs = osr_util.get_srs(pj4326_auth)
@@ -94,10 +98,12 @@ def test_gis_order():
9498
osr_util.set_default_axis_order()
9599

96100
srs = osr_util.get_srs(4326) # check the the default was restored
97-
assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
101+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
102+
assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
98103

99104
srs = osr_util.get_srs(pj4326_str)
100-
assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
105+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
106+
assert srs.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
101107

102108
# check that srs object is not affected by default
103109
srs = osr_util.get_srs(pj4326_gis) # check that srs object is also affected
@@ -118,11 +124,13 @@ def test_gis_order2():
118124
srs_from_epsg = osr.SpatialReference()
119125
srs_from_epsg.ImportFromEPSG(4326)
120126

121-
assert srs_from_epsg.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
127+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
128+
assert srs_from_epsg.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
122129
srs_from_str = osr.SpatialReference()
123130
srs_from_str.ImportFromProj4(pj4326_str)
124-
assert srs_from_str.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
125-
assert srs_from_epsg.IsSame(srs_from_str)
131+
if gdal.GetConfigOption('OSR_DEFAULT_AXIS_MAPPING_STRATEGY') is None:
132+
assert srs_from_str.GetAxisMappingStrategy() == osr.OAMS_AUTHORITY_COMPLIANT
133+
assert srs_from_epsg.IsSame(srs_from_str)
126134

127135
# testing that explicitly setting OAMS_AUTHORITY_COMPLIANT does not effect equivalence
128136
srs_from_epsg.SetAxisMappingStrategy(osr.OAMS_AUTHORITY_COMPLIANT)

ogr/ogrspatialreference.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,34 @@ struct OGRSpatialReference::Private
166166
void refreshAxisMapping();
167167
};
168168

169+
static OSRAxisMappingStrategy GetDefaultAxisMappingStrategy()
170+
{
171+
const char* pszDefaultAMS = CPLGetConfigOption(
172+
"OSR_DEFAULT_AXIS_MAPPING_STRATEGY", nullptr);
173+
if( pszDefaultAMS )
174+
{
175+
if( EQUAL(pszDefaultAMS, "AUTHORITY_COMPLIANT") )
176+
return OAMS_AUTHORITY_COMPLIANT;
177+
else if( EQUAL(pszDefaultAMS, "TRADITIONAL_GIS_ORDER") )
178+
return OAMS_TRADITIONAL_GIS_ORDER;
179+
else
180+
{
181+
CPLError(CE_Failure, CPLE_AppDefined,
182+
"Illegal value for OSR_DEFAULT_AXIS_MAPPING_STRATEGY = %s",
183+
pszDefaultAMS);
184+
}
185+
}
186+
return OAMS_AUTHORITY_COMPLIANT;
187+
}
188+
169189
OGRSpatialReference::Private::Private():
170190
m_poListener(std::shared_ptr<Listener>(new Listener(this)))
171191
{
192+
// Get the default value for m_axisMappingStrategy from the
193+
// OSR_DEFAULT_AXIS_MAPPING_STRATEGY configuration option, if set.
194+
static const OSRAxisMappingStrategy defaultAxisMappingStrategy = GetDefaultAxisMappingStrategy();
195+
196+
m_axisMappingStrategy = defaultAxisMappingStrategy;
172197
}
173198

174199
OGRSpatialReference::Private::~Private()
@@ -708,6 +733,18 @@ void OGRsnPrintDouble( char * pszStrBuf, size_t size, double dfValue )
708733
*
709734
* Note that newly created objects are given a reference count of one.
710735
*
736+
* Starting with GDAL 3.0, coordinates associated with a OGRSpatialReference
737+
* object are assumed to be in the order of the axis of the CRS definition (which
738+
* for example means latitude first, longitude second for geographic CRS belonging
739+
* to the EPSG authority). It is possible to define a data axis to CRS axis
740+
* mapping strategy with the SetAxisMappingStrategy() method.
741+
*
742+
* Starting with GDAL 3.5, the OSR_DEFAULT_AXIS_MAPPING_STRATEGY configuration
743+
* option can be set to "TRADITIONAL_GIS_ORDER" / "AUTHORITY_COMPLIANT" (the later
744+
* being the default value when the option is not set) to control the value of the
745+
* data axis to CRS axis mapping strategy when a OSRSpatialReference object is
746+
* created. Calling SetAxisMappingStrategy() will override this default value.
747+
711748
* The C function OSRNewSpatialReference() does the same thing as this
712749
* constructor.
713750
*
@@ -729,6 +766,18 @@ OGRSpatialReference::OGRSpatialReference( const char * pszWKT ) :
729766
/**
730767
* \brief Constructor.
731768
*
769+
* Starting with GDAL 3.0, coordinates associated with a OGRSpatialReference
770+
* object are assumed to be in the order of the axis of the CRS definition (which
771+
* for example means latitude first, longitude second for geographic CRS belonging
772+
* to the EPSG authority). It is possible to define a data axis to CRS axis
773+
* mapping strategy with the SetAxisMappingStrategy() method.
774+
*
775+
* Starting with GDAL 3.5, the OSR_DEFAULT_AXIS_MAPPING_STRATEGY configuration
776+
* option can be set to "TRADITIONAL_GIS_ORDER" / "AUTHORITY_COMPLIANT" (the later
777+
* being the default value when the option is not set) to control the value of the
778+
* data axis to CRS axis mapping strategy when a OSRSpatialReference object is
779+
* created. Calling SetAxisMappingStrategy() will override this default value.
780+
*
732781
* This function is the same as OGRSpatialReference::OGRSpatialReference()
733782
*/
734783
OGRSpatialReferenceH CPL_STDCALL OSRNewSpatialReference( const char *pszWKT )
@@ -11628,6 +11677,12 @@ OSRAxisMappingStrategy OSRGetAxisMappingStrategy( OGRSpatialReferenceH hSRS )
1162811677
/************************************************************************/
1162911678

1163011679
/** \brief Set the data axis to CRS axis mapping strategy.
11680+
*
11681+
* Starting with GDAL 3.5, the OSR_DEFAULT_AXIS_MAPPING_STRATEGY configuration
11682+
* option can be set to "TRADITIONAL_GIS_ORDER" / "AUTHORITY_COMPLIANT" (the later
11683+
* being the default value when the option is not set) to control the value of the
11684+
* data axis to CRS axis mapping strategy when a OSRSpatialReference object is
11685+
* created. Calling SetAxisMappingStrategy() will override this default value.
1163111686
*
1163211687
* See OGRSpatialReference::GetAxisMappingStrategy()
1163311688
* @since GDAL 3.0

0 commit comments

Comments
 (0)