From 35425763e70b70f7efc9a5c9616695369609553f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 12 Mar 2020 18:36:39 +0100 Subject: [PATCH 1/2] Add proj_get_units_from_database() (fixes #2004) --- data/sql/customizations.sql | 32 +++ data/sql/proj_db_table_defs.sql | 1 + data/sql/unit_of_measure.sql | 190 +++++++++--------- .../development/reference/functions.rst | 3 + include/proj/io.hpp | 30 ++- scripts/build_db.py | 2 +- src/iso19111/c_api.cpp | 127 +++++++++++- src/iso19111/factory.cpp | 58 ++++++ src/proj.h | 42 ++++ test/unit/test_c_api.cpp | 42 ++++ test/unit/test_factory.cpp | 84 +++++++- 11 files changed, 497 insertions(+), 114 deletions(-) diff --git a/data/sql/customizations.sql b/data/sql/customizations.sql index 82328f3cb6..fd67b8a1b3 100644 --- a/data/sql/customizations.sql +++ b/data/sql/customizations.sql @@ -135,3 +135,35 @@ INSERT INTO "alias_name" VALUES('geodetic_datum','EPSG','6312','hermannskogel',' INSERT INTO "alias_name" VALUES('geodetic_datum','EPSG','6299','ire65','PROJ'); INSERT INTO "alias_name" VALUES('geodetic_datum','EPSG','6272','nzgd49','PROJ'); INSERT INTO "alias_name" VALUES('geodetic_datum','EPSG','6277','OSGB36','PROJ'); + +---- PROJ unit short names ----- + +-- Linear units +UPDATE unit_of_measure SET proj_short_name = 'mm' WHERE auth_name = 'EPSG' AND code = '1025'; +UPDATE unit_of_measure SET proj_short_name = 'cm' WHERE auth_name = 'EPSG' AND code = '1033'; +UPDATE unit_of_measure SET proj_short_name = 'm' WHERE auth_name = 'EPSG' AND code = '9001'; +UPDATE unit_of_measure SET proj_short_name = 'ft' WHERE auth_name = 'EPSG' AND code = '9002'; +UPDATE unit_of_measure SET proj_short_name = 'us-ft' WHERE auth_name = 'EPSG' AND code = '9003'; +UPDATE unit_of_measure SET proj_short_name = 'fath' WHERE auth_name = 'EPSG' AND code = '9014'; +UPDATE unit_of_measure SET proj_short_name = 'kmi' WHERE auth_name = 'EPSG' AND code = '9030'; +UPDATE unit_of_measure SET proj_short_name = 'us-ch' WHERE auth_name = 'EPSG' AND code = '9033'; +UPDATE unit_of_measure SET proj_short_name = 'us-mi' WHERE auth_name = 'EPSG' AND code = '9035'; +UPDATE unit_of_measure SET proj_short_name = 'km' WHERE auth_name = 'EPSG' AND code = '9036'; +UPDATE unit_of_measure SET proj_short_name = 'ind-ft' WHERE auth_name = 'EPSG' AND code = '9081'; +UPDATE unit_of_measure SET proj_short_name = 'ind-yd' WHERE auth_name = 'EPSG' AND code = '9085'; +UPDATE unit_of_measure SET proj_short_name = 'mi' WHERE auth_name = 'EPSG' AND code = '9093'; +UPDATE unit_of_measure SET proj_short_name = 'yd' WHERE auth_name = 'EPSG' AND code = '9096'; +UPDATE unit_of_measure SET proj_short_name = 'ch' WHERE auth_name = 'EPSG' AND code = '9097'; +UPDATE unit_of_measure SET proj_short_name = 'link' WHERE auth_name = 'EPSG' AND code = '9098'; + +-- Angular units +UPDATE unit_of_measure SET proj_short_name = 'rad' WHERE auth_name = 'EPSG' AND code = '9101'; +UPDATE unit_of_measure SET proj_short_name = 'deg' WHERE auth_name = 'EPSG' AND code = '9102'; +UPDATE unit_of_measure SET proj_short_name = 'grad' WHERE auth_name = 'EPSG' AND code = '9105'; + +-- PROJ specific units +INSERT INTO "unit_of_measure" VALUES('PROJ','DM','decimeter','length',0.01,'dm',0); +INSERT INTO "unit_of_measure" VALUES('PROJ','IN','inch','length',0.0254,'in',0); +INSERT INTO "unit_of_measure" VALUES('PROJ','US_IN','US survey inch','length',0.025400050800101,'us-in',0); +INSERT INTO "unit_of_measure" VALUES('PROJ','US_YD','US survey yard','length',0.914401828803658,'us-yd',0); +INSERT INTO "unit_of_measure" VALUES('PROJ','IND_CH','Indian chain','length',20.11669506,'ind-ch',0); diff --git a/data/sql/proj_db_table_defs.sql b/data/sql/proj_db_table_defs.sql index 166929af6d..df20de318d 100644 --- a/data/sql/proj_db_table_defs.sql +++ b/data/sql/proj_db_table_defs.sql @@ -14,6 +14,7 @@ CREATE TABLE unit_of_measure( name TEXT NOT NULL CHECK (length(name) >= 2), type TEXT NOT NULL CHECK (type IN ('length', 'angle', 'scale', 'time')), conv_factor FLOAT, + proj_short_name TEXT, -- PROJ string name, like 'm', 'ft'. Might be NULL deprecated BOOLEAN NOT NULL CHECK (deprecated IN (0, 1)), CONSTRAINT pk_unit_of_measure PRIMARY KEY (auth_name, code) ); diff --git a/data/sql/unit_of_measure.sql b/data/sql/unit_of_measure.sql index a3011c9429..d361c1595a 100644 --- a/data/sql/unit_of_measure.sql +++ b/data/sql/unit_of_measure.sql @@ -1,97 +1,97 @@ --- This file has been generated by scripts/build_db.py. DO NOT EDIT ! -INSERT INTO "unit_of_measure" VALUES('EPSG','1024','bin','scale',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1025','millimetre','length',0.001,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1026','metre per second','length',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1027','millimetres per year','length',3.16887651727314875889e-11,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1028','parts per billion','scale',1.0e-09,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1029','year','time',31556925.445,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1030','parts per billion per year','scale',3.16887651727314834646e-17,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1031','milliarc-second','angle',4.84813681109535528357e-09,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1032','milliarc-seconds per year','angle',1.53631468932075975278e-16,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1033','centimetre','length',0.01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1034','centimetres per year','length',3.1688765172731483714e-10,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1035','radian per second','angle',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1036','unity per second','scale',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1040','second','time',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1041','parts per million per year','scale',3.1688765172731486173e-14,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1042','metres per year','length',3.16887651727314861947e-08,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','1043','arc-seconds per year','angle',1.53631468932075975646e-13,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9001','metre','length',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9002','foot','length',0.3048,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9003','US survey foot','length',3.04800609601219241184e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9005','Clarke''s foot','length',0.3047972654,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9014','fathom','length',1.8288,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9030','nautical mile','length',1852.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9031','German legal metre','length',1.0000135965,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9033','US survey chain','length',2.01168402336804703618e+01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9034','US survey link','length',2.0116840233680469141e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9035','US survey mile','length',1.60934721869443751532e+03,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9036','kilometre','length',1000.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9037','Clarke''s yard','length',0.9143917962,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9038','Clarke''s chain','length',20.1166195164,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9039','Clarke''s link','length',0.201166195164,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9040','British yard (Sears 1922)','length',9.14398414616028665236e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9041','British foot (Sears 1922)','length',3.04799471538676203241e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9042','British chain (Sears 1922)','length',2.01167651215526319683e+01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9043','British link (Sears 1922)','length',2.01167651215526294139e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9050','British yard (Benoit 1895 A)','length',0.9143992,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9051','British foot (Benoit 1895 A)','length',3.04799733333333322526e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9052','British chain (Benoit 1895 A)','length',20.1167824,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9053','British link (Benoit 1895 A)','length',0.201167824,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9060','British yard (Benoit 1895 B)','length',9.14399204289812361778e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9061','British foot (Benoit 1895 B)','length',3.04799734763270768755e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9062','British chain (Benoit 1895 B)','length',2.01167824943758724023e+01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9063','British link (Benoit 1895 B)','length',2.01167824943758705158e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9070','British foot (1865)','length',3.04800833333333354158e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9080','Indian foot','length',3.04799510248146943158e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9081','Indian foot (1937)','length',0.30479841,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9082','Indian foot (1962)','length',0.3047996,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9083','Indian foot (1975)','length',0.3047995,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9084','Indian yard','length',9.14398530744440773965e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9085','Indian yard (1937)','length',0.91439523,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9086','Indian yard (1962)','length',0.9143988,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9087','Indian yard (1975)','length',0.9143985,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9093','Statute mile','length',1609.344,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9094','Gold Coast foot','length',3.04799710181508809458e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9095','British foot (1936)','length',0.3048007491,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9096','yard','length',0.9144,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9097','chain','length',20.1168,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9098','link','length',0.201168,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9099','British yard (Sears 1922 truncated)','length',0.914398,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9101','radian','angle',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9102','degree','angle',1.74532925199432781271e-02,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9103','arc-minute','angle',2.90888208665721309346e-04,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9104','arc-second','angle',4.84813681109535476055e-06,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9105','grad','angle',1.57079632679489496205e-02,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9106','gon','angle',1.57079632679489496205e-02,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9107','degree minute second','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9108','degree minute second hemisphere','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9109','microradian','angle',1.0e-06,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9110','sexagesimal DMS','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9111','sexagesimal DM','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9112','centesimal minute','angle',1.57079632679489491868e-04,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9113','centesimal second','angle',1.57079632679489496951e-06,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9114','mil_6400','angle',9.81747704246809351283e-04,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9115','degree minute','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9116','degree hemisphere','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9117','hemisphere degree','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9118','degree minute hemisphere','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9119','hemisphere degree minute','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9120','hemisphere degree minute second','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9121','sexagesimal DMS.s','angle',NULL,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9122','degree (supplier to define representation)','angle',1.74532925199432781271e-02,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9201','unity','scale',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9202','parts per million','scale',1.0e-06,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9203','coefficient','scale',1.0,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9204','Bin width 330 US survey feet','length',1.00584201168402344707e+02,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9205','Bin width 165 US survey feet','length',5.02921005842011723538e+01,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9206','Bin width 82.5 US survey feet','length',2.51460502921005861769e+01,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9207','Bin width 37.5 metres','length',37.5,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9208','Bin width 25 metres','length',25.0,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9209','Bin width 12.5 metres','length',12.5,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9210','Bin width 6.25 metres','length',6.25,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9211','Bin width 3.125 metres','length',3.125,1); -INSERT INTO "unit_of_measure" VALUES('EPSG','9300','British foot (Sears 1922 truncated)','length',3.04799333333333366535e-01,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9301','British chain (Sears 1922 truncated)','length',20.116756,0); -INSERT INTO "unit_of_measure" VALUES('EPSG','9302','British link (Sears 1922 truncated)','length',0.20116756,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1024','bin','scale',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1025','millimetre','length',0.001,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1026','metre per second','length',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1027','millimetres per year','length',3.16887651727314875889e-11,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1028','parts per billion','scale',1.0e-09,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1029','year','time',31556925.445,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1030','parts per billion per year','scale',3.16887651727314834646e-17,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1031','milliarc-second','angle',4.84813681109535528357e-09,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1032','milliarc-seconds per year','angle',1.53631468932075975278e-16,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1033','centimetre','length',0.01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1034','centimetres per year','length',3.1688765172731483714e-10,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1035','radian per second','angle',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1036','unity per second','scale',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1040','second','time',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1041','parts per million per year','scale',3.1688765172731486173e-14,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1042','metres per year','length',3.16887651727314861947e-08,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','1043','arc-seconds per year','angle',1.53631468932075975646e-13,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9001','metre','length',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9002','foot','length',0.3048,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9003','US survey foot','length',3.04800609601219241184e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9005','Clarke''s foot','length',0.3047972654,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9014','fathom','length',1.8288,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9030','nautical mile','length',1852.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9031','German legal metre','length',1.0000135965,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9033','US survey chain','length',2.01168402336804703618e+01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9034','US survey link','length',2.0116840233680469141e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9035','US survey mile','length',1.60934721869443751532e+03,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9036','kilometre','length',1000.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9037','Clarke''s yard','length',0.9143917962,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9038','Clarke''s chain','length',20.1166195164,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9039','Clarke''s link','length',0.201166195164,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9040','British yard (Sears 1922)','length',9.14398414616028665236e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9041','British foot (Sears 1922)','length',3.04799471538676203241e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9042','British chain (Sears 1922)','length',2.01167651215526319683e+01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9043','British link (Sears 1922)','length',2.01167651215526294139e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9050','British yard (Benoit 1895 A)','length',0.9143992,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9051','British foot (Benoit 1895 A)','length',3.04799733333333322526e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9052','British chain (Benoit 1895 A)','length',20.1167824,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9053','British link (Benoit 1895 A)','length',0.201167824,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9060','British yard (Benoit 1895 B)','length',9.14399204289812361778e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9061','British foot (Benoit 1895 B)','length',3.04799734763270768755e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9062','British chain (Benoit 1895 B)','length',2.01167824943758724023e+01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9063','British link (Benoit 1895 B)','length',2.01167824943758705158e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9070','British foot (1865)','length',3.04800833333333354158e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9080','Indian foot','length',3.04799510248146943158e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9081','Indian foot (1937)','length',0.30479841,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9082','Indian foot (1962)','length',0.3047996,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9083','Indian foot (1975)','length',0.3047995,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9084','Indian yard','length',9.14398530744440773965e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9085','Indian yard (1937)','length',0.91439523,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9086','Indian yard (1962)','length',0.9143988,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9087','Indian yard (1975)','length',0.9143985,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9093','Statute mile','length',1609.344,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9094','Gold Coast foot','length',3.04799710181508809458e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9095','British foot (1936)','length',0.3048007491,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9096','yard','length',0.9144,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9097','chain','length',20.1168,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9098','link','length',0.201168,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9099','British yard (Sears 1922 truncated)','length',0.914398,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9101','radian','angle',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9102','degree','angle',1.74532925199432781271e-02,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9103','arc-minute','angle',2.90888208665721309346e-04,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9104','arc-second','angle',4.84813681109535476055e-06,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9105','grad','angle',1.57079632679489496205e-02,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9106','gon','angle',1.57079632679489496205e-02,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9107','degree minute second','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9108','degree minute second hemisphere','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9109','microradian','angle',1.0e-06,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9110','sexagesimal DMS','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9111','sexagesimal DM','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9112','centesimal minute','angle',1.57079632679489491868e-04,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9113','centesimal second','angle',1.57079632679489496951e-06,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9114','mil_6400','angle',9.81747704246809351283e-04,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9115','degree minute','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9116','degree hemisphere','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9117','hemisphere degree','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9118','degree minute hemisphere','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9119','hemisphere degree minute','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9120','hemisphere degree minute second','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9121','sexagesimal DMS.s','angle',NULL,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9122','degree (supplier to define representation)','angle',1.74532925199432781271e-02,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9201','unity','scale',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9202','parts per million','scale',1.0e-06,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9203','coefficient','scale',1.0,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9204','Bin width 330 US survey feet','length',1.00584201168402344707e+02,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9205','Bin width 165 US survey feet','length',5.02921005842011723538e+01,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9206','Bin width 82.5 US survey feet','length',2.51460502921005861769e+01,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9207','Bin width 37.5 metres','length',37.5,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9208','Bin width 25 metres','length',25.0,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9209','Bin width 12.5 metres','length',12.5,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9210','Bin width 6.25 metres','length',6.25,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9211','Bin width 3.125 metres','length',3.125,NULL,1); +INSERT INTO "unit_of_measure" VALUES('EPSG','9300','British foot (Sears 1922 truncated)','length',3.04799333333333366535e-01,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9301','British chain (Sears 1922 truncated)','length',20.116756,NULL,0); +INSERT INTO "unit_of_measure" VALUES('EPSG','9302','British link (Sears 1922 truncated)','length',0.20116756,NULL,0); diff --git a/docs/source/development/reference/functions.rst b/docs/source/development/reference/functions.rst index 983e8a506e..2d68ff685b 100644 --- a/docs/source/development/reference/functions.rst +++ b/docs/source/development/reference/functions.rst @@ -521,6 +521,9 @@ Lists entry of the returned array is a NULL-entry. The array is statically allocated and does not need to be freed after use. + Note: starting with PROJ 7.1, this function is deprecated by + :cpp:func:`proj_get_units_from_database` + :returns: :c:type:`PJ_UNITS*` .. c:function:: const PJ_PRIME_MERIDIANS* proj_list_prime_meridians(void) diff --git a/include/proj/io.hpp b/include/proj/io.hpp index 3dcf7928f5..f07f78b862 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -1013,6 +1013,8 @@ class PROJ_GCC_DLL AuthorityFactory { PROJ_DLL std::string getDescriptionText(const std::string &code) const; + // non-standard + /** CRS information */ struct CRSInfo { /** Authority name */ @@ -1049,7 +1051,33 @@ class PROJ_GCC_DLL AuthorityFactory { PROJ_DLL std::list getCRSInfoList() const; - // non-standard + /** Unit information */ + struct UnitInfo { + /** Authority name */ + std::string authName; + /** Code */ + std::string code; + /** Name */ + std::string name; + /** Category: one of "linear", "linear_per_time", "angular", + * "angular_per_time", "scale", "scale_per_time" or "time" */ + std::string category; + /** Conversion factor to the SI unit. + * It might be 0 in some cases to indicate no known conversion factor. + */ + double convFactor; + /** PROJ short name (may be empty) */ + std::string projShortName; + /** Whether the object is deprecated */ + bool deprecated; + + //! @cond Doxygen_Suppress + UnitInfo(); + //! @endcond + }; + + PROJ_DLL std::list getUnitList() const; + PROJ_DLL static AuthorityFactoryNNPtr create(const DatabaseContextNNPtr &context, const std::string &authorityName); diff --git a/scripts/build_db.py b/scripts/build_db.py index 6eed386776..5897a2d803 100755 --- a/scripts/build_db.py +++ b/scripts/build_db.py @@ -68,7 +68,7 @@ def ingest_epsg(): def fill_unit_of_measure(proj_db_cursor): proj_db_cursor.execute( - "INSERT INTO unit_of_measure SELECT ?, uom_code, unit_of_meas_name, unit_of_meas_type, factor_b / factor_c, deprecated FROM epsg.epsg_unitofmeasure", (EPSG_AUTHORITY,)) + "INSERT INTO unit_of_measure SELECT ?, uom_code, unit_of_meas_name, unit_of_meas_type, factor_b / factor_c, NULL, deprecated FROM epsg.epsg_unitofmeasure", (EPSG_AUTHORITY,)) def fill_ellipsoid(proj_db_cursor): diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index d5f299c2b2..1315266255 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -662,7 +662,8 @@ PJ *proj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name, // --------------------------------------------------------------------------- //! @cond Doxygen_Suppress -static const char *get_unit_category(UnitOfMeasure::Type type) { +static const char *get_unit_category(const std::string &unit_name, + UnitOfMeasure::Type type) { const char *ret = nullptr; switch (type) { case UnitOfMeasure::Type::UNKNOWN: @@ -672,19 +673,26 @@ static const char *get_unit_category(UnitOfMeasure::Type type) { ret = "none"; break; case UnitOfMeasure::Type::ANGULAR: - ret = "angular"; + ret = unit_name.find(" per ") != std::string::npos ? "angular_per_time" + : "angular"; break; case UnitOfMeasure::Type::LINEAR: - ret = "linear"; + ret = unit_name.find(" per ") != std::string::npos ? "linear_per_time" + : "linear"; break; case UnitOfMeasure::Type::SCALE: - ret = "scale"; + ret = unit_name.find(" per year") != std::string::npos || + unit_name.find(" per second") != std::string::npos + ? "scale_per_time" + : "scale"; break; case UnitOfMeasure::Type::TIME: ret = "time"; break; case UnitOfMeasure::Type::PARAMETRIC: - ret = "parametric"; + ret = unit_name.find(" per ") != std::string::npos + ? "parametric_per_time" + : "parametric"; break; } return ret; @@ -704,8 +712,9 @@ static const char *get_unit_category(UnitOfMeasure::Type type) { * @param out_conv_factor Pointer to a value to store the conversion * factor of the prime meridian longitude unit to radian. or NULL * @param out_category Pointer to a string value to store the parameter name. or - * NULL. This value might be "unknown", "none", "linear", "angular", "scale", - * "time" or "parametric"; + * NULL. This value might be "unknown", "none", "linear", "linear_per_time", + * "angular", "angular_per_time", "scale", "scale_per_time", "time", + * "parametric" or "parametric_per_time" * @return TRUE in case of success */ int proj_uom_get_info_from_database(PJ_CONTEXT *ctx, const char *auth_name, @@ -726,7 +735,7 @@ int proj_uom_get_info_from_database(PJ_CONTEXT *ctx, const char *auth_name, *out_conv_factor = obj->conversionToSI(); } if (out_category) { - *out_category = get_unit_category(obj->type()); + *out_category = get_unit_category(obj->name(), obj->type()); } ctx->cpp_context->autoCloseDbIfNeeded(); return true; @@ -2585,6 +2594,100 @@ void proj_crs_info_list_destroy(PROJ_CRS_INFO **list) { // --------------------------------------------------------------------------- +/** \brief Enumerate units from the database, taking into account various + * criteria. + * + * The returned object is an array of PROJ_UNIT_INFO* pointers, whose last + * entry is NULL. This array should be freed with proj_unit_list_destroy() + * + * @param ctx PROJ context, or NULL for default context + * @param auth_name Authority name, used to restrict the search. + * Or NULL for all authorities. + * @param category Filter by category, if this parameter is not NULL. Category + * is one of "linear", "linear_per_time", "angular", "angular_per_time", + * "scale", "scale_per_time" or "time" + * @param allow_deprecated whether we should return deprecated objects as well. + * @param out_result_count Output parameter pointing to an integer to receive + * the size of the result list. Might be NULL + * @return an array of PROJ_UNIT_INFO* pointers to be freed with + * proj_unit_list_destroy(), or NULL in case of error. + * + * @since 7.1 + */ +PROJ_UNIT_INFO **proj_get_units_from_database(PJ_CONTEXT *ctx, + const char *auth_name, + const char *category, + int allow_deprecated, + int *out_result_count) { + SANITIZE_CTX(ctx); + PROJ_UNIT_INFO **ret = nullptr; + int i = 0; + try { + auto factory = AuthorityFactory::create(getDBcontext(ctx), + auth_name ? auth_name : ""); + auto list = factory->getUnitList(); + ret = new PROJ_UNIT_INFO *[list.size() + 1]; + for (const auto &info : list) { + if (category && info.category != category) { + continue; + } + if (!allow_deprecated && info.deprecated) { + continue; + } + ret[i] = new PROJ_UNIT_INFO; + ret[i]->auth_name = pj_strdup(info.authName.c_str()); + ret[i]->code = pj_strdup(info.code.c_str()); + ret[i]->name = pj_strdup(info.name.c_str()); + ret[i]->category = pj_strdup(info.category.c_str()); + ret[i]->conv_factor = info.convFactor; + ret[i]->proj_short_name = + info.projShortName.empty() + ? nullptr + : pj_strdup(info.projShortName.c_str()); + ret[i]->deprecated = info.deprecated; + i++; + } + ret[i] = nullptr; + if (out_result_count) + *out_result_count = i; + ctx->cpp_context->autoCloseDbIfNeeded(); + return ret; + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + if (ret) { + ret[i + 1] = nullptr; + proj_unit_list_destroy(ret); + } + if (out_result_count) + *out_result_count = 0; + } + ctx->cpp_context->autoCloseDbIfNeeded(); + return nullptr; +} + +// --------------------------------------------------------------------------- + +/** \brief Destroy the result returned by + * proj_get_units_from_database(). + * + * @since 7.1 + */ +void proj_unit_list_destroy(PROJ_UNIT_INFO **list) { + if (list) { + for (int i = 0; list[i] != nullptr; i++) { + pj_dalloc(list[i]->auth_name); + pj_dalloc(list[i]->code); + pj_dalloc(list[i]->name); + pj_dalloc(list[i]->category); + pj_dalloc(list[i]->proj_short_name); + delete list[i]; + } + delete[] list; + } +} + +// --------------------------------------------------------------------------- + /** \brief Return the Conversion of a DerivedCRS (such as a ProjectedCRS), * or the Transformation from the baseCRS to the hubCRS of a BoundCRS * @@ -6749,8 +6852,9 @@ int proj_coordoperation_get_param_index(PJ_CONTEXT *ctx, * unit code. or NULL * @param out_unit_category Pointer to a string value to store the parameter * name. or - * NULL. This value might be "unknown", "none", "linear", "angular", "scale", - * "time" or "parametric"; + * NULL. This value might be "unknown", "none", "linear", "linear_per_time", + * "angular", "angular_per_time", "scale", "scale_per_time", "time", + * "parametric" or "parametric_per_time" * @return TRUE in case of success. */ @@ -6852,7 +6956,8 @@ int proj_coordoperation_get_param( *out_unit_code = unit.code().c_str(); } if (out_unit_category) { - *out_unit_category = get_unit_category(unit.type()); + *out_unit_category = + get_unit_category(unit.name(), unit.type()); } } } diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 1c83636771..6a707e0d10 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -5214,6 +5214,64 @@ std::list AuthorityFactory::getCRSInfoList() const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +AuthorityFactory::UnitInfo::UnitInfo() + : authName{}, code{}, name{}, category{}, convFactor{}, projShortName{}, + deprecated{} {} +//! @endcond + +// --------------------------------------------------------------------------- + +/** \brief Return the list of units. + * @throw FactoryException + * + * @since 7.1 + */ +std::list AuthorityFactory::getUnitList() const { + std::string sql = "SELECT auth_name, code, name, type, conv_factor, " + "proj_short_name, deprecated FROM unit_of_measure"; + ListOfParams params; + if (d->hasAuthorityRestriction()) { + sql += " WHERE auth_name = ?"; + params.emplace_back(d->authority()); + } + sql += " ORDER BY auth_name, code"; + + auto sqlRes = d->run(sql, params); + std::list res; + for (const auto &row : sqlRes) { + AuthorityFactory::UnitInfo info; + info.authName = row[0]; + info.code = row[1]; + info.name = row[2]; + const std::string &raw_category(row[3]); + if (raw_category == "length") { + info.category = info.name.find(" per ") != std::string::npos + ? "linear_per_time" + : "linear"; + } else if (raw_category == "angle") { + info.category = info.name.find(" per ") != std::string::npos + ? "angular_per_time" + : "angular"; + } else if (raw_category == "scale") { + info.category = + info.name.find(" per year") != std::string::npos || + info.name.find(" per second") != std::string::npos + ? "scale_per_time" + : "scale"; + } else { + info.category = raw_category; + } + info.convFactor = row[4].empty() ? 0 : c_locale_stod(row[4]); + info.projShortName = row[5]; + info.deprecated = row[6] == "1"; + res.emplace_back(info); + } + return res; +} + +// --------------------------------------------------------------------------- + /** \brief Gets the official name from a possibly alias name. * * @param aliasedName Alias name. diff --git a/src/proj.h b/src/proj.h index 90a11739c9..8f48217fb1 100644 --- a/src/proj.h +++ b/src/proj.h @@ -912,6 +912,39 @@ typedef struct int allow_deprecated; } PROJ_CRS_LIST_PARAMETERS; +/** \brief Structure given description of a unit. + * + * This structure may grow over time, and should not be directly allocated by + * client code. + * @since 7.1 + */ +typedef struct +{ + /** Authority name. */ + char* auth_name; + + /** Object code. */ + char* code; + + /** Object name. For example "metre", "US survey foot", etc. */ + char* name; + + /** Category of the unit: one of "linear", "linear_per_time", "angular", + * "angular_per_time", "scale", "scale_per_time" or "time" */ + char* category; + + /** Conversion factor to apply to transform from that unit to the + * corresponding SI unit (metre for "linear", radian for "angular", etc.). + * It might be 0 in some cases to indicate no known conversion factor. */ + double conv_factor; + + /** PROJ short name, like "m", "ft", "us-ft", etc... Might be NULL */ + char* proj_short_name; + + /** Whether the object is deprecated */ + int deprecated; +} PROJ_UNIT_INFO; + /**@}*/ @@ -1077,6 +1110,15 @@ PROJ_CRS_INFO PROJ_DLL **proj_get_crs_info_list_from_database( void PROJ_DLL proj_crs_info_list_destroy(PROJ_CRS_INFO** list); +PROJ_UNIT_INFO PROJ_DLL **proj_get_units_from_database( + PJ_CONTEXT *ctx, + const char *auth_name, + const char *category, + int allow_deprecated, + int *out_result_count); + +void PROJ_DLL proj_unit_list_destroy(PROJ_UNIT_INFO** list); + /* ------------------------------------------------------------------------- */ diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 0f1b906ec3..bcd14c0ff0 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -3401,6 +3401,48 @@ TEST_F(CApi, proj_get_crs_info_list_from_database) { // --------------------------------------------------------------------------- +TEST_F(CApi, proj_get_units_from_database) { + { proj_unit_list_destroy(nullptr); } + + { + auto list = proj_get_units_from_database(nullptr, nullptr, nullptr, + true, nullptr); + ASSERT_NE(list, nullptr); + ASSERT_NE(list[0], nullptr); + ASSERT_NE(list[0]->auth_name, nullptr); + ASSERT_NE(list[0]->code, nullptr); + ASSERT_NE(list[0]->name, nullptr); + proj_unit_list_destroy(list); + } + + { + int result_count = 0; + auto list = proj_get_units_from_database(nullptr, "EPSG", "linear", + false, &result_count); + ASSERT_NE(list, nullptr); + EXPECT_GT(result_count, 1); + EXPECT_EQ(list[result_count], nullptr); + bool found9001 = false; + for (int i = 0; i < result_count; i++) { + EXPECT_EQ(std::string(list[i]->auth_name), "EPSG"); + if (std::string(list[i]->code) == "9001") { + EXPECT_EQ(std::string(list[i]->name), "metre"); + EXPECT_EQ(std::string(list[i]->category), "linear"); + EXPECT_EQ(list[i]->conv_factor, 1.0); + ASSERT_NE(list[i]->proj_short_name, nullptr); + EXPECT_EQ(std::string(list[i]->proj_short_name), "m"); + EXPECT_EQ(list[i]->deprecated, 0); + found9001 = true; + } + EXPECT_EQ(list[i]->deprecated, 0); + } + EXPECT_TRUE(found9001); + proj_unit_list_destroy(list); + } +} + +// --------------------------------------------------------------------------- + TEST_F(CApi, proj_normalize_for_visualization) { { diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp index c7ae458e42..aee2f5721d 100644 --- a/test/unit/test_factory.cpp +++ b/test/unit/test_factory.cpp @@ -1401,16 +1401,18 @@ class FactoryWithTmpDatabase : public ::testing::Test { void populateWithFakeEPSG() { ASSERT_TRUE(execute("INSERT INTO unit_of_measure " - "VALUES('EPSG','9001','metre','length',1.0,0);")) + "VALUES('EPSG','9001','metre','length',1.0,NULL," + "0);")) << last_error(); ASSERT_TRUE(execute("INSERT INTO unit_of_measure " "VALUES('EPSG','9102','degree','angle',1." - "74532925199432781271e-02,0);")) + "74532925199432781271e-02,NULL,0);")) << last_error(); ASSERT_TRUE(execute( "INSERT INTO unit_of_measure VALUES('EPSG','9122','degree " "(supplier to " - "define representation)','angle',1.74532925199432781271e-02,0);")) + "define representation)','angle',1.74532925199432781271e-02,NULL," + "0);")) << last_error(); ASSERT_TRUE( execute("INSERT INTO area " @@ -1470,7 +1472,8 @@ class FactoryWithTmpDatabase : public ::testing::Test { << last_error(); ASSERT_TRUE(execute("INSERT INTO unit_of_measure " - "VALUES('EPSG','9201','unity','scale',1.0,0);")) + "VALUES('EPSG','9201','unity','scale',1.0," + "NULL,0);")) << last_error(); ASSERT_TRUE(execute( @@ -1547,7 +1550,7 @@ class FactoryWithTmpDatabase : public ::testing::Test { ASSERT_TRUE(execute( "INSERT INTO unit_of_measure VALUES('EPSG','9110','sexagesimal " - "DMS','angle',NULL,0);")) + "DMS','angle',NULL,NULL,0);")) << last_error(); ASSERT_TRUE(execute( @@ -2933,7 +2936,7 @@ TEST(factory, getCRSInfoList) { auto list = factory->getCRSInfoList(); EXPECT_GT(list.size(), 1U); bool foundEPSG = false; - bool foundIGNF = true; + bool foundIGNF = false; bool found4326 = false; for (const auto &info : list) { foundEPSG |= info.authName == "EPSG"; @@ -3023,4 +3026,73 @@ TEST(factory, getCRSInfoList) { EXPECT_TRUE(found6871); } } + +// --------------------------------------------------------------------------- + +TEST(factory, getUnitList) { + auto ctxt = DatabaseContext::create(); + { + auto factory = AuthorityFactory::create(ctxt, std::string()); + auto list = factory->getUnitList(); + EXPECT_GT(list.size(), 1U); + bool foundEPSG = false; + bool foundPROJ = false; + bool found1027 = false; + bool found1028 = false; + bool found1032 = false; + bool found1036 = false; + bool found9001 = false; + bool found9101 = false; + for (const auto &info : list) { + foundEPSG |= info.authName == "EPSG"; + foundPROJ |= info.authName == "PROJ"; + if (info.authName == "EPSG" && info.code == "1027") { + EXPECT_EQ(info.name, "millimetres per year"); + EXPECT_EQ(info.category, "linear_per_time"); + found1027 = true; + } else if (info.authName == "EPSG" && info.code == "1028") { + EXPECT_EQ(info.name, "parts per billion"); + EXPECT_EQ(info.category, "scale"); + found1028 = true; + } else if (info.authName == "EPSG" && info.code == "1032") { + EXPECT_EQ(info.name, "milliarc-seconds per year"); + EXPECT_EQ(info.category, "angular_per_time"); + found1032 = true; + } else if (info.authName == "EPSG" && info.code == "1036") { + EXPECT_EQ(info.name, "unity per second"); + EXPECT_EQ(info.category, "scale_per_time"); + found1036 = true; + } else if (info.authName == "EPSG" && info.code == "9001") { + EXPECT_EQ(info.name, "metre"); + EXPECT_EQ(info.category, "linear"); + EXPECT_EQ(info.convFactor, 1.0); + EXPECT_EQ(info.projShortName, "m"); + EXPECT_FALSE(info.deprecated); + found9001 = true; + } else if (info.authName == "EPSG" && info.code == "9101") { + EXPECT_EQ(info.name, "radian"); + EXPECT_EQ(info.category, "angular"); + EXPECT_FALSE(info.deprecated); + found9101 = true; + } + } + EXPECT_TRUE(foundEPSG); + EXPECT_TRUE(foundPROJ); + EXPECT_TRUE(found1027); + EXPECT_TRUE(found1028); + EXPECT_TRUE(found1032); + EXPECT_TRUE(found1036); + EXPECT_TRUE(found9001); + EXPECT_TRUE(found9101); + } + { + auto factory = AuthorityFactory::create(ctxt, "EPSG"); + auto list = factory->getUnitList(); + EXPECT_GT(list.size(), 1U); + for (const auto &info : list) { + EXPECT_EQ(info.authName, "EPSG"); + } + } +} + } // namespace From 2247841879faebe007ccade45d04027361d5d26c Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 13 Mar 2020 11:24:41 +0100 Subject: [PATCH 2/2] Tag proj_list_units() as deprecated --- src/apps/cs2cs.cpp | 17 ++++++++++++----- src/apps/geod.cpp | 17 ++++++++++++----- src/apps/geod_set.cpp | 24 +++++++++++++++--------- src/apps/proj.cpp | 17 ++++++++++++----- src/conversions/unitconvert.cpp | 4 +--- src/init.cpp | 2 +- src/iso19111/common.cpp | 3 ++- src/proj.h | 20 +++++++++++++++++++- src/proj_internal.h | 2 ++ src/units.cpp | 6 ++++++ test/unit/gie_self_tests.cpp | 6 ------ 11 files changed, 82 insertions(+), 36 deletions(-) diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 6c85d4aa44..affd2bec07 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -425,11 +425,18 @@ int main(int argc, char **argv) { (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units(); lu->id; ++lu) - (void)printf("%12s %-20s %s\n", lu->id, - lu->to_meter, lu->name); + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name ) + { + (void)printf("%12s %-20.15g %s\n", + units[i]->proj_short_name, + units[i]->conv_factor, + units[i]->name); + } + } + proj_unit_list_destroy(units); } else if (arg[1] == 'm') { /* list prime meridians */ const struct PJ_PRIME_MERIDIANS *lpm; diff --git a/src/apps/geod.cpp b/src/apps/geod.cpp index b46188d32f..919430ca97 100644 --- a/src/apps/geod.cpp +++ b/src/apps/geod.cpp @@ -185,11 +185,18 @@ noargument: emess(1,"missing argument for -%c",*arg); (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list of units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units();lu->id ; ++lu) - (void)printf("%12s %-20s %s\n", - lu->id, lu->to_meter, lu->name); + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name ) + { + (void)printf("%12s %-20.15g %s\n", + units[i]->proj_short_name, + units[i]->conv_factor, + units[i]->name); + } + } + proj_unit_list_destroy(units); } else emess(1,"invalid list option: l%c",arg[1]); exit( 0 ); diff --git a/src/apps/geod_set.cpp b/src/apps/geod_set.cpp index ed7edeb972..603f0d95ba 100644 --- a/src/apps/geod_set.cpp +++ b/src/apps/geod_set.cpp @@ -14,7 +14,6 @@ geod_set(int argc, char **argv) { paralist *start = nullptr, *curr; double es; char *name; - int i; /* put arguments into internal linked list */ if (argc <= 0) @@ -22,7 +21,7 @@ geod_set(int argc, char **argv) { start = curr = pj_mkparam(argv[0]); if (!curr) emess(1, "memory allocation failed"); - for (i = 1; curr != nullptr && i < argc; ++i) { + for (int i = 1; curr != nullptr && i < argc; ++i) { curr->next = pj_mkparam(argv[i]); if (!curr->next) emess(1, "memory allocation failed"); @@ -32,13 +31,20 @@ geod_set(int argc, char **argv) { if (pj_ell_set(pj_get_default_ctx(),start, &geod_a, &es)) emess(1,"ellipse setup failure"); /* set units */ if ((name = pj_param(nullptr,start, "sunits").s) != nullptr) { - const char *s; - const struct PJ_UNITS *unit_list = proj_list_units(); - for (i = 0; (s = unit_list[i].id) && strcmp(name, s) ; ++i) ; - if (!s) - emess(1,"%s unknown unit conversion id", name); - to_meter = unit_list[i].factor; - fr_meter = 1 / to_meter; + bool unit_found = false; + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name && + strcmp(units[i]->proj_short_name, name) == 0 ) { + unit_found = true; + to_meter = units[i]->conv_factor; + fr_meter = 1 / to_meter; + } + } + proj_unit_list_destroy(units); + if( !unit_found ) + emess(1,"%s unknown unit conversion id", name); } else to_meter = fr_meter = 1; geod_f = es/(1 + sqrt(1 - es)); diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index 852cea0436..0bf98b3a9f 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -380,11 +380,18 @@ int main(int argc, char **argv) { (void)printf("%9s %-16s %-16s %s\n", le->id, le->major, le->ell, le->name); } else if (arg[1] == 'u') { /* list units */ - const struct PJ_UNITS *lu; - - for (lu = proj_list_units(); lu->id ; ++lu) - (void)printf("%12s %-20s %s\n", - lu->id, lu->to_meter, lu->name); + auto units = proj_get_units_from_database(nullptr, nullptr, "linear", false, nullptr); + for( int i = 0; units && units[i]; i++ ) + { + if( units[i]->proj_short_name ) + { + (void)printf("%12s %-20.15g %s\n", + units[i]->proj_short_name, + units[i]->conv_factor, + units[i]->name); + } + } + proj_unit_list_destroy(units); } else emess(1,"invalid list option: l%c",arg[1]); exit(0); diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp index f8439aeeb9..6ce55b0220 100644 --- a/src/conversions/unitconvert.cpp +++ b/src/conversions/unitconvert.cpp @@ -393,9 +393,7 @@ static double get_unit_conversion_factor(const char* name, /***********************************************************************/ int i; const char* s; - const PJ_UNITS *units; - - units = proj_list_units(); + const PJ_UNITS *units = pj_list_linear_units(); /* Try first with linear units */ for (i = 0; (s = units[i].id) ; ++i) { diff --git a/src/init.cpp b/src/init.cpp index a25d1ccda8..101fc8ad5d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -738,7 +738,7 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO); /* Set units */ - units = proj_list_units(); + units = pj_list_linear_units(); s = nullptr; if ((name = pj_param(ctx, start, "sunits").s) != nullptr) { for (i = 0; (s = units[i].id) && strcmp(name, s) ; ++i) ; diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp index f2e4de4c8a..4606905b7d 100644 --- a/src/iso19111/common.cpp +++ b/src/iso19111/common.cpp @@ -39,6 +39,7 @@ #include "proj/internal/io_internal.hpp" #include "proj.h" +#include "proj_internal.h" #include // M_PI #include @@ -312,7 +313,7 @@ bool UnitOfMeasure::operator!=(const UnitOfMeasure &other) PROJ_PURE_DEFN { //! @cond Doxygen_Suppress std::string UnitOfMeasure::exportToPROJString() const { if (type() == Type::LINEAR) { - auto proj_units = proj_list_units(); + auto proj_units = pj_list_linear_units(); for (int i = 0; proj_units[i].id != nullptr; i++) { if (::fabs(proj_units[i].factor - conversionToSI()) < 1e-10 * conversionToSI()) { diff --git a/src/proj.h b/src/proj.h index 8f48217fb1..69aae6d85c 100644 --- a/src/proj.h +++ b/src/proj.h @@ -151,6 +151,24 @@ extern "C" { #endif #endif +#ifdef PROJ_SUPPRESS_DEPRECATION_MESSAGE + #define PROJ_DEPRECATED(decl, msg) decl +#elif defined(__has_extension) + #if __has_extension(attribute_deprecated_with_message) + #define PROJ_DEPRECATED(decl, msg) decl __attribute__ ((deprecated(msg))) + #elif defined(__GNUC__) + #define PROJ_DEPRECATED(decl, msg) decl __attribute__ ((deprecated)) + #else + #define PROJ_DEPRECATED(decl, msg) decl + #endif +#elif defined(__GNUC__) + #define PROJ_DEPRECATED(decl, msg) decl __attribute__ ((deprecated)) +#elif defined(_MSVC_VER) + #define PROJ_DEPRECATED(decl, msg) __declspec(deprecated(msg)) decl +#else + #define PROJ_DEPRECATED(decl, msg) decl +#endif + /* The version numbers should be updated with every release! **/ #define PROJ_VERSION_MAJOR 7 #define PROJ_VERSION_MINOR 1 @@ -608,7 +626,7 @@ PJ_INIT_INFO PROJ_DLL proj_init_info(const char *initname); /* Get lists of operations, ellipsoids, units and prime meridians. */ const PJ_OPERATIONS PROJ_DLL *proj_list_operations(void); const PJ_ELLPS PROJ_DLL *proj_list_ellps(void); -const PJ_UNITS PROJ_DLL *proj_list_units(void); +PROJ_DEPRECATED(const PJ_UNITS PROJ_DLL *proj_list_units(void), "Deprecated by proj_get_units_from_database"); const PJ_UNITS PROJ_DLL *proj_list_angular_units(void); const PJ_PRIME_MERIDIANS PROJ_DLL *proj_list_prime_meridians(void); diff --git a/src/proj_internal.h b/src/proj_internal.h index 8f73200d6f..78aff49f60 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -873,6 +873,8 @@ std::string PROJ_DLL pj_context_get_user_writable_directory(PJ_CONTEXT *ctx, boo void PROJ_DLL pj_context_set_user_writable_directory(PJ_CONTEXT* ctx, const std::string& path); std::string PROJ_DLL pj_get_relative_share_proj(PJ_CONTEXT *ctx); +const PJ_UNITS *pj_list_linear_units(); + /* classic public API */ #include "proj_api.h" diff --git a/src/units.cpp b/src/units.cpp index 34a71db13f..36f2d4c72d 100644 --- a/src/units.cpp +++ b/src/units.cpp @@ -36,6 +36,12 @@ pj_units[] = { {nullptr, nullptr, nullptr, 0.0} }; +// For internal use +const PJ_UNITS *pj_list_linear_units() +{ + return pj_units; +} + const PJ_UNITS *proj_list_units() { return pj_units; diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp index 720c13caab..6f1b3c3249 100644 --- a/test/unit/gie_self_tests.cpp +++ b/test/unit/gie_self_tests.cpp @@ -334,7 +334,6 @@ TEST(gie, info_functions) { const PJ_OPERATIONS *oper_list; const PJ_ELLPS *ellps_list; - const PJ_UNITS *unit_list; const PJ_PRIME_MERIDIANS *pm_list; char buf[40]; @@ -452,11 +451,6 @@ TEST(gie, info_functions) { n++; ASSERT_NE(n, 0U); - n = 0; - for (unit_list = proj_list_units(); unit_list->id; ++unit_list) - n++; - ASSERT_NE(n, 0U); - n = 0; for (pm_list = proj_list_prime_meridians(); pm_list->id; ++pm_list) n++;