aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2018-12-07 19:53:48 +0100
committerEven Rouault <even.rouault@spatialys.com>2018-12-07 19:53:48 +0100
commit23127c01ad535902665a975da81e27c389bb7aeb (patch)
treed6cc90dfe1069425824de40fbe42342a1afca9bd
parent706fac8bc70312f5729e2f3aeeb4f67ecb211b1d (diff)
parent29b522b4b80b43fe03cb1a955789676eec8051e7 (diff)
downloadPROJ-23127c01ad535902665a975da81e27c389bb7aeb.tar.gz
PROJ-23127c01ad535902665a975da81e27c389bb7aeb.zip
Merge remote-tracking branch 'rouault/gdalbarn'
-rw-r--r--data/Makefile.am1
-rw-r--r--data/sql/commit.sql9
-rw-r--r--data/sql/customizations.sql18
-rw-r--r--data/sql/deprecation.sql456
-rw-r--r--data/sql/proj_db_table_defs.sql33
-rw-r--r--data/sql_filelist.cmake1
-rw-r--r--include/proj/common.hpp12
-rw-r--r--include/proj/crs.hpp8
-rw-r--r--include/proj/io.hpp12
-rw-r--r--include/proj/metadata.hpp4
-rw-r--r--include/proj/util.hpp9
-rwxr-xr-xscripts/build_db.py19
-rw-r--r--src/c_api.cpp102
-rw-r--r--src/common.cpp80
-rw-r--r--src/coordinateoperation.cpp114
-rw-r--r--src/coordinatesystem.cpp8
-rw-r--r--src/crs.cpp194
-rw-r--r--src/factory.cpp1005
-rw-r--r--src/internal.cpp33
-rw-r--r--src/io.cpp25
-rw-r--r--src/metadata.cpp70
-rw-r--r--src/proj.h3
-rw-r--r--src/proj_experimental.h10
-rw-r--r--src/projinfo.cpp52
-rw-r--r--src/util.cpp104
-rwxr-xr-xtest/cli/testprojinfo4
-rw-r--r--test/cli/testprojinfo_out.dist98
-rw-r--r--test/unit/test_c_api.cpp43
-rw-r--r--test/unit/test_crs.cpp159
-rw-r--r--test/unit/test_operation.cpp8
30 files changed, 1973 insertions, 721 deletions
diff --git a/data/Makefile.am b/data/Makefile.am
index a85047c6..fe5ad532 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -28,6 +28,7 @@ SQL_ORDERED_LIST = sql/begin.sql \
sql/concatenated_operation.sql \
sql/alias_name.sql \
sql/supersession.sql \
+ sql/deprecation.sql \
sql/esri.sql \
sql/ignf.sql \
sql/grid_alternatives.sql \
diff --git a/data/sql/commit.sql b/data/sql/commit.sql
index 346c5b76..7aa91e8e 100644
--- a/data/sql/commit.sql
+++ b/data/sql/commit.sql
@@ -1,5 +1,14 @@
COMMIT;
+CREATE INDEX geodetic_crs_datum_idx ON geodetic_crs(datum_auth_name, datum_code);
+CREATE INDEX geodetic_datum_ellipsoid_idx ON geodetic_datum(ellipsoid_auth_name, ellipsoid_code);
+CREATE INDEX supersession_idx ON supersession(superseded_table_name, superseded_auth_name, superseded_code);
+CREATE INDEX deprecation_idx ON deprecation(table_name, deprecated_auth_name, deprecated_code);
+CREATE INDEX helmert_transformation_idx ON helmert_transformation(source_crs_auth_name, source_crs_code, target_crs_auth_name, target_crs_code);
+CREATE INDEX grid_transformation_idx ON grid_transformation(source_crs_auth_name, source_crs_code, target_crs_auth_name, target_crs_code);
+CREATE INDEX other_transformation_idx ON other_transformation(source_crs_auth_name, source_crs_code, target_crs_auth_name, target_crs_code);
+CREATE INDEX concatenated_operation_idx ON concatenated_operation(source_crs_auth_name, source_crs_code, target_crs_auth_name, target_crs_code);
+
-- Do an explicit foreign_key_check as foreign key checking is a no-op within
-- a transaction. Unfortunately we can't ask for this to be an error, so this
-- is just for verbose output. In Makefile, we check this separately
diff --git a/data/sql/customizations.sql b/data/sql/customizations.sql
index 2181cc2b..8e31c233 100644
--- a/data/sql/customizations.sql
+++ b/data/sql/customizations.sql
@@ -6,3 +6,21 @@ INSERT INTO "other_transformation" VALUES('PROJ','CRS84_TO_EPSG_4326','OGC:CRS84
-- alias of EPSG:3857
INSERT INTO "projected_crs" VALUES('EPSG','900913','Google Maps Global Mercator',NULL,NULL,'EPSG','4499','EPSG','4326','EPSG','3856','EPSG','3544',NULL,1);
+
+-- Define the allowed authorities, and their precedence, when researching a
+-- coordinate operation
+
+INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES
+ ('any', 'EPSG', 'PROJ,EPSG,any' );
+
+INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES
+ ('EPSG', 'EPSG', 'PROJ,EPSG' );
+
+INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES
+ ('PROJ', 'EPSG', 'PROJ,EPSG' );
+
+INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES
+ ('IGNF', 'EPSG', 'PROJ,IGNF,EPSG' );
+
+INSERT INTO authority_to_authority_preference(source_auth_name, target_auth_name, allowed_authorities) VALUES
+ ('ESRI', 'EPSG', 'PROJ,ESRI,EPSG' ); \ No newline at end of file
diff --git a/data/sql/deprecation.sql b/data/sql/deprecation.sql
new file mode 100644
index 00000000..4ea3e558
--- /dev/null
+++ b/data/sql/deprecation.sql
@@ -0,0 +1,456 @@
+--- This file has been generated by scripts/build_db.py. DO NOT EDIT !
+
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2156','EPSG','2195','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2291','EPSG','2292','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4035','EPSG','4047','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4226','EPSG','4142','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31462','EPSG','31466','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31463','EPSG','31467','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31464','EPSG','31468','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31465','EPSG','31469','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31265','EPSG','31275','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31266','EPSG','31276','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31267','EPSG','31277','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31268','EPSG','31278','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31278','EPSG','31279','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31291','EPSG','31281','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31292','EPSG','31282','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31293','EPSG','31283','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31294','EPSG','31284','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31295','EPSG','31285','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31296','EPSG','31286','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31297','EPSG','31287','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29900','EPSG','29902','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2155','EPSG','2194','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4226','EPSG','4143','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4172','EPSG','4190','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27581','EPSG','27571','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27582','EPSG','27572','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27583','EPSG','27573','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27584','EPSG','27574','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27591','EPSG','27561','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27592','EPSG','27562','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27593','EPSG','27563','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27594','EPSG','27564','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','7401','EPSG','7411','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','7402','EPSG','7412','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','7403','EPSG','7413','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32036','EPSG','2204','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26979','EPSG','2205','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4228','EPSG','4192','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4260','EPSG','4193','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','22832','EPSG','2214','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4287','EPSG','4194','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32074','EPSG','32064','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32075','EPSG','32065','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32076','EPSG','32066','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32077','EPSG','32067','EPSG');
+INSERT INTO "deprecation" VALUES('vertical_crs','EPSG','5704','EPSG','5736','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21473','EPSG','21453','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21474','EPSG','21454','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21475','EPSG','21455','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21476','EPSG','21456','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21477','EPSG','21457','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21478','EPSG','21458','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21479','EPSG','21459','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21480','EPSG','21460','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21481','EPSG','21461','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21482','EPSG','21462','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21483','EPSG','21463','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2199','EPSG','2462','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2166','EPSG','2397','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2167','EPSG','2398','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2168','EPSG','2399','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2091','EPSG','2395','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2092','EPSG','2396','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20092','EPSG','2491','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20091','EPSG','2490','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20090','EPSG','2489','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20089','EPSG','2488','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20088','EPSG','2487','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20087','EPSG','2486','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20086','EPSG','2485','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20085','EPSG','2484','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20084','EPSG','2483','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20083','EPSG','2482','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20082','EPSG','2481','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20081','EPSG','2480','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20080','EPSG','2479','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20079','EPSG','2478','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20078','EPSG','2477','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20077','EPSG','2476','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20076','EPSG','2475','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20075','EPSG','2474','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20074','EPSG','2473','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20073','EPSG','2472','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20072','EPSG','2471','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20071','EPSG','2470','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20070','EPSG','2469','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20069','EPSG','2468','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20068','EPSG','2467','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20067','EPSG','2466','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20066','EPSG','2465','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20065','EPSG','2464','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','20064','EPSG','2463','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28462','EPSG','2492','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28463','EPSG','2493','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28464','EPSG','2494','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28465','EPSG','2495','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28466','EPSG','2496','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28467','EPSG','2497','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28468','EPSG','2498','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28469','EPSG','2499','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28470','EPSG','2500','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28471','EPSG','2501','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28472','EPSG','2502','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28473','EPSG','2503','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28474','EPSG','2504','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28475','EPSG','2505','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28476','EPSG','2506','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28477','EPSG','2507','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28478','EPSG','2508','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28479','EPSG','2509','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28480','EPSG','2510','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28481','EPSG','2511','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28482','EPSG','2512','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28483','EPSG','2513','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28484','EPSG','2514','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28485','EPSG','2515','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28486','EPSG','2516','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28487','EPSG','2517','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28488','EPSG','2518','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28489','EPSG','2519','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28490','EPSG','2520','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28491','EPSG','2521','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28492','EPSG','2522','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4294','EPSG','4613','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4125','EPSG','4613','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2550','EPSG','2933','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4185','EPSG','4615','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4185','EPSG','4616','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2191','EPSG','2942','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2191','EPSG','2943','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4140','EPSG','4617','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2147','EPSG','2952','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2140','EPSG','2945','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2141','EPSG','2946','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2142','EPSG','2947','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2143','EPSG','2948','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2144','EPSG','2949','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2145','EPSG','2950','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2146','EPSG','2951','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2036','EPSG','2953','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2292','EPSG','2954','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2139','EPSG','2944','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2153','EPSG','2955','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2152','EPSG','2956','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2151','EPSG','2957','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2150','EPSG','2958','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2149','EPSG','2959','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2037','EPSG','2960','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2038','EPSG','2961','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2148','EPSG','2962','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4234','EPSG','4197','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','23433','EPSG','2312','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4291','EPSG','4618','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29100','EPSG','29101','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29177','EPSG','29187','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29118','EPSG','29168','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29185','EPSG','29195','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29184','EPSG','29194','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29183','EPSG','29193','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29182','EPSG','29192','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29181','EPSG','29191','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29180','EPSG','29190','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29179','EPSG','29189','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29178','EPSG','29188','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29122','EPSG','29172','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29121','EPSG','29171','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29120','EPSG','29170','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29119','EPSG','29169','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26193','EPSG','26194','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2245','EPSG','2966','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2244','EPSG','2965','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2889','EPSG','2967','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2890','EPSG','2968','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4327','EPSG','4329','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4235','EPSG','4623','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21100','EPSG','3001','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','25700','EPSG','3002','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2934','EPSG','3000','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26591','EPSG','3003','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26592','EPSG','3004','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29635','EPSG','20135','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29636','EPSG','20136','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4296','EPSG','4201','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2400','EPSG','3021','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','30800','EPSG','3027','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4634','EPSG','4662','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2982','EPSG','3060','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4340','EPSG','4930','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4344','EPSG','4932','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4342','EPSG','4934','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4346','EPSG','4936','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4348','EPSG','4938','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4350','EPSG','4940','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4352','EPSG','4942','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4387','EPSG','4944','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4385','EPSG','4919','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4330','EPSG','4910','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4331','EPSG','4911','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4332','EPSG','4912','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4333','EPSG','4913','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4334','EPSG','4914','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4335','EPSG','4915','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4336','EPSG','4916','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4337','EPSG','4917','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4338','EPSG','4918','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4354','EPSG','4946','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4389','EPSG','4948','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4356','EPSG','4950','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4358','EPSG','4952','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4360','EPSG','4954','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4362','EPSG','4956','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4364','EPSG','4958','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4366','EPSG','4960','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4368','EPSG','4962','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4370','EPSG','4964','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4372','EPSG','4966','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4382','EPSG','4968','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4374','EPSG','4970','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4384','EPSG','4972','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4376','EPSG','4974','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4378','EPSG','4976','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4328','EPSG','4978','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4380','EPSG','4980','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4388','EPSG','4949','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4386','EPSG','4945','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4383','EPSG','4973','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4381','EPSG','4969','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4379','EPSG','4981','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4377','EPSG','4977','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4375','EPSG','4975','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4373','EPSG','4971','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4371','EPSG','4967','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4369','EPSG','4965','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4367','EPSG','4963','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4365','EPSG','4961','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4363','EPSG','4959','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4361','EPSG','4957','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4359','EPSG','4955','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4357','EPSG','4953','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4355','EPSG','4951','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4353','EPSG','4947','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4351','EPSG','4943','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4349','EPSG','4941','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4347','EPSG','4939','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4345','EPSG','4937','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4343','EPSG','4933','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4341','EPSG','4935','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4339','EPSG','4931','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4329','EPSG','4979','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4126','EPSG','4669','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4819','EPSG','4307','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31900','EPSG','31901','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2194','EPSG','3102','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4233','EPSG','4684','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4233','EPSG','4685','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21891','EPSG','21896','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21892','EPSG','21897','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21893','EPSG','21898','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','21894','EPSG','21899','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2214','EPSG','3119','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26747','EPSG','26799','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4172','EPSG','4694','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4685','EPSG','4696','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2171','EPSG','3120','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2979','EPSG','3336','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4631','EPSG','4698','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2600','EPSG','3346','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26432','EPSG','3353','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26432','EPSG','3354','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4264','EPSG','4704','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4264','EPSG','4705','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','7408','EPSG','7415','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4681','EPSG','4700','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4681','EPSG','4702','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3103','EPSG','3343','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3103','EPSG','3367','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3104','EPSG','3344','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3104','EPSG','3368','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3105','EPSG','3345','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3105','EPSG','3369','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5532','EPSG','5858','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2577','EPSG','3389','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2694','EPSG','3390','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3785','EPSG','3857','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4968','EPSG','4906','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4645','EPSG','4749','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4969','EPSG','4907','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2984','EPSG','3163','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4635','EPSG','4750','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2983','EPSG','3164','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','24571','EPSG','3167','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','24571','EPSG','3168','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4731','EPSG','4752','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3359','EPSG','3404','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3366','EPSG','3407','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29700','EPSG','29701','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','29700','EPSG','29702','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3143','EPSG','3460','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2063','EPSG','3461','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2064','EPSG','3462','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3073','EPSG','3463','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3076','EPSG','3464','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2990','EPSG','3727','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4902','EPSG','4901','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','7412','EPSG','7421','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','7413','EPSG','7422','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27492','EPSG','27493','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32662','EPSG','32663','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32662','EPSG','3786','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2086','EPSG','3796','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2085','EPSG','3795','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26814','EPSG','26847','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26815','EPSG','26848','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26825','EPSG','26855','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26826','EPSG','26856','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26836','EPSG','26863','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26837','EPSG','26864','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26819','EPSG','26849','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26820','EPSG','26850','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26821','EPSG','26851','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26830','EPSG','26857','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26831','EPSG','26858','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26832','EPSG','26859','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26841','EPSG','26865','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26842','EPSG','26866','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26843','EPSG','26867','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26822','EPSG','26852','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26833','EPSG','26860','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26844','EPSG','26868','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26823','EPSG','26853','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26824','EPSG','26854','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26834','EPSG','26861','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26835','EPSG','26862','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26845','EPSG','26869','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26846','EPSG','26870','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3774','EPSG','3800','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3778','EPSG','3801','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3782','EPSG','3802','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3349','EPSG','3832','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3752','EPSG','3994','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28403','EPSG','3333','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','28402','EPSG','3833','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31700','EPSG','3844','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4317','EPSG','4179','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31275','EPSG','3907','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31276','EPSG','3908','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31277','EPSG','3909','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','31279','EPSG','3910','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3787','EPSG','3912','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2170','EPSG','3911','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3314','EPSG','3985','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3315','EPSG','3989','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3315','EPSG','3988','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3315','EPSG','3987','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3315','EPSG','3986','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32663','EPSG','4087','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3786','EPSG','4088','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3985','EPSG','4415','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3842','EPSG','4417','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3843','EPSG','4434','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32029','EPSG','4455','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32018','EPSG','4456','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3454','EPSG','4457','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4972','EPSG','4556','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4973','EPSG','4557','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4640','EPSG','4558','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2989','EPSG','4559','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4868','EPSG','5118','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4869','EPSG','5119','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4870','EPSG','5120','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4861','EPSG','5111','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4860','EPSG','5110','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4871','EPSG','5121','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4872','EPSG','5122','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4873','EPSG','5123','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4855','EPSG','5105','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4856','EPSG','5106','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4857','EPSG','5107','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4858','EPSG','5108','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4859','EPSG','5109','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4862','EPSG','5112','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4863','EPSG','5113','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4864','EPSG','5114','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4865','EPSG','5115','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4866','EPSG','5116','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4867','EPSG','5117','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4874','EPSG','5124','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4875','EPSG','5125','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4876','EPSG','5126','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4877','EPSG','5127','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4878','EPSG','5128','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4879','EPSG','5129','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4880','EPSG','5130','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32061','EPSG','5458','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','32062','EPSG','5459','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5466','EPSG','5589','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5458','EPSG','5559','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26801','EPSG','5623','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26802','EPSG','5624','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26803','EPSG','5625','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','2192','EPSG','2154','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5388','EPSG','5839','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','4474','EPSG','5879','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3356','EPSG','6128','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3357','EPSG','6129','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26811','EPSG','6200','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26812','EPSG','6201','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','26813','EPSG','6202','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','4268','EPSG','4267','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5570','EPSG','6381','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5577','EPSG','6381','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5571','EPSG','6382','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5578','EPSG','6382','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5579','EPSG','6383','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5572','EPSG','6383','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5573','EPSG','6384','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5580','EPSG','6384','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5574','EPSG','6385','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5581','EPSG','6385','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5575','EPSG','6386','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5582','EPSG','6386','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5576','EPSG','6387','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','5583','EPSG','6387','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6141','EPSG','6391','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6604','EPSG','6879','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6517','EPSG','6880','EPSG');
+INSERT INTO "deprecation" VALUES('compound_crs','EPSG','6871','EPSG','6893','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3975','EPSG','6933','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3973','EPSG','6931','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3974','EPSG','6932','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6200','EPSG','6966','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','7088','EPSG','7133','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6996','EPSG','7131','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6997','EPSG','7132','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27037','EPSG','7005','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3907','EPSG','8677','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','6978','EPSG','7134','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','6980','EPSG','7136','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','6979','EPSG','7135','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','6985','EPSG','7137','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','6986','EPSG','7138','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','6987','EPSG','7139','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3908','EPSG','8678','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3909','EPSG','6316','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','27038','EPSG','7006','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6956','EPSG','5896','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6957','EPSG','5897','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6958','EPSG','5898','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','6959','EPSG','5899','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3910','EPSG','8679','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','7082','EPSG','8456','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','7082','EPSG','8455','EPSG');
+INSERT INTO "deprecation" VALUES('projected_crs','EPSG','3911','EPSG','8686','EPSG');
+INSERT INTO "deprecation" VALUES('geodetic_crs','EPSG','8449','EPSG','8860','EPSG');
diff --git a/data/sql/proj_db_table_defs.sql b/data/sql/proj_db_table_defs.sql
index 553dab38..d403f0eb 100644
--- a/data/sql/proj_db_table_defs.sql
+++ b/data/sql/proj_db_table_defs.sql
@@ -946,6 +946,30 @@ FOR EACH ROW BEGIN
END;
+CREATE TABLE deprecation(
+ table_name TEXT NOT NULL CHECK (table_name IN (
+ 'unit_of_measure', 'celestial_body', 'ellipsoid',
+ 'area', 'prime_meridian', 'geodetic_datum', 'vertical_datum', 'geodetic_crs',
+ 'projected_crs', 'vertical_crs', 'compound_crs', 'conversion', 'grid_transformation',
+ 'helmert_transformation', 'other_transformation', 'concatenated_operation')),
+ deprecated_auth_name TEXT NOT NULL,
+ deprecated_code TEXT NOT NULL,
+ replacement_auth_name TEXT NOT NULL,
+ replacement_code TEXT NOT NULL,
+ source TEXT
+);
+
+CREATE TRIGGER deprecation_insert_trigger
+BEFORE INSERT ON deprecation
+FOR EACH ROW BEGIN
+ SELECT RAISE(ABORT, 'insert on deprecation violates constraint: deprecated entry refers to unexisting code')
+ WHERE NOT EXISTS (SELECT 1 FROM object_view o WHERE o.table_name = NEW.table_name AND o.auth_name = NEW.deprecated_auth_name AND o.code = NEW.deprecated_code);
+
+ SELECT RAISE(ABORT, 'insert on deprecation violates constraint: replacement entry refers to unexisting code')
+ WHERE NOT EXISTS (SELECT 1 FROM object_view o WHERE o.table_name = NEW.table_name AND o.auth_name = NEW.replacement_auth_name AND o.code = NEW.replacement_code);
+END;
+
+
CREATE VIEW coordinate_operation_view AS
SELECT 'grid_transformation' AS table_name, auth_name, code, name,
@@ -1048,3 +1072,12 @@ CREATE VIEW authority_list AS
UNION
SELECT DISTINCT auth_name FROM coordinate_operation_view
;
+
+-- Define the allowed authorities, and their precedence, when researching a
+-- coordinate operation
+CREATE TABLE authority_to_authority_preference(
+ source_auth_name TEXT NOT NULL, -- 'any' for any source
+ target_auth_name TEXT NOT NULL, -- 'any' for any target
+ allowed_authorities TEXT NOT NULL, -- for example 'PROJ,EPSG,any'
+ CONSTRAINT unique_authority_to_authority_preference UNIQUE (source_auth_name, target_auth_name)
+);
diff --git a/data/sql_filelist.cmake b/data/sql_filelist.cmake
index 09e45716..b9054d23 100644
--- a/data/sql_filelist.cmake
+++ b/data/sql_filelist.cmake
@@ -23,6 +23,7 @@ set(SQL_FILES "${SQL_DIR}/begin.sql"
"${SQL_DIR}/concatenated_operation.sql"
"${SQL_DIR}/alias_name.sql"
"${SQL_DIR}/supersession.sql"
+ "${SQL_DIR}/deprecation.sql"
"${SQL_DIR}/esri.sql"
"${SQL_DIR}/ignf.sql"
"${SQL_DIR}/grid_alternatives.sql"
diff --git a/include/proj/common.hpp b/include/proj/common.hpp
index f1e683e7..91756c62 100644
--- a/include/proj/common.hpp
+++ b/include/proj/common.hpp
@@ -277,9 +277,9 @@ using IdentifiedObjectNNPtr = util::nn<IdentifiedObjectPtr>;
*
* \remark Implements IdentifiedObject from \ref ISO_19111_2018
*/
-class IdentifiedObject : public util::BaseObject,
- public util::IComparable,
- public io::IWKTExportable {
+class PROJ_GCC_DLL IdentifiedObject : public util::BaseObject,
+ public util::IComparable,
+ public io::IWKTExportable {
public:
//! @cond Doxygen_Suppress
PROJ_DLL ~IdentifiedObject() override;
@@ -311,14 +311,14 @@ class IdentifiedObject : public util::BaseObject,
//! @cond Doxygen_Suppress
void
formatID(io::WKTFormatter *formatter) const;
- void formatRemarks(io::WKTFormatter *formatter) const;
+ PROJ_INTERNAL void formatRemarks(io::WKTFormatter *formatter) const;
- bool
+ PROJ_INTERNAL bool
_isEquivalentTo(const util::IComparable *other,
util::IComparable::Criterion criterion =
util::IComparable::Criterion::STRICT) const override;
- bool
+ PROJ_INTERNAL bool
_isEquivalentTo(const IdentifiedObject *other,
util::IComparable::Criterion criterion =
util::IComparable::Criterion::STRICT) PROJ_CONST_DECL;
diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp
index bdb36cd4..1066f886 100644
--- a/include/proj/crs.hpp
+++ b/include/proj/crs.hpp
@@ -92,8 +92,9 @@ class PROJ_GCC_DLL CRS : public common::ObjectUsage {
PROJ_DLL GeodeticCRSPtr extractGeodeticCRS() const;
PROJ_DLL GeographicCRSPtr extractGeographicCRS() const;
PROJ_DLL VerticalCRSPtr extractVerticalCRS() const;
- PROJ_DLL CRSNNPtr createBoundCRSToWGS84IfPossible(
- const io::DatabaseContextPtr &dbContext) const;
+ PROJ_DLL CRSNNPtr
+ createBoundCRSToWGS84IfPossible(const io::DatabaseContextPtr &dbContext,
+ bool allowIntermediateCRS) const;
PROJ_DLL CRSNNPtr stripVerticalComponent() const;
PROJ_DLL const BoundCRSPtr &canonicalBoundCRS() PROJ_CONST_DECL;
@@ -101,6 +102,9 @@ class PROJ_GCC_DLL CRS : public common::ObjectUsage {
PROJ_DLL std::list<std::pair<CRSNNPtr, int>>
identify(const io::AuthorityFactoryPtr &authorityFactory) const;
+ PROJ_DLL std::list<CRSNNPtr>
+ getNonDeprecated(const io::DatabaseContextNNPtr &dbContext) const;
+
PROJ_PRIVATE :
//! @cond Doxygen_Suppress
PROJ_INTERNAL const GeodeticCRS *
diff --git a/include/proj/io.hpp b/include/proj/io.hpp
index 26420150..c0d4fef5 100644
--- a/include/proj/io.hpp
+++ b/include/proj/io.hpp
@@ -731,6 +731,15 @@ class PROJ_GCC_DLL DatabaseContext {
PROJ_INTERNAL std::string getTextDefinition(const std::string &tableName,
const std::string &authName,
const std::string &code) const;
+
+ PROJ_INTERNAL std::vector<std::string>
+ getAllowedAuthorities(const std::string &sourceAuthName,
+ const std::string &targetAuthName) const;
+
+ PROJ_INTERNAL std::list<std::pair<std::string, std::string>>
+ getNonDeprecated(const std::string &tableName, const std::string &authName,
+ const std::string &code) const;
+
//! @endcond
protected:
@@ -952,7 +961,8 @@ class PROJ_GCC_DLL AuthorityFactory {
PROJ_INTERNAL operation::CoordinateOperationNNPtr
createCoordinateOperation(const std::string &code, bool allowConcatenated,
- bool usePROJAlternativeGridNames) const;
+ bool usePROJAlternativeGridNames,
+ const std::string &type) const;
INLINED_MAKE_SHARED
diff --git a/include/proj/metadata.hpp b/include/proj/metadata.hpp
index fc86693d..d1b91515 100644
--- a/include/proj/metadata.hpp
+++ b/include/proj/metadata.hpp
@@ -406,6 +406,7 @@ class PROJ_GCC_DLL Identifier : public util::BaseObject,
protected:
PROJ_INTERNAL explicit Identifier(const std::string &codeIn,
const util::PropertyMap &properties);
+ PROJ_INTERNAL explicit Identifier();
PROJ_FRIEND_OPTIONAL(Identifier);
INLINED_MAKE_SHARED
@@ -413,6 +414,9 @@ class PROJ_GCC_DLL Identifier : public util::BaseObject,
PROJ_FRIEND(common::IdentifiedObject);
+ PROJ_INTERNAL static IdentifierNNPtr
+ createFromDescription(const std::string &descriptionIn);
+
private:
PROJ_OPAQUE_PRIVATE_DATA
};
diff --git a/include/proj/util.hpp b/include/proj/util.hpp
index eb7288b2..c2f2b7fe 100644
--- a/include/proj/util.hpp
+++ b/include/proj/util.hpp
@@ -499,12 +499,13 @@ class PropertyMap {
PROJ_PRIVATE :
//! @cond Doxygen_Suppress
- std::map<std::string, BaseObjectNNPtr>::iterator
- find(const std::string &key) const;
- std::map<std::string, BaseObjectNNPtr>::iterator end() const;
+ const BaseObjectNNPtr *
+ get(const std::string &key) const;
// throw(InvalidValueTypeException)
bool getStringValue(const std::string &key, std::string &outVal) const;
+ bool getStringValue(const std::string &key,
+ optional<std::string> &outVal) const;
static PropertyMap createAndSetName(const char *name);
static PropertyMap createAndSetName(const std::string &name);
@@ -513,8 +514,6 @@ class PropertyMap {
private:
PropertyMap &operator=(const PropertyMap &) = delete;
- PropertyMap &set(const std::string &key, const BoxedValue &val);
-
PROJ_OPAQUE_PRIVATE_DATA
};
diff --git a/scripts/build_db.py b/scripts/build_db.py
index 46bef8c8..4f09a659 100755
--- a/scripts/build_db.py
+++ b/scripts/build_db.py
@@ -520,7 +520,7 @@ def fill_alias(proj_db_cursor):
def find_table(proj_db_cursor, code):
- for table_name in ('helmert_transformation', 'grid_transformation', 'concatenated_operation'):
+ for table_name in ('helmert_transformation', 'grid_transformation', 'concatenated_operation', 'geodetic_crs', 'projected_crs', 'vertical_crs', 'compound_crs'):
proj_db_cursor.execute('SELECT name FROM %s WHERE code = ?' % table_name, (code,))
row = proj_db_cursor.fetchone()
if row is not None:
@@ -545,6 +545,22 @@ def fill_supersession(proj_db_cursor):
continue
proj_db_cursor.execute("INSERT INTO supersession VALUES (?,'EPSG',?,?,'EPSG',?,'EPSG')", (superseded_table_name, code, replacement_table_name, superseded_by))
+def fill_deprecation(proj_db_cursor):
+ proj_db_cursor.execute("SELECT object_code, replaced_by FROM epsg.epsg_deprecation WHERE object_table_name = 'epsg_coordinatereferencesystem' AND object_code != replaced_by")
+ for row in proj_db_cursor.fetchall():
+ code, replaced_by = row
+ proj_db_cursor.execute('SELECT 1 FROM crs_view WHERE code = ?', (code,))
+ if proj_db_cursor.fetchone() is None:
+ print('Skipping deprecation of %d since it has not been imported' % code)
+ continue
+
+ src_name, deprecated_table_name = find_table(proj_db_cursor, code)
+ dst_name, replacement_table_name = find_table(proj_db_cursor, replaced_by)
+ assert deprecated_table_name, row
+ assert replacement_table_name, row
+ assert deprecated_table_name == replacement_table_name
+ proj_db_cursor.execute("INSERT INTO deprecation VALUES (?,'EPSG',?,'EPSG',?,'EPSG')", (deprecated_table_name, code, replaced_by))
+
def report_non_imported_operations(proj_db_cursor):
proj_db_cursor.execute("SELECT coord_op_code, coord_op_type, coord_op_name, coord_op_method_code, coord_op_method_name, source_crs_code, target_crs_code, area_of_use_code, coord_op_accuracy, epsg_coordoperation.deprecated FROM epsg.epsg_coordoperation LEFT JOIN epsg.epsg_coordoperationmethod USING (coord_op_method_code) WHERE coord_op_code NOT IN (SELECT code FROM coordinate_operation_with_conversion_view)")
rows = []
@@ -591,6 +607,7 @@ fill_other_transformation(proj_db_cursor)
fill_concatenated_operation(proj_db_cursor)
fill_alias(proj_db_cursor)
fill_supersession(proj_db_cursor)
+fill_deprecation(proj_db_cursor)
non_imported_operations = report_non_imported_operations(proj_db_cursor)
proj_db_cursor.close()
diff --git a/src/c_api.cpp b/src/c_api.cpp
index fed91750..9d66071b 100644
--- a/src/c_api.cpp
+++ b/src/c_api.cpp
@@ -522,6 +522,42 @@ PJ_OBJ *proj_obj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name,
// ---------------------------------------------------------------------------
+/** \brief Return GeodeticCRS that use the specified datum.
+ *
+ * @param ctx Context, or NULL for default context.
+ * @param crs_auth_name CRS authority name, or NULL.
+ * @param datum_auth_name Datum authority name (must not be NULL)
+ * @param datum_code Datum code (must not be NULL)
+ * @param crs_type "geographic 2D", "geographic 3D", "geocentric" or NULL
+ * @return a result set that must be unreferenced with
+ * proj_obj_list_unref(), or NULL in case of error.
+ */
+PJ_OBJ_LIST *proj_obj_query_geodetic_crs_from_datum(PJ_CONTEXT *ctx,
+ const char *crs_auth_name,
+ const char *datum_auth_name,
+ const char *datum_code,
+ const char *crs_type) {
+ assert(datum_auth_name);
+ assert(datum_code);
+ SANITIZE_CTX(ctx);
+ try {
+ auto factory = AuthorityFactory::create(
+ getDBcontext(ctx), crs_auth_name ? crs_auth_name : "");
+ auto res = factory->createGeodeticCRSFromDatum(
+ datum_auth_name, datum_code, crs_type ? crs_type : "");
+ std::vector<IdentifiedObjectNNPtr> objects;
+ for (const auto &obj : res) {
+ objects.push_back(obj);
+ }
+ return new PJ_OBJ_LIST(std::move(objects));
+ } catch (const std::exception &e) {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ }
+ return nullptr;
+}
+
+// ---------------------------------------------------------------------------
+
/** \brief Drops a reference on an object.
*
* This method should be called one and exactly one for each function
@@ -791,6 +827,36 @@ int proj_obj_is_deprecated(const PJ_OBJ *obj) {
// ---------------------------------------------------------------------------
+/** \brief Return a list of non-deprecated objects related to the passed one
+ *
+ * @param ctx Context, or NULL for default context.
+ * @param obj Object (of type CRS for now) for which non-deprecated objects
+ * must be searched. Must not be NULL
+ * @return a result set that must be unreferenced with
+ * proj_obj_list_unref(), or NULL in case of error.
+ */
+PJ_OBJ_LIST *proj_obj_get_non_deprecated(PJ_CONTEXT *ctx, const PJ_OBJ *obj) {
+ assert(obj);
+ SANITIZE_CTX(ctx);
+ auto crs = dynamic_cast<const CRS *>(obj->obj.get());
+ if (!crs) {
+ return nullptr;
+ }
+ try {
+ std::vector<IdentifiedObjectNNPtr> objects;
+ auto res = crs->getNonDeprecated(getDBcontext(ctx));
+ for (const auto &resObj : res) {
+ objects.push_back(resObj);
+ }
+ return new PJ_OBJ_LIST(std::move(objects));
+ } catch (const std::exception &e) {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ }
+ return nullptr;
+}
+
+// ---------------------------------------------------------------------------
+
/** \brief Return whether two objects are equivalent.
*
* @param obj Object (must not be NULL)
@@ -1289,11 +1355,19 @@ PJ_OBJ *proj_obj_crs_create_bound_crs(PJ_CONTEXT *ctx, const PJ_OBJ *base_crs,
*
* @param ctx PROJ context, or NULL for default context
* @param crs Objet of type CRS (must not be NULL)
+ * @param options null-terminated list of options, or NULL. Currently
+ * supported options are:
+ * <ul>
+ * <li>ALLOW_INTERMEDIATE_CRS=YES/NO. Defaults to NO. When set to YES,
+ * intermediate CRS may be considered when computing the possible
+ * tranformations. Slower.</li>
+ * </ul>
* @return Object that must be unreferenced with proj_obj_unref(), or NULL
* in case of error.
*/
PJ_OBJ *proj_obj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx,
- const PJ_OBJ *crs) {
+ const PJ_OBJ *crs,
+ const char *const *options) {
SANITIZE_CTX(ctx);
assert(crs);
auto l_crs = dynamic_cast<const CRS *>(crs->obj.get());
@@ -1303,8 +1377,20 @@ PJ_OBJ *proj_obj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx,
}
auto dbContext = getDBcontextNoException(ctx, __FUNCTION__);
try {
- return PJ_OBJ::create(
- l_crs->createBoundCRSToWGS84IfPossible(dbContext));
+ bool allowIntermediateCRS = false;
+ for (auto iter = options; iter && iter[0]; ++iter) {
+ const char *value;
+ if ((value = getOptionValue(*iter, "ALLOW_INTERMEDIATE_CRS="))) {
+ allowIntermediateCRS = ci_equal(value, "YES");
+ } else {
+ std::string msg("Unknown option :");
+ msg += *iter;
+ proj_log_error(ctx, __FUNCTION__, msg.c_str());
+ return nullptr;
+ }
+ }
+ return PJ_OBJ::create(l_crs->createBoundCRSToWGS84IfPossible(
+ dbContext, allowIntermediateCRS));
} catch (const std::exception &e) {
proj_log_error(ctx, __FUNCTION__, e.what());
return nullptr;
@@ -5354,9 +5440,17 @@ struct PJ_OPERATION_FACTORY_CONTEXT {
* The returned object must be unreferenced with
* proj_operation_factory_context_unref() after use.
*
+ * If authority is NULL or the empty string, then coordinate
+ * operations from any authority will be searched, with the restrictions set
+ * in the authority_to_authority_preference database table.
+ * If authority is set to "any", then coordinate
+ * operations from any authority will be searched
+ * If authority is a non-empty string different of "any",
+ * then coordinate operatiosn will be searched only in that authority namespace.
+ *
* @param ctx Context, or NULL for default context.
* @param authority Name of authority to which to restrict the search of
- * canidate operations. Or NULL to allow any authority.
+ * candidate operations.
* @return Object that must be unreferenced with
* proj_operation_factory_context_unref(), or NULL in
* case of error.
diff --git a/src/common.cpp b/src/common.cpp
index 94bc8678..2a9d17c7 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -650,23 +650,20 @@ bool IdentifiedObject::isDeprecated() PROJ_CONST_DEFN {
void IdentifiedObject::Private::setName(
const PropertyMap &properties) // throw(InvalidValueTypeException)
{
- auto oIter = properties.find(NAME_KEY);
- if (oIter == properties.end()) {
+ const auto pVal = properties.get(NAME_KEY);
+ if (!pVal) {
return;
}
- if (auto genVal =
- util::nn_dynamic_pointer_cast<BoxedValue>(oIter->second)) {
+ if (const auto genVal = dynamic_cast<const BoxedValue *>(pVal->get())) {
if (genVal->type() == BoxedValue::Type::STRING) {
- name = Identifier::create(
- std::string(), PropertyMap().set(Identifier::DESCRIPTION_KEY,
- genVal->stringValue()));
+ name = Identifier::createFromDescription(genVal->stringValue());
} else {
throw InvalidValueTypeException("Invalid value type for " +
NAME_KEY);
}
} else {
if (auto identifier =
- util::nn_dynamic_pointer_cast<Identifier>(oIter->second)) {
+ util::nn_dynamic_pointer_cast<Identifier>(*pVal)) {
name = NN_NO_CHECK(identifier);
} else {
throw InvalidValueTypeException("Invalid value type for " +
@@ -680,23 +677,21 @@ void IdentifiedObject::Private::setName(
void IdentifiedObject::Private::setIdentifiers(
const PropertyMap &properties) // throw(InvalidValueTypeException)
{
- auto oIter = properties.find(IDENTIFIERS_KEY);
- if (oIter == properties.end()) {
+ auto pVal = properties.get(IDENTIFIERS_KEY);
+ if (!pVal) {
- oIter = properties.find(Identifier::CODE_KEY);
- if (oIter != properties.end()) {
+ pVal = properties.get(Identifier::CODE_KEY);
+ if (pVal) {
identifiers.push_back(
Identifier::create(std::string(), properties));
}
return;
}
- if (auto identifier =
- util::nn_dynamic_pointer_cast<Identifier>(oIter->second)) {
+ if (auto identifier = util::nn_dynamic_pointer_cast<Identifier>(*pVal)) {
identifiers.clear();
identifiers.push_back(NN_NO_CHECK(identifier));
} else {
- if (auto array = util::nn_dynamic_pointer_cast<ArrayOfBaseObject>(
- oIter->second)) {
+ if (auto array = dynamic_cast<const ArrayOfBaseObject *>(pVal->get())) {
identifiers.clear();
for (const auto &val : *array) {
identifier = util::nn_dynamic_pointer_cast<Identifier>(val);
@@ -719,17 +714,16 @@ void IdentifiedObject::Private::setIdentifiers(
void IdentifiedObject::Private::setAliases(
const PropertyMap &properties) // throw(InvalidValueTypeException)
{
- auto oIter = properties.find(ALIAS_KEY);
- if (oIter == properties.end()) {
+ const auto pVal = properties.get(ALIAS_KEY);
+ if (!pVal) {
return;
}
- if (auto l_name =
- util::nn_dynamic_pointer_cast<GenericName>(oIter->second)) {
+ if (auto l_name = util::nn_dynamic_pointer_cast<GenericName>(*pVal)) {
aliases.clear();
aliases.push_back(NN_NO_CHECK(l_name));
} else {
- if (auto array = util::nn_dynamic_pointer_cast<ArrayOfBaseObject>(
- oIter->second)) {
+ if (const auto array =
+ dynamic_cast<const ArrayOfBaseObject *>(pVal->get())) {
aliases.clear();
for (const auto &val : *array) {
l_name = util::nn_dynamic_pointer_cast<GenericName>(val);
@@ -737,7 +731,7 @@ void IdentifiedObject::Private::setAliases(
aliases.push_back(NN_NO_CHECK(l_name));
} else {
if (auto genVal =
- util::nn_dynamic_pointer_cast<BoxedValue>(val)) {
+ dynamic_cast<const BoxedValue *>(val.get())) {
if (genVal->type() == BoxedValue::Type::STRING) {
aliases.push_back(NameFactory::createLocalName(
nullptr, genVal->stringValue()));
@@ -777,10 +771,10 @@ void IdentifiedObject::setProperties(
properties.getStringValue(REMARKS_KEY, d->remarks);
{
- auto oIter = properties.find(DEPRECATED_KEY);
- if (oIter != properties.end()) {
- if (auto genVal =
- util::nn_dynamic_pointer_cast<BoxedValue>(oIter->second)) {
+ const auto pVal = properties.get(DEPRECATED_KEY);
+ if (pVal) {
+ if (const auto genVal =
+ dynamic_cast<const BoxedValue *>(pVal->get())) {
if (genVal->type() == BoxedValue::Type::BOOLEAN) {
d->isDeprecated = genVal->booleanValue();
} else {
@@ -930,8 +924,8 @@ void ObjectDomain::_exportToWKT(WKTFormatter *formatter) const {
formatter->endNode();
}
if (d->domainOfValidity_->geographicElements().size() == 1) {
- auto bbox = util::nn_dynamic_pointer_cast<GeographicBoundingBox>(
- d->domainOfValidity_->geographicElements()[0]);
+ const auto bbox = dynamic_cast<const GeographicBoundingBox *>(
+ d->domainOfValidity_->geographicElements()[0].get());
if (bbox) {
formatter->startNode(WKTConstants::BBOX, false);
formatter->add(bbox->southBoundLatitude());
@@ -1029,19 +1023,13 @@ void ObjectUsage::setProperties(
IdentifiedObject::setProperties(properties);
optional<std::string> scope;
- {
- std::string temp;
- if (properties.getStringValue(SCOPE_KEY, temp)) {
- scope = temp;
- }
- }
+ properties.getStringValue(SCOPE_KEY, scope);
ExtentPtr domainOfValidity;
{
- auto oIter = properties.find(DOMAIN_OF_VALIDITY_KEY);
- if (oIter != properties.end()) {
- domainOfValidity =
- util::nn_dynamic_pointer_cast<Extent>(oIter->second);
+ const auto pVal = properties.get(DOMAIN_OF_VALIDITY_KEY);
+ if (pVal) {
+ domainOfValidity = util::nn_dynamic_pointer_cast<Extent>(*pVal);
if (!domainOfValidity) {
throw InvalidValueTypeException("Invalid value type for " +
DOMAIN_OF_VALIDITY_KEY);
@@ -1054,14 +1042,14 @@ void ObjectUsage::setProperties(
}
{
- auto oIter = properties.find(OBJECT_DOMAIN_KEY);
- if (oIter != properties.end()) {
- if (auto objectDomain = util::nn_dynamic_pointer_cast<ObjectDomain>(
- oIter->second)) {
+ const auto pVal = properties.get(OBJECT_DOMAIN_KEY);
+ if (pVal) {
+ if (auto objectDomain =
+ util::nn_dynamic_pointer_cast<ObjectDomain>(*pVal)) {
d->domains_.emplace_back(NN_NO_CHECK(objectDomain));
- } else if (auto array =
- util::nn_dynamic_pointer_cast<ArrayOfBaseObject>(
- oIter->second)) {
+ } else if (const auto array =
+ dynamic_cast<const ArrayOfBaseObject *>(
+ pVal->get())) {
for (const auto &val : *array) {
objectDomain =
util::nn_dynamic_pointer_cast<ObjectDomain>(val);
diff --git a/src/coordinateoperation.cpp b/src/coordinateoperation.cpp
index 04f9bc9a..8f75864e 100644
--- a/src/coordinateoperation.cpp
+++ b/src/coordinateoperation.cpp
@@ -2055,8 +2055,7 @@ static util::PropertyMap createMethodMapNameEPSGCode(int code) {
static util::PropertyMap
getUTMConversionProperty(const util::PropertyMap &properties, int zone,
bool north) {
- if (properties.find(common::IdentifiedObject::NAME_KEY) ==
- properties.end()) {
+ if (!properties.get(common::IdentifiedObject::NAME_KEY)) {
std::string conversionName("UTM zone ");
conversionName += toString(zone);
conversionName += (north ? 'N' : 'S');
@@ -2073,8 +2072,7 @@ getUTMConversionProperty(const util::PropertyMap &properties, int zone,
static util::PropertyMap
addDefaultNameIfNeeded(const util::PropertyMap &properties,
const std::string &defaultName) {
- if (properties.find(common::IdentifiedObject::NAME_KEY) ==
- properties.end()) {
+ if (!properties.get(common::IdentifiedObject::NAME_KEY)) {
return util::PropertyMap(properties)
.set(common::IdentifiedObject::NAME_KEY, defaultName);
} else {
@@ -5177,7 +5175,9 @@ void Conversion::_exportToPROJString(
double latitudePseudoStandardParallel = parameterValueNumeric(
EPSG_CODE_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL,
common::UnitOfMeasure::DEGREE);
- if (std::fabs(colatitude - 30.28813972222222) > 1e-8) {
+ // 30deg 17' 17.30311'' = 30.28813975277777776
+ // 30deg 17' 17.303'' = 30.288139722222223 as used in GDAL WKT1
+ if (std::fabs(colatitude - 30.2881397) > 1e-7) {
throw io::FormattingException(
std::string("Unsupported value for ") +
EPSG_NAME_PARAMETER_COLATITUDE_CONE_AXIS);
@@ -8937,6 +8937,14 @@ CoordinateOperationContext::getIntermediateCRS() const {
* If a non null authorityFactory is provided, the resulting context should
* not be used simultaneously by more than one thread.
*
+ * If authorityFactory->getAuthority() is the empty string, then coordinate
+ * operations from any authority will be searched, with the restrictions set
+ * in the authority_to_authority_preference database table.
+ * If authorityFactory->getAuthority() is set to "any", then coordinate
+ * operations from any authority will be searched
+ * If authorityFactory->getAuthority() is a non-empty string different of "any",
+ * then coordinate operatiosn will be searched only in that authority namespace.
+ *
* @param authorityFactory Authority factory, or null if no database lookup
* is allowed.
* Use io::authorityFactory::create(context, std::string()) to allow all
@@ -9569,6 +9577,10 @@ struct FilterAndSort {
// cppcheck-suppress functionStatic
void removeDuplicateOps() {
+ if (res.size() <= 1) {
+ return;
+ }
+
// When going from EPSG:4807 (NTF Paris) to EPSG:4171 (RGC93), we get
// EPSG:7811, NTF (Paris) to RGF93 (2), 1 m
// and unknown id, NTF (Paris) to NTF (1) + Inverse of RGF93 to NTF (2),
@@ -9663,6 +9675,8 @@ findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS,
const CoordinateOperationContextNNPtr &context) {
const auto &authFactory = context->getAuthorityFactory();
assert(authFactory);
+ const auto &authFactoryName = authFactory->getAuthority();
+
for (const auto &idSrc : sourceCRS->identifiers()) {
const auto &srcAuthName = *(idSrc->codeSpace());
const auto &srcCode = idSrc->code();
@@ -9671,17 +9685,39 @@ findOpsInRegistryDirect(const crs::CRSNNPtr &sourceCRS,
const auto &targetAuthName = *(idTarget->codeSpace());
const auto &targetCode = idTarget->code();
if (!targetAuthName.empty()) {
- auto res =
- authFactory->createFromCoordinateReferenceSystemCodes(
- srcAuthName, srcCode, targetAuthName, targetCode,
- context->getUsePROJAlternativeGridNames(),
- context->getGridAvailabilityUse() ==
- CoordinateOperationContext::
- GridAvailabilityUse::
- DISCARD_OPERATION_IF_MISSING_GRID,
- context->getDiscardSuperseded());
- if (!res.empty()) {
- return res;
+ std::vector<std::string> authorities;
+ if (authFactoryName == "any") {
+ authorities.emplace_back();
+ }
+ if (authFactoryName.empty()) {
+ authorities = authFactory->databaseContext()
+ ->getAllowedAuthorities(
+ srcAuthName, targetAuthName);
+ if (authorities.empty()) {
+ authorities.emplace_back();
+ }
+ } else {
+ authorities.emplace_back(authFactoryName);
+ }
+ for (const auto &authority : authorities) {
+ const auto tmpAuthFactory =
+ io::AuthorityFactory::create(
+ authFactory->databaseContext(),
+ authority == "any" ? std::string() : authority);
+ auto res =
+ tmpAuthFactory
+ ->createFromCoordinateReferenceSystemCodes(
+ srcAuthName, srcCode, targetAuthName,
+ targetCode,
+ context->getUsePROJAlternativeGridNames(),
+ context->getGridAvailabilityUse() ==
+ CoordinateOperationContext::
+ GridAvailabilityUse::
+ DISCARD_OPERATION_IF_MISSING_GRID,
+ context->getDiscardSuperseded());
+ if (!res.empty()) {
+ return res;
+ }
}
}
}
@@ -9706,6 +9742,8 @@ static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate(
const auto &authFactory = context->getAuthorityFactory();
assert(authFactory);
+ const auto &authFactoryName = authFactory->getAuthority();
+
for (const auto &idSrc : sourceCRS->identifiers()) {
const auto &srcAuthName = *(idSrc->codeSpace());
const auto &srcCode = idSrc->code();
@@ -9714,16 +9752,40 @@ static std::vector<CoordinateOperationNNPtr> findsOpsInRegistryWithIntermediate(
const auto &targetAuthName = *(idTarget->codeSpace());
const auto &targetCode = idTarget->code();
if (!targetAuthName.empty()) {
- auto res = authFactory->createFromCRSCodesWithIntermediates(
- srcAuthName, srcCode, targetAuthName, targetCode,
- context->getUsePROJAlternativeGridNames(),
- context->getGridAvailabilityUse() ==
- CoordinateOperationContext::GridAvailabilityUse::
- DISCARD_OPERATION_IF_MISSING_GRID,
- context->getDiscardSuperseded(),
- context->getIntermediateCRS());
- if (!res.empty()) {
- return res;
+ std::vector<std::string> authorities;
+ if (authFactoryName == "any") {
+ authorities.emplace_back();
+ }
+ if (authFactoryName.empty()) {
+ authorities = authFactory->databaseContext()
+ ->getAllowedAuthorities(
+ srcAuthName, targetAuthName);
+ if (authorities.empty()) {
+ authorities.emplace_back();
+ }
+ } else {
+ authorities.emplace_back(authFactoryName);
+ }
+ for (const auto &authority : authorities) {
+ const auto tmpAuthFactory =
+ io::AuthorityFactory::create(
+ authFactory->databaseContext(),
+ authority == "any" ? std::string() : authority);
+
+ auto res =
+ tmpAuthFactory->createFromCRSCodesWithIntermediates(
+ srcAuthName, srcCode, targetAuthName,
+ targetCode,
+ context->getUsePROJAlternativeGridNames(),
+ context->getGridAvailabilityUse() ==
+ CoordinateOperationContext::
+ GridAvailabilityUse::
+ DISCARD_OPERATION_IF_MISSING_GRID,
+ context->getDiscardSuperseded(),
+ context->getIntermediateCRS());
+ if (!res.empty()) {
+ return res;
+ }
}
}
}
diff --git a/src/coordinatesystem.cpp b/src/coordinatesystem.cpp
index f1220878..2305e6c4 100644
--- a/src/coordinatesystem.cpp
+++ b/src/coordinatesystem.cpp
@@ -325,7 +325,13 @@ void CoordinateSystemAxis::_exportToWKT(io::WKTFormatter *formatter, int order,
axisDesignation =
tolower(axisName.substr(0, 1)) + axisName.substr(1);
} else {
- axisDesignation = axisName;
+ if (axisName == "Geodetic latitude") {
+ axisDesignation = "Latitude";
+ } else if (axisName == "Geodetic longitude") {
+ axisDesignation = "Longitude";
+ } else {
+ axisDesignation = axisName;
+ }
}
}
diff --git a/src/crs.cpp b/src/crs.cpp
index 546cfb0a..572fae5d 100644
--- a/src/crs.cpp
+++ b/src/crs.cpp
@@ -92,10 +92,10 @@ struct CRS::Private {
bool implicitCS_ = false;
void setImplicitCS(const util::PropertyMap &properties) {
- auto oIter = properties.find("IMPLICIT_CS");
- if (oIter != properties.end()) {
- if (auto genVal = util::nn_dynamic_pointer_cast<util::BoxedValue>(
- oIter->second)) {
+ const auto pVal = properties.get("IMPLICIT_CS");
+ if (pVal) {
+ if (const auto genVal =
+ dynamic_cast<const util::BoxedValue *>(pVal->get())) {
if (genVal->type() == util::BoxedValue::Type::BOOLEAN &&
genVal->booleanValue()) {
implicitCS_ = true;
@@ -375,8 +375,9 @@ VerticalCRSPtr CRS::extractVerticalCRS() const {
*
* @return a CRS.
*/
-CRSNNPtr CRS::createBoundCRSToWGS84IfPossible(
- const io::DatabaseContextPtr &dbContext) const {
+CRSNNPtr
+CRS::createBoundCRSToWGS84IfPossible(const io::DatabaseContextPtr &dbContext,
+ bool allowIntermediateCRS) const {
auto thisAsCRS = NN_NO_CHECK(
std::static_pointer_cast<CRS>(shared_from_this().as_nullable()));
auto boundCRS = util::nn_dynamic_pointer_cast<BoundCRS>(thisAsCRS);
@@ -409,74 +410,98 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible(
} else {
geodCRS = geogCRS;
}
- auto l_domains = domains();
+
+ if (!dbContext) {
+ return thisAsCRS;
+ }
+
+ const auto &l_domains = domains();
metadata::ExtentPtr extent;
if (!l_domains.empty()) {
extent = l_domains[0]->domainOfValidity();
}
- try {
- auto authFactory = dbContext
- ? io::AuthorityFactory::create(
- NN_NO_CHECK(dbContext), std::string())
- .as_nullable()
- : nullptr;
- auto ctxt = operation::CoordinateOperationContext::create(authFactory,
- extent, 0.0);
- // ctxt->setSpatialCriterion(
- // operation::CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
- auto list =
- operation::CoordinateOperationFactory::create()->createOperations(
- NN_NO_CHECK(geodCRS), hubCRS, ctxt);
- for (const auto &op : list) {
- auto transf =
- util::nn_dynamic_pointer_cast<operation::Transformation>(op);
- if (transf) {
- try {
- transf->getTOWGS84Parameters();
- } catch (const std::exception &) {
- continue;
- }
- return util::nn_static_pointer_cast<CRS>(
- BoundCRS::create(thisAsCRS, hubCRS, NN_NO_CHECK(transf)));
- } else {
- auto concatenated =
- dynamic_cast<const operation::ConcatenatedOperation *>(
- op.get());
- if (concatenated) {
- // Case for EPSG:4807 / "NTF (Paris)" that is made of a
- // longitude rotation followed by a Helmert
- // The prime meridian shift will be accounted elsewhere
- const auto &subops = concatenated->operations();
- if (subops.size() == 2) {
- auto firstOpIsTransformation =
- dynamic_cast<const operation::Transformation *>(
- subops[0].get());
- auto firstOpIsConversion =
- dynamic_cast<const operation::Conversion *>(
- subops[0].get());
- if ((firstOpIsTransformation &&
- firstOpIsTransformation->isLongitudeRotation()) ||
- (dynamic_cast<DerivedCRS *>(thisAsCRS.get()) &&
- firstOpIsConversion)) {
- transf = util::nn_dynamic_pointer_cast<
- operation::Transformation>(subops[1]);
- if (transf) {
- try {
- transf->getTOWGS84Parameters();
- } catch (const std::exception &) {
- continue;
+ std::string crs_authority;
+ const auto &l_identifiers = identifiers();
+ // If the object has an authority, restrict the transformations to
+ // come from that codespace too. This avoids for example EPSG:4269
+ // (NAD83) to use a (dubious) ESRI transformation.
+ if (!l_identifiers.empty()) {
+ crs_authority = *(l_identifiers[0]->codeSpace());
+ }
+
+ auto authorities = dbContext->getAllowedAuthorities(crs_authority, "EPSG");
+ if (authorities.empty()) {
+ authorities.emplace_back();
+ }
+ for (const auto &authority : authorities) {
+ try {
+
+ auto authFactory = io::AuthorityFactory::create(
+ NN_NO_CHECK(dbContext),
+ authority == "any" ? std::string() : authority);
+ auto ctxt = operation::CoordinateOperationContext::create(
+ authFactory, extent, 0.0);
+ ctxt->setAllowUseIntermediateCRS(allowIntermediateCRS);
+ // ctxt->setSpatialCriterion(
+ // operation::CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION);
+ auto list =
+ operation::CoordinateOperationFactory::create()
+ ->createOperations(NN_NO_CHECK(geodCRS), hubCRS, ctxt);
+ for (const auto &op : list) {
+ auto transf =
+ util::nn_dynamic_pointer_cast<operation::Transformation>(
+ op);
+ if (transf && !starts_with(transf->nameStr(), "Null geo")) {
+ try {
+ transf->getTOWGS84Parameters();
+ } catch (const std::exception &) {
+ continue;
+ }
+ return util::nn_static_pointer_cast<CRS>(BoundCRS::create(
+ thisAsCRS, hubCRS, NN_NO_CHECK(transf)));
+ } else {
+ auto concatenated =
+ dynamic_cast<const operation::ConcatenatedOperation *>(
+ op.get());
+ if (concatenated) {
+ // Case for EPSG:4807 / "NTF (Paris)" that is made of a
+ // longitude rotation followed by a Helmert
+ // The prime meridian shift will be accounted elsewhere
+ const auto &subops = concatenated->operations();
+ if (subops.size() == 2) {
+ auto firstOpIsTransformation =
+ dynamic_cast<const operation::Transformation *>(
+ subops[0].get());
+ auto firstOpIsConversion =
+ dynamic_cast<const operation::Conversion *>(
+ subops[0].get());
+ if ((firstOpIsTransformation &&
+ firstOpIsTransformation
+ ->isLongitudeRotation()) ||
+ (dynamic_cast<DerivedCRS *>(thisAsCRS.get()) &&
+ firstOpIsConversion)) {
+ transf = util::nn_dynamic_pointer_cast<
+ operation::Transformation>(subops[1]);
+ if (transf &&
+ !starts_with(transf->nameStr(),
+ "Null geo")) {
+ try {
+ transf->getTOWGS84Parameters();
+ } catch (const std::exception &) {
+ continue;
+ }
+ return util::nn_static_pointer_cast<CRS>(
+ BoundCRS::create(thisAsCRS, hubCRS,
+ NN_NO_CHECK(transf)));
}
- return util::nn_static_pointer_cast<CRS>(
- BoundCRS::create(thisAsCRS, hubCRS,
- NN_NO_CHECK(transf)));
}
}
}
}
}
+ } catch (const std::exception &) {
}
- } catch (const std::exception &) {
}
return thisAsCRS;
}
@@ -580,6 +605,40 @@ CRS::identify(const io::AuthorityFactoryPtr &authorityFactory) const {
// ---------------------------------------------------------------------------
+/** \brief Return CRSs that are non-deprecated substitutes for the current CRS.
+ */
+std::list<CRSNNPtr>
+CRS::getNonDeprecated(const io::DatabaseContextNNPtr &dbContext) const {
+ std::list<CRSNNPtr> res;
+ const auto &l_identifiers = identifiers();
+ if (l_identifiers.empty()) {
+ return res;
+ }
+ const char *tableName = nullptr;
+ if (dynamic_cast<const GeodeticCRS *>(this)) {
+ tableName = "geodetic_crs";
+ } else if (dynamic_cast<const ProjectedCRS *>(this)) {
+ tableName = "projected_crs";
+ } else if (dynamic_cast<const VerticalCRS *>(this)) {
+ tableName = "vertical_crs";
+ } else if (dynamic_cast<const CompoundCRS *>(this)) {
+ tableName = "compound_crs";
+ }
+ if (!tableName) {
+ return res;
+ }
+ const auto &id = l_identifiers[0];
+ auto tmpRes =
+ dbContext->getNonDeprecated(tableName, *(id->codeSpace()), id->code());
+ for (const auto &pair : tmpRes) {
+ res.emplace_back(io::AuthorityFactory::create(dbContext, pair.first)
+ ->createCoordinateReferenceSystem(pair.second));
+ }
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
//! @cond Doxygen_Suppress
std::list<std::pair<CRSNNPtr, int>>
@@ -3167,8 +3226,7 @@ CompoundCRSNNPtr CompoundCRS::create(const util::PropertyMap &properties,
auto compoundCRS(CompoundCRS::nn_make_shared<CompoundCRS>(components));
compoundCRS->assignSelf(compoundCRS);
compoundCRS->setProperties(properties);
- if (properties.find(common::IdentifiedObject::NAME_KEY) ==
- properties.end()) {
+ if (!properties.get(common::IdentifiedObject::NAME_KEY)) {
std::string name;
for (const auto &crs : components) {
if (!name.empty()) {
@@ -4459,10 +4517,10 @@ EngineeringCRS::create(const util::PropertyMap &properties,
crs->assignSelf(crs);
crs->setProperties(properties);
- auto oIter = properties.find("FORCE_OUTPUT_CS");
- if (oIter != properties.end()) {
- if (auto genVal = util::nn_dynamic_pointer_cast<util::BoxedValue>(
- oIter->second)) {
+ const auto pVal = properties.get("FORCE_OUTPUT_CS");
+ if (pVal) {
+ if (const auto genVal =
+ dynamic_cast<const util::BoxedValue *>(pVal->get())) {
if (genVal->type() == util::BoxedValue::Type::BOOLEAN &&
genVal->booleanValue()) {
crs->d->forceOutputCS_ = true;
diff --git a/src/factory.cpp b/src/factory.cpp
index e24cee58..39679082 100644
--- a/src/factory.cpp
+++ b/src/factory.cpp
@@ -108,7 +108,8 @@ struct SQLValues {
// ---------------------------------------------------------------------------
using SQLRow = std::vector<std::string>;
-using SQLResultSet = std::vector<SQLRow>;
+using SQLResultSet = std::list<SQLRow>;
+using ListOfParams = std::list<SQLValues>;
// ---------------------------------------------------------------------------
@@ -124,9 +125,8 @@ struct DatabaseContext::Private {
PJ_CONTEXT *pjCtxt() const { return pjCtxt_; }
void setPjCtxt(PJ_CONTEXT *ctxt) { pjCtxt_ = ctxt; }
- SQLResultSet
- run(const std::string &sql,
- const std::vector<SQLValues> &parameters = std::vector<SQLValues>());
+ SQLResultSet run(const std::string &sql,
+ const ListOfParams &parameters = ListOfParams());
std::vector<std::string> getDatabaseStructure();
@@ -160,6 +160,48 @@ struct DatabaseContext::Private {
return mapCanonicalizeGRFName_;
}
+ // cppcheck-suppress functionStatic
+ common::UnitOfMeasurePtr getUOMFromCache(const std::string &code);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code, const common::UnitOfMeasureNNPtr &uom);
+
+ // cppcheck-suppress functionStatic
+ crs::CRSPtr getCRSFromCache(const std::string &code);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code, const crs::CRSNNPtr &crs);
+
+ datum::GeodeticReferenceFramePtr
+ // cppcheck-suppress functionStatic
+ getGeodeticDatumFromCache(const std::string &code);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code,
+ const datum::GeodeticReferenceFrameNNPtr &datum);
+
+ datum::PrimeMeridianPtr
+ // cppcheck-suppress functionStatic
+ getPrimeMeridianFromCache(const std::string &code);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code, const datum::PrimeMeridianNNPtr &pm);
+
+ // cppcheck-suppress functionStatic
+ cs::CoordinateSystemPtr
+ getCoordinateSystemFromCache(const std::string &code);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code, const cs::CoordinateSystemNNPtr &cs);
+
+ // cppcheck-suppress functionStatic
+ metadata::ExtentPtr getExtentFromCache(const std::string &code);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code, const metadata::ExtentNNPtr &extent);
+
+ // cppcheck-suppress functionStatic
+ bool getCRSToCRSCoordOpFromCache(
+ const std::string &code,
+ std::vector<operation::CoordinateOperationNNPtr> &list);
+ // cppcheck-suppress functionStatic
+ void cache(const std::string &code,
+ const std::vector<operation::CoordinateOperationNNPtr> &list);
+
private:
friend class DatabaseContext;
@@ -173,6 +215,25 @@ struct DatabaseContext::Private {
std::string lastMetadataValue_{};
std::map<std::string, std::list<SQLRow>> mapCanonicalizeGRFName_{};
+ using LRUCacheOfObjects = lru11::Cache<std::string, util::BaseObjectPtr>;
+
+ static constexpr size_t CACHE_SIZE = 128;
+ LRUCacheOfObjects cacheUOM_{CACHE_SIZE};
+ LRUCacheOfObjects cacheCRS_{CACHE_SIZE};
+ LRUCacheOfObjects cacheGeodeticDatum_{CACHE_SIZE};
+ LRUCacheOfObjects cachePrimeMeridian_{CACHE_SIZE};
+ LRUCacheOfObjects cacheCS_{CACHE_SIZE};
+ LRUCacheOfObjects cacheExtent_{CACHE_SIZE};
+ lru11::Cache<std::string, std::vector<operation::CoordinateOperationNNPtr>>
+ cacheCRSToCrsCoordOp_{CACHE_SIZE};
+
+ static void insertIntoCache(LRUCacheOfObjects &cache,
+ const std::string &code,
+ const util::BaseObjectPtr &obj);
+
+ static void getFromCache(LRUCacheOfObjects &cache, const std::string &code,
+ util::BaseObjectPtr &obj);
+
void closeDB();
// cppcheck-suppress functionStatic
@@ -240,6 +301,133 @@ void DatabaseContext::Private::closeDB() {
// ---------------------------------------------------------------------------
+void DatabaseContext::Private::insertIntoCache(LRUCacheOfObjects &cache,
+ const std::string &code,
+ const util::BaseObjectPtr &obj) {
+ cache.insert(code, obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::getFromCache(LRUCacheOfObjects &cache,
+ const std::string &code,
+ util::BaseObjectPtr &obj) {
+ cache.tryGet(code, obj);
+}
+
+// ---------------------------------------------------------------------------
+
+bool DatabaseContext::Private::getCRSToCRSCoordOpFromCache(
+ const std::string &code,
+ std::vector<operation::CoordinateOperationNNPtr> &list) {
+ return cacheCRSToCrsCoordOp_.tryGet(code, list);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(
+ const std::string &code,
+ const std::vector<operation::CoordinateOperationNNPtr> &list) {
+ cacheCRSToCrsCoordOp_.insert(code, list);
+}
+
+// ---------------------------------------------------------------------------
+
+crs::CRSPtr DatabaseContext::Private::getCRSFromCache(const std::string &code) {
+ util::BaseObjectPtr obj;
+ getFromCache(cacheCRS_, code, obj);
+ return std::static_pointer_cast<crs::CRS>(obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(const std::string &code,
+ const crs::CRSNNPtr &crs) {
+ insertIntoCache(cacheCRS_, code, crs.as_nullable());
+}
+
+// ---------------------------------------------------------------------------
+
+common::UnitOfMeasurePtr
+DatabaseContext::Private::getUOMFromCache(const std::string &code) {
+ util::BaseObjectPtr obj;
+ getFromCache(cacheUOM_, code, obj);
+ return std::static_pointer_cast<common::UnitOfMeasure>(obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(const std::string &code,
+ const common::UnitOfMeasureNNPtr &uom) {
+ insertIntoCache(cacheUOM_, code, uom.as_nullable());
+}
+
+// ---------------------------------------------------------------------------
+
+datum::GeodeticReferenceFramePtr
+DatabaseContext::Private::getGeodeticDatumFromCache(const std::string &code) {
+ util::BaseObjectPtr obj;
+ getFromCache(cacheGeodeticDatum_, code, obj);
+ return std::static_pointer_cast<datum::GeodeticReferenceFrame>(obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(
+ const std::string &code, const datum::GeodeticReferenceFrameNNPtr &datum) {
+ insertIntoCache(cacheGeodeticDatum_, code, datum.as_nullable());
+}
+
+// ---------------------------------------------------------------------------
+
+datum::PrimeMeridianPtr
+DatabaseContext::Private::getPrimeMeridianFromCache(const std::string &code) {
+ util::BaseObjectPtr obj;
+ getFromCache(cachePrimeMeridian_, code, obj);
+ return std::static_pointer_cast<datum::PrimeMeridian>(obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(const std::string &code,
+ const datum::PrimeMeridianNNPtr &pm) {
+ insertIntoCache(cachePrimeMeridian_, code, pm.as_nullable());
+}
+
+// ---------------------------------------------------------------------------
+
+cs::CoordinateSystemPtr DatabaseContext::Private::getCoordinateSystemFromCache(
+ const std::string &code) {
+ util::BaseObjectPtr obj;
+ getFromCache(cacheCS_, code, obj);
+ return std::static_pointer_cast<cs::CoordinateSystem>(obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(const std::string &code,
+ const cs::CoordinateSystemNNPtr &cs) {
+ insertIntoCache(cacheCS_, code, cs.as_nullable());
+}
+
+// ---------------------------------------------------------------------------
+
+metadata::ExtentPtr
+DatabaseContext::Private::getExtentFromCache(const std::string &code) {
+ util::BaseObjectPtr obj;
+ getFromCache(cacheExtent_, code, obj);
+ return std::static_pointer_cast<metadata::Extent>(obj);
+}
+
+// ---------------------------------------------------------------------------
+
+void DatabaseContext::Private::cache(const std::string &code,
+ const metadata::ExtentNNPtr &extent) {
+ insertIntoCache(cacheExtent_, code, extent.as_nullable());
+}
+
+// ---------------------------------------------------------------------------
+
#ifdef ENABLE_CUSTOM_LOCKLESS_VFS
typedef int (*ClosePtr)(sqlite3_file *);
@@ -564,9 +752,8 @@ void DatabaseContext::Private::registerFunctions() {
// ---------------------------------------------------------------------------
-SQLResultSet
-DatabaseContext::Private::run(const std::string &sql,
- const std::vector<SQLValues> &parameters) {
+SQLResultSet DatabaseContext::Private::run(const std::string &sql,
+ const ListOfParams &parameters) {
sqlite3_stmt *stmt = nullptr;
auto iter = mapSqlToStatement_.find(sql);
@@ -603,13 +790,15 @@ DatabaseContext::Private::run(const std::string &sql,
while (true) {
int ret = sqlite3_step(stmt);
if (ret == SQLITE_ROW) {
- SQLRow row;
+ SQLRow row(column_count);
for (int i = 0; i < column_count; i++) {
const char *txt = reinterpret_cast<const char *>(
sqlite3_column_text(stmt, i));
- row.emplace_back(txt ? txt : std::string());
+ if (txt) {
+ row[i] = txt;
+ }
}
- result.emplace_back(row);
+ result.emplace_back(std::move(row));
} else if (ret == SQLITE_DONE) {
break;
} else {
@@ -722,7 +911,7 @@ const char *DatabaseContext::getMetadata(const char *key) const {
if (res.empty()) {
return nullptr;
}
- d->lastMetadataValue_ = res[0][0];
+ d->lastMetadataValue_ = res.front()[0];
return d->lastMetadataValue_.c_str();
}
@@ -761,9 +950,10 @@ bool DatabaseContext::lookForGridAlternative(const std::string &officialName,
if (res.empty()) {
return false;
}
- projFilename = res[0][0];
- projFormat = res[0][1];
- inverse = res[0][2] == "1";
+ const auto &row = res.front();
+ projFilename = row[0];
+ projFormat = row[1];
+ inverse = row[2] == "1";
return true;
}
@@ -807,10 +997,11 @@ bool DatabaseContext::lookForGridInfo(const std::string &projFilename,
if (res.empty()) {
return false;
}
- packageName = std::move(res[0][0]);
- url = res[0][1].empty() ? std::move(res[0][2]) : std::move(res[0][1]);
- openLicense = (res[0][3].empty() ? res[0][4] : res[0][3]) == "1";
- directDownload = (res[0][5].empty() ? res[0][6] : res[0][5]) == "1";
+ const auto &row = res.front();
+ packageName = std::move(row[0]);
+ url = row[1].empty() ? std::move(row[2]) : std::move(row[1]);
+ openLicense = (row[3].empty() ? row[4] : row[3]) == "1";
+ directDownload = (row[5].empty() ? row[6] : row[5]) == "1";
return true;
}
@@ -848,13 +1039,14 @@ DatabaseContext::getAliasFromOfficialName(const std::string &officialName,
if (res.empty()) {
return std::string();
}
+ const auto &row = res.front();
res = d->run("SELECT alt_name FROM alias_name WHERE table_name = ? AND "
"auth_name = ? AND code = ? AND source = ?",
- {tableName, res[0][0], res[0][1], source});
+ {tableName, row[0], row[1], source});
if (res.empty()) {
return std::string();
}
- return res[0][0];
+ return res.front()[0];
}
// ---------------------------------------------------------------------------
@@ -877,7 +1069,77 @@ std::string DatabaseContext::getTextDefinition(const std::string &tableName,
if (res.empty()) {
return std::string();
}
- return res[0][0];
+ return res.front()[0];
+}
+
+// ---------------------------------------------------------------------------
+
+/** \brief Return the allowed authorities when researching transformations
+ * between different authorities.
+ *
+ * @throw FactoryException
+ */
+std::vector<std::string> DatabaseContext::getAllowedAuthorities(
+ const std::string &sourceAuthName,
+ const std::string &targetAuthName) const {
+ auto res = d->run(
+ "SELECT allowed_authorities FROM authority_to_authority_preference "
+ "WHERE source_auth_name = ? AND target_auth_name = ?",
+ {sourceAuthName, targetAuthName});
+ if (res.empty()) {
+ res = d->run(
+ "SELECT allowed_authorities FROM authority_to_authority_preference "
+ "WHERE source_auth_name = ? AND target_auth_name = 'any'",
+ {sourceAuthName});
+ }
+ if (res.empty()) {
+ res = d->run(
+ "SELECT allowed_authorities FROM authority_to_authority_preference "
+ "WHERE source_auth_name = 'any' AND target_auth_name = ?",
+ {targetAuthName});
+ }
+ if (res.empty()) {
+ res = d->run(
+ "SELECT allowed_authorities FROM authority_to_authority_preference "
+ "WHERE source_auth_name = 'any' AND target_auth_name = 'any'",
+ {});
+ }
+ if (res.empty()) {
+ return std::vector<std::string>();
+ }
+ return split(res.front()[0], ',');
+}
+
+// ---------------------------------------------------------------------------
+
+std::list<std::pair<std::string, std::string>>
+DatabaseContext::getNonDeprecated(const std::string &tableName,
+ const std::string &authName,
+ const std::string &code) const {
+ auto sqlRes =
+ d->run("SELECT replacement_auth_name, replacement_code, source "
+ "FROM deprecation "
+ "WHERE table_name = ? AND deprecated_auth_name = ? "
+ "AND deprecated_code = ?",
+ {tableName, authName, code});
+ std::list<std::pair<std::string, std::string>> res;
+ for (const auto &row : sqlRes) {
+ const auto &source = row[2];
+ if (source == "PROJ") {
+ const auto &replacement_auth_name = row[0];
+ const auto &replacement_code = row[1];
+ res.emplace_back(replacement_auth_name, replacement_code);
+ }
+ }
+ if (!res.empty()) {
+ return res;
+ }
+ for (const auto &row : sqlRes) {
+ const auto &replacement_auth_name = row[0];
+ const auto &replacement_code = row[1];
+ res.emplace_back(replacement_auth_name, replacement_code);
+ }
+ return res;
}
//! @endcond
@@ -904,24 +1166,12 @@ struct AuthorityFactory::Private {
// cppcheck-suppress functionStatic
AuthorityFactoryPtr getSharedFromThis() { return thisFactory_.lock(); }
- AuthorityFactoryNNPtr createFactory(const std::string &auth_name);
-
- // cppcheck-suppress functionStatic
- common::UnitOfMeasurePtr getUOMFromCache(const std::string &code);
- // cppcheck-suppress functionStatic
- void cache(const std::string &code, const common::UnitOfMeasureNNPtr &uom);
-
- // cppcheck-suppress functionStatic
- crs::CRSPtr getCRSFromCache(const std::string &code);
- // cppcheck-suppress functionStatic
- void cache(const std::string &code, const crs::CRSNNPtr &crs);
-
- datum::GeodeticReferenceFramePtr
- // cppcheck-suppress functionStatic
- getGeodeticDatumFromCache(const std::string &code);
- // cppcheck-suppress functionStatic
- void cache(const std::string &code,
- const datum::GeodeticReferenceFrameNNPtr &datum);
+ inline AuthorityFactoryNNPtr createFactory(const std::string &auth_name) {
+ if (auth_name == authority_) {
+ return NN_NO_CHECK(thisFactory_.lock());
+ }
+ return AuthorityFactory::create(context_, auth_name);
+ }
bool rejectOpDueToMissingGrid(const operation::CoordinateOperationNNPtr &op,
bool discardIfMissingGrid);
@@ -938,69 +1188,28 @@ struct AuthorityFactory::Private {
const std::string &area_of_use_auth_name,
const std::string &area_of_use_code);
- SQLResultSet
- run(const std::string &sql,
- const std::vector<SQLValues> &parameters = std::vector<SQLValues>());
+ SQLResultSet run(const std::string &sql,
+ const ListOfParams &parameters = ListOfParams());
SQLResultSet runWithCodeParam(const std::string &sql,
const std::string &code);
SQLResultSet runWithCodeParam(const char *sql, const std::string &code);
+ bool hasAuthorityRestriction() const {
+ return !authority_.empty() && authority_ != "any";
+ }
+
private:
DatabaseContextNNPtr context_;
std::string authority_;
std::weak_ptr<AuthorityFactory> thisFactory_{};
- std::weak_ptr<AuthorityFactory> parentFactory_{};
- std::map<std::string, AuthorityFactoryNNPtr> mapFactory_{};
- lru11::Cache<std::string, util::BaseObjectPtr> cacheUOM_{};
- lru11::Cache<std::string, util::BaseObjectPtr> cacheCRS_{};
- lru11::Cache<std::string, util::BaseObjectPtr> cacheGeodeticDatum_{};
-
- static void
- insertIntoCache(lru11::Cache<std::string, util::BaseObjectPtr> &cache,
- const std::string &code, const util::BaseObjectPtr &obj);
-
- static void
- getFromCache(lru11::Cache<std::string, util::BaseObjectPtr> &cache,
- const std::string &code, util::BaseObjectPtr &obj);
};
// ---------------------------------------------------------------------------
-AuthorityFactoryNNPtr
-AuthorityFactory::Private::createFactory(const std::string &auth_name) {
-
- // If we are a child factory, then create new factory on the parent
- auto parentFactoryLocked(parentFactory_.lock());
- if (parentFactoryLocked) {
- return parentFactoryLocked->d->createFactory(auth_name);
- }
-
- // If asked for a factory with our name, return ourselves.
- auto lockedThisFactory(thisFactory_.lock());
- assert(lockedThisFactory);
- if (auth_name == lockedThisFactory->getAuthority()) {
- return NN_NO_CHECK(lockedThisFactory);
- }
-
- // Find if there is already a child factory with the passed name.
- auto iter = mapFactory_.find(auth_name);
- if (iter == mapFactory_.end()) {
- auto newFactory = AuthorityFactory::create(context_, auth_name);
- newFactory->d->parentFactory_ = thisFactory_;
- mapFactory_.insert(std::pair<std::string, AuthorityFactoryNNPtr>(
- auth_name, newFactory));
- return newFactory;
- }
- return iter->second;
-}
-
-// ---------------------------------------------------------------------------
-
-SQLResultSet
-AuthorityFactory::Private::run(const std::string &sql,
- const std::vector<SQLValues> &parameters) {
+SQLResultSet AuthorityFactory::Private::run(const std::string &sql,
+ const ListOfParams &parameters) {
return context()->getPrivate()->run(sql, parameters);
}
@@ -1036,8 +1245,10 @@ util::PropertyMap AuthorityFactory::Private::createProperties(
auto props = util::PropertyMap()
.set(metadata::Identifier::CODESPACE_KEY, authority())
.set(metadata::Identifier::CODE_KEY, code)
- .set(common::IdentifiedObject::NAME_KEY, name)
- .set(common::IdentifiedObject::DEPRECATED_KEY, deprecated);
+ .set(common::IdentifiedObject::NAME_KEY, name);
+ if (deprecated) {
+ props.set(common::IdentifiedObject::DEPRECATED_KEY, true);
+ }
if (extent) {
props.set(
common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY,
@@ -1062,70 +1273,6 @@ util::PropertyMap AuthorityFactory::Private::createProperties(
// ---------------------------------------------------------------------------
-void AuthorityFactory::Private::insertIntoCache(
- lru11::Cache<std::string, util::BaseObjectPtr> &cache,
- const std::string &code, const util::BaseObjectPtr &obj) {
- cache.insert(code, obj);
-}
-
-// ---------------------------------------------------------------------------
-
-void AuthorityFactory::Private::getFromCache(
- lru11::Cache<std::string, util::BaseObjectPtr> &cache,
- const std::string &code, util::BaseObjectPtr &obj) {
- cache.tryGet(code, obj);
-}
-
-// ---------------------------------------------------------------------------
-
-crs::CRSPtr
-AuthorityFactory::Private::getCRSFromCache(const std::string &code) {
- util::BaseObjectPtr obj;
- getFromCache(cacheCRS_, code, obj);
- return std::static_pointer_cast<crs::CRS>(obj);
-}
-
-// ---------------------------------------------------------------------------
-
-void AuthorityFactory::Private::cache(const std::string &code,
- const crs::CRSNNPtr &crs) {
- insertIntoCache(cacheCRS_, code, crs.as_nullable());
-}
-
-// ---------------------------------------------------------------------------
-
-common::UnitOfMeasurePtr
-AuthorityFactory::Private::getUOMFromCache(const std::string &code) {
- util::BaseObjectPtr obj;
- getFromCache(cacheUOM_, code, obj);
- return std::static_pointer_cast<common::UnitOfMeasure>(obj);
-}
-
-// ---------------------------------------------------------------------------
-
-void AuthorityFactory::Private::cache(const std::string &code,
- const common::UnitOfMeasureNNPtr &uom) {
- insertIntoCache(cacheUOM_, code, uom.as_nullable());
-}
-
-// ---------------------------------------------------------------------------
-
-datum::GeodeticReferenceFramePtr
-AuthorityFactory::Private::getGeodeticDatumFromCache(const std::string &code) {
- util::BaseObjectPtr obj;
- getFromCache(cacheGeodeticDatum_, code, obj);
- return std::static_pointer_cast<datum::GeodeticReferenceFrame>(obj);
-}
-
-// ---------------------------------------------------------------------------
-
-void AuthorityFactory::Private::cache(
- const std::string &code, const datum::GeodeticReferenceFrameNNPtr &datum) {
- insertIntoCache(cacheGeodeticDatum_, code, datum.as_nullable());
-}
-
-// ---------------------------------------------------------------------------
-
bool AuthorityFactory::Private::rejectOpDueToMissingGrid(
const operation::CoordinateOperationNNPtr &op, bool discardIfMissingGrid) {
if (discardIfMissingGrid) {
@@ -1170,6 +1317,7 @@ AuthorityFactory::AuthorityFactory(const DatabaseContextNNPtr &context,
AuthorityFactoryNNPtr
AuthorityFactory::create(const DatabaseContextNNPtr &context,
const std::string &authorityName) {
+
auto factory = AuthorityFactory::nn_make_shared<AuthorityFactory>(
context, authorityName);
factory->d->setThis(factory);
@@ -1210,7 +1358,7 @@ AuthorityFactory::createObject(const std::string &code) const {
"SELECT table_name FROM object_view WHERE auth_name = ? AND code = ?",
code);
if (res.empty()) {
- throw NoSuchAuthorityCodeException("not found", getAuthority(), code);
+ throw NoSuchAuthorityCodeException("not found", d->authority(), code);
}
if (res.size() != 1) {
std::string msg(
@@ -1224,7 +1372,7 @@ AuthorityFactory::createObject(const std::string &code) const {
}
throw FactoryException(msg);
}
- const auto &table_name = res[0][0];
+ const auto &table_name = res.front()[0];
if (table_name == "area") {
return util::nn_static_pointer_cast<util::BaseObject>(
createExtent(code));
@@ -1276,7 +1424,7 @@ AuthorityFactory::createObject(const std::string &code) const {
return util::nn_static_pointer_cast<util::BaseObject>(
createCoordinateOperation(code, false));
}
- throw FactoryException("unimplemented factory for " + res[0][0]);
+ throw FactoryException("unimplemented factory for " + res.front()[0]);
}
// ---------------------------------------------------------------------------
@@ -1302,15 +1450,22 @@ static FactoryException buildFactoryException(const char *type,
metadata::ExtentNNPtr
AuthorityFactory::createExtent(const std::string &code) const {
+ const auto cacheKey(d->authority() + code);
+ {
+ auto extent = d->context()->d->getExtentFromCache(cacheKey);
+ if (extent) {
+ return NN_NO_CHECK(extent);
+ }
+ }
auto sql = "SELECT name, south_lat, north_lat, west_lon, east_lon, "
"deprecated FROM area WHERE auth_name = ? AND code = ?";
auto res = d->runWithCodeParam(sql, code);
if (res.empty()) {
- throw NoSuchAuthorityCodeException("area not found", getAuthority(),
+ throw NoSuchAuthorityCodeException("area not found", d->authority(),
code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
double south_lat = c_locale_stod(row[1]);
double north_lat = c_locale_stod(row[2]);
@@ -1319,11 +1474,13 @@ AuthorityFactory::createExtent(const std::string &code) const {
auto bbox = metadata::GeographicBoundingBox::create(
west_lon, south_lat, east_lon, north_lat);
- return metadata::Extent::create(
+ auto extent = metadata::Extent::create(
util::optional<std::string>(name),
std::vector<metadata::GeographicExtentNNPtr>{bbox},
std::vector<metadata::VerticalExtentNNPtr>(),
std::vector<metadata::TemporalExtentNNPtr>());
+ d->context()->d->cache(code, extent);
+ return extent;
} catch (const std::exception &ex) {
throw buildFactoryException("area", code, ex);
@@ -1342,8 +1499,9 @@ AuthorityFactory::createExtent(const std::string &code) const {
UnitOfMeasureNNPtr
AuthorityFactory::createUnitOfMeasure(const std::string &code) const {
+ const auto cacheKey(d->authority() + code);
{
- auto uom = d->getUOMFromCache(code);
+ auto uom = d->context()->d->getUOMFromCache(cacheKey);
if (uom) {
return NN_NO_CHECK(uom);
}
@@ -1354,10 +1512,10 @@ AuthorityFactory::createUnitOfMeasure(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("unit of measure not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name =
(row[0] == "degree (supplier to define representation)")
? UnitOfMeasure::DEGREE.name()
@@ -1386,8 +1544,8 @@ AuthorityFactory::createUnitOfMeasure(const std::string &code) const {
else if (type_str == "time")
unitType = UnitOfMeasure::Type::TIME;
auto uom = util::nn_make_shared<UnitOfMeasure>(
- name, conv_factor, unitType, getAuthority(), code);
- d->cache(code, uom);
+ name, conv_factor, unitType, d->authority(), code);
+ d->context()->d->cache(cacheKey, uom);
return uom;
} catch (const std::exception &ex) {
throw buildFactoryException("unit of measure", code, ex);
@@ -1397,14 +1555,12 @@ AuthorityFactory::createUnitOfMeasure(const std::string &code) const {
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
-static void normalizeMeasure(const std::string &uom_code,
- const std::string &value,
- std::string &normalized_uom_code,
- double &normalized_value) {
- normalized_uom_code = uom_code;
- normalized_value = c_locale_stod(value);
+static double normalizeMeasure(const std::string &uom_code,
+ const std::string &value,
+ std::string &normalized_uom_code) {
if (uom_code == "9110") // DDD.MMSSsss.....
{
+ double normalized_value = c_locale_stod(value);
std::ostringstream buffer;
buffer.imbue(std::locale::classic());
constexpr size_t precision = 12;
@@ -1422,6 +1578,10 @@ static void normalizeMeasure(const std::string &uom_code,
(c_locale_stod(seconds) / std::pow(10, seconds.size() - 2)) /
3600.);
normalized_uom_code = common::UnitOfMeasure::DEGREE.code();
+ return normalized_value;
+ } else {
+ normalized_uom_code = uom_code;
+ return c_locale_stod(value);
}
}
//! @endcond
@@ -1438,6 +1598,13 @@ static void normalizeMeasure(const std::string &uom_code,
datum::PrimeMeridianNNPtr
AuthorityFactory::createPrimeMeridian(const std::string &code) const {
+ const auto cacheKey(d->authority() + code);
+ {
+ auto pm = d->context()->d->getPrimeMeridianFromCache(cacheKey);
+ if (pm) {
+ return NN_NO_CHECK(pm);
+ }
+ }
auto res = d->runWithCodeParam(
"SELECT name, longitude, uom_auth_name, uom_code, deprecated FROM "
"prime_meridian WHERE "
@@ -1445,10 +1612,10 @@ AuthorityFactory::createPrimeMeridian(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("prime meridian not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &longitude = row[1];
const auto &uom_auth_name = row[2];
@@ -1456,14 +1623,15 @@ AuthorityFactory::createPrimeMeridian(const std::string &code) const {
const bool deprecated = row[4] == "1";
std::string normalized_uom_code(uom_code);
- double normalized_value(c_locale_stod(longitude));
- normalizeMeasure(uom_code, longitude, normalized_uom_code,
- normalized_value);
+ const double normalized_value =
+ normalizeMeasure(uom_code, longitude, normalized_uom_code);
auto uom = d->createUnitOfMeasure(uom_auth_name, normalized_uom_code);
auto props = d->createProperties(code, name, deprecated, nullptr);
- return datum::PrimeMeridian::create(
+ auto pm = datum::PrimeMeridian::create(
props, common::Angle(normalized_value, uom));
+ d->context()->d->cache(cacheKey, pm);
+ return pm;
} catch (const std::exception &ex) {
throw buildFactoryException("prime meridian", code, ex);
}
@@ -1492,7 +1660,7 @@ AuthorityFactory::identifyBodyFromSemiMajorAxis(double semi_major_axis,
if (res.size() > 1) {
throw FactoryException("more than one match found");
}
- return res[0][0];
+ return res.front()[0];
}
// ---------------------------------------------------------------------------
@@ -1519,10 +1687,10 @@ AuthorityFactory::createEllipsoid(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("ellipsoid not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &semi_major_axis_str = row[1];
double semi_major_axis = c_locale_stod(semi_major_axis_str);
@@ -1563,8 +1731,9 @@ AuthorityFactory::createEllipsoid(const std::string &code) const {
datum::GeodeticReferenceFrameNNPtr
AuthorityFactory::createGeodeticDatum(const std::string &code) const {
+ const auto cacheKey(d->authority() + code);
{
- auto datum = d->getGeodeticDatumFromCache(code);
+ auto datum = d->context()->d->getGeodeticDatumFromCache(cacheKey);
if (datum) {
return NN_NO_CHECK(datum);
}
@@ -1577,10 +1746,10 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("geodetic datum not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &ellipsoid_auth_name = row[1];
const auto &ellipsoid_code = row[2];
@@ -1598,7 +1767,7 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const {
auto anchor = util::optional<std::string>();
auto datum =
datum::GeodeticReferenceFrame::create(props, ellipsoid, anchor, pm);
- d->cache(code, datum);
+ d->context()->d->cache(cacheKey, datum);
return datum;
} catch (const std::exception &ex) {
throw buildFactoryException("geodetic reference frame", code, ex);
@@ -1623,10 +1792,10 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("vertical datum not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &area_of_use_auth_name = row[1];
const auto &area_of_use_code = row[2];
@@ -1656,12 +1825,12 @@ datum::DatumNNPtr AuthorityFactory::createDatum(const std::string &code) const {
"auth_name = ? AND code = ? "
"UNION ALL SELECT 'vertical_datum' FROM vertical_datum WHERE "
"auth_name = ? AND code = ?",
- {getAuthority(), code, getAuthority(), code});
+ {d->authority(), code, d->authority(), code});
if (res.empty()) {
- throw NoSuchAuthorityCodeException("datum not found", getAuthority(),
+ throw NoSuchAuthorityCodeException("datum not found", d->authority(),
code);
}
- if (res[0][0] == "geodetic_datum") {
+ if (res.front()[0] == "geodetic_datum") {
return createGeodeticDatum(code);
}
return createVerticalDatum(code);
@@ -1700,6 +1869,13 @@ static cs::MeridianPtr createMeridian(const std::string &val) {
cs::CoordinateSystemNNPtr
AuthorityFactory::createCoordinateSystem(const std::string &code) const {
+ const auto cacheKey(d->authority() + code);
+ {
+ auto cs = d->context()->d->getCoordinateSystemFromCache(cacheKey);
+ if (cs) {
+ return NN_NO_CHECK(cs);
+ }
+ }
auto res = d->runWithCodeParam(
"SELECT axis.name, abbrev, orientation, uom_auth_name, uom_code, "
"cs.type FROM "
@@ -1711,10 +1887,10 @@ AuthorityFactory::createCoordinateSystem(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("coordinate system not found",
- getAuthority(), code);
+ d->authority(), code);
}
- const auto &csType = res[0][5];
+ const auto &csType = res.front()[5];
std::vector<cs::CoordinateSystemAxisNNPtr> axisList;
for (const auto &row : res) {
const auto &name = row[0];
@@ -1755,32 +1931,41 @@ AuthorityFactory::createCoordinateSystem(const std::string &code) const {
axisList.emplace_back(cs::CoordinateSystemAxis::create(
props, abbrev, *direction, uom, meridian));
}
+
+ const auto cacheAndRet = [this,
+ &cacheKey](const cs::CoordinateSystemNNPtr &cs) {
+ d->context()->d->cache(cacheKey, cs);
+ return cs;
+ };
+
auto props = util::PropertyMap()
- .set(metadata::Identifier::CODESPACE_KEY, getAuthority())
+ .set(metadata::Identifier::CODESPACE_KEY, d->authority())
.set(metadata::Identifier::CODE_KEY, code);
if (csType == "ellipsoidal") {
if (axisList.size() == 2) {
- return cs::EllipsoidalCS::create(props, axisList[0], axisList[1]);
+ return cacheAndRet(
+ cs::EllipsoidalCS::create(props, axisList[0], axisList[1]));
}
if (axisList.size() == 3) {
- return cs::EllipsoidalCS::create(props, axisList[0], axisList[1],
- axisList[2]);
+ return cacheAndRet(cs::EllipsoidalCS::create(
+ props, axisList[0], axisList[1], axisList[2]));
}
throw FactoryException("invalid number of axis for EllipsoidalCS");
}
if (csType == "Cartesian") {
if (axisList.size() == 2) {
- return cs::CartesianCS::create(props, axisList[0], axisList[1]);
+ return cacheAndRet(
+ cs::CartesianCS::create(props, axisList[0], axisList[1]));
}
if (axisList.size() == 3) {
- return cs::CartesianCS::create(props, axisList[0], axisList[1],
- axisList[2]);
+ return cacheAndRet(cs::CartesianCS::create(
+ props, axisList[0], axisList[1], axisList[2]));
}
throw FactoryException("invalid number of axis for CartesianCS");
}
if (csType == "vertical") {
if (axisList.size() == 1) {
- return cs::VerticalCS::create(props, axisList[0]);
+ return cacheAndRet(cs::VerticalCS::create(props, axisList[0]));
}
throw FactoryException("invalid number of axis for VerticalCS");
}
@@ -1846,8 +2031,9 @@ cloneWithProps(const crs::GeodeticCRSNNPtr &geodCRS,
crs::GeodeticCRSNNPtr
AuthorityFactory::createGeodeticCRS(const std::string &code,
bool geographicOnly) const {
- auto crs =
- std::dynamic_pointer_cast<crs::GeodeticCRS>(d->getCRSFromCache(code));
+ const auto cacheKey(d->authority() + code);
+ auto crs = std::dynamic_pointer_cast<crs::GeodeticCRS>(
+ d->context()->d->getCRSFromCache(cacheKey));
if (crs) {
return NN_NO_CHECK(crs);
}
@@ -1862,10 +2048,10 @@ AuthorityFactory::createGeodeticCRS(const std::string &code,
auto res = d->runWithCodeParam(sql, code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("geodeticCRS not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &type = row[1];
const auto &cs_auth_name = row[2];
@@ -1917,14 +2103,14 @@ AuthorityFactory::createGeodeticCRS(const std::string &code,
ellipsoidalCS) {
auto crsRet = crs::GeographicCRS::create(
props, datum, NN_NO_CHECK(ellipsoidalCS));
- d->cache(code, crsRet);
+ d->context()->d->cache(cacheKey, crsRet);
return crsRet;
}
auto geocentricCS = util::nn_dynamic_pointer_cast<cs::CartesianCS>(cs);
if (type == "geocentric" && geocentricCS) {
auto crsRet = crs::GeodeticCRS::create(props, datum,
NN_NO_CHECK(geocentricCS));
- d->cache(code, crsRet);
+ d->context()->d->cache(cacheKey, crsRet);
return crsRet;
}
throw FactoryException("unsupported (type, CS type) for geodeticCRS: " +
@@ -1954,10 +2140,10 @@ AuthorityFactory::createVerticalCRS(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("verticalCRS not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &cs_auth_name = row[1];
const auto &cs_code = row[2];
@@ -1998,28 +2184,41 @@ AuthorityFactory::createVerticalCRS(const std::string &code) const {
operation::ConversionNNPtr
AuthorityFactory::createConversion(const std::string &code) const {
- std::ostringstream buffer;
- buffer.imbue(std::locale::classic());
- buffer << "SELECT name, area_of_use_auth_name, area_of_use_code, "
- "method_auth_name, method_code, method_name";
- constexpr int N_MAX_PARAMS = 7;
- for (int i = 1; i <= N_MAX_PARAMS; ++i) {
- buffer << ", param" << i << "_auth_name";
- buffer << ", param" << i << "_code";
- buffer << ", param" << i << "_name";
- buffer << ", param" << i << "_value";
- buffer << ", param" << i << "_uom_auth_name";
- buffer << ", param" << i << "_uom_code";
- }
- buffer << ", deprecated FROM conversion WHERE auth_name = ? AND code = ?";
-
- auto res = d->runWithCodeParam(buffer.str(), code);
+
+ static const char *sql =
+ "SELECT name, area_of_use_auth_name, area_of_use_code, "
+ "method_auth_name, method_code, method_name, "
+
+ "param1_auth_name, param1_code, param1_name, param1_value, "
+ "param1_uom_auth_name, param1_uom_code, "
+
+ "param2_auth_name, param2_code, param2_name, param2_value, "
+ "param2_uom_auth_name, param2_uom_code, "
+
+ "param3_auth_name, param3_code, param3_name, param3_value, "
+ "param3_uom_auth_name, param3_uom_code, "
+
+ "param4_auth_name, param4_code, param4_name, param4_value, "
+ "param4_uom_auth_name, param4_uom_code, "
+
+ "param5_auth_name, param5_code, param5_name, param5_value, "
+ "param5_uom_auth_name, param5_uom_code, "
+
+ "param6_auth_name, param6_code, param6_name, param6_value, "
+ "param6_uom_auth_name, param6_uom_code, "
+
+ "param7_auth_name, param7_code, param7_name, param7_value, "
+ "param7_uom_auth_name, param7_uom_code, "
+
+ "deprecated FROM conversion WHERE auth_name = ? AND code = ?";
+
+ auto res = d->runWithCodeParam(sql, code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("conversion not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
size_t idx = 0;
const auto &name = row[idx++];
const auto &area_of_use_auth_name = row[idx++];
@@ -2030,6 +2229,7 @@ AuthorityFactory::createConversion(const std::string &code) const {
const size_t base_param_idx = idx;
std::vector<operation::OperationParameterNNPtr> parameters;
std::vector<operation::ParameterValueNNPtr> values;
+ constexpr int N_MAX_PARAMS = 7;
for (int i = 0; i < N_MAX_PARAMS; ++i) {
const auto &param_auth_name = row[base_param_idx + i * 6 + 0];
if (param_auth_name.empty()) {
@@ -2046,9 +2246,8 @@ AuthorityFactory::createConversion(const std::string &code) const {
.set(metadata::Identifier::CODE_KEY, param_code)
.set(common::IdentifiedObject::NAME_KEY, param_name)));
std::string normalized_uom_code(param_uom_code);
- double normalized_value(c_locale_stod(param_value));
- normalizeMeasure(param_uom_code, param_value, normalized_uom_code,
- normalized_value);
+ const double normalized_value = normalizeMeasure(
+ param_uom_code, param_value, normalized_uom_code);
auto uom = d->createUnitOfMeasure(param_uom_auth_name,
normalized_uom_code);
values.emplace_back(operation::ParameterValue::create(
@@ -2095,10 +2294,10 @@ AuthorityFactory::createProjectedCRS(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("projectedCRS not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &cs_auth_name = row[1];
const auto &cs_code = row[2];
@@ -2194,10 +2393,10 @@ AuthorityFactory::createCompoundCRS(const std::string &code) const {
code);
if (res.empty()) {
throw NoSuchAuthorityCodeException("compoundCRS not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
const auto &name = row[0];
const auto &horiz_crs_auth_name = row[1];
const auto &horiz_crs_code = row[2];
@@ -2240,17 +2439,18 @@ crs::CRSNNPtr AuthorityFactory::createCoordinateReferenceSystem(
crs::CRSNNPtr
AuthorityFactory::createCoordinateReferenceSystem(const std::string &code,
bool allowCompound) const {
- auto crs = d->getCRSFromCache(code);
+ const auto cacheKey(d->authority() + code);
+ auto crs = d->context()->d->getCRSFromCache(cacheKey);
if (crs) {
return NN_NO_CHECK(crs);
}
auto res = d->runWithCodeParam(
"SELECT type FROM crs_view WHERE auth_name = ? AND code = ?", code);
if (res.empty()) {
- throw NoSuchAuthorityCodeException("crs not found", getAuthority(),
+ throw NoSuchAuthorityCodeException("crs not found", d->authority(),
code);
}
- const auto &type = res[0][0];
+ const auto &type = res.front()[0];
if (type == "geographic 2D" || type == "geographic 3D" ||
type == "geocentric") {
return createGeodeticCRS(code);
@@ -2315,28 +2515,33 @@ static operation::ParameterValueNNPtr createAngle(const std::string &value,
operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
const std::string &code, bool usePROJAlternativeGridNames) const {
- return createCoordinateOperation(code, true, usePROJAlternativeGridNames);
+ return createCoordinateOperation(code, true, usePROJAlternativeGridNames,
+ std::string());
}
operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
const std::string &code, bool allowConcatenated,
- bool usePROJAlternativeGridNames) const {
- auto res = d->runWithCodeParam(
- "SELECT type FROM coordinate_operation_with_conversion_view "
- "WHERE auth_name = ? AND code = ?",
- code);
- if (res.empty()) {
- throw NoSuchAuthorityCodeException("coordinate operation not found",
- getAuthority(), code);
+ bool usePROJAlternativeGridNames, const std::string &typeIn) const {
+ std::string type(typeIn);
+ if (type.empty()) {
+ auto res = d->runWithCodeParam(
+ "SELECT type FROM coordinate_operation_with_conversion_view "
+ "WHERE auth_name = ? AND code = ?",
+ code);
+ if (res.empty()) {
+ throw NoSuchAuthorityCodeException("coordinate operation not found",
+ d->authority(), code);
+ }
+ type = res.front()[0];
}
- const auto type = res[0][0];
+
if (type == "conversion") {
return createConversion(code);
}
if (type == "helmert_transformation") {
- res = d->runWithCodeParam(
+ auto res = d->runWithCodeParam(
"SELECT name, method_auth_name, method_code, method_name, "
"source_crs_auth_name, source_crs_code, target_crs_auth_name, "
"target_crs_code, area_of_use_auth_name, area_of_use_code, "
@@ -2356,10 +2561,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
if (res.empty()) {
// shouldn't happen if foreign keys are OK
throw NoSuchAuthorityCodeException(
- "helmert_transformation not found", getAuthority(), code);
+ "helmert_transformation not found", d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
size_t idx = 0;
const auto &name = row[idx++];
const auto &method_auth_name = row[idx++];
@@ -2573,7 +2778,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
}
if (type == "grid_transformation") {
- res = d->runWithCodeParam(
+ auto res = d->runWithCodeParam(
"SELECT name, method_auth_name, method_code, method_name, "
"source_crs_auth_name, source_crs_code, target_crs_auth_name, "
"target_crs_code, area_of_use_auth_name, area_of_use_code, "
@@ -2588,10 +2793,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
if (res.empty()) {
// shouldn't happen if foreign keys are OK
throw NoSuchAuthorityCodeException("grid_transformation not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
size_t idx = 0;
const auto &name = row[idx++];
const auto &method_auth_name = row[idx++];
@@ -2704,14 +2909,14 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
buffer << ", deprecated FROM other_transformation WHERE auth_name = ? "
"AND code = ?";
- res = d->runWithCodeParam(buffer.str(), code);
+ auto res = d->runWithCodeParam(buffer.str(), code);
if (res.empty()) {
// shouldn't happen if foreign keys are OK
throw NoSuchAuthorityCodeException("other_transformation not found",
- getAuthority(), code);
+ d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
size_t idx = 0;
const auto &name = row[idx++];
const auto &method_auth_name = row[idx++];
@@ -2746,9 +2951,8 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
.set(metadata::Identifier::CODE_KEY, param_code)
.set(common::IdentifiedObject::NAME_KEY, param_name)));
std::string normalized_uom_code(param_uom_code);
- double normalized_value(c_locale_stod(param_value));
- normalizeMeasure(param_uom_code, param_value,
- normalized_uom_code, normalized_value);
+ const double normalized_value = normalizeMeasure(
+ param_uom_code, param_value, normalized_uom_code);
auto uom = d->createUnitOfMeasure(param_uom_auth_name,
normalized_uom_code);
values.emplace_back(operation::ParameterValue::create(
@@ -2818,7 +3022,7 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
}
if (allowConcatenated && type == "concatenated_operation") {
- res = d->runWithCodeParam(
+ auto res = d->runWithCodeParam(
"SELECT name, source_crs_auth_name, source_crs_code, "
"target_crs_auth_name, target_crs_code, "
"area_of_use_auth_name, area_of_use_code, accuracy, "
@@ -2829,10 +3033,10 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
if (res.empty()) {
// shouldn't happen if foreign keys are OK
throw NoSuchAuthorityCodeException(
- "concatenated_operation not found", getAuthority(), code);
+ "concatenated_operation not found", d->authority(), code);
}
try {
- const auto &row = res[0];
+ const auto &row = res.front();
size_t idx = 0;
const auto &name = row[idx++];
const auto &source_crs_auth_name = row[idx++];
@@ -2855,17 +3059,20 @@ operation::CoordinateOperationNNPtr AuthorityFactory::createCoordinateOperation(
operations.push_back(
d->createFactory(step1_auth_name)
->createCoordinateOperation(step1_code, false,
- usePROJAlternativeGridNames));
+ usePROJAlternativeGridNames,
+ std::string()));
operations.push_back(
d->createFactory(step2_auth_name)
->createCoordinateOperation(step2_code, false,
- usePROJAlternativeGridNames));
+ usePROJAlternativeGridNames,
+ std::string()));
if (!step3_auth_name.empty()) {
operations.push_back(
d->createFactory(step3_auth_name)
- ->createCoordinateOperation(
- step3_code, false, usePROJAlternativeGridNames));
+ ->createCoordinateOperation(step3_code, false,
+ usePROJAlternativeGridNames,
+ std::string()));
}
// In case the operation is a conversion (we hope this is the
@@ -3045,7 +3252,7 @@ std::vector<operation::CoordinateOperationNNPtr>
AuthorityFactory::createFromCoordinateReferenceSystemCodes(
const std::string &sourceCRSCode, const std::string &targetCRSCode) const {
return createFromCoordinateReferenceSystemCodes(
- getAuthority(), sourceCRSCode, getAuthority(), targetCRSCode, false,
+ d->authority(), sourceCRSCode, d->authority(), targetCRSCode, false,
false, false);
}
@@ -3088,29 +3295,45 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes(
const std::string &targetCRSAuthName, const std::string &targetCRSCode,
bool usePROJAlternativeGridNames, bool discardIfMissingGrid,
bool discardSuperseded) const {
+
+ auto cacheKey(d->authority());
+ cacheKey += sourceCRSAuthName;
+ cacheKey += sourceCRSCode;
+ cacheKey += targetCRSAuthName;
+ cacheKey += targetCRSCode;
+ cacheKey += (usePROJAlternativeGridNames ? '1' : '0');
+ cacheKey += (discardIfMissingGrid ? '1' : '0');
+ cacheKey += (discardSuperseded ? '1' : '0');
+
std::vector<operation::CoordinateOperationNNPtr> list;
- // Look-up first for conversion which is the most precise.
- std::string sql(
- "SELECT conversion_auth_name, conversion_code FROM "
- "projected_crs WHERE geodetic_crs_auth_name = ? AND geodetic_crs_code "
- "= ? AND auth_name = ? AND code = ? AND deprecated != 1");
- auto params = std::vector<SQLValues>{sourceCRSAuthName, sourceCRSCode,
- targetCRSAuthName, targetCRSCode};
- if (!getAuthority().empty()) {
- sql += " AND conversion_auth_name = ?";
- params.emplace_back(getAuthority());
+ if (d->context()->d->getCRSToCRSCoordOpFromCache(cacheKey, list)) {
+ return list;
}
+
+ // Look-up first for conversion which is the most precise.
+ std::string sql("SELECT conversion_auth_name, "
+ "geodetic_crs_auth_name, geodetic_crs_code FROM "
+ "projected_crs WHERE auth_name = ? AND code = ?");
+ auto params = ListOfParams{targetCRSAuthName, targetCRSCode};
auto res = d->run(sql, params);
if (!res.empty()) {
- auto targetCRS = d->createFactory(targetCRSAuthName)
- ->createProjectedCRS(targetCRSCode);
- auto conv = targetCRS->derivingConversion();
- list.emplace_back(conv);
- return list;
+ const auto &row = res.front();
+ bool ok = row[1] == sourceCRSAuthName && row[2] == sourceCRSCode;
+ if (ok && d->hasAuthorityRestriction()) {
+ ok = row[0] == d->authority();
+ }
+ if (ok) {
+ auto targetCRS = d->createFactory(targetCRSAuthName)
+ ->createProjectedCRS(targetCRSCode);
+ auto conv = targetCRS->derivingConversion();
+ list.emplace_back(conv);
+ d->context()->d->cache(cacheKey, list);
+ return list;
+ }
}
if (discardSuperseded) {
- sql = "SELECT cov.auth_name, cov.code, "
+ sql = "SELECT cov.auth_name, cov.code, cov.table_name, "
"ss.replacement_auth_name, ss.replacement_code FROM "
"coordinate_operation_view cov JOIN area "
"ON cov.area_of_use_auth_name = area.auth_name AND "
@@ -3122,21 +3345,21 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes(
"ss.superseded_table_name = ss.replacement_table_name "
"WHERE source_crs_auth_name = ? AND source_crs_code = ? AND "
"target_crs_auth_name = ? AND target_crs_code = ? AND "
- "cov.deprecated != 1";
+ "cov.deprecated = 0";
} else {
- sql = "SELECT cov.auth_name, cov.code FROM "
+ sql = "SELECT cov.auth_name, cov.code, cov.table_name FROM "
"coordinate_operation_view cov JOIN area "
"ON cov.area_of_use_auth_name = area.auth_name AND "
"cov.area_of_use_code = area.code "
"WHERE source_crs_auth_name = ? AND source_crs_code = ? AND "
"target_crs_auth_name = ? AND target_crs_code = ? AND "
- "cov.deprecated != 1";
+ "cov.deprecated = 0";
}
params = {sourceCRSAuthName, sourceCRSCode, targetCRSAuthName,
targetCRSCode};
- if (!getAuthority().empty()) {
+ if (d->hasAuthorityRestriction()) {
sql += " AND cov.auth_name = ?";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
sql += " ORDER BY pseudo_area_from_swne(south_lat, west_lon, north_lat, "
"east_lon) DESC, "
@@ -3153,8 +3376,8 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes(
}
for (const auto &row : res) {
if (discardSuperseded) {
- const auto &replacement_auth_name = row[2];
- const auto &replacement_code = row[3];
+ const auto &replacement_auth_name = row[3];
+ const auto &replacement_code = row[4];
if (!replacement_auth_name.empty() &&
setTransf.find(std::pair<std::string, std::string>(
replacement_auth_name, replacement_code)) !=
@@ -3167,12 +3390,14 @@ AuthorityFactory::createFromCoordinateReferenceSystemCodes(
const auto &auth_name = row[0];
const auto &code = row[1];
+ const auto &table_name = row[2];
auto op = d->createFactory(auth_name)->createCoordinateOperation(
- code, true, usePROJAlternativeGridNames);
+ code, true, usePROJAlternativeGridNames, table_name);
if (!d->rejectOpDueToMissingGrid(op, discardIfMissingGrid)) {
list.emplace_back(op);
}
}
+ d->context()->d->cache(cacheKey, list);
return list;
}
@@ -3290,8 +3515,10 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
discardSuperseded
?
- "SELECT v1.auth_name AS auth_name1, v1.code AS code1, "
+ "SELECT v1.table_name as table1, "
+ "v1.auth_name AS auth_name1, v1.code AS code1, "
"v1.accuracy AS accuracy1, "
+ "v2.table_name as table2, "
"v2.auth_name AS auth_name2, v2.code AS code2, "
"v2.accuracy as accuracy2, "
"a1.south_lat AS south_lat1, "
@@ -3310,8 +3537,10 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
"JOIN coordinate_operation_view v2 "
:
- "SELECT v1.auth_name AS auth_name1, v1.code AS code1, "
+ "SELECT v1.table_name as table1, "
+ "v1.auth_name AS auth_name1, v1.code AS code1, "
"v1.accuracy AS accuracy1, "
+ "v2.table_name as table2, "
"v2.auth_name AS auth_name2, v2.code AS code2, "
"v2.accuracy as accuracy2, "
"a1.south_lat AS south_lat1, "
@@ -3354,17 +3583,17 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
joinArea +
"WHERE v1.source_crs_auth_name = ? AND v1.source_crs_code = ? "
"AND v2.target_crs_auth_name = ? AND v2.target_crs_code = ? ");
- auto params = std::vector<SQLValues>{sourceCRSAuthName, sourceCRSCode,
- targetCRSAuthName, targetCRSCode};
+ auto params = ListOfParams{sourceCRSAuthName, sourceCRSCode,
+ targetCRSAuthName, targetCRSCode};
std::string additionalWhere(
"AND v1.deprecated = 0 AND v2.deprecated = 0 "
"AND intersects_bbox(south_lat1, west_lon1, north_lat1, east_lon1, "
"south_lat2, west_lon2, north_lat2, east_lon2) == 1 ");
- if (!getAuthority().empty()) {
+ if (d->hasAuthorityRestriction()) {
additionalWhere += "AND v1.auth_name = ? AND v2.auth_name = ? ";
- params.emplace_back(getAuthority());
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
+ params.emplace_back(d->authority());
}
std::string intermediateWhere =
buildIntermediateWhere(intermediateCRSAuthCodes, "target", "source");
@@ -3381,11 +3610,13 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
std::set<std::pair<std::string, std::string>> setTransf1;
std::set<std::pair<std::string, std::string>> setTransf2;
for (const auto &row : resultSet) {
- const auto &auth_name1 = row[0];
- const auto &code1 = row[1];
- // const auto &accuracy1 = row[2];
- const auto &auth_name2 = row[3];
- const auto &code2 = row[4];
+ // table1
+ const auto &auth_name1 = row[1];
+ const auto &code1 = row[2];
+ // accuracy1
+ // table2
+ const auto &auth_name2 = row[5];
+ const auto &code2 = row[6];
setTransf1.insert(
std::pair<std::string, std::string>(auth_name1, code1));
setTransf2.insert(
@@ -3393,10 +3624,10 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
}
SQLResultSet filteredResultSet;
for (const auto &row : resultSet) {
- const auto &replacement_auth_name1 = row[14];
- const auto &replacement_code1 = row[15];
- const auto &replacement_auth_name2 = row[16];
- const auto &replacement_code2 = row[17];
+ const auto &replacement_auth_name1 = row[16];
+ const auto &replacement_code1 = row[17];
+ const auto &replacement_auth_name2 = row[18];
+ const auto &replacement_code2 = row[19];
if (!replacement_auth_name1.empty() &&
setTransf1.find(std::pair<std::string, std::string>(
replacement_auth_name1, replacement_code1)) !=
@@ -3422,22 +3653,24 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
res = filterOutSuperseded(std::move(res));
}
for (const auto &row : res) {
- const auto &auth_name1 = row[0];
- const auto &code1 = row[1];
- // const auto &accuracy1 = row[2];
- const auto &auth_name2 = row[3];
- const auto &code2 = row[4];
- // const auto &accuracy2 = row[5];
+ const auto &table1 = row[0];
+ const auto &auth_name1 = row[1];
+ const auto &code1 = row[2];
+ // const auto &accuracy1 = row[3];
+ const auto &table2 = row[4];
+ const auto &auth_name2 = row[5];
+ const auto &code2 = row[6];
+ // const auto &accuracy2 = row[7];
auto op1 = d->createFactory(auth_name1)
- ->createCoordinateOperation(code1, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code1, true, usePROJAlternativeGridNames, table1);
if (useIrrelevantPivot(op1, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
}
auto op2 = d->createFactory(auth_name2)
- ->createCoordinateOperation(code2, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code2, true, usePROJAlternativeGridNames, table2);
if (useIrrelevantPivot(op2, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
@@ -3461,22 +3694,24 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
res = filterOutSuperseded(std::move(res));
}
for (const auto &row : res) {
- const auto &auth_name1 = row[0];
- const auto &code1 = row[1];
- // const auto &accuracy1 = row[2];
- const auto &auth_name2 = row[3];
- const auto &code2 = row[4];
- // const auto &accuracy2 = row[5];
+ const auto &table1 = row[0];
+ const auto &auth_name1 = row[1];
+ const auto &code1 = row[2];
+ // const auto &accuracy1 = row[3];
+ const auto &table2 = row[4];
+ const auto &auth_name2 = row[5];
+ const auto &code2 = row[6];
+ // const auto &accuracy2 = row[7];
auto op1 = d->createFactory(auth_name1)
- ->createCoordinateOperation(code1, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code1, true, usePROJAlternativeGridNames, table1);
if (useIrrelevantPivot(op1, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
}
auto op2 = d->createFactory(auth_name2)
- ->createCoordinateOperation(code2, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code2, true, usePROJAlternativeGridNames, table2);
if (useIrrelevantPivot(op2, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
@@ -3500,22 +3735,24 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
res = filterOutSuperseded(std::move(res));
}
for (const auto &row : res) {
- const auto &auth_name1 = row[0];
- const auto &code1 = row[1];
- // const auto &accuracy1 = row[2];
- const auto &auth_name2 = row[3];
- const auto &code2 = row[4];
- // const auto &accuracy2 = row[5];
+ const auto &table1 = row[0];
+ const auto &auth_name1 = row[1];
+ const auto &code1 = row[2];
+ // const auto &accuracy1 = row[3];
+ const auto &table2 = row[4];
+ const auto &auth_name2 = row[5];
+ const auto &code2 = row[6];
+ // const auto &accuracy2 = row[7];
auto op1 = d->createFactory(auth_name1)
- ->createCoordinateOperation(code1, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code1, true, usePROJAlternativeGridNames, table1);
if (useIrrelevantPivot(op1, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
}
auto op2 = d->createFactory(auth_name2)
- ->createCoordinateOperation(code2, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code2, true, usePROJAlternativeGridNames, table2);
if (useIrrelevantPivot(op2, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
@@ -3539,22 +3776,24 @@ AuthorityFactory::createFromCRSCodesWithIntermediates(
res = filterOutSuperseded(std::move(res));
}
for (const auto &row : res) {
- const auto &auth_name1 = row[0];
- const auto &code1 = row[1];
- // const auto &accuracy1 = row[2];
- const auto &auth_name2 = row[3];
- const auto &code2 = row[4];
- // const auto &accuracy2 = row[5];
+ const auto &table1 = row[0];
+ const auto &auth_name1 = row[1];
+ const auto &code1 = row[2];
+ // const auto &accuracy1 = row[3];
+ const auto &table2 = row[4];
+ const auto &auth_name2 = row[5];
+ const auto &code2 = row[6];
+ // const auto &accuracy2 = row[7];
auto op1 = d->createFactory(auth_name1)
- ->createCoordinateOperation(code1, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code1, true, usePROJAlternativeGridNames, table1);
if (useIrrelevantPivot(op1, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
}
auto op2 = d->createFactory(auth_name2)
- ->createCoordinateOperation(code2, true,
- usePROJAlternativeGridNames);
+ ->createCoordinateOperation(
+ code2, true, usePROJAlternativeGridNames, table2);
if (useIrrelevantPivot(op2, sourceCRSAuthName, sourceCRSCode,
targetCRSAuthName, targetCRSCode)) {
continue;
@@ -3661,10 +3900,10 @@ AuthorityFactory::getAuthorityCodes(const ObjectType &type,
sql += "auth_name = ?";
if (!allowDeprecated) {
- sql += " AND deprecated != 1";
+ sql += " AND deprecated = 0";
}
- auto res = d->run(sql, {getAuthority()});
+ auto res = d->run(sql, {d->authority()});
std::set<std::string> set;
for (const auto &row : res) {
set.insert(row[0]);
@@ -3690,10 +3929,10 @@ AuthorityFactory::getDescriptionText(const std::string &code) const {
"? ORDER BY table_name";
auto res = d->runWithCodeParam(sql, code);
if (res.empty()) {
- throw NoSuchAuthorityCodeException("object not found", getAuthority(),
+ throw NoSuchAuthorityCodeException("object not found", d->authority(),
code);
}
- return res[0][0];
+ return res.front()[0];
}
// ---------------------------------------------------------------------------
@@ -3724,7 +3963,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias(
if (tryEquivalentNameSpelling) {
std::string sql(
"SELECT table_name, auth_name, code, alt_name FROM alias_name");
- std::vector<SQLValues> params;
+ ListOfParams params;
if (!tableName.empty()) {
sql += " WHERE table_name = ?";
params.push_back(tableName);
@@ -3756,7 +3995,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias(
if (res.empty()) { // shouldn't happen normally
return std::string();
}
- return res[0][0];
+ return res.front()[0];
}
}
return std::string();
@@ -3764,7 +4003,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias(
std::string sql(
"SELECT table_name, auth_name, code FROM alias_name WHERE "
"alt_name = ?");
- std::vector<SQLValues> params{aliasedName};
+ ListOfParams params{aliasedName};
if (!tableName.empty()) {
sql += " AND table_name = ?";
params.push_back(tableName);
@@ -3777,9 +4016,10 @@ std::string AuthorityFactory::getOfficialNameFromAlias(
if (res.empty()) {
return std::string();
}
- outTableName = res[0][0];
- outAuthName = res[0][1];
- outCode = res[0][2];
+ const auto &row = res.front();
+ outTableName = row[0];
+ outAuthName = row[1];
+ outCode = row[2];
sql = "SELECT name FROM \"";
sql += replaceAll(outTableName, "\"", "\"\"");
sql += "\" WHERE auth_name = ? AND code = ?";
@@ -3787,7 +4027,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias(
if (res.empty()) { // shouldn't happen normally
return std::string();
}
- return res[0][0];
+ return res.front()[0];
}
}
@@ -3847,14 +4087,14 @@ AuthorityFactory::createObjectsFromName(
std::string sql(
"SELECT table_name, auth_name, code, name FROM object_view WHERE "
"deprecated = ? AND ");
- std::vector<SQLValues> params{deprecated ? 1.0 : 0.0};
+ ListOfParams params{deprecated ? 1.0 : 0.0};
if (!approximateMatch) {
sql += "name LIKE ? AND ";
params.push_back(searchedNameWithoutDeprecated);
}
- if (!getAuthority().empty()) {
+ if (d->hasAuthorityRestriction()) {
sql += " auth_name = ? AND ";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
if (allowedObjectTypes.empty()) {
@@ -3971,7 +4211,7 @@ AuthorityFactory::createObjectsFromName(
// so cache results.
if (allowedObjectTypes.size() == 1 &&
allowedObjectTypes[0] == ObjectType::GEODETIC_REFERENCE_FRAME &&
- approximateMatch && getAuthority().empty()) {
+ approximateMatch && d->authority().empty()) {
auto &mapCanonicalizeGRFName =
d->context()->getPrivate()->getMapCanonicalizeGRFName();
if (mapCanonicalizeGRFName.empty()) {
@@ -4151,10 +4391,10 @@ AuthorityFactory::listAreaOfUseFromName(const std::string &name,
bool approximateMatch) const {
std::string sql(
"SELECT auth_name, code FROM area WHERE deprecated = 0 AND ");
- std::vector<SQLValues> params;
- if (!getAuthority().empty()) {
+ ListOfParams params;
+ if (d->hasAuthorityRestriction()) {
sql += " auth_name = ? AND ";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
sql += "name LIKE ?";
if (!approximateMatch) {
@@ -4182,10 +4422,9 @@ std::list<datum::EllipsoidNNPtr> AuthorityFactory::createEllipsoidFromExisting(
"abs(semi_minor_axis - ?) < 1e-10 * abs(semi_minor_axis)) OR "
"((inv_flattening IS NOT NULL AND "
"abs(inv_flattening - ?) < 1e-10 * abs(inv_flattening))))");
- std::vector<SQLValues> params{
- ellipsoid->semiMajorAxis().getSIValue(),
- ellipsoid->computeSemiMinorAxis().getSIValue(),
- ellipsoid->computedInverseFlattening()};
+ ListOfParams params{ellipsoid->semiMajorAxis().getSIValue(),
+ ellipsoid->computeSemiMinorAxis().getSIValue(),
+ ellipsoid->computedInverseFlattening()};
auto sqlRes = d->run(sql, params);
std::list<datum::EllipsoidNNPtr> res;
for (const auto &row : sqlRes) {
@@ -4205,10 +4444,10 @@ std::list<crs::GeodeticCRSNNPtr> AuthorityFactory::createGeodeticCRSFromDatum(
std::string sql(
"SELECT auth_name, code FROM geodetic_crs WHERE "
"datum_auth_name = ? AND datum_code = ? AND deprecated = 0");
- std::vector<SQLValues> params{datum_auth_name, datum_code};
- if (!getAuthority().empty()) {
+ ListOfParams params{datum_auth_name, datum_code};
+ if (d->hasAuthorityRestriction()) {
sql += " AND auth_name = ?";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
if (!geodetic_crs_type.empty()) {
sql += " AND type = ?";
@@ -4241,10 +4480,10 @@ AuthorityFactory::createGeodeticCRSFromEllipsoid(
"geodetic_datum.ellipsoid_code = ? AND "
"geodetic_datum.deprecated = 0 AND "
"geodetic_crs.deprecated = 0");
- std::vector<SQLValues> params{ellipsoid_auth_name, ellipsoid_code};
- if (!getAuthority().empty()) {
+ ListOfParams params{ellipsoid_auth_name, ellipsoid_code};
+ if (d->hasAuthorityRestriction()) {
sql += " AND geodetic_crs.auth_name = ?";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
if (!geodetic_crs_type.empty()) {
sql += " AND geodetic_crs.type = ?";
@@ -4265,8 +4504,8 @@ AuthorityFactory::createGeodeticCRSFromEllipsoid(
//! @cond Doxygen_Suppress
static std::string buildSqlLookForAuthNameCode(
- const std::list<std::pair<crs::CRSNNPtr, int>> &list,
- std::vector<SQLValues> &params, const char *prefixField) {
+ const std::list<std::pair<crs::CRSNNPtr, int>> &list, ListOfParams &params,
+ const char *prefixField) {
std::string sql("(");
std::set<std::string> authorities;
@@ -4354,7 +4593,7 @@ AuthorityFactory::createProjectedCRSFromExisting(
"projected_crs.conversion_auth_name = conversion.auth_name AND "
"projected_crs.conversion_code = conversion.code WHERE "
"projected_crs.deprecated = 0 AND ");
- std::vector<SQLValues> params;
+ ListOfParams params;
if (!candidatesGeodCRS.empty()) {
sql += buildSqlLookForAuthNameCode(candidatesGeodCRS, params,
"projected_crs.geodetic_crs_");
@@ -4363,9 +4602,9 @@ AuthorityFactory::createProjectedCRSFromExisting(
sql += "conversion.method_auth_name = 'EPSG' AND "
"conversion.method_code = ?";
params.emplace_back(toString(methodEPSGCode));
- if (!getAuthority().empty()) {
+ if (d->hasAuthorityRestriction()) {
sql += " AND projected_crs.auth_name = ?";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
int iParam = 1;
@@ -4533,9 +4772,9 @@ AuthorityFactory::createProjectedCRSFromExisting(
params.emplace_back(patternVal);
}
sql += ")";
- if (!getAuthority().empty()) {
+ if (d->hasAuthorityRestriction()) {
sql += " AND auth_name = ?";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
auto sqlRes2 = d->run(sql, params);
@@ -4582,7 +4821,7 @@ AuthorityFactory::createCompoundCRSFromExisting(
std::string sql("SELECT auth_name, code FROM compound_crs WHERE "
"deprecated = 0 AND ");
- std::vector<SQLValues> params;
+ ListOfParams params;
bool addAnd = false;
if (!candidatesHorizCRS.empty()) {
sql += buildSqlLookForAuthNameCode(candidatesHorizCRS, params,
@@ -4597,12 +4836,12 @@ AuthorityFactory::createCompoundCRSFromExisting(
"vertical_crs_");
addAnd = true;
}
- if (!getAuthority().empty()) {
+ if (d->hasAuthorityRestriction()) {
if (addAnd) {
sql += " AND ";
}
sql += "auth_name = ?";
- params.emplace_back(getAuthority());
+ params.emplace_back(d->authority());
}
auto sqlRes = d->run(sql, params);
diff --git a/src/internal.cpp b/src/internal.cpp
index 4bec1bf9..ecb724c2 100644
--- a/src/internal.cpp
+++ b/src/internal.cpp
@@ -32,6 +32,7 @@
#include "proj/internal/internal.hpp"
+#include <cstdint>
#include <cstring>
#ifdef _MSC_VER
#include <string.h>
@@ -237,6 +238,38 @@ bool ends_with(const std::string &str, const std::string &suffix) noexcept {
// ---------------------------------------------------------------------------
double c_locale_stod(const std::string &s) {
+
+ const auto s_size = s.size();
+ // Fast path
+ if (s_size > 0 && s_size < 15) {
+ std::int64_t acc = 0;
+ std::int64_t div = 1;
+ bool afterDot = false;
+ size_t i = 0;
+ if (s[0] == '-') {
+ ++i;
+ div = -1;
+ } else if (s[0] == '+') {
+ ++i;
+ }
+ for (; i < s_size; ++i) {
+ const auto ch = s[i];
+ if (ch >= '0' && ch <= '9') {
+ acc = acc * 10 + ch - '0';
+ if (afterDot) {
+ div *= 10;
+ }
+ } else if (ch == '.') {
+ afterDot = true;
+ } else {
+ div = 0;
+ }
+ }
+ if (div) {
+ return static_cast<double>(acc) / div;
+ }
+ }
+
std::istringstream iss(s);
iss.imbue(std::locale::classic());
double d;
diff --git a/src/io.cpp b/src/io.cpp
index f396f1df..b5da2b8c 100644
--- a/src/io.cpp
+++ b/src/io.cpp
@@ -490,7 +490,7 @@ static std::string normalizeSerializedString(const std::string &in) {
return in;
}
#else
-static std::string normalizeSerializedString(const std::string &in) {
+static inline std::string normalizeSerializedString(const std::string &in) {
return in;
}
#endif
@@ -499,11 +499,19 @@ static std::string normalizeSerializedString(const std::string &in) {
void WKTFormatter::add(double number, int precision) {
d->startNewChild();
- std::string val(
- normalizeSerializedString(internal::toString(number, precision)));
- d->result_ += val;
- if (d->params_.useESRIDialect_ && val.find('.') == std::string::npos) {
- d->result_ += ".0";
+ if (number == 0.0) {
+ if (d->params_.useESRIDialect_) {
+ d->result_ += "0.0";
+ } else {
+ d->result_ += '0';
+ }
+ } else {
+ std::string val(
+ normalizeSerializedString(internal::toString(number, precision)));
+ d->result_ += val;
+ if (d->params_.useESRIDialect_ && val.find('.') == std::string::npos) {
+ d->result_ += ".0";
+ }
}
}
@@ -1963,8 +1971,7 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame(
foundDatumName = true;
properties.set(IdentifiedObject::NAME_KEY,
refDatum->nameStr());
- if (properties.find(Identifier::CODESPACE_KEY) ==
- properties.end() &&
+ if (!properties.get(Identifier::CODESPACE_KEY) &&
refDatum->identifiers().size() == 1) {
const auto &id = refDatum->identifiers()[0];
auto identifiers = ArrayOfBaseObject::create();
@@ -6674,7 +6681,7 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS(
} else if (step.name == "krovak") {
if (param->epsg_code ==
EPSG_CODE_PARAMETER_COLATITUDE_CONE_AXIS) {
- value = 30.2881397222222;
+ value = 30.28813975277777776;
} else if (
param->epsg_code ==
EPSG_CODE_PARAMETER_LATITUDE_PSEUDO_STANDARD_PARALLEL) {
diff --git a/src/metadata.cpp b/src/metadata.cpp
index af8dc1fe..fac2ae6b 100644
--- a/src/metadata.cpp
+++ b/src/metadata.cpp
@@ -858,6 +858,8 @@ struct Identifier::Private {
optional<std::string> description_{};
optional<std::string> uri_{};
+ Private() = default;
+
Private(const std::string &codeIn, const PropertyMap &properties)
: code_(codeIn) {
setProperties(properties);
@@ -874,10 +876,9 @@ void Identifier::Private::setProperties(
const PropertyMap &properties) // throw(InvalidValueTypeException)
{
{
- auto oIter = properties.find(AUTHORITY_KEY);
- if (oIter != properties.end()) {
- if (auto genVal =
- dynamic_cast<const BoxedValue *>(oIter->second.get())) {
+ const auto pVal = properties.get(AUTHORITY_KEY);
+ if (pVal) {
+ if (auto genVal = dynamic_cast<const BoxedValue *>(pVal->get())) {
if (genVal->type() == BoxedValue::Type::STRING) {
authority_ = Citation(genVal->stringValue());
} else {
@@ -886,7 +887,7 @@ void Identifier::Private::setProperties(
}
} else {
if (auto citation =
- dynamic_cast<const Citation *>(oIter->second.get())) {
+ dynamic_cast<const Citation *>(pVal->get())) {
authority_ = *citation;
} else {
throw InvalidValueTypeException("Invalid value type for " +
@@ -897,10 +898,9 @@ void Identifier::Private::setProperties(
}
{
- auto oIter = properties.find(CODE_KEY);
- if (oIter != properties.end()) {
- if (auto genVal =
- dynamic_cast<const BoxedValue *>(oIter->second.get())) {
+ const auto pVal = properties.get(CODE_KEY);
+ if (pVal) {
+ if (auto genVal = dynamic_cast<const BoxedValue *>(pVal->get())) {
if (genVal->type() == BoxedValue::Type::INTEGER) {
code_ = toString(genVal->integerValue());
} else if (genVal->type() == BoxedValue::Type::STRING) {
@@ -916,45 +916,30 @@ void Identifier::Private::setProperties(
}
}
- {
- std::string temp;
- if (properties.getStringValue(CODESPACE_KEY, temp)) {
- codeSpace_ = temp;
- }
- }
-
- {
- std::string temp;
- if (properties.getStringValue(VERSION_KEY, temp)) {
- version_ = temp;
- }
- }
-
- {
- std::string temp;
- if (properties.getStringValue(DESCRIPTION_KEY, temp)) {
- description_ = temp;
- }
- }
-
- {
- std::string temp;
- if (properties.getStringValue(URI_KEY, temp)) {
- uri_ = temp;
- }
- }
+ properties.getStringValue(CODESPACE_KEY, codeSpace_);
+ properties.getStringValue(VERSION_KEY, version_);
+ properties.getStringValue(DESCRIPTION_KEY, description_);
+ properties.getStringValue(URI_KEY, uri_);
}
//! @endcond
// ---------------------------------------------------------------------------
-Identifier::Identifier(const std::string &codeIn, const PropertyMap &properties)
+Identifier::Identifier(const std::string &codeIn,
+ const util::PropertyMap &properties)
: d(internal::make_unique<Private>(codeIn, properties)) {}
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+
+// ---------------------------------------------------------------------------
+
+Identifier::Identifier() : d(internal::make_unique<Private>()) {}
+
+// ---------------------------------------------------------------------------
+
Identifier::Identifier(const Identifier &other)
: d(internal::make_unique<Private>(*(other.d))) {}
@@ -979,6 +964,17 @@ IdentifierNNPtr Identifier::create(const std::string &codeIn,
// ---------------------------------------------------------------------------
+//! @cond Doxygen_Suppress
+IdentifierNNPtr
+Identifier::createFromDescription(const std::string &descriptionIn) {
+ auto id = Identifier::nn_make_shared<Identifier>();
+ id->d->description_ = descriptionIn;
+ return id;
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
/** \brief Return a citation for the organization responsible for definition and
* maintenance of the code.
*
diff --git a/src/proj.h b/src/proj.h
index c41a2770..cce371d4 100644
--- a/src/proj.h
+++ b/src/proj.h
@@ -572,6 +572,9 @@ PJ_OBJ_TYPE PROJ_DLL proj_obj_get_type(const PJ_OBJ *obj);
int PROJ_DLL proj_obj_is_deprecated(const PJ_OBJ *obj);
+PJ_OBJ_LIST PROJ_DLL *proj_obj_get_non_deprecated(PJ_CONTEXT *ctx,
+ const PJ_OBJ *obj);
+
/** Comparison criterion. */
typedef enum
{
diff --git a/src/proj_experimental.h b/src/proj_experimental.h
index b8c37054..698b235b 100644
--- a/src/proj_experimental.h
+++ b/src/proj_experimental.h
@@ -123,6 +123,13 @@ PJ_OBJ PROJ_DLL *proj_obj_create_ellipsoidal_2D_cs(PJ_CONTEXT *ctx,
const char* unit_name,
double unit_conv_factor);
+PJ_OBJ_LIST PROJ_DLL *proj_obj_query_geodetic_crs_from_datum(
+ PJ_CONTEXT *ctx,
+ const char *crs_auth_name,
+ const char *datum_auth_name,
+ const char *datum_code,
+ const char *crs_type);
+
PJ_OBJ PROJ_DLL *proj_obj_create_geographic_crs(
PJ_CONTEXT *ctx,
const char *crs_name,
@@ -244,7 +251,8 @@ PJ_OBJ PROJ_DLL *proj_obj_crs_create_bound_crs(PJ_CONTEXT *ctx,
const PJ_OBJ *transformation);
PJ_OBJ PROJ_DLL *proj_obj_crs_create_bound_crs_to_WGS84(PJ_CONTEXT *ctx,
- const PJ_OBJ *crs);
+ const PJ_OBJ *crs,
+ const char *const *options);
/* BEGIN: Generated by scripts/create_c_api_projections.py*/
PJ_OBJ PROJ_DLL *proj_obj_create_conversion_utm(
diff --git a/src/projinfo.cpp b/src/projinfo.cpp
index ddcc09da..d6fa37bc 100644
--- a/src/projinfo.cpp
+++ b/src/projinfo.cpp
@@ -37,6 +37,7 @@
#include "projects.h"
+#include <proj/common.hpp>
#include <proj/coordinateoperation.hpp>
#include <proj/crs.hpp>
#include <proj/io.hpp>
@@ -45,6 +46,7 @@
#include "proj/internal/internal.hpp" // for split
+using namespace NS_PROJ::common;
using namespace NS_PROJ::crs;
using namespace NS_PROJ::io;
using namespace NS_PROJ::metadata;
@@ -134,7 +136,8 @@ static std::string c_ify_string(const std::string &str) {
static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext,
const std::string &user_string,
bool kindIsCRS, const std::string &context,
- bool buildBoundCRSToWGS84) {
+ bool buildBoundCRSToWGS84,
+ bool allowPivots) {
BaseObjectPtr obj;
std::string l_user_string(user_string);
@@ -190,7 +193,8 @@ static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext,
if (buildBoundCRSToWGS84) {
auto crs = std::dynamic_pointer_cast<CRS>(obj);
if (crs) {
- obj = crs->createBoundCRSToWGS84IfPossible(dbContext).as_nullable();
+ obj = crs->createBoundCRSToWGS84IfPossible(dbContext, allowPivots)
+ .as_nullable();
}
}
@@ -200,7 +204,31 @@ static BaseObjectNNPtr buildObject(DatabaseContextPtr dbContext,
// ---------------------------------------------------------------------------
static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj,
- const OutputOptions &outputOpt) {
+ bool allowPivots, const OutputOptions &outputOpt) {
+
+ auto identified = dynamic_cast<const IdentifiedObject *>(obj.get());
+ if (!outputOpt.quiet && identified && identified->isDeprecated()) {
+ std::cout << "Warning: object is deprecated" << std::endl;
+ auto crs = dynamic_cast<const CRS *>(obj.get());
+ if (crs && dbContext) {
+ try {
+ auto list = crs->getNonDeprecated(NN_NO_CHECK(dbContext));
+ if (!list.empty()) {
+ std::cout << "Alternative non-deprecated CRS:" << std::endl;
+ }
+ for (const auto &altCRS : list) {
+ const auto &ids = altCRS->identifiers();
+ if (!ids.empty()) {
+ std::cout << " " << *(ids[0]->codeSpace()) << ":"
+ << ids[0]->code() << std::endl;
+ }
+ }
+ } catch (const std::exception &) {
+ }
+ }
+ std::cout << std::endl;
+ }
+
auto projStringExportable =
nn_dynamic_pointer_cast<IPROJStringExportable>(obj);
bool alreadyOutputed = false;
@@ -237,7 +265,8 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj,
if (crs) {
objToExport =
nn_dynamic_pointer_cast<IPROJStringExportable>(
- crs->createBoundCRSToWGS84IfPossible(dbContext));
+ crs->createBoundCRSToWGS84IfPossible(dbContext,
+ allowPivots));
}
if (!objToExport) {
objToExport = projStringExportable;
@@ -372,7 +401,8 @@ static void outputObject(DatabaseContextPtr dbContext, BaseObjectNNPtr obj,
std::shared_ptr<IWKTExportable> objToExport;
if (crs) {
objToExport = nn_dynamic_pointer_cast<IWKTExportable>(
- crs->createBoundCRSToWGS84IfPossible(dbContext));
+ crs->createBoundCRSToWGS84IfPossible(dbContext,
+ allowPivots));
}
if (!objToExport) {
objToExport = wktExportable;
@@ -480,7 +510,7 @@ static void outputOperations(
const std::string &authority, bool usePROJGridAlternatives,
bool showSuperseded, const OutputOptions &outputOpt, bool summary) {
auto sourceObj =
- buildObject(dbContext, sourceCRSStr, true, "source CRS", false);
+ buildObject(dbContext, sourceCRSStr, true, "source CRS", false, false);
auto sourceCRS = nn_dynamic_pointer_cast<CRS>(sourceObj);
if (!sourceCRS) {
std::cerr << "source CRS string is not a CRS" << std::endl;
@@ -488,7 +518,7 @@ static void outputOperations(
}
auto targetObj =
- buildObject(dbContext, targetCRSStr, true, "target CRS", false);
+ buildObject(dbContext, targetCRSStr, true, "target CRS", false, false);
auto targetCRS = nn_dynamic_pointer_cast<CRS>(targetObj);
if (!targetCRS) {
std::cerr << "target CRS string is not a CRS" << std::endl;
@@ -519,7 +549,7 @@ static void outputOperations(
std::exit(1);
}
if (outputOpt.quiet && !list.empty()) {
- outputObject(dbContext, list[0], outputOpt);
+ outputObject(dbContext, list[0], allowPivots, outputOpt);
return;
}
if (summary) {
@@ -545,7 +575,7 @@ static void outputOperations(
}
outputOperationSummary(op);
std::cout << std::endl;
- outputObject(dbContext, op, outputOpt);
+ outputObject(dbContext, op, allowPivots, outputOpt);
}
}
}
@@ -880,7 +910,7 @@ int main(int argc, char **argv) {
if (!user_string.empty()) {
auto obj(buildObject(dbContext, user_string, kindIsCRS, "input string",
- buildBoundCRSToWGS84));
+ buildBoundCRSToWGS84, allowPivots));
if (guessDialect) {
auto dialect = WKTParser().guessDialect(user_string);
std::cout << "Guessed WKT dialect: ";
@@ -897,7 +927,7 @@ int main(int argc, char **argv) {
}
std::cout << std::endl;
}
- outputObject(dbContext, obj, outputOpt);
+ outputObject(dbContext, obj, allowPivots, outputOpt);
if (identify) {
auto crs = dynamic_cast<CRS *>(obj.get());
if (crs) {
diff --git a/src/util.cpp b/src/util.cpp
index b3a5149d..ac6357a2 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -239,7 +239,18 @@ ArrayOfBaseObjectNNPtr ArrayOfBaseObject::create() {
//! @cond Doxygen_Suppress
struct PropertyMap::Private {
- std::map<std::string, BaseObjectNNPtr> map_{};
+ std::list<std::pair<std::string, BaseObjectNNPtr>> list_{};
+
+ // cppcheck-suppress functionStatic
+ void set(const std::string &key, const BoxedValueNNPtr &val) {
+ for (auto &pair : list_) {
+ if (pair.first == key) {
+ pair.second = val;
+ return;
+ }
+ }
+ list_.emplace_back(key, val);
+ }
};
//! @endcond
@@ -263,15 +274,13 @@ PropertyMap::~PropertyMap() = default;
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
-std::map<std::string, BaseObjectNNPtr>::iterator
-PropertyMap::find(const std::string &key) const {
- return d->map_.find(key);
-}
-
-// ---------------------------------------------------------------------------
-
-std::map<std::string, BaseObjectNNPtr>::iterator PropertyMap::end() const {
- return d->map_.end();
+const BaseObjectNNPtr *PropertyMap::get(const std::string &key) const {
+ for (const auto &pair : d->list_) {
+ if (pair.first == key) {
+ return &(pair.second);
+ }
+ }
+ return nullptr;
}
//! @endcond
@@ -280,26 +289,13 @@ std::map<std::string, BaseObjectNNPtr>::iterator PropertyMap::end() const {
/** \brief Set a BaseObjectNNPtr as the value of a key. */
PropertyMap &PropertyMap::set(const std::string &key,
const BaseObjectNNPtr &val) {
- auto iter = d->map_.find(key);
- if (iter != d->map_.end()) {
- iter->second = val;
- } else {
- d->map_.insert(std::pair<std::string, BaseObjectNNPtr>(key, val));
- }
- return *this;
-}
-
-// ---------------------------------------------------------------------------
-
-/** \brief Set a BoxedValue as the value of a key. */
-PropertyMap &PropertyMap::set(const std::string &key, const BoxedValue &val) {
- auto iter = d->map_.find(key);
- if (iter != d->map_.end()) {
- iter->second = util::nn_make_shared<BoxedValue>(val);
- } else {
- d->map_.insert(std::pair<std::string, BaseObjectNNPtr>(
- key, util::nn_make_shared<BoxedValue>(val)));
+ for (auto &pair : d->list_) {
+ if (pair.first == key) {
+ pair.second = val;
+ return *this;
+ }
}
+ d->list_.emplace_back(key, val);
return *this;
}
@@ -307,28 +303,32 @@ PropertyMap &PropertyMap::set(const std::string &key, const BoxedValue &val) {
/** \brief Set a string as the value of a key. */
PropertyMap &PropertyMap::set(const std::string &key, const std::string &val) {
- return set(key, BoxedValue(val));
+ d->set(key, util::nn_make_shared<BoxedValue>(val));
+ return *this;
}
// ---------------------------------------------------------------------------
/** \brief Set a string as the value of a key. */
PropertyMap &PropertyMap::set(const std::string &key, const char *val) {
- return set(key, BoxedValue(val));
+ d->set(key, util::nn_make_shared<BoxedValue>(val));
+ return *this;
}
// ---------------------------------------------------------------------------
/** \brief Set a integer as the value of a key. */
PropertyMap &PropertyMap::set(const std::string &key, int val) {
- return set(key, BoxedValue(val));
+ d->set(key, util::nn_make_shared<BoxedValue>(val));
+ return *this;
}
// ---------------------------------------------------------------------------
/** \brief Set a boolean as the value of a key. */
PropertyMap &PropertyMap::set(const std::string &key, bool val) {
- return set(key, BoxedValue(val));
+ d->set(key, util::nn_make_shared<BoxedValue>(val));
+ return *this;
}
// ---------------------------------------------------------------------------
@@ -350,16 +350,38 @@ bool PropertyMap::getStringValue(
const std::string &key,
std::string &outVal) const // throw(InvalidValueTypeException)
{
- auto oIter = d->map_.find(key);
- if (oIter == d->map_.end()) {
- return false;
+ for (const auto &pair : d->list_) {
+ if (pair.first == key) {
+ auto genVal = dynamic_cast<const BoxedValue *>(pair.second.get());
+ if (genVal && genVal->type() == BoxedValue::Type::STRING) {
+ outVal = genVal->stringValue();
+ return true;
+ }
+ throw InvalidValueTypeException("Invalid value type for " + key);
+ }
}
- auto genVal = dynamic_cast<const BoxedValue *>(oIter->second.get());
- if (genVal && genVal->type() == BoxedValue::Type::STRING) {
- outVal = genVal->stringValue();
- return true;
+ return false;
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
+bool PropertyMap::getStringValue(
+ const std::string &key,
+ optional<std::string> &outVal) const // throw(InvalidValueTypeException)
+{
+ for (const auto &pair : d->list_) {
+ if (pair.first == key) {
+ auto genVal = dynamic_cast<const BoxedValue *>(pair.second.get());
+ if (genVal && genVal->type() == BoxedValue::Type::STRING) {
+ outVal = genVal->stringValue();
+ return true;
+ }
+ throw InvalidValueTypeException("Invalid value type for " + key);
+ }
}
- throw InvalidValueTypeException("Invalid value type for " + key);
+ return false;
}
//! @endcond
diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo
index 90829fdd..ea0dcc2d 100755
--- a/test/cli/testprojinfo
+++ b/test/cli/testprojinfo
@@ -74,6 +74,10 @@ echo "Testing projinfo -s EPSG:4230 -t EPSG:4258 --area WRONG:CODE --summary" >>
$EXE -s EPSG:4230 -t EPSG:4258 --area WRONG:CODE --summary >>${OUT} 2>&1
echo "" >>${OUT}
+echo "Testing deprecated CRS: projinfo EPSG:26591" >> ${OUT}
+$EXE EPSG:26591 >>${OUT} 2>&1
+echo "" >>${OUT}
+
# do 'diff' with distribution results
echo "diff ${OUT} with testprojinfo_out.dist"
diff -u ${OUT} ${TEST_CLI_DIR}/testprojinfo_out.dist
diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist
index f3d4854a..40035489 100644
--- a/test/cli/testprojinfo_out.dist
+++ b/test/cli/testprojinfo_out.dist
@@ -110,12 +110,11 @@ CONVERSION["UTM zone 31N",
ID["EPSG",16031]]
Testing projinfo -s NAD27 -t NAD83 --grid-check none --spatial-test intersects --summary
-Candidate operations found: 8
+Candidate operations found: 7
DERIVED_FROM(EPSG):1312, NAD27 to NAD83 (3), 1.0 m, Canada
DERIVED_FROM(EPSG):1313, NAD27 to NAD83 (4), 1.5 m, Canada - NAD27
DERIVED_FROM(EPSG):1241, NAD27 to NAD83 (1), 0.15 m, USA - CONUS including EEZ
DERIVED_FROM(EPSG):1243, NAD27 to NAD83 (2), 0.5 m, USA - Alaska including EEZ
-ESRI:108003, NAD_1927_To_NAD_1983_PR_VI, 0.05 m, Caribbean - Puerto Rico and Virgin Islands - onshore
unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World
EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec
EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec
@@ -306,52 +305,6 @@ COORDINATEOPERATION["NAD27 to NAD83 (2)",
-------------------------------------
Operation n°5:
-ESRI:108003, NAD_1927_To_NAD_1983_PR_VI, 0.05 m, Caribbean - Puerto Rico and Virgin Islands - onshore
-
-PROJ string:
-+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=hgridshift +grids=prvi +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1
-
-WKT2_2015 string:
-COORDINATEOPERATION["NAD_1927_To_NAD_1983_PR_VI",
- SOURCECRS[
- GEODCRS["NAD27",
- DATUM["North American Datum 1927",
- ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
- LENGTHUNIT["metre",1]]],
- PRIMEM["Greenwich",0,
- ANGLEUNIT["degree",0.0174532925199433]],
- CS[ellipsoidal,2],
- AXIS["geodetic latitude (Lat)",north,
- ORDER[1],
- ANGLEUNIT["degree",0.0174532925199433]],
- AXIS["geodetic longitude (Lon)",east,
- ORDER[2],
- ANGLEUNIT["degree",0.0174532925199433]]]],
- TARGETCRS[
- GEODCRS["NAD83",
- DATUM["North American Datum 1983",
- ELLIPSOID["GRS 1980",6378137,298.257222101,
- LENGTHUNIT["metre",1]]],
- PRIMEM["Greenwich",0,
- ANGLEUNIT["degree",0.0174532925199433]],
- CS[ellipsoidal,2],
- AXIS["geodetic latitude (Lat)",north,
- ORDER[1],
- ANGLEUNIT["degree",0.0174532925199433]],
- AXIS["geodetic longitude (Lon)",east,
- ORDER[2],
- ANGLEUNIT["degree",0.0174532925199433]]]],
- METHOD["NTv2",
- ID["EPSG",9615]],
- PARAMETERFILE["Latitude and longitude difference file","prvi"],
- OPERATIONACCURACY[0.05],
- AREA["Caribbean - Puerto Rico and Virgin Islands - onshore"],
- BBOX[17.62,-67.97,18.78,-64.25],
- ID["ESRI",108003]]
-
--------------------------------------
-Operation n°6:
-
unknown id, Null geographic offset from NAD27 to NAD83, unknown accuracy, World
PROJ string:
@@ -405,7 +358,7 @@ COORDINATEOPERATION["Null geographic offset from NAD27 to NAD83",
BBOX[-90,-180,90,180]]
-------------------------------------
-Operation n°7:
+Operation n°6:
EPSG:1462, NAD27 to NAD83 (5), 1.0 m, Canada - Quebec
@@ -451,7 +404,7 @@ COORDINATEOPERATION["NAD27 to NAD83 (5)",
ID["EPSG",1462]]
-------------------------------------
-Operation n°8:
+Operation n°7:
EPSG:1573, NAD27 to NAD83 (6), 1.5 m, Canada - Quebec
@@ -525,3 +478,48 @@ No area of use matching provided name
Testing projinfo -s EPSG:4230 -t EPSG:4258 --area WRONG:CODE --summary
Area of use retrieval failed: area not found
+Testing deprecated CRS: projinfo EPSG:26591
+Warning: object is deprecated
+Alternative non-deprecated CRS:
+ EPSG:3003
+
+PROJ string:
++proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +inv +proj=longlat +ellps=intl +pm=rome +step +proj=tmerc +lat_0=0 +lon_0=9 +k=0.9996 +x_0=1500000 +y_0=0 +ellps=intl +pm=rome
+
+WKT2_2015 string:
+PROJCRS["Monte Mario (Rome) / Italy zone 1",
+ BASEGEODCRS["Monte Mario (Rome)",
+ DATUM["Monte Mario (Rome)",
+ ELLIPSOID["International 1924",6378388,297,
+ LENGTHUNIT["metre",1]]],
+ PRIMEM["Rome",12.4523333333333,
+ ANGLEUNIT["degree",0.0174532925199433]]],
+ CONVERSION["Italy zone 1",
+ METHOD["Transverse Mercator",
+ ID["EPSG",9807]],
+ PARAMETER["Latitude of natural origin",0,
+ ANGLEUNIT["degree",0.0174532925199433],
+ ID["EPSG",8801]],
+ PARAMETER["Longitude of natural origin",9,
+ ANGLEUNIT["degree",0.0174532925199433],
+ ID["EPSG",8802]],
+ PARAMETER["Scale factor at natural origin",0.9996,
+ SCALEUNIT["unity",1],
+ ID["EPSG",8805]],
+ PARAMETER["False easting",1500000,
+ LENGTHUNIT["metre",1],
+ ID["EPSG",8806]],
+ PARAMETER["False northing",0,
+ LENGTHUNIT["metre",1],
+ ID["EPSG",8807]]],
+ CS[Cartesian,2],
+ AXIS["easting (X)",east,
+ ORDER[1],
+ LENGTHUNIT["metre",1]],
+ AXIS["northing (Y)",north,
+ ORDER[2],
+ LENGTHUNIT["metre",1]],
+ AREA["Italy - west of 12°E"],
+ BBOX[36.53,5.94,47.04,12],
+ ID["EPSG",26591]]
+
diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp
index 42d00fa6..e9782ae8 100644
--- a/test/unit/test_c_api.cpp
+++ b/test/unit/test_c_api.cpp
@@ -402,7 +402,7 @@ TEST_F(CApi, proj_obj_crs_create_bound_crs_to_WGS84) {
ObjectKeeper keeper(crs);
ASSERT_NE(crs, nullptr);
- auto res = proj_obj_crs_create_bound_crs_to_WGS84(m_ctxt, crs);
+ auto res = proj_obj_crs_create_bound_crs_to_WGS84(m_ctxt, crs, nullptr);
ObjectKeeper keeper_res(res);
ASSERT_NE(res, nullptr);
@@ -447,7 +447,7 @@ TEST_F(CApi, proj_obj_crs_create_bound_crs_to_WGS84_on_invalid_type) {
ObjectKeeper keeper(obj);
ASSERT_NE(obj, nullptr);
- auto res = proj_obj_crs_create_bound_crs_to_WGS84(m_ctxt, obj);
+ auto res = proj_obj_crs_create_bound_crs_to_WGS84(m_ctxt, obj, nullptr);
ASSERT_EQ(res, nullptr);
}
@@ -1146,7 +1146,7 @@ TEST_F(CApi, proj_obj_create_operations) {
ASSERT_NE(res, nullptr);
ObjListKeeper keeper_res(res);
- EXPECT_EQ(proj_obj_list_get_count(res), 8);
+ EXPECT_EQ(proj_obj_list_get_count(res), 7);
EXPECT_EQ(proj_obj_list_get(m_ctxt, res, -1), nullptr);
EXPECT_EQ(proj_obj_list_get(m_ctxt, res, proj_obj_list_get_count(res)),
@@ -1247,7 +1247,7 @@ TEST_F(CApi, proj_obj_create_operations_with_pivot) {
// Restrict pivot to JGD2000
{
- auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr);
+ auto ctxt = proj_create_operation_factory_context(m_ctxt, "any");
ASSERT_NE(ctxt, nullptr);
ContextKeeper keeper_ctxt(ctxt);
@@ -1263,7 +1263,7 @@ TEST_F(CApi, proj_obj_create_operations_with_pivot) {
proj_obj_create_operations(m_ctxt, source_crs, target_crs, ctxt);
ASSERT_NE(res, nullptr);
ObjListKeeper keeper_res(res);
- // includes 2 results from ESRI
+ // includes results from ESRI
EXPECT_EQ(proj_obj_list_get_count(res), 5);
auto op = proj_obj_list_get(m_ctxt, res, 0);
ASSERT_NE(op, nullptr);
@@ -2552,4 +2552,37 @@ TEST_F(CApi, proj_obj_convert_conversion_to_other_method) {
}
}
+// ---------------------------------------------------------------------------
+
+TEST_F(CApi, proj_obj_get_non_deprecated) {
+ auto crs = proj_obj_create_from_database(
+ m_ctxt, "EPSG", "4226", PJ_OBJ_CATEGORY_CRS, false, nullptr);
+ ObjectKeeper keeper(crs);
+ ASSERT_NE(crs, nullptr);
+
+ auto list = proj_obj_get_non_deprecated(m_ctxt, crs);
+ ASSERT_NE(list, nullptr);
+ ObjListKeeper keeper_list(list);
+ EXPECT_EQ(proj_obj_list_get_count(list), 2);
+}
+
+// ---------------------------------------------------------------------------
+
+TEST_F(CApi, proj_obj_query_geodetic_crs_from_datum) {
+ {
+ auto list = proj_obj_query_geodetic_crs_from_datum(
+ m_ctxt, nullptr, "EPSG", "6326", nullptr);
+ ASSERT_NE(list, nullptr);
+ ObjListKeeper keeper_list(list);
+ EXPECT_GE(proj_obj_list_get_count(list), 3);
+ }
+ {
+ auto list = proj_obj_query_geodetic_crs_from_datum(
+ m_ctxt, "EPSG", "EPSG", "6326", "geographic 2D");
+ ASSERT_NE(list, nullptr);
+ ObjListKeeper keeper_list(list);
+ EXPECT_EQ(proj_obj_list_get_count(list), 1);
+ }
+}
+
} // namespace
diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp
index 44b84401..6ed002a9 100644
--- a/test/unit/test_crs.cpp
+++ b/test/unit/test_crs.cpp
@@ -339,6 +339,28 @@ TEST(crs, EPSG_4326_as_WKT1_GDAL_with_axis) {
// ---------------------------------------------------------------------------
+TEST(crs, EPSG_4326_from_db_as_WKT1_GDAL_with_axis) {
+ auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto crs = factory->createCoordinateReferenceSystem("4326");
+ auto wkt = crs->exportToWKT(
+ &(WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL)
+ ->setOutputAxis(WKTFormatter::OutputAxisRule::YES)));
+ EXPECT_EQ(wkt, "GEOGCS[\"WGS 84\",\n"
+ " DATUM[\"WGS_1984\",\n"
+ " SPHEROID[\"WGS 84\",6378137,298.257223563,\n"
+ " AUTHORITY[\"EPSG\",\"7030\"]],\n"
+ " AUTHORITY[\"EPSG\",\"6326\"]],\n"
+ " PRIMEM[\"Greenwich\",0,\n"
+ " AUTHORITY[\"EPSG\",\"8901\"]],\n"
+ " UNIT[\"degree\",0.0174532925199433,\n"
+ " AUTHORITY[\"EPSG\",\"9122\"]],\n"
+ " AXIS[\"Latitude\",NORTH],\n"
+ " AXIS[\"Longitude\",EAST],\n"
+ " AUTHORITY[\"EPSG\",\"4326\"]]");
+}
+
+// ---------------------------------------------------------------------------
+
TEST(crs, EPSG_4326_as_WKT1_ESRI_with_database) {
auto crs = GeographicCRS::EPSG_4326;
WKTFormatterNNPtr f(WKTFormatter::create(
@@ -1777,6 +1799,38 @@ TEST(crs, projectedCRS_as_PROJ_string) {
// ---------------------------------------------------------------------------
+TEST(crs, projectedCRS_Krovak_EPSG_5221_as_PROJ_string) {
+ auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG");
+ auto crs = factory->createProjectedCRS("5221");
+ // 30deg 17' 17.30311'' = 30.28813975277777776
+ EXPECT_EQ(crs->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=bessel +pm=ferro "
+ "+step +proj=krovak +lat_0=49.5 +lon_0=42.5 "
+ "+alpha=30.2881397527778 +k=0.9999 +x_0=0 +y_0=0 "
+ "+ellps=bessel +pm=ferro");
+}
+
+// ---------------------------------------------------------------------------
+
+TEST(crs, projectedCRS_Krovak_with_approximate_alpha_as_PROJ_string) {
+ // 30deg 17' 17.303'' = 30.288139722222223 as used in GDAL WKT1
+ auto obj = PROJStringParser().createFromPROJString(
+ "+proj=krovak +lat_0=49.5 +lon_0=42.5 +alpha=30.28813972222222 "
+ "+k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +pm=ferro +units=m +no_defs");
+ auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj);
+ EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()),
+ "+proj=pipeline "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +inv +proj=longlat +ellps=bessel +pm=ferro "
+ "+step +proj=krovak +lat_0=49.5 +lon_0=42.5 "
+ "+alpha=30.2881397222222 +k=0.9999 +x_0=0 +y_0=0 "
+ "+ellps=bessel +pm=ferro");
+}
+
+// ---------------------------------------------------------------------------
+
TEST(crs, projectedCRS_identify_no_db) {
{
// Hard-coded case: WGS 84 / UTM. No name
@@ -2433,7 +2487,7 @@ TEST(crs, Krovak_North_Orientated_as_WKT1_ESRI) {
"PARAMETER[\"False_Northing\",0.0],"
"PARAMETER[\"Pseudo_Standard_Parallel_1\",78.5],"
"PARAMETER[\"Scale_Factor\",1.0],"
- "PARAMETER[\"Azimuth\",30.2881397222222],"
+ "PARAMETER[\"Azimuth\",30.2881397527778],"
"PARAMETER[\"Longitude_Of_Center\",0.0],"
"PARAMETER[\"Latitude_Of_Center\",0.0],"
"PARAMETER[\"X_Scale\",-1.0],"
@@ -2465,7 +2519,7 @@ TEST(crs, Krovak_as_WKT1_ESRI) {
"PARAMETER[\"False_Northing\",0.0],"
"PARAMETER[\"Pseudo_Standard_Parallel_1\",78.5],"
"PARAMETER[\"Scale_Factor\",1.0],"
- "PARAMETER[\"Azimuth\",30.2881397222222],"
+ "PARAMETER[\"Azimuth\",30.2881397527778],"
"PARAMETER[\"Longitude_Of_Center\",0.0],"
"PARAMETER[\"Latitude_Of_Center\",0.0],"
"PARAMETER[\"X_Scale\",1.0],"
@@ -3425,9 +3479,8 @@ TEST(crs, boundCRS_crs_link) {
EXPECT_TRUE(baseCRS->isEquivalentTo(GeographicCRS::EPSG_4267.get()));
EXPECT_TRUE(baseCRS->canonicalBoundCRS() != nullptr);
- EXPECT_TRUE(
- baseCRS->createBoundCRSToWGS84IfPossible(nullptr)->isEquivalentTo(
- baseCRS->canonicalBoundCRS().get()));
+ EXPECT_TRUE(baseCRS->createBoundCRSToWGS84IfPossible(nullptr, false)
+ ->isEquivalentTo(baseCRS->canonicalBoundCRS().get()));
}
{
@@ -4726,26 +4779,28 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
auto factory = AuthorityFactory::create(dbContext, "EPSG");
{
auto crs_4326 = factory->createCoordinateReferenceSystem("4326");
- EXPECT_EQ(crs_4326->createBoundCRSToWGS84IfPossible(dbContext),
+ EXPECT_EQ(crs_4326->createBoundCRSToWGS84IfPossible(dbContext, false),
crs_4326);
}
{
auto crs_32631 = factory->createCoordinateReferenceSystem("32631");
- EXPECT_EQ(crs_32631->createBoundCRSToWGS84IfPossible(dbContext),
+ EXPECT_EQ(crs_32631->createBoundCRSToWGS84IfPossible(dbContext, false),
crs_32631);
}
{
// Pulkovo 42 East Germany
auto crs_5670 = factory->createCoordinateReferenceSystem("5670");
- EXPECT_EQ(crs_5670->createBoundCRSToWGS84IfPossible(dbContext),
+ EXPECT_EQ(crs_5670->createBoundCRSToWGS84IfPossible(dbContext, false),
crs_5670);
}
{
// Pulkovo 42 Romania
auto crs_3844 = factory->createCoordinateReferenceSystem("3844");
- auto bound = crs_3844->createBoundCRSToWGS84IfPossible(dbContext);
+ auto bound =
+ crs_3844->createBoundCRSToWGS84IfPossible(dbContext, false);
EXPECT_NE(bound, crs_3844);
- EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext), bound);
+ EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext, false),
+ bound);
auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(bound);
ASSERT_TRUE(boundCRS != nullptr);
EXPECT_EQ(boundCRS->exportToPROJString(
@@ -4760,9 +4815,11 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
{
// Pulkovo 42 Poland
auto crs_2171 = factory->createCoordinateReferenceSystem("2171");
- auto bound = crs_2171->createBoundCRSToWGS84IfPossible(dbContext);
+ auto bound =
+ crs_2171->createBoundCRSToWGS84IfPossible(dbContext, false);
EXPECT_NE(bound, crs_2171);
- EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext), bound);
+ EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext, false),
+ bound);
auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(bound);
ASSERT_TRUE(boundCRS != nullptr);
EXPECT_EQ(boundCRS->exportToPROJString(
@@ -4777,9 +4834,11 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
{
// NTF (Paris)
auto crs_4807 = factory->createCoordinateReferenceSystem("4807");
- auto bound = crs_4807->createBoundCRSToWGS84IfPossible(dbContext);
+ auto bound =
+ crs_4807->createBoundCRSToWGS84IfPossible(dbContext, false);
EXPECT_NE(bound, crs_4807);
- EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext), bound);
+ EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext, false),
+ bound);
auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(bound);
ASSERT_TRUE(boundCRS != nullptr);
EXPECT_EQ(boundCRS->exportToPROJString(
@@ -4792,9 +4851,11 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
{
// NTF (Paris) / Lambert zone II + NGF-IGN69 height
auto crs_7421 = factory->createCoordinateReferenceSystem("7421");
- auto bound = crs_7421->createBoundCRSToWGS84IfPossible(dbContext);
+ auto bound =
+ crs_7421->createBoundCRSToWGS84IfPossible(dbContext, false);
EXPECT_NE(bound, crs_7421);
- EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext), bound);
+ EXPECT_EQ(bound->createBoundCRSToWGS84IfPossible(dbContext, false),
+ bound);
auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(bound);
ASSERT_TRUE(boundCRS != nullptr);
EXPECT_EQ(boundCRS->exportToPROJString(
@@ -4808,13 +4869,13 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
}
{
auto crs = createVerticalCRS();
- EXPECT_EQ(crs->createBoundCRSToWGS84IfPossible(dbContext), crs);
+ EXPECT_EQ(crs->createBoundCRSToWGS84IfPossible(dbContext, false), crs);
}
{
auto factoryIGNF =
AuthorityFactory::create(DatabaseContext::create(), "IGNF");
auto crs = factoryIGNF->createCoordinateReferenceSystem("TERA50STEREO");
- auto bound = crs->createBoundCRSToWGS84IfPossible(dbContext);
+ auto bound = crs->createBoundCRSToWGS84IfPossible(dbContext, false);
EXPECT_NE(bound, crs);
auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(bound);
ASSERT_TRUE(boundCRS != nullptr);
@@ -4830,7 +4891,7 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
auto factoryIGNF =
AuthorityFactory::create(DatabaseContext::create(), "IGNF");
auto crs = factoryIGNF->createCoordinateReferenceSystem("PGP50");
- auto bound = crs->createBoundCRSToWGS84IfPossible(dbContext);
+ auto bound = crs->createBoundCRSToWGS84IfPossible(dbContext, false);
EXPECT_NE(bound, crs);
auto boundCRS = nn_dynamic_pointer_cast<BoundCRS>(bound);
ASSERT_TRUE(boundCRS != nullptr);
@@ -4841,6 +4902,11 @@ TEST(crs, crs_createBoundCRSToWGS84IfPossible) {
"+proj=geocent +ellps=intl "
"+towgs84=324.8,153.6,172.1,0,0,0,0 +units=m +no_defs");
}
+ {
+ auto crs = factory->createCoordinateReferenceSystem("4269"); // NAD83
+ auto bound = crs->createBoundCRSToWGS84IfPossible(dbContext, false);
+ EXPECT_EQ(bound, crs);
+ }
}
// ---------------------------------------------------------------------------
@@ -5023,3 +5089,58 @@ TEST(crs, alterParametersLinearUnit) {
<< wkt;
}
}
+
+// ---------------------------------------------------------------------------
+
+TEST(crs, getNonDeprecated) {
+ auto dbContext = DatabaseContext::create();
+ auto factory = AuthorityFactory::create(dbContext, "EPSG");
+
+ {
+ // No id
+ auto crs = ProjectedCRS::create(
+ PropertyMap(), GeographicCRS::EPSG_4326,
+ Conversion::createUTM(PropertyMap(), 31, true),
+ CartesianCS::createEastingNorthing(UnitOfMeasure::METRE));
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 0);
+ }
+
+ {
+ // Non-deprecated
+ auto crs = factory->createGeodeticCRS("4326");
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 0);
+ }
+
+ {
+ // Non supported CRS type
+ auto crs = BoundCRS::createFromTOWGS84(
+ createProjected(), std::vector<double>{1, 2, 3, 4, 5, 6, 7});
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 0);
+ }
+
+ {
+ auto crs = factory->createGeodeticCRS("4226");
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 2);
+ }
+
+ {
+ auto crs = factory->createProjectedCRS("26591");
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 1);
+ }
+
+ {
+ auto crs = factory->createVerticalCRS("5704");
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 1);
+ }
+ {
+ auto crs = factory->createCompoundCRS("7401");
+ auto list = crs->getNonDeprecated(dbContext);
+ ASSERT_EQ(list.size(), 1);
+ }
+}
diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp
index 057f1717..e5734cd1 100644
--- a/test/unit/test_operation.cpp
+++ b/test/unit/test_operation.cpp
@@ -5941,7 +5941,7 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) {
AuthorityFactory::create(DatabaseContext::create(), "EPSG")
->createCoordinateReferenceSystem("4326"),
ctxt);
- ASSERT_GE(list2.size(), 4U);
+ ASSERT_GE(list2.size(), 3U);
EXPECT_EQ(replaceAll(list2[0]->exportToPROJString(
PROJStringFormatter::create().get()),
@@ -5950,10 +5950,8 @@ TEST(operation, IGNF_LAMB1_TO_EPSG_4326) {
// The second entry in list2 (list2[1]) uses the
// weird +pm=2.33720833333333 from "NTF (Paris) to NTF (2)"
- // and the third one uses the ESRI geographic offset method with another
- // value
- // so skip to the 4th method
- EXPECT_EQ(replaceAll(list2[3]->exportToPROJString(
+ // 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()));