aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorKristian Evers <kristianevers@gmail.com>2020-12-21 17:28:48 +0100
committerKristian Evers <kristianevers@gmail.com>2020-12-21 17:28:48 +0100
commit5aad0d25f8423b8b88a716d0333c7bd19f6184c7 (patch)
treef0a248ef08fb51ef0ec29178ef41fd4168d4c85d /test
parentc3efbd23a5bf26f1dfd5bc55ae3488d5665ace98 (diff)
parent1cafe3e602d3f697c8d2daaa9b634f3ad23b0d53 (diff)
downloadPROJ-5aad0d25f8423b8b88a716d0333c7bd19f6184c7.tar.gz
PROJ-5aad0d25f8423b8b88a716d0333c7bd19f6184c7.zip
Merge remote-tracking branch 'osgeo/master'
Diffstat (limited to 'test')
-rwxr-xr-xtest/cli/testprojinfo4
-rw-r--r--test/cli/testprojinfo_out.dist3
-rwxr-xr-xtest/cli/testvarious12
-rw-r--r--test/cli/tv_out.dist4
-rw-r--r--test/gie/4D-API_cs2cs-style.gie4
-rw-r--r--test/gie/adams_hemi.gie776
-rw-r--r--test/gie/adams_ws1.gie114
-rw-r--r--test/gie/adams_ws2.gie114
-rw-r--r--test/gie/builtins.gie194
-rw-r--r--test/gie/defmodel.gie6
-rw-r--r--test/gie/deformation.gie20
-rw-r--r--test/gie/ellipsoid.gie28
-rw-r--r--test/gie/geotiff_grids.gie12
-rw-r--r--test/gie/guyou.gie772
-rw-r--r--test/gie/more_builtins.gie32
-rw-r--r--test/gie/nkg.gie240
-rw-r--r--test/gie/peirce_q.gie106
-rw-r--r--test/gie/tinshift.gie6
-rw-r--r--test/unit/CMakeLists.txt1
-rw-r--r--test/unit/Makefile.am13
-rw-r--r--test/unit/gie_self_tests.cpp44
-rw-r--r--test/unit/proj_errno_string_test.cpp43
-rw-r--r--test/unit/test_c_api.cpp66
-rw-r--r--test/unit/test_factory.cpp6
-rw-r--r--test/unit/test_operation.cpp5815
-rw-r--r--test/unit/test_operationfactory.cpp5954
26 files changed, 7435 insertions, 6954 deletions
diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo
index c31cfef0..ee1b27f5 100755
--- a/test/cli/testprojinfo
+++ b/test/cli/testprojinfo
@@ -213,6 +213,10 @@ fi
rm testprojinfo_out_remotedata.txt
unset PROJ_NETWORK
+echo 'Testing --accuracy 0.05 -s EPSG:4326 -t EPSG:4258' >> ${OUT}
+$EXE --accuracy 0.05 -s EPSG:4326 -t EPSG:4258 >>${OUT} 2>&1
+echo "" >>${OUT}
+
######################
# NZGD2000 -> ITRFxx #
######################
diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist
index 8e8ef294..829c914c 100644
--- a/test/cli/testprojinfo_out.dist
+++ b/test/cli/testprojinfo_out.dist
@@ -1384,6 +1384,9 @@ DATUM["World Geodetic System 1984",
LENGTHUNIT["metre",1]],
ID["EPSG",6326]]
+Testing --accuracy 0.05 -s EPSG:4326 -t EPSG:4258
+Candidate operations found: 0
+
Testing -s NZGD2000 -t ITRF96 -o PROJ -q
+proj=pipeline
+step +proj=unitconvert +xy_in=deg +xy_out=rad
diff --git a/test/cli/testvarious b/test/cli/testvarious
index 82be4992..a121393c 100755
--- a/test/cli/testvarious
+++ b/test/cli/testvarious
@@ -1021,6 +1021,18 @@ $EXE --authority EPSG -E +proj=latlong +datum=WGS84 +no_defs +to +init=epsg:6342
-105 40
EOF
+echo "##############################################################" >> ${OUT}
+echo "Test effect of --accuracy" >> ${OUT}
+$EXE -E --accuracy 0.05 EPSG:4326 EPSG:4258 >> ${OUT} <<EOF
+49 2
+EOF
+
+echo "##############################################################" >> ${OUT}
+echo "Test effect of --no-ballpark" >> ${OUT}
+$EXE -E --no-ballpark EPSG:4267 EPSG:4258 >> ${OUT} <<EOF
+49 2
+EOF
+
# Done!
# do 'diff' with distribution results
diff --git a/test/cli/tv_out.dist b/test/cli/tv_out.dist
index fe1aa452..59129d99 100644
--- a/test/cli/tv_out.dist
+++ b/test/cli/tv_out.dist
@@ -492,3 +492,7 @@ The first result should use the 'WGS_1984_(ITRF08)_To_NAD_1983_2011' (ESRI:10836
and the second one a no-op
-105 40 500000.86 4427756.50 0.00
-105 40 500000.00 4427757.22 0.00
+##############################################################
+Test effect of --accuracy
+##############################################################
+Test effect of --no-ballpark
diff --git a/test/gie/4D-API_cs2cs-style.gie b/test/gie/4D-API_cs2cs-style.gie
index ade75907..b4ceb4f6 100644
--- a/test/gie/4D-API_cs2cs-style.gie
+++ b/test/gie/4D-API_cs2cs-style.gie
@@ -495,7 +495,7 @@ expect 0 0 1
roundtrip 1
operation +proj=longlat +a=1 +b=1 +vto_meter=1/0
-expect failure errno unit_factor_less_than_0
+expect failure errno invalid_op_illegal_arg_value
operation +proj=longlat +a=1 +b=1 +vto_meter=1000 +geoc
accept 0 0 1000
@@ -522,7 +522,7 @@ roundtrip 1
# in the creation of a PJ object.
-------------------------------------------------------------------------------
operation this is a bogus CRS meant to trigger a generic error in proj_create()
-expect failure errno generic error
+expect failure errno other
-------------------------------------------------------------------------------
# Test proj=set
diff --git a/test/gie/adams_hemi.gie b/test/gie/adams_hemi.gie
index b31c3581..9d23b939 100644
--- a/test/gie/adams_hemi.gie
+++ b/test/gie/adams_hemi.gie
@@ -9,31 +9,31 @@ operation +proj=adams_hemi +R=6370997
tolerance 1 mm
------------------------------------------------------------
accept -179.0512914938 -90.1445918836
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -169.5842217825 -89.1738195765
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.8126151474 -88.9303357409
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.8486678837 -88.7598088570
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.3978823413 -88.5424937255
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.4584139907 -88.3017941113
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.6382190434 -88.1579367749
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.1571755829 -87.4911657719
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.4449870732 -87.1707570236
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.9433443609 -87.0825895518
expect -2032451.307 -14670658.595
@@ -90,61 +90,61 @@ accept 80.5231675121 -77.0660588617
expect 3923735.969 -12068158.388
accept 90.0066580543 -76.6161050638
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.5350349572 -76.3746207928
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.7544963160 -76.2761103137
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.0734970456 -75.8866598636
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.5824490023 -75.8761529489
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.8041765005 -75.3058724059
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.3183273801 -74.4580538960
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.0892519416 -73.7178034782
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.3366715442 -72.7342346131
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.6302993811 -72.6551561090
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.1498353863 -79.8617775679
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.6126454375 -78.9973036997
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5376706591 -78.3099466224
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.7206409942 -77.9762123582
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.5308439004 -77.1568269429
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.5655598613 -76.3111768828
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.7726048543 -75.3290637518
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.6962230001 -74.3833782562
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.6722260401 -73.9288741111
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.0043085338 -73.3335214021
expect -4844180.674 -11775270.656
@@ -201,61 +201,61 @@ accept 80.1994904845 -64.1621304539
expect 5574892.739 -10059995.184
accept 90.4107676644 -63.6583206132
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.7435829266 -62.9292855324
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.6722999581 -62.8950940661
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.8104324458 -62.4946649855
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.0315355771 -61.8657176607
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.7842333846 -61.7278379595
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.5202047210 -61.0467237730
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.7596965102 -60.2885251988
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1658638654 -60.0997063537
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.2502374139 -59.7318603713
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.9256771826 -69.2161805164
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.2003519382 -68.5724302106
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5787597594 -67.9857475830
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.8429607974 -67.2794853256
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.5406690392 -67.1131557084
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7848559822 -66.2388824806
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.1305416029 -65.8739932573
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.5840686978 -65.1388713461
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.0639263051 -65.0873010186
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.1823111373 -64.6956687932
expect -6023804.986 -10592902.952
@@ -312,61 +312,61 @@ accept 80.4614530617 -58.9769415123
expect 6157836.688 -9386832.221
accept 90.1145386062 -58.4070158299
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.7207579758 -58.0174867644
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5210303471 -57.2190055708
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.6967482820 -56.4709263993
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.0815389060 -55.4932687347
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.1058922487 -54.7233777967
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.7972249220 -54.0392541094
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.4001197642 -53.4894321537
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.7522870277 -52.8073510172
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.9552557119 -51.9628267761
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.8457680307 -59.7627027888
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.9866964666 -59.3961476674
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.7470584020 -58.4027994525
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.6934351691 -57.7899236032
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.8251656458 -57.1675573730
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7548669173 -56.7627741202
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.8194582121 -56.1851853006
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.9910713909 -55.2204505294
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.5100607596 -54.5311736441
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.8644038896 -53.9245170355
expect -7342928.224 -9343992.584
@@ -423,61 +423,61 @@ accept 80.9191136756 -48.5703968561
expect 7251379.374 -8116860.291
accept 90.3784337844 -48.2622816670
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.0644440138 -47.5531771971
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.4395693884 -47.1020565364
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.8787420308 -46.5648775386
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.8192016133 -45.7254461234
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6056889736 -45.1737240013
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.1175388463 -44.6690953878
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.6179845473 -44.6641530409
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.3909883495 -43.8609446159
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.3536945715 -43.4346766235
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.6728016921 -49.7927741248
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8899091213 -49.5948095572
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.7193834386 -48.9692766397
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3161804706 -48.3900540417
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.3059860307 -47.5443099911
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.2607005772 -47.3426945690
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.0464442962 -46.3637609990
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3006137776 -46.2470536112
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.1086587357 -45.3788313212
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.6418391342 -44.9558227898
expect -8329227.919 -8319528.025
@@ -534,61 +534,61 @@ accept 80.6995146991 -37.6252342058
expect 8295075.544 -6755019.382
accept 90.0888221682 -36.9847575823
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.7780137471 -36.6711774624
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5677826175 -36.0072187827
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.4571639125 -35.5987514678
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.4994689409 -35.0078880309
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.4973246226 -34.7603698284
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.2185553402 -33.7827115000
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.0049830768 -33.6576606654
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1113538332 -32.7218296414
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.0413323536 -32.6458132046
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.7614880705 -39.3083971924
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.2195161001 -38.8120777840
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.8162149104 -38.0579151517
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.1975646236 -38.0219346503
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.4875552064 -37.4333640809
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.3174577073 -37.3101077795
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.3659376731 -37.0018039210
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.4951561921 -36.7266176768
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.0146344791 -36.1766584469
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.4535006021 -35.4158065520
expect -9377248.574 -7225961.706
@@ -645,61 +645,61 @@ accept 80.7902728211 -26.9566814760
expect 9340735.895 -5359874.908
accept 90.7774660604 -26.3781900961
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.9677349413 -25.6947295847
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.4045415377 -24.8858012124
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.9106581244 -24.6760450197
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1070741983 -24.3713625355
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.5983717849 -23.4696540641
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.9695044815 -23.2859623288
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.2904693231 -22.4177486612
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.9786886104 -22.3889418243
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.4135817841 -21.4141834167
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.1529257481 -29.4728615966
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.2570543721 -28.7440325834
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.4124846191 -27.8743740104
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.9984258738 -27.2290510016
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.4767743694 -27.0546870326
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.5641039139 -26.6837015309
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.3705764793 -25.8611684419
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.5378587803 -25.4624789903
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.3734787689 -24.9304945684
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3465946697 -24.1700440971
expect -10704395.428 -5847361.236
@@ -756,61 +756,61 @@ accept 80.8671865869 -16.2424776439
expect 10422654.067 -3712280.432
accept 90.2461291404 -15.5645924718
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.9711143384 -14.9057684714
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5061775944 -13.9999376124
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.6646869394 -13.8762395278
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.4786384854 -13.6641917166
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.4992250881 -12.7990197875
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.0366235813 -12.4696803942
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.5278707110 -12.2720940753
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.3484529579 -12.2138862792
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.2280212650 -11.3213090122
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.9887698836 -19.8434403334
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.6164294546 -19.0221825561
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5308654294 -18.1879041212
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.8050966059 -17.4019446265
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.1612469827 -16.6625595025
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.4619391187 -16.4594418864
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.8383311004 -16.1675065524
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3335459376 -15.6868347454
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.7976668059 -15.6854972046
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.7267294244 -14.8632370454
expect -12053401.390 -4568307.176
@@ -867,61 +867,61 @@ accept 80.6138637845 -4.9732504580
expect 11379290.973 -1327935.989
accept 90.6032354861 -4.1370495786
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.1644532030 -3.7428216159
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.6488410247 -3.6483998900
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.4200133401 -3.5679026480
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.4611248753 -2.8417810196
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.5117693002 -2.1994039429
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.8812291858 -1.4289441365
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.7607399916 -1.4071810906
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.8773135555 -1.0552787291
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.0261501820 -0.4477561568
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.6651296552 -9.8752237332
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8040567331 -9.5090347854
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.2369236977 -8.7812050100
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.4668694945 -8.7411685014
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.4921425087 -8.4838585832
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.0489643890 -8.3165131291
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2267713387 -8.2419396541
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.8259504273 -7.2718622518
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9614377002 -7.1037710855
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.8090238071 -6.4232987368
expect -13640751.484 -2974873.944
@@ -978,61 +978,61 @@ accept 80.6476764259 3.6310845229
expect 11462634.636 984489.812
accept 90.5849650699 4.1063917523
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.6238525596 4.1230600723
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.6594697851 5.0495381196
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.0930076215 5.2661796574
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.5000547754 5.3939702157
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.4751452989 5.8876297478
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.7452375246 6.3021488806
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.1359677924 6.9173640629
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.0302177328 7.6378853558
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.8170157951 8.3472735471
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.1943150364 0.7596010223
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.6391212860 1.0795717122
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.2152700578 1.5596096157
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3566080854 2.3935395760
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.6411690265 2.8792042895
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.0884027419 3.3736512451
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.6412398776 3.5609941446
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.8410023851 4.3613065976
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.5554211656 5.1657533479
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3773565828 5.9157121060
expect -13652078.995 2749284.275
@@ -1089,61 +1089,61 @@ accept 80.2140199400 13.5624272700
expect 10571534.837 3165721.762
accept 90.4576635954 13.9718076506
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.6449925924 14.8800104945
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.2075367326 15.0521133300
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.4913041985 15.0889224537
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1088876084 15.6744717063
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6091054692 15.9789322360
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.8827038395 16.1118935785
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.8584892232 16.9655055987
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.7081605352 17.1424915281
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.4875952646 17.7286920734
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.2192819040 10.8569245931
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.0657035958 11.2213297367
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.1659774291 11.5431930234
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.9545173238 12.5029285949
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.3117413904 12.6753804804
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.3194639426 13.3306225335
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.8562785026 13.8682936931
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.1061461002 14.0130001331
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.6079217864 14.7921669533
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3223757109 14.9467935082
expect -11977848.908 4521084.682
@@ -1200,61 +1200,61 @@ accept 80.7948402736 23.3693033859
expect 9696270.644 4844753.993
accept 90.9423588456 23.9305098127
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.5427479545 24.6568371578
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.6483359564 25.2988879331
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.6254581560 25.7897168715
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.6198305384 26.5579713234
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.5223099495 27.4665102983
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.1770507578 27.9150551786
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.8757513817 28.5236724280
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.8877826460 29.0924417375
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.6425321330 29.5764205068
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.9444701529 20.8756448666
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.6232517758 21.6942653703
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5830169036 22.4130383475
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.4619550763 22.6339632787
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.7058201004 23.2553831478
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7766004320 23.8189681109
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.3228272091 24.7032636217
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.5551540716 24.7745254301
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9135718461 25.5385802763
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.1841069049 26.2083957447
expect -10431143.612 6091127.422
@@ -1311,61 +1311,61 @@ accept 80.9991967787 34.8943272959
expect 8589604.803 6432883.803
accept 90.5925677009 35.3510670805
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.0148954666 36.2711932097
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.4283207815 36.6017613088
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.6777960225 37.3666811945
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.2891249681 37.8530786142
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.8212942434 38.5395736955
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.7430926180 38.7113483726
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.9509577553 39.6821505727
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.3061167023 40.4192356875
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.9886935244 41.3233715669
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.3343647471 30.6447124879
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.9318029695 30.8088173910
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9351347433 31.4030041187
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.1603401895 31.7370508292
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.8411358400 31.9883214220
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.6487283950 32.2540792459
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.3377596938 32.5474903700
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.4052121056 32.6499740509
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9645719240 33.2634048792
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3430796801 33.3255757200
expect -9605176.890 6972552.471
@@ -1422,61 +1422,61 @@ accept 80.6903986951 43.0741360152
expect 7768806.954 7429525.503
accept 90.6634321726 43.5837411887
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.8304968356 44.3478015738
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.2734219112 44.4218804789
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.7981801963 44.9674252843
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.6206535666 45.4286113875
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.3730391283 46.0714239353
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.9426457881 46.5091534230
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.6115790352 47.4101077572
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.3277640796 48.0638373590
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.8477425796 48.8442357472
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.2598149320 40.1705017627
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.6056153255 40.1727881259
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.3396275493 41.0355246248
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3430287138 41.0573932198
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.3972998819 41.0866734660
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.2347342883 41.3220478306
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.9384666450 41.9087201484
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.1765297705 42.5137977627
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.7425660165 43.1240737964
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3631524858 43.6013437171
expect -8456598.089 8145902.918
@@ -1533,61 +1533,61 @@ accept 80.1015409967 53.6234824949
expect 6684866.077 8688618.853
accept 90.9390534980 54.4032676618
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.2275975816 54.6540829630
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.2799875321 55.5050863665
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.5746083149 55.8365526658
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.5493283922 55.8603600954
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.1036826064 56.0703761781
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.2683487285 56.7530037053
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.2871251380 57.2145257183
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1375706366 57.2304506879
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.2551410057 57.5449642224
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.4163113130 50.3425538005
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.9733110986 50.4458299488
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.7576358296 50.9581504113
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3417213155 51.6042289093
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.0195163151 51.8452436385
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.9037457234 52.0925641350
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.8773360504 52.9710431510
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3390467545 53.2106639106
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.5444768748 53.6966176349
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.1508332331 54.2933793206
expect -7253089.374 9338825.070
@@ -1644,61 +1644,61 @@ accept 80.2667195466 63.4462194528
expect 5659364.075 9965995.331
accept 90.1958404963 64.0831209279
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.5787966151 64.7750993019
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5253826702 65.0311314831
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.1812962078 65.3475412110
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.6287227669 65.6970336106
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.0181654960 66.0623612621
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.7856466511 66.3591210923
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.9724593003 66.6162174492
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.0946608724 66.6386212957
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.4742461481 67.2758505348
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.3409209668 60.7971917835
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8189576120 61.1637771517
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5389911401 61.2887975834
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.8226015684 61.6437737052
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.2361655032 62.2457658007
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.4677006422 63.0421916813
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2765495979 63.0575080285
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.6674914716 63.2917945558
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.7670971881 63.3834861911
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.8162159435 64.1409584458
expect -6128005.443 10556995.120
@@ -1755,61 +1755,61 @@ accept 80.1791569395 72.7183017021
expect 4529430.842 11315638.668
accept 90.8791736411 72.9059905421
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.0478827489 73.6259975169
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.4087249466 74.2803681973
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.3401612468 74.8365621394
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1826062634 75.5694271641
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.9483568214 75.9187393924
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.4892277622 76.6692051191
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.6382868956 77.4573927636
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.7717121538 77.8061856572
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.3573673565 78.0660690876
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.6675977383 70.0957203052
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.7405185971 70.8584256587
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5167125707 71.8322204655
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.0042143904 72.1158106531
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.0329602286 72.2542294354
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7801336775 73.2077231869
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.3119539671 73.8550759705
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.4758176356 74.3266149256
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.6607202273 75.0169362990
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.4753530769 75.9617981968
expect -4457168.999 12206697.987
@@ -1866,61 +1866,61 @@ accept 80.9787521274 84.9230149078
expect 2463890.570 13818835.453
accept 90.9143604315 85.3871192550
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.4734880731 86.0042464514
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.9680822795 86.3859461851
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.8622100732 87.2340544489
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.2558456040 87.3620502284
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.2081210889 87.9608446770
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.4963196965 88.3752399281
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.1141812758 89.1315428504
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.8037412086 89.6150717843
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.1602592915 90.5979873573
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.4988010038 80.2382292021
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.7323895837 80.2920174872
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9503807693 80.8196927273
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.0925061081 81.4663152862
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.5716369758 82.4286410234
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.8787197288 82.8456226975
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.4793423714 83.5516191256
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.2664761985 84.4756117750
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.3415573570 85.3222226381
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.5621686999 86.1477384313
expect -2328002.776 14359252.241
@@ -1950,171 +1950,171 @@ accept -9.7223365758 89.3832521756
expect -112026.906 15387878.248
accept 0.6641448256 90.0106423220
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 10.1860723801 90.3688642972
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 20.9490167192 90.7173958262
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.5649867370 90.9925163187
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.4458702150 91.4734308311
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.5856921606 91.9158720484
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.1363202035 92.2767051552
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.0710227099 93.2758942081
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.2222434482 93.6733349750
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.0483434140 94.4740404396
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.6823676393 95.0641687155
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.6403276588 95.6156935259
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.2581625576 96.0431766104
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.4609264126 96.4854267472
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.6441294534 96.7262713213
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.3252472008 97.1420609214
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.7668616164 97.4790143988
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.7465062128 97.6550567817
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.7542323137 98.2872938097
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.4933532172 89.0462961156
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8505428520 89.8903183246
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.6997771019 89.9583403191
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.2613507188 90.8395350848
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -139.1842997548 91.1573946186
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -129.6568991775 91.9446769249
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -119.3115606256 92.6597043587
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -109.6274703609 93.6500222571
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -99.3955363318 93.6790731121
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -89.4902277654 93.7101118679
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -79.2055095189 93.8973426839
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -69.2694919752 94.5715889948
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -59.2096313695 94.8767204910
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -49.3346426547 95.7619370286
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -39.2940192313 95.9177686800
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -29.1265263906 96.4025342806
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -19.8149677195 96.5067828223
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -9.2806942519 96.8402148749
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 0.9337491530 97.5569468760
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 10.2800898790 97.9514714385
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 20.9290209494 98.9284832763
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.3939457169 99.5719752144
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.6958590705 100.0328567981
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.1473239826 100.6776574030
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.6429472168 100.7044060498
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.8017862719 101.2635238404
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.3144473172 101.9663622692
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.7459660200 102.3134423218
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.1161002435 103.1947683448
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.1928396624 104.0579352787
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.2928981698 104.8100792607
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.4257286255 105.4176918707
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.8110132830 105.4248870814
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.8802025406 106.2350153626
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.3540927190 106.6211948814
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.1006211763 106.7429949781
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.9080349563 107.0582862622
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
</gie-strict>
diff --git a/test/gie/adams_ws1.gie b/test/gie/adams_ws1.gie
index fa9da8c6..3593fe12 100644
--- a/test/gie/adams_ws1.gie
+++ b/test/gie/adams_ws1.gie
@@ -10,10 +10,10 @@ operation +proj=adams_ws1 +R=6370997
tolerance 1 mm
------------------------------------------------------------
accept -179.5170670673 -90.3642618405
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -169.6193301609 -90.0089826784
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -159.5146913398 -89.9552061084
expect -350717.162 -11748881.092
@@ -1891,10 +1891,10 @@ accept 160.6971562328 89.4208328233
expect 1268680.941 11594325.039
accept 170.3991577317 90.3170479552
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.5908903286 90.7796418583
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.6672737749 80.9670130376
expect -5579975.368 11792148.700
@@ -1957,165 +1957,165 @@ accept 10.1878191712 89.8306694493
expect 61235.456 11123325.873
accept 20.3202271141 90.0891258483
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.4076531874 90.1655009485
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.4697816170 90.3073014721
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.0046280736 90.9081150272
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.2882853272 91.3234973005
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.1983790734 92.0487871293
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.2016298087 92.7883781050
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.1380649347 93.4193661081
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.9727810821 94.0036131508
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.2124518442 94.5588879261
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.9027437830 95.4070516655
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.4370128971 95.6659394457
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.5025123065 95.8655824422
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.4051276696 96.5597126498
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.6794810904 97.5509003421
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.0804614782 97.7962770171
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.7350988655 97.9297507566
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.6509243766 89.9594690425
expect -339016.824 11811270.987
accept -169.1462360158 90.2259103522
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -159.1237371257 91.0966186475
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -149.3864893992 92.0018593591
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -139.8836795793 92.7310580140
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -129.2447556879 93.0874941458
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -119.5691328385 94.0016439421
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -109.5375733271 94.6275672079
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -99.6767551820 94.9362396518
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -89.0765267674 95.5300020136
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -79.7404375474 95.8979843707
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -69.2186423862 96.1670313079
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -59.3116550382 97.0176191327
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -49.2194140278 97.9598960425
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -39.4423952109 97.9675789614
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -29.2846350035 98.7361321642
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -19.5599253582 98.8248133304
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -9.7751102831 99.2905137713
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 0.4459912613 99.9348079001
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 10.2556901904 100.0679369696
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 20.2129499464 100.4339484435
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.5120716507 100.8173987820
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.9186217475 101.3362169174
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.4499309674 101.7519777648
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.9618169609 101.9681616248
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.5136938969 102.7263743079
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.1112365376 103.4930742925
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.0656487088 104.2687818917
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.4737302350 105.1672304167
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.0826941374 105.9578331609
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.5038465053 106.4653112353
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.1946022249 107.2836000330
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.1612060920 108.2561565502
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.8381796528 108.3785139275
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.5344804952 109.2381208530
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.6816130052 110.0255190870
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.9197969760 110.0988929845
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
</gie-strict>
diff --git a/test/gie/adams_ws2.gie b/test/gie/adams_ws2.gie
index c2ff193f..06df3696 100644
--- a/test/gie/adams_ws2.gie
+++ b/test/gie/adams_ws2.gie
@@ -11,7 +11,7 @@ operation +proj=adams_ws2 +R=6370997
tolerance 1 mm
------------------------------------------------------------
accept -179.7092450238 -90.0290393775
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -169.9316998581 -89.6983443874
expect -2757243.603 -13694037.516
@@ -1886,16 +1886,16 @@ accept 140.8963110473 89.7228156694
expect 2304894.417 13439579.058
accept 150.4318097094 90.4391164019
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.7127363327 90.6605815936
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.7492804294 90.8176634524
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.4583398460 90.9109976584
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.7591323884 80.4424115493
expect -6903393.952 9786682.886
@@ -1964,160 +1964,160 @@ accept 30.8762585995 89.9894216623
expect 237234.260 14954822.615
accept 40.2272544657 90.2854737833
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.3342208278 90.6201781373
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.0620171885 91.1323497706
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.7871678571 91.2021231110
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.7237355733 91.8207335323
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.5359055804 91.8495346522
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.2370378259 92.3201685216
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.7018248262 92.7082390660
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.4791498907 92.8320642395
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.7292413039 93.7863129954
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.1002623482 94.2304861566
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.7401582820 94.4002034978
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.9690930362 95.0432445572
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.5238000008 95.9332496636
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.5593997844 96.9295538910
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.2788799656 89.7588830795
expect -2720982.745 13966946.704
accept -169.2920835775 90.4241930348
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -159.9895526197 91.4107597532
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -149.2463523987 92.1662912669
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -139.5441662785 93.0270602663
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -129.2489121030 93.8575161591
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -119.2218964968 94.3245277139
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -109.6391371233 94.8605218216
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -99.7022656135 95.4188372117
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -89.9236110047 96.1459344102
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -79.3053114467 96.4284727639
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -69.9403123372 97.1204524330
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -59.8919954903 98.0976036625
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -49.4360361183 99.0132534146
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -39.1296215520 99.7082663882
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -29.7429317093 100.3804719805
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -19.9518617483 100.7090523427
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -9.8094666546 100.7731576636
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 0.6789399156 101.1890038152
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 10.3002789517 101.6303167682
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 20.3122591998 101.9746447499
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.8403181671 102.1868812356
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.5913833272 102.9224326125
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.4094599185 103.4226263618
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.2807542048 103.6337815648
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.1179652096 103.9375646519
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.0709906538 104.9002368302
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.4905546467 104.9051484801
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.8677613905 105.1778053719
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.7875504667 106.1651152124
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.3531685812 106.2777498204
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.5786379336 106.8735960149
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.2390732913 107.1035922681
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.2230766093 107.9665006223
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.0106199737 108.8731447468
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.2666681817 109.4591245928
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.2003062924 109.9750225424
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
-------------------------------------------------------------------------------
# Test inverse
@@ -2171,6 +2171,6 @@ roundtrip 1
direction inverse
accept 0.000005801264 16722285.492330472916
-expect failure errno non_convergent
+expect failure errno coord_transfm_outside_projection_domain
</gie-strict>
diff --git a/test/gie/builtins.gie b/test/gie/builtins.gie
index 813b67bb..b3c84f74 100644
--- a/test/gie/builtins.gie
+++ b/test/gie/builtins.gie
@@ -79,18 +79,18 @@ accept -200 -100
expect -0.001790493 -0.000895247
operation +proj=aea +ellps=GRS80 +lat_1=900
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
operation +proj=aea +ellps=GRS80 +lat_2=900
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
operation +proj=aea +R=6400000 +lat_1=1 +lat_2=-1
-expect failure errno conic_lat_equal
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=aea +a=9999999 +b=.9 +lat_2=1
-------------------------------------------------------------------------
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Azimuthal Equidistant
@@ -126,7 +126,7 @@ roundtrip 100
# point opposite projection center is undefined
accept 180 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test equatorial aspect of the ellipsoidal azimuthal equidistant. Test data from
@@ -269,11 +269,11 @@ roundtrip 100
#point opposite of projection center is undefined
accept 0 -90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 0 5
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 0 3.14159265359
expect 180 -90
@@ -302,7 +302,7 @@ roundtrip 100
#point opposite of projection center is undefined
accept 0 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
@@ -385,7 +385,7 @@ expect 0 -1.3863
accept 0 90
expect 0 0
accept 0 -90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
@@ -399,7 +399,7 @@ expect 0 1.3863
accept 0 -90
expect 0 0
accept 0 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test oblique aspect
@@ -412,7 +412,7 @@ expect 0 0
accept 0 0
expect -0.7336 -0.5187
accept -45 -45
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test that coordinates on the opposing hemisphere are projected when using
@@ -446,7 +446,7 @@ expect 0.3821 0.4216
operation +proj=airy +R=1 +no_cut
-------------------------------------------------------------------------------
accept -180 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
# Aitoff
@@ -1351,16 +1351,16 @@ operation +proj=eqdc +a=9999999 +b=.9 +lat_2=1
expect failure
operation +proj=eqdc +R=6400000 +lat_1=1 +lat_2=-1
-expect failure errno conic_lat_equal
+expect failure errno invalid_op_illegal_arg_value
operation +proj=eqdc +R=6400000 +lat_1=91
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
operation +proj=eqdc +R=6400000 +lat_2=91
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
operation +proj=eqdc +R=1 +lat_1=1e-9
-expect failure errno conic_lat_equal
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Euler
@@ -1679,12 +1679,12 @@ expect -0.001790493 -0.000895247
-------------------------------------------------------------------------------
operation +proj=geos +R=1 +h=0
-------------------------------------------------------------------------------
-expect failure errno invalid_h
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=geos +R=1 +h=1e11
-------------------------------------------------------------------------------
-expect failure errno invalid_h
+expect failure errno invalid_op_illegal_arg_value
@@ -1780,7 +1780,7 @@ accept 80 80
expect 5.6713 32.6596
roundtrip 100
accept 0 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# test that extreme northings are mapped to the sphere
direction inverse
@@ -1801,9 +1801,9 @@ accept 45 45
expect 0.7071 -0.7071
roundtrip 100
accept 0 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 90 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test the southern polar aspect of the gnonomic projection
@@ -1818,9 +1818,9 @@ accept 45 -45
expect 0.7071 0.7071
roundtrip 100
accept 0 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 90 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test the oblique aspect of the gnonomic projection
@@ -1838,7 +1838,7 @@ accept 0 90
expect 0 1
roundtrip 100
accept 0 -45
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
# Goode Homolosine
@@ -1918,7 +1918,7 @@ expect 3450764.261536101 -175619.041820732
# For some reason, does not fail on MacOSX
#accept 60 -45
-#expect failure errno tolerance_condition
+#expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept -1800000.000000000 2600000.000000000
@@ -1988,7 +1988,7 @@ expect -0.001790493 -0.000895247
operation +proj=hammer +a=6400000 +W=1
-------------------------------------------------------------------------------
accept -180 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
# Hatano Asymmetrical Equal Area
@@ -2502,7 +2502,7 @@ expect 24.833333333333 59.757598563058
-------------------------------------------------------------------------------
operation +proj=krovak +lat_0=-90
-------------------------------------------------------------------------------
-expect failure errno invalid_arg
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Laborde
@@ -2536,7 +2536,7 @@ expect 0.498202283 1.999095641
-------------------------------------------------------------------------------
operation +proj=labrd +ellps=GRS80 +lat_0=0
accept 0 0
-expect failure errno lat_0_is_zero
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Lambert Azimuthal Equal Area
@@ -2557,7 +2557,7 @@ accept -2 -1
expect -222602.471450095 -110589.827224409
accept 180 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 200 100
@@ -2583,7 +2583,7 @@ accept -2 -1
expect -223365.281370125 -111716.668072916
accept 180 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 200 100
@@ -2619,7 +2619,7 @@ roundtrip 100
# error when waaay outside the sphere
direction inverse
accept 0 10
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test oblique aspect of the ellipsoidal form
@@ -2662,7 +2662,7 @@ expect 0 0.7654
accept 0 45
expect 0 1.8478
accept 0 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
tolerance 0.1 mm
accept 45 45
@@ -2683,7 +2683,7 @@ expect 0 4889334.8030
accept 0 45
expect 0 11766619.5307
accept 0 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
tolerance 10 cm
accept 45 45
@@ -2709,7 +2709,7 @@ expect 0 -0.7654
accept 0 -45
expect 0 -1.8478
accept 0 -90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
tolerance 0.1 mm
accept 45 45
@@ -2730,7 +2730,7 @@ expect 0 -4889334.8030
accept 0 -45
expect 0 -11766619.5307
accept 0 -90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
tolerance 10 cm
accept 45 45
@@ -2740,7 +2740,7 @@ roundtrip 100
# Test error in projection setup
-------------------------------------------------------------------------------
operation +proj=laea +ellps=GRS80 +lat_0=91
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Lagrange
@@ -2782,22 +2782,22 @@ expect 0.10 0.0
-------------------------------------------------------------------------------
operation +proj=lagrng +R=1 +W=-1
-------------------------------------------------------------------------------
-expect failure errno w_or_m_zero_or_less
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lagrng +R=1 +lat_1=90.00001
-------------------------------------------------------------------------------
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lagrng +R=1 +W=0.5
-------------------------------------------------------------------------------
accept 90 0 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 2 0 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
operation +proj=lagrng +R=1
@@ -2966,7 +2966,7 @@ expect 1 2
-------------------------------------------------------------------------------
operation +proj=lcc +a=9999999 +b=.9 +lat_2=1
-------------------------------------------------------------------------------
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
# This case is incredible. ossfuzz has found the exact value of lat_1 that
@@ -2975,42 +2975,42 @@ operation +proj=lcc +lat_1=2D32 +lat_2=0 +a=6378137 +b=0.2
-------------------------------------------------------------------------------
expect failure
# For some reason fails on MacOSX with a different error
-# errno invalid_eccentricity
+# errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=GRS80 +lat_1=0 +lat_2=90
-------------------------------------------------------------------------------
-expect failure errno lat_1_or_2_zero_or_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=GRS80 +lat_1=90 +lat_2=0
-------------------------------------------------------------------------------
-expect failure errno lat_1_or_2_zero_or_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=GRS80 +lat_1=90 +lat_2=90
-------------------------------------------------------------------------------
-expect failure errno lat_1_or_2_zero_or_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=sphere +lat_1=0 +lat_2=90
-------------------------------------------------------------------------------
-expect failure errno lat_1_or_2_zero_or_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=sphere +lat_1=90 +lat_2=0
-------------------------------------------------------------------------------
-expect failure errno lat_1_or_2_zero_or_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=sphere +lat_1=91
-------------------------------------------------------------------------------
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=lcc +ellps=sphere +lat_2=91
-------------------------------------------------------------------------------
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Lambert Conformal Conic Alternative
@@ -3187,7 +3187,7 @@ operation +proj=lsat +path=1 +lsat=5 +ellps=sphere
-------------------------------------------------------------------------------
direction inverse
accept 0 1e10
-expect failure errno invalid_x_or_y
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
# McBryde-Thomas Flat-Polar Sine (No. 1)
@@ -3930,13 +3930,13 @@ accept 45 45
expect 0.4555 -0.4555
roundtrip 100
accept 0 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 0 0
expect 0 90
accept 0 2 # projected coordinate is outside the sphere
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test south polar aspect
@@ -3950,7 +3950,7 @@ accept -45 -45
expect -0.4555 0.4555
roundtrip 100
accept 0 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
operation +proj=nsper +R=1 +h=3 +lat_0=45
@@ -3970,12 +3970,12 @@ roundtrip 100
-------------------------------------------------------------------------------
operation +proj=nsper +R=1 +h=0
-------------------------------------------------------------------------------
-expect failure errno invalid_h
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=nsper +R=1 +h=1e11
-------------------------------------------------------------------------------
-expect failure errno invalid_h
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
@@ -4042,7 +4042,7 @@ expect -65.862385599 51.830295078
-------------------------------------------------------------------------------
operation +proj=ob_tran +R=6400000 +o_proj +o_proj=ob_tran
-------------------------------------------------------------------------------
-expect failure errno pjd_err_failed_to_find_proj
+expect failure errno invalid_op_missing_arg
===============================================================================
# Oblique Cylindrical Equal Area
@@ -4241,7 +4241,7 @@ operation +proj=omerc +R=1 +lat_0=1 +lat_1=2 +no_rot
-------------------------------------------------------------------------------
direction inverse
accept 0 1e200
-expect failure errno invalid_x_or_y
+expect failure errno coord_transfm_outside_projection_domain
@@ -4263,28 +4263,28 @@ expect -3569.825230822232 -5093592.310871849768
-------------------------------------------------------------------------------
operation +proj=omerc +R=1 +alpha=0 +lat_0=90
-------------------------------------------------------------------------------
-expect failure errno lat_0_or_alpha_eq_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=omerc +lat_1=0.1 +a=6400000 +b=1
-------------------------------------------------------------------------------
# Disabled since fails on i386. Not so important. Edge condition found by ossfuzz
-#expect failure errno invalid_eccentricity
+#expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=omerc +lat_1=0.8 +a=6400000 +b=.4
-------------------------------------------------------------------------------
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=omerc +lat_1=91
-------------------------------------------------------------------------------
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
operation +proj=omerc +lat_2=91
-------------------------------------------------------------------------------
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
@@ -4356,11 +4356,11 @@ accept 90 90
expect 0 1
roundtrip 100
accept 120 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 2 2
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
@@ -4390,11 +4390,11 @@ accept 170 60
expect 0.0868 0.9799
roundtrip 100
accept 140 20
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 2 2
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
@@ -4419,13 +4419,13 @@ accept 90 0
expect 1 0
roundtrip 100
accept 180 -90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 0 -45
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 2 2
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# Test the south polar aspect of the Orthographic projection.
@@ -4449,13 +4449,13 @@ accept 90 0
expect 1 0
roundtrip 100
accept 180 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 0 45
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 2 2
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Put a point a tiny tiny bit outside the radius of the sphere.
# Since we are right at the numerical limit of floating point representation
@@ -4496,7 +4496,7 @@ expect -6378137 18504.1253
# Slightly outside
direction inverse
accept -6378137.001 18504.1253
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# On boundary of visibility domain
direction forward
@@ -4507,7 +4507,7 @@ expect 0 -6343601.0991
# Just on it, but fails to converge. This test might be fragile
direction inverse
accept 0 -6343601.099075031466782093
-expect failure errno non_convergent
+expect failure errno coord_transfm_outside_projection_domain
# Slightly inside
direction inverse
@@ -4559,11 +4559,11 @@ roundtrip 1
# Point not visible from the projection plane
accept 90.00001 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Point not visible from the projection plane
accept -90.00001 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Consistent with WGS84 semi-major axis
accept 90 0
@@ -4586,17 +4586,17 @@ roundtrip 1
# Point not visible from the projection plane
direction inverse
accept 0 6356752.3143
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Point not visible from the projection plane
direction inverse
accept 1000 6356752.314
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Point not visible from the projection plane
direction inverse
accept 6378137.0001 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# North pole tests
@@ -4617,7 +4617,7 @@ roundtrip 1
# Point not visible from the projection plane
accept 0 -0.0000001
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Consistent with WGS84 semi-major axis
accept 0 0
@@ -4627,7 +4627,7 @@ roundtrip 1
# Point not visible from the projection plane
direction inverse
accept 0 -6378137.1
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
-------------------------------------------------------------------------------
# South pole tests
@@ -4644,7 +4644,7 @@ roundtrip 1
# Point not visible from the projection plane
accept 0 0.0000001
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
# Consistent with WGS84 semi-major axis
accept 0 0
@@ -4654,7 +4654,7 @@ roundtrip 1
# Point not visible from the projection plane
direction inverse
accept 0 6378137.1
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
@@ -5209,7 +5209,7 @@ accept 0.000000000000 -8654720.000000000000
expect 0 -90
accept 17250000 100000
-expect failure errno lat_or_lon_exceed_limit
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
@@ -5486,7 +5486,7 @@ expect -223407.810259507 111737.938996443
accept -2 -1
expect -223407.810259507 -111737.938996443
accept 180 0
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
direction inverse
accept 200 100
@@ -5978,7 +5978,7 @@ operation +proj=tmerc +R=1
-------------------------------------------------------------------------------
direction inverse
accept -1e200 0
-expect failure errno invalid_x_or_y
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
@@ -6137,10 +6137,10 @@ operation +proj=tobmerc +ellps=sphere
# Test expected failure at the poles:
-------------------------------------------------------------------------------
accept 0 90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 0 -90
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
@@ -6287,7 +6287,8 @@ expect -45.001432287 64.914588378
-------------------------------------------------------------------------------
operation +proj=ups +a=6400000
-------------------------------------------------------------------------------
-expect failure errno ellipsoid_use_required
+# ups not possible on sphere
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Urmaev V
@@ -6309,7 +6310,7 @@ accept -2 -1
expect -223393.638433964 -111696.818785117
operation +proj=urm5 +a=6400000 +n=1 +alpha=90
-expect failure errno lat_0_or_alpha_eq_90
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# Urmaev Flat-Polar Sinusoidal
@@ -6385,7 +6386,8 @@ expect 687071.43911000 6210141.32675053 0.00000000 2000.0000
-------------------------------------------------------------------------------
operation +proj=utm +a=6400000 +zone=30
-------------------------------------------------------------------------------
-expect failure errno ellipsoid_use_required
+# utm not possible on sphere
+expect failure errno invalid_op_illegal_arg_value
===============================================================================
# van der Grinten (I)
@@ -6421,7 +6423,7 @@ operation +proj=vandg +R=1
-------------------------------------------------------------------------------
direction inverse
accept 0 -1e100
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
===============================================================================
@@ -6901,18 +6903,18 @@ roundtrip 1
# missing X_0,Y_0,Z_0 or lon_0,lat_0
operation +proj=topocentric +ellps=WGS84
-expect failure errno missing_args
+expect failure errno invalid_op_missing_arg
# missing Z_0
operation +proj=topocentric +ellps=WGS84 +X_0=0 +Y_0=0
-expect failure errno missing_args
+expect failure errno invalid_op_missing_arg
# missing lat_0
operation +proj=topocentric +ellps=WGS84 +lon_0=0
-expect failure errno missing_args
+expect failure errno invalid_op_missing_arg
# X_0 and lon_0 are mutually exclusive
operation +proj=topocentric +ellps=WGS84 +X_0=0 +lon_0=0
-expect failure errno mutually_exclusive_args
+expect failure errno invalid_op_mutually_exclusive_args
</gie-strict>
diff --git a/test/gie/defmodel.gie b/test/gie/defmodel.gie
index 94dd5784..95264c82 100644
--- a/test/gie/defmodel.gie
+++ b/test/gie/defmodel.gie
@@ -8,15 +8,15 @@ Test +proj=defmodel
# Missing +model
operation +proj=defmodel
-expect failure errno no_args
+expect failure errno invalid_op_missing_arg
# +model doesn't point to an existing file
operation +proj=defmodel +model=i_do_not_exist
-expect failure errno invalid_arg
+expect failure errno invalid_op_file_not_found_or_invalid
# Not a JSON file
operation +proj=defmodel +model=proj.ini
-expect failure errno invalid_arg
+expect failure errno invalid_op_file_not_found_or_invalid
# Horizontal deformation with horizontal unit = degree
operation +proj=defmodel +model=tests/simple_model_degree_horizontal.json
diff --git a/test/gie/deformation.gie b/test/gie/deformation.gie
index cda2e5ac..086c1ebe 100644
--- a/test/gie/deformation.gie
+++ b/test/gie/deformation.gie
@@ -47,7 +47,6 @@ operation +proj=deformation +xy_grids=alaska +z_grids=egm96_15.gtx \
+ellps=GRS80 +dt=16.0 # 2016.0 - 2000.0
-------------------------------------------------------------------------------
tolerance 0.1 mm
-ignore pjd_err_failed_to_load_grid
accept -3004295.5882503074 -1093474.1690603832 5500477.1338251457
expect -3004295.7000 -1093474.2097 5500477.3397
roundtrip 5
@@ -55,9 +54,9 @@ roundtrip 5
# Test that errors are reported for coordinates outside the grid.
# Here we test 120W 40N which is well outside the alaska grid.
accept -2446353.8001 -4237209.0750 4077985.572
-expect failure errno grid_area
+expect failure errno coord_transfm_outside_grid
accept -2446353.8001 -4237209.0750 4077985.572
-expect failure errno grid_area
+expect failure errno coord_transfm_outside_grid
-------------------------------------------------------------------------------
@@ -68,34 +67,32 @@ operation +proj=deformation \
-------------------------------------------------------------------------------
tolerance 0.1 mm
direction inverse
-ignore pjd_err_failed_to_load_grid
accept -3004295.5882503074 -1093474.1690603832 5500477.1338251457 2000.0
expect -3004295.7000 -1093474.2097 5500477.3397 2000.0
roundtrip 5
-------------------------------------------------------------------------------
operation proj=deformation xy_grids=alaska +dt=1.0 ellps=GRS80
-expect failure pjd_err_no_args
+expect failure errno invalid_op_missing_arg
operation proj=deformation z_grids=egm96_15.gtx +dt=1.0 ellps=GRS80
-expect failure pjd_err_no_args
+expect failure errno invalid_op_missing_arg
operation proj=deformation xy_grids=nonexisting z_grids=egm96_15.gtx \
+dt=1.0 ellps=GRS80
-expect failure pjd_err_failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
operation proj=deformation xy_grids=alaska z_grids=nonexisting \
+dt=1.0 ellps=GRS80
-expect failure pjd_err_failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
operation proj=deformation xy_grids=alaska z_grids=nonexisting ellps=GRS80
-expect failure pjd_err_missing_args
+expect failure errno invalid_op_file_not_found_or_invalid
-------------------------------------------------------------------------------
operation +proj=vgridshift +grids=egm96_15.gtx +t_epoch=2010.0 +t_final=2018.0
-------------------------------------------------------------------------------
tolerance 0.1 mm
-ignore pjd_err_failed_to_load_grid
accept 12 56 0.0 2000.0
expect 12 56 -36.9960 2000.0
@@ -118,7 +115,6 @@ roundtrip 100
operation +proj=vgridshift +grids=egm96_15.gtx +t_epoch=2010.0 +t_final=now
-------------------------------------------------------------------------------
tolerance 0.1 mm
-ignore pjd_err_failed_to_load_grid
accept 12 56 0.0 2000.0
expect 12 56 -36.9960 2000.0
@@ -137,7 +133,6 @@ roundtrip 100
operation +proj=hgridshift +grids=alaska +t_epoch=2010.0 +t_final=2018.0
-------------------------------------------------------------------------------
tolerance 0.1 mm
-ignore pjd_err_failed_to_load_grid
accept -147.0 64.0 0.0 2000.0
expect -147.0023233121 63.9995792119 0.0 2000.0
@@ -155,7 +150,6 @@ roundtrip 100
operation +proj=hgridshift +grids=alaska +t_epoch=2010.0 +t_final=now
-------------------------------------------------------------------------------
tolerance 0.1 mm
-ignore pjd_err_failed_to_load_grid
accept -147.0 64.0 0.0 2000.0
expect -147.0023233121 63.9995792119 0.0 2000.0
diff --git a/test/gie/ellipsoid.gie b/test/gie/ellipsoid.gie
index 5e0049f7..ea0e326a 100644
--- a/test/gie/ellipsoid.gie
+++ b/test/gie/ellipsoid.gie
@@ -53,22 +53,22 @@ expect 1335833.8895192828 7326837.7148738774
# Then try to fail deliberately
-------------------------------------------------------------------------------
operation proj=merc ellps=GRS80000000000
-expect failure errno unknown_ellp_param
+expect failure errno invalid_op_illegal_arg_value
operation proj=merc +a=-1
-expect failure errno major_axis_not_given
+expect failure errno invalid_op_illegal_arg_value
operation proj=merc
accept 0 0
expect 0 0
-operation proj=merc +es=-1
-expect failure errno major_axis_not_given
+operation proj=merc +a=1 +es=-1
+expect failure errno invalid_op_illegal_arg_value
operation proj=merc +R=0
-expect failure errno major_axis_not_given
+expect failure errno invalid_op_illegal_arg_value
operation +proj=merc +R_a +a=2 +f=2
-expect failure errno major_axis_not_given
+expect failure errno invalid_op_illegal_arg_value
operation
expect failure
@@ -117,8 +117,6 @@ expect 1338073.2696101593 7374207.4801437631
-------------------------------------------------------------------------------
operation proj=merc a=1E77 R_lat_a=90 b=1
-# errno invalid_eccentricity on x86_64
-# errno pjd_err_ref_rad_larger_than_90 on i386
expect failure
-------------------------------------------------------------------------------
@@ -136,25 +134,25 @@ expect -1.56904 0
# Shape parameters
-------------------------------------------------------------------------------
operation proj=utm zone=32 ellps=GRS80 rf=0
-expect failure errno rev_flattening_is_zero
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 ellps=GRS80 e=-0.5
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 ellps=GRS80 e=1
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 ellps=GRS80 es=1
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 a=1 es=1.1
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 ellps=GRS80 b=0
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 ellps=GRS80 f=1
-expect failure errno invalid_eccentricity
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm zone=32 ellps=GRS80 b=6000000
accept 12 55
diff --git a/test/gie/geotiff_grids.gie b/test/gie/geotiff_grids.gie
index b71ed774..7e03d20a 100644
--- a/test/gie/geotiff_grids.gie
+++ b/test/gie/geotiff_grids.gie
@@ -151,13 +151,13 @@ expect 4.05 52.1 10
-------------------------------------------------------------------------------
operation +proj=vgridshift +grids=tests/test_vgrid_invalid_channel_type.tif +multiplier=1
-------------------------------------------------------------------------------
-expect failure errno failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
operation +proj=vgridshift +grids=tests/test_vgrid_unsupported_byte.tif +multiplier=1
-------------------------------------------------------------------------------
-expect failure errno failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
@@ -181,7 +181,7 @@ accept 179.8 54.5 0
expect 179.8 54.5 -0.7011
accept 179.799 54.5 0
-expect failure errno grid_area
+expect failure errno coord_transfm_outside_grid
accept 180.1833333 54.5 0
expect -179.8166667 54.5 -3.1933
@@ -190,10 +190,10 @@ accept -179.8166667 54.5 0
expect -179.8166667 54.5 -3.1933
accept 180.184 54.5 0
-expect failure errno grid_area
+expect failure errno coord_transfm_outside_grid
accept -179.816 54.5 0
-expect failure errno grid_area
+expect failure errno coord_transfm_outside_grid
-------------------------------------------------------------------------------
operation +proj=hgridshift +grids=tests/test_hgrid.tif
@@ -327,7 +327,7 @@ accept -45.0 22.5 5
-------------------------------------------------------------------------------
operation +proj=hgridshift +grids=tests/test_vgrid.tif
-------------------------------------------------------------------------------
-expect failure errno failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
-------------------------------------------------------------------------------
diff --git a/test/gie/guyou.gie b/test/gie/guyou.gie
index f311c173..2ed2ab49 100644
--- a/test/gie/guyou.gie
+++ b/test/gie/guyou.gie
@@ -9,31 +9,31 @@ operation +proj=guyou +R=6370997
tolerance 1 mm
------------------------------------------------------------
accept -179.2338274749 -90.7265739758
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -169.3015609686 -90.0683270041
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -159.4420546811 -89.5695551279
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.0045856345 -89.3536369188
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.7153960960 -88.6283945950
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.2286632319 -88.1551228787
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.6286953558 -87.5083524092
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3328522812 -86.7510648640
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.1598524965 -86.5788079857
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3858632536 -85.7390309668
expect -671252.534 -11805089.168
@@ -90,61 +90,61 @@ accept 80.2085188693 -77.6809008485
expect 1936586.409 -11469925.164
accept 90.8009658259 -76.9680414794
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.6742326194 -76.5942100817
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5209403479 -75.7585741711
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.5896919383 -74.7649093703
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.7851397036 -73.8582467239
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.7197125638 -72.9106110624
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.4163065521 -72.4059990981
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.4383759680 -71.9757412863
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.5708534042 -71.9525642223
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.2751947006 -71.5923171899
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.7095201992 -79.9687467646
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.0436424710 -79.2424043855
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.2911675882 -78.8917009107
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.2815042820 -78.0224816760
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.5027225646 -77.9987560452
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.2026665027 -77.1138023157
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.6161746714 -76.2954327600
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.9384914753 -75.7674050764
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.2183181307 -75.3730011624
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.2190150125 -74.7701795551
expect -2454071.146 -11777557.324
@@ -201,61 +201,61 @@ accept 80.8997122704 -66.2858473379
expect 3898590.190 -11120572.688
accept 90.1834036836 -65.9440561722
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.1984006355 -65.8229326488
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.0486236854 -65.7960345782
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.0510835725 -65.5190096678
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.0896340570 -64.7428784330
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.3678752942 -64.2229928140
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.9150615805 -63.6990548356
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.7280406636 -63.2384418688
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.9183869916 -62.3774990742
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.5619551786 -61.8063907044
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.5943789042 -69.9992085183
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.2134281484 -69.9776667645
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.4518981501 -69.3934026425
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3420413989 -68.4537518490
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.1131932532 -67.9826718761
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7785737569 -67.0804523760
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.8160590971 -66.1963102135
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.4603476745 -65.8550220266
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.0748524068 -64.9756976432
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.9206313411 -64.7601702734
expect -4268828.098 -11805632.912
@@ -312,61 +312,61 @@ accept 80.0904535261 -56.6354279372
expect 5822685.735 -10504356.087
accept 90.6634211024 -56.5251359813
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.1452342443 -55.8401169432
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.6864799856 -55.5116401637
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.3347823427 -55.2601958124
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.5134926951 -55.0238926067
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.3265242174 -54.4313834318
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.3685976599 -54.1552793246
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.9436711470 -53.1842316256
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.4034003030 -52.8621841373
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.0812683568 -52.6818511960
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.2224188803 -59.7295306861
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.4132895133 -59.2803345438
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.2336212919 -58.3674875157
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.6086565801 -57.6885943847
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.4537382278 -57.2767531329
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.8015642819 -57.0799116685
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.7728590554 -56.2047588377
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.7735055519 -55.4019628150
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.4371631073 -55.2867551270
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.8854290226 -55.2220077227
expect -6418775.726 -11794916.199
@@ -423,61 +423,61 @@ accept 80.4369996020 -46.9794332723
expect 8182405.160 -9269149.720
accept 90.9151039880 -46.9029866463
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.4373534616 -46.3943619602
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.2842129880 -46.0308507793
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.6486866778 -45.8054277747
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.9364857762 -44.8554259969
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6165699073 -43.9676693909
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.9528142413 -43.4405627423
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.5641245537 -42.8137396224
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.0938980656 -42.4864250646
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.3769971687 -41.5989802375
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.6808058361 -49.7903016746
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.7237623059 -49.1268921477
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.4102418582 -48.8849591656
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.2254953136 -48.1844242863
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.6041758915 -48.1179744801
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.3754143228 -47.1336832541
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.9746970079 -46.6736994965
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.7581919902 -46.0366124472
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.3823846098 -45.2381613350
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.0277852820 -44.5174266340
expect -11094288.600 -10444365.724
@@ -534,61 +534,61 @@ accept 80.3791490145 -38.1923095026
expect 9574134.022 -7007709.059
accept 90.5297378114 -37.5687159826
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.5373276614 -37.4573903187
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.0551604465 -36.8785291472
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.5920897044 -36.3504262236
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1692367892 -36.3071095311
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.0034604349 -35.8053875550
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.9162515055 -35.0369229256
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.4006102901 -34.7824559736
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.8020614665 -34.6367632672
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.1238278697 -34.5735242626
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.3392011550 -39.0089519711
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.9896135260 -38.7758352491
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9464206150 -38.3643075290
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.8580885141 -38.2565849818
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.0005407033 -37.8175552179
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.9744744916 -36.9749101428
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.4953757022 -36.8251466679
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.8732055905 -36.2644266473
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.2563126423 -35.6283177384
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.2720021301 -34.8337636531
expect -11652944.582 -6432012.406
@@ -645,61 +645,61 @@ accept 80.2959404087 -25.8737294352
expect 10093881.725 -4297066.952
accept 90.1903848581 -25.5035070096
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.5725497895 -24.6749860350
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.0757522922 -23.8621044004
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.4910038636 -23.3154304481
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.4609905705 -22.3944602016
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6308884892 -22.1941484220
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.0358167607 -21.7789499055
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.5878069076 -21.7481812197
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.4050593367 -20.8432353205
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.6001699300 -20.8118177919
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.3361000782 -29.8463222037
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8999068245 -28.9429338477
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.7592377898 -28.1615925042
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.9913638701 -28.0372332017
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.2301202473 -27.0565876723
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.1268966632 -26.9865340393
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2460222852 -26.3197565889
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.2062914741 -26.1682287226
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9045914125 -25.7799438486
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.4037956256 -25.6991927518
expect -11705355.483 -4359448.179
@@ -756,61 +756,61 @@ accept 80.3956836685 -17.4271102390
expect 10234009.562 -2784279.451
accept 90.6808556357 -16.9481935094
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.3669156655 -16.2433923188
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.3790328662 -15.6932515137
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.0882522480 -15.6441029970
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.9326190128 -15.1072978015
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.4297399110 -14.7647959439
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.6670621082 -14.1800360544
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.3083279810 -13.5438931052
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.8801051896 -12.6909069291
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.9127621133 -11.7358777998
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.9634704329 -19.2242789077
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.1616383718 -18.5021923570
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.5989242161 -17.7569846767
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.7658699571 -17.6838689314
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.2283007229 -17.1203530837
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.9856069274 -16.5121558117
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.7066160149 -15.8271303941
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.0808307002 -15.7236132624
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.7051569128 -15.2351555878
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.3984343202 -14.2830109769
expect -11714485.527 -2294583.435
@@ -867,61 +867,61 @@ accept 80.1896127919 -6.1835665729
expect 10268415.013 -962009.778
accept 90.2901075635 -5.6342271039
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.1017071129 -4.7732910406
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.6453720127 -4.6247740358
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.7065181706 -4.2131506322
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.0549243427 -3.6680122287
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.9588650575 -3.4693258990
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.3128054514 -2.8622073994
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.6250791828 -2.1132082532
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1249865639 -1.7779699685
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.4636820369 -1.0447468723
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.0903238876 -9.3809572676
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8021514554 -8.8200596604
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.6897632216 -8.8151211116
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3642571872 -7.9578518334
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.1869613409 -7.1376473645
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.8103143949 -6.6533639455
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.0042762894 -6.5424897944
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3222469320 -6.2626405858
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.2447484897 -5.4322064514
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.6583934020 -4.8520491055
expect -11758391.270 -764820.107
@@ -978,61 +978,61 @@ accept 80.4040420231 2.1516254056
expect 10309233.052 333889.458
accept 90.0745563464 2.5008083079
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.1323994743 3.4798778581
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.7633392793 3.6524418056
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.4935453458 3.8138602324
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1832453461 4.1827817395
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6879708211 4.3228601350
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.2872780471 5.0096390922
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.4567844437 5.3289862640
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1798195714 5.7690110660
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.6237066153 6.6873727446
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.1879408995 0.2925675717
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8193242429 0.5456299185
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.6143094365 0.8491614798
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.1327424918 1.5360082778
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.9118046279 2.2304783506
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.0707848713 3.1774300866
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.0155367869 3.7108516861
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.7138958240 4.2367325538
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.7626123411 4.9489248449
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.0617378460 5.0261998535
expect -11664192.229 792317.110
@@ -1089,61 +1089,61 @@ accept 80.6785108917 11.6138802990
expect 10322728.590 1826238.813
accept 90.9684446145 11.7088334392
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.8216260873 12.6522648050
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.9341322494 12.8091489452
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.9598573820 12.9840580805
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1838852888 13.9674113487
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.0163435591 14.2583869011
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.3440941987 15.1977215509
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.6373902313 15.9779535702
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.7489315029 16.0224553269
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.4315909707 16.2341190017
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.9613846400 10.9181102314
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.2464750707 11.2011582425
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.3961353214 12.0814824633
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.9176675016 12.1332225594
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.0300120770 12.7448426145
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.1479377942 13.2115900349
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.6509465671 13.5121287506
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3485953585 13.9838806488
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.8025484668 14.3000196702
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.6183447418 14.3419323455
expect -11750225.007 2304558.947
@@ -1200,61 +1200,61 @@ accept 80.2433369822 23.0164275848
expect 10137749.549 3763259.969
accept 90.9377687408 23.1511733038
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.5407405945 23.7761284488
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.0059145808 24.0087396721
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.0839708022 24.8505061022
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.5684827033 25.5457759639
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.2735017629 25.7841586919
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.4960718541 26.4511385776
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.5086557650 26.5248940712
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1010951379 26.6437577891
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.4667032708 27.5171288037
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.2332673731 20.5208357556
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.9852102849 20.6884242583
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.0918834805 20.7807287727
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3554284700 21.5195488802
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.0517203599 22.3228377599
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7889045882 22.9579802676
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2864956877 23.1541372478
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.1249371549 23.9554652672
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.7886236408 24.2156608317
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.8158531726 24.4254617574
expect -11779801.464 4109615.321
@@ -1311,61 +1311,61 @@ accept 80.8754092571 33.4499285913
expect 9965465.329 5886025.407
accept 90.9417476435 34.2241428842
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.8763555867 34.9730810876
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.3824336404 35.8924849218
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.3907138338 36.0772654252
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.2213236652 36.3411661168
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6643127929 37.0777875387
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.5696707234 38.0028546554
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.7330142926 38.8399381962
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.7575452122 39.6058463190
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.9074447347 39.7506383769
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.8967233384 30.5573004598
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.4186924041 30.7925389719
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.3550554816 31.7173298465
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3340973772 32.5661389704
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.8793305042 33.1451975000
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.0718020283 34.1077930148
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.3765659597 34.6652275838
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.7130644703 34.6829381126
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.5574458139 35.6024191831
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.7509673047 36.5904991465
expect -11753853.356 6923417.921
@@ -1422,61 +1422,61 @@ accept 80.5212319721 43.4298814980
expect 8945156.756 8415826.102
accept 90.6029060873 44.3367368198
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.2968163089 44.7347899226
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5453757907 45.2325884903
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.7132187645 46.1810408682
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.6036848279 46.5953112427
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.8567165951 47.1100600825
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.2452206431 47.5590007593
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.4264735249 47.6243197261
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.1158223427 47.9911994181
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.2100320112 48.9423016681
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.5621188253 40.3822966969
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.0785389235 40.7397870392
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9453288766 41.0637989828
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.0072837113 41.2595851413
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.3677527689 41.6743754043
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.1116359654 41.9054883189
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2367048985 42.7084205060
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.9662473469 42.7707453425
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.5437449083 43.0239640060
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.4757325990 43.2756199739
expect -11568961.170 9589089.555
@@ -1533,61 +1533,61 @@ accept 80.7661690288 51.9879378395
expect 6957594.499 10145750.592
accept 90.2760527960 52.6279152662
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.4470132582 53.2519801847
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.1282829759 53.4607562483
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.5033443580 53.9989335755
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.6561885293 54.6823982531
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.8127091472 54.7255186711
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.0054753699 55.4459165788
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.8312787949 56.2470115579
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.4614439985 57.0241073917
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.7047485406 57.6022388310
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.1586219943 50.1365490236
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.1490260788 50.5023613434
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9535088204 50.9035428509
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.0803324654 51.7753015653
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.7669273536 52.0799612604
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.3599142098 52.6974765371
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.6940989810 52.7976100393
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.7805542206 53.6394720461
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9951721199 54.3490528856
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.4965032257 55.2735286995
expect -6404341.484 11736182.738
@@ -1644,61 +1644,61 @@ accept 80.0566574740 65.2466871256
expect 4076741.126 11011949.460
accept 90.0598623933 65.7380193724
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.2499385302 65.8274446207
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.0091445253 66.5841928232
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.1938557094 67.3045114589
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.1756983494 67.6825233842
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.0774508004 68.5260112188
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.3642244888 69.0087889372
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.0390197585 69.5064813197
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.9882511230 69.9663419458
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.7855662108 70.7558001565
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.8630282894 60.2684905661
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.8774561096 60.7063957678
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.1639611249 61.1269337981
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.0814548820 61.9063878006
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.0476545160 62.7911475081
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.8276916999 62.8515546512
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.9464541970 63.7277849393
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.6864148265 63.9317823343
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.4184495170 64.2249537529
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.6146334566 64.3967878406
expect -4340586.273 11779220.401
@@ -1755,61 +1755,61 @@ accept 80.5645741906 73.7542661119
expect 2585249.402 11363593.076
accept 90.6177784757 74.6865930919
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.2695381559 74.9397012116
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.3724185381 75.3340827987
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.0440856622 75.6509550283
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.4765915697 75.8794035471
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.8273607225 76.0863350217
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.7446122566 76.4130503173
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.9066279973 77.2046671411
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.7039755420 77.5254695021
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.7301487821 78.3643690894
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.8424303971 70.7640164273
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.3071682617 71.3534426809
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9256766432 72.0788134529
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.4389257633 72.9048071827
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.4466193836 73.7144086150
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.4240513471 74.3140345936
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2324314226 75.1789245938
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.4080456874 75.9740320316
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9624349535 76.7254677659
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.8454838458 77.0914030368
expect -2065538.883 11806583.302
@@ -1866,61 +1866,61 @@ accept 80.6482540792 83.6156947131
expect 994412.198 11647508.801
accept 90.5789951029 84.1124942551
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 100.9443622402 84.2131541284
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 110.5781783058 84.7127066970
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 120.6025664533 85.5661224284
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 130.0976840056 86.3318417998
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 140.6428111911 86.3329325553
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 150.5251209004 86.5841388479
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 160.4225603060 86.8828039057
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 170.2581319411 87.4171568183
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept 180.2641439484 88.1608036446
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -179.8401984185 80.4164439367
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.6918872432 81.0641431423
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.9211815920 81.7949103274
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.6075138921 82.1028453149
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -139.7372920424 82.6385276754
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -129.7998353504 83.1090136759
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -119.2572393635 83.4744235117
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -109.3246360912 84.2608342272
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -99.9601976700 84.4677069243
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -89.7505869053 85.0897168462
expect -774050.983 11808922.435
@@ -1956,166 +1956,166 @@ accept 10.6007672189 89.4603893825
expect 15609.535 11728897.894
accept 20.8972133561 90.3008662748
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.3236847010 90.9360697392
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.5211596030 91.7425546179
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.9530657025 92.7167872262
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.2966089164 93.5518747322
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.7058277145 93.9478756274
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.2842419408 94.5029189079
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.7046514943 94.5870657217
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.5757828394 94.7544968060
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.0784957493 95.6326996288
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.4420696450 95.7426558832
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.0586467430 96.7026620164
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.4982918026 97.2453640881
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.5137836610 97.2825819689
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.8117951323 97.8473653755
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.3402740510 98.3587698302
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.9378053935 98.8743871260
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.1153600127 89.6136396944
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -169.2261536485 89.9072554901
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -159.1164133392 89.9075872145
-expect failure errno -20
+expect failure errno coord_transfm_outside_projection_domain
accept -149.3960866375 90.6652890542
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -139.1720109722 91.2726639403
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -129.0729383513 91.6124307897
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -119.9896731679 92.3534538297
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -109.8793121665 92.7446796075
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -99.4084806305 92.8846710223
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -89.0674703286 93.0281709121
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -79.1149414160 93.4632295476
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -69.5261517902 94.2811379653
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -59.0417407292 95.2403005497
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -49.3488539326 95.3977809221
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -39.5548627592 96.1026759897
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -29.0476034815 96.4820442045
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -19.8278954645 96.7461121139
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -9.5488366916 97.4860281314
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 0.2307496667 97.5054708483
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 10.6032378382 97.7247157965
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 20.8959156966 98.0573474237
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.7104889319 98.5114024172
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.1762654017 98.8114138429
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.8420835837 99.5737438963
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.4391516649 99.6023781174
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.3833096116 99.8129052911
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.6796681432 100.7784977140
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.8893235311 100.9639616716
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.8499388037 101.2529844461
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.5488903609 101.9706798836
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.1208651509 102.2817021553
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.1003249085 102.6010355936
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.8624898562 102.6311753718
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.3852952852 103.0749738073
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.7214099599 103.8391207142
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.6439119665 104.6357199780
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.2173889904 105.2754168153
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
------------------------------------------------------------
------------------------------------------------------------
diff --git a/test/gie/more_builtins.gie b/test/gie/more_builtins.gie
index 41d0ac52..67635642 100644
--- a/test/gie/more_builtins.gie
+++ b/test/gie/more_builtins.gie
@@ -75,11 +75,11 @@ roundtrip 1
-------------------------------------------------------------------------------
# No arguments
operation proj=molodensky a=6378160 rf=298.25
-expect failure errno no_args
+expect failure errno invalid_op_missing_arg
# Missing arguments
operation proj=molodensky a=6378160 rf=298.25 dx=0
-expect failure errno missing_arg
+expect failure errno invalid_op_missing_arg
-------------------------------------------------------------------------------
@@ -267,11 +267,11 @@ roundtrip 100 1 nm
-------------------------------------------------------------------------------
# Fail on purpose: +grids parameter is mandatory
operation proj=vgridshift
-expect failure errno no_args
+expect failure errno invalid_op_missing_arg
# Fail on purpose: open non-existing grid
operation proj=vgridshift grids=nonexistinggrid.gtx
-expect failure errno failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
@@ -298,11 +298,11 @@ expect 2.250704350387 46.500051597273
-------------------------------------------------------------------------------
# Fail on purpose: open non-existing grid:
operation proj=hgridshift grids=@nonexistinggrid.gsb,anothernonexistinggrid.gsb
-expect failure errno failed_to_load_grid
+expect failure errno invalid_op_file_not_found_or_invalid
# Fail on purpose: +grids parameter is mandatory:
operation proj=hgridshift
-expect failure errno no_args
+expect failure errno invalid_op_missing_arg
-------------------------------------------------------------------------------
@@ -434,27 +434,27 @@ expect 3513638.1999 778956.4533 5248216.4535 2008.75
-------------------------------------------------------------------------------
# A rotational term implies an explicit convention to be specified
operation proj=helmert rx=1
-expect failure errno missing_arg
+expect failure errno invalid_op_missing_arg
operation proj=helmert rx=1 convention=foo
-expect failure errno invalid_arg
+expect failure errno invalid_op_illegal_arg_value
operation proj=helmert rx=1 convention=1
-expect failure errno invalid_arg
+expect failure errno invalid_op_illegal_arg_value
# towgs84 in helmert context should always be position_vector
operation proj=helmert towgs84=1,2,3,4,5,6,7 convention=coordinate_frame
-expect failure errno invalid_arg
+expect failure errno invalid_op_illegal_arg_value
# Transpose no longer accepted
operation proj=helmert transpose
-expect failure errno invalid_arg
+expect failure errno invalid_op_illegal_arg_value
# Use of 2D Helmert interface with 3D Helmert setup
operation +proj=ob_tran +o_proj=helmert +o_lat_p=0
direction inverse
accept 0 0
-expect failure errno 22
+expect failure errno no_inverse_op
-------------------------------------------------------------------------------
# Molodensky-Badekas from IOGP Guidance 7.2, Transformation from La Canoa to REGVEN
@@ -477,7 +477,7 @@ expect 2550138.45 -5749799.87 1054530.82
# Missing convention
operation proj=molobadekas
-expect failure errno missing_arg
+expect failure errno invalid_op_missing_arg
-------------------------------------------------------------------------------
@@ -513,14 +513,14 @@ roundtrip 1
# some less used options
-------------------------------------------------------------------------------
operation proj=utm ellps=GRS80 zone=32 to_meter=0
-expect failure errno unit_factor_less_than_0
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm ellps=GRS80 zone=32 to_meter=10
accept 12 55
expect 69187.5632 609890.7825
operation proj=utm ellps=GRS80 zone=32 to_meter=1/0
-expect failure errno unit_factor_less_than_0
+expect failure errno invalid_op_illegal_arg_value
operation proj=utm ellps=GRS80 zone=32 to_meter=2.0/0.2
accept 12 55
@@ -791,7 +791,7 @@ expect 25 25 25 25
# Test invalid lat_0
operation +proj=aeqd +R=1 +lat_0=91
-expect failure errno lat_larger_than_90
+expect failure errno invalid_op_illegal_arg_value
-------------------------------------------------------------------------------
# cart
diff --git a/test/gie/nkg.gie b/test/gie/nkg.gie
new file mode 100644
index 00000000..7414914e
--- /dev/null
+++ b/test/gie/nkg.gie
@@ -0,0 +1,240 @@
+<gie-strict>
+
+# -------------------------------------------------------------------------------
+# NKG
+# -------------------------------------------------------------------------------
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_NKG_ETRF00
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9311 948983.7980 5201383.2227 2020.5
+
+
+#-------------------------------------------------------------------------------
+# DENMARK
+#-------------------------------------------------------------------------------
+
+# 2008 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_DK
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9362 948983.7825 5201383.2292 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_DK
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.3829 948984.2188 5201383.5296 2020.5
+
+
+# 2020 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_DK
+tolerance 0.1 mm
+
+# BUDD
+accept 3513638.0964 778956.5470 5248216.5248 2015.0
+expect 3513638.5607 778956.1875 5248216.2477 2015.0
+
+#ESBC
+accept 3582104.8458 532590.0946 5232755.0863 2015.0
+expect 3582105.2916 532589.7310 5232754.8057 2015.0
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_NKG_ETRF14
+tolerance 0.1 mm
+
+# BUDD
+accept 3513638.0964 778956.5470 5248216.5248 2015.0
+expect 3513638.5071 778956.1528 5248216.2870 2015.0
+
+# ESBC
+accept 3582104.8458 532590.0946 5232755.0863 2015.0
+expect 3582105.2401 532589.6950 5232754.8507 2015.0
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF14_TO_DK
+tolerance 0.1 mm
+
+# BUDD
+accept 3513638.5071 778956.1528 5248216.2870 2015.0
+expect 3513638.5607 778956.1875 5248216.2477 2015.0
+
+# ESBC
+accept 3582105.2401 532589.6950 5232754.8507 2015.0
+expect 3582105.2916 532589.7310 5232754.8057 2015.0
+
+# -------------------------------------------------------------------------------
+# ESTONIA
+# -------------------------------------------------------------------------------
+
+# 2008 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_EE
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9395 948983.8006 5201383.2242 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_EE
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.3862 948984.2370 5201383.5246 2020.5
+
+
+# 2020 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_EE
+tolerance 0.1 mm
+
+# AJOE
+accept 2922027.7409 1516183.8589 5444680.6502 2015.0
+expect 2922028.2730 1516183.5457 5444680.4094 2015.0
+
+# -------------------------------------------------------------------------------
+# FINLAND
+# -------------------------------------------------------------------------------
+
+# 2008 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_FI
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9522 948983.7911 5201383.2230 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_FI
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.3989 948984.2274 5201383.5235 2020.5
+
+
+# 2020 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_FI
+tolerance 0.1 mm
+
+# DEGE
+accept 2994012.0569 1112559.9272 5502272.0863 2015.0
+expect 2994012.5170 1112559.5902 5502271.7683 2015.0
+
+
+# -------------------------------------------------------------------------------
+# LATVIA
+# -------------------------------------------------------------------------------
+
+# 2008 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_LV
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9806 948983.8606 5201383.3118 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_LV
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.4273 948984.2970 5201383.6122 2020.5
+
+# 2020 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_LV
+tolerance 0.1 mm
+
+# BAUS
+accept 3226814.4746 1449250.4615 5289639.6134 2015.0
+expect 3226814.9950 1449250.1841 5289639.3779 2015.0
+
+
+# -------------------------------------------------------------------------------
+# LITHUANIA
+# -------------------------------------------------------------------------------
+
+# 2008 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_LT
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9358 948983.8042 5201383.2294 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_LT
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.3826 948984.2405 5201383.5299 2020.5
+
+# 2020 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_LT
+tolerance 0.1 mm
+
+# VLNS
+accept 3343600.4221 1580417.8797 5179337.3696 2015.0
+expect 3343600.9945 1580417.5661 5179337.1637 2015.0
+
+
+# -------------------------------------------------------------------------------
+# NORWAY
+# -------------------------------------------------------------------------------
+
+# 2008 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_NO
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9204 948983.8049 5201383.2054 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_NO
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.3671 948984.2412 5201383.5058 2020.5
+
+
+# -------------------------------------------------------------------------------
+# SWEDEN
+# -------------------------------------------------------------------------------
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2000_TO_SE
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.9223 948983.7912 5201383.2025 2020.5
+
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ETRF00_TO_SE
+tolerance 1 mm
+
+accept 3541657.3778 948984.2343 5201383.5231 2020.5
+expect 3541657.3690 948984.2275 5201383.5030 2020.5
+
+# 2020 Transformations
+
+operation operation urn:ogc:def:coordinateOperation:NKG::ITRF2014_TO_SE
+tolerance 0.1 mm
+
+# ARJ0
+accept 2441774.9791 799268.3078 5818729.4941 2015.0
+expect 2441775.4338 799268.0336 5818729.1635 2015.0
+
+# BOD3
+accept 2391774.0738 615615.1324 5860966.0796 2015.0
+expect 2391774.5409 615614.8770 5860965.8078 2015.0
+
+# KIR0
+accept 2248123.0276 865686.7906 5886425.8928 2015.0
+expect 2248123.5028 865686.5301 5886425.5928 2015.0
+
+</gie-strict>
diff --git a/test/gie/peirce_q.gie b/test/gie/peirce_q.gie
index 3706e15a..6e3e5aa8 100644
--- a/test/gie/peirce_q.gie
+++ b/test/gie/peirce_q.gie
@@ -9,10 +9,10 @@ operation +proj=peirce_q +R=6370997
tolerance 1 mm
------------------------------------------------------------
accept -179.6126302052 -90.2440064745
-expect failure errno lat_or_lon_exceed_limit
+expect failure errno coord_transfm_invalid_coord
accept -169.8486692749 -89.5742075028
-expect failure errno tolerance_condition
+expect failure errno coord_transfm_outside_projection_domain
accept 0.8029310185 0.0770204080
expect 126271.599 -11800190.331
@@ -1026,159 +1026,159 @@ accept 30.5303411995 89.7622494101
expect 13429.693 -22771.512
accept 40.0593735791 90.6542378643
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.0020623503 91.1469954761
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.8522213793 91.6903429214
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.7535252886 92.4836618501
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.1051275124 92.9389937571
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.4124853570 93.5341249190
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.7024119502 93.5550590372
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.8115837786 93.7909664255
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.6013207533 93.8492870154
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.7349056594 94.3767135242
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.9588399299 94.8671896725
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.0262851842 95.3534968784
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.4280397748 95.5380581127
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.7651411492 95.6370520364
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.0448345846 96.2732937318
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -179.8257499571 89.6174371357
expect -129.372 42538.994
accept -169.2875892301 90.5843674190
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -159.8023916584 91.1545744228
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -149.1639625275 92.0870993705
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -139.8013904331 92.8786158281
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -129.1637359401 92.9919538772
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -119.8393027005 93.1739711428
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -109.3406602631 94.1639584700
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -99.0695417625 95.1551429476
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -89.0610247556 95.6178466298
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -79.4516859556 96.0205106534
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -69.8082104896 96.1879870093
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -59.8296737152 96.7698954045
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -49.8769972300 97.2097042960
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -39.9274760034 97.5295561660
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -29.8470989427 97.6781116960
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -19.4625703588 98.0419802761
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept -9.0210837473 98.0868081244
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 0.9799321756 98.5464017880
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 10.0429624590 98.7459055217
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 20.2792585617 99.0223555196
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 30.0602725080 100.0053623620
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 40.2383571525 100.9390147017
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 50.7977119707 101.0770157329
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 60.1464549470 101.4743886273
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 70.3854313326 101.6912083253
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 80.4259639014 102.1177916319
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 90.8059360471 102.5951916979
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 100.0616865688 102.7748252495
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 110.4583416539 103.6248728355
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 120.9751205255 103.7983620507
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 130.7919815186 104.0148850515
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 140.6325380833 104.1792511999
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 150.5737064232 105.0050682525
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 160.8571448065 105.0125232729
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 170.6832502669 105.0174505020
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
accept 180.7137917600 105.8174218935
-expect failure errno -14
+expect failure errno coord_transfm_invalid_coord
</gie-strict>
diff --git a/test/gie/tinshift.gie b/test/gie/tinshift.gie
index dff62693..f16c16bb 100644
--- a/test/gie/tinshift.gie
+++ b/test/gie/tinshift.gie
@@ -8,15 +8,15 @@ Test +proj=tinshift
# Missing +file
operation +proj=tinshift
-expect failure errno no_args
+expect failure errno invalid_op_missing_arg
# +file doesn't point to an existing file
operation +proj=tinshift +file=i_do_not_exist
-expect failure errno invalid_arg
+expect failure errno invalid_op_file_not_found_or_invalid
# Not a JSON file
operation +proj=tinshift +file=proj.ini
-expect failure errno invalid_arg
+expect failure errno invalid_op_file_not_found_or_invalid
# Tests on a file without explicit CRS
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 3924f47d..7c4c124a 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -121,6 +121,7 @@ add_executable(proj_test_cpp_api
test_metadata.cpp
test_io.cpp
test_operation.cpp
+ test_operationfactory.cpp
test_datum.cpp
test_factory.cpp
test_c_api.cpp
diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am
index 4e931c2b..b073fcf2 100644
--- a/test/unit/Makefile.am
+++ b/test/unit/Makefile.am
@@ -45,7 +45,18 @@ proj_context_test_LDADD = ../../src/libproj.la @GTEST_LIBS@
proj_context_test-check: proj_context_test
PROJ_SKIP_READ_USER_WRITABLE_DIRECTORY=YES ./proj_context_test
-test_cpp_api_SOURCES = test_util.cpp test_common.cpp test_crs.cpp test_metadata.cpp test_io.cpp test_operation.cpp test_datum.cpp test_factory.cpp test_c_api.cpp test_grids.cpp main.cpp
+test_cpp_api_SOURCES = test_util.cpp \
+ test_common.cpp \
+ test_crs.cpp \
+ test_metadata.cpp \
+ test_io.cpp \
+ test_operation.cpp \
+ test_operationfactory.cpp \
+ test_datum.cpp \
+ test_factory.cpp \
+ test_c_api.cpp \
+ test_grids.cpp \
+ main.cpp
test_cpp_api_LDADD = ../../src/libproj.la @GTEST_LIBS@ @SQLITE3_LIBS@
test_cpp_api-check: test_cpp_api
diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp
index f9252137..4244766e 100644
--- a/test/unit/gie_self_tests.cpp
+++ b/test/unit/gie_self_tests.cpp
@@ -46,9 +46,8 @@ TEST(gie, cart_selftest) {
PJ_CONTEXT *ctx;
PJ *P;
PJ_COORD a, b, obs[2];
- PJ_COORD coord[2];
+ PJ_COORD coord[3];
- int err;
size_t n, sz;
double dist, h, t;
const char *const args[3] = {"proj=utm", "zone=32", "ellps=GRS80"};
@@ -89,16 +88,6 @@ TEST(gie, cart_selftest) {
/* Clear any previous error */
proj_errno_reset(P);
- /* Invalid projection */
- a = proj_trans(P, static_cast<PJ_DIRECTION>(42), a);
- ASSERT_EQ(a.lpz.lam, HUGE_VAL);
-
- err = proj_errno(P);
- ASSERT_NE(err, 0);
-
- /* Clear error again */
- proj_errno_reset(P);
-
/* Clean up */
proj_destroy(P);
@@ -211,7 +200,7 @@ TEST(gie, cart_selftest) {
coord[0] = proj_coord(proj_torad(12), proj_torad(55), 45, 0);
coord[1] = proj_coord(proj_torad(12), proj_torad(56), 50, 0);
- ASSERT_FALSE(proj_trans_array(P, PJ_FWD, 2, coord));
+ ASSERT_EQ(proj_trans_array(P, PJ_FWD, 2, coord), 0);
ASSERT_EQ(a.lpz.lam, coord[0].lpz.lam);
ASSERT_EQ(a.lpz.phi, coord[0].lpz.phi);
@@ -220,6 +209,35 @@ TEST(gie, cart_selftest) {
ASSERT_EQ(b.lpz.phi, coord[1].lpz.phi);
ASSERT_EQ(b.lpz.z, coord[1].lpz.z);
+ /* test proj_trans_array () with two failed points for the same reason */
+
+ coord[0] =
+ proj_coord(proj_torad(12), proj_torad(95), 45, 0); // invalid latitude
+ coord[1] = proj_coord(proj_torad(12), proj_torad(56), 50, 0);
+ coord[2] =
+ proj_coord(proj_torad(12), proj_torad(95), 45, 0); // invalid latitude
+ ASSERT_EQ(proj_trans_array(P, PJ_FWD, 3, coord),
+ PROJ_ERR_COORD_TRANSFM_INVALID_COORD);
+
+ ASSERT_EQ(HUGE_VAL, coord[0].lpz.lam);
+ ASSERT_EQ(HUGE_VAL, coord[0].lpz.phi);
+ ASSERT_EQ(HUGE_VAL, coord[0].lpz.z);
+ ASSERT_EQ(b.lpz.lam, coord[1].lpz.lam);
+ ASSERT_EQ(b.lpz.phi, coord[1].lpz.phi);
+ ASSERT_EQ(b.lpz.z, coord[1].lpz.z);
+ ASSERT_EQ(HUGE_VAL, coord[2].lpz.lam);
+ ASSERT_EQ(HUGE_VAL, coord[2].lpz.phi);
+ ASSERT_EQ(HUGE_VAL, coord[2].lpz.z);
+
+ /* test proj_trans_array () with two failed points for different reasons */
+
+ coord[0] =
+ proj_coord(proj_torad(12), proj_torad(95), 45, 0); // invalid latitude
+ coord[1] =
+ proj_coord(proj_torad(105), proj_torad(0), 45,
+ 0); // in the equatorial axis, at 90° of the central meridian
+ ASSERT_EQ(proj_trans_array(P, PJ_FWD, 2, coord), PROJ_ERR_COORD_TRANSFM);
+
/* Clean up after proj_trans_* tests */
proj_destroy(P);
}
diff --git a/test/unit/proj_errno_string_test.cpp b/test/unit/proj_errno_string_test.cpp
index a592b31f..d58c5e3f 100644
--- a/test/unit/proj_errno_string_test.cpp
+++ b/test/unit/proj_errno_string_test.cpp
@@ -35,37 +35,26 @@
namespace {
-TEST(ProjErrnoStringTest, NoError) { EXPECT_EQ(0, proj_errno_string(0)); }
+TEST(ProjErrnoStringTest, NoError) { EXPECT_EQ(nullptr, proj_errno_string(0)); }
TEST(ProjErrnoStringTest, ProjErrnos) {
- EXPECT_STREQ("no arguments in initialization list", proj_errno_string(-1));
- EXPECT_STREQ("invalid projection system error (-1000)",
- proj_errno_string(-1000));
- EXPECT_STREQ("invalid projection system error (-9999)",
- proj_errno_string(-9999));
- // for errnos < -9999, -9999 is always returned
- const int min = std::numeric_limits<int>::min();
- EXPECT_STREQ("invalid projection system error (-9999)",
- proj_errno_string(min));
- EXPECT_STREQ("invalid projection system error (-9999)",
- proj_errno_string(-10000));
+ EXPECT_STREQ("Unknown error (code -1)", proj_errno_string(-1));
+ EXPECT_STREQ("Invalid PROJ string syntax",
+ proj_errno_string(PROJ_ERR_INVALID_OP_WRONG_SYNTAX));
+ EXPECT_STREQ(
+ "Unspecified error related to coordinate operation initialization",
+ proj_errno_string(PROJ_ERR_INVALID_OP));
+ EXPECT_STREQ("Unspecified error related to coordinate transformation",
+ proj_errno_string(PROJ_ERR_COORD_TRANSFM));
}
-TEST(ProjErrnoStringTest, SystemErrnos) {
- const int max = std::numeric_limits<int>::max();
-
-#ifdef HAVE_STRERROR
- EXPECT_STREQ(strerror(5), proj_errno_string(5));
- EXPECT_STREQ(strerror(9999), proj_errno_string(9999));
- EXPECT_STREQ(strerror(10000), proj_errno_string(10000));
- EXPECT_STREQ(strerror(max), proj_errno_string(max));
-#else
- EXPECT_STREQ("no system list, errno: 5\n", proj_errno_string(5));
- EXPECT_STREQ("no system list, errno: 9999\n", proj_errno_string(9999));
- // for errnos > 9999, 9999 is always returned
- EXPECT_STREQ("no system list, errno: 9999\n", proj_errno_string(10000));
- EXPECT_STREQ("no system list, errno: 9999\n", proj_errno_string(max));
-#endif
+TEST(ProjErrnoStringTest, proj_context_errno_string) {
+ EXPECT_STREQ("Unknown error (code -1)",
+ proj_context_errno_string(nullptr, -1));
+ PJ_CONTEXT *ctx = proj_context_create();
+ EXPECT_STREQ("Unknown error (code -999)",
+ proj_context_errno_string(ctx, -999));
+ proj_context_destroy(ctx);
}
} // namespace
diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp
index c417371d..d43d68ce 100644
--- a/test/unit/test_c_api.cpp
+++ b/test/unit/test_c_api.cpp
@@ -1183,10 +1183,12 @@ TEST_F(CApi, proj_get_authorities_from_database) {
ASSERT_TRUE(list[2] != nullptr);
EXPECT_EQ(list[2], std::string("IGNF"));
ASSERT_TRUE(list[3] != nullptr);
- EXPECT_EQ(list[3], std::string("OGC"));
+ EXPECT_EQ(list[3], std::string("NKG"));
ASSERT_TRUE(list[4] != nullptr);
- EXPECT_EQ(list[4], std::string("PROJ"));
- EXPECT_EQ(list[5], nullptr);
+ EXPECT_EQ(list[4], std::string("OGC"));
+ ASSERT_TRUE(list[5] != nullptr);
+ EXPECT_EQ(list[5], std::string("PROJ"));
+ EXPECT_EQ(list[6], nullptr);
}
// ---------------------------------------------------------------------------
@@ -4196,6 +4198,64 @@ TEST_F(CApi, proj_create_crs_to_crs_from_pj) {
// ---------------------------------------------------------------------------
+TEST_F(CApi, proj_create_crs_to_crs_from_pj_accuracy_filter) {
+
+ auto src = proj_create(m_ctxt, "EPSG:4326"); // WGS 84
+ ObjectKeeper keeper_src(src);
+ ASSERT_NE(src, nullptr);
+
+ auto dst = proj_create(m_ctxt, "EPSG:4258"); // ETRS89
+ ObjectKeeper keeper_dst(dst);
+ ASSERT_NE(dst, nullptr);
+
+ // No options
+ {
+ auto P =
+ proj_create_crs_to_crs_from_pj(m_ctxt, src, dst, nullptr, nullptr);
+ ObjectKeeper keeper_P(P);
+ ASSERT_NE(P, nullptr);
+ }
+
+ {
+ const char *const options[] = {"ACCURACY=0.05", nullptr};
+ auto P =
+ proj_create_crs_to_crs_from_pj(m_ctxt, src, dst, nullptr, options);
+ ObjectKeeper keeper_P(P);
+ ASSERT_EQ(P, nullptr);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST_F(CApi, proj_create_crs_to_crs_from_pj_ballpark_filter) {
+
+ auto src = proj_create(m_ctxt, "EPSG:4267"); // NAD 27
+ ObjectKeeper keeper_src(src);
+ ASSERT_NE(src, nullptr);
+
+ auto dst = proj_create(m_ctxt, "EPSG:4258"); // ETRS89
+ ObjectKeeper keeper_dst(dst);
+ ASSERT_NE(dst, nullptr);
+
+ // No options
+ {
+ auto P =
+ proj_create_crs_to_crs_from_pj(m_ctxt, src, dst, nullptr, nullptr);
+ ObjectKeeper keeper_P(P);
+ ASSERT_NE(P, nullptr);
+ }
+
+ {
+ const char *const options[] = {"ALLOW_BALLPARK=NO", nullptr};
+ auto P =
+ proj_create_crs_to_crs_from_pj(m_ctxt, src, dst, nullptr, options);
+ ObjectKeeper keeper_P(P);
+ ASSERT_EQ(P, nullptr);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
static void
check_axis_is_latitude(PJ_CONTEXT *ctx, PJ *cs, int axis_number,
const char *unit_name = "degree",
diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp
index ff86c4d3..7f474dcf 100644
--- a/test/unit/test_factory.cpp
+++ b/test/unit/test_factory.cpp
@@ -2806,6 +2806,7 @@ TEST(factory, attachExtraDatabases_none) {
auto factory = AuthorityFactory::create(ctxt, "EPSG");
auto crs = factory->createGeodeticCRS("4979");
auto gcrs = nn_dynamic_pointer_cast<GeographicCRS>(crs);
+ EXPECT_TRUE(gcrs != nullptr);
}
// ---------------------------------------------------------------------------
@@ -2877,12 +2878,14 @@ TEST(factory, attachExtraDatabases_auxiliary) {
auto factory = AuthorityFactory::create(ctxt, "EPSG");
auto crs = factory->createGeodeticCRS("4326");
auto gcrs = nn_dynamic_pointer_cast<GeographicCRS>(crs);
+ EXPECT_TRUE(gcrs != nullptr);
}
// Look for object located in auxiliary DB
{
auto factory = AuthorityFactory::create(ctxt, "OTHER");
auto crs = factory->createGeodeticCRS("OTHER_4326");
auto gcrs = nn_dynamic_pointer_cast<GeographicCRS>(crs);
+ EXPECT_TRUE(gcrs != nullptr);
}
}
@@ -2894,12 +2897,14 @@ TEST(factory, attachExtraDatabases_auxiliary) {
auto factory = AuthorityFactory::create(ctxt, "EPSG");
auto crs = factory->createGeodeticCRS("4326");
auto gcrs = nn_dynamic_pointer_cast<GeographicCRS>(crs);
+ EXPECT_TRUE(gcrs != nullptr);
}
// Look for object located in auxiliary DB
{
auto factory = AuthorityFactory::create(ctxt, "OTHER");
auto crs = factory->createGeodeticCRS("OTHER_4326");
auto gcrs = nn_dynamic_pointer_cast<GeographicCRS>(crs);
+ EXPECT_TRUE(gcrs != nullptr);
}
}
@@ -2910,6 +2915,7 @@ TEST(factory, attachExtraDatabases_auxiliary) {
auto factory = AuthorityFactory::create(ctxt, "EPSG");
auto crs = factory->createGeodeticCRS("4326");
auto gcrs = nn_dynamic_pointer_cast<GeographicCRS>(crs);
+ EXPECT_TRUE(gcrs != nullptr);
}
// Look for object located in auxiliary DB
{
diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp
index d0085004..422ab97d 100644
--- a/test/unit/test_operation.cpp
+++ b/test/unit/test_operation.cpp
@@ -28,8 +28,6 @@
#include "gtest_include.h"
-#include "test_primitives.hpp"
-
// to be able to use internal::replaceAll
#ifndef FROM_PROJ_CPP
#define FROM_PROJ_CPP
@@ -4285,5819 +4283,6 @@ TEST(operation, PROJ_based_with_global_parameters) {
// ---------------------------------------------------------------------------
-TEST(operation, geogCRS_to_geogCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(
- op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv +proj=longlat "
- "+ellps=clrk80ign +pm=paris +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_default) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setAllowUseIntermediateCRS(
- CoordinateOperationContext::IntermediateCRSUse::NEVER);
-
- // Directly found in database
- {
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4179"), // Pulkovo 42
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
- ctxt);
- ASSERT_EQ(list.size(), 3U);
- // Romania has a larger area than Poland (given our approx formula)
- EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m
- EXPECT_EQ(list[1]->getEPSGCode(), 1644); // Poland - 1m
- EXPECT_EQ(list[2]->nameStr(),
- "Ballpark geographic offset from Pulkovo 1942(58) to ETRS89");
-
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
- "+step +proj=cart +ellps=krass +step +proj=helmert +x=2.3287 "
- "+y=-147.0425 +z=-92.0802 +rx=0.3092483 +ry=-0.32482185 "
- "+rz=-0.49729934 +s=5.68906266 +convention=coordinate_frame +step "
- "+inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
- }
-
- // Reverse case
- {
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4258"),
- authFactory->createCoordinateReferenceSystem("4179"), ctxt);
- ASSERT_EQ(list.size(), 3U);
- // Romania has a larger area than Poland (given our approx formula)
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of Pulkovo 1942(58) to ETRS89 (4)"); // Romania - 3m
-
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
- "+step +proj=cart +ellps=GRS80 +step +inv +proj=helmert +x=2.3287 "
- "+y=-147.0425 +z=-92.0802 +rx=0.3092483 +ry=-0.32482185 "
- "+rz=-0.49729934 +s=5.68906266 +convention=coordinate_frame +step "
- "+inv +proj=cart +ellps=krass +step +proj=pop +v_3 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_match_by_name) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setAllowUseIntermediateCRS(
- CoordinateOperationContext::IntermediateCRSUse::NEVER);
- auto NAD27 = GeographicCRS::create(
- PropertyMap().set(IdentifiedObject::NAME_KEY,
- GeographicCRS::EPSG_4267->nameStr()),
- GeographicCRS::EPSG_4267->datum(),
- GeographicCRS::EPSG_4267->datumEnsemble(),
- GeographicCRS::EPSG_4267->coordinateSystem());
- auto list = CoordinateOperationFactory::create()->createOperations(
- NAD27, GeographicCRS::EPSG_4326, ctxt);
- auto listInv = CoordinateOperationFactory::create()->createOperations(
- GeographicCRS::EPSG_4326, NAD27, ctxt);
- auto listRef = CoordinateOperationFactory::create()->createOperations(
- GeographicCRS::EPSG_4267, GeographicCRS::EPSG_4326, ctxt);
- EXPECT_EQ(list.size(), listRef.size());
- EXPECT_EQ(listInv.size(), listRef.size());
- EXPECT_GE(listRef.size(), 2U);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_filter_accuracy) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 1.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4179"),
- authFactory->createCoordinateReferenceSystem("4258"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->getEPSGCode(), 1644); // Poland - 1m
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.9);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4179"),
- authFactory->createCoordinateReferenceSystem("4258"), ctxt);
- ASSERT_EQ(list.size(), 0U);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_filter_bbox) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- // INSERT INTO "area" VALUES('EPSG','1197','Romania','Romania - onshore and
- // offshore.',43.44,48.27,20.26,31.41,0);
- {
- auto ctxt = CoordinateOperationContext::create(
- authFactory, Extent::createFromBBOX(20.26, 43.44, 31.41, 48.27),
- 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4179"),
- authFactory->createCoordinateReferenceSystem("4258"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m
- }
- {
- auto ctxt = CoordinateOperationContext::create(
- authFactory, Extent::createFromBBOX(20.26 + .1, 43.44 + .1,
- 31.41 - .1, 48.27 - .1),
- 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4179"),
- authFactory->createCoordinateReferenceSystem("4258"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m
- }
- {
- auto ctxt = CoordinateOperationContext::create(
- authFactory, Extent::createFromBBOX(20.26 - .1, 43.44 - .1,
- 31.41 + .1, 48.27 + .1),
- 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4179"),
- authFactory->createCoordinateReferenceSystem("4258"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_incompatible_area) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4267"), // NAD27
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS 89
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_inverse_needed) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setUsePROJAlternativeGridNames(false);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4275"), // NTF
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 "
- "+y=-60 +z=320 +step +inv +proj=cart +ellps=GRS80 +step +proj=pop "
- "+v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step "
- "+proj=axisswap +order=2,1");
- EXPECT_EQ(list[1]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step "
- "+proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
- "+proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4275"), // NTF
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step "
- "+proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
- "+proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
- authFactory->createCoordinateReferenceSystem("4275"), // NTF
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv "
- "+proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
- "+proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_ntv1_ntv2_ctable2) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4267"), // NAD27
- authFactory->createCoordinateReferenceSystem("4269"), // NAD83
- ctxt);
- ASSERT_EQ(list.size(), 10U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
- "+grids=ca_nrc_ntv1_can.tif +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
- "+grids=ca_nrc_ntv2_0.tif +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(list[2]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
- "+grids=us_noaa_conus.tif +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_NAD27_to_WGS84) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4267"), // NAD27
- authFactory->createCoordinateReferenceSystem("4326"), // WGS84
- ctxt);
- ASSERT_EQ(list.size(), 79U);
- EXPECT_EQ(list[0]->nameStr(),
- "NAD27 to WGS 84 (33)"); // 1.0 m, Canada - NAD27
- EXPECT_EQ(list[1]->nameStr(),
- "NAD27 to WGS 84 (3)"); // 20.0 m, Canada - NAD27
- EXPECT_EQ(list[2]->nameStr(),
- "NAD27 to WGS 84 (79)"); // 5.0 m, USA - CONUS including EEZ
- EXPECT_EQ(list[3]->nameStr(),
- "NAD27 to WGS 84 (4)"); // 10.0 m, USA - CONUS - onshore
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_NAD27_to_WGS84_G1762) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
-
- auto authFactoryEPSG =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NAD27
- authFactoryEPSG->createCoordinateReferenceSystem("4267"),
- // WGS84 (G1762)
- authFactoryEPSG->createCoordinateReferenceSystem("9057"), ctxt);
- ASSERT_GE(list.size(), 78U);
- EXPECT_EQ(list[0]->nameStr(),
- "NAD27 to WGS 84 (33) + WGS 84 to WGS 84 (G1762)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=ca_nrc_ntv2_0.tif "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- EXPECT_EQ(list[1]->nameStr(),
- "NAD27 to WGS 84 (3) + WGS 84 to WGS 84 (G1762)");
- EXPECT_EQ(list[2]->nameStr(),
- "NAD27 to WGS 84 (79) + WGS 84 to WGS 84 (G1762)");
- EXPECT_EQ(list[3]->nameStr(),
- "NAD27 to WGS 84 (4) + WGS 84 to WGS 84 (G1762)");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_WGS84_G1674_to_WGS84_G1762) {
- // Check that particular behavior with WGS 84 (Gxxx) related to
- // 'geodetic_datum_preferred_hub' table and custom no-op transformations
- // between WGS 84 and WGS 84 (Gxxx) doesn't affect direct transformations
- // to those realizations.
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
-
- auto authFactoryEPSG =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto list = CoordinateOperationFactory::create()->createOperations(
- // WGS84 (G1674)
- authFactoryEPSG->createCoordinateReferenceSystem("9056"),
- // WGS84 (G1762)
- authFactoryEPSG->createCoordinateReferenceSystem("9057"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=-0.004 +y=0.003 +z=0.004 +rx=0.00027 "
- "+ry=-0.00027 +rz=0.00038 +s=-0.0069 "
- "+convention=coordinate_frame "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_EPSG_4240_Indian1975_to_EPSG_4326) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4240"), // Indian 1975
- authFactory->createCoordinateReferenceSystem("4326"), ctxt);
- ASSERT_EQ(list.size(), 3U);
-
- // Indian 1975 to WGS 84 (4), 3.0 m, Thailand - onshore
- EXPECT_EQ(list[0]->getEPSGCode(), 1812);
-
- // The following is the one we want to see. It has a lesser accuracy than
- // the above one and the same bbox, but the name of its area of use is
- // slightly different
- // Indian 1975 to WGS 84 (2), 5.0 m, Thailand - onshore and Gulf of Thailand
- EXPECT_EQ(list[1]->getEPSGCode(), 1304);
-
- // Indian 1975 to WGS 84 (3), 1.0 m, Thailand - Bongkot field
- EXPECT_EQ(list[2]->getEPSGCode(), 1537);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_helmert_geog3D_crs) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4939"), // GDA94 3D
- authFactory->createCoordinateReferenceSystem("7843"), // GDA2020 3D
- ctxt);
- ASSERT_EQ(list.size(), 1U);
-
- // Check there is no push / pop of v_3
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
- "+step +proj=cart +ellps=GRS80 "
- "+step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
- "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
- "+convention=coordinate_frame "
- "+step +inv +proj=cart +ellps=GRS80 "
- "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_helmert_geocentric_3D) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- // GDA94 geocentric
- authFactory->createCoordinateReferenceSystem("4348"),
- // GDA2020 geocentric
- authFactory->createCoordinateReferenceSystem("7842"), ctxt);
- ASSERT_EQ(list.size(), 1U);
-
- // Check there is no push / pop of v_3
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
- "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
- "+convention=coordinate_frame");
- EXPECT_EQ(list[0]->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
- "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
- "+convention=coordinate_frame");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_helmert_geog3D_to_geocentirc) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- // GDA94 3D
- authFactory->createCoordinateReferenceSystem("4939"),
- // GDA2020 geocentric
- authFactory->createCoordinateReferenceSystem("7842"), ctxt);
- ASSERT_EQ(list.size(), 1U);
-
- // Check there is no push / pop of v_3
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
- "+step +proj=cart +ellps=GRS80 "
- "+step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
- "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
- "+convention=coordinate_frame");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_invalid_EPSG_ID) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
- // EPSG:4656 is incorrect. Should be EPSG:8997
- auto obj = WKTParser().createFromWKT(
- "GEOGCS[\"ITRF2000\","
- "DATUM[\"International_Terrestrial_Reference_Frame_2000\","
- "SPHEROID[\"GRS 1980\",6378137,298.257222101,"
- "AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6656\"]],"
- "PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.0174532925199433],"
- "AUTHORITY[\"EPSG\",\"4656\"]]");
- auto crs = nn_dynamic_pointer_cast<GeographicCRS>(obj);
- ASSERT_TRUE(crs != nullptr);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(crs), GeographicCRS::EPSG_4326, ctxt);
- ASSERT_EQ(list.size(), 1U);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_datum_ensemble) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
-
- auto dst_wkt =
- "GEOGCRS[\"unknown\","
- " ENSEMBLE[\"World Geodetic System 1984 ensemble\","
- " MEMBER[\"World Geodetic System 1984 (Transit)\","
- " ID[\"EPSG\",1166]],"
- " MEMBER[\"World Geodetic System 1984 (G730)\","
- " ID[\"EPSG\",1152]],"
- " MEMBER[\"World Geodetic System 1984 (G873)\","
- " ID[\"EPSG\",1153]],"
- " MEMBER[\"World Geodetic System 1984 (G1150)\","
- " ID[\"EPSG\",1154]],"
- " MEMBER[\"World Geodetic System 1984 (G1674)\","
- " ID[\"EPSG\",1155]],"
- " MEMBER[\"World Geodetic System 1984 (G1762)\","
- " ID[\"EPSG\",1156]],"
- " ELLIPSOID[\"WGS 84\",6378137,298.257223563,"
- " LENGTHUNIT[\"metre\",1,ID[\"EPSG\",9001]],"
- " ID[\"EPSG\",7030]],"
- " ENSEMBLEACCURACY[2]],"
- " PRIMEM[\"Greenwich\",0,"
- " ANGLEUNIT[\"degree\",0.0174532925199433,ID[\"EPSG\",9102]],"
- " ID[\"EPSG\",8901]],"
- " CS[ellipsoidal,2,"
- " ID[\"EPSG\",6422]],"
- " AXIS[\"Geodetic latitude (Lat)\",north,"
- " ORDER[1]],"
- " AXIS[\"Geodetic longitude (Lon)\",east,"
- " ORDER[2]],"
- " ANGLEUNIT[\"degree (supplier to define representation)\","
- "0.0174532925199433,ID[\"EPSG\",9122]]]";
- auto dstObj = WKTParser().createFromWKT(dst_wkt);
- auto dstCRS = nn_dynamic_pointer_cast<CRS>(dstObj);
- ASSERT_TRUE(dstCRS != nullptr);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
- NN_NO_CHECK(dstCRS), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "ETRS89 to WGS 84 (1)");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, vertCRS_to_geogCRS_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setUsePROJAlternativeGridNames(false);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem(
- "3855"), // EGM2008 height
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- ctxt);
- ASSERT_EQ(list.size(), 3U);
- EXPECT_EQ(
- list[1]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem(
- "3855"), // EGM2008 height
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- ctxt);
- ASSERT_EQ(list.size(), 3U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- authFactory->createCoordinateReferenceSystem(
- "3855"), // EGM2008 height
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +inv +proj=vgridshift +grids=us_nga_egm08_25.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NGVD29 depth (ftUS)
- authFactory->createCoordinateReferenceSystem("6359"),
- authFactory->createCoordinateReferenceSystem("4326"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=affine +s33=-0.304800609601219");
- }
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NZVD2016 height
- authFactory->createCoordinateReferenceSystem("7839"),
- // NZGD2000
- authFactory->createCoordinateReferenceSystem("4959"), ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=nz_linz_nzgeoid2016.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
- {
- // Test actually the database where we derive records using the more
- // classic 'Geographic3D to GravityRelatedHeight' method from
- // records using EPSG:9635
- //'Geog3D to Geog2D+GravityRelatedHeight (US .gtx)' method
- auto ctxt = CoordinateOperationContext::create(
- AuthorityFactory::create(DatabaseContext::create(), std::string()),
- nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // Baltic 1957 height
- authFactory->createCoordinateReferenceSystem("8357"),
- // ETRS89
- authFactory->createCoordinateReferenceSystem("4937"), ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift "
- "+grids=sk_gku_Slovakia_ETRS89h_to_Baltic1957.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geog3DCRS_to_geog2DCRS_plus_vertCRS_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // ETRS89 (3D)
- authFactory->createCoordinateReferenceSystem("4937"),
- // ETRS89 + Baltic 1957 height
- authFactory->createCoordinateReferenceSystem("8360"), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +inv +proj=vgridshift "
- "+grids=sk_gku_Slovakia_ETRS89h_to_Baltic1957.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- EXPECT_EQ(list[0]->inverse()->nameStr(),
- "Inverse of 'ETRS89 to ETRS89 + Baltic 1957 height (1)'");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_noop) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(), "Null geographic offset from WGS 84 to WGS 84");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
- EXPECT_EQ(op->inverse()->nameStr(), op->nameStr());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_longitude_rotation) {
-
- auto src = GeographicCRS::create(
- PropertyMap().set(IdentifiedObject::NAME_KEY, "A"),
- GeodeticReferenceFrame::create(PropertyMap(), Ellipsoid::WGS84,
- optional<std::string>(),
- PrimeMeridian::GREENWICH),
- EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
- auto dest = GeographicCRS::create(
- PropertyMap().set(IdentifiedObject::NAME_KEY, "B"),
- GeodeticReferenceFrame::create(PropertyMap(), Ellipsoid::WGS84,
- optional<std::string>(),
- PrimeMeridian::PARIS),
- EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
-
- auto op = CoordinateOperationFactory::create()->createOperation(src, dest);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=longlat "
- "+ellps=WGS84 +pm=paris +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(op->inverse()->exportToWKT(WKTFormatter::create().get()),
- CoordinateOperationFactory::create()
- ->createOperation(dest, src)
- ->exportToWKT(WKTFormatter::create().get()));
- EXPECT_TRUE(
- op->inverse()->isEquivalentTo(CoordinateOperationFactory::create()
- ->createOperation(dest, src)
- .get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_longitude_rotation_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris)
- authFactory->createCoordinateReferenceSystem("4275"), // NTF
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(list[0]->nameStr(), "NTF (Paris) to NTF (1)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=paris +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
- EXPECT_EQ(list[1]->nameStr(), "NTF (Paris) to NTF (2)");
- EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=2.33720833333333 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_concatenated_operation) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setAllowUseIntermediateCRS(
- CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris)
- authFactory->createCoordinateReferenceSystem("4171"), // RGF93
- ctxt);
- ASSERT_EQ(list.size(), 4U);
-
- EXPECT_EQ(list[0]->nameStr(), "NTF (Paris) to RGF93 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
- "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign "
- "+step +proj=xyzgridshift +grids=fr_ign_gr3df97a.tif "
- "+grid_ref=output_crs +ellps=GRS80 "
- "+step +inv +proj=cart +ellps=GRS80 "
- "+step +proj=pop +v_3 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- EXPECT_EQ(list[1]->nameStr(), "NTF (Paris) to RGF93 (2)");
- EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=hgridshift "
- "+grids=fr_ign_ntf_r93.tif +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
-
- EXPECT_TRUE(nn_dynamic_pointer_cast<ConcatenatedOperation>(list[0]) !=
- nullptr);
- auto grids = list[0]->gridsNeeded(DatabaseContext::create(), false);
- EXPECT_EQ(grids.size(), 1U);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_ED50_to_WGS72_no_NTF_intermediate) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4230"), // ED50
- authFactory->createCoordinateReferenceSystem("4322"), // WGS 72
- ctxt);
- ASSERT_GE(list.size(), 2U);
- // We should not use the ancient NTF as an intermediate when looking for
- // ED50 -> WGS 72 operations.
- for (const auto &op : list) {
- EXPECT_TRUE(op->nameStr().find("NTF") == std::string::npos)
- << op->nameStr();
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_context_same_grid_name) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4314"), // DHDN
- authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
- ctxt);
- ASSERT_TRUE(!list.empty());
- EXPECT_EQ(list[0]->nameStr(), "DHDN to ETRS89 (8)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
- "+grids=de_adv_BETA2007.tif +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_geographic_offset_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4120"), // NTF(Paris)
- authFactory->createCoordinateReferenceSystem("4121"), // NTF
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "Greek to GGRS87 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=-5.86 +dlon=0.28 +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_CH1903_to_CH1903plus_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setAllowUseIntermediateCRS(
- CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4149"), // CH1903
- authFactory->createCoordinateReferenceSystem("4150"), // CH1903+
- ctxt);
- ASSERT_TRUE(list.size() == 1U);
-
- EXPECT_EQ(list[0]->nameStr(), "CH1903 to CH1903+ (1)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=ch_swisstopo_CHENyx06a.tif "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_init_IGNF_to_init_IGNF_context) {
-
- auto dbContext = DatabaseContext::create();
-
- auto sourceCRS_obj = PROJStringParser()
- .attachDatabaseContext(dbContext)
- .setUsePROJ4InitRules(true)
- .createFromPROJString("+init=IGNF:NTFG");
- auto sourceCRS = nn_dynamic_pointer_cast<CRS>(sourceCRS_obj);
- ASSERT_TRUE(sourceCRS != nullptr);
-
- auto targetCRS_obj = PROJStringParser()
- .attachDatabaseContext(dbContext)
- .setUsePROJ4InitRules(true)
- .createFromPROJString("+init=IGNF:RGF93G");
- auto targetCRS = nn_dynamic_pointer_cast<CRS>(targetCRS_obj);
- ASSERT_TRUE(targetCRS != nullptr);
-
- auto authFactory = AuthorityFactory::create(dbContext, std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_CHECK_ASSERT(sourceCRS), NN_CHECK_ASSERT(targetCRS), ctxt);
- ASSERT_EQ(list.size(), 2U);
-
- EXPECT_EQ(list[0]->nameStr(),
- "NOUVELLE TRIANGULATION DE LA FRANCE (NTF) vers RGF93 (ETRS89)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geogCRS_3D) {
-
- auto geogcrs_m_obj = PROJStringParser().createFromPROJString(
- "+proj=longlat +vunits=m +type=crs");
- auto geogcrs_m = nn_dynamic_pointer_cast<CRS>(geogcrs_m_obj);
- ASSERT_TRUE(geogcrs_m != nullptr);
-
- auto geogcrs_ft_obj = PROJStringParser().createFromPROJString(
- "+proj=longlat +vunits=ft +type=crs");
- auto geogcrs_ft = nn_dynamic_pointer_cast<CRS>(geogcrs_ft_obj);
- ASSERT_TRUE(geogcrs_ft != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(geogcrs_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=unitconvert +z_in=m +z_out=ft");
- }
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(geogcrs_ft), NN_CHECK_ASSERT(geogcrs_m));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=unitconvert +z_in=ft +z_out=m");
- }
-
- auto geogcrs_m_with_pm_obj = PROJStringParser().createFromPROJString(
- "+proj=longlat +pm=paris +vunits=m +type=crs");
- auto geogcrs_m_with_pm =
- nn_dynamic_pointer_cast<CRS>(geogcrs_m_with_pm_obj);
- ASSERT_TRUE(geogcrs_m_with_pm != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(geogcrs_m_with_pm), NN_CHECK_ASSERT(geogcrs_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +z_in=m "
- "+xy_out=rad +z_out=m +step +inv +proj=longlat +ellps=WGS84 "
- "+pm=paris +step +proj=unitconvert +xy_in=rad +z_in=m "
- "+xy_out=deg +z_out=ft");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_3D_lat_long_non_metre_to_geogCRS_longlat) {
-
- auto wkt = "GEOGCRS[\"my CRS\",\n"
- " DATUM[\"World Geodetic System 1984\",\n"
- " ELLIPSOID[\"WGS 84\",6378137,298.257223563],\n"
- " ID[\"EPSG\",6326]],\n"
- " CS[ellipsoidal,3],\n"
- " AXIS[\"latitude\",north,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"longitude\",east,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"ellipsoidal height\",up,\n"
- " LENGTHUNIT[\"my_vunit\",0.3]]]";
- auto srcCRS_obj = WKTParser().createFromWKT(wkt);
- auto srcCRS = nn_dynamic_pointer_cast<CRS>(srcCRS_obj);
- ASSERT_TRUE(srcCRS != nullptr);
-
- auto dstCRS_obj = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +type=crs");
- auto dstCRS = nn_dynamic_pointer_cast<CRS>(dstCRS_obj);
- ASSERT_TRUE(dstCRS != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(srcCRS), NN_CHECK_ASSERT(dstCRS));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +z_in=0.3 +z_out=m");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_without_id_to_geogCRS_3D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto src =
- authFactory->createCoordinateReferenceSystem("4289"); // Amersfoort
- auto dst =
- authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_GE(list.size(), 1U);
- auto wkt2 = "GEOGCRS[\"unnamed\",\n"
- " DATUM[\"Amersfoort\",\n"
- " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " CS[ellipsoidal,2],\n"
- " AXIS[\"geodetic latitude (Lat)\",north,\n"
- " ORDER[1],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"geodetic longitude (Lon)\",east,\n"
- " ORDER[2],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],"
- " USAGE[\n"
- " SCOPE[\"unknown\"],\n"
- " AREA[\"Netherlands - onshore\"],\n"
- " BBOX[50.75,3.2,53.7,7.22]]]\n";
-
- auto obj = WKTParser().createFromWKT(wkt2);
- auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
- ASSERT_TRUE(src_from_wkt2 != nullptr);
- auto list2 = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src_from_wkt2), dst, ctxt);
- ASSERT_GE(list.size(), list2.size());
- for (size_t i = 0; i < list.size(); i++) {
- const auto &op = list[i];
- const auto &op2 = list2[i];
- EXPECT_TRUE(
- op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT))
- << op->nameStr() << " " << op2->nameStr();
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geogCRS_same_datum) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createGeocentricDatumWGS84(), GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geogCRS_different_datum) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createGeocentricDatumWGS84(), GeographicCRS::EPSG_4269);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(),
- "Ballpark geocentric translation from WGS 84 to NAD83 "
- "(geocentric) + Conversion from NAD83 "
- "(geocentric) to NAD83");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=GRS80 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geocentricCRS_different_datum) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4269, createGeocentricDatumWGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(), "Conversion from NAD83 to NAD83 (geocentric) + "
- "Ballpark geocentric translation from NAD83 "
- "(geocentric) to WGS 84");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
- "+ellps=GRS80");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geocentricCRS_same_noop) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createGeocentricDatumWGS84(), createGeocentricDatumWGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(),
- "Null geocentric translation from WGS 84 to WGS 84");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
- EXPECT_EQ(op->inverse()->nameStr(), op->nameStr());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geocentricCRS_different_ballpark) {
-
- PropertyMap propertiesCRS;
- propertiesCRS.set(Identifier::CODESPACE_KEY, "EPSG")
- .set(Identifier::CODE_KEY, 4328)
- .set(IdentifiedObject::NAME_KEY, "unknown");
- auto otherGeocentricCRS = GeodeticCRS::create(
- propertiesCRS, GeodeticReferenceFrame::EPSG_6269,
- CartesianCS::createGeocentric(UnitOfMeasure::METRE));
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createGeocentricKM(), otherGeocentricCRS);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(
- op->nameStr(),
- "Ballpark geocentric translation from Based on WGS 84 to unknown");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=unitconvert +xy_in=km +z_in=km +xy_out=m +z_out=m");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geogCRS_same_datum_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4326"),
- // WGS84 geocentric
- authFactory->createCoordinateReferenceSystem("4978"), ctxt);
- ASSERT_EQ(list.size(), 1U);
-
- EXPECT_EQ(list[0]->nameStr(),
- "Conversion from WGS 84 (geog2D) to WGS 84 (geocentric)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
- "+ellps=WGS84");
-
- EXPECT_EQ(list[0]->inverse()->nameStr(),
- "Conversion from WGS 84 (geocentric) to WGS 84 (geog2D)");
- EXPECT_EQ(list[0]->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geogCRS_same_datum_context_all_auth) {
- // This is to check we don't use OGC:CRS84 as a pivot
- auto authFactoryEPSG =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto authFactoryAll =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt =
- CoordinateOperationContext::create(authFactoryAll, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactoryEPSG->createCoordinateReferenceSystem("4326"),
- // WGS84 geocentric
- authFactoryEPSG->createCoordinateReferenceSystem("4978"), ctxt);
- ASSERT_EQ(list.size(), 1U);
-
- EXPECT_EQ(list[0]->nameStr(),
- "Conversion from WGS 84 (geog2D) to WGS 84 (geocentric)");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geocentricCRS_different_datum_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // ITRF2000 (geocentric)
- authFactory->createCoordinateReferenceSystem("4919"),
- // ITRF2005 (geocentric)
- authFactory->createCoordinateReferenceSystem("4896"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "ITRF2000 to ITRF2005 (1)");
- EXPECT_PRED_FORMAT2(
- ComparePROJString,
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=helmert +x=-0.0001 "
- "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
- "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
- "+t_epoch=2000 +convention=position_vector");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_geocentricCRS_same_datum_to_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // WGS84 geocentric
- authFactory->createCoordinateReferenceSystem("4978"),
- authFactory->createCoordinateReferenceSystem("4326"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "Conversion from WGS 84 (geocentric) to WGS 84 (geog2D)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- geog2D_to_geog3D_same_datum_but_with_potential_other_pivot_context) {
- // Check that when going from geog2D to geog3D of same datum, we don't
- // try to go through a WGS84 pivot...
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("5365"), // CR 05 2D
- authFactory->createCoordinateReferenceSystem("5364"), // CR 05 3D
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- geogCRS_to_geogCRS_different_datum_though_geocentric_transform_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // ITRF2000 (geog3D)
- authFactory->createCoordinateReferenceSystem("7909"),
- // ITRF2005 (geog3D)
- authFactory->createCoordinateReferenceSystem("7910"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "Conversion from ITRF2000 (geog3D) to ITRF2000 (geocentric) + "
- "ITRF2000 to ITRF2005 (1) + "
- "Conversion from ITRF2005 (geocentric) to ITRF2005 (geog3D)");
- EXPECT_PRED_FORMAT2(
- ComparePROJString,
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
- "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=-0.0001 "
- "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
- "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
- "+t_epoch=2000 +convention=position_vector +step +inv "
- "+proj=cart +ellps=GRS80 +step +proj=unitconvert +xy_in=rad "
- "+z_in=m +xy_out=deg +z_out=m +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_geocentricCRS_different_datum_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // ITRF2000 (geog3D)
- authFactory->createCoordinateReferenceSystem("7909"),
- // ITRF2005 (geocentric)
- authFactory->createCoordinateReferenceSystem("4896"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "Conversion from ITRF2000 (geog3D) to ITRF2000 (geocentric) + "
- "ITRF2000 to ITRF2005 (1)");
- EXPECT_PRED_FORMAT2(
- ComparePROJString,
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
- "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=-0.0001 "
- "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
- "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
- "+t_epoch=2000 +convention=position_vector");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_geogCRS_different_datum_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // ITRF2000 (geocentric)
- authFactory->createCoordinateReferenceSystem("4919"),
- // ITRF2005 (geog3D)
- authFactory->createCoordinateReferenceSystem("7910"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "ITRF2000 to ITRF2005 (1) + "
- "Conversion from ITRF2005 (geocentric) to ITRF2005 (geog3D)");
- EXPECT_PRED_FORMAT2(
- ComparePROJString,
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=helmert +x=-0.0001 "
- "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
- "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
- "+t_epoch=2000 +convention=position_vector +step +inv "
- "+proj=cart +ellps=GRS80 +step +proj=unitconvert +xy_in=rad "
- "+z_in=m +xy_out=deg +z_out=m +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, esri_projectedCRS_to_geogCRS_with_ITRF_intermediate_context) {
- auto dbContext = DatabaseContext::create();
- auto authFactoryEPSG = AuthorityFactory::create(dbContext, "EPSG");
- auto authFactoryESRI = AuthorityFactory::create(dbContext, "ESRI");
- auto ctxt =
- CoordinateOperationContext::create(authFactoryEPSG, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NAD_1983_CORS96_StatePlane_North_Carolina_FIPS_3200_Ft_US (projected)
- authFactoryESRI->createCoordinateReferenceSystem("103501"),
- // ITRF2005 (geog3D)
- authFactoryEPSG->createCoordinateReferenceSystem("7910"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of NAD_1983_CORS96_StatePlane_North_Carolina_"
- "FIPS_3200_Ft_US + "
- "Conversion from NAD83(CORS96) (geog2D) to NAD83(CORS96) "
- "(geocentric) + Inverse of ITRF2000 to NAD83(CORS96) (1) + "
- "ITRF2000 to ITRF2005 (1) + "
- "Conversion from ITRF2005 (geocentric) to ITRF2005 (geog3D)");
- EXPECT_PRED_FORMAT2(
- ComparePROJString,
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft "
- "+xy_out=m +step +inv +proj=lcc +lat_0=33.75 +lon_0=-79 "
- "+lat_1=34.3333333333333 +lat_2=36.1666666666667 "
- "+x_0=609601.219202438 +y_0=0 +ellps=GRS80 +step +proj=cart "
- "+ellps=GRS80 +step +inv +proj=helmert +x=0.9956 +y=-1.9013 "
- "+z=-0.5215 +rx=0.025915 +ry=0.009426 +rz=0.011599 +s=0.00062 "
- "+dx=0.0007 +dy=-0.0007 +dz=0.0005 +drx=6.7e-05 +dry=-0.000757 "
- "+drz=-5.1e-05 +ds=-0.00018 +t_epoch=1997 "
- "+convention=coordinate_frame +step +proj=helmert +x=-0.0001 "
- "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
- "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
- "+t_epoch=2000 +convention=position_vector +step +inv +proj=cart "
- "+ellps=GRS80 +step +proj=unitconvert +xy_in=rad +z_in=m "
- "+xy_out=deg +z_out=m +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-static ProjectedCRSNNPtr createUTM31_WGS84() {
- return ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4326,
- Conversion::createUTM(PropertyMap(), 31, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
-}
-
-// ---------------------------------------------------------------------------
-
-static ProjectedCRSNNPtr createUTM32_WGS84() {
- return ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4326,
- Conversion::createUTM(PropertyMap(), 32, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_projCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4326, createUTM31_WGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_TRUE(std::dynamic_pointer_cast<Conversion>(op) != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=utm "
- "+zone=31 +ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_longlat_to_geogCS_latlong) {
-
- auto sourceCRS = GeographicCRS::OGC_CRS84;
- auto targetCRS = GeographicCRS::EPSG_4326;
- auto op = CoordinateOperationFactory::create()->createOperation(sourceCRS,
- targetCRS);
- ASSERT_TRUE(op != nullptr);
- auto conv = std::dynamic_pointer_cast<Conversion>(op);
- ASSERT_TRUE(conv != nullptr);
- EXPECT_TRUE(op->sourceCRS() &&
- op->sourceCRS()->isEquivalentTo(sourceCRS.get()));
- EXPECT_TRUE(op->targetCRS() &&
- op->targetCRS()->isEquivalentTo(targetCRS.get()));
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=axisswap +order=2,1");
- auto convInverse = nn_dynamic_pointer_cast<Conversion>(conv->inverse());
- ASSERT_TRUE(convInverse != nullptr);
- EXPECT_TRUE(convInverse->sourceCRS() &&
- convInverse->sourceCRS()->isEquivalentTo(targetCRS.get()));
- EXPECT_TRUE(convInverse->targetCRS() &&
- convInverse->targetCRS()->isEquivalentTo(sourceCRS.get()));
- EXPECT_EQ(conv->method()->exportToWKT(WKTFormatter::create().get()),
- convInverse->method()->exportToWKT(WKTFormatter::create().get()));
- EXPECT_TRUE(conv->method()->isEquivalentTo(convInverse->method().get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_longlat_to_geogCS_latlong_database) {
-
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- AuthorityFactory::create(DatabaseContext::create(), "OGC")
- ->createCoordinateReferenceSystem("CRS84"),
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("4326"),
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_longlat_to_projCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::OGC_CRS84, createUTM31_WGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=utm +zone=31 +ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_different_from_baseCRS_to_projCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4807, createUTM31_WGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(
- op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv +proj=longlat "
- "+ellps=clrk80ign +pm=paris +step +proj=utm +zone=31 "
- "+ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- geogCRS_different_from_baseCRS_to_projCRS_context_compatible_area) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setAllowUseIntermediateCRS(
- CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris)
- authFactory->createCoordinateReferenceSystem("32631"), // UTM31 WGS84
- ctxt);
- ASSERT_EQ(list.size(), 4U);
- EXPECT_EQ(
- list[0]->nameStr(),
- "NTF (Paris) to NTF (1) + Inverse of WGS 84 to NTF (3) + UTM zone 31N");
- ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
- EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "1");
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=hgridshift "
- "+grids=fr_ign_ntf_r93.tif +step +proj=utm +zone=31 +ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocentricCRS_to_projCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createGeocentricDatumWGS84(), createUTM31_WGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
- "+proj=utm +zone=31 +ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_geogCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createUTM31_WGS84(), GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=WGS84 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_no_id_to_geogCRS_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto src = authFactory->createCoordinateReferenceSystem(
- "28992"); // Amersfoort / RD New
- auto dst =
- authFactory->createCoordinateReferenceSystem("4258"); // ETRS89 2D
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_GE(list.size(), 1U);
- auto wkt2 =
- "PROJCRS[\"unknown\",\n"
- " BASEGEOGCRS[\"Amersfoort\",\n"
- " DATUM[\"Amersfoort\",\n"
- " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128]]],\n"
- " CONVERSION[\"unknown\",\n"
- " METHOD[\"Oblique Stereographic\"],\n"
- " PARAMETER[\"Latitude of natural origin\",52.1561605555556],\n"
- " PARAMETER[\"Longitude of natural origin\",5.38763888888889],\n"
- " PARAMETER[\"Scale factor at natural origin\",0.9999079],\n"
- " PARAMETER[\"False easting\",155000],\n"
- " PARAMETER[\"False northing\",463000]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"(E)\",east],\n"
- " AXIS[\"(N)\",north],\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",28992]]";
- auto obj = WKTParser().createFromWKT(wkt2);
- auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
- ASSERT_TRUE(src_from_wkt2 != nullptr);
- auto list2 = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src_from_wkt2), dst, ctxt);
- ASSERT_GE(list.size(), list2.size() - 1);
- for (size_t i = 0; i < list.size(); i++) {
- const auto &op = list[i];
- const auto &op2 = list2[i];
- EXPECT_TRUE(
- op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT));
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_3D_to_geogCRS_3D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto wkt = "PROJCRS[\"NAD83(HARN) / Oregon GIC Lambert (ft)\",\n"
- " BASEGEOGCRS[\"NAD83(HARN)\",\n"
- " DATUM[\"NAD83 (High Accuracy Reference Network)\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " ID[\"EPSG\",4957]],\n"
- " CONVERSION[\"unnamed\",\n"
- " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
- " ID[\"EPSG\",9802]],\n"
- " PARAMETER[\"Latitude of false origin\",41.75,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8821]],\n"
- " PARAMETER[\"Longitude of false origin\",-120.5,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8822]],\n"
- " PARAMETER[\"Latitude of 1st standard parallel\",43,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8823]],\n"
- " PARAMETER[\"Latitude of 2nd standard parallel\",45.5,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8824]],\n"
- " PARAMETER[\"Easting at false origin\",1312335.958,\n"
- " LENGTHUNIT[\"foot\",0.3048],\n"
- " ID[\"EPSG\",8826]],\n"
- " PARAMETER[\"Northing at false origin\",0,\n"
- " LENGTHUNIT[\"foot\",0.3048],\n"
- " ID[\"EPSG\",8827]]],\n"
- " CS[Cartesian,3],\n"
- " AXIS[\"easting\",east,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"foot\",0.3048]],\n"
- " AXIS[\"northing\",north,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"foot\",0.3048]],\n"
- " AXIS[\"ellipsoidal height (h)\",up,\n"
- " ORDER[3],\n"
- " LENGTHUNIT[\"foot\",0.3048]]]";
- auto obj = WKTParser().createFromWKT(wkt);
- auto src = NN_CHECK_ASSERT(nn_dynamic_pointer_cast<CRS>(obj));
- auto dst = authFactory->createCoordinateReferenceSystem(
- "4957"); // NAD83(HARN) (3D)
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- // Check that z ft->m conversion is done (and just once)
- "+step +proj=unitconvert +xy_in=ft +z_in=ft +xy_out=m +z_out=m "
- "+step +inv +proj=lcc +lat_0=41.75 +lon_0=-120.5 +lat_1=43 "
- "+lat_2=45.5 +x_0=399999.9999984 +y_0=0 +ellps=GRS80 "
- "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
- "+step +proj=axisswap +order=2,1");
-}
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_3D_to_projCRS_2D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto wkt =
- "PROJCRS[\"Projected 3d CRS\",\n"
- " BASEGEOGCRS[\"JGD2000\",\n"
- " DATUM[\"Japanese Geodetic Datum 2000\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " ID[\"EPSG\",4947]],\n" // the code is what triggered the bug
- " CONVERSION[\"Japan Plane Rectangular CS zone VII\",\n"
- " METHOD[\"Transverse Mercator\",\n"
- " ID[\"EPSG\",9807]],\n"
- " PARAMETER[\"Latitude of natural origin\",36,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8801]],\n"
- " PARAMETER[\"Longitude of natural origin\",137.166666666667,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8802]],\n"
- " PARAMETER[\"Scale factor at natural origin\",0.9999,\n"
- " SCALEUNIT[\"unity\",1],\n"
- " ID[\"EPSG\",8805]],\n"
- " PARAMETER[\"False easting\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8806]],\n"
- " PARAMETER[\"False northing\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8807]],\n"
- " ID[\"EPSG\",17807]],\n"
- " CS[Cartesian,3],\n"
- " AXIS[\"northing (X)\",north,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"metre\",1,\n"
- " ID[\"EPSG\",9001]]],\n"
- " AXIS[\"easting (Y)\",east,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"metre\",1,\n"
- " ID[\"EPSG\",9001]]],\n"
- " AXIS[\"ellipsoidal height (h)\",up,\n"
- " ORDER[3],\n"
- " LENGTHUNIT[\"metre\",1,\n"
- " ID[\"EPSG\",9001]]]]";
- auto obj = WKTParser().createFromWKT(wkt);
- auto src = NN_CHECK_ASSERT(nn_dynamic_pointer_cast<CRS>(obj));
- auto dst =
- authFactory->createCoordinateReferenceSystem("32653"); // WGS 84 UTM 53
- // We just want to check that we don't get inconsistent chaining exception
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_GE(list.size(), 1U);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_3D_to_projCRS_with_2D_geocentric_translation) {
-
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto src =
- authFactory->createCoordinateReferenceSystem("4979"); // WGS 84 3D
-
- // Azores Central 1948 / UTM zone 26N
- auto dst = authFactory->createCoordinateReferenceSystem("2189");
-
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
- "+step +proj=push +v_3 " // this is what we check. Due to the
- // target system being 2D only
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=104 +y=-167 +z=38 "
- "+step +inv +proj=cart +ellps=intl "
- "+step +proj=pop +v_3 " // this is what we check
- "+step +proj=utm +zone=26 +ellps=intl");
-
- auto listReverse =
- CoordinateOperationFactory::create()->createOperations(dst, src, ctxt);
- ASSERT_GE(listReverse.size(), 1U);
- EXPECT_EQ(
- listReverse[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=26 +ellps=intl "
- "+step +proj=push +v_3 " // this is what we check
- "+step +proj=cart +ellps=intl "
- "+step +proj=helmert +x=-104 +y=167 +z=-38 "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=pop +v_3 " // this is what we check
- "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS) {
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createUTM31_WGS84(), createUTM32_WGS84());
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=WGS84 +step "
- "+proj=utm +zone=32 +ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_different_baseCRS) {
-
- auto utm32 = ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4807,
- Conversion::createUTM(PropertyMap(), 32, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- createUTM31_WGS84(), utm32);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=WGS84 +step "
- "+proj=utm +zone=32 +ellps=clrk80ign +pm=paris");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_context_compatible_area) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("32634"), // UTM 34
- authFactory->createCoordinateReferenceSystem(
- "2171"), // Pulkovo 42 Poland I
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of UTM zone 34N + Inverse of Pulkovo 1942(58) to WGS 84 "
- "(1) + Poland zone I");
- ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
- EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_context_compatible_area_bis) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem(
- "3844"), // Pulkovo 42 Stereo 70 (Romania)
- authFactory->createCoordinateReferenceSystem("32634"), // UTM 34
- ctxt);
- ASSERT_EQ(list.size(), 3U);
- EXPECT_EQ(list[0]->nameStr(), "Inverse of Stereo 70 + "
- "Pulkovo 1942(58) to WGS 84 "
- "(19) + UTM zone 34N");
- ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
- EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "3");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_context_one_incompatible_area) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("32631"), // UTM 31
- authFactory->createCoordinateReferenceSystem(
- "2171"), // Pulkovo 42 Poland I
- ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of UTM zone 31N + Inverse of Pulkovo 1942(58) to WGS 84 "
- "(1) + Poland zone I");
- ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
- EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_context_incompatible_areas) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("32631"), // UTM 31
- authFactory->createCoordinateReferenceSystem("32633"), // UTM 33
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "Inverse of UTM zone 31N + UTM zone 33N");
- ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
- EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "0");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_context_incompatible_areas_ballpark) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("26711"), // UTM 11 NAD27
- authFactory->createCoordinateReferenceSystem(
- "3034"), // ETRS89 / LCC Europe
- ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_TRUE(list[0]->hasBallparkTransformation());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- projCRS_to_projCRS_context_incompatible_areas_crs_extent_use_intersection) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSourceAndTargetCRSExtentUse(
- CoordinateOperationContext::SourceTargetCRSExtentUse::INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("26711"), // UTM 11 NAD27
- authFactory->createCoordinateReferenceSystem(
- "3034"), // ETRS89 / LCC Europe
- ctxt);
- ASSERT_GE(list.size(), 0U);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_north_pole_inverted_axis) {
-
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("32661"),
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("5041"),
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_south_pole_inverted_axis) {
-
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("32761"),
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("5042"),
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_to_projCRS_through_geog3D) {
- // Check that when going from projCRS to projCRS, using
- // geog2D-->geog3D-->geog3D-->geog2D we do not have issues with
- // inconsistent CRS chaining, due to how we 'hack' a bit some intermediate
- // steps
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("5367"), // CR05 / CRTM05
- authFactory->createCoordinateReferenceSystem(
- "8908"), // CR-SIRGAS / CRTM05
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +inv +proj=tmerc +lat_0=0 +lon_0=-84 +k=0.9999 "
- "+x_0=500000 +y_0=0 +ellps=WGS84 "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=-0.16959 +y=0.35312 +z=0.51846 "
- "+rx=-0.03385 +ry=0.16325 +rz=-0.03446 +s=0.03693 "
- "+convention=position_vector "
- "+step +inv +proj=cart +ellps=GRS80 "
- "+step +proj=pop +v_3 "
- "+step +proj=tmerc +lat_0=0 +lon_0=-84 +k=0.9999 +x_0=500000 "
- "+y_0=0 +ellps=GRS80");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transform_from_amersfoort_rd_new_to_epsg_4326) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem("28992"),
- authFactory->createCoordinateReferenceSystem("4326"), ctxt);
- ASSERT_EQ(list.size(), 2U);
- // The order matters: "Amersfoort to WGS 84 (4)" replaces "Amersfoort to WGS
- // 84 (3)"
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of RD New + Amersfoort to WGS 84 (4)");
- EXPECT_EQ(list[1]->nameStr(),
- "Inverse of RD New + Amersfoort to WGS 84 (3)");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_geogCRS) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto op = CoordinateOperationFactory::create()->createOperation(
- boundCRS, GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 "
- "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step "
- "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_geodCRS) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto op = CoordinateOperationFactory::create()->createOperation(
- boundCRS, GeodeticCRS::EPSG_4978);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step "
- "+proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
- "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
- "+step +proj=cart +ellps=clrk80ign "
- "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
- "+convention=position_vector");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_geodCRS_not_related_to_hub) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- boundCRS,
- // ETRS89 geocentric
- authFactory->createCoordinateReferenceSystem("4936"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step "
- "+proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
- "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign "
- "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
- "+convention=position_vector "
- "+step +inv +proj=cart +ellps=GRS80 "
- "+step +proj=pop +v_3 "
- "+step +proj=cart +ellps=GRS80");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_geogCRS_with_area) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4267, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto op = CoordinateOperationFactory::create()->createOperation(
- boundCRS, authFactory->createCoordinateReferenceSystem("4326"));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk66 +step +proj=helmert +x=1 +y=2 "
- "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step "
- "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_unrelated_geogCRS) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto op = CoordinateOperationFactory::create()->createOperation(
- boundCRS, GeographicCRS::EPSG_4269);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- CoordinateOperationFactory::create()
- ->createOperation(GeographicCRS::EPSG_4807,
- GeographicCRS::EPSG_4269)
- ->exportToPROJString(PROJStringFormatter::create().get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, createOperation_boundCRS_identified_by_datum) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +type=crs");
- auto src = nn_dynamic_pointer_cast<GeographicCRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDest = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=32 +a=6378249.2 +b=6356515 "
- "+towgs84=-263.0,6.0,431.0 +no_defs +type=crs");
- auto dest = nn_dynamic_pointer_cast<BoundCRS>(objDest);
- ASSERT_TRUE(dest != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=push +v_3 +step +proj=cart +ellps=WGS84 +step "
- "+proj=helmert +x=263 +y=-6 +z=-431 +step +inv +proj=cart "
- "+ellps=clrk80ign +step +proj=pop +v_3 +step +proj=utm +zone=32 "
- "+ellps=clrk80ign");
-
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_TRUE(list[0]->isEquivalentTo(op.get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_clrk_66_geogCRS_to_nad83_geogCRS) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=latlong +ellps=clrk66 +nadgrids=ntv1_can.dat,conus +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDest = PROJStringParser().createFromPROJString(
- "+proj=latlong +datum=NAD83 +type=crs");
- auto dest = nn_dynamic_pointer_cast<CRS>(objDest);
- ASSERT_TRUE(dest != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=ntv1_can.dat,conus "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_clrk_66_projCRS_to_nad83_geogCRS) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=17 +ellps=clrk66 +nadgrids=ntv1_can.dat,conus "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDest = PROJStringParser().createFromPROJString(
- "+proj=latlong +datum=NAD83 +type=crs");
- auto dest = nn_dynamic_pointer_cast<CRS>(objDest);
- ASSERT_TRUE(dest != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=17 +ellps=clrk66 "
- "+step +proj=hgridshift +grids=ntv1_can.dat,conus "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_projCRS_to_geogCRS) {
- auto utm31 = ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4807,
- Conversion::createUTM(PropertyMap(), 31, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
- auto boundCRS = BoundCRS::createFromTOWGS84(
- utm31, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto op = CoordinateOperationFactory::create()->createOperation(
- boundCRS, GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign "
- "+pm=paris +step +proj=push +v_3 +step +proj=cart "
- "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 "
- "+rz=6 +s=7 +convention=position_vector +step +inv +proj=cart "
- "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_projCRS) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto utm31 = ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4326,
- Conversion::createUTM(PropertyMap(), 31, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
- auto op =
- CoordinateOperationFactory::create()->createOperation(boundCRS, utm31);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 "
- "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step "
- "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step "
- "+proj=utm +zone=31 +ellps=WGS84");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_geogCRS_to_unrelated_geogCRS_context) {
- auto src = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- // ETRS89
- auto dst = authFactory->createCoordinateReferenceSystem("4258");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_EQ(list.size(), 1U);
- // Check with it is a concatenated operation, since it doesn't particularly
- // show up in the PROJ string
- EXPECT_TRUE(dynamic_cast<ConcatenatedOperation *>(list[0].get()) !=
- nullptr);
- EXPECT_EQ(list[0]->nameStr(), "Transformation from NTF (Paris) to WGS84 + "
- "Inverse of ETRS89 to WGS 84 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
- "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
- "+step +proj=push +v_3 +step +proj=cart +ellps=clrk80ign "
- "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
- "+convention=position_vector "
- "+step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geogCRS_to_boundCRS_of_geogCRS) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4326, boundCRS);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
- "+step +proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=1 "
- "+y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector "
- "+step +inv +proj=cart +ellps=clrk80ign +step +proj=pop +v_3 "
- "+step +proj=longlat +ellps=clrk80ign +pm=paris +step "
- "+proj=unitconvert +xy_in=rad +xy_out=grad +step +proj=axisswap "
- "+order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_to_geogCRS_same_datum_context) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4269, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- boundCRS, GeographicCRS::EPSG_4269, ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_to_geogCRS_hubCRS_and_targetCRS_same_but_baseCRS_not) {
- const char *wkt =
- "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"Ellipsoid (US Feet)\",\n"
- " VERT_DATUM[\"Ellipsoid\",2002],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Up\",UP]]]";
-
- auto dbContext = DatabaseContext::create();
- auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
- auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(obj);
- ASSERT_TRUE(boundCRS != nullptr);
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(boundCRS), GeographicCRS::EPSG_4979, ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=unitconvert +z_in=us-ft +z_out=m");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_to_boundCRS) {
- auto utm31 = ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4807,
- Conversion::createUTM(PropertyMap(), 31, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
- auto utm32 = ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4269,
- Conversion::createUTM(PropertyMap(), 32, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
- auto boundCRS1 = BoundCRS::createFromTOWGS84(
- utm31, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto boundCRS2 = BoundCRS::createFromTOWGS84(
- utm32, std::vector<double>{8, 9, 10, 11, 12, 13, 14});
- auto op = CoordinateOperationFactory::create()->createOperation(boundCRS1,
- boundCRS2);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign "
- "+pm=paris +step +proj=push +v_3 +step +proj=cart "
- "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 "
- "+rz=6 +s=7 +convention=position_vector +step +inv +proj=helmert "
- "+x=8 +y=9 +z=10 +rx=11 +ry=12 +rz=13 +s=14 "
- "+convention=position_vector +step +inv +proj=cart +ellps=GRS80 "
- "+step +proj=pop +v_3 +step +proj=utm +zone=32 +ellps=GRS80");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_to_boundCRS_noop_for_TOWGS84) {
- auto boundCRS1 = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto boundCRS2 = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4269, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto op = CoordinateOperationFactory::create()->createOperation(boundCRS1,
- boundCRS2);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
- "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign +step +inv +proj=cart "
- "+ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_to_boundCRS_unralated_hub) {
- auto boundCRS1 = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto boundCRS2 = BoundCRS::create(
- GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4979,
- Transformation::createGeocentricTranslations(
- PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4979,
- 1.0, 2.0, 3.0, std::vector<PositionalAccuracyNNPtr>()));
- auto op = CoordinateOperationFactory::create()->createOperation(boundCRS1,
- boundCRS2);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- CoordinateOperationFactory::create()
- ->createOperation(boundCRS1->baseCRS(), boundCRS2->baseCRS())
- ->exportToPROJString(PROJStringFormatter::create().get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_of_projCRS_towgs84_to_boundCRS_of_projCRS_nadgrids) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=15 +datum=NAD83 +units=m +no_defs +ellps=GRS80 "
- "+towgs84=0,0,0 +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=15 +datum=NAD27 +units=m +no_defs +ellps=clrk66 "
- "+nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=15 +ellps=GRS80 +step "
- "+inv +proj=hgridshift "
- "+grids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat +step +proj=utm "
- "+zone=15 +ellps=clrk66");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_with_basecrs_with_extent_to_geogCRS) {
-
- auto wkt =
- "BOUNDCRS[\n"
- " SOURCECRS[\n"
- " PROJCRS[\"NAD83 / California zone 3 (ftUS)\",\n"
- " BASEGEODCRS[\"NAD83\",\n"
- " DATUM[\"North American Datum 1983\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
- " CONVERSION[\"SPCS83 California zone 3 (US Survey "
- "feet)\",\n"
- " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
- " ID[\"EPSG\",9802]],\n"
- " PARAMETER[\"Latitude of false origin\",36.5,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8821]],\n"
- " PARAMETER[\"Longitude of false origin\",-120.5,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8822]],\n"
- " PARAMETER[\"Latitude of 1st standard parallel\","
- " 38.4333333333333,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8823]],\n"
- " PARAMETER[\"Latitude of 2nd standard parallel\","
- " 37.0666666666667,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8824]],\n"
- " PARAMETER[\"Easting at false origin\",6561666.667,\n"
- " LENGTHUNIT[\"US survey foot\","
- " 0.304800609601219],\n"
- " ID[\"EPSG\",8826]],\n"
- " PARAMETER[\"Northing at false origin\",1640416.667,\n"
- " LENGTHUNIT[\"US survey foot\","
- " 0.304800609601219],\n"
- " ID[\"EPSG\",8827]]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"easting (X)\",east,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"US survey foot\","
- " 0.304800609601219]],\n"
- " AXIS[\"northing (Y)\",north,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"US survey foot\","
- " 0.304800609601219]],\n"
- " SCOPE[\"unknown\"],\n"
- " AREA[\"USA - California - SPCS - 3\"],\n"
- " BBOX[36.73,-123.02,38.71,-117.83],\n"
- " ID[\"EPSG\",2227]]],\n"
- " TARGETCRS[\n"
- " GEODCRS[\"WGS 84\",\n"
- " DATUM[\"World Geodetic System 1984\",\n"
- " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " CS[ellipsoidal,2],\n"
- " AXIS[\"latitude\",north,\n"
- " ORDER[1],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"longitude\",east,\n"
- " ORDER[2],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " ID[\"EPSG\",4326]]],\n"
- " ABRIDGEDTRANSFORMATION[\"NAD83 to WGS 84 (1)\",\n"
- " METHOD[\"Geocentric translations (geog2D domain)\",\n"
- " ID[\"EPSG\",9603]],\n"
- " PARAMETER[\"X-axis translation\",0,\n"
- " ID[\"EPSG\",8605]],\n"
- " PARAMETER[\"Y-axis translation\",0,\n"
- " ID[\"EPSG\",8606]],\n"
- " PARAMETER[\"Z-axis translation\",0,\n"
- " ID[\"EPSG\",8607]],\n"
- " SCOPE[\"unknown\"],\n"
- " AREA[\"North America - Canada and USA (CONUS, Alaska "
- "mainland)\"],\n"
- " BBOX[23.81,-172.54,86.46,-47.74],\n"
- " ID[\"EPSG\",1188]]]";
- auto obj = WKTParser().createFromWKT(wkt);
- auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(obj);
- ASSERT_TRUE(boundCRS != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(boundCRS), GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(), "Inverse of SPCS83 California zone 3 (US Survey "
- "feet) + NAD83 to WGS 84 (1)");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, ETRS89_3D_to_proj_string_with_geoidgrids_nadgrids) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- // ETRS89 3D
- auto src = authFactory->createCoordinateReferenceSystem("4937");
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 "
- "+k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel "
- "+nadgrids=rdtrans2008.gsb +geoidgrids=naptrans2008.gtx +units=m "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- src, NN_NO_CHECK(dst), ctxt);
- ASSERT_EQ(list.size(), 2U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +inv +proj=vgridshift +grids=naptrans2008.gtx "
- "+multiplier=1 "
- "+step +inv +proj=hgridshift +grids=rdtrans2008.gsb "
- "+step +proj=sterea +lat_0=52.1561605555556 "
- "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 "
- "+y_0=463000 +ellps=bessel");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, nadgrids_with_pm) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=tmerc +lat_0=39.66666666666666 +lon_0=1 +k=1 +x_0=200000 "
- "+y_0=300000 +ellps=intl +nadgrids=foo.gsb +pm=lisbon "
- "+units=m +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto dst = authFactory->createCoordinateReferenceSystem("4326");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), dst, ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=tmerc +lat_0=39.6666666666667 +lon_0=1 "
- "+k=1 +x_0=200000 +y_0=300000 +ellps=intl +pm=lisbon "
- // Check that there is no extra +step +proj=longlat +pm=lisbon
- "+step +proj=hgridshift +grids=foo.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- // ETRS89
- dst = authFactory->createCoordinateReferenceSystem("4258");
- list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), dst, ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=tmerc +lat_0=39.6666666666667 +lon_0=1 "
- "+k=1 +x_0=200000 +y_0=300000 +ellps=intl +pm=lisbon "
- // Check that there is no extra +step +proj=longlat +pm=lisbon
- "+step +proj=hgridshift +grids=foo.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- // From WKT BOUNDCRS
- auto formatter = WKTFormatter::create(WKTFormatter::Convention::WKT2_2019);
- auto src_wkt = src->exportToWKT(formatter.get());
- auto objFromWkt = WKTParser().createFromWKT(src_wkt);
- auto crsFromWkt = nn_dynamic_pointer_cast<BoundCRS>(objFromWkt);
- ASSERT_TRUE(crsFromWkt);
- list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(crsFromWkt), dst, ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=tmerc +lat_0=39.6666666666667 +lon_0=1 "
- "+k=1 +x_0=200000 +y_0=300000 +ellps=intl +pm=lisbon "
- // Check that there is no extra +step +proj=longlat +pm=lisbon
- "+step +proj=hgridshift +grids=foo.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, WGS84_G1762_to_compoundCRS_with_bound_vertCRS) {
- auto authFactoryEPSG =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- // WGS 84 (G1762) 3D
- auto src = authFactoryEPSG->createCoordinateReferenceSystem("7665");
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=NAD83 +geoidgrids=@foo.gtx +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- src, NN_NO_CHECK(dst), ctxt);
- ASSERT_GE(list.size(), 53U);
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of WGS 84 to WGS 84 (G1762) + "
- "Inverse of unknown to WGS84 ellipsoidal height + "
- "Inverse of NAD83 to WGS 84 (1) + "
- "axis order change (2D)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +inv +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS) {
-
- auto compound = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{GeographicCRS::EPSG_4326, createVerticalCRS()});
- auto op = CoordinateOperationFactory::create()->createOperation(
- compound, GeographicCRS::EPSG_4807);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- CoordinateOperationFactory::create()
- ->createOperation(GeographicCRS::EPSG_4326,
- GeographicCRS::EPSG_4807)
- ->exportToPROJString(PROJStringFormatter::create().get()));
-}
-
-// ---------------------------------------------------------------------------
-
-static BoundCRSNNPtr createBoundVerticalCRS() {
- auto vertCRS = createVerticalCRS();
- auto transformation =
- Transformation::createGravityRelatedHeightToGeographic3D(
- PropertyMap(), vertCRS, GeographicCRS::EPSG_4979, nullptr,
- "us_nga_egm08_25.tif", std::vector<PositionalAccuracyNNPtr>());
- return BoundCRS::create(vertCRS, GeographicCRS::EPSG_4979, transformation);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_height_to_PROJ_string) {
- auto transf = createBoundVerticalCRS()->transformation();
- EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_nga_egm08_25.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- auto grids = transf->gridsNeeded(DatabaseContext::create(), false);
- ASSERT_EQ(grids.size(), 1U);
- auto gridDesc = *(grids.begin());
- EXPECT_EQ(gridDesc.shortName, "us_nga_egm08_25.tif");
- EXPECT_TRUE(gridDesc.packageName.empty());
- EXPECT_EQ(gridDesc.url, "https://cdn.proj.org/us_nga_egm08_25.tif");
- if (gridDesc.available) {
- EXPECT_TRUE(!gridDesc.fullName.empty()) << gridDesc.fullName;
- EXPECT_TRUE(gridDesc.fullName.find(gridDesc.shortName) !=
- std::string::npos)
- << gridDesc.fullName;
- } else {
- EXPECT_TRUE(gridDesc.fullName.empty()) << gridDesc.fullName;
- }
- EXPECT_EQ(gridDesc.directDownload, true);
- EXPECT_EQ(gridDesc.openLicense, true);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_Geographic3D_to_GravityRelatedHeight_gtx) {
- auto wkt =
- "COORDINATEOPERATION[\"ETRS89 to NAP height (1)\",\n"
- " VERSION[\"RDNAP-Nld 2008\"],\n"
- " SOURCECRS[\n"
- " GEOGCRS[\"ETRS89\",\n"
- " DATUM[\"European Terrestrial Reference System 1989\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " CS[ellipsoidal,3],\n"
- " AXIS[\"geodetic latitude (Lat)\",north,\n"
- " ORDER[1],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"geodetic longitude (Lon)\",east,\n"
- " ORDER[2],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"ellipsoidal height (h)\",up,\n"
- " ORDER[3],\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " ID[\"EPSG\",4937]]],\n"
- " TARGETCRS[\n"
- " VERTCRS[\"NAP height\",\n"
- " VDATUM[\"Normaal Amsterdams Peil\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " ID[\"EPSG\",5709]]],\n"
- " METHOD[\"Geographic3D to GravityRelatedHeight (US .gtx)\",\n"
- " ID[\"EPSG\",9665]],\n"
- " PARAMETERFILE[\"Geoid (height correction) model "
- "file\",\"naptrans2008.gtx\"],\n"
- " OPERATIONACCURACY[0.01],\n"
- " USAGE[\n"
- " SCOPE[\"unknown\"],\n"
- " AREA[\"Netherlands - onshore\"],\n"
- " BBOX[50.75,3.2,53.7,7.22]],\n"
- " ID[\"EPSG\",7001]]";
- ;
- auto obj = WKTParser().createFromWKT(wkt);
- auto transf = nn_dynamic_pointer_cast<Transformation>(obj);
- ASSERT_TRUE(transf != nullptr);
-
- // Check that we correctly inverse files in the case of
- // "Geographic3D to GravityRelatedHeight (US .gtx)"
- EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +inv +proj=vgridshift "
- "+grids=naptrans2008.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_ntv2_to_PROJ_string) {
- auto transformation = Transformation::createNTv2(
- PropertyMap(), GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326,
- "foo.gsb", std::vector<PositionalAccuracyNNPtr>());
- EXPECT_EQ(
- transformation->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=grad +xy_out=rad +step "
- "+proj=hgridshift +grids=foo.gsb +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_VERTCON_to_PROJ_string) {
- auto verticalCRS1 = createVerticalCRS();
-
- auto verticalCRS2 = VerticalCRS::create(
- PropertyMap(), VerticalReferenceFrame::create(PropertyMap()),
- VerticalCS::createGravityRelatedHeight(UnitOfMeasure::METRE));
-
- // Use of this type of transformation is a bit of non-sense here
- // since it should normally be used with NGVD29 and NAVD88 for VerticalCRS,
- // and NAD27/NAD83 as horizontal CRS...
- auto vtransformation = Transformation::createVERTCON(
- PropertyMap(), verticalCRS1, verticalCRS2, "bla.gtx",
- std::vector<PositionalAccuracyNNPtr>());
- EXPECT_EQ(vtransformation->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=vgridshift +grids=bla.gtx +multiplier=0.001");
-}
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_NZLVD_to_PROJ_string) {
- auto dbContext = DatabaseContext::create();
- auto factory = AuthorityFactory::create(dbContext, "EPSG");
- auto op = factory->createCoordinateOperation("7860", false);
- EXPECT_EQ(op->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5, dbContext)
- .get()),
- "+proj=vgridshift +grids=nz_linz_auckht1946-nzvd2016.tif "
- "+multiplier=1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_BEV_AT_to_PROJ_string) {
- auto dbContext = DatabaseContext::create();
- auto factory = AuthorityFactory::create(dbContext, "EPSG");
- auto op = factory->createCoordinateOperation("9275", false);
- EXPECT_EQ(op->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5, dbContext)
- .get()),
- "+proj=vgridshift +grids=at_bev_GV_Hoehengrid_V1.tif "
- "+multiplier=1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_longitude_rotation_to_PROJ_string) {
-
- auto src = GeographicCRS::create(
- PropertyMap(), GeodeticReferenceFrame::create(
- PropertyMap(), Ellipsoid::WGS84,
- optional<std::string>(), PrimeMeridian::GREENWICH),
- EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
- auto dest = GeographicCRS::create(
- PropertyMap(), GeodeticReferenceFrame::create(
- PropertyMap(), Ellipsoid::WGS84,
- optional<std::string>(), PrimeMeridian::PARIS),
- EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
- auto transformation = Transformation::createLongitudeRotation(
- PropertyMap(), src, dest, Angle(10));
- EXPECT_TRUE(transformation->validateParameters().empty());
- EXPECT_EQ(
- transformation->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv "
- "+proj=longlat +ellps=WGS84 +pm=10 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(transformation->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv "
- "+proj=longlat +ellps=WGS84 +pm=-10 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_Geographic2D_offsets_to_PROJ_string) {
-
- auto transformation = Transformation::createGeographic2DOffsets(
- PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326,
- Angle(0.5), Angle(-1), {});
- EXPECT_TRUE(transformation->validateParameters().empty());
-
- EXPECT_EQ(
- transformation->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=1800 +dlon=-3600 +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(transformation->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=-1800 +dlon=3600 +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_Geographic3D_offsets_to_PROJ_string) {
-
- auto transformation = Transformation::createGeographic3DOffsets(
- PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326,
- Angle(0.5), Angle(-1), Length(2), {});
- EXPECT_TRUE(transformation->validateParameters().empty());
-
- EXPECT_EQ(
- transformation->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=1800 +dlon=-3600 +dh=2 +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(transformation->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=-1800 +dlon=3600 +dh=-2 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- transformation_Geographic2D_with_height_offsets_to_PROJ_string) {
-
- auto transformation = Transformation::createGeographic2DWithHeightOffsets(
- PropertyMap(),
- CompoundCRS::create(PropertyMap(),
- {GeographicCRS::EPSG_4326, createVerticalCRS()}),
- GeographicCRS::EPSG_4326, Angle(0.5), Angle(-1), Length(2), {});
- EXPECT_TRUE(transformation->validateParameters().empty());
-
- EXPECT_EQ(
- transformation->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=1800 +dlon=-3600 +dh=2 +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- EXPECT_EQ(transformation->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
- "+dlat=-1800 +dlon=3600 +dh=-2 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, transformation_vertical_offset_to_PROJ_string) {
-
- auto transformation = Transformation::createVerticalOffset(
- PropertyMap(), createVerticalCRS(), createVerticalCRS(), Length(1), {});
- EXPECT_TRUE(transformation->validateParameters().empty());
-
- EXPECT_EQ(
- transformation->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=geogoffset +dh=1");
- EXPECT_EQ(transformation->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=geogoffset +dh=-1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_with_boundVerticalCRS_to_geogCRS) {
-
- auto compound = CompoundCRS::create(
- PropertyMap(), std::vector<CRSNNPtr>{GeographicCRS::EPSG_4326,
- createBoundVerticalCRS()});
- auto op = CoordinateOperationFactory::create()->createOperation(
- compound, GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(
- op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=vgridshift "
- "+grids=us_nga_egm08_25.tif +multiplier=1 +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_with_boundGeogCRS_to_geogCRS) {
-
- auto geogCRS = GeographicCRS::create(
- PropertyMap(), GeodeticReferenceFrame::create(
- PropertyMap(), Ellipsoid::WGS84,
- optional<std::string>(), PrimeMeridian::GREENWICH),
- EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
- auto horizBoundCRS = BoundCRS::createFromTOWGS84(
- geogCRS, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto compound = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{horizBoundCRS, createVerticalCRS()});
- auto op = CoordinateOperationFactory::create()->createOperation(
- compound, GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
- "+convention=position_vector "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=pop +v_3 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_with_boundGeogCRS_and_boundVerticalCRS_to_geogCRS) {
-
- auto horizBoundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto compound = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{horizBoundCRS, createBoundVerticalCRS()});
- auto op = CoordinateOperationFactory::create()->createOperation(
- compound, GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
- // Not completely sure the order of horizontal and vertical operations
- // makes sense
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
- "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign "
- "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
- "+convention=position_vector "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=pop +v_3 "
- "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- auto grids = op->gridsNeeded(DatabaseContext::create(), false);
- EXPECT_EQ(grids.size(), 1U);
-
- auto opInverse = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4979, compound);
- ASSERT_TRUE(opInverse != nullptr);
- EXPECT_TRUE(opInverse->inverse()->isEquivalentTo(op.get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_with_boundProjCRS_and_boundVerticalCRS_to_geogCRS) {
-
- auto horizBoundCRS = BoundCRS::createFromTOWGS84(
- ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4807,
- Conversion::createUTM(PropertyMap(), 31, true),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)),
- std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto compound = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{horizBoundCRS, createBoundVerticalCRS()});
- auto op = CoordinateOperationFactory::create()->createOperation(
- compound, GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
- // Not completely sure the order of horizontal and vertical operations
- // makes sense
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=31 +ellps=clrk80ign +pm=paris "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=clrk80ign "
- "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
- "+convention=position_vector "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=pop +v_3 "
- "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- auto opInverse = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4979, compound);
- ASSERT_TRUE(opInverse != nullptr);
- EXPECT_TRUE(opInverse->inverse()->isEquivalentTo(op.get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- compoundCRS_with_boundVerticalCRS_from_geoidgrids_with_m_to_geogCRS) {
-
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_NO_CHECK(src), GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(), "axis order change (2D) + "
- "unknown to WGS84 ellipsoidal height");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- compoundCRS_with_boundVerticalCRS_from_geoidgrids_with_ftus_to_geogCRS) {
-
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +vunits=us-ft "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_NO_CHECK(src), GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->nameStr(), "axis order change (2D) + "
- "Transformation from unknown to unknown + "
- "unknown to WGS84 ellipsoidal height");
- EXPECT_EQ(
- op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad +z_out=m "
- "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- compoundCRS_with_boundProjCRS_with_ftus_and_boundVerticalCRS_to_geogCRS) {
-
- auto wkt =
- "COMPD_CS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet + "
- "NAVD88 height - Geoid12B (US Feet)\",\n"
- " PROJCS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0],\n"
- " UNIT[\"Degree\",0.0174532925199433]],\n"
- " PROJECTION[\"Transverse_Mercator\"],\n"
- " PARAMETER[\"latitude_of_origin\",30],\n"
- " PARAMETER[\"central_meridian\",-87.5],\n"
- " PARAMETER[\"scale_factor\",0.999933333333333],\n"
- " PARAMETER[\"false_easting\",1968500],\n"
- " PARAMETER[\"false_northing\",0],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Easting\",EAST],\n"
- " AXIS[\"Northing\",NORTH],\n"
- " AUTHORITY[\"ESRI\",\"102630\"]],\n"
- " VERT_CS[\"NAVD88 height (ftUS)\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " EXTENSION[\"PROJ4_GRIDS\",\"foo.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"6360\"]]]";
-
- auto obj = WKTParser().createFromWKT(wkt);
- auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj);
- ASSERT_TRUE(crs != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_NO_CHECK(crs), GeographicCRS::EPSG_4979);
- ASSERT_TRUE(op != nullptr);
-
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
- "+step +inv +proj=tmerc +lat_0=30 +lon_0=-87.5 "
- "+k=0.999933333333333 +x_0=600000 +y_0=0 +ellps=GRS80 "
- "+step +proj=unitconvert +z_in=us-ft +z_out=m "
- "+step +proj=vgridshift +grids=foo.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- compoundCRS_with_boundVerticalCRS_from_grids_to_geogCRS_with_ftus_ctxt) {
-
- auto dbContext = DatabaseContext::create();
-
- const char *wktSrc =
- "COMPD_CS[\"NAD83 + NAVD88 height - Geoid12B (Meters)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " EXTENSION[\"PROJ4_GRIDS\",\"@foo.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"metre\",1.0,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"5703\"]]]";
- auto objSrc =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
- auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCRS != nullptr);
-
- const char *wktDst =
- "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"Ellipsoid (US Feet)\",\n"
- " VERT_DATUM[\"Ellipsoid\",2002],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Up\",UP]]]";
- auto objDst =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktDst);
- auto dstCRS = nn_dynamic_pointer_cast<GeographicCRS>(objDst);
- ASSERT_TRUE(dstCRS != nullptr);
-
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCRS), NN_NO_CHECK(dstCRS), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +z_in=m "
- "+xy_out=deg +z_out=us-ft "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_with_boundGeogCRS_boundVerticalCRS_from_grids_to_boundGeogCRS_with_ftus_ctxt) {
-
- // Variant of above but with TOWGS84 in source & target CRS
-
- auto dbContext = DatabaseContext::create();
-
- const char *wktSrc =
- "COMPD_CS[\"NAD83 + NAVD88 height - Geoid12B (Meters)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " EXTENSION[\"PROJ4_GRIDS\",\"@foo.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"metre\",1.0,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"5703\"]]]";
- auto objSrc =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
- auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCRS != nullptr);
-
- const char *wktDst =
- "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"Ellipsoid (US Feet)\",\n"
- " VERT_DATUM[\"Ellipsoid\",2002],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Up\",UP]]]";
- auto objDst =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktDst);
- auto dstCRS = nn_dynamic_pointer_cast<BoundCRS>(objDst);
- ASSERT_TRUE(dstCRS != nullptr);
-
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCRS), NN_NO_CHECK(dstCRS), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=rad +z_in=m "
- "+xy_out=deg +z_out=us-ft");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_with_boundVerticalCRS_from_grids_to_boundGeogCRS_with_ftus_ctxt) {
-
- // Variant of above but with TOWGS84 in target CRS only
-
- auto dbContext = DatabaseContext::create();
-
- const char *wktSrc =
- "COMPD_CS[\"NAD83 + NAVD88 height - Geoid12B (Meters)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " EXTENSION[\"PROJ4_GRIDS\",\"@foo.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"metre\",1.0,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"5703\"]]]";
- auto objSrc =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
- auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCRS != nullptr);
-
- const char *wktDst =
- "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"Ellipsoid (US Feet)\",\n"
- " VERT_DATUM[\"Ellipsoid\",2002],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Up\",UP]]]";
- auto objDst =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktDst);
- auto dstCRS = nn_dynamic_pointer_cast<BoundCRS>(objDst);
- ASSERT_TRUE(dstCRS != nullptr);
-
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCRS), NN_NO_CHECK(dstCRS), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +z_in=m "
- "+xy_out=deg +z_out=us-ft "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- compoundCRS_with_boundGeogCRS_and_geoid_to_geodCRS_NAD2011_ctxt) {
-
- auto dbContext = DatabaseContext::create();
-
- const char *wktSrc =
- "COMPD_CS[\"NAD83 / California zone 5 (ftUS) + "
- "NAVD88 height - Geoid12B (ftUS)\","
- " PROJCS[\"NAD83 / California zone 5 (ftUS)\","
- " GEOGCS[\"NAD83\","
- " DATUM[\"North_American_Datum_1983\","
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,"
- " AUTHORITY[\"EPSG\",\"7019\"]],"
- " TOWGS84[0,0,0,0,0,0,0],"
- " AUTHORITY[\"EPSG\",\"6269\"]],"
- " PRIMEM[\"Greenwich\",0,"
- " AUTHORITY[\"EPSG\",\"8901\"]],"
- " UNIT[\"degree\",0.0174532925199433,"
- " AUTHORITY[\"EPSG\",\"9122\"]],"
- " AUTHORITY[\"EPSG\",\"4269\"]],"
- " PROJECTION[\"Lambert_Conformal_Conic_2SP\"],"
- " PARAMETER[\"standard_parallel_1\",35.46666666666667],"
- " PARAMETER[\"standard_parallel_2\",34.03333333333333],"
- " PARAMETER[\"latitude_of_origin\",33.5],"
- " PARAMETER[\"central_meridian\",-118],"
- " PARAMETER[\"false_easting\",6561666.667],"
- " PARAMETER[\"false_northing\",1640416.667],"
- " UNIT[\"US survey foot\",0.3048006096012192,"
- " AUTHORITY[\"EPSG\",\"9003\"]],"
- " AXIS[\"X\",EAST],"
- " AXIS[\"Y\",NORTH],"
- " AUTHORITY[\"EPSG\",\"2229\"]],"
- "VERT_CS[\"NAVD88 height - Geoid12B (ftUS)\","
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,"
- " AUTHORITY[\"EPSG\",\"5103\"]],"
- " UNIT[\"US survey foot\",0.3048006096012192,"
- " AUTHORITY[\"EPSG\",\"9003\"]],"
- " AXIS[\"Gravity-related height\",UP],"
- " AUTHORITY[\"EPSG\",\"6360\"]]]";
- auto objSrc =
- WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
- auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCRS != nullptr);
-
- auto authFactoryEPSG = AuthorityFactory::create(dbContext, "EPSG");
- // NAD83(2011) geocentric
- auto dstCRS = authFactoryEPSG->createCoordinateReferenceSystem("6317");
-
- auto authFactory = AuthorityFactory::create(dbContext, std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCRS), dstCRS, ctxt);
- bool found = false;
- for (const auto &op : list) {
- if (op->nameStr() ==
- "Inverse of unnamed + "
- "Transformation from NAD83 to WGS84 + "
- "Ballpark geographic offset from WGS 84 to NAD83(2011) + "
- "Transformation from NAVD88 height (ftUS) to NAVD88 height + "
- "Inverse of NAD83(2011) to NAVD88 height (1) + "
- "Conversion from NAD83(2011) (geog3D) to NAD83(2011) "
- "(geocentric)") {
- found = true;
- EXPECT_EQ(
- op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
- "+step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 "
- "+lat_1=35.4666666666667 +lat_2=34.0333333333333 "
- "+x_0=2000000.0001016 +y_0=500000.0001016 +ellps=GRS80 "
- "+step +proj=unitconvert +z_in=us-ft +z_out=m "
- "+step +proj=vgridshift +grids=us_noaa_g2012bu0.tif "
- "+multiplier=1 "
- "+step +proj=cart +ellps=GRS80");
- }
- }
- EXPECT_TRUE(found);
- if (!found) {
- for (const auto &op : list) {
- std::cerr << op->nameStr() << std::endl;
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocent_to_compoundCRS) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=geocent +datum=WGS84 +units=m +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv "
- "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv "
- "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, geocent_to_compoundCRS_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- // WGS84 geocentric
- auto src = authFactory->createCoordinateReferenceSystem("4978");
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- src, NN_CHECK_ASSERT(dst), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv "
- "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv "
- "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert "
- "+xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_compoundCRS) {
- auto compound1 = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{createUTM31_WGS84(), createVerticalCRS()});
- auto compound2 = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{createUTM32_WGS84(), createVerticalCRS()});
- auto op = CoordinateOperationFactory::create()->createOperation(compound1,
- compound2);
- ASSERT_TRUE(op != nullptr);
- auto opRef = CoordinateOperationFactory::create()->createOperation(
- createUTM31_WGS84(), createUTM32_WGS84());
- ASSERT_TRUE(opRef != nullptr);
- EXPECT_TRUE(op->isEquivalentTo(opRef.get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_compoundCRS_with_vertical_transform) {
- auto verticalCRS1 = createVerticalCRS();
-
- auto verticalCRS2 = VerticalCRS::create(
- PropertyMap(), VerticalReferenceFrame::create(PropertyMap()),
- VerticalCS::createGravityRelatedHeight(UnitOfMeasure::METRE));
-
- // Use of this type of transformation is a bit of non-sense here
- // since it should normally be used with NGVD29 and NAVD88 for VerticalCRS,
- // and NAD27/NAD83 as horizontal CRS...
- auto vtransformation = Transformation::createVERTCON(
- PropertyMap(), verticalCRS1, verticalCRS2, "bla.gtx",
- std::vector<PositionalAccuracyNNPtr>());
-
- auto compound1 = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{
- ProjectedCRS::create(
- PropertyMap(), GeographicCRS::EPSG_4326,
- Conversion::createTransverseMercator(PropertyMap(), Angle(1),
- Angle(2), Scale(3),
- Length(4), Length(5)),
- CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)),
- BoundCRS::create(verticalCRS1, verticalCRS2, vtransformation)});
- auto compound2 = CompoundCRS::create(
- PropertyMap(),
- std::vector<CRSNNPtr>{createUTM32_WGS84(), verticalCRS2});
-
- auto op = CoordinateOperationFactory::create()->createOperation(compound1,
- compound2);
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=tmerc +lat_0=1 +lon_0=2 +k=3 "
- "+x_0=4 +y_0=5 +ellps=WGS84 +step "
- "+proj=vgridshift +grids=bla.gtx +multiplier=0.001 +step "
- "+proj=utm +zone=32 "
- "+ellps=WGS84");
- {
- auto formatter = PROJStringFormatter::create();
- formatter->setUseApproxTMerc(true);
- EXPECT_EQ(
- op->exportToPROJString(formatter.get()),
- "+proj=pipeline +step +inv +proj=tmerc +approx +lat_0=1 +lon_0=2 "
- "+k=3 +x_0=4 +y_0=5 +ellps=WGS84 +step "
- "+proj=vgridshift +grids=bla.gtx +multiplier=0.001 +step "
- "+proj=utm +approx +zone=32 "
- "+ellps=WGS84");
- }
- {
- auto formatter = PROJStringFormatter::create();
- formatter->setUseApproxTMerc(true);
- EXPECT_EQ(
- op->inverse()->exportToPROJString(formatter.get()),
- "+proj=pipeline +step +inv +proj=utm +approx +zone=32 +ellps=WGS84 "
- "+step +inv +proj=vgridshift +grids=bla.gtx "
- "+multiplier=0.001 +step +proj=tmerc +approx +lat_0=1 +lon_0=2 "
- "+k=3 +x_0=4 +y_0=5 +ellps=WGS84");
- }
-
- auto opInverse = CoordinateOperationFactory::create()->createOperation(
- compound2, compound1);
- ASSERT_TRUE(opInverse != nullptr);
- {
- auto formatter = PROJStringFormatter::create();
- auto formatter2 = PROJStringFormatter::create();
- EXPECT_EQ(opInverse->inverse()->exportToPROJString(formatter.get()),
- op->exportToPROJString(formatter2.get()));
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=@foo.gsb "
- "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
- "+step +inv +proj=vgridshift +grids=@bar.gtx +multiplier=1 "
- "+step +inv +proj=hgridshift +grids=@bar.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_geoidgrids) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=@foo.gsb "
- "+step +inv +proj=hgridshift +grids=@bar.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_geoidgrids_different_vunits) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@foo.gtx "
- "+vunits=us-ft +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=@foo.gsb "
- "+step +proj=unitconvert +z_in=m +z_out=us-ft "
- "+step +inv +proj=hgridshift +grids=@bar.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_nadgrids_same_geoidgrids) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS80 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_towgs84_same_geoidgrids) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +towgs84=0,0,0 +geoidgrids=@foo.gtx "
- "+type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS80 +towgs84=0,0,0 +geoidgrids=@foo.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=GRS67 "
- "+step +inv +proj=cart +ellps=GRS80 "
- "+step +proj=pop +v_3 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_WKT1_same_geoidgrids_context) {
- auto objSrc = WKTParser().createFromWKT(
- "COMPD_CS[\"NAD83 / Alabama West + NAVD88 height - Geoid12B "
- "(Meters)\",\n"
- " PROJCS[\"NAD83 / Alabama West\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " PROJECTION[\"Transverse_Mercator\"],\n"
- " PARAMETER[\"latitude_of_origin\",30],\n"
- " PARAMETER[\"central_meridian\",-87.5],\n"
- " PARAMETER[\"scale_factor\",0.999933333],\n"
- " PARAMETER[\"false_easting\",600000],\n"
- " PARAMETER[\"false_northing\",0],\n"
- " UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"X\",EAST],\n"
- " AXIS[\"Y\",NORTH],\n"
- " AUTHORITY[\"EPSG\",\"26930\"]],\n"
- " VERT_CS[\"NAVD88 height\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " "
- "EXTENSION[\"PROJ4_GRIDS\",\"g2012a_alaska.gtx,g2012a_hawaii.gtx,"
- "g2012a_conus.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"5703\"]]]");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = WKTParser().createFromWKT(
- "COMPD_CS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet + NAVD88 "
- "height - Geoid12B (US Feet)\",\n"
- " PROJCS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0],\n"
- " UNIT[\"Degree\",0.0174532925199433]],\n"
- " PROJECTION[\"Transverse_Mercator\"],\n"
- " PARAMETER[\"latitude_of_origin\",30],\n"
- " PARAMETER[\"central_meridian\",-87.5],\n"
- " PARAMETER[\"scale_factor\",0.999933333333333],\n"
- " PARAMETER[\"false_easting\",1968500],\n"
- " PARAMETER[\"false_northing\",0],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Easting\",EAST],\n"
- " AXIS[\"Northing\",NORTH],\n"
- " AUTHORITY[\"ESRI\",\"102630\"]],\n"
- " VERT_CS[\"NAVD88 height (ftUS)\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " "
- "EXTENSION[\"PROJ4_GRIDS\",\"g2012a_alaska.gtx,g2012a_hawaii.gtx,"
- "g2012a_conus.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"US survey foot\",0.304800609601219,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"6360\"]]]");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of unnamed + "
- "Transformation from NAD83 to WGS84 + "
- "NAVD88 height to NAVD88 height (ftUS) + "
- "Inverse of Transformation from NAD83 to WGS84 + "
- "unnamed");
- auto grids = list[0]->gridsNeeded(dbContext, false);
- EXPECT_TRUE(grids.empty());
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=tmerc +lat_0=30 +lon_0=-87.5 +k=0.999933333 "
- "+x_0=600000 +y_0=0 +ellps=GRS80 "
- "+step +proj=unitconvert +z_in=m +z_out=us-ft "
- "+step +proj=tmerc +lat_0=30 +lon_0=-87.5 +k=0.999933333333333 "
- "+x_0=600000 +y_0=0 +ellps=GRS80 "
- "+step +proj=unitconvert +xy_in=m +xy_out=us-ft");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_compoundCRS_issue_2232) {
- auto objSrc = WKTParser().createFromWKT(
- "COMPD_CS[\"NAD83 / Alabama West + NAVD88 height - Geoid12B "
- "(Meters)\",\n"
- " PROJCS[\"NAD83 / Alabama West\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " PROJECTION[\"Transverse_Mercator\"],\n"
- " PARAMETER[\"latitude_of_origin\",30],\n"
- " PARAMETER[\"central_meridian\",-87.5],\n"
- " PARAMETER[\"scale_factor\",0.999933333],\n"
- " PARAMETER[\"false_easting\",600000],\n"
- " PARAMETER[\"false_northing\",0],\n"
- " UNIT[\"metre\",1,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"X\",EAST],\n"
- " AXIS[\"Y\",NORTH],\n"
- " AUTHORITY[\"EPSG\",\"26930\"]],\n"
- " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
- " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
- " EXTENSION[\"PROJ4_GRIDS\",\"foo.gtx\"],\n"
- " AUTHORITY[\"EPSG\",\"5103\"]],\n"
- " UNIT[\"metre\",1.0,\n"
- " AUTHORITY[\"EPSG\",\"9001\"]],\n"
- " AXIS[\"Gravity-related height\",UP],\n"
- " AUTHORITY[\"EPSG\",\"5703\"]]]");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = WKTParser().createFromWKT(
- "COMPD_CS[\"NAD83 + some CRS (US Feet)\",\n"
- " GEOGCS[\"NAD83\",\n"
- " DATUM[\"North_American_Datum_1983\",\n"
- " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
- " AUTHORITY[\"EPSG\",\"7019\"]],\n"
- " TOWGS84[0,0,0,0,0,0,0],\n"
- " AUTHORITY[\"EPSG\",\"6269\"]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " AUTHORITY[\"EPSG\",\"8901\"]],\n"
- " UNIT[\"degree\",0.0174532925199433,\n"
- " AUTHORITY[\"EPSG\",\"9122\"]],\n"
- " AUTHORITY[\"EPSG\",\"4269\"]],\n"
- " VERT_CS[\"some CRS (US Feet)\",\n"
- " VERT_DATUM[\"some datum\",2005],\n"
- " UNIT[\"US survey foot\",0.3048006096012192,\n"
- " AUTHORITY[\"EPSG\",\"9003\"]],\n"
- " AXIS[\"Up\",UP]]]");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst), ctxt);
- EXPECT_GE(list.size(), 1U);
-
- auto list2 = CoordinateOperationFactory::create()->createOperations(
- NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src), ctxt);
- EXPECT_EQ(list2.size(), list.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_compoundCRS_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NAD27 + NGVD29 height (ftUS)
- authFactory->createCoordinateReferenceSystem("7406"),
- // NAD83(NSRS2007) + NAVD88 height
- authFactory->createCoordinateReferenceSystem("5500"), ctxt);
- // 152 or 155 depending if the VERTCON grids are there
- ASSERT_GE(list.size(), 152U);
- EXPECT_FALSE(list[0]->hasBallparkTransformation());
- EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (ftUS) to NAVD88 height (3) + "
- "NAD27 to WGS 84 (79) + Inverse of "
- "NAD83(NSRS2007) to WGS 84 (1)");
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad +z_out=m "
- "+step +proj=vgridshift +grids=us_noaa_vertcone.tif +multiplier=1 "
- "+step +proj=hgridshift +grids=us_noaa_conus.tif +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
- "+order=2,1");
- {
- // Test that we can round-trip this through WKT and still get the same
- // PROJ string.
- auto wkt = list[0]->exportToWKT(
- WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get());
- auto obj = WKTParser().createFromWKT(wkt);
- auto co = nn_dynamic_pointer_cast<CoordinateOperation>(obj);
- ASSERT_TRUE(co != nullptr);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- co->exportToPROJString(PROJStringFormatter::create().get()));
- }
-
- bool foundApprox = false;
- for (size_t i = 0; i < list.size(); i++) {
- auto projString =
- list[i]->exportToPROJString(PROJStringFormatter::create().get());
- EXPECT_TRUE(
- projString.find("+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +z_in=us-ft "
- "+xy_out=rad +z_out=m") == 0)
- << list[i]->nameStr();
- if (list[i]->nameStr().find("Transformation from NGVD29 height (ftUS) "
- "to NAVD88 height (ballpark vertical "
- "transformation)") == 0) {
- EXPECT_TRUE(list[i]->hasBallparkTransformation());
- EXPECT_EQ(list[i]->nameStr(),
- "Transformation from NGVD29 height (ftUS) to NAVD88 "
- "height (ballpark vertical transformation) + NAD27 to "
- "WGS 84 (79) + Inverse of NAD83(NSRS2007) to WGS 84 (1)");
- EXPECT_EQ(
- projString,
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad "
- "+z_out=m +step +proj=hgridshift +grids=us_noaa_conus.tif "
- "+step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
- foundApprox = true;
- break;
- }
- }
- EXPECT_TRUE(foundApprox);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_compoundCRS_context_helmert_noop) {
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- // WGS84 + EGM96
- auto objSrc = createFromUserInput("EPSG:4326+5773", dbContext);
- auto srcCrs = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCrs != nullptr);
- // ETRS89 + EGM96
- auto objDest = createFromUserInput("EPSG:4258+5773", dbContext);
- auto destCrs = nn_dynamic_pointer_cast<CompoundCRS>(objDest);
- ASSERT_TRUE(destCrs != nullptr);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCrs), NN_NO_CHECK(destCrs), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=noop");
-}
-
-// ---------------------------------------------------------------------------
-
-// EGM96 has a geoid model referenced to WGS84, and Belfast height has a
-// geoid model referenced to ETRS89
-TEST(operation, compoundCRS_to_compoundCRS_WGS84_EGM96_to_ETRS89_Belfast) {
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- // WGS84 + EGM96
- auto objSrc = createFromUserInput("EPSG:4326+5773", dbContext);
- auto srcCrs = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCrs != nullptr);
- // ETRS89 + Belfast height
- auto objDest = createFromUserInput("EPSG:4258+5732", dbContext);
- auto destCrs = nn_dynamic_pointer_cast<CompoundCRS>(objDest);
- ASSERT_TRUE(destCrs != nullptr);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCrs), NN_NO_CHECK(destCrs), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
- "Inverse of ETRS89 to WGS 84 (1) + "
- "ETRS89 to Belfast height (2)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
- "+step +inv +proj=vgridshift +grids=uk_os_OSGM15_Belfast.tif "
- "+multiplier=1 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-// Variant of above where source intermediate geog3D CRS == target intermediate
-// geog3D CRS
-TEST(operation, compoundCRS_to_compoundCRS_WGS84_EGM96_to_WGS84_Belfast) {
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- // WGS84 + EGM96
- auto objSrc = createFromUserInput("EPSG:4326+5773", dbContext);
- auto srcCrs = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
- ASSERT_TRUE(srcCrs != nullptr);
- // WGS84 + Belfast height
- auto objDest = createFromUserInput("EPSG:4326+5732", dbContext);
- auto destCrs = nn_dynamic_pointer_cast<CompoundCRS>(objDest);
- ASSERT_TRUE(destCrs != nullptr);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCrs), NN_NO_CHECK(destCrs), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
- "Inverse of ETRS89 to WGS 84 (1) + "
- "ETRS89 to Belfast height (2) + "
- "ETRS89 to WGS 84 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
- "+step +inv +proj=vgridshift +grids=uk_os_OSGM15_Belfast.tif "
- "+multiplier=1 +step "
- "+proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_compoundCRS_concatenated_operation_with_two_vert_transformation) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // ETRS89 + Baltic 1957 height
- authFactory->createCoordinateReferenceSystem("8360"),
- // ETRS89 + EVRF2007 height
- authFactory->createCoordinateReferenceSystem("7423"), ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(
- list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift "
- "+grids=sk_gku_Slovakia_ETRS89h_to_Baltic1957.tif +multiplier=1 "
- "+step +inv +proj=vgridshift "
- "+grids=sk_gku_Slovakia_ETRS89h_to_EVRF2007.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- EXPECT_EQ(
- list[0]->nameStr(),
- "ETRS89 + Baltic 1957 height to ETRS89 + EVRF2007 height (1)");
- EXPECT_EQ(list[0]->inverse()->nameStr(), "Inverse of 'ETRS89 + Baltic "
- "1957 height to ETRS89 + "
- "EVRF2007 height (1)'");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, vertCRS_to_vertCRS) {
-
- auto vertcrs_m_obj = PROJStringParser().createFromPROJString("+vunits=m");
- auto vertcrs_m = nn_dynamic_pointer_cast<VerticalCRS>(vertcrs_m_obj);
- ASSERT_TRUE(vertcrs_m != nullptr);
-
- auto vertcrs_ft_obj = PROJStringParser().createFromPROJString("+vunits=ft");
- auto vertcrs_ft = nn_dynamic_pointer_cast<VerticalCRS>(vertcrs_ft_obj);
- ASSERT_TRUE(vertcrs_ft != nullptr);
-
- auto vertcrs_us_ft_obj =
- PROJStringParser().createFromPROJString("+vunits=us-ft");
- auto vertcrs_us_ft =
- nn_dynamic_pointer_cast<VerticalCRS>(vertcrs_us_ft_obj);
- ASSERT_TRUE(vertcrs_us_ft != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(vertcrs_m), NN_CHECK_ASSERT(vertcrs_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=unitconvert +z_in=m +z_out=ft");
- }
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(vertcrs_m), NN_CHECK_ASSERT(vertcrs_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->inverse()->exportToPROJString(
- PROJStringFormatter::create().get()),
- "+proj=unitconvert +z_in=ft +z_out=m");
- }
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(vertcrs_ft), NN_CHECK_ASSERT(vertcrs_m));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=unitconvert +z_in=ft +z_out=m");
- }
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(vertcrs_ft), NN_CHECK_ASSERT(vertcrs_us_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=affine +s33=0.999998");
- }
-
- auto vertCRSMetreUp =
- nn_dynamic_pointer_cast<VerticalCRS>(WKTParser().createFromWKT(
- "VERTCRS[\"my height\",VDATUM[\"my datum\"],CS[vertical,1],"
- "AXIS[\"gravity-related height (H)\",up,"
- "LENGTHUNIT[\"metre\",1]]]"));
- ASSERT_TRUE(vertCRSMetreUp != nullptr);
-
- auto vertCRSMetreDown =
- nn_dynamic_pointer_cast<VerticalCRS>(WKTParser().createFromWKT(
- "VERTCRS[\"my depth\",VDATUM[\"my datum\"],CS[vertical,1],"
- "AXIS[\"depth (D)\",down,LENGTHUNIT[\"metre\",1]]]"));
- ASSERT_TRUE(vertCRSMetreDown != nullptr);
-
- auto vertCRSMetreDownFtUS =
- nn_dynamic_pointer_cast<VerticalCRS>(WKTParser().createFromWKT(
- "VERTCRS[\"my depth (ftUS)\",VDATUM[\"my datum\"],CS[vertical,1],"
- "AXIS[\"depth (D)\",down,LENGTHUNIT[\"US survey "
- "foot\",0.304800609601219]]]"));
- ASSERT_TRUE(vertCRSMetreDownFtUS != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(vertCRSMetreUp), NN_CHECK_ASSERT(vertCRSMetreDown));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=axisswap +order=1,2,-3");
- }
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(vertCRSMetreUp),
- NN_CHECK_ASSERT(vertCRSMetreDownFtUS));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=affine +s33=-3.28083333333333");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, vertCRS_to_vertCRS_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NGVD29 height (m)
- authFactory->createCoordinateReferenceSystem("7968"),
- // NAVD88 height (1)
- authFactory->createCoordinateReferenceSystem("5703"), ctxt);
- ASSERT_EQ(list.size(), 3U);
- EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (m) to NAVD88 height (3)");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=vgridshift +grids=us_noaa_vertcone.tif +multiplier=1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, vertCRS_to_vertCRS_New_Zealand_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NZVD2016 height
- authFactory->createCoordinateReferenceSystem("7839"),
- // Auckland 1946 height
- authFactory->createCoordinateReferenceSystem("5759"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=vgridshift +grids=nz_linz_auckht1946-nzvd2016.tif "
- "+multiplier=1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, projCRS_3D_to_geogCRS_3D) {
-
- auto compoundcrs_ft_obj = PROJStringParser().createFromPROJString(
- "+proj=merc +vunits=ft +type=crs");
- auto proj3DCRS_ft = nn_dynamic_pointer_cast<CRS>(compoundcrs_ft_obj);
- ASSERT_TRUE(proj3DCRS_ft != nullptr);
-
- auto geogcrs_m_obj = PROJStringParser().createFromPROJString(
- "+proj=longlat +vunits=m +type=crs");
- auto geogcrs_m = nn_dynamic_pointer_cast<CRS>(geogcrs_m_obj);
- ASSERT_TRUE(geogcrs_m != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(proj3DCRS_ft), NN_CHECK_ASSERT(geogcrs_m));
- ASSERT_TRUE(op != nullptr);
- EXPECT_FALSE(op->hasBallparkTransformation());
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=m +z_in=ft "
- "+xy_out=m +z_out=m "
- "+step +inv +proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 "
- "+ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +z_in=m "
- "+xy_out=deg +z_out=m");
- }
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(proj3DCRS_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_FALSE(op->hasBallparkTransformation());
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +z_in=m +z_out=ft "
- "+step +proj=unitconvert +xy_in=deg +z_in=ft "
- "+xy_out=rad +z_out=m "
- "+step +proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=m +z_in=m "
- "+xy_out=m +z_out=ft");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS_3D) {
-
- auto compoundcrs_ft_obj = WKTParser().createFromWKT(
- "COMPOUNDCRS[\"unknown\",\n"
- " PROJCRS[\"unknown\",\n"
- " BASEGEOGCRS[\"unknown\",\n"
- " DATUM[\"World Geodetic System 1984\",\n"
- " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " ID[\"EPSG\",6326]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8901]]],\n"
- " CONVERSION[\"unknown\",\n"
- " METHOD[\"Mercator (variant A)\",\n"
- " ID[\"EPSG\",9804]],\n"
- " PARAMETER[\"Latitude of natural origin\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8801]],\n"
- " PARAMETER[\"Longitude of natural origin\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8802]],\n"
- " PARAMETER[\"Scale factor at natural origin\",1,\n"
- " SCALEUNIT[\"unity\",1],\n"
- " ID[\"EPSG\",8805]],\n"
- " PARAMETER[\"False easting\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8806]],\n"
- " PARAMETER[\"False northing\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8807]]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"(E)\",east,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"metre\",1,\n"
- " ID[\"EPSG\",9001]]],\n"
- " AXIS[\"(N)\",north,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"metre\",1,\n"
- " ID[\"EPSG\",9001]]]],\n"
- " VERTCRS[\"unknown\",\n"
- " VDATUM[\"unknown\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"foot\",0.3048,\n"
- " ID[\"EPSG\",9002]]]]]");
- auto compoundcrs_ft = nn_dynamic_pointer_cast<CRS>(compoundcrs_ft_obj);
- ASSERT_TRUE(compoundcrs_ft != nullptr);
-
- auto geogcrs_m_obj = PROJStringParser().createFromPROJString(
- "+proj=longlat +vunits=m +type=crs");
- auto geogcrs_m = nn_dynamic_pointer_cast<CRS>(geogcrs_m_obj);
- ASSERT_TRUE(geogcrs_m != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(compoundcrs_ft), NN_CHECK_ASSERT(geogcrs_m));
- ASSERT_TRUE(op != nullptr);
- EXPECT_TRUE(op->hasBallparkTransformation());
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=merc +lon_0=0 +k=1 +x_0=0 "
- "+y_0=0 +ellps=WGS84 +step +proj=unitconvert +xy_in=rad "
- "+z_in=ft +xy_out=deg +z_out=m");
- }
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(compoundcrs_ft));
- ASSERT_TRUE(op != nullptr);
- EXPECT_TRUE(op->hasBallparkTransformation());
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=unitconvert +xy_in=deg +z_in=m "
- "+xy_out=rad +z_out=ft +step +proj=merc +lon_0=0 +k=1 +x_0=0 "
- "+y_0=0 +ellps=WGS84");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS_3D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- // CompoundCRS to Geog3DCRS, with vertical unit change, but without
- // ellipsoid height <--> vertical height correction
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem(
- "7406"), // NAD27 + NGVD29 height (ftUS)
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_TRUE(list[0]->hasBallparkTransformation());
- EXPECT_EQ(list[0]->nameStr(),
- "NAD27 to WGS 84 (79) + Transformation from NGVD29 height "
- "(ftUS) to WGS 84 (ballpark vertical transformation, without "
- "ellipsoid height to vertical height correction)");
- EXPECT_EQ(list[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
- "+proj=unitconvert +xy_in=deg +xy_out=rad +step "
- "+proj=hgridshift +grids=us_noaa_conus.tif "
- "+step +proj=unitconvert "
- "+xy_in=rad +z_in=us-ft +xy_out=deg +z_out=m +step "
- "+proj=axisswap +order=2,1");
- }
-
- // CompoundCRS to Geog3DCRS, with same vertical unit, and with
- // direct ellipsoid height <--> vertical height correction and
- // direct horizontal transform (no-op here)
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto list = CoordinateOperationFactory::create()->createOperations(
- authFactory->createCoordinateReferenceSystem(
- "5500"), // NAD83(NSRS2007) + NAVD88 height
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of NAD83(NSRS2007) to NAVD88 height (1) + "
- "NAD83(NSRS2007) to WGS 84 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_noaa_geoid09_conus.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- EXPECT_EQ(list[0]->remarks(),
- "For NAD83(NSRS2007) to NAVD88 height (1) (EPSG:9173): Uses "
- "Geoid09 hybrid model. Replaced by 2012 model (CT code 6326)."
- "\n"
- "For NAD83(NSRS2007) to WGS 84 (1) (EPSG:15931): "
- "Approximation at the +/- 1m level assuming that "
- "NAD83(NSRS2007) is equivalent to WGS 84 within the accuracy "
- "of the transformation.");
- }
-
- // NAD83 + NAVD88 height --> WGS 84
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83 + NAVD88 height
- auto srcObj = createFromUserInput(
- "EPSG:4269+5703", authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- nnSrc,
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- ctxt);
- ASSERT_GE(list.size(), 2U);
-
- EXPECT_EQ(list[0]->nameStr(),
- "NAD83 to WGS 84 (1) + "
- "Inverse of NAD83(NSRS2007) to WGS 84 (1) + "
- "Inverse of NAD83(NSRS2007) to NAVD88 height (1) + "
- "NAD83(NSRS2007) to WGS 84 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_noaa_geoid09_conus.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
-
- // Another variation, but post horizontal adjustment is in two steps
- {
- auto ctxt =
- CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83(2011) + NAVD88 height
- auto srcObj = createFromUserInput(
- "EPSG:6318+5703", authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- nnSrc,
- authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
- ctxt);
- ASSERT_GE(list.size(), 2U);
-
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of NAD83(2011) to NAVD88 height (3) + "
- "Inverse of NAD83 to NAD83(2011) (1) + "
- "NAD83 to WGS 84 (1)");
- EXPECT_EQ(list[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_noaa_g2018u0.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-
- // Shows vertical step, and then horizontal step
- EXPECT_EQ(list[1]->nameStr(),
- "Inverse of NAD83(2011) to NAVD88 height (3) + "
- "Inverse of NAD83 to NAD83(2011) (1) + "
- "NAD83 to WGS 84 (18)");
- EXPECT_EQ(list[1]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_noaa_g2018u0.tif "
- "+multiplier=1 "
- "+step +proj=hgridshift +grids=us_noaa_FL.tif "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS_3D_with_3D_helmert_context) {
- // Use case of https://github.com/OSGeo/PROJ/issues/2225
- auto dbContext = DatabaseContext::create();
- auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // WGS84 + EGM96 height
- auto srcObj = createFromUserInput("EPSG:4326+5773", dbContext, false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src),
- // CH1903+
- authFactory->createCoordinateReferenceSystem("4150")->promoteTo3D(
- std::string(), dbContext),
- ctxt);
- ASSERT_GE(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
- "Inverse of CH1903+ to WGS 84 (1)");
- // Check that there is no push v_3 / pop v_3
- const char *expected_proj =
- "+proj=pipeline "
- "+step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=-674.374 +y=-15.056 +z=-405.346 "
- "+step +inv +proj=cart +ellps=bessel "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1";
- EXPECT_EQ(list[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5, dbContext)
- .get()),
- expected_proj);
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS_2D_promote_to_3D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83 + NAVD88 height
- auto srcObj = createFromUserInput("EPSG:4269+5703",
- authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
- auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
-
- auto listCompoundToGeog2D =
- CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
- ctxt);
- // The checked value is not that important, but in case this changes,
- // likely due to a EPSG upgrade, worth checking
- EXPECT_EQ(listCompoundToGeog2D.size(), 142U);
-
- auto listGeog2DToCompound =
- CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
- ctxt);
- EXPECT_EQ(listGeog2DToCompound.size(), listCompoundToGeog2D.size());
-
- auto listCompoundToGeog3D =
- CoordinateOperationFactory::create()->createOperations(
- nnSrc,
- dst->promoteTo3D(std::string(), authFactory->databaseContext()),
- ctxt);
- EXPECT_EQ(listCompoundToGeog3D.size(), listCompoundToGeog2D.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_of_projCRS_to_geogCRS_2D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // SPCS83 California zone 1 (US Survey feet) + NAVD88 height (ftUS)
- auto srcObj = createFromUserInput("EPSG:2225+6360",
- authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
- auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- nnSrc, dst, ctxt);
- // The checked value is not that important, but in case this changes,
- // likely due to a EPSG upgrade, worth checking
- // We want to make sure that the horizontal adjustments before and after
- // the vertical transformation are the reverse of each other, and there are
- // not mixes with different alternative operations (like California grid
- // forward and Nevada grid reverse)
- ASSERT_EQ(list.size(), 14U);
-
- // Check that unit conversion is OK
- auto op_proj =
- list[0]->exportToPROJString(PROJStringFormatter::create().get());
- EXPECT_EQ(op_proj,
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
- "+step +inv +proj=lcc +lat_0=39.3333333333333 +lon_0=-122 "
- "+lat_1=41.6666666666667 +lat_2=40 +x_0=2000000.0001016 "
- "+y_0=500000.0001016 +ellps=GRS80 "
- "+step +proj=unitconvert +z_in=us-ft +z_out=m "
- "+step +proj=vgridshift +grids=us_noaa_geoid09_conus.tif "
- "+multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_from_wkt_without_id_to_geogCRS) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto wkt =
- "COMPOUNDCRS[\"NAD83(2011) + NAVD88 height\",\n"
- " GEOGCRS[\"NAD83(2011)\",\n"
- " DATUM[\"NAD83 (National Spatial Reference System 2011)\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " CS[ellipsoidal,2],\n"
- " AXIS[\"geodetic latitude (Lat)\",north,\n"
- " ORDER[1],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
- " AXIS[\"geodetic longitude (Lon)\",east,\n"
- " ORDER[2],\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
- " VERTCRS[\"NAVD88 height\",\n"
- " VDATUM[\"North American Vertical Datum 1988\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"metre\",1]]]]";
- auto srcObj =
- createFromUserInput(wkt, authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto dst =
- authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011)
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), dst, ctxt);
- // NAD83(2011) + NAVD88 height
- auto srcRefObj = createFromUserInput("EPSG:6318+5703",
- authFactory->databaseContext(), false);
- auto srcRef = nn_dynamic_pointer_cast<CRS>(srcRefObj);
- ASSERT_TRUE(srcRef != nullptr);
- ASSERT_TRUE(
- src->isEquivalentTo(srcRef.get(), IComparable::Criterion::EQUIVALENT));
- auto listRef = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcRef), dst, ctxt);
-
- EXPECT_EQ(list.size(), listRef.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- compoundCRS_of_projCRS_from_wkt_without_id_or_extent_to_geogCRS) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto wkt =
- "COMPOUNDCRS[\"NAD83 / Pennsylvania South + NAVD88 height\",\n"
- " PROJCRS[\"NAD83 / Pennsylvania South\",\n"
- " BASEGEOGCRS[\"NAD83\",\n"
- " DATUM[\"North American Datum 1983\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
- " CONVERSION[\"SPCS83 Pennsylvania South zone (meters)\",\n"
- " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
- " ID[\"EPSG\",9802]],\n"
- " PARAMETER[\"Latitude of false origin\",39.3333333333333,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8821]],\n"
- " PARAMETER[\"Longitude of false origin\",-77.75,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8822]],\n"
- " PARAMETER[\"Latitude of 1st standard "
- "parallel\",40.9666666666667,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8823]],\n"
- " PARAMETER[\"Latitude of 2nd standard "
- "parallel\",39.9333333333333,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8824]],\n"
- " PARAMETER[\"Easting at false origin\",600000,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8826]],\n"
- " PARAMETER[\"Northing at false origin\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8827]]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"easting (X)\",east,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " AXIS[\"northing (Y)\",north,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " VERTCRS[\"NAVD88 height\",\n"
- " VDATUM[\"North American Vertical Datum 1988\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"metre\",1]]]]";
- auto srcObj =
- createFromUserInput(wkt, authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), dst, ctxt);
- // NAD83 / Pennsylvania South + NAVD88 height
- auto srcRefObj = createFromUserInput("EPSG:32129+5703",
- authFactory->databaseContext(), false);
- auto srcRef = nn_dynamic_pointer_cast<CRS>(srcRefObj);
- ASSERT_TRUE(srcRef != nullptr);
- ASSERT_TRUE(
- src->isEquivalentTo(srcRef.get(), IComparable::Criterion::EQUIVALENT));
- auto listRef = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcRef), dst, ctxt);
-
- EXPECT_EQ(list.size(), listRef.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS_with_vertical_unit_change) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83(2011) + NAVD88 height (ftUS)
- auto srcObj = createFromUserInput("EPSG:6318+6360",
- authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
- auto dst =
- authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011) 3D
-
- auto listCompoundToGeog =
- CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
- ctxt);
- ASSERT_TRUE(!listCompoundToGeog.empty());
-
- // NAD83(2011) + NAVD88 height
- auto srcObjCompoundVMetre = createFromUserInput(
- "EPSG:6318+5703", authFactory->databaseContext(), false);
- auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
- ASSERT_TRUE(srcCompoundVMetre != nullptr);
- auto listCompoundMetreToGeog =
- CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
-
- // Check that we get the same and similar results whether we start from
- // regular NAVD88 height or its ftUs variant
- ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
-
- EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
- "Inverse of NAVD88 height to NAVD88 height (ftUS) + " +
- listCompoundMetreToGeog[0]->nameStr());
- EXPECT_EQ(
- listCompoundToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
- "+step +proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad "
- "+z_out=m"));
-
- // Check reverse path
- auto listGeogToCompound =
- CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
- ctxt);
- EXPECT_EQ(listGeogToCompound.size(), listCompoundToGeog.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_geogCRS_with_vertical_unit_change_and_complex_horizontal_change) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83(2011) + NAVD88 height (ftUS)
- auto srcObj = createFromUserInput("EPSG:6318+6360",
- authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
- auto dst =
- authFactory->createCoordinateReferenceSystem("7665"); // WGS84(G1762) 3D
-
- auto listCompoundToGeog =
- CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
- ctxt);
-
- // NAD83(2011) + NAVD88 height
- auto srcObjCompoundVMetre = createFromUserInput(
- "EPSG:6318+5703", authFactory->databaseContext(), false);
- auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
- ASSERT_TRUE(srcCompoundVMetre != nullptr);
- auto listCompoundMetreToGeog =
- CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
-
- // Check that we get the same and similar results whether we start from
- // regular NAVD88 height or its ftUs variant
- ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
-
- ASSERT_GE(listCompoundToGeog.size(), 1U);
-
- EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
- "Inverse of NAVD88 height to NAVD88 height (ftUS) + " +
- listCompoundMetreToGeog[0]->nameStr());
- EXPECT_EQ(
- listCompoundToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
- "+step +proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad "
- "+z_out=m"));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_to_geogCRS_with_height_depth_reversal) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83(2011) + NAVD88 depth
- auto srcObj = createFromUserInput("EPSG:6318+6357",
- authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
- auto dst =
- authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011) 3D
-
- auto listCompoundToGeog =
- CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
- ctxt);
- ASSERT_TRUE(!listCompoundToGeog.empty());
-
- // NAD83(2011) + NAVD88 height
- auto srcObjCompoundVMetre = createFromUserInput(
- "EPSG:6318+5703", authFactory->databaseContext(), false);
- auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
- ASSERT_TRUE(srcCompoundVMetre != nullptr);
- auto listCompoundMetreToGeog =
- CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
-
- // Check that we get the same and similar results whether we start from
- // regular NAVD88 height or its depth variant
- ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
-
- EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
- "Inverse of NAVD88 height to NAVD88 depth + " +
- listCompoundMetreToGeog[0]->nameStr());
- EXPECT_EQ(
- listCompoundToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=axisswap +order=1,2,-3"));
-
- // Check reverse path
- auto listGeogToCompound =
- CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
- ctxt);
- EXPECT_EQ(listGeogToCompound.size(), listCompoundToGeog.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- compoundCRS_to_geogCRS_with_vertical_unit_change_and_height_depth_reversal) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- // NAD83(2011) + NAVD88 depth (ftUS)
- auto srcObj = createFromUserInput("EPSG:6318+6358",
- authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto nnSrc = NN_NO_CHECK(src);
- auto dst =
- authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011) 3D
-
- auto listCompoundToGeog =
- CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
- ctxt);
- ASSERT_TRUE(!listCompoundToGeog.empty());
-
- // NAD83(2011) + NAVD88 height
- auto srcObjCompoundVMetre = createFromUserInput(
- "EPSG:6318+5703", authFactory->databaseContext(), false);
- auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
- ASSERT_TRUE(srcCompoundVMetre != nullptr);
- auto listCompoundMetreToGeog =
- CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
-
- // Check that we get the same and similar results whether we start from
- // regular NAVD88 height or its depth (ftUS) variant
- ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
-
- EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
- "Inverse of NAVD88 height (ftUS) to NAVD88 depth (ftUS) + "
- "Inverse of NAVD88 height to NAVD88 height (ftUS) + " +
- listCompoundMetreToGeog[0]->nameStr());
- EXPECT_EQ(
- listCompoundToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
- PROJStringFormatter::create(
- PROJStringFormatter::Convention::PROJ_5,
- authFactory->databaseContext())
- .get()),
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=axisswap +order=1,2,-3 "
- "+step +proj=unitconvert +z_in=us-ft +z_out=m"));
-
- // Check reverse path
- auto listGeogToCompound =
- CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
- ctxt);
- EXPECT_EQ(listGeogToCompound.size(), listCompoundToGeog.size());
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_of_vertCRS_with_geoid_model_to_geogCRS) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- auto wkt =
- "COMPOUNDCRS[\"NAD83 / Pennsylvania South + NAVD88 height\",\n"
- " PROJCRS[\"NAD83 / Pennsylvania South\",\n"
- " BASEGEOGCRS[\"NAD83\",\n"
- " DATUM[\"North American Datum 1983\",\n"
- " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
- " CONVERSION[\"SPCS83 Pennsylvania South zone (meters)\",\n"
- " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
- " ID[\"EPSG\",9802]],\n"
- " PARAMETER[\"Latitude of false origin\",39.3333333333333,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8821]],\n"
- " PARAMETER[\"Longitude of false origin\",-77.75,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8822]],\n"
- " PARAMETER[\"Latitude of 1st standard "
- "parallel\",40.9666666666667,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8823]],\n"
- " PARAMETER[\"Latitude of 2nd standard "
- "parallel\",39.9333333333333,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8824]],\n"
- " PARAMETER[\"Easting at false origin\",600000,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8826]],\n"
- " PARAMETER[\"Northing at false origin\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8827]]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"easting (X)\",east,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " AXIS[\"northing (Y)\",north,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " VERTCRS[\"NAVD88 height\",\n"
- " VDATUM[\"North American Vertical Datum 1988\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " GEOIDMODEL[\"GEOID12B\"]]]";
- auto srcObj =
- createFromUserInput(wkt, authFactory->databaseContext(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
- ASSERT_TRUE(src != nullptr);
- auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
-
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), dst, ctxt);
- ASSERT_TRUE(!list.empty());
- EXPECT_EQ(list[0]->nameStr(),
- "Inverse of SPCS83 Pennsylvania South zone (meters) + "
- "Ballpark geographic offset from NAD83 to NAD83(2011) + "
- "Inverse of NAD83(2011) to NAVD88 height (1) + "
- "Ballpark geographic offset from NAD83(2011) to NAD83");
- auto op_proj =
- list[0]->exportToPROJString(PROJStringFormatter::create().get());
- EXPECT_EQ(
- op_proj,
- "+proj=pipeline "
- "+step +inv +proj=lcc +lat_0=39.3333333333333 +lon_0=-77.75 "
- "+lat_1=40.9666666666667 +lat_2=39.9333333333333 +x_0=600000 "
- "+y_0=0 +ellps=GRS80 "
- "+step +proj=vgridshift +grids=us_noaa_g2012bu0.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_from_WKT2_to_geogCRS_3D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto src = authFactory->createCoordinateReferenceSystem(
- "7415"); // Amersfoort / RD New + NAP height
- auto dst =
- authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_GE(list.size(), 1U);
- auto wkt2 = src->exportToWKT(
- WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get());
- auto obj = WKTParser().createFromWKT(wkt2);
- auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
- ASSERT_TRUE(src_from_wkt2 != nullptr);
- auto list2 = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src_from_wkt2), dst, ctxt);
- ASSERT_GE(list.size(), list2.size());
- for (size_t i = 0; i < list.size(); i++) {
- const auto &op = list[i];
- const auto &op2 = list2[i];
- EXPECT_TRUE(
- op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT));
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_from_WKT2_no_id_to_geogCRS_3D_context) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto src = authFactory->createCoordinateReferenceSystem(
- "7415"); // Amersfoort / RD New + NAP height
- auto dst =
- authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D
- auto list =
- CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
- ASSERT_GE(list.size(), 1U);
-
- {
- auto op_proj =
- list[0]->exportToPROJString(PROJStringFormatter::create().get());
- EXPECT_EQ(
- op_proj,
- "+proj=pipeline +step +inv +proj=sterea +lat_0=52.1561605555556 "
- "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 "
- "+ellps=bessel "
- "+step +proj=hgridshift +grids=nl_nsgi_rdtrans2018.tif "
- "+step +proj=vgridshift +grids=nl_nsgi_nlgeo2018.tif +multiplier=1 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
- }
-
- auto wkt2 =
- "COMPOUNDCRS[\"unknown\",\n"
- " PROJCRS[\"unknown\",\n"
- " BASEGEOGCRS[\"Amersfoort\",\n"
- " DATUM[\"Amersfoort\",\n"
- " ELLIPSOID[\"Bessel "
- "1841\",6377397.155,299.1528128]]],\n"
- " CONVERSION[\"unknown\",\n"
- " METHOD[\"Oblique Stereographic\"],\n"
- " PARAMETER[\"Latitude of natural origin\",52.1561605555556],\n"
- " PARAMETER[\"Longitude of natural origin\",5.38763888888889],\n"
- " PARAMETER[\"Scale factor at natural origin\",0.9999079],\n"
- " PARAMETER[\"False easting\",155000],\n"
- " PARAMETER[\"False northing\",463000]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"(E)\",east],\n"
- " AXIS[\"(N)\",north],\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " VERTCRS[\"NAP height\",\n"
- " VDATUM[\"Normaal Amsterdams Peil\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"metre\",1]]],\n"
- " USAGE[\n"
- " SCOPE[\"unknown\"],\n"
- " AREA[\"Netherlands - onshore\"],\n"
- " BBOX[50.75,3.2,53.7,7.22]]]";
-
- auto obj = WKTParser().createFromWKT(wkt2);
- auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
- ASSERT_TRUE(src_from_wkt2 != nullptr);
- auto list2 = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src_from_wkt2), dst, ctxt);
- ASSERT_EQ(list.size(), list2.size());
- for (size_t i = 0; i < list.size(); i++) {
- const auto &op = list[i];
- const auto &op2 = list2[i];
- auto op_proj =
- op->exportToPROJString(PROJStringFormatter::create().get());
- auto op2_proj =
- op2->exportToPROJString(PROJStringFormatter::create().get());
- EXPECT_EQ(op_proj, op2_proj) << "op=" << op->nameStr()
- << " op2=" << op2->nameStr();
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, proj3DCRS_with_non_meter_horiz_and_vertical_to_geog) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=31 +datum=WGS84 +units=us-ft +vunits=us-ft +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), authFactory->createCoordinateReferenceSystem("4326"),
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- // Check that vertical unit conversion is done just once
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=us-ft +z_in=us-ft "
- "+xy_out=m +z_out=m "
- "+step +inv +proj=utm +zone=31 +ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, compoundCRS_with_non_meter_horiz_and_vertical_to_geog) {
- auto objSrc = WKTParser().createFromWKT(
- "COMPOUNDCRS[\"unknown\",\n"
- " PROJCRS[\"unknown\",\n"
- " BASEGEOGCRS[\"unknown\",\n"
- " DATUM[\"World Geodetic System 1984\",\n"
- " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
- " LENGTHUNIT[\"metre\",1]],\n"
- " ID[\"EPSG\",6326]],\n"
- " PRIMEM[\"Greenwich\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8901]]],\n"
- " CONVERSION[\"UTM zone 31N\",\n"
- " METHOD[\"Transverse Mercator\",\n"
- " ID[\"EPSG\",9807]],\n"
- " PARAMETER[\"Latitude of natural origin\",0,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8801]],\n"
- " PARAMETER[\"Longitude of natural origin\",3,\n"
- " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
- " ID[\"EPSG\",8802]],\n"
- " PARAMETER[\"Scale factor at natural origin\",0.9996,\n"
- " SCALEUNIT[\"unity\",1],\n"
- " ID[\"EPSG\",8805]],\n"
- " PARAMETER[\"False easting\",500000,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8806]],\n"
- " PARAMETER[\"False northing\",0,\n"
- " LENGTHUNIT[\"metre\",1],\n"
- " ID[\"EPSG\",8807]],\n"
- " ID[\"EPSG\",16031]],\n"
- " CS[Cartesian,2],\n"
- " AXIS[\"(E)\",east,\n"
- " ORDER[1],\n"
- " LENGTHUNIT[\"US survey foot\",0.304800609601219,\n"
- " ID[\"EPSG\",9003]]],\n"
- " AXIS[\"(N)\",north,\n"
- " ORDER[2],\n"
- " LENGTHUNIT[\"US survey foot\",0.304800609601219,\n"
- " ID[\"EPSG\",9003]]]],\n"
- " VERTCRS[\"unknown\",\n"
- " VDATUM[\"unknown\"],\n"
- " CS[vertical,1],\n"
- " AXIS[\"gravity-related height (H)\",up,\n"
- " LENGTHUNIT[\"US survey foot\",0.304800609601219,\n"
- " ID[\"EPSG\",9003]]]]]"
-
- );
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- auto list = CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(src), authFactory->createCoordinateReferenceSystem("4326"),
- ctxt);
- ASSERT_EQ(list.size(), 1U);
- // Check that vertical unit conversion is done just once
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
- "+step +inv +proj=utm +zone=31 +ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +z_in=us-ft "
- "+xy_out=deg +z_out=m "
- "+step +proj=axisswap +order=2,1");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, boundCRS_to_compoundCRS) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx "
- "+type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=hgridshift +grids=@foo.gsb "
- "+step +inv +proj=vgridshift +grids=@bar.gtx +multiplier=1 "
- "+step +inv +proj=hgridshift +grids=@bar.gsb "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-
- auto opInverse = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src));
- ASSERT_TRUE(opInverse != nullptr);
- EXPECT_TRUE(opInverse->inverse()->_isEquivalentTo(op.get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, IGNF_LAMB1_TO_EPSG_4326) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), std::string());
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setGridAvailabilityUse(
- CoordinateOperationContext::GridAvailabilityUse::
- IGNORE_GRID_AVAILABILITY);
- ctxt->setAllowUseIntermediateCRS(
- CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
- auto list = CoordinateOperationFactory::create()->createOperations(
- AuthorityFactory::create(DatabaseContext::create(), "IGNF")
- ->createCoordinateReferenceSystem("LAMB1"),
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("4326"),
- ctxt);
- ASSERT_EQ(list.size(), 2U);
-
- EXPECT_FALSE(list[0]->hasBallparkTransformation());
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=lcc +lat_1=49.5 +lat_0=49.5 "
- "+lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 "
- "+ellps=clrk80ign +pm=paris +step +proj=hgridshift "
- "+grids=fr_ign_ntf_r93.tif +step +proj=unitconvert +xy_in=rad "
- "+xy_out=deg +step +proj=axisswap +order=2,1");
-
- EXPECT_FALSE(list[1]->hasBallparkTransformation());
- EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=lcc +lat_1=49.5 +lat_0=49.5 "
- "+lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 "
- "+ellps=clrk80ign +pm=paris +step +proj=push +v_3 +step "
- "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 +y=-60 "
- "+z=320 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step "
- "+proj=axisswap +order=2,1");
-
- auto list2 = CoordinateOperationFactory::create()->createOperations(
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- // NTF (Paris) / Lambert Nord France equivalent to IGNF:LAMB1
- ->createCoordinateReferenceSystem("27561"),
- AuthorityFactory::create(DatabaseContext::create(), "EPSG")
- ->createCoordinateReferenceSystem("4326"),
- ctxt);
- ASSERT_GE(list2.size(), 3U);
-
- EXPECT_EQ(replaceAll(list2[0]->exportToPROJString(
- PROJStringFormatter::create().get()),
- "0.999877341", "0.99987734"),
- list[0]->exportToPROJString(PROJStringFormatter::create().get()));
-
- // The second entry in list2 (list2[1]) uses the
- // weird +pm=2.33720833333333 from "NTF (Paris) to NTF (2)"
- // so skip to the 3th method
- EXPECT_EQ(replaceAll(list2[2]->exportToPROJString(
- PROJStringFormatter::create().get()),
- "0.999877341", "0.99987734"),
- list[1]->exportToPROJString(PROJStringFormatter::create().get()));
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, NAD83_to_projeted_CRS_based_on_NAD83_2011) {
- auto authFactory =
- AuthorityFactory::create(DatabaseContext::create(), "EPSG");
- auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
- ctxt->setSpatialCriterion(
- CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list = CoordinateOperationFactory::create()->createOperations(
- // NAD83
- authFactory->createCoordinateReferenceSystem("4269"),
- // NAD83(2011) / California Albers
- authFactory->createCoordinateReferenceSystem("6414"), ctxt);
- ASSERT_EQ(list.size(), 1U);
- EXPECT_EQ(list[0]->nameStr(), "Ballpark geographic offset from NAD83 to "
- "NAD83(2011) + California Albers");
- EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=aea +lat_0=0 +lon_0=-120 +lat_1=34 "
- "+lat_2=40.5 +x_0=0 +y_0=-4000000 +ellps=GRS80");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, isPROJInstantiable) {
-
- {
- auto transformation = Transformation::createGeocentricTranslations(
- PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326,
- 1.0, 2.0, 3.0, {});
- EXPECT_TRUE(transformation->isPROJInstantiable(
- DatabaseContext::create(), false));
- }
-
- // Missing grid
- {
- auto transformation = Transformation::createNTv2(
- PropertyMap(), GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326,
- "foo.gsb", std::vector<PositionalAccuracyNNPtr>());
- EXPECT_FALSE(transformation->isPROJInstantiable(
- DatabaseContext::create(), false));
- }
-
- // Unsupported method
- {
- auto transformation = Transformation::create(
- PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326,
- nullptr, OperationMethod::create(
- PropertyMap(), std::vector<OperationParameterNNPtr>{}),
- std::vector<GeneralParameterValueNNPtr>{},
- std::vector<PositionalAccuracyNNPtr>{});
- EXPECT_FALSE(transformation->isPROJInstantiable(
- DatabaseContext::create(), false));
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, createOperation_on_crs_with_canonical_bound_crs) {
- auto boundCRS = BoundCRS::createFromTOWGS84(
- GeographicCRS::EPSG_4267, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
- auto crs = boundCRS->baseCRSWithCanonicalBoundCRS();
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- crs, GeographicCRS::EPSG_4326);
- ASSERT_TRUE(op != nullptr);
- EXPECT_TRUE(op->isEquivalentTo(boundCRS->transformation().get()));
- {
- auto wkt1 = op->exportToWKT(
- WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
- .get());
- auto wkt2 = boundCRS->transformation()->exportToWKT(
- WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
- .get());
- EXPECT_EQ(wkt1, wkt2);
- }
- }
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4326, crs);
- ASSERT_TRUE(op != nullptr);
- EXPECT_TRUE(
- op->isEquivalentTo(boundCRS->transformation()->inverse().get()));
- {
- auto wkt1 = op->exportToWKT(
- WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
- .get());
- auto wkt2 = boundCRS->transformation()->inverse()->exportToWKT(
- WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
- .get());
- EXPECT_EQ(wkt1, wkt2);
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, createOperation_fallback_to_proj4_strings) {
- auto objDest = PROJStringParser().createFromPROJString(
- "+proj=longlat +geoc +datum=WGS84 +type=crs");
- auto dest = nn_dynamic_pointer_cast<GeographicCRS>(objDest);
- ASSERT_TRUE(dest != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- GeographicCRS::EPSG_4326, NN_CHECK_ASSERT(dest));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=longlat +geoc +datum=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- createOperation_fallback_to_proj4_strings_regular_with_datum_to_projliteral) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=11 +datum=NAD27 +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +over +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=11 +datum=NAD27 "
- "+step +proj=longlat +datum=WGS84 +over "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- createOperation_fallback_to_proj4_strings_proj_NAD83_to_projliteral) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=11 +datum=NAD83 +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +over +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=11 +ellps=GRS80 "
- "+step +proj=longlat +datum=WGS84 +over "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- createOperation_fallback_to_proj4_strings_geog_NAD83_to_projliteral) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=NAD83 +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +over +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=longlat +datum=WGS84 +over "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- createOperation_fallback_to_proj4_strings_regular_with_nadgrids_to_projliteral) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=11 +ellps=clrk66 +nadgrids=@conus +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +over +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=11 +ellps=clrk66 +nadgrids=@conus "
- "+step +proj=longlat +datum=WGS84 +over "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation,
- createOperation_fallback_to_proj4_strings_projliteral_to_projliteral) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=11 +datum=NAD27 +over +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +over +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline "
- "+step +inv +proj=utm +zone=11 +datum=NAD27 +over "
- "+step +proj=longlat +datum=WGS84 +over "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(
- operation,
- createOperation_fallback_to_proj4_strings_regular_to_projliteral_with_towgs84) {
- auto objSrc =
- createFromUserInput("EPSG:4326", DatabaseContext::create(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=31 +ellps=GRS80 +towgs84=1,2,3 +over +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=utm +zone=31 +ellps=GRS80 +towgs84=1,2,3 +over");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, createOperation_on_crs_with_bound_crs_and_wktext) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
- "+units=m +no_defs +nadgrids=@GDA94_GDA2020_conformal.gsb +ignored1 "
- "+ignored2=val +wktext +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
- "+units=m +no_defs +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +inv +proj=utm +zone=55 +south "
- "+ellps=GRS80 +step +proj=hgridshift "
- "+grids=@GDA94_GDA2020_conformal.gsb +step +proj=utm +zone=55 "
- "+south +ellps=GRS80");
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, createOperation_ossfuzz_18587) {
- auto objSrc =
- createFromUserInput("EPSG:4326", DatabaseContext::create(), false);
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
-
- // Extremely weird string ! We should likely reject it
- auto objDst = PROJStringParser().createFromPROJString(
- "type=crs proj=pipeline step proj=merc vunits=m nadgrids=@x "
- "proj=\"\nproj=pipeline step\n\"");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- // Just check that we don't go into an infinite recursion
- try {
- CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- } catch (const std::exception &) {
- }
-}
-
-// ---------------------------------------------------------------------------
-
-TEST(operation, derivedGeographicCRS_with_to_wgs84_to_geographicCRS) {
- auto objSrc = PROJStringParser().createFromPROJString(
- "+proj=ob_tran +o_proj=latlon +lat_0=0 +lon_0=180 +o_lat_p=18.0 "
- "+o_lon_p=-200.0 +ellps=WGS84 +towgs84=1,2,3 +type=crs");
- auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
- ASSERT_TRUE(src != nullptr);
- auto objDst = PROJStringParser().createFromPROJString(
- "+proj=longlat +datum=WGS84 +type=crs");
- auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
- ASSERT_TRUE(dst != nullptr);
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
- ASSERT_TRUE(op != nullptr);
- std::string pipeline(
- "+proj=pipeline "
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +inv +proj=ob_tran +o_proj=latlon +lat_0=0 +lon_0=180 "
- "+o_lat_p=18 +o_lon_p=-200 +ellps=WGS84 "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=1 +y=2 +z=3 "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=pop +v_3 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- pipeline);
-
- auto op2 = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(src),
- nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4326));
- ASSERT_TRUE(op2 != nullptr);
- EXPECT_EQ(op2->exportToPROJString(PROJStringFormatter::create().get()),
- pipeline + " +step +proj=axisswap +order=2,1");
- }
-
- {
- auto op = CoordinateOperationFactory::create()->createOperation(
- NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src));
- ASSERT_TRUE(op != nullptr);
- std::string pipeline(
- "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
- "+step +proj=push +v_3 "
- "+step +proj=cart +ellps=WGS84 "
- "+step +proj=helmert +x=-1 +y=-2 +z=-3 "
- "+step +inv +proj=cart +ellps=WGS84 "
- "+step +proj=pop +v_3 "
- "+step +proj=ob_tran +o_proj=latlon +lat_0=0 +lon_0=180 "
- "+o_lat_p=18 +o_lon_p=-200 +ellps=WGS84 "
- "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
- EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline " + pipeline);
-
- auto op2 = CoordinateOperationFactory::create()->createOperation(
- nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4326),
- NN_CHECK_ASSERT(src));
- ASSERT_TRUE(op2 != nullptr);
- EXPECT_EQ(op2->exportToPROJString(PROJStringFormatter::create().get()),
- "+proj=pipeline +step +proj=axisswap +order=2,1 " + pipeline);
- }
-}
-
-// ---------------------------------------------------------------------------
-
TEST(operation, geographic_topocentric) {
auto wkt =
"PROJCRS[\"EPSG topocentric example A\",\n"
diff --git a/test/unit/test_operationfactory.cpp b/test/unit/test_operationfactory.cpp
new file mode 100644
index 00000000..b71c3d66
--- /dev/null
+++ b/test/unit/test_operationfactory.cpp
@@ -0,0 +1,5954 @@
+/******************************************************************************
+ *
+ * Project: PROJ
+ * Purpose: Test ISO19111:2019 implementation
+ * Author: Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "gtest_include.h"
+
+#include "test_primitives.hpp"
+
+// to be able to use internal::replaceAll
+#ifndef FROM_PROJ_CPP
+#define FROM_PROJ_CPP
+#endif
+
+#include "proj/common.hpp"
+#include "proj/coordinateoperation.hpp"
+#include "proj/coordinatesystem.hpp"
+#include "proj/crs.hpp"
+#include "proj/datum.hpp"
+#include "proj/io.hpp"
+#include "proj/metadata.hpp"
+#include "proj/util.hpp"
+
+#include "proj/internal/internal.hpp"
+
+#include "proj_constants.h"
+
+#include <string>
+#include <vector>
+
+using namespace osgeo::proj::common;
+using namespace osgeo::proj::crs;
+using namespace osgeo::proj::cs;
+using namespace osgeo::proj::datum;
+using namespace osgeo::proj::io;
+using namespace osgeo::proj::internal;
+using namespace osgeo::proj::metadata;
+using namespace osgeo::proj::operation;
+using namespace osgeo::proj::util;
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(
+ op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv +proj=longlat "
+ "+ellps=clrk80ign +pm=paris +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_default) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setAllowUseIntermediateCRS(
+ CoordinateOperationContext::IntermediateCRSUse::NEVER);
+
+ // Directly found in database
+ {
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4179"), // Pulkovo 42
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
+ ctxt);
+ ASSERT_EQ(list.size(), 3U);
+ // Romania has a larger area than Poland (given our approx formula)
+ EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m
+ EXPECT_EQ(list[1]->getEPSGCode(), 1644); // Poland - 1m
+ EXPECT_EQ(list[2]->nameStr(),
+ "Ballpark geographic offset from Pulkovo 1942(58) to ETRS89");
+
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=krass +step +proj=helmert +x=2.3287 "
+ "+y=-147.0425 +z=-92.0802 +rx=0.3092483 +ry=-0.32482185 "
+ "+rz=-0.49729934 +s=5.68906266 +convention=coordinate_frame +step "
+ "+inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+ }
+
+ // Reverse case
+ {
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4258"),
+ authFactory->createCoordinateReferenceSystem("4179"), ctxt);
+ ASSERT_EQ(list.size(), 3U);
+ // Romania has a larger area than Poland (given our approx formula)
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of Pulkovo 1942(58) to ETRS89 (4)"); // Romania - 3m
+
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=GRS80 +step +inv +proj=helmert +x=2.3287 "
+ "+y=-147.0425 +z=-92.0802 +rx=0.3092483 +ry=-0.32482185 "
+ "+rz=-0.49729934 +s=5.68906266 +convention=coordinate_frame +step "
+ "+inv +proj=cart +ellps=krass +step +proj=pop +v_3 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_match_by_name) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setAllowUseIntermediateCRS(
+ CoordinateOperationContext::IntermediateCRSUse::NEVER);
+ auto NAD27 = GeographicCRS::create(
+ PropertyMap().set(IdentifiedObject::NAME_KEY,
+ GeographicCRS::EPSG_4267->nameStr()),
+ GeographicCRS::EPSG_4267->datum(),
+ GeographicCRS::EPSG_4267->datumEnsemble(),
+ GeographicCRS::EPSG_4267->coordinateSystem());
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NAD27, GeographicCRS::EPSG_4326, ctxt);
+ auto listInv = CoordinateOperationFactory::create()->createOperations(
+ GeographicCRS::EPSG_4326, NAD27, ctxt);
+ auto listRef = CoordinateOperationFactory::create()->createOperations(
+ GeographicCRS::EPSG_4267, GeographicCRS::EPSG_4326, ctxt);
+ EXPECT_EQ(list.size(), listRef.size());
+ EXPECT_EQ(listInv.size(), listRef.size());
+ EXPECT_GE(listRef.size(), 2U);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_filter_accuracy) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 1.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4179"),
+ authFactory->createCoordinateReferenceSystem("4258"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->getEPSGCode(), 1644); // Poland - 1m
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.9);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4179"),
+ authFactory->createCoordinateReferenceSystem("4258"), ctxt);
+ ASSERT_EQ(list.size(), 0U);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_filter_bbox) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // INSERT INTO "area" VALUES('EPSG','1197','Romania','Romania - onshore and
+ // offshore.',43.44,48.27,20.26,31.41,0);
+ {
+ auto ctxt = CoordinateOperationContext::create(
+ authFactory, Extent::createFromBBOX(20.26, 43.44, 31.41, 48.27),
+ 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4179"),
+ authFactory->createCoordinateReferenceSystem("4258"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m
+ }
+ {
+ auto ctxt = CoordinateOperationContext::create(
+ authFactory, Extent::createFromBBOX(20.26 + .1, 43.44 + .1,
+ 31.41 - .1, 48.27 - .1),
+ 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4179"),
+ authFactory->createCoordinateReferenceSystem("4258"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->getEPSGCode(), 15994); // Romania - 3m
+ }
+ {
+ auto ctxt = CoordinateOperationContext::create(
+ authFactory, Extent::createFromBBOX(20.26 - .1, 43.44 - .1,
+ 31.41 + .1, 48.27 + .1),
+ 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4179"),
+ authFactory->createCoordinateReferenceSystem("4258"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_incompatible_area) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4267"), // NAD27
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS 89
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_inverse_needed) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setUsePROJAlternativeGridNames(false);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4275"), // NTF
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 "
+ "+y=-60 +z=320 +step +inv +proj=cart +ellps=GRS80 +step +proj=pop "
+ "+v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step "
+ "+proj=axisswap +order=2,1");
+ EXPECT_EQ(list[1]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step "
+ "+proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
+ "+proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4275"), // NTF
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step "
+ "+proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
+ "+proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
+ authFactory->createCoordinateReferenceSystem("4275"), // NTF
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv "
+ "+proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
+ "+proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_ntv1_ntv2_ctable2) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4267"), // NAD27
+ authFactory->createCoordinateReferenceSystem("4269"), // NAD83
+ ctxt);
+ ASSERT_EQ(list.size(), 10U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
+ "+grids=ca_nrc_ntv1_can.tif +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
+ "+grids=ca_nrc_ntv2_0.tif +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(list[2]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
+ "+grids=us_noaa_conus.tif +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_NAD27_to_WGS84) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4267"), // NAD27
+ authFactory->createCoordinateReferenceSystem("4326"), // WGS84
+ ctxt);
+ ASSERT_EQ(list.size(), 79U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "NAD27 to WGS 84 (33)"); // 1.0 m, Canada - NAD27
+ EXPECT_EQ(list[1]->nameStr(),
+ "NAD27 to WGS 84 (3)"); // 20.0 m, Canada - NAD27
+ EXPECT_EQ(list[2]->nameStr(),
+ "NAD27 to WGS 84 (79)"); // 5.0 m, USA - CONUS including EEZ
+ EXPECT_EQ(list[3]->nameStr(),
+ "NAD27 to WGS 84 (4)"); // 10.0 m, USA - CONUS - onshore
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_NAD27_to_WGS84_G1762) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+
+ auto authFactoryEPSG =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NAD27
+ authFactoryEPSG->createCoordinateReferenceSystem("4267"),
+ // WGS84 (G1762)
+ authFactoryEPSG->createCoordinateReferenceSystem("9057"), ctxt);
+ ASSERT_GE(list.size(), 78U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "NAD27 to WGS 84 (33) + WGS 84 to WGS 84 (G1762)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=ca_nrc_ntv2_0.tif "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ EXPECT_EQ(list[1]->nameStr(),
+ "NAD27 to WGS 84 (3) + WGS 84 to WGS 84 (G1762)");
+ EXPECT_EQ(list[2]->nameStr(),
+ "NAD27 to WGS 84 (79) + WGS 84 to WGS 84 (G1762)");
+ EXPECT_EQ(list[3]->nameStr(),
+ "NAD27 to WGS 84 (4) + WGS 84 to WGS 84 (G1762)");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_WGS84_G1674_to_WGS84_G1762) {
+ // Check that particular behavior with WGS 84 (Gxxx) related to
+ // 'geodetic_datum_preferred_hub' table and custom no-op transformations
+ // between WGS 84 and WGS 84 (Gxxx) doesn't affect direct transformations
+ // to those realizations.
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+
+ auto authFactoryEPSG =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // WGS84 (G1674)
+ authFactoryEPSG->createCoordinateReferenceSystem("9056"),
+ // WGS84 (G1762)
+ authFactoryEPSG->createCoordinateReferenceSystem("9057"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=-0.004 +y=0.003 +z=0.004 +rx=0.00027 "
+ "+ry=-0.00027 +rz=0.00038 +s=-0.0069 "
+ "+convention=coordinate_frame "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_EPSG_4240_Indian1975_to_EPSG_4326) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4240"), // Indian 1975
+ authFactory->createCoordinateReferenceSystem("4326"), ctxt);
+ ASSERT_EQ(list.size(), 3U);
+
+ // Indian 1975 to WGS 84 (4), 3.0 m, Thailand - onshore
+ EXPECT_EQ(list[0]->getEPSGCode(), 1812);
+
+ // The following is the one we want to see. It has a lesser accuracy than
+ // the above one and the same bbox, but the name of its area of use is
+ // slightly different
+ // Indian 1975 to WGS 84 (2), 5.0 m, Thailand - onshore and Gulf of Thailand
+ EXPECT_EQ(list[1]->getEPSGCode(), 1304);
+
+ // Indian 1975 to WGS 84 (3), 1.0 m, Thailand - Bongkot field
+ EXPECT_EQ(list[2]->getEPSGCode(), 1537);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_helmert_geog3D_crs) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4939"), // GDA94 3D
+ authFactory->createCoordinateReferenceSystem("7843"), // GDA2020 3D
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+
+ // Check there is no push / pop of v_3
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
+ "+step +proj=cart +ellps=GRS80 "
+ "+step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
+ "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
+ "+convention=coordinate_frame "
+ "+step +inv +proj=cart +ellps=GRS80 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_helmert_geocentric_3D) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // GDA94 geocentric
+ authFactory->createCoordinateReferenceSystem("4348"),
+ // GDA2020 geocentric
+ authFactory->createCoordinateReferenceSystem("7842"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+
+ // Check there is no push / pop of v_3
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
+ "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
+ "+convention=coordinate_frame");
+ EXPECT_EQ(list[0]->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
+ "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
+ "+convention=coordinate_frame");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_helmert_geog3D_to_geocentirc) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // GDA94 3D
+ authFactory->createCoordinateReferenceSystem("4939"),
+ // GDA2020 geocentric
+ authFactory->createCoordinateReferenceSystem("7842"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+
+ // Check there is no push / pop of v_3
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
+ "+step +proj=cart +ellps=GRS80 "
+ "+step +proj=helmert +x=0.06155 +y=-0.01087 +z=-0.04019 "
+ "+rx=-0.0394924 +ry=-0.0327221 +rz=-0.0328979 +s=-0.009994 "
+ "+convention=coordinate_frame");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_invalid_EPSG_ID) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+ // EPSG:4656 is incorrect. Should be EPSG:8997
+ auto obj = WKTParser().createFromWKT(
+ "GEOGCS[\"ITRF2000\","
+ "DATUM[\"International_Terrestrial_Reference_Frame_2000\","
+ "SPHEROID[\"GRS 1980\",6378137,298.257222101,"
+ "AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6656\"]],"
+ "PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.0174532925199433],"
+ "AUTHORITY[\"EPSG\",\"4656\"]]");
+ auto crs = nn_dynamic_pointer_cast<GeographicCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(crs), GeographicCRS::EPSG_4326, ctxt);
+ ASSERT_EQ(list.size(), 1U);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_datum_ensemble) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0);
+
+ auto dst_wkt =
+ "GEOGCRS[\"unknown\","
+ " ENSEMBLE[\"World Geodetic System 1984 ensemble\","
+ " MEMBER[\"World Geodetic System 1984 (Transit)\","
+ " ID[\"EPSG\",1166]],"
+ " MEMBER[\"World Geodetic System 1984 (G730)\","
+ " ID[\"EPSG\",1152]],"
+ " MEMBER[\"World Geodetic System 1984 (G873)\","
+ " ID[\"EPSG\",1153]],"
+ " MEMBER[\"World Geodetic System 1984 (G1150)\","
+ " ID[\"EPSG\",1154]],"
+ " MEMBER[\"World Geodetic System 1984 (G1674)\","
+ " ID[\"EPSG\",1155]],"
+ " MEMBER[\"World Geodetic System 1984 (G1762)\","
+ " ID[\"EPSG\",1156]],"
+ " ELLIPSOID[\"WGS 84\",6378137,298.257223563,"
+ " LENGTHUNIT[\"metre\",1,ID[\"EPSG\",9001]],"
+ " ID[\"EPSG\",7030]],"
+ " ENSEMBLEACCURACY[2]],"
+ " PRIMEM[\"Greenwich\",0,"
+ " ANGLEUNIT[\"degree\",0.0174532925199433,ID[\"EPSG\",9102]],"
+ " ID[\"EPSG\",8901]],"
+ " CS[ellipsoidal,2,"
+ " ID[\"EPSG\",6422]],"
+ " AXIS[\"Geodetic latitude (Lat)\",north,"
+ " ORDER[1]],"
+ " AXIS[\"Geodetic longitude (Lon)\",east,"
+ " ORDER[2]],"
+ " ANGLEUNIT[\"degree (supplier to define representation)\","
+ "0.0174532925199433,ID[\"EPSG\",9122]]]";
+ auto dstObj = WKTParser().createFromWKT(dst_wkt);
+ auto dstCRS = nn_dynamic_pointer_cast<CRS>(dstObj);
+ ASSERT_TRUE(dstCRS != nullptr);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
+ NN_NO_CHECK(dstCRS), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "ETRS89 to WGS 84 (1)");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, vertCRS_to_geogCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setUsePROJAlternativeGridNames(false);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem(
+ "3855"), // EGM2008 height
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ ctxt);
+ ASSERT_EQ(list.size(), 3U);
+ EXPECT_EQ(
+ list[1]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem(
+ "3855"), // EGM2008 height
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ ctxt);
+ ASSERT_EQ(list.size(), 3U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ authFactory->createCoordinateReferenceSystem(
+ "3855"), // EGM2008 height
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=vgridshift +grids=us_nga_egm08_25.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NGVD29 depth (ftUS)
+ authFactory->createCoordinateReferenceSystem("6359"),
+ authFactory->createCoordinateReferenceSystem("4326"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=affine +s33=-0.304800609601219");
+ }
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NZVD2016 height
+ authFactory->createCoordinateReferenceSystem("7839"),
+ // NZGD2000
+ authFactory->createCoordinateReferenceSystem("4959"), ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=nz_linz_nzgeoid2016.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+ {
+ // Test actually the database where we derive records using the more
+ // classic 'Geographic3D to GravityRelatedHeight' method from
+ // records using EPSG:9635
+ //'Geog3D to Geog2D+GravityRelatedHeight (US .gtx)' method
+ auto ctxt = CoordinateOperationContext::create(
+ AuthorityFactory::create(DatabaseContext::create(), std::string()),
+ nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // Baltic 1957 height
+ authFactory->createCoordinateReferenceSystem("8357"),
+ // ETRS89
+ authFactory->createCoordinateReferenceSystem("4937"), ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift "
+ "+grids=sk_gku_Slovakia_ETRS89h_to_Baltic1957.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geog3DCRS_to_geog2DCRS_plus_vertCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // ETRS89 (3D)
+ authFactory->createCoordinateReferenceSystem("4937"),
+ // ETRS89 + Baltic 1957 height
+ authFactory->createCoordinateReferenceSystem("8360"), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=vgridshift "
+ "+grids=sk_gku_Slovakia_ETRS89h_to_Baltic1957.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ EXPECT_EQ(list[0]->inverse()->nameStr(),
+ "Inverse of 'ETRS89 to ETRS89 + Baltic 1957 height (1)'");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_noop) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(), "Null geographic offset from WGS 84 to WGS 84");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+ EXPECT_EQ(op->inverse()->nameStr(), op->nameStr());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_longitude_rotation) {
+
+ auto src = GeographicCRS::create(
+ PropertyMap().set(IdentifiedObject::NAME_KEY, "A"),
+ GeodeticReferenceFrame::create(PropertyMap(), Ellipsoid::WGS84,
+ optional<std::string>(),
+ PrimeMeridian::GREENWICH),
+ EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
+ auto dest = GeographicCRS::create(
+ PropertyMap().set(IdentifiedObject::NAME_KEY, "B"),
+ GeodeticReferenceFrame::create(PropertyMap(), Ellipsoid::WGS84,
+ optional<std::string>(),
+ PrimeMeridian::PARIS),
+ EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
+
+ auto op = CoordinateOperationFactory::create()->createOperation(src, dest);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=longlat "
+ "+ellps=WGS84 +pm=paris +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(op->inverse()->exportToWKT(WKTFormatter::create().get()),
+ CoordinateOperationFactory::create()
+ ->createOperation(dest, src)
+ ->exportToWKT(WKTFormatter::create().get()));
+ EXPECT_TRUE(
+ op->inverse()->isEquivalentTo(CoordinateOperationFactory::create()
+ ->createOperation(dest, src)
+ .get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_longitude_rotation_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris)
+ authFactory->createCoordinateReferenceSystem("4275"), // NTF
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(list[0]->nameStr(), "NTF (Paris) to NTF (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=paris +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+ EXPECT_EQ(list[1]->nameStr(), "NTF (Paris) to NTF (2)");
+ EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=2.33720833333333 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_concatenated_operation) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setAllowUseIntermediateCRS(
+ CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris)
+ authFactory->createCoordinateReferenceSystem("4171"), // RGF93
+ ctxt);
+ ASSERT_EQ(list.size(), 4U);
+
+ EXPECT_EQ(list[0]->nameStr(), "NTF (Paris) to RGF93 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
+ "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign "
+ "+step +proj=xyzgridshift +grids=fr_ign_gr3df97a.tif "
+ "+grid_ref=output_crs +ellps=GRS80 "
+ "+step +inv +proj=cart +ellps=GRS80 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ EXPECT_EQ(list[1]->nameStr(), "NTF (Paris) to RGF93 (2)");
+ EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=hgridshift "
+ "+grids=fr_ign_ntf_r93.tif +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+
+ EXPECT_TRUE(nn_dynamic_pointer_cast<ConcatenatedOperation>(list[0]) !=
+ nullptr);
+ auto grids = list[0]->gridsNeeded(DatabaseContext::create(), false);
+ EXPECT_EQ(grids.size(), 1U);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_ED50_to_WGS72_no_NTF_intermediate) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4230"), // ED50
+ authFactory->createCoordinateReferenceSystem("4322"), // WGS 72
+ ctxt);
+ ASSERT_GE(list.size(), 2U);
+ // We should not use the ancient NTF as an intermediate when looking for
+ // ED50 -> WGS 72 operations.
+ for (const auto &op : list) {
+ EXPECT_TRUE(op->nameStr().find("NTF") == std::string::npos)
+ << op->nameStr();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_context_same_grid_name) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4314"), // DHDN
+ authFactory->createCoordinateReferenceSystem("4258"), // ETRS89
+ ctxt);
+ ASSERT_TRUE(!list.empty());
+ EXPECT_EQ(list[0]->nameStr(), "DHDN to ETRS89 (8)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift "
+ "+grids=de_adv_BETA2007.tif +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_geographic_offset_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4120"), // NTF(Paris)
+ authFactory->createCoordinateReferenceSystem("4121"), // NTF
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "Greek to GGRS87 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=-5.86 +dlon=0.28 +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_CH1903_to_CH1903plus_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setAllowUseIntermediateCRS(
+ CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4149"), // CH1903
+ authFactory->createCoordinateReferenceSystem("4150"), // CH1903+
+ ctxt);
+ ASSERT_TRUE(list.size() == 1U);
+
+ EXPECT_EQ(list[0]->nameStr(), "CH1903 to CH1903+ (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=ch_swisstopo_CHENyx06a.tif "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_init_IGNF_to_init_IGNF_context) {
+
+ auto dbContext = DatabaseContext::create();
+
+ auto sourceCRS_obj = PROJStringParser()
+ .attachDatabaseContext(dbContext)
+ .setUsePROJ4InitRules(true)
+ .createFromPROJString("+init=IGNF:NTFG");
+ auto sourceCRS = nn_dynamic_pointer_cast<CRS>(sourceCRS_obj);
+ ASSERT_TRUE(sourceCRS != nullptr);
+
+ auto targetCRS_obj = PROJStringParser()
+ .attachDatabaseContext(dbContext)
+ .setUsePROJ4InitRules(true)
+ .createFromPROJString("+init=IGNF:RGF93G");
+ auto targetCRS = nn_dynamic_pointer_cast<CRS>(targetCRS_obj);
+ ASSERT_TRUE(targetCRS != nullptr);
+
+ auto authFactory = AuthorityFactory::create(dbContext, std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_CHECK_ASSERT(sourceCRS), NN_CHECK_ASSERT(targetCRS), ctxt);
+ ASSERT_EQ(list.size(), 2U);
+
+ EXPECT_EQ(list[0]->nameStr(),
+ "NOUVELLE TRIANGULATION DE LA FRANCE (NTF) vers RGF93 (ETRS89)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=fr_ign_ntf_r93.tif +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geogCRS_3D) {
+
+ auto geogcrs_m_obj = PROJStringParser().createFromPROJString(
+ "+proj=longlat +vunits=m +type=crs");
+ auto geogcrs_m = nn_dynamic_pointer_cast<CRS>(geogcrs_m_obj);
+ ASSERT_TRUE(geogcrs_m != nullptr);
+
+ auto geogcrs_ft_obj = PROJStringParser().createFromPROJString(
+ "+proj=longlat +vunits=ft +type=crs");
+ auto geogcrs_ft = nn_dynamic_pointer_cast<CRS>(geogcrs_ft_obj);
+ ASSERT_TRUE(geogcrs_ft != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(geogcrs_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=unitconvert +z_in=m +z_out=ft");
+ }
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(geogcrs_ft), NN_CHECK_ASSERT(geogcrs_m));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=unitconvert +z_in=ft +z_out=m");
+ }
+
+ auto geogcrs_m_with_pm_obj = PROJStringParser().createFromPROJString(
+ "+proj=longlat +pm=paris +vunits=m +type=crs");
+ auto geogcrs_m_with_pm =
+ nn_dynamic_pointer_cast<CRS>(geogcrs_m_with_pm_obj);
+ ASSERT_TRUE(geogcrs_m_with_pm != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(geogcrs_m_with_pm), NN_CHECK_ASSERT(geogcrs_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +z_in=m "
+ "+xy_out=rad +z_out=m +step +inv +proj=longlat +ellps=WGS84 "
+ "+pm=paris +step +proj=unitconvert +xy_in=rad +z_in=m "
+ "+xy_out=deg +z_out=ft");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_3D_lat_long_non_metre_to_geogCRS_longlat) {
+
+ auto wkt = "GEOGCRS[\"my CRS\",\n"
+ " DATUM[\"World Geodetic System 1984\",\n"
+ " ELLIPSOID[\"WGS 84\",6378137,298.257223563],\n"
+ " ID[\"EPSG\",6326]],\n"
+ " CS[ellipsoidal,3],\n"
+ " AXIS[\"latitude\",north,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"longitude\",east,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"ellipsoidal height\",up,\n"
+ " LENGTHUNIT[\"my_vunit\",0.3]]]";
+ auto srcCRS_obj = WKTParser().createFromWKT(wkt);
+ auto srcCRS = nn_dynamic_pointer_cast<CRS>(srcCRS_obj);
+ ASSERT_TRUE(srcCRS != nullptr);
+
+ auto dstCRS_obj = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +type=crs");
+ auto dstCRS = nn_dynamic_pointer_cast<CRS>(dstCRS_obj);
+ ASSERT_TRUE(dstCRS != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(srcCRS), NN_CHECK_ASSERT(dstCRS));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +z_in=0.3 +z_out=m");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_without_id_to_geogCRS_3D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto src =
+ authFactory->createCoordinateReferenceSystem("4289"); // Amersfoort
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+ auto wkt2 = "GEOGCRS[\"unnamed\",\n"
+ " DATUM[\"Amersfoort\",\n"
+ " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " CS[ellipsoidal,2],\n"
+ " AXIS[\"geodetic latitude (Lat)\",north,\n"
+ " ORDER[1],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"geodetic longitude (Lon)\",east,\n"
+ " ORDER[2],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],"
+ " USAGE[\n"
+ " SCOPE[\"unknown\"],\n"
+ " AREA[\"Netherlands - onshore\"],\n"
+ " BBOX[50.75,3.2,53.7,7.22]]]\n";
+
+ auto obj = WKTParser().createFromWKT(wkt2);
+ auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
+ ASSERT_TRUE(src_from_wkt2 != nullptr);
+ auto list2 = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src_from_wkt2), dst, ctxt);
+ ASSERT_GE(list.size(), list2.size());
+ for (size_t i = 0; i < list.size(); i++) {
+ const auto &op = list[i];
+ const auto &op2 = list2[i];
+ EXPECT_TRUE(
+ op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT))
+ << op->nameStr() << " " << op2->nameStr();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+static GeodeticCRSNNPtr createGeocentricDatumWGS84() {
+ PropertyMap propertiesCRS;
+ propertiesCRS.set(Identifier::CODESPACE_KEY, "EPSG")
+ .set(Identifier::CODE_KEY, 4328)
+ .set(IdentifiedObject::NAME_KEY, "WGS 84");
+ return GeodeticCRS::create(
+ propertiesCRS, GeodeticReferenceFrame::EPSG_6326,
+ CartesianCS::createGeocentric(UnitOfMeasure::METRE));
+}
+
+// ---------------------------------------------------------------------------
+
+static GeodeticCRSNNPtr createGeocentricKM() {
+ PropertyMap propertiesCRS;
+ propertiesCRS.set(IdentifiedObject::NAME_KEY, "Based on WGS 84");
+ return GeodeticCRS::create(
+ propertiesCRS, GeodeticReferenceFrame::EPSG_6326,
+ CartesianCS::createGeocentric(
+ UnitOfMeasure("kilometre", 1000.0, UnitOfMeasure::Type::LINEAR)));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geogCRS_same_datum) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createGeocentricDatumWGS84(), GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geogCRS_different_datum) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createGeocentricDatumWGS84(), GeographicCRS::EPSG_4269);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(),
+ "Ballpark geocentric translation from WGS 84 to NAD83 "
+ "(geocentric) + Conversion from NAD83 "
+ "(geocentric) to NAD83");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=GRS80 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geocentricCRS_different_datum) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4269, createGeocentricDatumWGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(), "Conversion from NAD83 to NAD83 (geocentric) + "
+ "Ballpark geocentric translation from NAD83 "
+ "(geocentric) to WGS 84");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
+ "+ellps=GRS80");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geocentricCRS_same_noop) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createGeocentricDatumWGS84(), createGeocentricDatumWGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(),
+ "Null geocentric translation from WGS 84 to WGS 84");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+ EXPECT_EQ(op->inverse()->nameStr(), op->nameStr());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geocentricCRS_different_ballpark) {
+
+ PropertyMap propertiesCRS;
+ propertiesCRS.set(Identifier::CODESPACE_KEY, "EPSG")
+ .set(Identifier::CODE_KEY, 4328)
+ .set(IdentifiedObject::NAME_KEY, "unknown");
+ auto otherGeocentricCRS = GeodeticCRS::create(
+ propertiesCRS, GeodeticReferenceFrame::EPSG_6269,
+ CartesianCS::createGeocentric(UnitOfMeasure::METRE));
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createGeocentricKM(), otherGeocentricCRS);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(
+ op->nameStr(),
+ "Ballpark geocentric translation from Based on WGS 84 to unknown");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=unitconvert +xy_in=km +z_in=km +xy_out=m +z_out=m");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geogCRS_same_datum_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4326"),
+ // WGS84 geocentric
+ authFactory->createCoordinateReferenceSystem("4978"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+
+ EXPECT_EQ(list[0]->nameStr(),
+ "Conversion from WGS 84 (geog2D) to WGS 84 (geocentric)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=cart "
+ "+ellps=WGS84");
+
+ EXPECT_EQ(list[0]->inverse()->nameStr(),
+ "Conversion from WGS 84 (geocentric) to WGS 84 (geog2D)");
+ EXPECT_EQ(list[0]->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geogCRS_same_datum_context_all_auth) {
+ // This is to check we don't use OGC:CRS84 as a pivot
+ auto authFactoryEPSG =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto authFactoryAll =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt =
+ CoordinateOperationContext::create(authFactoryAll, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactoryEPSG->createCoordinateReferenceSystem("4326"),
+ // WGS84 geocentric
+ authFactoryEPSG->createCoordinateReferenceSystem("4978"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+
+ EXPECT_EQ(list[0]->nameStr(),
+ "Conversion from WGS 84 (geog2D) to WGS 84 (geocentric)");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geocentricCRS_different_datum_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // ITRF2000 (geocentric)
+ authFactory->createCoordinateReferenceSystem("4919"),
+ // ITRF2005 (geocentric)
+ authFactory->createCoordinateReferenceSystem("4896"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "ITRF2000 to ITRF2005 (1)");
+ EXPECT_PRED_FORMAT2(
+ ComparePROJString,
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=helmert +x=-0.0001 "
+ "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
+ "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
+ "+t_epoch=2000 +convention=position_vector");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_geocentricCRS_same_datum_to_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // WGS84 geocentric
+ authFactory->createCoordinateReferenceSystem("4978"),
+ authFactory->createCoordinateReferenceSystem("4326"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Conversion from WGS 84 (geocentric) to WGS 84 (geog2D)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ geog2D_to_geog3D_same_datum_but_with_potential_other_pivot_context) {
+ // Check that when going from geog2D to geog3D of same datum, we don't
+ // try to go through a WGS84 pivot...
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("5365"), // CR 05 2D
+ authFactory->createCoordinateReferenceSystem("5364"), // CR 05 3D
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ geogCRS_to_geogCRS_different_datum_though_geocentric_transform_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // ITRF2000 (geog3D)
+ authFactory->createCoordinateReferenceSystem("7909"),
+ // ITRF2005 (geog3D)
+ authFactory->createCoordinateReferenceSystem("7910"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Conversion from ITRF2000 (geog3D) to ITRF2000 (geocentric) + "
+ "ITRF2000 to ITRF2005 (1) + "
+ "Conversion from ITRF2005 (geocentric) to ITRF2005 (geog3D)");
+ EXPECT_PRED_FORMAT2(
+ ComparePROJString,
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
+ "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=-0.0001 "
+ "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
+ "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
+ "+t_epoch=2000 +convention=position_vector +step +inv "
+ "+proj=cart +ellps=GRS80 +step +proj=unitconvert +xy_in=rad "
+ "+z_in=m +xy_out=deg +z_out=m +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_geocentricCRS_different_datum_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // ITRF2000 (geog3D)
+ authFactory->createCoordinateReferenceSystem("7909"),
+ // ITRF2005 (geocentric)
+ authFactory->createCoordinateReferenceSystem("4896"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Conversion from ITRF2000 (geog3D) to ITRF2000 (geocentric) + "
+ "ITRF2000 to ITRF2005 (1)");
+ EXPECT_PRED_FORMAT2(
+ ComparePROJString,
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
+ "+step +proj=cart +ellps=GRS80 +step +proj=helmert +x=-0.0001 "
+ "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
+ "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
+ "+t_epoch=2000 +convention=position_vector");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_geogCRS_different_datum_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // ITRF2000 (geocentric)
+ authFactory->createCoordinateReferenceSystem("4919"),
+ // ITRF2005 (geog3D)
+ authFactory->createCoordinateReferenceSystem("7910"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "ITRF2000 to ITRF2005 (1) + "
+ "Conversion from ITRF2005 (geocentric) to ITRF2005 (geog3D)");
+ EXPECT_PRED_FORMAT2(
+ ComparePROJString,
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=helmert +x=-0.0001 "
+ "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
+ "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
+ "+t_epoch=2000 +convention=position_vector +step +inv "
+ "+proj=cart +ellps=GRS80 +step +proj=unitconvert +xy_in=rad "
+ "+z_in=m +xy_out=deg +z_out=m +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, esri_projectedCRS_to_geogCRS_with_ITRF_intermediate_context) {
+ auto dbContext = DatabaseContext::create();
+ auto authFactoryEPSG = AuthorityFactory::create(dbContext, "EPSG");
+ auto authFactoryESRI = AuthorityFactory::create(dbContext, "ESRI");
+ auto ctxt =
+ CoordinateOperationContext::create(authFactoryEPSG, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NAD_1983_CORS96_StatePlane_North_Carolina_FIPS_3200_Ft_US (projected)
+ authFactoryESRI->createCoordinateReferenceSystem("103501"),
+ // ITRF2005 (geog3D)
+ authFactoryEPSG->createCoordinateReferenceSystem("7910"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of NAD_1983_CORS96_StatePlane_North_Carolina_"
+ "FIPS_3200_Ft_US + "
+ "Conversion from NAD83(CORS96) (geog2D) to NAD83(CORS96) "
+ "(geocentric) + Inverse of ITRF2000 to NAD83(CORS96) (1) + "
+ "ITRF2000 to ITRF2005 (1) + "
+ "Conversion from ITRF2005 (geocentric) to ITRF2005 (geog3D)");
+ EXPECT_PRED_FORMAT2(
+ ComparePROJString,
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft "
+ "+xy_out=m +step +inv +proj=lcc +lat_0=33.75 +lon_0=-79 "
+ "+lat_1=34.3333333333333 +lat_2=36.1666666666667 "
+ "+x_0=609601.219202438 +y_0=0 +ellps=GRS80 +step +proj=cart "
+ "+ellps=GRS80 +step +inv +proj=helmert +x=0.9956 +y=-1.9013 "
+ "+z=-0.5215 +rx=0.025915 +ry=0.009426 +rz=0.011599 +s=0.00062 "
+ "+dx=0.0007 +dy=-0.0007 +dz=0.0005 +drx=6.7e-05 +dry=-0.000757 "
+ "+drz=-5.1e-05 +ds=-0.00018 +t_epoch=1997 "
+ "+convention=coordinate_frame +step +proj=helmert +x=-0.0001 "
+ "+y=0.0008 +z=0.0058 +rx=0 +ry=0 +rz=0 +s=-0.0004 +dx=0.0002 "
+ "+dy=-0.0001 +dz=0.0018 +drx=0 +dry=0 +drz=0 +ds=-8e-05 "
+ "+t_epoch=2000 +convention=position_vector +step +inv +proj=cart "
+ "+ellps=GRS80 +step +proj=unitconvert +xy_in=rad +z_in=m "
+ "+xy_out=deg +z_out=m +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+static ProjectedCRSNNPtr createUTM31_WGS84() {
+ return ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4326,
+ Conversion::createUTM(PropertyMap(), 31, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+}
+
+// ---------------------------------------------------------------------------
+
+static ProjectedCRSNNPtr createUTM32_WGS84() {
+ return ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4326,
+ Conversion::createUTM(PropertyMap(), 32, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_projCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4326, createUTM31_WGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_TRUE(std::dynamic_pointer_cast<Conversion>(op) != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=utm "
+ "+zone=31 +ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_longlat_to_geogCS_latlong) {
+
+ auto sourceCRS = GeographicCRS::OGC_CRS84;
+ auto targetCRS = GeographicCRS::EPSG_4326;
+ auto op = CoordinateOperationFactory::create()->createOperation(sourceCRS,
+ targetCRS);
+ ASSERT_TRUE(op != nullptr);
+ auto conv = std::dynamic_pointer_cast<Conversion>(op);
+ ASSERT_TRUE(conv != nullptr);
+ EXPECT_TRUE(op->sourceCRS() &&
+ op->sourceCRS()->isEquivalentTo(sourceCRS.get()));
+ EXPECT_TRUE(op->targetCRS() &&
+ op->targetCRS()->isEquivalentTo(targetCRS.get()));
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=axisswap +order=2,1");
+ auto convInverse = nn_dynamic_pointer_cast<Conversion>(conv->inverse());
+ ASSERT_TRUE(convInverse != nullptr);
+ EXPECT_TRUE(convInverse->sourceCRS() &&
+ convInverse->sourceCRS()->isEquivalentTo(targetCRS.get()));
+ EXPECT_TRUE(convInverse->targetCRS() &&
+ convInverse->targetCRS()->isEquivalentTo(sourceCRS.get()));
+ EXPECT_EQ(conv->method()->exportToWKT(WKTFormatter::create().get()),
+ convInverse->method()->exportToWKT(WKTFormatter::create().get()));
+ EXPECT_TRUE(conv->method()->isEquivalentTo(convInverse->method().get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_longlat_to_geogCS_latlong_database) {
+
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ AuthorityFactory::create(DatabaseContext::create(), "OGC")
+ ->createCoordinateReferenceSystem("CRS84"),
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("4326"),
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_longlat_to_projCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::OGC_CRS84, createUTM31_WGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=utm +zone=31 +ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_different_from_baseCRS_to_projCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4807, createUTM31_WGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(
+ op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv +proj=longlat "
+ "+ellps=clrk80ign +pm=paris +step +proj=utm +zone=31 "
+ "+ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ geogCRS_different_from_baseCRS_to_projCRS_context_compatible_area) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setAllowUseIntermediateCRS(
+ CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris)
+ authFactory->createCoordinateReferenceSystem("32631"), // UTM31 WGS84
+ ctxt);
+ ASSERT_EQ(list.size(), 4U);
+ EXPECT_EQ(
+ list[0]->nameStr(),
+ "NTF (Paris) to NTF (1) + Inverse of WGS 84 to NTF (3) + UTM zone 31N");
+ ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
+ EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "1");
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=hgridshift "
+ "+grids=fr_ign_ntf_r93.tif +step +proj=utm +zone=31 +ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocentricCRS_to_projCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createGeocentricDatumWGS84(), createUTM31_WGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step "
+ "+proj=utm +zone=31 +ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_geogCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createUTM31_WGS84(), GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=WGS84 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_no_id_to_geogCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto src = authFactory->createCoordinateReferenceSystem(
+ "28992"); // Amersfoort / RD New
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("4258"); // ETRS89 2D
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+ auto wkt2 =
+ "PROJCRS[\"unknown\",\n"
+ " BASEGEOGCRS[\"Amersfoort\",\n"
+ " DATUM[\"Amersfoort\",\n"
+ " ELLIPSOID[\"Bessel 1841\",6377397.155,299.1528128]]],\n"
+ " CONVERSION[\"unknown\",\n"
+ " METHOD[\"Oblique Stereographic\"],\n"
+ " PARAMETER[\"Latitude of natural origin\",52.1561605555556],\n"
+ " PARAMETER[\"Longitude of natural origin\",5.38763888888889],\n"
+ " PARAMETER[\"Scale factor at natural origin\",0.9999079],\n"
+ " PARAMETER[\"False easting\",155000],\n"
+ " PARAMETER[\"False northing\",463000]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"(E)\",east],\n"
+ " AXIS[\"(N)\",north],\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",28992]]";
+ auto obj = WKTParser().createFromWKT(wkt2);
+ auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
+ ASSERT_TRUE(src_from_wkt2 != nullptr);
+ auto list2 = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src_from_wkt2), dst, ctxt);
+ ASSERT_GE(list.size(), list2.size() - 1);
+ for (size_t i = 0; i < list.size(); i++) {
+ const auto &op = list[i];
+ const auto &op2 = list2[i];
+ EXPECT_TRUE(
+ op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_3D_to_geogCRS_3D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto wkt = "PROJCRS[\"NAD83(HARN) / Oregon GIC Lambert (ft)\",\n"
+ " BASEGEOGCRS[\"NAD83(HARN)\",\n"
+ " DATUM[\"NAD83 (High Accuracy Reference Network)\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " ID[\"EPSG\",4957]],\n"
+ " CONVERSION[\"unnamed\",\n"
+ " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
+ " ID[\"EPSG\",9802]],\n"
+ " PARAMETER[\"Latitude of false origin\",41.75,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8821]],\n"
+ " PARAMETER[\"Longitude of false origin\",-120.5,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8822]],\n"
+ " PARAMETER[\"Latitude of 1st standard parallel\",43,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8823]],\n"
+ " PARAMETER[\"Latitude of 2nd standard parallel\",45.5,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8824]],\n"
+ " PARAMETER[\"Easting at false origin\",1312335.958,\n"
+ " LENGTHUNIT[\"foot\",0.3048],\n"
+ " ID[\"EPSG\",8826]],\n"
+ " PARAMETER[\"Northing at false origin\",0,\n"
+ " LENGTHUNIT[\"foot\",0.3048],\n"
+ " ID[\"EPSG\",8827]]],\n"
+ " CS[Cartesian,3],\n"
+ " AXIS[\"easting\",east,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"foot\",0.3048]],\n"
+ " AXIS[\"northing\",north,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"foot\",0.3048]],\n"
+ " AXIS[\"ellipsoidal height (h)\",up,\n"
+ " ORDER[3],\n"
+ " LENGTHUNIT[\"foot\",0.3048]]]";
+ auto obj = WKTParser().createFromWKT(wkt);
+ auto src = NN_CHECK_ASSERT(nn_dynamic_pointer_cast<CRS>(obj));
+ auto dst = authFactory->createCoordinateReferenceSystem(
+ "4957"); // NAD83(HARN) (3D)
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ // Check that z ft->m conversion is done (and just once)
+ "+step +proj=unitconvert +xy_in=ft +z_in=ft +xy_out=m +z_out=m "
+ "+step +inv +proj=lcc +lat_0=41.75 +lon_0=-120.5 +lat_1=43 "
+ "+lat_2=45.5 +x_0=399999.9999984 +y_0=0 +ellps=GRS80 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
+ "+step +proj=axisswap +order=2,1");
+}
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_3D_to_projCRS_2D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto wkt =
+ "PROJCRS[\"Projected 3d CRS\",\n"
+ " BASEGEOGCRS[\"JGD2000\",\n"
+ " DATUM[\"Japanese Geodetic Datum 2000\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " ID[\"EPSG\",4947]],\n" // the code is what triggered the bug
+ " CONVERSION[\"Japan Plane Rectangular CS zone VII\",\n"
+ " METHOD[\"Transverse Mercator\",\n"
+ " ID[\"EPSG\",9807]],\n"
+ " PARAMETER[\"Latitude of natural origin\",36,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8801]],\n"
+ " PARAMETER[\"Longitude of natural origin\",137.166666666667,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8802]],\n"
+ " PARAMETER[\"Scale factor at natural origin\",0.9999,\n"
+ " SCALEUNIT[\"unity\",1],\n"
+ " ID[\"EPSG\",8805]],\n"
+ " PARAMETER[\"False easting\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8806]],\n"
+ " PARAMETER[\"False northing\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8807]],\n"
+ " ID[\"EPSG\",17807]],\n"
+ " CS[Cartesian,3],\n"
+ " AXIS[\"northing (X)\",north,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"metre\",1,\n"
+ " ID[\"EPSG\",9001]]],\n"
+ " AXIS[\"easting (Y)\",east,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"metre\",1,\n"
+ " ID[\"EPSG\",9001]]],\n"
+ " AXIS[\"ellipsoidal height (h)\",up,\n"
+ " ORDER[3],\n"
+ " LENGTHUNIT[\"metre\",1,\n"
+ " ID[\"EPSG\",9001]]]]";
+ auto obj = WKTParser().createFromWKT(wkt);
+ auto src = NN_CHECK_ASSERT(nn_dynamic_pointer_cast<CRS>(obj));
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("32653"); // WGS 84 UTM 53
+ // We just want to check that we don't get inconsistent chaining exception
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_3D_to_projCRS_with_2D_geocentric_translation) {
+
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto src =
+ authFactory->createCoordinateReferenceSystem("4979"); // WGS 84 3D
+
+ // Azores Central 1948 / UTM zone 26N
+ auto dst = authFactory->createCoordinateReferenceSystem("2189");
+
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +z_in=m +xy_out=rad +z_out=m "
+ "+step +proj=push +v_3 " // this is what we check. Due to the
+ // target system being 2D only
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=104 +y=-167 +z=38 "
+ "+step +inv +proj=cart +ellps=intl "
+ "+step +proj=pop +v_3 " // this is what we check
+ "+step +proj=utm +zone=26 +ellps=intl");
+
+ auto listReverse =
+ CoordinateOperationFactory::create()->createOperations(dst, src, ctxt);
+ ASSERT_GE(listReverse.size(), 1U);
+ EXPECT_EQ(
+ listReverse[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=utm +zone=26 +ellps=intl "
+ "+step +proj=push +v_3 " // this is what we check
+ "+step +proj=cart +ellps=intl "
+ "+step +proj=helmert +x=-104 +y=167 +z=-38 "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=pop +v_3 " // this is what we check
+ "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS) {
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createUTM31_WGS84(), createUTM32_WGS84());
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=WGS84 +step "
+ "+proj=utm +zone=32 +ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_different_baseCRS) {
+
+ auto utm32 = ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4807,
+ Conversion::createUTM(PropertyMap(), 32, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ createUTM31_WGS84(), utm32);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=WGS84 +step "
+ "+proj=utm +zone=32 +ellps=clrk80ign +pm=paris");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_context_compatible_area) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("32634"), // UTM 34
+ authFactory->createCoordinateReferenceSystem(
+ "2171"), // Pulkovo 42 Poland I
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of UTM zone 34N + Inverse of Pulkovo 1942(58) to WGS 84 "
+ "(1) + Poland zone I");
+ ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
+ EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_context_compatible_area_bis) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem(
+ "3844"), // Pulkovo 42 Stereo 70 (Romania)
+ authFactory->createCoordinateReferenceSystem("32634"), // UTM 34
+ ctxt);
+ ASSERT_EQ(list.size(), 3U);
+ EXPECT_EQ(list[0]->nameStr(), "Inverse of Stereo 70 + "
+ "Pulkovo 1942(58) to WGS 84 "
+ "(19) + UTM zone 34N");
+ ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
+ EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "3");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_context_one_incompatible_area) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("32631"), // UTM 31
+ authFactory->createCoordinateReferenceSystem(
+ "2171"), // Pulkovo 42 Poland I
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of UTM zone 31N + Inverse of Pulkovo 1942(58) to WGS 84 "
+ "(1) + Poland zone I");
+ ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
+ EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_context_incompatible_areas) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("32631"), // UTM 31
+ authFactory->createCoordinateReferenceSystem("32633"), // UTM 33
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "Inverse of UTM zone 31N + UTM zone 33N");
+ ASSERT_EQ(list[0]->coordinateOperationAccuracies().size(), 1U);
+ EXPECT_EQ(list[0]->coordinateOperationAccuracies()[0]->value(), "0");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_context_incompatible_areas_ballpark) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("26711"), // UTM 11 NAD27
+ authFactory->createCoordinateReferenceSystem(
+ "3034"), // ETRS89 / LCC Europe
+ ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_TRUE(list[0]->hasBallparkTransformation());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ projCRS_to_projCRS_context_incompatible_areas_crs_extent_use_intersection) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSourceAndTargetCRSExtentUse(
+ CoordinateOperationContext::SourceTargetCRSExtentUse::INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("26711"), // UTM 11 NAD27
+ authFactory->createCoordinateReferenceSystem(
+ "3034"), // ETRS89 / LCC Europe
+ ctxt);
+ ASSERT_GE(list.size(), 0U);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_north_pole_inverted_axis) {
+
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("32661"),
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("5041"),
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_south_pole_inverted_axis) {
+
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("32761"),
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("5042"),
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_to_projCRS_through_geog3D) {
+ // Check that when going from projCRS to projCRS, using
+ // geog2D-->geog3D-->geog3D-->geog2D we do not have issues with
+ // inconsistent CRS chaining, due to how we 'hack' a bit some intermediate
+ // steps
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("5367"), // CR05 / CRTM05
+ authFactory->createCoordinateReferenceSystem(
+ "8908"), // CR-SIRGAS / CRTM05
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +inv +proj=tmerc +lat_0=0 +lon_0=-84 +k=0.9999 "
+ "+x_0=500000 +y_0=0 +ellps=WGS84 "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=-0.16959 +y=0.35312 +z=0.51846 "
+ "+rx=-0.03385 +ry=0.16325 +rz=-0.03446 +s=0.03693 "
+ "+convention=position_vector "
+ "+step +inv +proj=cart +ellps=GRS80 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=tmerc +lat_0=0 +lon_0=-84 +k=0.9999 +x_0=500000 "
+ "+y_0=0 +ellps=GRS80");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transform_from_amersfoort_rd_new_to_epsg_4326) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem("28992"),
+ authFactory->createCoordinateReferenceSystem("4326"), ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ // The order matters: "Amersfoort to WGS 84 (4)" replaces "Amersfoort to WGS
+ // 84 (3)"
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of RD New + Amersfoort to WGS 84 (4)");
+ EXPECT_EQ(list[1]->nameStr(),
+ "Inverse of RD New + Amersfoort to WGS 84 (3)");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_geogCRS) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ boundCRS, GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 "
+ "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step "
+ "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_geodCRS) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ boundCRS, GeodeticCRS::EPSG_4978);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step "
+ "+proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
+ "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
+ "+step +proj=cart +ellps=clrk80ign "
+ "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
+ "+convention=position_vector");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_geodCRS_not_related_to_hub) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ boundCRS,
+ // ETRS89 geocentric
+ authFactory->createCoordinateReferenceSystem("4936"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step "
+ "+proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
+ "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign "
+ "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
+ "+convention=position_vector "
+ "+step +inv +proj=cart +ellps=GRS80 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=cart +ellps=GRS80");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_geogCRS_with_area) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4267, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ boundCRS, authFactory->createCoordinateReferenceSystem("4326"));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk66 +step +proj=helmert +x=1 +y=2 "
+ "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step "
+ "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_unrelated_geogCRS) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ boundCRS, GeographicCRS::EPSG_4269);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ CoordinateOperationFactory::create()
+ ->createOperation(GeographicCRS::EPSG_4807,
+ GeographicCRS::EPSG_4269)
+ ->exportToPROJString(PROJStringFormatter::create().get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, createOperation_boundCRS_identified_by_datum) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +type=crs");
+ auto src = nn_dynamic_pointer_cast<GeographicCRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDest = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=32 +a=6378249.2 +b=6356515 "
+ "+towgs84=-263.0,6.0,431.0 +no_defs +type=crs");
+ auto dest = nn_dynamic_pointer_cast<BoundCRS>(objDest);
+ ASSERT_TRUE(dest != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=push +v_3 +step +proj=cart +ellps=WGS84 +step "
+ "+proj=helmert +x=263 +y=-6 +z=-431 +step +inv +proj=cart "
+ "+ellps=clrk80ign +step +proj=pop +v_3 +step +proj=utm +zone=32 "
+ "+ellps=clrk80ign");
+
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_TRUE(list[0]->isEquivalentTo(op.get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_clrk_66_geogCRS_to_nad83_geogCRS) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=latlong +ellps=clrk66 +nadgrids=ntv1_can.dat,conus +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDest = PROJStringParser().createFromPROJString(
+ "+proj=latlong +datum=NAD83 +type=crs");
+ auto dest = nn_dynamic_pointer_cast<CRS>(objDest);
+ ASSERT_TRUE(dest != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=ntv1_can.dat,conus "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_clrk_66_projCRS_to_nad83_geogCRS) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=17 +ellps=clrk66 +nadgrids=ntv1_can.dat,conus "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDest = PROJStringParser().createFromPROJString(
+ "+proj=latlong +datum=NAD83 +type=crs");
+ auto dest = nn_dynamic_pointer_cast<CRS>(objDest);
+ ASSERT_TRUE(dest != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=17 +ellps=clrk66 "
+ "+step +proj=hgridshift +grids=ntv1_can.dat,conus "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_projCRS_to_geogCRS) {
+ auto utm31 = ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4807,
+ Conversion::createUTM(PropertyMap(), 31, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ utm31, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ boundCRS, GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign "
+ "+pm=paris +step +proj=push +v_3 +step +proj=cart "
+ "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 "
+ "+rz=6 +s=7 +convention=position_vector +step +inv +proj=cart "
+ "+ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_projCRS) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto utm31 = ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4326,
+ Conversion::createUTM(PropertyMap(), 31, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+ auto op =
+ CoordinateOperationFactory::create()->createOperation(boundCRS, utm31);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign +step +proj=helmert +x=1 +y=2 "
+ "+z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector +step "
+ "+inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step "
+ "+proj=utm +zone=31 +ellps=WGS84");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_geogCRS_to_unrelated_geogCRS_context) {
+ auto src = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // ETRS89
+ auto dst = authFactory->createCoordinateReferenceSystem("4258");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ // Check with it is a concatenated operation, since it doesn't particularly
+ // show up in the PROJ string
+ EXPECT_TRUE(dynamic_cast<ConcatenatedOperation *>(list[0].get()) !=
+ nullptr);
+ EXPECT_EQ(list[0]->nameStr(), "Transformation from NTF (Paris) to WGS84 + "
+ "Inverse of ETRS89 to WGS 84 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
+ "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
+ "+step +proj=push +v_3 +step +proj=cart +ellps=clrk80ign "
+ "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
+ "+convention=position_vector "
+ "+step +inv +proj=cart +ellps=GRS80 +step +proj=pop +v_3 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geogCRS_to_boundCRS_of_geogCRS) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4326, boundCRS);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=1 "
+ "+y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 +convention=position_vector "
+ "+step +inv +proj=cart +ellps=clrk80ign +step +proj=pop +v_3 "
+ "+step +proj=longlat +ellps=clrk80ign +pm=paris +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=grad +step +proj=axisswap "
+ "+order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_to_geogCRS_same_datum_context) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4269, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ boundCRS, GeographicCRS::EPSG_4269, ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_to_geogCRS_hubCRS_and_targetCRS_same_but_baseCRS_not) {
+ const char *wkt =
+ "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"Ellipsoid (US Feet)\",\n"
+ " VERT_DATUM[\"Ellipsoid\",2002],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Up\",UP]]]";
+
+ auto dbContext = DatabaseContext::create();
+ auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT(wkt);
+ auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(obj);
+ ASSERT_TRUE(boundCRS != nullptr);
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(boundCRS), GeographicCRS::EPSG_4979, ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=unitconvert +z_in=us-ft +z_out=m");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_to_boundCRS) {
+ auto utm31 = ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4807,
+ Conversion::createUTM(PropertyMap(), 31, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+ auto utm32 = ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4269,
+ Conversion::createUTM(PropertyMap(), 32, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+ auto boundCRS1 = BoundCRS::createFromTOWGS84(
+ utm31, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto boundCRS2 = BoundCRS::createFromTOWGS84(
+ utm32, std::vector<double>{8, 9, 10, 11, 12, 13, 14});
+ auto op = CoordinateOperationFactory::create()->createOperation(boundCRS1,
+ boundCRS2);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=31 +ellps=clrk80ign "
+ "+pm=paris +step +proj=push +v_3 +step +proj=cart "
+ "+ellps=clrk80ign +step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 "
+ "+rz=6 +s=7 +convention=position_vector +step +inv +proj=helmert "
+ "+x=8 +y=9 +z=10 +rx=11 +ry=12 +rz=13 +s=14 "
+ "+convention=position_vector +step +inv +proj=cart +ellps=GRS80 "
+ "+step +proj=pop +v_3 +step +proj=utm +zone=32 +ellps=GRS80");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_to_boundCRS_noop_for_TOWGS84) {
+ auto boundCRS1 = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto boundCRS2 = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4269, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto op = CoordinateOperationFactory::create()->createOperation(boundCRS1,
+ boundCRS2);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=clrk80ign +pm=paris +step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign +step +inv +proj=cart "
+ "+ellps=GRS80 +step +proj=pop +v_3 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_to_boundCRS_unralated_hub) {
+ auto boundCRS1 = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto boundCRS2 = BoundCRS::create(
+ GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4979,
+ Transformation::createGeocentricTranslations(
+ PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4979,
+ 1.0, 2.0, 3.0, std::vector<PositionalAccuracyNNPtr>()));
+ auto op = CoordinateOperationFactory::create()->createOperation(boundCRS1,
+ boundCRS2);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ CoordinateOperationFactory::create()
+ ->createOperation(boundCRS1->baseCRS(), boundCRS2->baseCRS())
+ ->exportToPROJString(PROJStringFormatter::create().get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_of_projCRS_towgs84_to_boundCRS_of_projCRS_nadgrids) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=15 +datum=NAD83 +units=m +no_defs +ellps=GRS80 "
+ "+towgs84=0,0,0 +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=15 +datum=NAD27 +units=m +no_defs +ellps=clrk66 "
+ "+nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=15 +ellps=GRS80 +step "
+ "+inv +proj=hgridshift "
+ "+grids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat +step +proj=utm "
+ "+zone=15 +ellps=clrk66");
+}
+
+// ---------------------------------------------------------------------------
+
+static CRSNNPtr buildCRSFromProjStrThroughWKT(const std::string &projStr) {
+ auto crsFromProj = nn_dynamic_pointer_cast<CRS>(
+ PROJStringParser().createFromPROJString(projStr));
+ if (crsFromProj == nullptr) {
+ throw "crsFromProj == nullptr";
+ }
+ auto crsFromWkt = nn_dynamic_pointer_cast<CRS>(
+ WKTParser().createFromWKT(crsFromProj->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get())));
+ if (crsFromWkt == nullptr) {
+ throw "crsFromWkt == nullptr";
+ }
+ return NN_NO_CHECK(crsFromWkt);
+}
+
+TEST(operation,
+ boundCRS_to_boundCRS_with_base_geog_crs_different_from_source_of_transf) {
+
+ auto src = buildCRSFromProjStrThroughWKT(
+ "+proj=lcc +lat_1=49 +lat_0=49 +lon_0=0 +k_0=0.999877499 +x_0=600000 "
+ "+y_0=200000 +ellps=clrk80ign +pm=paris +towgs84=-168,-60,320,0,0,0,0 "
+ "+units=m +no_defs +type=crs");
+ auto dst = buildCRSFromProjStrThroughWKT(
+ "+proj=longlat +ellps=clrk80ign +pm=paris "
+ "+towgs84=-168,-60,320,0,0,0,0 +no_defs +type=crs");
+
+ auto op = CoordinateOperationFactory::create()->createOperation(src, dst);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=lcc +lat_1=49 +lat_0=49 +lon_0=0 "
+ "+k_0=0.999877499 +x_0=600000 +y_0=200000 +ellps=clrk80ign "
+ "+pm=paris "
+ "+step +proj=longlat +ellps=clrk80ign +pm=paris "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_with_basecrs_with_extent_to_geogCRS) {
+
+ auto wkt =
+ "BOUNDCRS[\n"
+ " SOURCECRS[\n"
+ " PROJCRS[\"NAD83 / California zone 3 (ftUS)\",\n"
+ " BASEGEODCRS[\"NAD83\",\n"
+ " DATUM[\"North American Datum 1983\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
+ " CONVERSION[\"SPCS83 California zone 3 (US Survey "
+ "feet)\",\n"
+ " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
+ " ID[\"EPSG\",9802]],\n"
+ " PARAMETER[\"Latitude of false origin\",36.5,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8821]],\n"
+ " PARAMETER[\"Longitude of false origin\",-120.5,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8822]],\n"
+ " PARAMETER[\"Latitude of 1st standard parallel\","
+ " 38.4333333333333,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8823]],\n"
+ " PARAMETER[\"Latitude of 2nd standard parallel\","
+ " 37.0666666666667,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8824]],\n"
+ " PARAMETER[\"Easting at false origin\",6561666.667,\n"
+ " LENGTHUNIT[\"US survey foot\","
+ " 0.304800609601219],\n"
+ " ID[\"EPSG\",8826]],\n"
+ " PARAMETER[\"Northing at false origin\",1640416.667,\n"
+ " LENGTHUNIT[\"US survey foot\","
+ " 0.304800609601219],\n"
+ " ID[\"EPSG\",8827]]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"easting (X)\",east,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"US survey foot\","
+ " 0.304800609601219]],\n"
+ " AXIS[\"northing (Y)\",north,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"US survey foot\","
+ " 0.304800609601219]],\n"
+ " SCOPE[\"unknown\"],\n"
+ " AREA[\"USA - California - SPCS - 3\"],\n"
+ " BBOX[36.73,-123.02,38.71,-117.83],\n"
+ " ID[\"EPSG\",2227]]],\n"
+ " TARGETCRS[\n"
+ " GEODCRS[\"WGS 84\",\n"
+ " DATUM[\"World Geodetic System 1984\",\n"
+ " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " CS[ellipsoidal,2],\n"
+ " AXIS[\"latitude\",north,\n"
+ " ORDER[1],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"longitude\",east,\n"
+ " ORDER[2],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " ID[\"EPSG\",4326]]],\n"
+ " ABRIDGEDTRANSFORMATION[\"NAD83 to WGS 84 (1)\",\n"
+ " METHOD[\"Geocentric translations (geog2D domain)\",\n"
+ " ID[\"EPSG\",9603]],\n"
+ " PARAMETER[\"X-axis translation\",0,\n"
+ " ID[\"EPSG\",8605]],\n"
+ " PARAMETER[\"Y-axis translation\",0,\n"
+ " ID[\"EPSG\",8606]],\n"
+ " PARAMETER[\"Z-axis translation\",0,\n"
+ " ID[\"EPSG\",8607]],\n"
+ " SCOPE[\"unknown\"],\n"
+ " AREA[\"North America - Canada and USA (CONUS, Alaska "
+ "mainland)\"],\n"
+ " BBOX[23.81,-172.54,86.46,-47.74],\n"
+ " ID[\"EPSG\",1188]]]";
+ auto obj = WKTParser().createFromWKT(wkt);
+ auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(obj);
+ ASSERT_TRUE(boundCRS != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(boundCRS), GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(), "Inverse of SPCS83 California zone 3 (US Survey "
+ "feet) + NAD83 to WGS 84 (1)");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, ETRS89_3D_to_proj_string_with_geoidgrids_nadgrids) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // ETRS89 3D
+ auto src = authFactory->createCoordinateReferenceSystem("4937");
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 "
+ "+k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel "
+ "+nadgrids=rdtrans2008.gsb +geoidgrids=naptrans2008.gtx +units=m "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ src, NN_NO_CHECK(dst), ctxt);
+ ASSERT_EQ(list.size(), 2U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=vgridshift +grids=naptrans2008.gtx "
+ "+multiplier=1 "
+ "+step +inv +proj=hgridshift +grids=rdtrans2008.gsb "
+ "+step +proj=sterea +lat_0=52.1561605555556 "
+ "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 "
+ "+y_0=463000 +ellps=bessel");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, nadgrids_with_pm) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=tmerc +lat_0=39.66666666666666 +lon_0=1 +k=1 +x_0=200000 "
+ "+y_0=300000 +ellps=intl +nadgrids=foo.gsb +pm=lisbon "
+ "+units=m +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto dst = authFactory->createCoordinateReferenceSystem("4326");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), dst, ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=tmerc +lat_0=39.6666666666667 +lon_0=1 "
+ "+k=1 +x_0=200000 +y_0=300000 +ellps=intl +pm=lisbon "
+ // Check that there is no extra +step +proj=longlat +pm=lisbon
+ "+step +proj=hgridshift +grids=foo.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ // ETRS89
+ dst = authFactory->createCoordinateReferenceSystem("4258");
+ list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=tmerc +lat_0=39.6666666666667 +lon_0=1 "
+ "+k=1 +x_0=200000 +y_0=300000 +ellps=intl +pm=lisbon "
+ // Check that there is no extra +step +proj=longlat +pm=lisbon
+ "+step +proj=hgridshift +grids=foo.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ // From WKT BOUNDCRS
+ auto formatter = WKTFormatter::create(WKTFormatter::Convention::WKT2_2019);
+ auto src_wkt = src->exportToWKT(formatter.get());
+ auto objFromWkt = WKTParser().createFromWKT(src_wkt);
+ auto crsFromWkt = nn_dynamic_pointer_cast<BoundCRS>(objFromWkt);
+ ASSERT_TRUE(crsFromWkt);
+ list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(crsFromWkt), dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=tmerc +lat_0=39.6666666666667 +lon_0=1 "
+ "+k=1 +x_0=200000 +y_0=300000 +ellps=intl +pm=lisbon "
+ // Check that there is no extra +step +proj=longlat +pm=lisbon
+ "+step +proj=hgridshift +grids=foo.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, WGS84_G1762_to_compoundCRS_with_bound_vertCRS) {
+ auto authFactoryEPSG =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // WGS 84 (G1762) 3D
+ auto src = authFactoryEPSG->createCoordinateReferenceSystem("7665");
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=NAD83 +geoidgrids=@foo.gtx +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ src, NN_NO_CHECK(dst), ctxt);
+ ASSERT_GE(list.size(), 53U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of WGS 84 to WGS 84 (G1762) + "
+ "Inverse of unknown to WGS84 ellipsoidal height + "
+ "Inverse of NAD83 to WGS 84 (1) + "
+ "axis order change (2D)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+static VerticalCRSNNPtr createVerticalCRS() {
+ PropertyMap propertiesVDatum;
+ propertiesVDatum.set(Identifier::CODESPACE_KEY, "EPSG")
+ .set(Identifier::CODE_KEY, 5101)
+ .set(IdentifiedObject::NAME_KEY, "Ordnance Datum Newlyn");
+ auto vdatum = VerticalReferenceFrame::create(propertiesVDatum);
+ PropertyMap propertiesCRS;
+ propertiesCRS.set(Identifier::CODESPACE_KEY, "EPSG")
+ .set(Identifier::CODE_KEY, 5701)
+ .set(IdentifiedObject::NAME_KEY, "ODN height");
+ return VerticalCRS::create(
+ propertiesCRS, vdatum,
+ VerticalCS::createGravityRelatedHeight(UnitOfMeasure::METRE));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS) {
+
+ auto compound = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{GeographicCRS::EPSG_4326, createVerticalCRS()});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ compound, GeographicCRS::EPSG_4807);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ CoordinateOperationFactory::create()
+ ->createOperation(GeographicCRS::EPSG_4326,
+ GeographicCRS::EPSG_4807)
+ ->exportToPROJString(PROJStringFormatter::create().get()));
+}
+
+// ---------------------------------------------------------------------------
+
+static BoundCRSNNPtr createBoundVerticalCRS() {
+ auto vertCRS = createVerticalCRS();
+ auto transformation =
+ Transformation::createGravityRelatedHeightToGeographic3D(
+ PropertyMap(), vertCRS, GeographicCRS::EPSG_4979, nullptr,
+ "us_nga_egm08_25.tif", std::vector<PositionalAccuracyNNPtr>());
+ return BoundCRS::create(vertCRS, GeographicCRS::EPSG_4979, transformation);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_height_to_PROJ_string) {
+ auto transf = createBoundVerticalCRS()->transformation();
+ EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_nga_egm08_25.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ auto grids = transf->gridsNeeded(DatabaseContext::create(), false);
+ ASSERT_EQ(grids.size(), 1U);
+ auto gridDesc = *(grids.begin());
+ EXPECT_EQ(gridDesc.shortName, "us_nga_egm08_25.tif");
+ EXPECT_TRUE(gridDesc.packageName.empty());
+ EXPECT_EQ(gridDesc.url, "https://cdn.proj.org/us_nga_egm08_25.tif");
+ if (gridDesc.available) {
+ EXPECT_TRUE(!gridDesc.fullName.empty()) << gridDesc.fullName;
+ EXPECT_TRUE(gridDesc.fullName.find(gridDesc.shortName) !=
+ std::string::npos)
+ << gridDesc.fullName;
+ } else {
+ EXPECT_TRUE(gridDesc.fullName.empty()) << gridDesc.fullName;
+ }
+ EXPECT_EQ(gridDesc.directDownload, true);
+ EXPECT_EQ(gridDesc.openLicense, true);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_Geographic3D_to_GravityRelatedHeight_gtx) {
+ auto wkt =
+ "COORDINATEOPERATION[\"ETRS89 to NAP height (1)\",\n"
+ " VERSION[\"RDNAP-Nld 2008\"],\n"
+ " SOURCECRS[\n"
+ " GEOGCRS[\"ETRS89\",\n"
+ " DATUM[\"European Terrestrial Reference System 1989\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " CS[ellipsoidal,3],\n"
+ " AXIS[\"geodetic latitude (Lat)\",north,\n"
+ " ORDER[1],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"geodetic longitude (Lon)\",east,\n"
+ " ORDER[2],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"ellipsoidal height (h)\",up,\n"
+ " ORDER[3],\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " ID[\"EPSG\",4937]]],\n"
+ " TARGETCRS[\n"
+ " VERTCRS[\"NAP height\",\n"
+ " VDATUM[\"Normaal Amsterdams Peil\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " ID[\"EPSG\",5709]]],\n"
+ " METHOD[\"Geographic3D to GravityRelatedHeight (US .gtx)\",\n"
+ " ID[\"EPSG\",9665]],\n"
+ " PARAMETERFILE[\"Geoid (height correction) model "
+ "file\",\"naptrans2008.gtx\"],\n"
+ " OPERATIONACCURACY[0.01],\n"
+ " USAGE[\n"
+ " SCOPE[\"unknown\"],\n"
+ " AREA[\"Netherlands - onshore\"],\n"
+ " BBOX[50.75,3.2,53.7,7.22]],\n"
+ " ID[\"EPSG\",7001]]";
+ ;
+ auto obj = WKTParser().createFromWKT(wkt);
+ auto transf = nn_dynamic_pointer_cast<Transformation>(obj);
+ ASSERT_TRUE(transf != nullptr);
+
+ // Check that we correctly inverse files in the case of
+ // "Geographic3D to GravityRelatedHeight (US .gtx)"
+ EXPECT_EQ(transf->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=vgridshift "
+ "+grids=naptrans2008.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_ntv2_to_PROJ_string) {
+ auto transformation = Transformation::createNTv2(
+ PropertyMap(), GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326,
+ "foo.gsb", std::vector<PositionalAccuracyNNPtr>());
+ EXPECT_EQ(
+ transformation->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=grad +xy_out=rad +step "
+ "+proj=hgridshift +grids=foo.gsb +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_VERTCON_to_PROJ_string) {
+ auto verticalCRS1 = createVerticalCRS();
+
+ auto verticalCRS2 = VerticalCRS::create(
+ PropertyMap(), VerticalReferenceFrame::create(PropertyMap()),
+ VerticalCS::createGravityRelatedHeight(UnitOfMeasure::METRE));
+
+ // Use of this type of transformation is a bit of non-sense here
+ // since it should normally be used with NGVD29 and NAVD88 for VerticalCRS,
+ // and NAD27/NAD83 as horizontal CRS...
+ auto vtransformation = Transformation::createVERTCON(
+ PropertyMap(), verticalCRS1, verticalCRS2, "bla.gtx",
+ std::vector<PositionalAccuracyNNPtr>());
+ EXPECT_EQ(vtransformation->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=vgridshift +grids=bla.gtx +multiplier=0.001");
+}
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_NZLVD_to_PROJ_string) {
+ auto dbContext = DatabaseContext::create();
+ auto factory = AuthorityFactory::create(dbContext, "EPSG");
+ auto op = factory->createCoordinateOperation("7860", false);
+ EXPECT_EQ(op->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5, dbContext)
+ .get()),
+ "+proj=vgridshift +grids=nz_linz_auckht1946-nzvd2016.tif "
+ "+multiplier=1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_BEV_AT_to_PROJ_string) {
+ auto dbContext = DatabaseContext::create();
+ auto factory = AuthorityFactory::create(dbContext, "EPSG");
+ auto op = factory->createCoordinateOperation("9275", false);
+ EXPECT_EQ(op->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5, dbContext)
+ .get()),
+ "+proj=vgridshift +grids=at_bev_GV_Hoehengrid_V1.tif "
+ "+multiplier=1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_longitude_rotation_to_PROJ_string) {
+
+ auto src = GeographicCRS::create(
+ PropertyMap(), GeodeticReferenceFrame::create(
+ PropertyMap(), Ellipsoid::WGS84,
+ optional<std::string>(), PrimeMeridian::GREENWICH),
+ EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
+ auto dest = GeographicCRS::create(
+ PropertyMap(), GeodeticReferenceFrame::create(
+ PropertyMap(), Ellipsoid::WGS84,
+ optional<std::string>(), PrimeMeridian::PARIS),
+ EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
+ auto transformation = Transformation::createLongitudeRotation(
+ PropertyMap(), src, dest, Angle(10));
+ EXPECT_TRUE(transformation->validateParameters().empty());
+ EXPECT_EQ(
+ transformation->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=WGS84 +pm=10 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(transformation->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +inv "
+ "+proj=longlat +ellps=WGS84 +pm=-10 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_Geographic2D_offsets_to_PROJ_string) {
+
+ auto transformation = Transformation::createGeographic2DOffsets(
+ PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326,
+ Angle(0.5), Angle(-1), {});
+ EXPECT_TRUE(transformation->validateParameters().empty());
+
+ EXPECT_EQ(
+ transformation->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=1800 +dlon=-3600 +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(transformation->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=-1800 +dlon=3600 +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_Geographic3D_offsets_to_PROJ_string) {
+
+ auto transformation = Transformation::createGeographic3DOffsets(
+ PropertyMap(), GeographicCRS::EPSG_4326, GeographicCRS::EPSG_4326,
+ Angle(0.5), Angle(-1), Length(2), {});
+ EXPECT_TRUE(transformation->validateParameters().empty());
+
+ EXPECT_EQ(
+ transformation->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=1800 +dlon=-3600 +dh=2 +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(transformation->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=-1800 +dlon=3600 +dh=-2 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ transformation_Geographic2D_with_height_offsets_to_PROJ_string) {
+
+ auto transformation = Transformation::createGeographic2DWithHeightOffsets(
+ PropertyMap(),
+ CompoundCRS::create(PropertyMap(),
+ {GeographicCRS::EPSG_4326, createVerticalCRS()}),
+ GeographicCRS::EPSG_4326, Angle(0.5), Angle(-1), Length(2), {});
+ EXPECT_TRUE(transformation->validateParameters().empty());
+
+ EXPECT_EQ(
+ transformation->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=1800 +dlon=-3600 +dh=2 +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ EXPECT_EQ(transformation->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=geogoffset "
+ "+dlat=-1800 +dlon=3600 +dh=-2 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, transformation_vertical_offset_to_PROJ_string) {
+
+ auto transformation = Transformation::createVerticalOffset(
+ PropertyMap(), createVerticalCRS(), createVerticalCRS(), Length(1), {});
+ EXPECT_TRUE(transformation->validateParameters().empty());
+
+ EXPECT_EQ(
+ transformation->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=geogoffset +dh=1");
+ EXPECT_EQ(transformation->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=geogoffset +dh=-1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_with_boundVerticalCRS_to_geogCRS) {
+
+ auto compound = CompoundCRS::create(
+ PropertyMap(), std::vector<CRSNNPtr>{GeographicCRS::EPSG_4326,
+ createBoundVerticalCRS()});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ compound, GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(
+ op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=vgridshift "
+ "+grids=us_nga_egm08_25.tif +multiplier=1 +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_with_boundGeogCRS_to_geogCRS) {
+
+ auto geogCRS = GeographicCRS::create(
+ PropertyMap(), GeodeticReferenceFrame::create(
+ PropertyMap(), Ellipsoid::WGS84,
+ optional<std::string>(), PrimeMeridian::GREENWICH),
+ EllipsoidalCS::createLatitudeLongitude(UnitOfMeasure::DEGREE));
+ auto horizBoundCRS = BoundCRS::createFromTOWGS84(
+ geogCRS, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto compound = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{horizBoundCRS, createVerticalCRS()});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ compound, GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
+ "+convention=position_vector "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_with_boundGeogCRS_and_boundVerticalCRS_to_geogCRS) {
+
+ auto horizBoundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4807, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto compound = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{horizBoundCRS, createBoundVerticalCRS()});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ compound, GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+ // Not completely sure the order of horizontal and vertical operations
+ // makes sense
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=grad +xy_out=rad "
+ "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign "
+ "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
+ "+convention=position_vector "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ auto grids = op->gridsNeeded(DatabaseContext::create(), false);
+ EXPECT_EQ(grids.size(), 1U);
+
+ auto opInverse = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4979, compound);
+ ASSERT_TRUE(opInverse != nullptr);
+ EXPECT_TRUE(opInverse->inverse()->isEquivalentTo(op.get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_with_boundProjCRS_and_boundVerticalCRS_to_geogCRS) {
+
+ auto horizBoundCRS = BoundCRS::createFromTOWGS84(
+ ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4807,
+ Conversion::createUTM(PropertyMap(), 31, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)),
+ std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto compound = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{horizBoundCRS, createBoundVerticalCRS()});
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ compound, GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+ // Not completely sure the order of horizontal and vertical operations
+ // makes sense
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=utm +zone=31 +ellps=clrk80ign +pm=paris "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=clrk80ign "
+ "+step +proj=helmert +x=1 +y=2 +z=3 +rx=4 +ry=5 +rz=6 +s=7 "
+ "+convention=position_vector "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=vgridshift +grids=us_nga_egm08_25.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ auto opInverse = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4979, compound);
+ ASSERT_TRUE(opInverse != nullptr);
+ EXPECT_TRUE(opInverse->inverse()->isEquivalentTo(op.get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ compoundCRS_with_boundVerticalCRS_from_geoidgrids_with_m_to_geogCRS) {
+
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_NO_CHECK(src), GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(), "axis order change (2D) + "
+ "unknown to WGS84 ellipsoidal height");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ compoundCRS_with_boundVerticalCRS_from_geoidgrids_with_ftus_to_geogCRS) {
+
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +geoidgrids=@foo.gtx +vunits=us-ft "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_NO_CHECK(src), GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->nameStr(), "axis order change (2D) + "
+ "Transformation from unknown to unknown + "
+ "unknown to WGS84 ellipsoidal height");
+ EXPECT_EQ(
+ op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad +z_out=m "
+ "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ compoundCRS_with_boundProjCRS_with_ftus_and_boundVerticalCRS_to_geogCRS) {
+
+ auto wkt =
+ "COMPD_CS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet + "
+ "NAVD88 height - Geoid12B (US Feet)\",\n"
+ " PROJCS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"Degree\",0.0174532925199433]],\n"
+ " PROJECTION[\"Transverse_Mercator\"],\n"
+ " PARAMETER[\"latitude_of_origin\",30],\n"
+ " PARAMETER[\"central_meridian\",-87.5],\n"
+ " PARAMETER[\"scale_factor\",0.999933333333333],\n"
+ " PARAMETER[\"false_easting\",1968500],\n"
+ " PARAMETER[\"false_northing\",0],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Easting\",EAST],\n"
+ " AXIS[\"Northing\",NORTH],\n"
+ " AUTHORITY[\"ESRI\",\"102630\"]],\n"
+ " VERT_CS[\"NAVD88 height (ftUS)\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " EXTENSION[\"PROJ4_GRIDS\",\"foo.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"6360\"]]]";
+
+ auto obj = WKTParser().createFromWKT(wkt);
+ auto crs = nn_dynamic_pointer_cast<CompoundCRS>(obj);
+ ASSERT_TRUE(crs != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_NO_CHECK(crs), GeographicCRS::EPSG_4979);
+ ASSERT_TRUE(op != nullptr);
+
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
+ "+step +inv +proj=tmerc +lat_0=30 +lon_0=-87.5 "
+ "+k=0.999933333333333 +x_0=600000 +y_0=0 +ellps=GRS80 "
+ "+step +proj=unitconvert +z_in=us-ft +z_out=m "
+ "+step +proj=vgridshift +grids=foo.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ compoundCRS_with_boundVerticalCRS_from_grids_to_geogCRS_with_ftus_ctxt) {
+
+ auto dbContext = DatabaseContext::create();
+
+ const char *wktSrc =
+ "COMPD_CS[\"NAD83 + NAVD88 height - Geoid12B (Meters)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " EXTENSION[\"PROJ4_GRIDS\",\"@foo.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"metre\",1.0,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"5703\"]]]";
+ auto objSrc =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
+ auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCRS != nullptr);
+
+ const char *wktDst =
+ "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"Ellipsoid (US Feet)\",\n"
+ " VERT_DATUM[\"Ellipsoid\",2002],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Up\",UP]]]";
+ auto objDst =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktDst);
+ auto dstCRS = nn_dynamic_pointer_cast<GeographicCRS>(objDst);
+ ASSERT_TRUE(dstCRS != nullptr);
+
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCRS), NN_NO_CHECK(dstCRS), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m "
+ "+xy_out=deg +z_out=us-ft "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_with_boundGeogCRS_boundVerticalCRS_from_grids_to_boundGeogCRS_with_ftus_ctxt) {
+
+ // Variant of above but with TOWGS84 in source & target CRS
+
+ auto dbContext = DatabaseContext::create();
+
+ const char *wktSrc =
+ "COMPD_CS[\"NAD83 + NAVD88 height - Geoid12B (Meters)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " EXTENSION[\"PROJ4_GRIDS\",\"@foo.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"metre\",1.0,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"5703\"]]]";
+ auto objSrc =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
+ auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCRS != nullptr);
+
+ const char *wktDst =
+ "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"Ellipsoid (US Feet)\",\n"
+ " VERT_DATUM[\"Ellipsoid\",2002],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Up\",UP]]]";
+ auto objDst =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktDst);
+ auto dstCRS = nn_dynamic_pointer_cast<BoundCRS>(objDst);
+ ASSERT_TRUE(dstCRS != nullptr);
+
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCRS), NN_NO_CHECK(dstCRS), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m "
+ "+xy_out=deg +z_out=us-ft");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_with_boundVerticalCRS_from_grids_to_boundGeogCRS_with_ftus_ctxt) {
+
+ // Variant of above but with TOWGS84 in target CRS only
+
+ auto dbContext = DatabaseContext::create();
+
+ const char *wktSrc =
+ "COMPD_CS[\"NAD83 + NAVD88 height - Geoid12B (Meters)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " EXTENSION[\"PROJ4_GRIDS\",\"@foo.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"metre\",1.0,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"5703\"]]]";
+ auto objSrc =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
+ auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCRS != nullptr);
+
+ const char *wktDst =
+ "COMPD_CS[\"NAD83 + Ellipsoid (US Feet)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"Ellipsoid (US Feet)\",\n"
+ " VERT_DATUM[\"Ellipsoid\",2002],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Up\",UP]]]";
+ auto objDst =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktDst);
+ auto dstCRS = nn_dynamic_pointer_cast<BoundCRS>(objDst);
+ ASSERT_TRUE(dstCRS != nullptr);
+
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCRS), NN_NO_CHECK(dstCRS), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m "
+ "+xy_out=deg +z_out=us-ft "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ compoundCRS_with_boundGeogCRS_and_geoid_to_geodCRS_NAD2011_ctxt) {
+
+ auto dbContext = DatabaseContext::create();
+
+ const char *wktSrc =
+ "COMPD_CS[\"NAD83 / California zone 5 (ftUS) + "
+ "NAVD88 height - Geoid12B (ftUS)\","
+ " PROJCS[\"NAD83 / California zone 5 (ftUS)\","
+ " GEOGCS[\"NAD83\","
+ " DATUM[\"North_American_Datum_1983\","
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,"
+ " AUTHORITY[\"EPSG\",\"7019\"]],"
+ " TOWGS84[0,0,0,0,0,0,0],"
+ " AUTHORITY[\"EPSG\",\"6269\"]],"
+ " PRIMEM[\"Greenwich\",0,"
+ " AUTHORITY[\"EPSG\",\"8901\"]],"
+ " UNIT[\"degree\",0.0174532925199433,"
+ " AUTHORITY[\"EPSG\",\"9122\"]],"
+ " AUTHORITY[\"EPSG\",\"4269\"]],"
+ " PROJECTION[\"Lambert_Conformal_Conic_2SP\"],"
+ " PARAMETER[\"standard_parallel_1\",35.46666666666667],"
+ " PARAMETER[\"standard_parallel_2\",34.03333333333333],"
+ " PARAMETER[\"latitude_of_origin\",33.5],"
+ " PARAMETER[\"central_meridian\",-118],"
+ " PARAMETER[\"false_easting\",6561666.667],"
+ " PARAMETER[\"false_northing\",1640416.667],"
+ " UNIT[\"US survey foot\",0.3048006096012192,"
+ " AUTHORITY[\"EPSG\",\"9003\"]],"
+ " AXIS[\"X\",EAST],"
+ " AXIS[\"Y\",NORTH],"
+ " AUTHORITY[\"EPSG\",\"2229\"]],"
+ "VERT_CS[\"NAVD88 height - Geoid12B (ftUS)\","
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,"
+ " AUTHORITY[\"EPSG\",\"5103\"]],"
+ " UNIT[\"US survey foot\",0.3048006096012192,"
+ " AUTHORITY[\"EPSG\",\"9003\"]],"
+ " AXIS[\"Gravity-related height\",UP],"
+ " AUTHORITY[\"EPSG\",\"6360\"]]]";
+ auto objSrc =
+ WKTParser().attachDatabaseContext(dbContext).createFromWKT(wktSrc);
+ auto srcCRS = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCRS != nullptr);
+
+ auto authFactoryEPSG = AuthorityFactory::create(dbContext, "EPSG");
+ // NAD83(2011) geocentric
+ auto dstCRS = authFactoryEPSG->createCoordinateReferenceSystem("6317");
+
+ auto authFactory = AuthorityFactory::create(dbContext, std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCRS), dstCRS, ctxt);
+ bool found = false;
+ for (const auto &op : list) {
+ if (op->nameStr() ==
+ "Inverse of unnamed + "
+ "Transformation from NAD83 to WGS84 + "
+ "Ballpark geographic offset from WGS 84 to NAD83(2011) + "
+ "Transformation from NAVD88 height (ftUS) to NAVD88 height + "
+ "Inverse of NAD83(2011) to NAVD88 height (1) + "
+ "Conversion from NAD83(2011) (geog3D) to NAD83(2011) "
+ "(geocentric)") {
+ found = true;
+ EXPECT_EQ(
+ op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
+ "+step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 "
+ "+lat_1=35.4666666666667 +lat_2=34.0333333333333 "
+ "+x_0=2000000.0001016 +y_0=500000.0001016 +ellps=GRS80 "
+ "+step +proj=unitconvert +z_in=us-ft +z_out=m "
+ "+step +proj=vgridshift +grids=us_noaa_g2012bu0.tif "
+ "+multiplier=1 "
+ "+step +proj=cart +ellps=GRS80");
+ }
+ }
+ EXPECT_TRUE(found);
+ if (!found) {
+ for (const auto &op : list) {
+ std::cerr << op->nameStr() << std::endl;
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocent_to_compoundCRS) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=geocent +datum=WGS84 +units=m +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv "
+ "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv "
+ "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, geocent_to_compoundCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // WGS84 geocentric
+ auto src = authFactory->createCoordinateReferenceSystem("4978");
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ src, NN_CHECK_ASSERT(dst), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=cart +ellps=WGS84 +step +inv "
+ "+proj=vgridshift +grids=@foo.gtx +multiplier=1 +step +inv "
+ "+proj=hgridshift +grids=@foo.gsb +step +proj=unitconvert "
+ "+xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_compoundCRS) {
+ auto compound1 = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{createUTM31_WGS84(), createVerticalCRS()});
+ auto compound2 = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{createUTM32_WGS84(), createVerticalCRS()});
+ auto op = CoordinateOperationFactory::create()->createOperation(compound1,
+ compound2);
+ ASSERT_TRUE(op != nullptr);
+ auto opRef = CoordinateOperationFactory::create()->createOperation(
+ createUTM31_WGS84(), createUTM32_WGS84());
+ ASSERT_TRUE(opRef != nullptr);
+ EXPECT_TRUE(op->isEquivalentTo(opRef.get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_compoundCRS_with_vertical_transform) {
+ auto verticalCRS1 = createVerticalCRS();
+
+ auto verticalCRS2 = VerticalCRS::create(
+ PropertyMap(), VerticalReferenceFrame::create(PropertyMap()),
+ VerticalCS::createGravityRelatedHeight(UnitOfMeasure::METRE));
+
+ // Use of this type of transformation is a bit of non-sense here
+ // since it should normally be used with NGVD29 and NAVD88 for VerticalCRS,
+ // and NAD27/NAD83 as horizontal CRS...
+ auto vtransformation = Transformation::createVERTCON(
+ PropertyMap(), verticalCRS1, verticalCRS2, "bla.gtx",
+ std::vector<PositionalAccuracyNNPtr>());
+
+ auto compound1 = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{
+ ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4326,
+ Conversion::createTransverseMercator(PropertyMap(), Angle(1),
+ Angle(2), Scale(3),
+ Length(4), Length(5)),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)),
+ BoundCRS::create(verticalCRS1, verticalCRS2, vtransformation)});
+ auto compound2 = CompoundCRS::create(
+ PropertyMap(),
+ std::vector<CRSNNPtr>{createUTM32_WGS84(), verticalCRS2});
+
+ auto op = CoordinateOperationFactory::create()->createOperation(compound1,
+ compound2);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=tmerc +lat_0=1 +lon_0=2 +k=3 "
+ "+x_0=4 +y_0=5 +ellps=WGS84 +step "
+ "+proj=vgridshift +grids=bla.gtx +multiplier=0.001 +step "
+ "+proj=utm +zone=32 "
+ "+ellps=WGS84");
+ {
+ auto formatter = PROJStringFormatter::create();
+ formatter->setUseApproxTMerc(true);
+ EXPECT_EQ(
+ op->exportToPROJString(formatter.get()),
+ "+proj=pipeline +step +inv +proj=tmerc +approx +lat_0=1 +lon_0=2 "
+ "+k=3 +x_0=4 +y_0=5 +ellps=WGS84 +step "
+ "+proj=vgridshift +grids=bla.gtx +multiplier=0.001 +step "
+ "+proj=utm +approx +zone=32 "
+ "+ellps=WGS84");
+ }
+ {
+ auto formatter = PROJStringFormatter::create();
+ formatter->setUseApproxTMerc(true);
+ EXPECT_EQ(
+ op->inverse()->exportToPROJString(formatter.get()),
+ "+proj=pipeline +step +inv +proj=utm +approx +zone=32 +ellps=WGS84 "
+ "+step +inv +proj=vgridshift +grids=bla.gtx "
+ "+multiplier=0.001 +step +proj=tmerc +approx +lat_0=1 +lon_0=2 "
+ "+k=3 +x_0=4 +y_0=5 +ellps=WGS84");
+ }
+
+ auto opInverse = CoordinateOperationFactory::create()->createOperation(
+ compound2, compound1);
+ ASSERT_TRUE(opInverse != nullptr);
+ {
+ auto formatter = PROJStringFormatter::create();
+ auto formatter2 = PROJStringFormatter::create();
+ EXPECT_EQ(opInverse->inverse()->exportToPROJString(formatter.get()),
+ op->exportToPROJString(formatter2.get()));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=@foo.gsb "
+ "+step +proj=vgridshift +grids=@foo.gtx +multiplier=1 "
+ "+step +inv +proj=vgridshift +grids=@bar.gtx +multiplier=1 "
+ "+step +inv +proj=hgridshift +grids=@bar.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_geoidgrids) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=@foo.gsb "
+ "+step +inv +proj=hgridshift +grids=@bar.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_geoidgrids_different_vunits) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@foo.gtx "
+ "+vunits=us-ft +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=@foo.gsb "
+ "+step +proj=unitconvert +z_in=m +z_out=us-ft "
+ "+step +inv +proj=hgridshift +grids=@bar.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_nadgrids_same_geoidgrids) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS80 +nadgrids=@foo.gsb +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_same_towgs84_same_geoidgrids) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +towgs84=0,0,0 +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS80 +towgs84=0,0,0 +geoidgrids=@foo.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=GRS67 "
+ "+step +inv +proj=cart +ellps=GRS80 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_compoundCRS_with_bound_crs_in_horiz_and_vert_WKT1_same_geoidgrids_context) {
+ auto objSrc = WKTParser().createFromWKT(
+ "COMPD_CS[\"NAD83 / Alabama West + NAVD88 height - Geoid12B "
+ "(Meters)\",\n"
+ " PROJCS[\"NAD83 / Alabama West\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " PROJECTION[\"Transverse_Mercator\"],\n"
+ " PARAMETER[\"latitude_of_origin\",30],\n"
+ " PARAMETER[\"central_meridian\",-87.5],\n"
+ " PARAMETER[\"scale_factor\",0.999933333],\n"
+ " PARAMETER[\"false_easting\",600000],\n"
+ " PARAMETER[\"false_northing\",0],\n"
+ " UNIT[\"metre\",1,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"X\",EAST],\n"
+ " AXIS[\"Y\",NORTH],\n"
+ " AUTHORITY[\"EPSG\",\"26930\"]],\n"
+ " VERT_CS[\"NAVD88 height\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " "
+ "EXTENSION[\"PROJ4_GRIDS\",\"g2012a_alaska.gtx,g2012a_hawaii.gtx,"
+ "g2012a_conus.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"metre\",1,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"5703\"]]]");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = WKTParser().createFromWKT(
+ "COMPD_CS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet + NAVD88 "
+ "height - Geoid12B (US Feet)\",\n"
+ " PROJCS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0],\n"
+ " UNIT[\"Degree\",0.0174532925199433]],\n"
+ " PROJECTION[\"Transverse_Mercator\"],\n"
+ " PARAMETER[\"latitude_of_origin\",30],\n"
+ " PARAMETER[\"central_meridian\",-87.5],\n"
+ " PARAMETER[\"scale_factor\",0.999933333333333],\n"
+ " PARAMETER[\"false_easting\",1968500],\n"
+ " PARAMETER[\"false_northing\",0],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Easting\",EAST],\n"
+ " AXIS[\"Northing\",NORTH],\n"
+ " AUTHORITY[\"ESRI\",\"102630\"]],\n"
+ " VERT_CS[\"NAVD88 height (ftUS)\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " "
+ "EXTENSION[\"PROJ4_GRIDS\",\"g2012a_alaska.gtx,g2012a_hawaii.gtx,"
+ "g2012a_conus.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"US survey foot\",0.304800609601219,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"6360\"]]]");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of unnamed + "
+ "Transformation from NAD83 to WGS84 + "
+ "NAVD88 height to NAVD88 height (ftUS) + "
+ "Inverse of Transformation from NAD83 to WGS84 + "
+ "unnamed");
+ auto grids = list[0]->gridsNeeded(dbContext, false);
+ EXPECT_TRUE(grids.empty());
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=tmerc +lat_0=30 +lon_0=-87.5 +k=0.999933333 "
+ "+x_0=600000 +y_0=0 +ellps=GRS80 "
+ "+step +proj=unitconvert +z_in=m +z_out=us-ft "
+ "+step +proj=tmerc +lat_0=30 +lon_0=-87.5 +k=0.999933333333333 "
+ "+x_0=600000 +y_0=0 +ellps=GRS80 "
+ "+step +proj=unitconvert +xy_in=m +xy_out=us-ft");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_compoundCRS_issue_2232) {
+ auto objSrc = WKTParser().createFromWKT(
+ "COMPD_CS[\"NAD83 / Alabama West + NAVD88 height - Geoid12B "
+ "(Meters)\",\n"
+ " PROJCS[\"NAD83 / Alabama West\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " PROJECTION[\"Transverse_Mercator\"],\n"
+ " PARAMETER[\"latitude_of_origin\",30],\n"
+ " PARAMETER[\"central_meridian\",-87.5],\n"
+ " PARAMETER[\"scale_factor\",0.999933333],\n"
+ " PARAMETER[\"false_easting\",600000],\n"
+ " PARAMETER[\"false_northing\",0],\n"
+ " UNIT[\"metre\",1,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"X\",EAST],\n"
+ " AXIS[\"Y\",NORTH],\n"
+ " AUTHORITY[\"EPSG\",\"26930\"]],\n"
+ " VERT_CS[\"NAVD88 height - Geoid12B (Meters)\",\n"
+ " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n"
+ " EXTENSION[\"PROJ4_GRIDS\",\"foo.gtx\"],\n"
+ " AUTHORITY[\"EPSG\",\"5103\"]],\n"
+ " UNIT[\"metre\",1.0,\n"
+ " AUTHORITY[\"EPSG\",\"9001\"]],\n"
+ " AXIS[\"Gravity-related height\",UP],\n"
+ " AUTHORITY[\"EPSG\",\"5703\"]]]");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = WKTParser().createFromWKT(
+ "COMPD_CS[\"NAD83 + some CRS (US Feet)\",\n"
+ " GEOGCS[\"NAD83\",\n"
+ " DATUM[\"North_American_Datum_1983\",\n"
+ " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n"
+ " AUTHORITY[\"EPSG\",\"7019\"]],\n"
+ " TOWGS84[0,0,0,0,0,0,0],\n"
+ " AUTHORITY[\"EPSG\",\"6269\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AUTHORITY[\"EPSG\",\"4269\"]],\n"
+ " VERT_CS[\"some CRS (US Feet)\",\n"
+ " VERT_DATUM[\"some datum\",2005],\n"
+ " UNIT[\"US survey foot\",0.3048006096012192,\n"
+ " AUTHORITY[\"EPSG\",\"9003\"]],\n"
+ " AXIS[\"Up\",UP]]]");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst), ctxt);
+ EXPECT_GE(list.size(), 1U);
+
+ auto list2 = CoordinateOperationFactory::create()->createOperations(
+ NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src), ctxt);
+ EXPECT_EQ(list2.size(), list.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_compoundCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NAD27 + NGVD29 height (ftUS)
+ authFactory->createCoordinateReferenceSystem("7406"),
+ // NAD83(NSRS2007) + NAVD88 height
+ authFactory->createCoordinateReferenceSystem("5500"), ctxt);
+ // 152 or 155 depending if the VERTCON grids are there
+ ASSERT_GE(list.size(), 152U);
+ EXPECT_FALSE(list[0]->hasBallparkTransformation());
+ EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (ftUS) to NAVD88 height (3) + "
+ "NAD27 to WGS 84 (79) + Inverse of "
+ "NAD83(NSRS2007) to WGS 84 (1)");
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad +z_out=m "
+ "+step +proj=vgridshift +grids=us_noaa_vertcone.tif +multiplier=1 "
+ "+step +proj=hgridshift +grids=us_noaa_conus.tif +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap "
+ "+order=2,1");
+ {
+ // Test that we can round-trip this through WKT and still get the same
+ // PROJ string.
+ auto wkt = list[0]->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get());
+ auto obj = WKTParser().createFromWKT(wkt);
+ auto co = nn_dynamic_pointer_cast<CoordinateOperation>(obj);
+ ASSERT_TRUE(co != nullptr);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ co->exportToPROJString(PROJStringFormatter::create().get()));
+ }
+
+ bool foundApprox = false;
+ for (size_t i = 0; i < list.size(); i++) {
+ auto projString =
+ list[i]->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_TRUE(
+ projString.find("+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +z_in=us-ft "
+ "+xy_out=rad +z_out=m") == 0)
+ << list[i]->nameStr();
+ if (list[i]->nameStr().find("Transformation from NGVD29 height (ftUS) "
+ "to NAVD88 height (ballpark vertical "
+ "transformation)") == 0) {
+ EXPECT_TRUE(list[i]->hasBallparkTransformation());
+ EXPECT_EQ(list[i]->nameStr(),
+ "Transformation from NGVD29 height (ftUS) to NAVD88 "
+ "height (ballpark vertical transformation) + NAD27 to "
+ "WGS 84 (79) + Inverse of NAD83(NSRS2007) to WGS 84 (1)");
+ EXPECT_EQ(
+ projString,
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad "
+ "+z_out=m +step +proj=hgridshift +grids=us_noaa_conus.tif "
+ "+step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+ foundApprox = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(foundApprox);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_compoundCRS_context_helmert_noop) {
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ // WGS84 + EGM96
+ auto objSrc = createFromUserInput("EPSG:4326+5773", dbContext);
+ auto srcCrs = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCrs != nullptr);
+ // ETRS89 + EGM96
+ auto objDest = createFromUserInput("EPSG:4258+5773", dbContext);
+ auto destCrs = nn_dynamic_pointer_cast<CompoundCRS>(objDest);
+ ASSERT_TRUE(destCrs != nullptr);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCrs), NN_NO_CHECK(destCrs), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=noop");
+}
+
+// ---------------------------------------------------------------------------
+
+// EGM96 has a geoid model referenced to WGS84, and Belfast height has a
+// geoid model referenced to ETRS89
+TEST(operation, compoundCRS_to_compoundCRS_WGS84_EGM96_to_ETRS89_Belfast) {
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ // WGS84 + EGM96
+ auto objSrc = createFromUserInput("EPSG:4326+5773", dbContext);
+ auto srcCrs = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCrs != nullptr);
+ // ETRS89 + Belfast height
+ auto objDest = createFromUserInput("EPSG:4258+5732", dbContext);
+ auto destCrs = nn_dynamic_pointer_cast<CompoundCRS>(objDest);
+ ASSERT_TRUE(destCrs != nullptr);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCrs), NN_NO_CHECK(destCrs), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
+ "Inverse of ETRS89 to WGS 84 (1) + "
+ "ETRS89 to Belfast height (2)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
+ "+step +inv +proj=vgridshift +grids=uk_os_OSGM15_Belfast.tif "
+ "+multiplier=1 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+// Variant of above where source intermediate geog3D CRS == target intermediate
+// geog3D CRS
+TEST(operation, compoundCRS_to_compoundCRS_WGS84_EGM96_to_WGS84_Belfast) {
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ // WGS84 + EGM96
+ auto objSrc = createFromUserInput("EPSG:4326+5773", dbContext);
+ auto srcCrs = nn_dynamic_pointer_cast<CompoundCRS>(objSrc);
+ ASSERT_TRUE(srcCrs != nullptr);
+ // WGS84 + Belfast height
+ auto objDest = createFromUserInput("EPSG:4326+5732", dbContext);
+ auto destCrs = nn_dynamic_pointer_cast<CompoundCRS>(objDest);
+ ASSERT_TRUE(destCrs != nullptr);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCrs), NN_NO_CHECK(destCrs), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
+ "Inverse of ETRS89 to WGS 84 (1) + "
+ "ETRS89 to Belfast height (2) + "
+ "ETRS89 to WGS 84 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
+ "+step +inv +proj=vgridshift +grids=uk_os_OSGM15_Belfast.tif "
+ "+multiplier=1 +step "
+ "+proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_compoundCRS_concatenated_operation_with_two_vert_transformation) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // ETRS89 + Baltic 1957 height
+ authFactory->createCoordinateReferenceSystem("8360"),
+ // ETRS89 + EVRF2007 height
+ authFactory->createCoordinateReferenceSystem("7423"), ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift "
+ "+grids=sk_gku_Slovakia_ETRS89h_to_Baltic1957.tif +multiplier=1 "
+ "+step +inv +proj=vgridshift "
+ "+grids=sk_gku_Slovakia_ETRS89h_to_EVRF2007.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ EXPECT_EQ(
+ list[0]->nameStr(),
+ "ETRS89 + Baltic 1957 height to ETRS89 + EVRF2007 height (1)");
+ EXPECT_EQ(list[0]->inverse()->nameStr(), "Inverse of 'ETRS89 + Baltic "
+ "1957 height to ETRS89 + "
+ "EVRF2007 height (1)'");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, vertCRS_to_vertCRS) {
+
+ auto vertcrs_m_obj = PROJStringParser().createFromPROJString("+vunits=m");
+ auto vertcrs_m = nn_dynamic_pointer_cast<VerticalCRS>(vertcrs_m_obj);
+ ASSERT_TRUE(vertcrs_m != nullptr);
+
+ auto vertcrs_ft_obj = PROJStringParser().createFromPROJString("+vunits=ft");
+ auto vertcrs_ft = nn_dynamic_pointer_cast<VerticalCRS>(vertcrs_ft_obj);
+ ASSERT_TRUE(vertcrs_ft != nullptr);
+
+ auto vertcrs_us_ft_obj =
+ PROJStringParser().createFromPROJString("+vunits=us-ft");
+ auto vertcrs_us_ft =
+ nn_dynamic_pointer_cast<VerticalCRS>(vertcrs_us_ft_obj);
+ ASSERT_TRUE(vertcrs_us_ft != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(vertcrs_m), NN_CHECK_ASSERT(vertcrs_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=unitconvert +z_in=m +z_out=ft");
+ }
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(vertcrs_m), NN_CHECK_ASSERT(vertcrs_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->inverse()->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "+proj=unitconvert +z_in=ft +z_out=m");
+ }
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(vertcrs_ft), NN_CHECK_ASSERT(vertcrs_m));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=unitconvert +z_in=ft +z_out=m");
+ }
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(vertcrs_ft), NN_CHECK_ASSERT(vertcrs_us_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=affine +s33=0.999998");
+ }
+
+ auto vertCRSMetreUp =
+ nn_dynamic_pointer_cast<VerticalCRS>(WKTParser().createFromWKT(
+ "VERTCRS[\"my height\",VDATUM[\"my datum\"],CS[vertical,1],"
+ "AXIS[\"gravity-related height (H)\",up,"
+ "LENGTHUNIT[\"metre\",1]]]"));
+ ASSERT_TRUE(vertCRSMetreUp != nullptr);
+
+ auto vertCRSMetreDown =
+ nn_dynamic_pointer_cast<VerticalCRS>(WKTParser().createFromWKT(
+ "VERTCRS[\"my depth\",VDATUM[\"my datum\"],CS[vertical,1],"
+ "AXIS[\"depth (D)\",down,LENGTHUNIT[\"metre\",1]]]"));
+ ASSERT_TRUE(vertCRSMetreDown != nullptr);
+
+ auto vertCRSMetreDownFtUS =
+ nn_dynamic_pointer_cast<VerticalCRS>(WKTParser().createFromWKT(
+ "VERTCRS[\"my depth (ftUS)\",VDATUM[\"my datum\"],CS[vertical,1],"
+ "AXIS[\"depth (D)\",down,LENGTHUNIT[\"US survey "
+ "foot\",0.304800609601219]]]"));
+ ASSERT_TRUE(vertCRSMetreDownFtUS != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(vertCRSMetreUp), NN_CHECK_ASSERT(vertCRSMetreDown));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=axisswap +order=1,2,-3");
+ }
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(vertCRSMetreUp),
+ NN_CHECK_ASSERT(vertCRSMetreDownFtUS));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=affine +s33=-3.28083333333333");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, vertCRS_to_vertCRS_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NGVD29 height (m)
+ authFactory->createCoordinateReferenceSystem("7968"),
+ // NAVD88 height (1)
+ authFactory->createCoordinateReferenceSystem("5703"), ctxt);
+ ASSERT_EQ(list.size(), 3U);
+ EXPECT_EQ(list[0]->nameStr(), "NGVD29 height (m) to NAVD88 height (3)");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=vgridshift +grids=us_noaa_vertcone.tif +multiplier=1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, vertCRS_to_vertCRS_New_Zealand_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NZVD2016 height
+ authFactory->createCoordinateReferenceSystem("7839"),
+ // Auckland 1946 height
+ authFactory->createCoordinateReferenceSystem("5759"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=vgridshift +grids=nz_linz_auckht1946-nzvd2016.tif "
+ "+multiplier=1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, projCRS_3D_to_geogCRS_3D) {
+
+ auto compoundcrs_ft_obj = PROJStringParser().createFromPROJString(
+ "+proj=merc +vunits=ft +type=crs");
+ auto proj3DCRS_ft = nn_dynamic_pointer_cast<CRS>(compoundcrs_ft_obj);
+ ASSERT_TRUE(proj3DCRS_ft != nullptr);
+
+ auto geogcrs_m_obj = PROJStringParser().createFromPROJString(
+ "+proj=longlat +vunits=m +type=crs");
+ auto geogcrs_m = nn_dynamic_pointer_cast<CRS>(geogcrs_m_obj);
+ ASSERT_TRUE(geogcrs_m != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(proj3DCRS_ft), NN_CHECK_ASSERT(geogcrs_m));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_FALSE(op->hasBallparkTransformation());
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=m +z_in=ft "
+ "+xy_out=m +z_out=m "
+ "+step +inv +proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 "
+ "+ellps=WGS84 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m "
+ "+xy_out=deg +z_out=m");
+ }
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(proj3DCRS_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_FALSE(op->hasBallparkTransformation());
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +z_in=m +z_out=ft "
+ "+step +proj=unitconvert +xy_in=deg +z_in=ft "
+ "+xy_out=rad +z_out=m "
+ "+step +proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 "
+ "+step +proj=unitconvert +xy_in=m +z_in=m "
+ "+xy_out=m +z_out=ft");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS_3D) {
+
+ auto compoundcrs_ft_obj = WKTParser().createFromWKT(
+ "COMPOUNDCRS[\"unknown\",\n"
+ " PROJCRS[\"unknown\",\n"
+ " BASEGEOGCRS[\"unknown\",\n"
+ " DATUM[\"World Geodetic System 1984\",\n"
+ " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " ID[\"EPSG\",6326]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8901]]],\n"
+ " CONVERSION[\"unknown\",\n"
+ " METHOD[\"Mercator (variant A)\",\n"
+ " ID[\"EPSG\",9804]],\n"
+ " PARAMETER[\"Latitude of natural origin\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8801]],\n"
+ " PARAMETER[\"Longitude of natural origin\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8802]],\n"
+ " PARAMETER[\"Scale factor at natural origin\",1,\n"
+ " SCALEUNIT[\"unity\",1],\n"
+ " ID[\"EPSG\",8805]],\n"
+ " PARAMETER[\"False easting\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8806]],\n"
+ " PARAMETER[\"False northing\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8807]]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"(E)\",east,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"metre\",1,\n"
+ " ID[\"EPSG\",9001]]],\n"
+ " AXIS[\"(N)\",north,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"metre\",1,\n"
+ " ID[\"EPSG\",9001]]]],\n"
+ " VERTCRS[\"unknown\",\n"
+ " VDATUM[\"unknown\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"foot\",0.3048,\n"
+ " ID[\"EPSG\",9002]]]]]");
+ auto compoundcrs_ft = nn_dynamic_pointer_cast<CRS>(compoundcrs_ft_obj);
+ ASSERT_TRUE(compoundcrs_ft != nullptr);
+
+ auto geogcrs_m_obj = PROJStringParser().createFromPROJString(
+ "+proj=longlat +vunits=m +type=crs");
+ auto geogcrs_m = nn_dynamic_pointer_cast<CRS>(geogcrs_m_obj);
+ ASSERT_TRUE(geogcrs_m != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(compoundcrs_ft), NN_CHECK_ASSERT(geogcrs_m));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_TRUE(op->hasBallparkTransformation());
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=merc +lon_0=0 +k=1 +x_0=0 "
+ "+y_0=0 +ellps=WGS84 +step +proj=unitconvert +xy_in=rad "
+ "+z_in=ft +xy_out=deg +z_out=m");
+ }
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(geogcrs_m), NN_CHECK_ASSERT(compoundcrs_ft));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_TRUE(op->hasBallparkTransformation());
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=unitconvert +xy_in=deg +z_in=m "
+ "+xy_out=rad +z_out=ft +step +proj=merc +lon_0=0 +k=1 +x_0=0 "
+ "+y_0=0 +ellps=WGS84");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS_3D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ // CompoundCRS to Geog3DCRS, with vertical unit change, but without
+ // ellipsoid height <--> vertical height correction
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem(
+ "7406"), // NAD27 + NGVD29 height (ftUS)
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_TRUE(list[0]->hasBallparkTransformation());
+ EXPECT_EQ(list[0]->nameStr(),
+ "NAD27 to WGS 84 (79) + Transformation from NGVD29 height "
+ "(ftUS) to WGS 84 (ballpark vertical transformation, without "
+ "ellipsoid height to vertical height correction)");
+ EXPECT_EQ(list[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step "
+ "+proj=unitconvert +xy_in=deg +xy_out=rad +step "
+ "+proj=hgridshift +grids=us_noaa_conus.tif "
+ "+step +proj=unitconvert "
+ "+xy_in=rad +z_in=us-ft +xy_out=deg +z_out=m +step "
+ "+proj=axisswap +order=2,1");
+ }
+
+ // CompoundCRS to Geog3DCRS, with same vertical unit, and with
+ // direct ellipsoid height <--> vertical height correction and
+ // direct horizontal transform (no-op here)
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ authFactory->createCoordinateReferenceSystem(
+ "5500"), // NAD83(NSRS2007) + NAVD88 height
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of NAD83(NSRS2007) to NAVD88 height (1) + "
+ "NAD83(NSRS2007) to WGS 84 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_noaa_geoid09_conus.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ EXPECT_EQ(list[0]->remarks(),
+ "For NAD83(NSRS2007) to NAVD88 height (1) (EPSG:9173): Uses "
+ "Geoid09 hybrid model. Replaced by 2012 model (CT code 6326)."
+ "\n"
+ "For NAD83(NSRS2007) to WGS 84 (1) (EPSG:15931): "
+ "Approximation at the +/- 1m level assuming that "
+ "NAD83(NSRS2007) is equivalent to WGS 84 within the accuracy "
+ "of the transformation.");
+ }
+
+ // NAD83 + NAVD88 height --> WGS 84
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83 + NAVD88 height
+ auto srcObj = createFromUserInput(
+ "EPSG:4269+5703", authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ nnSrc,
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ ctxt);
+ ASSERT_GE(list.size(), 2U);
+
+ EXPECT_EQ(list[0]->nameStr(),
+ "NAD83 to WGS 84 (1) + "
+ "Inverse of NAD83(NSRS2007) to WGS 84 (1) + "
+ "Inverse of NAD83(NSRS2007) to NAVD88 height (1) + "
+ "NAD83(NSRS2007) to WGS 84 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_noaa_geoid09_conus.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+
+ // Another variation, but post horizontal adjustment is in two steps
+ {
+ auto ctxt =
+ CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83(2011) + NAVD88 height
+ auto srcObj = createFromUserInput(
+ "EPSG:6318+5703", authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ nnSrc,
+ authFactory->createCoordinateReferenceSystem("4979"), // WGS 84
+ ctxt);
+ ASSERT_GE(list.size(), 2U);
+
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of NAD83(2011) to NAVD88 height (3) + "
+ "Inverse of NAD83 to NAD83(2011) (1) + "
+ "NAD83 to WGS 84 (1)");
+ EXPECT_EQ(list[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_noaa_g2018u0.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+
+ // Shows vertical step, and then horizontal step
+ EXPECT_EQ(list[1]->nameStr(),
+ "Inverse of NAD83(2011) to NAVD88 height (3) + "
+ "Inverse of NAD83 to NAD83(2011) (1) + "
+ "NAD83 to WGS 84 (18)");
+ EXPECT_EQ(list[1]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_noaa_g2018u0.tif "
+ "+multiplier=1 "
+ "+step +proj=hgridshift +grids=us_noaa_FL.tif "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS_3D_with_3D_helmert_context) {
+ // Use case of https://github.com/OSGeo/PROJ/issues/2225
+ auto dbContext = DatabaseContext::create();
+ auto authFactory = AuthorityFactory::create(dbContext, "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // WGS84 + EGM96 height
+ auto srcObj = createFromUserInput("EPSG:4326+5773", dbContext, false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src),
+ // CH1903+
+ authFactory->createCoordinateReferenceSystem("4150")->promoteTo3D(
+ std::string(), dbContext),
+ ctxt);
+ ASSERT_GE(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "Inverse of WGS 84 to EGM96 height (1) + "
+ "Inverse of CH1903+ to WGS 84 (1)");
+ // Check that there is no push v_3 / pop v_3
+ const char *expected_proj =
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=vgridshift +grids=us_nga_egm96_15.tif +multiplier=1 "
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=-674.374 +y=-15.056 +z=-405.346 "
+ "+step +inv +proj=cart +ellps=bessel "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1";
+ EXPECT_EQ(list[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5, dbContext)
+ .get()),
+ expected_proj);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS_2D_promote_to_3D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83 + NAVD88 height
+ auto srcObj = createFromUserInput("EPSG:4269+5703",
+ authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+ auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
+
+ auto listCompoundToGeog2D =
+ CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
+ ctxt);
+ // The checked value is not that important, but in case this changes,
+ // likely due to a EPSG upgrade, worth checking
+ EXPECT_EQ(listCompoundToGeog2D.size(), 142U);
+
+ auto listGeog2DToCompound =
+ CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
+ ctxt);
+ EXPECT_EQ(listGeog2DToCompound.size(), listCompoundToGeog2D.size());
+
+ auto listCompoundToGeog3D =
+ CoordinateOperationFactory::create()->createOperations(
+ nnSrc,
+ dst->promoteTo3D(std::string(), authFactory->databaseContext()),
+ ctxt);
+ EXPECT_EQ(listCompoundToGeog3D.size(), listCompoundToGeog2D.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_of_projCRS_to_geogCRS_2D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // SPCS83 California zone 1 (US Survey feet) + NAVD88 height (ftUS)
+ auto srcObj = createFromUserInput("EPSG:2225+6360",
+ authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+ auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ nnSrc, dst, ctxt);
+ // The checked value is not that important, but in case this changes,
+ // likely due to a EPSG upgrade, worth checking
+ // We want to make sure that the horizontal adjustments before and after
+ // the vertical transformation are the reverse of each other, and there are
+ // not mixes with different alternative operations (like California grid
+ // forward and Nevada grid reverse)
+ ASSERT_EQ(list.size(), 14U);
+
+ // Check that unit conversion is OK
+ auto op_proj =
+ list[0]->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_EQ(op_proj,
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
+ "+step +inv +proj=lcc +lat_0=39.3333333333333 +lon_0=-122 "
+ "+lat_1=41.6666666666667 +lat_2=40 +x_0=2000000.0001016 "
+ "+y_0=500000.0001016 +ellps=GRS80 "
+ "+step +proj=unitconvert +z_in=us-ft +z_out=m "
+ "+step +proj=vgridshift +grids=us_noaa_geoid09_conus.tif "
+ "+multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_from_wkt_without_id_to_geogCRS) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto wkt =
+ "COMPOUNDCRS[\"NAD83(2011) + NAVD88 height\",\n"
+ " GEOGCRS[\"NAD83(2011)\",\n"
+ " DATUM[\"NAD83 (National Spatial Reference System 2011)\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " CS[ellipsoidal,2],\n"
+ " AXIS[\"geodetic latitude (Lat)\",north,\n"
+ " ORDER[1],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]],\n"
+ " AXIS[\"geodetic longitude (Lon)\",east,\n"
+ " ORDER[2],\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
+ " VERTCRS[\"NAVD88 height\",\n"
+ " VDATUM[\"North American Vertical Datum 1988\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"metre\",1]]]]";
+ auto srcObj =
+ createFromUserInput(wkt, authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011)
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), dst, ctxt);
+ // NAD83(2011) + NAVD88 height
+ auto srcRefObj = createFromUserInput("EPSG:6318+5703",
+ authFactory->databaseContext(), false);
+ auto srcRef = nn_dynamic_pointer_cast<CRS>(srcRefObj);
+ ASSERT_TRUE(srcRef != nullptr);
+ ASSERT_TRUE(
+ src->isEquivalentTo(srcRef.get(), IComparable::Criterion::EQUIVALENT));
+ auto listRef = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcRef), dst, ctxt);
+
+ EXPECT_EQ(list.size(), listRef.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ compoundCRS_of_projCRS_from_wkt_without_id_or_extent_to_geogCRS) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto wkt =
+ "COMPOUNDCRS[\"NAD83 / Pennsylvania South + NAVD88 height\",\n"
+ " PROJCRS[\"NAD83 / Pennsylvania South\",\n"
+ " BASEGEOGCRS[\"NAD83\",\n"
+ " DATUM[\"North American Datum 1983\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
+ " CONVERSION[\"SPCS83 Pennsylvania South zone (meters)\",\n"
+ " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
+ " ID[\"EPSG\",9802]],\n"
+ " PARAMETER[\"Latitude of false origin\",39.3333333333333,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8821]],\n"
+ " PARAMETER[\"Longitude of false origin\",-77.75,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8822]],\n"
+ " PARAMETER[\"Latitude of 1st standard "
+ "parallel\",40.9666666666667,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8823]],\n"
+ " PARAMETER[\"Latitude of 2nd standard "
+ "parallel\",39.9333333333333,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8824]],\n"
+ " PARAMETER[\"Easting at false origin\",600000,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8826]],\n"
+ " PARAMETER[\"Northing at false origin\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8827]]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"easting (X)\",east,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " AXIS[\"northing (Y)\",north,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " VERTCRS[\"NAVD88 height\",\n"
+ " VDATUM[\"North American Vertical Datum 1988\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"metre\",1]]]]";
+ auto srcObj =
+ createFromUserInput(wkt, authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), dst, ctxt);
+ // NAD83 / Pennsylvania South + NAVD88 height
+ auto srcRefObj = createFromUserInput("EPSG:32129+5703",
+ authFactory->databaseContext(), false);
+ auto srcRef = nn_dynamic_pointer_cast<CRS>(srcRefObj);
+ ASSERT_TRUE(srcRef != nullptr);
+ ASSERT_TRUE(
+ src->isEquivalentTo(srcRef.get(), IComparable::Criterion::EQUIVALENT));
+ auto listRef = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcRef), dst, ctxt);
+
+ EXPECT_EQ(list.size(), listRef.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS_with_vertical_unit_change) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83(2011) + NAVD88 height (ftUS)
+ auto srcObj = createFromUserInput("EPSG:6318+6360",
+ authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011) 3D
+
+ auto listCompoundToGeog =
+ CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
+ ctxt);
+ ASSERT_TRUE(!listCompoundToGeog.empty());
+
+ // NAD83(2011) + NAVD88 height
+ auto srcObjCompoundVMetre = createFromUserInput(
+ "EPSG:6318+5703", authFactory->databaseContext(), false);
+ auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
+ ASSERT_TRUE(srcCompoundVMetre != nullptr);
+ auto listCompoundMetreToGeog =
+ CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
+
+ // Check that we get the same and similar results whether we start from
+ // regular NAVD88 height or its ftUs variant
+ ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
+
+ EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
+ "Inverse of NAVD88 height to NAVD88 height (ftUS) + " +
+ listCompoundMetreToGeog[0]->nameStr());
+ EXPECT_EQ(
+ listCompoundToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
+ "+step +proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad "
+ "+z_out=m"));
+
+ // Check reverse path
+ auto listGeogToCompound =
+ CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
+ ctxt);
+ EXPECT_EQ(listGeogToCompound.size(), listCompoundToGeog.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_geogCRS_with_vertical_unit_change_and_complex_horizontal_change) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83(2011) + NAVD88 height (ftUS)
+ auto srcObj = createFromUserInput("EPSG:6318+6360",
+ authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("7665"); // WGS84(G1762) 3D
+
+ auto listCompoundToGeog =
+ CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
+ ctxt);
+
+ // NAD83(2011) + NAVD88 height
+ auto srcObjCompoundVMetre = createFromUserInput(
+ "EPSG:6318+5703", authFactory->databaseContext(), false);
+ auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
+ ASSERT_TRUE(srcCompoundVMetre != nullptr);
+ auto listCompoundMetreToGeog =
+ CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
+
+ // Check that we get the same and similar results whether we start from
+ // regular NAVD88 height or its ftUs variant
+ ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
+
+ ASSERT_GE(listCompoundToGeog.size(), 1U);
+
+ EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
+ "Inverse of NAVD88 height to NAVD88 height (ftUS) + " +
+ listCompoundMetreToGeog[0]->nameStr());
+ EXPECT_EQ(
+ listCompoundToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
+ "+step +proj=unitconvert +xy_in=deg +z_in=us-ft +xy_out=rad "
+ "+z_out=m"));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_to_geogCRS_with_height_depth_reversal) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83(2011) + NAVD88 depth
+ auto srcObj = createFromUserInput("EPSG:6318+6357",
+ authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011) 3D
+
+ auto listCompoundToGeog =
+ CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
+ ctxt);
+ ASSERT_TRUE(!listCompoundToGeog.empty());
+
+ // NAD83(2011) + NAVD88 height
+ auto srcObjCompoundVMetre = createFromUserInput(
+ "EPSG:6318+5703", authFactory->databaseContext(), false);
+ auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
+ ASSERT_TRUE(srcCompoundVMetre != nullptr);
+ auto listCompoundMetreToGeog =
+ CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
+
+ // Check that we get the same and similar results whether we start from
+ // regular NAVD88 height or its depth variant
+ ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
+
+ EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
+ "Inverse of NAVD88 height to NAVD88 depth + " +
+ listCompoundMetreToGeog[0]->nameStr());
+ EXPECT_EQ(
+ listCompoundToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=axisswap +order=1,2,-3"));
+
+ // Check reverse path
+ auto listGeogToCompound =
+ CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
+ ctxt);
+ EXPECT_EQ(listGeogToCompound.size(), listCompoundToGeog.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ compoundCRS_to_geogCRS_with_vertical_unit_change_and_height_depth_reversal) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ // NAD83(2011) + NAVD88 depth (ftUS)
+ auto srcObj = createFromUserInput("EPSG:6318+6358",
+ authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto nnSrc = NN_NO_CHECK(src);
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("6319"); // NAD83(2011) 3D
+
+ auto listCompoundToGeog =
+ CoordinateOperationFactory::create()->createOperations(nnSrc, dst,
+ ctxt);
+ ASSERT_TRUE(!listCompoundToGeog.empty());
+
+ // NAD83(2011) + NAVD88 height
+ auto srcObjCompoundVMetre = createFromUserInput(
+ "EPSG:6318+5703", authFactory->databaseContext(), false);
+ auto srcCompoundVMetre = nn_dynamic_pointer_cast<CRS>(srcObjCompoundVMetre);
+ ASSERT_TRUE(srcCompoundVMetre != nullptr);
+ auto listCompoundMetreToGeog =
+ CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(srcCompoundVMetre), dst, ctxt);
+
+ // Check that we get the same and similar results whether we start from
+ // regular NAVD88 height or its depth (ftUS) variant
+ ASSERT_EQ(listCompoundToGeog.size(), listCompoundMetreToGeog.size());
+
+ EXPECT_EQ(listCompoundToGeog[0]->nameStr(),
+ "Inverse of NAVD88 height (ftUS) to NAVD88 depth (ftUS) + "
+ "Inverse of NAVD88 height to NAVD88 height (ftUS) + " +
+ listCompoundMetreToGeog[0]->nameStr());
+ EXPECT_EQ(
+ listCompoundToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ replaceAll(listCompoundMetreToGeog[0]->exportToPROJString(
+ PROJStringFormatter::create(
+ PROJStringFormatter::Convention::PROJ_5,
+ authFactory->databaseContext())
+ .get()),
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad",
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=axisswap +order=1,2,-3 "
+ "+step +proj=unitconvert +z_in=us-ft +z_out=m"));
+
+ // Check reverse path
+ auto listGeogToCompound =
+ CoordinateOperationFactory::create()->createOperations(dst, nnSrc,
+ ctxt);
+ EXPECT_EQ(listGeogToCompound.size(), listCompoundToGeog.size());
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_of_vertCRS_with_geoid_model_to_geogCRS) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ auto wkt =
+ "COMPOUNDCRS[\"NAD83 / Pennsylvania South + NAVD88 height\",\n"
+ " PROJCRS[\"NAD83 / Pennsylvania South\",\n"
+ " BASEGEOGCRS[\"NAD83\",\n"
+ " DATUM[\"North American Datum 1983\",\n"
+ " ELLIPSOID[\"GRS 1980\",6378137,298.257222101,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433]]],\n"
+ " CONVERSION[\"SPCS83 Pennsylvania South zone (meters)\",\n"
+ " METHOD[\"Lambert Conic Conformal (2SP)\",\n"
+ " ID[\"EPSG\",9802]],\n"
+ " PARAMETER[\"Latitude of false origin\",39.3333333333333,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8821]],\n"
+ " PARAMETER[\"Longitude of false origin\",-77.75,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8822]],\n"
+ " PARAMETER[\"Latitude of 1st standard "
+ "parallel\",40.9666666666667,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8823]],\n"
+ " PARAMETER[\"Latitude of 2nd standard "
+ "parallel\",39.9333333333333,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8824]],\n"
+ " PARAMETER[\"Easting at false origin\",600000,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8826]],\n"
+ " PARAMETER[\"Northing at false origin\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8827]]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"easting (X)\",east,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " AXIS[\"northing (Y)\",north,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " VERTCRS[\"NAVD88 height\",\n"
+ " VDATUM[\"North American Vertical Datum 1988\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " GEOIDMODEL[\"GEOID12B\"]]]";
+ auto srcObj =
+ createFromUserInput(wkt, authFactory->databaseContext(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(srcObj);
+ ASSERT_TRUE(src != nullptr);
+ auto dst = authFactory->createCoordinateReferenceSystem("4269"); // NAD83
+
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), dst, ctxt);
+ ASSERT_TRUE(!list.empty());
+ EXPECT_EQ(list[0]->nameStr(),
+ "Inverse of SPCS83 Pennsylvania South zone (meters) + "
+ "Ballpark geographic offset from NAD83 to NAD83(2011) + "
+ "Inverse of NAD83(2011) to NAVD88 height (1) + "
+ "Ballpark geographic offset from NAD83(2011) to NAD83");
+ auto op_proj =
+ list[0]->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_EQ(
+ op_proj,
+ "+proj=pipeline "
+ "+step +inv +proj=lcc +lat_0=39.3333333333333 +lon_0=-77.75 "
+ "+lat_1=40.9666666666667 +lat_2=39.9333333333333 +x_0=600000 "
+ "+y_0=0 +ellps=GRS80 "
+ "+step +proj=vgridshift +grids=us_noaa_g2012bu0.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_from_WKT2_to_geogCRS_3D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto src = authFactory->createCoordinateReferenceSystem(
+ "7415"); // Amersfoort / RD New + NAP height
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+ auto wkt2 = src->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get());
+ auto obj = WKTParser().createFromWKT(wkt2);
+ auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
+ ASSERT_TRUE(src_from_wkt2 != nullptr);
+ auto list2 = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src_from_wkt2), dst, ctxt);
+ ASSERT_GE(list.size(), list2.size());
+ for (size_t i = 0; i < list.size(); i++) {
+ const auto &op = list[i];
+ const auto &op2 = list2[i];
+ EXPECT_TRUE(
+ op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_from_WKT2_no_id_to_geogCRS_3D_context) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto src = authFactory->createCoordinateReferenceSystem(
+ "7415"); // Amersfoort / RD New + NAP height
+ auto dst =
+ authFactory->createCoordinateReferenceSystem("4937"); // ETRS89 3D
+ auto list =
+ CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
+ ASSERT_GE(list.size(), 1U);
+
+ {
+ auto op_proj =
+ list[0]->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_EQ(
+ op_proj,
+ "+proj=pipeline +step +inv +proj=sterea +lat_0=52.1561605555556 "
+ "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 "
+ "+ellps=bessel "
+ "+step +proj=hgridshift +grids=nl_nsgi_rdtrans2018.tif "
+ "+step +proj=vgridshift +grids=nl_nsgi_nlgeo2018.tif +multiplier=1 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+ }
+
+ auto wkt2 =
+ "COMPOUNDCRS[\"unknown\",\n"
+ " PROJCRS[\"unknown\",\n"
+ " BASEGEOGCRS[\"Amersfoort\",\n"
+ " DATUM[\"Amersfoort\",\n"
+ " ELLIPSOID[\"Bessel "
+ "1841\",6377397.155,299.1528128]]],\n"
+ " CONVERSION[\"unknown\",\n"
+ " METHOD[\"Oblique Stereographic\"],\n"
+ " PARAMETER[\"Latitude of natural origin\",52.1561605555556],\n"
+ " PARAMETER[\"Longitude of natural origin\",5.38763888888889],\n"
+ " PARAMETER[\"Scale factor at natural origin\",0.9999079],\n"
+ " PARAMETER[\"False easting\",155000],\n"
+ " PARAMETER[\"False northing\",463000]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"(E)\",east],\n"
+ " AXIS[\"(N)\",north],\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " VERTCRS[\"NAP height\",\n"
+ " VDATUM[\"Normaal Amsterdams Peil\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"metre\",1]]],\n"
+ " USAGE[\n"
+ " SCOPE[\"unknown\"],\n"
+ " AREA[\"Netherlands - onshore\"],\n"
+ " BBOX[50.75,3.2,53.7,7.22]]]";
+
+ auto obj = WKTParser().createFromWKT(wkt2);
+ auto src_from_wkt2 = nn_dynamic_pointer_cast<CRS>(obj);
+ ASSERT_TRUE(src_from_wkt2 != nullptr);
+ auto list2 = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src_from_wkt2), dst, ctxt);
+ ASSERT_EQ(list.size(), list2.size());
+ for (size_t i = 0; i < list.size(); i++) {
+ const auto &op = list[i];
+ const auto &op2 = list2[i];
+ auto op_proj =
+ op->exportToPROJString(PROJStringFormatter::create().get());
+ auto op2_proj =
+ op2->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_EQ(op_proj, op2_proj) << "op=" << op->nameStr()
+ << " op2=" << op2->nameStr();
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, proj3DCRS_with_non_meter_horiz_and_vertical_to_geog) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=31 +datum=WGS84 +units=us-ft +vunits=us-ft +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), authFactory->createCoordinateReferenceSystem("4326"),
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ // Check that vertical unit conversion is done just once
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=us-ft +z_in=us-ft "
+ "+xy_out=m +z_out=m "
+ "+step +inv +proj=utm +zone=31 +ellps=WGS84 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, compoundCRS_with_non_meter_horiz_and_vertical_to_geog) {
+ auto objSrc = WKTParser().createFromWKT(
+ "COMPOUNDCRS[\"unknown\",\n"
+ " PROJCRS[\"unknown\",\n"
+ " BASEGEOGCRS[\"unknown\",\n"
+ " DATUM[\"World Geodetic System 1984\",\n"
+ " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n"
+ " LENGTHUNIT[\"metre\",1]],\n"
+ " ID[\"EPSG\",6326]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8901]]],\n"
+ " CONVERSION[\"UTM zone 31N\",\n"
+ " METHOD[\"Transverse Mercator\",\n"
+ " ID[\"EPSG\",9807]],\n"
+ " PARAMETER[\"Latitude of natural origin\",0,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8801]],\n"
+ " PARAMETER[\"Longitude of natural origin\",3,\n"
+ " ANGLEUNIT[\"degree\",0.0174532925199433],\n"
+ " ID[\"EPSG\",8802]],\n"
+ " PARAMETER[\"Scale factor at natural origin\",0.9996,\n"
+ " SCALEUNIT[\"unity\",1],\n"
+ " ID[\"EPSG\",8805]],\n"
+ " PARAMETER[\"False easting\",500000,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8806]],\n"
+ " PARAMETER[\"False northing\",0,\n"
+ " LENGTHUNIT[\"metre\",1],\n"
+ " ID[\"EPSG\",8807]],\n"
+ " ID[\"EPSG\",16031]],\n"
+ " CS[Cartesian,2],\n"
+ " AXIS[\"(E)\",east,\n"
+ " ORDER[1],\n"
+ " LENGTHUNIT[\"US survey foot\",0.304800609601219,\n"
+ " ID[\"EPSG\",9003]]],\n"
+ " AXIS[\"(N)\",north,\n"
+ " ORDER[2],\n"
+ " LENGTHUNIT[\"US survey foot\",0.304800609601219,\n"
+ " ID[\"EPSG\",9003]]]],\n"
+ " VERTCRS[\"unknown\",\n"
+ " VDATUM[\"unknown\"],\n"
+ " CS[vertical,1],\n"
+ " AXIS[\"gravity-related height (H)\",up,\n"
+ " LENGTHUNIT[\"US survey foot\",0.304800609601219,\n"
+ " ID[\"EPSG\",9003]]]]]"
+
+ );
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ NN_NO_CHECK(src), authFactory->createCoordinateReferenceSystem("4326"),
+ ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ // Check that vertical unit conversion is done just once
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=us-ft +xy_out=m "
+ "+step +inv +proj=utm +zone=31 +ellps=WGS84 "
+ "+step +proj=unitconvert +xy_in=rad +z_in=us-ft "
+ "+xy_out=deg +z_out=m "
+ "+step +proj=axisswap +order=2,1");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, boundCRS_to_compoundCRS) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS67 +nadgrids=@foo.gsb +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +ellps=GRS80 +nadgrids=@bar.gsb +geoidgrids=@bar.gtx "
+ "+type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=hgridshift +grids=@foo.gsb "
+ "+step +inv +proj=vgridshift +grids=@bar.gtx +multiplier=1 "
+ "+step +inv +proj=hgridshift +grids=@bar.gsb "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+
+ auto opInverse = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src));
+ ASSERT_TRUE(opInverse != nullptr);
+ EXPECT_TRUE(opInverse->inverse()->_isEquivalentTo(op.get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, IGNF_LAMB1_TO_EPSG_4326) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), std::string());
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setGridAvailabilityUse(
+ CoordinateOperationContext::GridAvailabilityUse::
+ IGNORE_GRID_AVAILABILITY);
+ ctxt->setAllowUseIntermediateCRS(
+ CoordinateOperationContext::IntermediateCRSUse::ALWAYS);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ AuthorityFactory::create(DatabaseContext::create(), "IGNF")
+ ->createCoordinateReferenceSystem("LAMB1"),
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("4326"),
+ ctxt);
+ ASSERT_EQ(list.size(), 2U);
+
+ EXPECT_FALSE(list[0]->hasBallparkTransformation());
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=lcc +lat_1=49.5 +lat_0=49.5 "
+ "+lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 "
+ "+ellps=clrk80ign +pm=paris +step +proj=hgridshift "
+ "+grids=fr_ign_ntf_r93.tif +step +proj=unitconvert +xy_in=rad "
+ "+xy_out=deg +step +proj=axisswap +order=2,1");
+
+ EXPECT_FALSE(list[1]->hasBallparkTransformation());
+ EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=lcc +lat_1=49.5 +lat_0=49.5 "
+ "+lon_0=0 +k_0=0.99987734 +x_0=600000 +y_0=200000 "
+ "+ellps=clrk80ign +pm=paris +step +proj=push +v_3 +step "
+ "+proj=cart +ellps=clrk80ign +step +proj=helmert +x=-168 +y=-60 "
+ "+z=320 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg +step "
+ "+proj=axisswap +order=2,1");
+
+ auto list2 = CoordinateOperationFactory::create()->createOperations(
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ // NTF (Paris) / Lambert Nord France equivalent to IGNF:LAMB1
+ ->createCoordinateReferenceSystem("27561"),
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG")
+ ->createCoordinateReferenceSystem("4326"),
+ ctxt);
+ ASSERT_GE(list2.size(), 3U);
+
+ EXPECT_EQ(replaceAll(list2[0]->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "0.999877341", "0.99987734"),
+ list[0]->exportToPROJString(PROJStringFormatter::create().get()));
+
+ // The second entry in list2 (list2[1]) uses the
+ // weird +pm=2.33720833333333 from "NTF (Paris) to NTF (2)"
+ // so skip to the 3th method
+ EXPECT_EQ(replaceAll(list2[2]->exportToPROJString(
+ PROJStringFormatter::create().get()),
+ "0.999877341", "0.99987734"),
+ list[1]->exportToPROJString(PROJStringFormatter::create().get()));
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, NAD83_to_projeted_CRS_based_on_NAD83_2011) {
+ auto authFactory =
+ AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto ctxt = CoordinateOperationContext::create(authFactory, nullptr, 0.0);
+ ctxt->setSpatialCriterion(
+ CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list = CoordinateOperationFactory::create()->createOperations(
+ // NAD83
+ authFactory->createCoordinateReferenceSystem("4269"),
+ // NAD83(2011) / California Albers
+ authFactory->createCoordinateReferenceSystem("6414"), ctxt);
+ ASSERT_EQ(list.size(), 1U);
+ EXPECT_EQ(list[0]->nameStr(), "Ballpark geographic offset from NAD83 to "
+ "NAD83(2011) + California Albers");
+ EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=aea +lat_0=0 +lon_0=-120 +lat_1=34 "
+ "+lat_2=40.5 +x_0=0 +y_0=-4000000 +ellps=GRS80");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, isPROJInstantiable) {
+
+ {
+ auto transformation = Transformation::createGeocentricTranslations(
+ PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326,
+ 1.0, 2.0, 3.0, {});
+ EXPECT_TRUE(transformation->isPROJInstantiable(
+ DatabaseContext::create(), false));
+ }
+
+ // Missing grid
+ {
+ auto transformation = Transformation::createNTv2(
+ PropertyMap(), GeographicCRS::EPSG_4807, GeographicCRS::EPSG_4326,
+ "foo.gsb", std::vector<PositionalAccuracyNNPtr>());
+ EXPECT_FALSE(transformation->isPROJInstantiable(
+ DatabaseContext::create(), false));
+ }
+
+ // Unsupported method
+ {
+ auto transformation = Transformation::create(
+ PropertyMap(), GeographicCRS::EPSG_4269, GeographicCRS::EPSG_4326,
+ nullptr, OperationMethod::create(
+ PropertyMap(), std::vector<OperationParameterNNPtr>{}),
+ std::vector<GeneralParameterValueNNPtr>{},
+ std::vector<PositionalAccuracyNNPtr>{});
+ EXPECT_FALSE(transformation->isPROJInstantiable(
+ DatabaseContext::create(), false));
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, createOperation_on_crs_with_canonical_bound_crs) {
+ auto boundCRS = BoundCRS::createFromTOWGS84(
+ GeographicCRS::EPSG_4267, std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto crs = boundCRS->baseCRSWithCanonicalBoundCRS();
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ crs, GeographicCRS::EPSG_4326);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_TRUE(op->isEquivalentTo(boundCRS->transformation().get()));
+ {
+ auto wkt1 = op->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
+ .get());
+ auto wkt2 = boundCRS->transformation()->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
+ .get());
+ EXPECT_EQ(wkt1, wkt2);
+ }
+ }
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4326, crs);
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_TRUE(
+ op->isEquivalentTo(boundCRS->transformation()->inverse().get()));
+ {
+ auto wkt1 = op->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
+ .get());
+ auto wkt2 = boundCRS->transformation()->inverse()->exportToWKT(
+ WKTFormatter::create(WKTFormatter::Convention::WKT2_2019)
+ .get());
+ EXPECT_EQ(wkt1, wkt2);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, createOperation_fallback_to_proj4_strings) {
+ auto objDest = PROJStringParser().createFromPROJString(
+ "+proj=longlat +geoc +datum=WGS84 +type=crs");
+ auto dest = nn_dynamic_pointer_cast<GeographicCRS>(objDest);
+ ASSERT_TRUE(dest != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ GeographicCRS::EPSG_4326, NN_CHECK_ASSERT(dest));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=longlat +geoc +datum=WGS84 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ createOperation_fallback_to_proj4_strings_regular_with_datum_to_projliteral) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=11 +datum=NAD27 +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +over +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=utm +zone=11 +datum=NAD27 "
+ "+step +proj=longlat +datum=WGS84 +over "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ createOperation_fallback_to_proj4_strings_proj_NAD83_to_projliteral) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=11 +datum=NAD83 +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +over +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=utm +zone=11 +ellps=GRS80 "
+ "+step +proj=longlat +datum=WGS84 +over "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ createOperation_fallback_to_proj4_strings_geog_NAD83_to_projliteral) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=NAD83 +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +over +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=longlat +datum=WGS84 +over "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ createOperation_fallback_to_proj4_strings_regular_with_nadgrids_to_projliteral) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=11 +ellps=clrk66 +nadgrids=@conus +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +over +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=utm +zone=11 +ellps=clrk66 +nadgrids=@conus "
+ "+step +proj=longlat +datum=WGS84 +over "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation,
+ createOperation_fallback_to_proj4_strings_projliteral_to_projliteral) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=11 +datum=NAD27 +over +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +over +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +inv +proj=utm +zone=11 +datum=NAD27 +over "
+ "+step +proj=longlat +datum=WGS84 +over "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(
+ operation,
+ createOperation_fallback_to_proj4_strings_regular_to_projliteral_with_towgs84) {
+ auto objSrc =
+ createFromUserInput("EPSG:4326", DatabaseContext::create(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=31 +ellps=GRS80 +towgs84=1,2,3 +over +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=utm +zone=31 +ellps=GRS80 +towgs84=1,2,3 +over");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, createOperation_on_crs_with_bound_crs_and_wktext) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
+ "+units=m +no_defs +nadgrids=@GDA94_GDA2020_conformal.gsb +ignored1 "
+ "+ignored2=val +wktext +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=utm +zone=55 +south +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 "
+ "+units=m +no_defs +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +inv +proj=utm +zone=55 +south "
+ "+ellps=GRS80 +step +proj=hgridshift "
+ "+grids=@GDA94_GDA2020_conformal.gsb +step +proj=utm +zone=55 "
+ "+south +ellps=GRS80");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, createOperation_ossfuzz_18587) {
+ auto objSrc =
+ createFromUserInput("EPSG:4326", DatabaseContext::create(), false);
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+
+ // Extremely weird string ! We should likely reject it
+ auto objDst = PROJStringParser().createFromPROJString(
+ "type=crs proj=pipeline step proj=merc vunits=m nadgrids=@x "
+ "proj=\"\nproj=pipeline step\n\"");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ // Just check that we don't go into an infinite recursion
+ try {
+ CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ } catch (const std::exception &) {
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(operation, derivedGeographicCRS_with_to_wgs84_to_geographicCRS) {
+ auto objSrc = PROJStringParser().createFromPROJString(
+ "+proj=ob_tran +o_proj=latlon +lat_0=0 +lon_0=180 +o_lat_p=18.0 "
+ "+o_lon_p=-200.0 +ellps=WGS84 +towgs84=1,2,3 +type=crs");
+ auto src = nn_dynamic_pointer_cast<CRS>(objSrc);
+ ASSERT_TRUE(src != nullptr);
+ auto objDst = PROJStringParser().createFromPROJString(
+ "+proj=longlat +datum=WGS84 +type=crs");
+ auto dst = nn_dynamic_pointer_cast<CRS>(objDst);
+ ASSERT_TRUE(dst != nullptr);
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dst));
+ ASSERT_TRUE(op != nullptr);
+ std::string pipeline(
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=ob_tran +o_proj=latlon +lat_0=0 +lon_0=180 "
+ "+o_lat_p=18 +o_lon_p=-200 +ellps=WGS84 "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=1 +y=2 +z=3 "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ pipeline);
+
+ auto op2 = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(src),
+ nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4326));
+ ASSERT_TRUE(op2 != nullptr);
+ EXPECT_EQ(op2->exportToPROJString(PROJStringFormatter::create().get()),
+ pipeline + " +step +proj=axisswap +order=2,1");
+ }
+
+ {
+ auto op = CoordinateOperationFactory::create()->createOperation(
+ NN_CHECK_ASSERT(dst), NN_CHECK_ASSERT(src));
+ ASSERT_TRUE(op != nullptr);
+ std::string pipeline(
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=push +v_3 "
+ "+step +proj=cart +ellps=WGS84 "
+ "+step +proj=helmert +x=-1 +y=-2 +z=-3 "
+ "+step +inv +proj=cart +ellps=WGS84 "
+ "+step +proj=pop +v_3 "
+ "+step +proj=ob_tran +o_proj=latlon +lat_0=0 +lon_0=180 "
+ "+o_lat_p=18 +o_lon_p=-200 +ellps=WGS84 "
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg");
+ EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline " + pipeline);
+
+ auto op2 = CoordinateOperationFactory::create()->createOperation(
+ nn_static_pointer_cast<CRS>(GeographicCRS::EPSG_4326),
+ NN_CHECK_ASSERT(src));
+ ASSERT_TRUE(op2 != nullptr);
+ EXPECT_EQ(op2->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline +step +proj=axisswap +order=2,1 " + pipeline);
+ }
+}