diff --git a/docs/source/apps/projinfo.rst b/docs/source/apps/projinfo.rst index 611b079967..05a88fbb46 100644 --- a/docs/source/apps/projinfo.rst +++ b/docs/source/apps/projinfo.rst @@ -35,7 +35,8 @@ Synopsis | --list-crs [list-crs-filter] | | --dump-db-structure [{object_definition} | {object_reference}] | | {object_definition} | {object_reference} | - | (-s {srs_def} [--s_epoch {epoch}] -t {srs_def} [--t_epoch {epoch}]) + | (-s {srs_def} [--s_epoch {epoch}] -t {srs_def} [--t_epoch {epoch}]) | + | ({srs_def} {srs_def}) | where {object_definition} or {srs_def} is one of the possibilities accepted @@ -66,6 +67,8 @@ Synopsis file referenced by the {object_reference} must contain a valid {object_definition}. + The usage of "{srs_def} {srs_def}" is equivalent to "-s {srs_def} -t {srs_def}" (*added in 9.5*). + Description *********** diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 45a78c8209..b432e0867d 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -122,8 +122,9 @@ struct OutputOptions { << " {object_definition} | {object_reference} |" << std::endl << " (-s {srs_def} [--s_epoch {epoch}] " - "-t {srs_def} [--t_epoch {epoch}])" - << std::endl; + "-t {srs_def} [--t_epoch {epoch}]) |" + << std::endl + << " ({srs_def} {srs_def})" << std::endl; std::cerr << std::endl; std::cerr << "-o: formats is a comma separated combination of: " "all,default,PROJ,WKT_ALL,WKT2:2015,WKT2:2019,WKT1:GDAL," @@ -1042,8 +1043,7 @@ int main(int argc, char **argv) { usage(); } - std::string user_string; - bool user_string_specified = false; + std::vector positional_args; std::string sourceCRSStr; std::string sourceEpoch; std::string targetCRSStr; @@ -1405,13 +1405,7 @@ int main(int argc, char **argv) { std::cerr << "Unrecognized option: " << arg << std::endl; usage(); } else { - if (!user_string_specified) { - user_string_specified = true; - user_string = arg; - } else { - std::cerr << "Too many parameters: " << arg << std::endl; - usage(); - } + positional_args.push_back(arg); } } @@ -1420,7 +1414,8 @@ int main(int argc, char **argv) { std::exit(1); } - if (dumpDbStructure && user_string_specified && !outputSwitchSpecified) { + if (dumpDbStructure && positional_args.size() == 1 && + !outputSwitchSpecified) { // Implicit settings in --output-db-structure mode + object outputSwitchSpecified = true; outputOpt.SQL = true; @@ -1569,6 +1564,19 @@ int main(int argc, char **argv) { } } + std::string user_string; + if (sourceCRSStr.empty() && targetCRSStr.empty() && + positional_args.size() == 2) { + sourceCRSStr = positional_args[0]; + targetCRSStr = positional_args[1]; + positional_args.resize(0); + } else if (positional_args.size() == 1) { + user_string = positional_args.front(); + } else if (positional_args.size() > 1) { + std::cerr << "Too many parameters: " << positional_args[1] << std::endl; + usage(); + } + if (!sourceCRSStr.empty() && targetCRSStr.empty()) { std::cerr << "Source CRS specified, but missing target CRS" << std::endl; @@ -1578,11 +1586,11 @@ int main(int argc, char **argv) { << std::endl; usage(); } else if (!sourceCRSStr.empty() && !targetCRSStr.empty()) { - if (user_string_specified) { + if (!positional_args.empty()) { std::cerr << "Unused extra value" << std::endl; usage(); } - } else if (!user_string_specified) { + } else if (positional_args.empty()) { if (dumpDbStructure || listCRSSpecified) { std::exit(0); } diff --git a/test/cli/test_projinfo.yaml b/test/cli/test_projinfo.yaml index b01ec90c13..58f1f1c1dd 100644 --- a/test/cli/test_projinfo.yaml +++ b/test/cli/test_projinfo.yaml @@ -315,6 +315,24 @@ tests: WKT2:2019 string: CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]],ID["EPSG",16031]] +- args: EPSG:4326 EPSG:32631 --single-line + out: | + Candidate operations found: 1 + ------------------------------------- + Operation No. 1: + + EPSG:16031, UTM zone 31N, 0 m, Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. + + PROJ string: + +proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=utm +zone=31 +ellps=WGS84 + + WKT2:2019 string: + CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]],ID["EPSG",16031]] +- args: EPSG:4326 EPSG:32631 EPSG:4327 + grep: Too many parameters + stderr: | + Too many parameters: EPSG:32631 + exitcode: 1 - args: --source-crs NAD27 --target-crs NAD83 out: | Candidate operations found: 1 @@ -371,6 +389,62 @@ tests: SCOPE["unknown"], AREA["World"], BBOX[-90,-180,90,180]]] +- args: NAD27 NAD83 + out: | + Candidate operations found: 1 + Note: using '--spatial-test intersects' would bring more results (10) + ------------------------------------- + Operation No. 1: + + unknown id, Ballpark geographic offset from NAD27 to NAD83, unknown accuracy, World, has ballpark transformation + + PROJ string: + +proj=noop + + WKT2:2019 string: + COORDINATEOPERATION["Ballpark geographic offset from NAD27 to NAD83", + SOURCECRS[ + GEOGCRS["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]], + ID["EPSG",4267]]], + TARGETCRS[ + GEOGCRS["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]], + ID["EPSG",4269]]], + METHOD["Geographic2D offsets", + ID["EPSG",9619]], + PARAMETER["Latitude offset",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8601]], + PARAMETER["Longitude offset",0, + ANGLEUNIT["degree",0.0174532925199433], + ID["EPSG",8602]], + USAGE[ + SCOPE["unknown"], + AREA["World"], + BBOX[-90,-180,90,180]]] - args: -s NAD27 -t NAD83 --grid-check none --spatial-test intersects --summary --hide-ballpark out: | Candidate operations found: 9