From b3a20c5b9c6efbeb0d6f528aad1d4e6bb4332bfa Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Mon, 26 Oct 2020 13:58:42 -0400 Subject: Try to fix compiler complaints for max and constexpr sqrt --- src/apps/gie.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/apps') diff --git a/src/apps/gie.cpp b/src/apps/gie.cpp index 8940afde..2fe854fa 100644 --- a/src/apps/gie.cpp +++ b/src/apps/gie.cpp @@ -1124,7 +1124,7 @@ static const struct errno_vs_err_const lookup[] = { {"pjd_err_invalid_x_or_y" , -15}, {"pjd_err_wrong_format_dms_value" , -16}, {"pjd_err_non_conv_inv_meri_dist" , -17}, - {"pjd_err_non_con_inv_phi2" , -18}, + {"pjd_err_non_conv_sinhpsi2tanphi" , -18}, {"pjd_err_acos_asin_arg_too_large" , -19}, {"pjd_err_tolerance_condition" , -20}, {"pjd_err_conic_lat_equal" , -21}, -- cgit v1.2.3 From 1e5acb00a0c0fc2533b9bce2e5803da10ed1d8d6 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 8 Oct 2020 20:59:19 +0200 Subject: projinfo / createObjectsFromName(): support returning a datum ensemble --- src/apps/projinfo.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src/apps') diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 37b76346..6ee5925a 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -79,7 +79,8 @@ struct OutputOptions { static void usage() { std::cerr - << "usage: projinfo [-o formats] [-k crs|operation|datum|ellipsoid] " + << "usage: projinfo [-o formats] " + "[-k crs|operation|datum|ensemble|ellipsoid] " "[--summary] [-q]" << std::endl << " ([--area name_or_code] | " @@ -184,11 +185,11 @@ static BaseObjectNNPtr buildObject( auto urn = "urn:ogc:def:coordinateOperation:" + tokens[0] + "::" + tokens[1]; obj = createFromUserInput(urn, dbContext).as_nullable(); - } else if (kind == "ellipsoid" && tokens.size() == 2) { - auto urn = "urn:ogc:def:ellipsoid:" + tokens[0] + "::" + tokens[1]; - obj = createFromUserInput(urn, dbContext).as_nullable(); - } else if (kind == "datum" && tokens.size() == 2) { - auto urn = "urn:ogc:def:datum:" + tokens[0] + "::" + tokens[1]; + } else if ((kind == "ellipsoid" || kind == "datum" || + kind == "ensemble") && + tokens.size() == 2) { + auto urn = + "urn:ogc:def:" + kind + ":" + tokens[0] + "::" + tokens[1]; obj = createFromUserInput(urn, dbContext).as_nullable(); } else { // Convenience to be able to use C escaped strings... @@ -222,6 +223,9 @@ static BaseObjectNNPtr buildObject( AuthorityFactory::ObjectType::ELLIPSOID); else if (kind == "datum") allowedTypes.push_back(AuthorityFactory::ObjectType::DATUM); + else if (kind == "ensemble") + allowedTypes.push_back( + AuthorityFactory::ObjectType::DATUM_ENSEMBLE); constexpr size_t limitResultCount = 10; auto factory = AuthorityFactory::create(NN_NO_CHECK(dbContext), std::string()); @@ -929,6 +933,8 @@ int main(int argc, char **argv) { objectKind = "ellipsoid"; } else if (ci_equal(kind, "datum")) { objectKind = "datum"; + } else if (ci_equal(kind, "ensemble")) { + objectKind = "ensemble"; } else { std::cerr << "Unrecognized value for option -k: " << kind << std::endl; -- cgit v1.2.3 From af342bf74cd154b653a0f9d931d4ca17001650b9 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 10 Nov 2020 14:08:30 +0100 Subject: Allow cct to instantiate operations via object codes or names (#2419) Running cct like cct EPSG:8366 or cct "ITRF2014 to ETRF2014 (1)" is now possible. --- src/apps/cct.cpp | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index f7413872..4de3cf8e 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -77,6 +77,7 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-10-26 #include #include #include +#include #include "proj.h" #include "proj_internal.h" @@ -193,9 +194,8 @@ static void print(PJ_LOG_LEVEL log_level, const char *fmt, ...) { free( msg_buf ); } - int main(int argc, char **argv) { - PJ *P; + PJ *P = nullptr; PJ_COORD point; PJ_PROJ_INFO info; OPTARGS *o; @@ -292,8 +292,36 @@ int main(int argc, char **argv) { } /* Setup transformation */ - P = proj_create_argv (nullptr, o->pargc, o->pargv); - if ((nullptr==P) || (0==o->pargc)) { + if (o-> pargc == 0 && o->fargc > 0) { + /* Assume we got a auth:code combination */ + std::string input(o->fargv[0]); + auto n = input.find(":"); + if (n > 0) { + std::string auth = input.substr(0,n); + std::string code = input.substr(n+1, input.length()); + P = proj_create_from_database( + nullptr, auth.c_str(), code.c_str(), PJ_CATEGORY_COORDINATE_OPERATION, 0, nullptr + ); + } + if( P == nullptr ) { + /* if we didn't get a auth:code combo we try to see if the input matches */ + /* anything else */ + P = proj_create(nullptr, o->fargv[0]); + } + + /* If instantiating operation without +-options optargpm thinks the input is */ + /* a file, hence we move all o->fargv entries one place closer to the start */ + /* of the array. This effectively overwrites the input and only leaves a list */ + /* of files in o->fargv. */ + o->fargc = o->fargc-1; + for (int j=0; j < o->fargc; j++) { + o->fargv[j] = o->fargv[j+1]; + } + } else { + P = proj_create_argv (nullptr, o->pargc, o->pargv); + } + + if (nullptr==P) { print (PJ_LOG_ERROR, "%s: Bad transformation arguments - (%s)\n '%s -h' for help", o->progname, pj_strerrno (proj_errno(P)), o->progname); free (o); -- cgit v1.2.3 From 6be4e25c66e805218c851d67157e4d1ddc0a761e Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 10 Nov 2020 14:40:17 +0100 Subject: cct: allow @filename syntax Similarly as for projinfo, allow "cct @filename" to mean read filename and use its content as if it was provided inline. Useful for WKT or PROJJSON And a tiny improvements, when the object definition contains ':', only try proj_create_from_database() if the left part (authority name) matches a known authority, to avoid a warning. --- src/apps/cct.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index 4de3cf8e..c482efc2 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -77,6 +77,8 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-10-26 #include #include #include + +#include // std::ifstream #include #include "proj.h" @@ -293,20 +295,55 @@ int main(int argc, char **argv) { /* Setup transformation */ if (o-> pargc == 0 && o->fargc > 0) { - /* Assume we got a auth:code combination */ std::string input(o->fargv[0]); + + if (!input.empty() && input[0] == '@') { + std::ifstream fs; + auto filename = input.substr(1); + fs.open(filename, std::fstream::in | std::fstream::binary); + if (!fs.is_open()) { + std::cerr << "cannot open " << filename << std::endl; + std::exit(1); + } + input.clear(); + while (!fs.eof()) { + char buffer[256]; + fs.read(buffer, sizeof(buffer)); + input.append(buffer, static_cast(fs.gcount())); + if (input.size() > 100 * 1000) { + fs.close(); + std::cerr << "too big file " << filename << std::endl; + std::exit(1); + } + } + fs.close(); + } + + /* Assume we got a auth:code combination */ auto n = input.find(":"); if (n > 0) { std::string auth = input.substr(0,n); std::string code = input.substr(n+1, input.length()); - P = proj_create_from_database( - nullptr, auth.c_str(), code.c_str(), PJ_CATEGORY_COORDINATE_OPERATION, 0, nullptr - ); + // Check that the authority matches one of the known ones + auto authorityList = proj_get_authorities_from_database(nullptr); + if( authorityList ) + { + for( auto iter = authorityList; *iter; iter++ ) + { + if( *iter == auth ) { + P = proj_create_from_database( + nullptr, auth.c_str(), code.c_str(), + PJ_CATEGORY_COORDINATE_OPERATION, 0, nullptr); + break; + } + } + proj_string_list_destroy(authorityList); + } } if( P == nullptr ) { /* if we didn't get a auth:code combo we try to see if the input matches */ /* anything else */ - P = proj_create(nullptr, o->fargv[0]); + P = proj_create(nullptr, input.c_str()); } /* If instantiating operation without +-options optargpm thinks the input is */ -- cgit v1.2.3 From c560b7957664c32e2465e8425abaccc5a6b2607d Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 17 Nov 2020 12:39:48 +0100 Subject: cs2cs, cct, proj and geod: fflush(stdout) after each line to emit each result as soon as it is produced This is needed when working with pipes, when stdout is not an interactive terminal, and thus the behaviour is to have it buffered as a regular file, whereas with an interactive terminal, each newline character causes an implicit flush. --- src/apps/cct.cpp | 2 ++ src/apps/cs2cs.cpp | 1 + src/apps/geod.cpp | 1 + src/apps/proj.cpp | 3 +++ 4 files changed, 7 insertions(+) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index c482efc2..fa75267a 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -470,6 +470,8 @@ int main(int argc, char **argv) { decimals_distances, point.xyzt.z, point.xyzt.t, comment_delimiter, comment ); + if( fout == stdout ) + fflush(stdout); } proj_destroy(P); diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 58c164c9..1a33d444 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -217,6 +217,7 @@ static void process(FILE *fid) printf("%s", s); else printf("\n"); + fflush(stdout); } } diff --git a/src/apps/geod.cpp b/src/apps/geod.cpp index 919430ca..35a8e826 100644 --- a/src/apps/geod.cpp +++ b/src/apps/geod.cpp @@ -124,6 +124,7 @@ process(FILE *fid) { (void)fputs(rtodms(pline, al21, 0, 0), stdout); } (void)fputs(s, stdout); + fflush(stdout); } } diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index 0bf98b3a..c9bd8950 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -171,6 +171,7 @@ static void process(FILE *fid) { (void)fputs("\t<* * * * * *>", stdout); } (void)fputs(bin_in ? "\n" : s, stdout); + fflush(stdout); } } @@ -286,6 +287,8 @@ static void vprocess(FILE *fid) { (void)fputs(proj_rtodms(pline, facs.meridian_convergence, 0, 0), stdout); (void)printf(" [ %.8f ]\n", facs.meridian_convergence * RAD_TO_DEG); (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", facs.tissot_semimajor, facs.tissot_semiminor); + + fflush(stdout); } } -- cgit v1.2.3 From 2cbf659bfcdffe12a4e7e397553c886566b2e949 Mon Sep 17 00:00:00 2001 From: "J.H. van de Water" Date: Thu, 19 Nov 2020 10:52:29 +0100 Subject: Replace line feed in input line by null character As result of a modification in logging (adding a line feed), many changes had to be made in different places of cct.cpp. However, one missed the line feed in input to cct. As result of missing this, the output from cct showed a superfluous empty line after each output line, but only if the corresponding input line ended with comment. Replacing the LF in the "comment" string (present if the input line ended with comment) by a null character ('\0') solves this issue. Modification in logging? https://github.com/OSGeo/PROJ/commit/37da5e243191c04607597f6b8a77acfa017a5c99 ( cct: revise end-of-line handling in logging, and always output debug ) See also: https://github.com/OSGeo/PROJ/issues/1677 ( cct outputs excessive whitespace comments are included in input data ) --- src/apps/cct.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index fa75267a..b0e15e62 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -450,6 +450,11 @@ int main(int argc, char **argv) { colmax = MAX(colmax, columns_xyzt[i]); comment = column(buf, colmax+1); } + /* remove the line feed from comment, as logger() above, invoked + by print() below (output), will add one */ + size_t len = strlen(comment); + if (len >= 1) + comment[len - 1] = '\0'; comment_delimiter = (comment && *comment) ? whitespace : blank_comment; /* Time to print the result */ -- cgit v1.2.3 From 9419b42ade1f1d35a61c05f0f7ce9aab2eeff3c7 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Sun, 1 Nov 2020 13:34:32 +0100 Subject: Remove proj_api.h Removes proj_api.h from the public API. The contents of the header file has been moved to proj_internal.h verbatim and any references to proj_api.h has been changed to proj_internal.h. The documentation of proj_api.h has been removed. The only exception to this is the API migration guides which still mention the old API. Fixes #837 --- src/apps/emess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/apps') diff --git a/src/apps/emess.cpp b/src/apps/emess.cpp index 53018ba8..138cbf01 100644 --- a/src/apps/emess.cpp +++ b/src/apps/emess.cpp @@ -19,7 +19,7 @@ #include #include -#include "proj_api.h" +#include "proj_internal.h" #include "proj_config.h" #define EMESS_ROUTINE #include "emess.h" -- cgit v1.2.3 From 9e50c8c0e207191c4c7bb6883f7ad485df04fc2c Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Sun, 1 Nov 2020 14:56:17 +0100 Subject: Remove ACCEPT_USE_OF_DEPRECATED_PROJ_API_H macro --- src/apps/emess.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/apps') diff --git a/src/apps/emess.cpp b/src/apps/emess.cpp index 138cbf01..5a50cd25 100644 --- a/src/apps/emess.cpp +++ b/src/apps/emess.cpp @@ -9,10 +9,6 @@ # endif #endif -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif - #include #include #include -- cgit v1.2.3 From a74b985b5006c2d279353a245cfcb850cf7fcc94 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 17 Nov 2020 12:54:24 +0100 Subject: Remove pj_ctx_* functions and use their proj_context counterparts --- src/apps/cs2cs.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/apps') diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 1a33d444..92e4441e 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -468,10 +468,23 @@ int main(int argc, char **argv) { reverseout = 1; continue; case 'D': /* set debug level */ + { if (--argc <= 0) goto noargument; - pj_ctx_set_debug(pj_get_default_ctx(), atoi(*++argv)); + int log_level = atoi(*++argv); + if (log_level <= 0) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_NONE); + } else if (log_level == 1) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_ERROR); + } else if (log_level == 2) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_DEBUG); + } else if (log_level == 3) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_TRACE); + } else { + proj_log_level(pj_get_default_ctx(), PJ_LOG_TELL); + } continue; + } case 'd': if (--argc <= 0) goto noargument; -- cgit v1.2.3 From 43efca4ab87fb37a0931edcb6be11c0bd3784098 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 18 Nov 2020 09:57:42 +0100 Subject: Remove pj_free() and move it's functional parts to proj_destroy() --- src/apps/cct.cpp | 2 +- src/apps/proj.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index fa75267a..e63a5fc2 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -387,7 +387,7 @@ int main(int argc, char **argv) { buf = static_cast(calloc (1, 10000)); if (nullptr==buf) { print (PJ_LOG_ERROR, "%s: Out of memory", o->progname); - pj_free (P); + proj_destroy (P); free (o); if (stdout != fout) fclose (fout); diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index c9bd8950..8bfd99a3 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -562,7 +562,7 @@ int main(int argc, char **argv) { } if( Proj ) - pj_free(Proj); + proj_destroy(Proj); exit(0); /* normal completion */ } -- cgit v1.2.3 From 56f0ad70054eea15e9671cd67aafd14bf7c11c74 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 18 Nov 2020 10:43:16 +0100 Subject: Remove pj_errno and related functions --- src/apps/cct.cpp | 4 ++-- src/apps/cs2cs.cpp | 2 +- src/apps/gie.cpp | 8 ++++---- src/apps/proj.cpp | 8 +++----- 4 files changed, 10 insertions(+), 12 deletions(-) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index e63a5fc2..92867b3a 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -360,7 +360,7 @@ int main(int argc, char **argv) { if (nullptr==P) { print (PJ_LOG_ERROR, "%s: Bad transformation arguments - (%s)\n '%s -h' for help", - o->progname, pj_strerrno (proj_errno(P)), o->progname); + o->progname, proj_errno_string (proj_errno(P)), o->progname); free (o); if (stdout != fout) fclose (fout); @@ -435,7 +435,7 @@ int main(int argc, char **argv) { if (HUGE_VAL==point.xyzt.x) { /* transformation error */ print (PJ_LOG_NONE, "# Record %d TRANSFORMATION ERROR: %s (%s)", - (int) o->record_index, buf, pj_strerrno (proj_errno(P))); + (int) o->record_index, buf, proj_errno_string (proj_errno(P))); proj_errno_restore (P, err); continue; } diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 92e4441e..12e045bb 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -624,7 +624,7 @@ int main(int argc, char **argv) { if (!transformation) { emess(3, "cannot initialize transformation\ncause: %s", - pj_strerrno(pj_errno)); + proj_errno_string(proj_context_errno(nullptr))); } if (use_env_locale) { diff --git a/src/apps/gie.cpp b/src/apps/gie.cpp index 2fe854fa..b504b922 100644 --- a/src/apps/gie.cpp +++ b/src/apps/gie.cpp @@ -880,8 +880,8 @@ static int expect_failure_with_errno_message (int expected, int got) { banner (T.operation); fprintf (T.fout, "%s", T.op_ko? " -----\n": delim); fprintf (T.fout, " FAILURE in %s(%d):\n", opt_strip_path (T.curr_file), (int) F->lineno); - fprintf (T.fout, " got errno %s (%d): %s\n", err_const_from_errno(got), got, pj_strerrno (got)); - fprintf (T.fout, " expected %s (%d): %s", err_const_from_errno(expected), expected, pj_strerrno (expected)); + fprintf (T.fout, " got errno %s (%d): %s\n", err_const_from_errno(got), got, proj_errno_string (got)); + fprintf (T.fout, " expected %s (%d): %s", err_const_from_errno(expected), expected, proj_errno_string (expected)); fprintf (T.fout, "\n"); return 1; } @@ -934,7 +934,7 @@ Tell GIE what to expect, when transforming the ACCEPTed input /* Otherwise, it's a true failure */ banner (T.operation); errmsg (3, "%sInvalid operation definition in line no. %d:\n %s (errno=%s/%d)\n", - delim, (int) T.operation_lineno, pj_strerrno(proj_errno(T.P)), + delim, (int) T.operation_lineno, proj_errno_string (proj_errno(T.P)), err_const_from_errno (proj_errno(T.P)), proj_errno(T.P) ); return another_failing_failure (); @@ -1186,7 +1186,7 @@ static int list_err_codes (void) { if (9999==lookup[i].the_errno) break; fprintf (T.fout, "%25s (%2.2d): %s\n", lookup[i].the_err_const + 8, - lookup[i].the_errno, pj_strerrno(lookup[i].the_errno)); + lookup[i].the_errno, proj_errno_string (lookup[i].the_errno)); } return 0; } diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index 8bfd99a3..a5c917f6 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -250,10 +250,8 @@ static void vprocess(FILE *fid) { if (postscale) { dat_xy.x *= fscale; dat_xy.y *= fscale; } } - /* For some reason pj_errno does not work as expected in some */ - /* versions of Visual Studio, so using pj_get_errno_ref instead */ - if (*pj_get_errno_ref()) { - emess(-1, pj_strerrno(*pj_get_errno_ref())); + if (proj_context_errno(nullptr)) { + emess(-1, proj_errno_string(proj_context_errno(nullptr))); continue; } @@ -477,7 +475,7 @@ int main(int argc, char **argv) { } if (!(Proj = pj_init(pargc, pargv))) emess(3,"projection initialization failure\ncause: %s", - pj_strerrno(pj_errno)); + proj_errno_string(proj_context_errno(nullptr))); if (!proj_angular_input(Proj, PJ_FWD)) { emess(3, "can't initialize operations that take non-angular input coordinates"); -- cgit v1.2.3 From 046270a85faf20f38d01e02942d197db74bb8542 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Fri, 20 Nov 2020 16:37:12 +0100 Subject: Remove old pj_ memory (de)allocation functions Gone are pj_malloc, pj_calloc, pj_dalloc and pj_dealloc. Their primary function as API memory functions in proj_api.h is no longer there and the other use as a workaround for old errno problems is no longer valid either. Replaced with malloc and free across the codebase. --- src/apps/geod_set.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/apps') diff --git a/src/apps/geod_set.cpp b/src/apps/geod_set.cpp index 603f0d95..d6516f22 100644 --- a/src/apps/geod_set.cpp +++ b/src/apps/geod_set.cpp @@ -75,6 +75,6 @@ geod_set(int argc, char **argv) { /* free up linked list */ for ( ; start; start = curr) { curr = start->next; - pj_dalloc(start); + free(start); } } -- cgit v1.2.3 From f50221ed6606a67ef0354cacd449f02aca3faba7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 22 Nov 2020 23:16:48 +0100 Subject: projinfo.cpp: improve hint when to use --spatial-test intersects --- src/apps/projinfo.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/apps') diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 6ee5925a..3d57dcd6 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -693,6 +693,7 @@ static void outputOperations( std::vector list; size_t spatialCriterionPartialIntersectionResultCount = 0; + bool spatialCriterionPartialIntersectionMoreRelevant = false; try { auto authFactory = dbContext @@ -718,10 +719,15 @@ static void outputOperations( ctxt->setSpatialCriterion( CoordinateOperationContext::SpatialCriterion:: PARTIAL_INTERSECTION); - spatialCriterionPartialIntersectionResultCount = - CoordinateOperationFactory::create() - ->createOperations(nnSourceCRS, nnTargetCRS, ctxt) - .size(); + auto list2 = + CoordinateOperationFactory::create()->createOperations( + nnSourceCRS, nnTargetCRS, ctxt); + spatialCriterionPartialIntersectionResultCount = list2.size(); + if (spatialCriterionPartialIntersectionResultCount == 1 && + list.size() == 1 && + list2[0]->nameStr() != list[0]->nameStr()) { + spatialCriterionPartialIntersectionMoreRelevant = true; + } } catch (const std::exception &) { } } @@ -740,6 +746,10 @@ static void outputOperations( "more results (" << spatialCriterionPartialIntersectionResultCount << ")" << std::endl; + } else if (spatialCriterionPartialIntersectionMoreRelevant) { + std::cout << "Note: using '--spatial-test intersects' would bring " + "more relevant results." + << std::endl; } if (summary) { for (const auto &op : list) { -- cgit v1.2.3 From 4caf32aedd4da6b1fd1b1ce0e04a1a08dc1e3f33 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 24 Nov 2020 19:16:12 +0100 Subject: Add option to allow export of Geographic/Projected 3D CRS in WKT1_GDAL as CompoundCRS with a VerticalCRS being an ellipsoidal height, which is not conformant. But needed for LAS 1.4 that only supports WKT1 --- src/apps/projinfo.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/apps') diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 3d57dcd6..da885fbb 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -72,6 +72,7 @@ struct OutputOptions { bool singleLine = false; bool strict = true; bool ballparkAllowed = true; + bool allowEllipsoidalHeightAsVerticalCRS = false; }; } // anonymous namespace @@ -95,6 +96,8 @@ static void usage() { << " [--pivot-crs always|if_no_direct_transformation|" << "never|{auth:code[,auth:code]*}]" << std::endl << " [--show-superseded] [--hide-ballpark]" << std::endl + << " [--allow-ellipsoidal-height-as-vertical-crs]" + << std::endl << " [--boundcrs-to-wgs84]" << std::endl << " [--main-db-path path] [--aux-db-path path]*" << std::endl @@ -487,6 +490,8 @@ static void outputObject( formatter->setMultiLine(false); } formatter->setStrict(outputOpt.strict); + formatter->setAllowEllipsoidalHeightAsVerticalCRS( + outputOpt.allowEllipsoidalHeightAsVerticalCRS); auto wkt = wktExportable->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); @@ -1070,6 +1075,8 @@ int main(int argc, char **argv) { showSuperseded = true; } else if (arg == "--lax") { outputOpt.strict = false; + } else if (arg == "--allow-ellipsoidal-height-as-vertical-crs") { + outputOpt.allowEllipsoidalHeightAsVerticalCRS = true; } else if (arg == "--hide-ballpark") { outputOpt.ballparkAllowed = false; } else if (ci_equal(arg, "--3d")) { -- cgit v1.2.3 From 24c74a4d1cead8df41a7f22c8f28b1bf9e884de9 Mon Sep 17 00:00:00 2001 From: Houder <74594217+Houder@users.noreply.github.com> Date: Sat, 28 Nov 2020 13:45:06 +0100 Subject: Use same arguments to printf format string for both radians and degrees in output by cct (#2453) Currently the output of the cct utility is different between radians and degrees (as expected by cct), because of a bug in cct: $ printf "1 2\n" | cct -z 0 -t 0 +proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad 1.0000000000 2.0000000000 0.0000 0.0000 $ printf "1 2\n" | cct -z 0 -t 0 +proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=deg 1.0000 2.0000 0.0000 0.0000 The arguments to the printf format string are as follows: * radians: width 14, precision 10 * degrees: width 13, precision 4 (this is by mistake. bug!) After the suggested fix has been applied, output will be the same for both radians and degrees: $ printf "1 2\n" | cct -z 0 -t 0 +proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad 1.0000000000 2.0000000000 0.0000 0.0000 $ printf "1 2\n" | cct -z 0 -t 0 +proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=deg 1.0000000000 2.0000000000 0.0000 0.0000 The cause of the bug is that cct does test if it "has radians to output", but "neglects" to test if it "has degrees to output", resulting in using different arguments to the printf format string in the latter case. The fix makes cct test if it "has either radians or degrees to output". --- src/apps/cct.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/apps') diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index ebfa6a23..4f21f10a 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -458,9 +458,14 @@ int main(int argc, char **argv) { comment_delimiter = (comment && *comment) ? whitespace : blank_comment; /* Time to print the result */ - if (proj_angular_output (P, direction)) { - point.lpzt.lam = proj_todeg (point.lpzt.lam); - point.lpzt.phi = proj_todeg (point.lpzt.phi); + /* use same arguments to printf format string for both radians and + degrees; convert radians to degrees before printing */ + if (proj_angular_output (P, direction) || + proj_degree_output (P, direction)) { + if (proj_angular_output (P, direction)) { + point.lpzt.lam = proj_todeg (point.lpzt.lam); + point.lpzt.phi = proj_todeg (point.lpzt.phi); + } print (PJ_LOG_NONE, "%14.*f %14.*f %12.*f %12.4f%s%s", decimals_angles, point.xyzt.x, decimals_angles, point.xyzt.y, -- cgit v1.2.3 From 0b4c8b0a76c65d8b1146224bf314cad53e9f6607 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 28 Nov 2020 15:51:27 +0100 Subject: cs2cs: add --area and --bbox options to restrict candidate coordinate operations (fixes #2423) --- src/apps/cs2cs.cpp | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 150 insertions(+), 4 deletions(-) (limited to 'src/apps') diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 12e045bb..dd65baf4 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -36,8 +36,13 @@ #include #include +#include #include +#include +#include +#include + #include // PROJ include order is sensitive @@ -70,12 +75,18 @@ static const char *oform = static char oform_buffer[16]; /* buffer for oform when using -d */ static const char *oterr = "*\t*"; /* output line for unprojectable input */ static const char *usage = - "%s\nusage: %s [-dDeEfIlrstvwW [args]] [+opt[=arg] ...]\n" - " [+to +opt[=arg] ...] [file ...]\n"; + "%s\nusage: %s [-dDeEfIlrstvwW [args]]\n" + " [[--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]]\n" + " [+opt[=arg] ...] [+to +opt[=arg] ...] [file ...]\n"; static double (*informat)(const char *, char **); /* input data deformatter function */ +using namespace NS_PROJ::io; +using namespace NS_PROJ::metadata; +using namespace NS_PROJ::util; +using namespace NS_PROJ::internal; + /************************************************************************/ /* process() */ /* */ @@ -359,9 +370,47 @@ int main(int argc, char **argv) { } } + ExtentPtr bboxFilter; + std::string area; + /* process run line arguments */ while (--argc > 0) { /* collect run line arguments */ - if (**++argv == '-') { + ++argv; + if (strcmp(*argv, "--area") == 0 ) { + ++argv; + --argc; + if( argc == 0 ) { + emess(1, "missing argument for --area"); + std::exit(1); + } + area = *argv; + } + else if (strcmp(*argv, "--bbox") == 0) { + ++argv; + --argc; + if( argc == 0 ) { + emess(1, "missing argument for --bbox"); + std::exit(1); + } + auto bboxStr(*argv); + auto bbox(split(bboxStr, ',')); + if (bbox.size() != 4) { + std::cerr << "Incorrect number of values for option --bbox: " + << bboxStr << std::endl; + std::exit(1); + } + try { + bboxFilter = Extent::createFromBBOX( + c_locale_stod(bbox[0]), c_locale_stod(bbox[1]), + c_locale_stod(bbox[2]), c_locale_stod(bbox[3])) + .as_nullable(); + } catch (const std::exception &e) { + std::cerr << "Invalid value for option --bbox: " << bboxStr + << ", " << e.what() << std::endl; + std::exit(1); + } + } + else if (**argv == '-') { for (arg = *argv;;) { switch (*++arg) { case '\0': /* position of "stdin" */ @@ -536,6 +585,102 @@ int main(int argc, char **argv) { } } + if (bboxFilter && !area.empty()) { + std::cerr << "ERROR: --bbox and --area are exclusive" << std::endl; + std::exit(1); + } + + PJ_AREA* pj_area = nullptr; + if (!area.empty()) { + + DatabaseContextPtr dbContext; + try { + dbContext = + DatabaseContext::create().as_nullable(); + } catch (const std::exception &e) { + std::cerr << "ERROR: Cannot create database connection: " + << e.what() << std::endl; + std::exit(1); + } + + // Process area of use + try { + if (area.find(' ') == std::string::npos && + area.find(':') != std::string::npos) { + auto tokens = split(area, ':'); + if (tokens.size() == 2) { + const std::string &areaAuth = tokens[0]; + const std::string &areaCode = tokens[1]; + bboxFilter = AuthorityFactory::create( + NN_NO_CHECK(dbContext), areaAuth) + ->createExtent(areaCode) + .as_nullable(); + } + } + if (!bboxFilter) { + auto authFactory = AuthorityFactory::create( + NN_NO_CHECK(dbContext), std::string()); + auto res = authFactory->listAreaOfUseFromName(area, false); + if (res.size() == 1) { + bboxFilter = + AuthorityFactory::create(NN_NO_CHECK(dbContext), + res.front().first) + ->createExtent(res.front().second) + .as_nullable(); + } else { + res = authFactory->listAreaOfUseFromName(area, true); + if (res.size() == 1) { + bboxFilter = + AuthorityFactory::create(NN_NO_CHECK(dbContext), + res.front().first) + ->createExtent(res.front().second) + .as_nullable(); + } else if (res.empty()) { + std::cerr << "No area of use matching provided name" + << std::endl; + std::exit(1); + } else { + std::cerr << "Several candidates area of use " + "matching provided name :" + << std::endl; + for (const auto &candidate : res) { + auto obj = + AuthorityFactory::create( + NN_NO_CHECK(dbContext), candidate.first) + ->createExtent(candidate.second); + std::cerr << " " << candidate.first << ":" + << candidate.second << " : " + << *obj->description() << std::endl; + } + std::exit(1); + } + } + } + } catch (const std::exception &e) { + std::cerr << "Area of use retrieval failed: " << e.what() + << std::endl; + std::exit(1); + } + } + + if (bboxFilter) { + auto geogElts = bboxFilter->geographicElements(); + if (geogElts.size() == 1) + { + auto bbox = std::dynamic_pointer_cast( + geogElts[0].as_nullable()); + if (bbox) + { + pj_area = proj_area_create(); + proj_area_set_bbox(pj_area, + bbox->westBoundLongitude(), + bbox->southBoundLatitude(), + bbox->eastBoundLongitude(), + bbox->northBoundLatitude()); + } + } + } + /* * If the user has requested inverse, then just reverse the * coordinate systems. @@ -617,10 +762,11 @@ int main(int argc, char **argv) { } transformation = proj_create_crs_to_crs_from_pj(nullptr, src, dst, - nullptr, nullptr); + pj_area, nullptr); proj_destroy(src); proj_destroy(dst); + proj_area_destroy(pj_area); if (!transformation) { emess(3, "cannot initialize transformation\ncause: %s", -- cgit v1.2.3 From f4dc79075c19706dda6e3253c2f224e9df468291 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 30 Nov 2020 01:35:59 +0100 Subject: API cleanup: unexport number of internal symbols, and remove/replace a few unused ones --- src/apps/proj.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src/apps') diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index a5c917f6..0108cb74 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -9,6 +9,8 @@ #include "emess.h" #include "utils.h" +#include + #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__WIN32__) # include # include @@ -292,10 +294,10 @@ static void vprocess(FILE *fid) { int main(int argc, char **argv) { char *arg; - char *pargv[MAX_PARGS] = {}; + std::vector argvVector; char **eargv = argv; FILE *fid; - int pargc = 0, eargc = 0, mon = 0; + int eargc = 0, mon = 0; if ( (emess_dat.Prog_name = strrchr(*argv,DIR_CHAR)) != nullptr) ++emess_dat.Prog_name; @@ -450,10 +452,7 @@ int main(int argc, char **argv) { } break; } else if (**argv == '+') { /* + argument */ - if (pargc < MAX_PARGS) - pargv[pargc++] = *argv + 1; - else - emess(1,"overflowed + argument table"); + argvVector.push_back(*argv + 1); } else /* assumed to be input file name(s) */ eargv[eargc++] = *argv; } @@ -473,7 +472,12 @@ int main(int argc, char **argv) { postscale = 0; fscale = 1./fscale; } - if (!(Proj = pj_init(pargc, pargv))) + proj_context_use_proj4_init_rules(nullptr, true); + + // proj historically ignores any datum shift specifier, like nadgrids, towgs84, etc + argvVector.push_back(const_cast("break_cs2cs_recursion")); + + if (!(Proj = proj_create_argv(nullptr, static_cast(argvVector.size()), argvVector.data()))) emess(3,"projection initialization failure\ncause: %s", proj_errno_string(proj_context_errno(nullptr))); -- cgit v1.2.3 From 18ab7ef2e357e0c01464848a6911e754ebca471f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 2 Dec 2020 17:12:54 +0100 Subject: cs2cs / proj_create_crs_to_crs_from_pj(): add a --authority switch to control where coordinate operations are looked for (fixes #2442) --- src/apps/cs2cs.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'src/apps') diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index dd65baf4..409a5ef3 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -77,6 +77,7 @@ static const char *oterr = "*\t*"; /* output line for unprojectable input */ static const char *usage = "%s\nusage: %s [-dDeEfIlrstvwW [args]]\n" " [[--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]]\n" + " [--authority {name}]\n" " [+opt[=arg] ...] [+to +opt[=arg] ...] [file ...]\n"; static double (*informat)(const char *, @@ -372,6 +373,7 @@ int main(int argc, char **argv) { ExtentPtr bboxFilter; std::string area; + const char* authority = nullptr; /* process run line arguments */ while (--argc > 0) { /* collect run line arguments */ @@ -410,6 +412,15 @@ int main(int argc, char **argv) { std::exit(1); } } + else if (strcmp(*argv, "--authority") == 0 ) { + ++argv; + --argc; + if( argc == 0 ) { + emess(1, "missing argument for --authority"); + std::exit(1); + } + authority = *argv; + } else if (**argv == '-') { for (arg = *argv;;) { switch (*++arg) { @@ -761,8 +772,15 @@ int main(int argc, char **argv) { } } + std::string authorityOption; /* keep this variable in this outer scope ! */ + const char* options[2] = { nullptr, nullptr }; + if( authority ) { + authorityOption = "AUTHORITY="; + authorityOption += authority; + options[0] = authorityOption.data(); + } transformation = proj_create_crs_to_crs_from_pj(nullptr, src, dst, - pj_area, nullptr); + pj_area, options); proj_destroy(src); proj_destroy(dst); -- cgit v1.2.3