From 56075006131263e0859808d263d6d22cd4594fb9 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 29 Aug 2017 10:25:47 +0200 Subject: PJ_horner.c: fix memory leaks. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3204. Credit to OSS Fuzz --- src/PJ_horner.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/PJ_horner.c b/src/PJ_horner.c index 56980f72..c6560d3a 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -128,6 +128,8 @@ static void horner_free (HORNER *h) { horner_dealloc (h->fwd_u); horner_dealloc (h->fwd_c); horner_dealloc (h->inv_c); + horner_dealloc (h->fwd_origin); + horner_dealloc (h->inv_origin); horner_dealloc (h); } @@ -406,8 +408,10 @@ static int parse_coefs (PJ *P, double *coefs, char *param, int ncoefs) { } sprintf (buf, "t%s", param); - if (0==pj_param (P->ctx, P->params, buf).i) + if (0==pj_param (P->ctx, P->params, buf).i) { + pj_dealloc (buf); return 0; + } sprintf (buf, "s%s", param); init = pj_param(P->ctx, P->params, buf).s; pj_dealloc (buf); -- cgit v1.2.3 From 2a13208980a42b645e72486109a9ae02a92238a3 Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Tue, 29 Aug 2017 15:58:00 -0400 Subject: Release candidate for geodesic library version 1.49. Only substantial changes are (1) testing the HAVE_C99_MATH flag and acting accordingly and (2) adding a couple of tests. --- src/geodesic.c | 40 +++++++++++++++++++++++++++++++++++++--- src/geodesic.h | 26 +++++++++++++------------- src/geodtest.c | 42 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/geodesic.c b/src/geodesic.c index aeb82c71..84951d7f 100644 --- a/src/geodesic.c +++ b/src/geodesic.c @@ -26,6 +26,10 @@ #include "geodesic.h" #include +#if !defined(HAVE_C99_MATH) +#define HAVE_C99_MATH 0 +#endif + #define GEOGRAPHICLIB_GEODESIC_ORDER 6 #define nA1 GEOGRAPHICLIB_GEODESIC_ORDER #define nC1 GEOGRAPHICLIB_GEODESIC_ORDER @@ -105,6 +109,12 @@ enum captype { }; static real sq(real x) { return x * x; } +#if HAVE_C99_MATH +#define atanhx atanh +#define copysignx copysign +#define hypotx hypot +#define cbrtx cbrt +#else static real log1px(real x) { volatile real y = 1 + x, @@ -133,6 +143,7 @@ static real cbrtx(real x) { real y = pow(fabs(x), 1/(real)(3)); /* Return the real cube root */ return x < 0 ? -y : y; } +#endif static real sumx(real u, real v, real* t) { volatile real s = u + v; @@ -170,8 +181,13 @@ static void norm2(real* sinx, real* cosx) { } static real AngNormalize(real x) { +#if HAVE_C99_MATH + x = remainder(x, (real)(360)); + return x != -180 ? x : 180; +#else x = fmod(x, (real)(360)); return x <= -180 ? x + 360 : (x <= 180 ? x : x - 360); +#endif } static real LatFix(real x) @@ -202,9 +218,15 @@ static void sincosdx(real x, real* sinx, real* cosx) { /* In order to minimize round-off errors, this function exactly reduces * the argument to the range [-45, 45] before converting it to radians. */ real r, s, c; int q; +#if HAVE_C99_MATH && !defined(__GNUC__) + /* Disable for gcc because of bug in glibc version < 2.22, see + * https://sourceware.org/bugzilla/show_bug.cgi?id=17569 */ + r = remquo(x, (real)(90), &q); +#else r = fmod(x, (real)(360)); q = (int)(floor(r / 90 + (real)(0.5))); r -= 90 * q; +#endif /* now abs(r) <= 45 */ r *= degree; /* Possibly could call the gnu extension sincos */ @@ -538,7 +560,9 @@ real geod_genposition(const struct geod_geodesicline* l, salp2 = l->salp0; calp2 = l->calp0 * csig2; /* No need to normalize */ if (outmask & GEOD_DISTANCE) - s12 = flags & GEOD_ARCMODE ? l->b * ((1 + l->A1m1) * sig12 + AB1) : s12_a12; + s12 = flags & GEOD_ARCMODE ? + l->b * ((1 + l->A1m1) * sig12 + AB1) : + s12_a12; if (outmask & GEOD_LONGITUDE) { real E = copysignx(1, l->salp0); /* east or west going? */ @@ -576,7 +600,8 @@ real geod_genposition(const struct geod_geodesicline* l, m12 = l->b * ((dn2 * (l->csig1 * ssig2) - l->dn1 * (l->ssig1 * csig2)) - l->csig1 * csig2 * J12); if (outmask & GEOD_GEODESICSCALE) { - real t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) / (l->dn1 + dn2); + real t = l->k2 * (ssig2 - l->ssig1) * (ssig2 + l->ssig1) / + (l->dn1 + dn2); M12 = csig12 + (t * ssig2 - csig2 * J12) * l->ssig1 / l->dn1; M21 = csig12 - (t * l->ssig1 - l->csig1 * J12) * ssig2 / dn2; } @@ -639,7 +664,9 @@ static void geod_setarc(struct geod_geodesicline* l, real a13) { void geod_gensetdistance(struct geod_geodesicline* l, unsigned flags, real s13_a13) { - flags & GEOD_ARCMODE ? geod_setarc(l, s13_a13) : geod_setdistance(l, s13_a13); + flags & GEOD_ARCMODE ? + geod_setarc(l, s13_a13) : + geod_setdistance(l, s13_a13); } void geod_position(const struct geod_geodesicline* l, real s12, @@ -1758,10 +1785,17 @@ int transit(real lon1, real lon2) { } int transitdirect(real lon1, real lon2) { +#if HAVE_C99_MATH + lon1 = remainder(lon1, (real)(720)); + lon2 = remainder(lon2, (real)(720)); + return ( (lon2 >= 0 && lon2 < 360 ? 0 : 1) - + (lon1 >= 0 && lon1 < 360 ? 0 : 1) ); +#else lon1 = fmod(lon1, (real)(720)); lon2 = fmod(lon2, (real)(720)); return ( ((lon2 >= 0 && lon2 < 360) || lon2 < -360 ? 0 : 1) - ((lon1 >= 0 && lon1 < 360) || lon1 < -360 ? 0 : 1) ); +#endif } void accini(real s[]) { diff --git a/src/geodesic.h b/src/geodesic.h index f3cb3009..ab18a01f 100644 --- a/src/geodesic.h +++ b/src/geodesic.h @@ -112,7 +112,7 @@ * https://geographiclib.sourceforge.io/ * * This library was distributed with - * GeographicLib 1.48. + * GeographicLib 1.49. **********************************************************************/ #if !defined(GEODESIC_H) @@ -127,12 +127,12 @@ * The minor version of the geodesic library. (This tracks the version of * GeographicLib.) **********************************************************************/ -#define GEODESIC_VERSION_MINOR 48 +#define GEODESIC_VERSION_MINOR 49 /** * The patch level of the geodesic library. (This tracks the version of * GeographicLib.) **********************************************************************/ -#define GEODESIC_VERSION_PATCH 1 +#define GEODESIC_VERSION_PATCH 0 /** * Pack the version components into a single integer. Users should not rely on @@ -881,16 +881,16 @@ extern "C" { * mask values for the \e caps argument to geod_lineinit(). **********************************************************************/ enum geod_mask { - GEOD_NONE = 0U, /**< Calculate nothing */ - GEOD_LATITUDE = 1U<<7 | 0U, /**< Calculate latitude */ - GEOD_LONGITUDE = 1U<<8 | 1U<<3, /**< Calculate longitude */ - GEOD_AZIMUTH = 1U<<9 | 0U, /**< Calculate azimuth */ - GEOD_DISTANCE = 1U<<10 | 1U<<0, /**< Calculate distance */ - GEOD_DISTANCE_IN = 1U<<11 | 1U<<0 | 1U<<1, /**< Allow distance as input */ - GEOD_REDUCEDLENGTH= 1U<<12 | 1U<<0 | 1U<<2, /**< Calculate reduced length */ - GEOD_GEODESICSCALE= 1U<<13 | 1U<<0 | 1U<<2, /**< Calculate geodesic scale */ - GEOD_AREA = 1U<<14 | 1U<<4, /**< Calculate reduced length */ - GEOD_ALL = 0x7F80U| 0x1FU /**< Calculate everything */ + GEOD_NONE = 0U, /**< Calculate nothing */ + GEOD_LATITUDE = 1U<<7 | 0U, /**< Calculate latitude */ + GEOD_LONGITUDE = 1U<<8 | 1U<<3, /**< Calculate longitude */ + GEOD_AZIMUTH = 1U<<9 | 0U, /**< Calculate azimuth */ + GEOD_DISTANCE = 1U<<10 | 1U<<0, /**< Calculate distance */ + GEOD_DISTANCE_IN = 1U<<11 | 1U<<0 | 1U<<1,/**< Allow distance as input */ + GEOD_REDUCEDLENGTH= 1U<<12 | 1U<<0 | 1U<<2,/**< Calculate reduced length */ + GEOD_GEODESICSCALE= 1U<<13 | 1U<<0 | 1U<<2,/**< Calculate geodesic scale */ + GEOD_AREA = 1U<<14 | 1U<<4, /**< Calculate reduced length */ + GEOD_ALL = 0x7F80U| 0x1FU /**< Calculate everything */ }; /** diff --git a/src/geodtest.c b/src/geodtest.c index 5ca741b1..6899436c 100644 --- a/src/geodtest.c +++ b/src/geodtest.c @@ -16,7 +16,7 @@ #include #if defined(_MSC_VER) -// Squelch warnings about assignment within conditional expression +/* Squelch warnings about assignment within conditional expression */ # pragma warning (disable: 4706) #endif @@ -618,8 +618,9 @@ static int GeodSolve73() { return result; } -static void planimeter(const struct geod_geodesic* g, double points[][2], int N, - double* perimeter, double* area) { +static void planimeter(const struct geod_geodesic* g, + double points[][2], int N, + double* perimeter, double* area) { struct geod_polygon p; int i; geod_polygon_init(&p, 0); @@ -628,8 +629,9 @@ static void planimeter(const struct geod_geodesic* g, double points[][2], int N, geod_polygon_compute(g, &p, 0, 1, area, perimeter); } -static void polylength(const struct geod_geodesic* g, double points[][2], int N, - double* perimeter) { +static void polylength(const struct geod_geodesic* g, + double points[][2], int N, + double* perimeter) { struct geod_polygon p; int i; geod_polygon_init(&p, 1); @@ -658,6 +660,34 @@ static int GeodSolve74() { return result; } +static int GeodSolve76() { + /* The distance from Wellington and Salamanca (a classic failure of + Vincenty) */ + double azi1, azi2, s12; + struct geod_geodesic g; + int result = 0; + geod_init(&g, wgs84_a, wgs84_f); + geod_inverse(&g, -(41+19/60.0), 174+49/60.0, 40+58/60.0, -(5+30/60.0), + &s12, &azi1, &azi2); + result += assertEquals(azi1, 160.39137649664, 0.5e-11); + result += assertEquals(azi2, 19.50042925176, 0.5e-11); + result += assertEquals(s12, 19960543.857179, 0.5e-6); + return result; +} + +static int GeodSolve78() { + /* An example where the NGS calculator fails to converge */ + double azi1, azi2, s12; + struct geod_geodesic g; + int result = 0; + geod_init(&g, wgs84_a, wgs84_f); + geod_inverse(&g, 27.2, 0.0, -27.1, 179.5, &s12, &azi1, &azi2); + result += assertEquals(azi1, 45.82468716758, 0.5e-11); + result += assertEquals(azi2, 134.22776532670, 0.5e-11); + result += assertEquals(s12, 19974354.765767, 0.5e-6); + return result; +} + static int Planimeter0() { /* Check fix for pole-encircling bug found 2011-03-16 */ double pa[4][2] = {{89, 0}, {89, 90}, {89, 180}, {89, 270}}; @@ -786,6 +816,8 @@ int main() { if ((i = GeodSolve71())) {++n; printf("GeodSolve71 fail: %d\n", i);} if ((i = GeodSolve73())) {++n; printf("GeodSolve73 fail: %d\n", i);} if ((i = GeodSolve74())) {++n; printf("GeodSolve74 fail: %d\n", i);} + if ((i = GeodSolve76())) {++n; printf("GeodSolve76 fail: %d\n", i);} + if ((i = GeodSolve78())) {++n; printf("GeodSolve78 fail: %d\n", i);} if ((i = Planimeter0())) {++n; printf("Planimeter0 fail: %d\n", i);} if ((i = Planimeter5())) {++n; printf("Planimeter5 fail: %d\n", i);} if ((i = Planimeter6())) {++n; printf("Planimeter6 fail: %d\n", i);} -- cgit v1.2.3 From 9b664865a2926568440de57f4d3f5a64e0cee6dc Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 30 Aug 2017 10:19:59 +0200 Subject: urm5: fix memory leaks in error code paths of initialization. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3235. Credit to OSS Fuzz --- src/PJ_urm5.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/PJ_urm5.c b/src/PJ_urm5.c index 9d904fc7..4edb4215 100644 --- a/src/PJ_urm5.c +++ b/src/PJ_urm5.c @@ -47,11 +47,11 @@ PJ *PROJECTION(urm5) { Q->n = pj_param(P->ctx, P->params, "dn").f; if (Q->n <= 0. || Q->n > 1.) { proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(0); + return freeup_new(P); } } else { proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(0); + return freeup_new(P); } Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; alpha = pj_param(P->ctx, P->params, "ralpha").f; -- cgit v1.2.3 From 03eb6a7804019df8c90014c1fb5dd885bc08b40e Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Wed, 30 Aug 2017 09:54:41 -0400 Subject: Add geodtest to autoconf's 'make check' suite. It's already including in cmake's test suite. --- src/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index dbfefe9c..12d11c5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,9 @@ AM_CFLAGS = @C_WFLAGS@ bin_PROGRAMS = proj nad2bin geod cs2cs EXTRA_PROGRAMS = multistresstest test228 +TESTS = geodtest +check_PROGRAMS = geodtest + AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ -DMUTEX_@MUTEX_SETTING@ @JNI_INCLUDE@ @@ -19,6 +22,7 @@ nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c test228_SOURCES = test228.c +geodtest_SOURCES = geodtest.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la @@ -26,6 +30,7 @@ nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ test228_LDADD = libproj.la @THREAD_LIB@ +geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -- cgit v1.2.3 From f658c3c822e65ec907e44f14c937aef7824d404c Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Wed, 30 Aug 2017 10:11:33 -0400 Subject: Rejig how geodtest is specified in automake to make coverage stats accurate?? --- src/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 12d11c5f..d215e678 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c test228_SOURCES = test228.c -geodtest_SOURCES = geodtest.c +geodtest_SOURCES = geodtest.c geod.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la @@ -30,7 +30,6 @@ nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ test228_LDADD = libproj.la @THREAD_LIB@ -geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -- cgit v1.2.3 From 195c883b7f76bd5193052f3d5532e73005eadf0c Mon Sep 17 00:00:00 2001 From: Charles Karney Date: Wed, 30 Aug 2017 10:43:48 -0400 Subject: Back out of previous change. Coverage stats are still wrong. geodtest should have included geodesic.c and not geod.c and yet I'm not allowed to use geodesic.c except through the library and then the coverage of geodesic.c seems to be wildly wrong. --- src/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index d215e678..12d11c5f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c test228_SOURCES = test228.c -geodtest_SOURCES = geodtest.c geod.c +geodtest_SOURCES = geodtest.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la @@ -30,6 +30,7 @@ nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ test228_LDADD = libproj.la @THREAD_LIB@ +geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la -- cgit v1.2.3 From efe7db5daf1067d57be1726193a7b59d5ba038af Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sun, 3 Sep 2017 10:21:15 +0200 Subject: PJ_goode: fix memory leak. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3274. Credit to OSS Fuzz --- src/PJ_goode.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/PJ_goode.c b/src/PJ_goode.c index fff12a78..9138cedc 100644 --- a/src/PJ_goode.c +++ b/src/PJ_goode.c @@ -49,9 +49,9 @@ static void *freeup_new (PJ *P) { /* Destructor */ if (0==P->opaque) return pj_dealloc(P); if (P->opaque->sinu) - pj_dealloc(P->opaque->sinu); + pj_free(P->opaque->sinu); if (P->opaque->moll) - pj_dealloc(P->opaque->moll); + pj_free(P->opaque->moll); pj_dealloc (P->opaque); return pj_dealloc(P); @@ -104,7 +104,11 @@ int pj_goode_selftest (void) { }; XY s_fwd_expect[] = { - { 223368.11902663155, 111701.07212763709}, { 223368.11902663155, -111701.07212763709}, {-223368.11902663155, 111701.07212763709}, {-223368.11902663155, -111701.07212763709}, }; + { 223368.11902663155, 111701.07212763709}, + { 223368.11902663155, -111701.07212763709}, + {-223368.11902663155, 111701.07212763709}, + {-223368.11902663155, -111701.07212763709}, + }; XY inv_in[] = { { 200, 100}, @@ -114,7 +118,11 @@ int pj_goode_selftest (void) { }; LP s_inv_expect[] = { - { 0.0017904931100023887, 0.00089524655489191132}, { 0.0017904931100023887, -0.00089524655489191132}, {-0.0017904931100023887, 0.00089524655489191132}, {-0.0017904931100023887, -0.00089524655489191132}, }; + { 0.0017904931100023887, 0.00089524655489191132}, + { 0.0017904931100023887, -0.00089524655489191132}, + {-0.0017904931100023887, 0.00089524655489191132}, + {-0.0017904931100023887, -0.00089524655489191132}, + }; return pj_generic_selftest (0, s_args, tolerance_xy, tolerance_lp, 4, 4, fwd_in, 0, s_fwd_expect, inv_in, 0, s_inv_expect); } -- cgit v1.2.3 From 0d50cc980df7b5b25be8ea29689cdfe08c587650 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 4 Sep 2017 09:51:14 +0200 Subject: PJ_hgridshift.c: fix memleak in initialization if grid loading fail. Same fix as commit e1ad1046873056ab3bfc3262bd343e8c874f395c. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3276. Credit to OSS Fuzz --- src/PJ_hgridshift.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/PJ_hgridshift.c b/src/PJ_hgridshift.c index 41c2b629..674b4da8 100644 --- a/src/PJ_hgridshift.c +++ b/src/PJ_hgridshift.c @@ -81,6 +81,8 @@ PJ *PROJECTION(hgridshift) { /* Was gridlist compiled properly? */ if ( pj_ctx_get_errno(P->ctx) ) { proj_log_error(P, "hgridshift: could not find required grid(s)."); + pj_dalloc(P->gridlist); + P->gridlist = NULL; return freeup_msg(P, -38); } -- cgit v1.2.3 From 60970de2d0e47f40c7a30222eba0c1de511ea0a1 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 5 Sep 2017 11:23:02 +0200 Subject: Reformat proj.c before making functional changes. Mixed usage of tabs and spaces replaced with spaces. Code slightly reformatted to present a consistent style from top to bottom. --- src/proj.c | 507 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 271 insertions(+), 236 deletions(-) (limited to 'src') diff --git a/src/proj.c b/src/proj.c index 67d60f21..70ca4033 100644 --- a/src/proj.c +++ b/src/proj.c @@ -21,243 +21,274 @@ extern void gen_cheb(int, projUV(*)(projUV), char *, PJ *, int, char **); +static PJ *Proj; +static projUV (*proj)(projUV, PJ *); - static PJ -*Proj; - static projUV -(*proj)(projUV, PJ *); - static int -reversein = 0, /* != 0 reverse input arguments */ -reverseout = 0, /* != 0 reverse output arguments */ -bin_in = 0, /* != 0 then binary input */ -bin_out = 0, /* != 0 then binary output */ -echoin = 0, /* echo input data to output line */ -tag = '#', /* beginning of line tag character */ -inverse = 0, /* != 0 then inverse projection */ -prescale = 0, /* != 0 apply cartesian scale factor */ -dofactors = 0, /* determine scale factors */ -facs_bad = 0, /* return condition from pj_factors */ -very_verby = 0, /* very verbose mode */ -postscale = 0; - static char -*cheby_str, /* string controlling Chebychev evaluation */ -*oform = (char *)0, /* output format for x-y or decimal degrees */ -*oterr = "*\t*", /* output line for unprojectable input */ -*usage = -"%s\nusage: %s [ -bCeEfiIlormsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n"; - static struct FACTORS -facs; - static double -(*informat)(const char *, char **), /* input data deformatter function */ -fscale = 0.; /* cartesian scale factor */ - static projUV -int_proj(projUV data) { - if (prescale) { data.u *= fscale; data.v *= fscale; } - data = (*proj)(data, Proj); - if (postscale && data.u != HUGE_VAL) - { data.u *= fscale; data.v *= fscale; } - return(data); +static int + reversein = 0, /* != 0 reverse input arguments */ + reverseout = 0, /* != 0 reverse output arguments */ + bin_in = 0, /* != 0 then binary input */ + bin_out = 0, /* != 0 then binary output */ + echoin = 0, /* echo input data to output line */ + tag = '#', /* beginning of line tag character */ + inverse = 0, /* != 0 then inverse projection */ + prescale = 0, /* != 0 apply cartesian scale factor */ + dofactors = 0, /* determine scale factors */ + facs_bad = 0, /* return condition from pj_factors */ + very_verby = 0, /* very verbose mode */ + postscale = 0; + +static char + *cheby_str, /* string controlling Chebychev evaluation */ + *oform = (char *)0, /* output format for x-y or decimal degrees */ + *oterr = "*\t*", /* output line for unprojectable input */ + *usage = "%s\nusage: %s [ -bCeEfiIlormsStTvVwW [args] ] [ +opts[=arg] ] [ files ]\n"; + +static struct FACTORS facs; + +static double (*informat)(const char *, char **), /* input data deformatter function */ + fscale = 0.; /* cartesian scale factor */ + +static projUV int_proj(projUV data) { + if (prescale) { + data.u *= fscale; + data.v *= fscale; + } + + data = (*proj)(data, Proj); + + if (postscale && data.u != HUGE_VAL) { + data.u *= fscale; + data.v *= fscale; + } + + return data; } - static void /* file processing function */ -process(FILE *fid) { - char line[MAX_LINE+3], *s = 0, pline[40]; - projUV data; - - for (;;) { - ++emess_dat.File_line; - if (bin_in) { /* binary input */ - if (fread(&data, sizeof(projUV), 1, fid) != 1) - break; - } else { /* ascii input */ - if (!(s = fgets(line, MAX_LINE, fid))) - break; - if (!strchr(s, '\n')) { /* overlong line */ - int c; - (void)strcat(s, "\n"); - /* gobble up to newline */ - while ((c = fgetc(fid)) != EOF && c != '\n') ; - } - if (*s == tag) { - if (!bin_out) - (void)fputs(line, stdout); - continue; - } - if (reversein) { - data.v = (*informat)(s, &s); - data.u = (*informat)(s, &s); - } else { - data.u = (*informat)(s, &s); - data.v = (*informat)(s, &s); - } - if (data.v == HUGE_VAL) - data.u = HUGE_VAL; - if (!*s && (s > line)) --s; /* assumed we gobbled \n */ - if (!bin_out && echoin) { - char t; - t = *s; - *s = '\0'; - (void)fputs(line, stdout); - *s = t; - putchar('\t'); - } - } - if (data.u != HUGE_VAL) { - if (prescale) { data.u *= fscale; data.v *= fscale; } - if (dofactors && !inverse) - facs_bad = pj_factors(data, Proj, 0., &facs); - data = (*proj)(data, Proj); - if (dofactors && inverse) - facs_bad = pj_factors(data, Proj, 0., &facs); - if (postscale && data.u != HUGE_VAL) - { data.u *= fscale; data.v *= fscale; } - } - if (bin_out) { /* binary output */ - (void)fwrite(&data, sizeof(projUV), 1, stdout); - continue; - } else if (data.u == HUGE_VAL) /* error output */ - (void)fputs(oterr, stdout); - else if (inverse && !oform) { /*ascii DMS output */ - if (reverseout) { - (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); - putchar('\t'); - (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); - } else { - (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); - putchar('\t'); - (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); - } - } else { /* x-y or decimal degree ascii output */ - if (inverse) { - data.v *= RAD_TO_DEG; - data.u *= RAD_TO_DEG; - } - if (reverseout) { - (void)printf(oform,data.v); putchar('\t'); - (void)printf(oform,data.u); - } else { - (void)printf(oform,data.u); putchar('\t'); - (void)printf(oform,data.v); - } - } - if (dofactors) /* print scale factor data */ - { - if (!facs_bad) - (void)printf("\t<%g %g %g %g %g %g>", - facs.h, facs.k, facs.s, - facs.omega * RAD_TO_DEG, facs.a, facs.b); - else - (void)fputs("\t<* * * * * *>", stdout); - } - (void)fputs(bin_in ? "\n" : s, stdout); - } + +/* file processing function */ +static void process(FILE *fid) { + char line[MAX_LINE+3], *s = 0, pline[40]; + projUV data; + + for (;;) { + ++emess_dat.File_line; + + if (bin_in) { /* binary input */ + if (fread(&data, sizeof(projUV), 1, fid) != 1) + break; + } else { /* ascii input */ + if (!(s = fgets(line, MAX_LINE, fid))) + break; + + if (!strchr(s, '\n')) { /* overlong line */ + int c; + (void)strcat(s, "\n"); + /* gobble up to newline */ + while ((c = fgetc(fid)) != EOF && c != '\n') ; + } + + if (*s == tag) { + if (!bin_out) + (void)fputs(line, stdout); + continue; + } + + if (reversein) { + data.v = (*informat)(s, &s); + data.u = (*informat)(s, &s); + } else { + data.u = (*informat)(s, &s); + data.v = (*informat)(s, &s); + } + + if (data.v == HUGE_VAL) + data.u = HUGE_VAL; + + if (!*s && (s > line)) --s; /* assumed we gobbled \n */ + if (!bin_out && echoin) { + char t; + t = *s; + *s = '\0'; + (void)fputs(line, stdout); + *s = t; + putchar('\t'); + } + } + + if (data.u != HUGE_VAL) { + if (prescale) { data.u *= fscale; data.v *= fscale; } + if (dofactors && !inverse) + facs_bad = pj_factors(data, Proj, 0., &facs); + data = (*proj)(data, Proj); + + if (dofactors && inverse) + facs_bad = pj_factors(data, Proj, 0., &facs); + + if (postscale && data.u != HUGE_VAL) + { data.u *= fscale; data.v *= fscale; } + } + + if (bin_out) { /* binary output */ + (void)fwrite(&data, sizeof(projUV), 1, stdout); + continue; + } else if (data.u == HUGE_VAL) /* error output */ + (void)fputs(oterr, stdout); + else if (inverse && !oform) { /*ascii DMS output */ + if (reverseout) { + (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); + putchar('\t'); + (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); + } else { + (void)fputs(rtodms(pline, data.u, 'E', 'W'), stdout); + putchar('\t'); + (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); + } + } else { /* x-y or decimal degree ascii output */ + if (inverse) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; + } + + if (reverseout) { + (void)printf(oform,data.v); putchar('\t'); + (void)printf(oform,data.u); + } else { + (void)printf(oform,data.u); putchar('\t'); + (void)printf(oform,data.v); + } + } + + /* print scale factor data */ + if (dofactors) { + if (!facs_bad) + (void)printf("\t<%g %g %g %g %g %g>", + facs.h, facs.k, facs.s, + facs.omega * RAD_TO_DEG, facs.a, facs.b); + else + (void)fputs("\t<* * * * * *>", stdout); + } + (void)fputs(bin_in ? "\n" : s, stdout); + } } - static void /* file processing function --- verbosely */ -vprocess(FILE *fid) { - char line[MAX_LINE+3], *s, pline[40]; - projUV dat_ll, dat_xy, temp; - int linvers; - - if (!oform) - oform = "%.3f"; - if (bin_in || bin_out) - emess(1,"binary I/O not available in -V option"); - for (;;) { - ++emess_dat.File_line; - if (!(s = fgets(line, MAX_LINE, fid))) - break; - if (!strchr(s, '\n')) { /* overlong line */ - int c; - (void)strcat(s, "\n"); - /* gobble up to newline */ - while ((c = fgetc(fid)) != EOF && c != '\n') ; - } - if (*s == tag) { /* pass on data */ - (void)fputs(s, stdout); - continue; - } - /* check to override default input mode */ - if (*s == 'I' || *s == 'i') { - linvers = 1; - ++s; - } else if (*s == 'I' || *s == 'i') { - linvers = 0; - ++s; - } else - linvers = inverse; - if (linvers) { - if (!PJ_INVERS(Proj)) { - emess(-1,"inverse for this projection not avail.\n"); - continue; - } - dat_xy.u = strtod(s, &s); - dat_xy.v = strtod(s, &s); - if (dat_xy.u == HUGE_VAL || dat_xy.v == HUGE_VAL) { - emess(-1,"lon-lat input conversion failure\n"); - continue; - } - if (prescale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } - if (reversein) { - temp.u = dat_xy.u; - temp.v = dat_xy.v; - dat_xy.u = temp.v; - dat_xy.v = temp.u; - } - dat_ll = pj_inv(dat_xy, Proj); - } else { - dat_ll.u = dmstor(s, &s); - dat_ll.v = dmstor(s, &s); - if (dat_ll.u == HUGE_VAL || dat_ll.v == HUGE_VAL) { - emess(-1,"lon-lat input conversion failure\n"); - continue; - } - if (reversein) { - temp.u = dat_ll.u; - temp.v = dat_ll.v; - dat_ll.u = temp.v; - dat_ll.v = temp.u; - } - dat_xy = pj_fwd(dat_ll, Proj); - if (postscale) { dat_xy.u *= fscale; dat_xy.v *= 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())); - continue; - } - if (!*s && (s > line)) --s; /* assumed we gobbled \n */ - if (pj_factors(dat_ll, Proj, 0., &facs)) { - emess(-1,"failed to compute factors\n\n"); - continue; - } - if (*s != '\n') - (void)fputs(s, stdout); - (void)fputs("Longitude: ", stdout); - (void)fputs(rtodms(pline, dat_ll.u, 'E', 'W'), stdout); - (void)printf(" [ %.11g ]\n", dat_ll.u * RAD_TO_DEG); - (void)fputs("Latitude: ", stdout); - (void)fputs(rtodms(pline, dat_ll.v, 'N', 'S'), stdout); - (void)printf(" [ %.11g ]\n", dat_ll.v * RAD_TO_DEG); - (void)fputs("Easting (x): ", stdout); - (void)printf(oform, dat_xy.u); putchar('\n'); - (void)fputs("Northing (y): ", stdout); - (void)printf(oform, dat_xy.v); putchar('\n'); - (void)printf("Meridian scale (h)%c: %.8f ( %.4g %% error )\n", - facs.code & IS_ANAL_HK ? '*' : ' ', facs.h, (facs.h-1.)*100.); - (void)printf("Parallel scale (k)%c: %.8f ( %.4g %% error )\n", - facs.code & IS_ANAL_HK ? '*' : ' ', facs.k, (facs.k-1.)*100.); - (void)printf("Areal scale (s): %.8f ( %.4g %% error )\n", - facs.s, (facs.s-1.)*100.); - (void)printf("Angular distortion (w): %.3f\n", facs.omega * - RAD_TO_DEG); - (void)printf("Meridian/Parallel angle: %.5f\n", - facs.thetap * RAD_TO_DEG); - (void)printf("Convergence%c: ",facs.code & IS_ANAL_CONV ? '*' : ' '); - (void)fputs(rtodms(pline, facs.conv, 0, 0), stdout); - (void)printf(" [ %.8f ]\n", facs.conv * RAD_TO_DEG); - (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", - facs.a, facs.b); - } + +/* file processing function --- verbosely */ +static void vprocess(FILE *fid) { + char line[MAX_LINE+3], *s, pline[40]; + projUV dat_ll, dat_xy, temp; + int linvers; + + if (!oform) + oform = "%.3f"; + + if (bin_in || bin_out) + emess(1,"binary I/O not available in -V option"); + + for (;;) { + ++emess_dat.File_line; + + if (!(s = fgets(line, MAX_LINE, fid))) + break; + + if (!strchr(s, '\n')) { /* overlong line */ + int c; + (void)strcat(s, "\n"); + /* gobble up to newline */ + while ((c = fgetc(fid)) != EOF && c != '\n') ; + } + + if (*s == tag) { /* pass on data */ + (void)fputs(s, stdout); + continue; + } + + /* check to override default input mode */ + if (*s == 'I' || *s == 'i') { + linvers = 1; + ++s; + } else if (*s == 'I' || *s == 'i') { + linvers = 0; + ++s; + } else + linvers = inverse; + + if (linvers) { + if (!PJ_INVERS(Proj)) { + emess(-1,"inverse for this projection not avail.\n"); + continue; + } + dat_xy.u = strtod(s, &s); + dat_xy.v = strtod(s, &s); + if (dat_xy.u == HUGE_VAL || dat_xy.v == HUGE_VAL) { + emess(-1,"lon-lat input conversion failure\n"); + continue; + } + if (prescale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } + if (reversein) { + temp.u = dat_xy.u; + temp.v = dat_xy.v; + dat_xy.u = temp.v; + dat_xy.v = temp.u; + } + dat_ll = pj_inv(dat_xy, Proj); + } else { + dat_ll.u = dmstor(s, &s); + dat_ll.v = dmstor(s, &s); + if (dat_ll.u == HUGE_VAL || dat_ll.v == HUGE_VAL) { + emess(-1,"lon-lat input conversion failure\n"); + continue; + } + if (reversein) { + temp.u = dat_ll.u; + temp.v = dat_ll.v; + dat_ll.u = temp.v; + dat_ll.v = temp.u; + } + dat_xy = pj_fwd(dat_ll, Proj); + if (postscale) { dat_xy.u *= fscale; dat_xy.v *= 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())); + continue; + } + + if (!*s && (s > line)) --s; /* assumed we gobbled \n */ + if (pj_factors(dat_ll, Proj, 0., &facs)) { + emess(-1,"failed to compute factors\n\n"); + continue; + } + + if (*s != '\n') + (void)fputs(s, stdout); + + (void)fputs("Longitude: ", stdout); + (void)fputs(rtodms(pline, dat_ll.u, 'E', 'W'), stdout); + (void)printf(" [ %.11g ]\n", dat_ll.u * RAD_TO_DEG); + (void)fputs("Latitude: ", stdout); + (void)fputs(rtodms(pline, dat_ll.v, 'N', 'S'), stdout); + (void)printf(" [ %.11g ]\n", dat_ll.v * RAD_TO_DEG); + (void)fputs("Easting (x): ", stdout); + (void)printf(oform, dat_xy.u); putchar('\n'); + (void)fputs("Northing (y): ", stdout); + (void)printf(oform, dat_xy.v); putchar('\n'); + (void)printf("Meridian scale (h)%c: %.8f ( %.4g %% error )\n", + facs.code & IS_ANAL_HK ? '*' : ' ', facs.h, (facs.h-1.)*100.); + (void)printf("Parallel scale (k)%c: %.8f ( %.4g %% error )\n", + facs.code & IS_ANAL_HK ? '*' : ' ', facs.k, (facs.k-1.)*100.); + (void)printf("Areal scale (s): %.8f ( %.4g %% error )\n", + facs.s, (facs.s-1.)*100.); + (void)printf("Angular distortion (w): %.3f\n", facs.omega * + RAD_TO_DEG); + (void)printf("Meridian/Parallel angle: %.5f\n", + facs.thetap * RAD_TO_DEG); + (void)printf("Convergence%c: ",facs.code & IS_ANAL_CONV ? '*' : ' '); + (void)fputs(rtodms(pline, facs.conv, 0, 0), stdout); + (void)printf(" [ %.8f ]\n", facs.conv * RAD_TO_DEG); + (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", + facs.a, facs.b); + } } int main(int argc, char **argv) { @@ -273,6 +304,7 @@ int main(int argc, char **argv) { (void)fprintf(stderr, usage, pj_get_release(), emess_dat.Prog_name); exit (0); } + /* process run line arguments */ while (--argc > 0) { /* collect run line arguments */ if(**++argv == '-') for(arg = *argv;;) { @@ -459,6 +491,7 @@ int main(int argc, char **argv) { gen_cheb(inverse, int_proj, cheby_str, Proj, iargc, iargv); exit(0); } + /* set input formatting control */ if (mon) { pj_pr_list(Proj); @@ -477,6 +510,7 @@ int main(int argc, char **argv) { } } } + if (inverse) informat = strtod; else { @@ -485,8 +519,7 @@ int main(int argc, char **argv) { oform = "%.2f"; } - if (bin_out) - { + if (bin_out) { SET_BINARY_MODE(stdout); } @@ -516,7 +549,9 @@ int main(int argc, char **argv) { (void)fclose(fid); emess_dat.File_name = 0; } + if( Proj ) pj_free(Proj); + exit(0); /* normal completion */ } -- cgit v1.2.3 From d55c25c7f639f91cfd2e6ef9bdef0c68d9e93289 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 5 Sep 2017 12:19:12 +0200 Subject: PJ_unitconvert: fix memory leak. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3288. Credit to OSS Fuzz --- src/PJ_unitconvert.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 27672c8d..1e4cb839 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -200,6 +200,8 @@ static void *freeup_msg (PJ *P, int errlev) { if (0!=P->ctx) pj_ctx_set_errno (P->ctx, errlev); + pj_dealloc (P->opaque); + return pj_dealloc(P); } -- cgit v1.2.3 From 1c743de193f43f818635235d60330e78dbd4cd96 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 5 Sep 2017 13:13:52 +0200 Subject: proj: Do rad->deg conversion if output units warrants it. With the introduction of transformation pipelines it is possible to create a pipeline that has degrees as it's output unit. If that is the case the output coordinate will be in radians internally. This commit makes sure that a conversion to degrees is applied before printing to stdout. --- src/proj.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/proj.c b/src/proj.c index 70ca4033..aa0f07c0 100644 --- a/src/proj.c +++ b/src/proj.c @@ -143,10 +143,17 @@ static void process(FILE *fid) { putchar('\t'); (void)fputs(rtodms(pline, data.v, 'N', 'S'), stdout); } - } else { /* x-y or decimal degree ascii output */ + } else { /* x-y or decimal degree ascii output, scale if warranted by output units */ if (inverse) { - data.v *= RAD_TO_DEG; - data.u *= RAD_TO_DEG; + if (Proj->left == PJ_IO_UNITS_RADIANS || Proj->left == PJ_IO_UNITS_CLASSIC) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; + } + } else { + if (Proj->right == PJ_IO_UNITS_RADIANS) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; + } } if (reverseout) { @@ -177,6 +184,7 @@ static void vprocess(FILE *fid) { projUV dat_ll, dat_xy, temp; int linvers; + if (!oform) oform = "%.3f"; @@ -247,6 +255,12 @@ static void vprocess(FILE *fid) { if (postscale) { dat_xy.u *= fscale; dat_xy.v *= fscale; } } + /* apply rad->deg scaling in case the output from a pipeline has degrees as units */ + if (!inverse && Proj->right == PJ_IO_UNITS_RADIANS) { + dat_xy.u *= RAD_TO_DEG; + dat_xy.v *= RAD_TO_DEG; + } + /* 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()) { -- cgit v1.2.3 From cf9401abeeb15be0d4d886e4aabbce6c19245fd2 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 6 Sep 2017 16:31:02 +0200 Subject: Add PJ_FACTORS bit flags to proj.h --- src/proj.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/proj.h b/src/proj.h index 1d6191fd..3b4a1a67 100644 --- a/src/proj.h +++ b/src/proj.h @@ -304,6 +304,10 @@ struct PJ_FACTORS { int code; /* info as to analytics, see following */ }; +#define PJ_IS_ANAL_XL_YL 01 /* derivatives of lon analytic */ +#define PJ_IS_ANAL_XP_YP 02 /* derivatives of lat analytic */ +#define PJ_IS_ANAL_HK 04 /* h and k analytic */ +#define PJ_IS_ANAL_CONV 010 /* convergence analytic */ struct PJ_INFO { char release[64]; /* Release info. Version + date */ -- cgit v1.2.3 From 14710d9989c731b2f51b0d309b0e97bc30ad2339 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 7 Sep 2017 16:51:39 +0200 Subject: PJ_ob_tran: fix potential memory leak. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3321. Credit to OSS Fuzz --- src/PJ_ob_tran.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/PJ_ob_tran.c b/src/PJ_ob_tran.c index 238dba67..a610a1fe 100644 --- a/src/PJ_ob_tran.c +++ b/src/PJ_ob_tran.c @@ -87,7 +87,14 @@ static void *freeup_new (PJ *P) { /* Destructor */ return pj_dealloc (P); if (P->opaque->link) - P->opaque->link->pfree(P->opaque->link); + { + /* This is a bit tricky: the linked PJ* shares the same params as */ + /* the current one, so unset it to avoid double free */ + /* We used to call P->opaque->link->pfree(P->opaque->link); only */ + /* but this leaked grids */ + P->opaque->link->params = NULL; + pj_free(P->opaque->link); + } pj_dealloc (P->opaque); return pj_dealloc(P); -- cgit v1.2.3 From 5e97ef560034cb0ae2aec9613a5ff7695b1704c5 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Sat, 9 Sep 2017 11:16:40 +0200 Subject: Tested for wrong indices before array lookup. Fixes #566. --- src/PJ_unitconvert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 27672c8d..49bb6556 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -309,9 +309,9 @@ static PJ_OBS reverse_obs(PJ_OBS obs, PJ *P) { /* delegate unit conversion of physical dimensions to the 3D function */ out.coo.lpz = reverse_3d(obs.coo.xyz, P); - if (Q->t_in_id >= 0) - out.coo.xyzt.t = time_units[Q->t_out_id].t_in( obs.coo.xyzt.t ); if (Q->t_out_id >= 0) + out.coo.xyzt.t = time_units[Q->t_out_id].t_in( obs.coo.xyzt.t ); + if (Q->t_in_id >= 0) out.coo.xyzt.t = time_units[Q->t_in_id].t_out( out.coo.xyzt.t ); return out; -- cgit v1.2.3 From 2edafb2504e3b20da6033e4a396636cfe22942f2 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Tue, 12 Sep 2017 21:11:52 +0200 Subject: Change how existance of strings in info-structs are checked. Before this commit they always evaluated as true. Fixes #568. --- src/PJ_cart.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/PJ_cart.c b/src/PJ_cart.c index 1373e870..257d0dca 100644 --- a/src/PJ_cart.c +++ b/src/PJ_cart.c @@ -486,13 +486,13 @@ int pj_cart_selftest (void) { /* proj_info() */ /* this one is difficult to test, since the output changes with the setup */ info = proj_info(); - if (info.version) { + if (info.version[0] != '\0' ) { char tmpstr[64]; sprintf(tmpstr, "%d.%d.%d", info.major, info.minor, info.patch); if (strcmp(info.version, tmpstr)) return 55; } - if (!info.release) return 56; - if (!info.searchpath) return 57; + if (info.release[0] == '\0') return 56; + if (info.searchpath[0] == '\0') return 57; /* proj_pj_info() */ P = proj_create(0, "+proj=august"); /* august has no inverse */ -- cgit v1.2.3 From fe86f34556dfc4613347c41bb14e8ac025282627 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 11:57:03 +0200 Subject: Add typedef for transformation direction enum --- src/PJ_horner.c | 6 +++--- src/pj_obs_api.c | 12 ++++++------ src/proj.h | 16 ++++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/PJ_horner.c b/src/PJ_horner.c index c6560d3a..43fe1896 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -94,7 +94,7 @@ PROJ_HEAD(horner, "Horner polynomial evaluation"); struct horner; typedef struct horner HORNER; -static UV horner (const HORNER *transformation, enum proj_direction, UV position); +static UV horner (const HORNER *transformation, PJ_DIRECTION direction, UV position); static HORNER *horner_alloc (size_t order, int complex_polynomia); static void horner_free (HORNER *h); @@ -178,7 +178,7 @@ static HORNER *horner_alloc (size_t order, int complex_polynomia) { /**********************************************************************/ -static UV horner (const HORNER *transformation, enum proj_direction direction, UV position) { +static UV horner (const HORNER *transformation, PJ_DIRECTION direction, UV position) { /*********************************************************************** A reimplementation of the classic Engsager/Poder 2D Horner polynomial @@ -303,7 +303,7 @@ static PJ_OBS horner_reverse_obs (PJ_OBS point, PJ *P) { /**********************************************************************/ -static UV complex_horner (const HORNER *transformation, enum proj_direction direction, UV position) { +static UV complex_horner (const HORNER *transformation, PJ_DIRECTION direction, UV position) { /*********************************************************************** A reimplementation of a classic Engsager/Poder Horner complex diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index b2929a07..90269764 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -90,7 +90,7 @@ double proj_xyz_dist (XYZ a, XYZ b) { /* Measure numerical deviation after n roundtrips fwd-inv (or inv-fwd) */ -double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs) { +double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_OBS obs) { int i; PJ_OBS o, u; @@ -125,7 +125,7 @@ double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs) /* Apply the transformation P to the coordinate coo */ -PJ_OBS proj_trans_obs (PJ *P, enum proj_direction direction, PJ_OBS obs) { +PJ_OBS proj_trans_obs (PJ *P, PJ_DIRECTION direction, PJ_OBS obs) { if (0==P) return obs; @@ -147,7 +147,7 @@ PJ_OBS proj_trans_obs (PJ *P, enum proj_direction direction, PJ_OBS obs) { /* Apply the transformation P to the coordinate coo */ -PJ_COORD proj_trans_coord (PJ *P, enum proj_direction direction, PJ_COORD coo) { +PJ_COORD proj_trans_coord (PJ *P, PJ_DIRECTION direction, PJ_COORD coo) { if (0==P) return coo; @@ -171,7 +171,7 @@ PJ_COORD proj_trans_coord (PJ *P, enum proj_direction direction, PJ_COORD coo) { /*************************************************************************************/ size_t proj_transform ( PJ *P, - enum proj_direction direction, + PJ_DIRECTION direction, double *x, size_t sx, size_t nx, double *y, size_t sy, size_t ny, double *z, size_t sz, size_t nz, @@ -319,7 +319,7 @@ size_t proj_transform ( } /*****************************************************************************/ -int proj_transform_obs (PJ *P, enum proj_direction direction, size_t n, PJ_OBS *obs) { +int proj_transform_obs (PJ *P, PJ_DIRECTION direction, size_t n, PJ_OBS *obs) { /****************************************************************************** Batch transform an array of PJ_OBS. @@ -337,7 +337,7 @@ int proj_transform_obs (PJ *P, enum proj_direction direction, size_t n, PJ_OBS * } /*****************************************************************************/ -int proj_transform_coord (PJ *P, enum proj_direction direction, size_t n, PJ_COORD *coord) { +int proj_transform_coord (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord) { /****************************************************************************** Batch transform an array of PJ_COORD. diff --git a/src/proj.h b/src/proj.h index 3b4a1a67..c2eb3523 100644 --- a/src/proj.h +++ b/src/proj.h @@ -367,35 +367,35 @@ PJ *proj_destroy (PJ *P); /* Apply transformation to observation - in forward or inverse direction */ -enum proj_direction { +enum PJ_DIRECTION { PJ_FWD = 1, /* Forward */ PJ_IDENT = 0, /* Do nothing */ PJ_INV = -1 /* Inverse */ }; +typedef enum PJ_DIRECTION PJ_DIRECTION; - -PJ_OBS proj_trans_obs (PJ *P, enum proj_direction direction, PJ_OBS obs); -PJ_COORD proj_trans_coord (PJ *P, enum proj_direction direction, PJ_COORD coord); +PJ_OBS proj_trans_obs (PJ *P, PJ_DIRECTION direction, PJ_OBS obs); +PJ_COORD proj_trans_coord (PJ *P, PJ_DIRECTION direction, PJ_COORD coord); size_t proj_transform ( PJ *P, - enum proj_direction direction, + PJ_DIRECTION direction, double *x, size_t sx, size_t nx, double *y, size_t sy, size_t ny, double *z, size_t sz, size_t nz, double *t, size_t st, size_t nt ); -int proj_transform_obs (PJ *P, enum proj_direction direction, size_t n, PJ_OBS *obs); -int proj_transform_coord (PJ *P, enum proj_direction direction, size_t n, PJ_COORD *coord); +int proj_transform_obs (PJ *P, PJ_DIRECTION direction, size_t n, PJ_OBS *obs); +int proj_transform_coord (PJ *P, PJ_DIRECTION direction, size_t n, PJ_COORD *coord); /* Initializers */ PJ_COORD proj_coord (double x, double y, double z, double t); PJ_OBS proj_obs (double x, double y, double z, double t, double o, double p, double k, int id, unsigned int flags); /* Measure internal consistency - in forward or inverse direction */ -double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs); +double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_OBS obs); /* Geodesic distance between two points with angular 2D coordinates */ double proj_lp_dist (PJ *P, LP a, LP b); -- cgit v1.2.3 From e2faff822f2161d1a45b515d71edde54a19c48cb Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 13:05:04 +0200 Subject: make PJ* P argument of proj_lp_dist const --- src/pj_obs_api.c | 2 +- src/proj.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 90269764..6f9644b1 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -70,7 +70,7 @@ PJ_OBS proj_obs (double x, double y, double z, double t, double o, double p, dou /* Geodesic distance between two points with angular 2D coordinates */ -double proj_lp_dist (PJ *P, LP a, LP b) { +double proj_lp_dist (const PJ *P, LP a, LP b) { double s12, azi1, azi2; /* Note: the geodesic code takes arguments in degrees */ geod_inverse (P->geod, PJ_TODEG(a.phi), PJ_TODEG(a.lam), PJ_TODEG(b.phi), PJ_TODEG(b.lam), &s12, &azi1, &azi2); diff --git a/src/proj.h b/src/proj.h index c2eb3523..943c500f 100644 --- a/src/proj.h +++ b/src/proj.h @@ -398,7 +398,7 @@ PJ_OBS proj_obs (double x, double y, double z, double t, double o, double p, double proj_roundtrip (PJ *P, PJ_DIRECTION direction, int n, PJ_OBS obs); /* Geodesic distance between two points with angular 2D coordinates */ -double proj_lp_dist (PJ *P, LP a, LP b); +double proj_lp_dist (const PJ *P, LP a, LP b); /* Euclidean distance between two points with linear 2D coordinates */ double proj_xy_dist (XY a, XY b); @@ -415,8 +415,8 @@ void proj_errno_restore (PJ *P, int err); PJ_DERIVS proj_derivatives(const PJ *P, const LP lp); -PJ_FACTORS proj_factors(const PJ *P, const LP lp); - +PJ_FACTORS proj_factors(const PJ *P, const LP lp); + /* Info functions - get information about various PROJ.4 entities */ PJ_INFO proj_info(void); PJ_PROJ_INFO proj_pj_info(const PJ *P); -- cgit v1.2.3 From 6b07474e9427d53134e77f0bdf3ced7812d080c4 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 13:27:14 +0200 Subject: Introduce PJ_DEFAULT_CTX constant that improves code readability --- src/PJ_cart.c | 18 +++++++++--------- src/PJ_hgridshift.c | 6 +++--- src/PJ_horner.c | 4 ++-- src/PJ_molodensky.c | 4 ++-- src/PJ_pipeline.c | 6 +++--- src/PJ_unitconvert.c | 4 ++-- src/PJ_vgridshift.c | 8 ++++---- src/proj.h | 2 ++ 8 files changed, 27 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/PJ_cart.c b/src/PJ_cart.c index 257d0dca..d50036b5 100644 --- a/src/PJ_cart.c +++ b/src/PJ_cart.c @@ -253,7 +253,7 @@ int pj_cart_selftest (void) { char buf[40]; /* An utm projection on the GRS80 ellipsoid */ - P = proj_create (0, arg); + P = proj_create (PJ_DEFAULT_CTX, arg); if (0==P) return 1; @@ -262,7 +262,7 @@ int pj_cart_selftest (void) { proj_destroy (P); /* Same projection, now using argc/argv style initialization */ - P = proj_create_argv (0, 3, args); + P = proj_create_argv (PJ_DEFAULT_CTX, 3, args); if (0==P) return 2; @@ -306,7 +306,7 @@ int pj_cart_selftest (void) { proj_destroy (P); /* Now do some 3D transformations */ - P = proj_create (0, "+proj=cart +ellps=GRS80"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=cart +ellps=GRS80"); if (0==P) return 6; @@ -374,7 +374,7 @@ int pj_cart_selftest (void) { /* Testing the proj_transform nightmare */ /* An utm projection on the GRS80 ellipsoid */ - P = proj_create (0, "+proj=utm +zone=32 +ellps=GRS80"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=utm +zone=32 +ellps=GRS80"); if (0==P) return 13; @@ -457,7 +457,7 @@ int pj_cart_selftest (void) { proj_destroy (P); /* test proj_create_crs_to_crs() */ - P = proj_create_crs_to_crs(0, "epsg:25832", "epsg:25833"); + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "epsg:25832", "epsg:25833"); if (P==0) return 50; @@ -472,7 +472,7 @@ int pj_cart_selftest (void) { proj_destroy(P); /* let's make sure that only entries in init-files results in a usable PJ */ - P = proj_create_crs_to_crs(0, "proj=utm +zone=32 +datum=WGS84", "proj=utm +zone=33 +datum=WGS84"); + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, "proj=utm +zone=32 +datum=WGS84", "proj=utm +zone=33 +datum=WGS84"); if (P != 0) { proj_destroy(P); return 52; @@ -495,11 +495,11 @@ int pj_cart_selftest (void) { if (info.searchpath[0] == '\0') return 57; /* proj_pj_info() */ - P = proj_create(0, "+proj=august"); /* august has no inverse */ + P = proj_create(PJ_DEFAULT_CTX, "+proj=august"); /* august has no inverse */ if (proj_pj_info(P).has_inverse) { proj_destroy(P); return 60; } proj_destroy(P); - P = proj_create(0, arg); + P = proj_create(PJ_DEFAULT_CTX, arg); pj_info = proj_pj_info(P); if ( !pj_info.has_inverse ) { proj_destroy(P); return 61; } if ( strcmp(pj_info.definition, arg) ) { proj_destroy(P); return 62; } @@ -539,7 +539,7 @@ int pj_cart_selftest (void) { /* test proj_derivatives_retrieve() and proj_factors_retrieve() */ - P = proj_create(0, "+proj=merc"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=merc"); a = proj_obs_null; a.coo.lp.lam = PJ_TORAD(12); a.coo.lp.phi = PJ_TORAD(55); diff --git a/src/PJ_hgridshift.c b/src/PJ_hgridshift.c index 674b4da8..4ee3fd42 100644 --- a/src/PJ_hgridshift.c +++ b/src/PJ_hgridshift.c @@ -110,18 +110,18 @@ int pj_hgridshift_selftest (void) { double dist; /* fail on purpose: +grids parameter is mandatory*/ - P = proj_create(0, "+proj=hgridshift"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift"); if (0!=P) return 99; /* fail on purpose: open non-existing grid */ - P = proj_create(0, "+proj=hgridshift +grids=nonexistinggrid.gsb"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift +grids=nonexistinggrid.gsb"); if (0!=P) return 999; /* Failure most likely means the grid is missing */ - P = proj_create (0, "+proj=hgridshift +grids=nzgd2kgrid0005.gsb +ellps=GRS80"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift +grids=nzgd2kgrid0005.gsb +ellps=GRS80"); if (0==P) return 10; diff --git a/src/PJ_horner.c b/src/PJ_horner.c index 43fe1896..a9a618c7 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -529,7 +529,7 @@ int pj_horner_selftest (void) { double dist; /* Real polynonia relating the technical coordinate system TC32 to "System 45 Bornholm" */ - P = proj_create (0, tc32_utm32); + P = proj_create (PJ_DEFAULT_CTX, tc32_utm32); if (0==P) return 10; @@ -543,7 +543,7 @@ int pj_horner_selftest (void) { return 1; /* The complex polynomial transformation between the "System Storebaelt" and utm32/ed50 */ - P = proj_create (0, sb_utm32); + P = proj_create (PJ_DEFAULT_CTX, sb_utm32); if (0==P) return 11; diff --git a/src/PJ_molodensky.c b/src/PJ_molodensky.c index 49e27763..d9377234 100644 --- a/src/PJ_molodensky.c +++ b/src/PJ_molodensky.c @@ -338,7 +338,7 @@ int pj_molodensky_selftest (void) { PJ *P; /* Test the abridged Molodensky first. Example from appendix 3 of Deakin (2004). */ - P = proj_create(0, + P = proj_create(PJ_DEFAULT_CTX, "+proj=molodensky +a=6378160 +rf=298.25 " "+da=-23 +df=-8.120449e-8 +dx=-134 +dy=-48 +dz=149 " "+abridged " @@ -376,7 +376,7 @@ int pj_molodensky_selftest (void) { /* Test the abridged Molodensky first. Example from appendix 3 of Deaking (2004). */ - P = proj_create(0, + P = proj_create(PJ_DEFAULT_CTX, "+proj=molodensky +a=6378160 +rf=298.25 " "+da=-23 +df=-8.120449e-8 +dx=-134 +dy=-48 +dz=149 " ); diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c index 6e42c0cb..a26f3ccf 100644 --- a/src/PJ_pipeline.c +++ b/src/PJ_pipeline.c @@ -526,7 +526,7 @@ int pj_pipeline_selftest (void) { double dist; /* forward-reverse geo->utm->geo */ - P = proj_create (0, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +step +proj=utm +ellps=GRS80 +inv"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +step +proj=utm +ellps=GRS80 +inv"); if (0==P) return 1000; /* zero initialize everything, then set (longitude, latitude, height) to (12, 55, 0) */ @@ -548,7 +548,7 @@ int pj_pipeline_selftest (void) { proj_destroy (P); /* And now the back-to-back situation utm->geo->utm */ - P = proj_create (0, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +inv +step +proj=utm +ellps=GRS80"); + P = proj_create (PJ_DEFAULT_CTX, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 +inv +step +proj=utm +ellps=GRS80"); if (0==P) return 2000; @@ -572,7 +572,7 @@ int pj_pipeline_selftest (void) { /* Finally testing a corner case: A rather pointless one-step pipeline geo->utm */ - P = proj_create (0, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 "); + P = proj_create (PJ_DEFAULT_CTX, "+proj=pipeline +zone=32 +step +proj=utm +ellps=GRS80 "); if (0==P) return 3000; diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 06723399..7ce6035c 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -412,7 +412,7 @@ int pj_unitconvert_selftest (void) {return 0;} static int test_time(char* args, double tol, double t_in, double t_exp) { PJ_OBS in, out; - PJ *P = proj_create(0, args); + PJ *P = proj_create(PJ_DEFAULT_CTX, args); int ret = 0; if (P == 0) @@ -438,7 +438,7 @@ static int test_time(char* args, double tol, double t_in, double t_exp) { static int test_xyz(char* args, double tol, PJ_TRIPLET in, PJ_TRIPLET exp) { PJ_OBS out, obs_in; - PJ *P = proj_create(0, args); + PJ *P = proj_create(PJ_DEFAULT_CTX, args); int ret = 0; if (P == 0) diff --git a/src/PJ_vgridshift.c b/src/PJ_vgridshift.c index e790cd4d..0f031d4f 100644 --- a/src/PJ_vgridshift.c +++ b/src/PJ_vgridshift.c @@ -112,18 +112,18 @@ int pj_vgridshift_selftest (void) { PJ_OBS expect, a, b; double dist; - /* fail on purpose: +grids parameter it mandatory*/ - P = proj_create(0, "+proj=vgridshift"); + /* fail on purpose: +grids parameter is mandatory*/ + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift"); if (0!=P) return 99; /* fail on purpose: open non-existing grid */ - P = proj_create(0, "+proj=vgridshift +grids=nonexistinggrid.gtx"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift +grids=nonexistinggrid.gtx"); if (0!=P) return 999; /* Failure most likely means the grid is missing */ - P = proj_create (0, "+proj=vgridshift +grids=egm96_15.gtx +ellps=GRS80"); + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift +grids=egm96_15.gtx +ellps=GRS80"); if (0==P) return 10; diff --git a/src/proj.h b/src/proj.h index 943c500f..badde4cc 100644 --- a/src/proj.h +++ b/src/proj.h @@ -355,10 +355,12 @@ typedef struct projCtx_t PJ_CONTEXT; /* Functionality for handling thread contexts */ +#define PJ_DEFAULT_CTX 0 PJ_CONTEXT *proj_context_create (void); void proj_context_destroy (PJ_CONTEXT *ctx); + /* Manage the transformation definition object PJ */ PJ *proj_create (PJ_CONTEXT *ctx, const char *definition); PJ *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv); -- cgit v1.2.3 From 9755994609973ee5325530052a241f85469da864 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 13 Sep 2017 13:41:00 +0200 Subject: Make proj_destroy and proj_context_destroy behave in the same way. --- src/pj_obs_api.c | 7 ++++--- src/proj.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 6f9644b1..df8cfa3d 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -501,15 +501,16 @@ PJ_CONTEXT *proj_context_create (void) { } -void proj_context_destroy (PJ_CONTEXT *ctx) { +PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx) { if (0==ctx) - return; + return 0; /* Trying to free the default context is a no-op (since it is statically allocated) */ if (pj_get_default_ctx ()==ctx) - return; + return 0; pj_ctx_free (ctx); + return 0; } diff --git a/src/proj.h b/src/proj.h index badde4cc..e1990e34 100644 --- a/src/proj.h +++ b/src/proj.h @@ -357,7 +357,7 @@ typedef struct projCtx_t PJ_CONTEXT; /* Functionality for handling thread contexts */ #define PJ_DEFAULT_CTX 0 PJ_CONTEXT *proj_context_create (void); -void proj_context_destroy (PJ_CONTEXT *ctx); +PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx); -- cgit v1.2.3 From 33175ead05bf03853ab8a33372602160cf69d745 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 21 Sep 2017 21:10:07 +0200 Subject: Use FACTORS and DERIVS structs from projects.h instead of duplicating them in proj.h --- src/pj_obs_api.c | 6 ++---- src/proj.h | 24 ++++-------------------- 2 files changed, 6 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index df8cfa3d..54c75f45 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -740,8 +740,7 @@ PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { ******************************************************************************/ PJ_DERIVS derivs; - /* casting to struct DERIVS for compatibility reasons */ - if (pj_deriv(lp, 1e-5, (PJ *)P, (struct DERIVS *)&derivs)) { + if (pj_deriv(lp, 1e-5, (PJ *)P, &derivs)) { /* errno set in pj_derivs */ memset(&derivs, 0, sizeof(PJ_DERIVS)); } @@ -767,8 +766,7 @@ PJ_FACTORS proj_factors(const PJ *P, const LP lp) { /* pj_factors rely code being zero */ factors.code = 0; - /* casting to struct FACTORS for compatibility reasons */ - if (pj_factors(lp, (PJ *)P, 0.0, (struct FACTORS *)&factors)) { + if (pj_factors(lp, (PJ *)P, 0.0, &factors)) { /* errno set in pj_factors */ memset(&factors, 0, sizeof(PJ_FACTORS)); } diff --git a/src/proj.h b/src/proj.h index e1990e34..140ba320 100644 --- a/src/proj.h +++ b/src/proj.h @@ -182,11 +182,11 @@ typedef union PJ_TRIPLET PJ_TRIPLET; union PJ_COORD; typedef union PJ_COORD PJ_COORD; -struct PJ_DERIVS; -typedef struct PJ_DERIVS PJ_DERIVS; +struct DERIVS; +typedef struct DERIVS PJ_DERIVS; -struct PJ_FACTORS; -typedef struct PJ_FACTORS PJ_FACTORS; +struct FACTORS; +typedef struct FACTORS PJ_FACTORS; /* Data type for projection/transformation information */ struct PJconsts; @@ -288,22 +288,6 @@ struct PJ_OBS { unsigned int flags; /* additional data, intended for flags */ }; - -struct PJ_DERIVS { - double x_l, x_p; /* derivatives of x for lambda-phi */ - double y_l, y_p; /* derivatives of y for lambda-phi */ -}; - -struct PJ_FACTORS { - struct PJ_DERIVS der; - double h, k; /* meridional, parallel scales */ - double omega, thetap; /* angular distortion, theta prime */ - double conv; /* convergence */ - double s; /* areal scale factor */ - double a, b; /* max-min scale error */ - int code; /* info as to analytics, see following */ -}; - #define PJ_IS_ANAL_XL_YL 01 /* derivatives of lon analytic */ #define PJ_IS_ANAL_XP_YP 02 /* derivatives of lat analytic */ #define PJ_IS_ANAL_HK 04 /* h and k analytic */ -- cgit v1.2.3 From dd12554da8979e47be1eb1b8654c980865da654d Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Thu, 21 Sep 2017 21:18:59 +0200 Subject: Changed a few occurences of 'const PJ*' to just 'PJ*' since they were making promises that couldn't be kept --- src/pj_obs_api.c | 12 ++++++------ src/proj.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 54c75f45..a6cb2623 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -583,7 +583,7 @@ PJ_INFO proj_info(void) { /*****************************************************************************/ -PJ_PROJ_INFO proj_pj_info(const PJ *P) { +PJ_PROJ_INFO proj_pj_info(PJ *P) { /****************************************************************************** Basic info about a particular instance of a projection object. @@ -607,7 +607,7 @@ PJ_PROJ_INFO proj_pj_info(const PJ *P) { pj_strlcpy(info.description, P->descr, sizeof(info.description)); /* projection definition */ - def = pj_get_def((PJ *)P, 0); /* pj_get_def takes a non-const PJ pointer */ + def = pj_get_def(P, 0); /* pj_get_def takes a non-const PJ pointer */ pj_strlcpy(info.definition, &def[1], sizeof(info.definition)); /* def includes a leading space */ pj_dealloc(def); @@ -730,7 +730,7 @@ PJ_INIT_INFO proj_init_info(const char *initname){ /*****************************************************************************/ -PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { +PJ_DERIVS proj_derivatives(PJ *P, const LP lp) { /****************************************************************************** Derivatives of coordinates. @@ -740,7 +740,7 @@ PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { ******************************************************************************/ PJ_DERIVS derivs; - if (pj_deriv(lp, 1e-5, (PJ *)P, &derivs)) { + if (pj_deriv(lp, 1e-5, P, &derivs)) { /* errno set in pj_derivs */ memset(&derivs, 0, sizeof(PJ_DERIVS)); } @@ -750,7 +750,7 @@ PJ_DERIVS proj_derivatives(const PJ *P, const LP lp) { /*****************************************************************************/ -PJ_FACTORS proj_factors(const PJ *P, const LP lp) { +PJ_FACTORS proj_factors(PJ *P, const LP lp) { /****************************************************************************** Cartographic characteristics at point lp. @@ -766,7 +766,7 @@ PJ_FACTORS proj_factors(const PJ *P, const LP lp) { /* pj_factors rely code being zero */ factors.code = 0; - if (pj_factors(lp, (PJ *)P, 0.0, &factors)) { + if (pj_factors(lp, P, 0.0, &factors)) { /* errno set in pj_factors */ memset(&factors, 0, sizeof(PJ_FACTORS)); } diff --git a/src/proj.h b/src/proj.h index 140ba320..d344485d 100644 --- a/src/proj.h +++ b/src/proj.h @@ -400,12 +400,12 @@ int proj_errno_reset (PJ *P); void proj_errno_restore (PJ *P, int err); -PJ_DERIVS proj_derivatives(const PJ *P, const LP lp); -PJ_FACTORS proj_factors(const PJ *P, const LP lp); +PJ_DERIVS proj_derivatives(PJ *P, const LP lp); +PJ_FACTORS proj_factors(PJ *P, const LP lp); /* Info functions - get information about various PROJ.4 entities */ PJ_INFO proj_info(void); -PJ_PROJ_INFO proj_pj_info(const PJ *P); +PJ_PROJ_INFO proj_pj_info(PJ *P); PJ_GRID_INFO proj_grid_info(const char *gridname); PJ_INIT_INFO proj_init_info(const char *initname); -- cgit v1.2.3 From 6fb79f304faec4d036ea46f19aa197e8cc85fe2e Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Fri, 22 Sep 2017 08:51:43 +0200 Subject: Add 'expected accuracy' member to PJ_PROJ_INFO struct. --- src/pj_obs_api.c | 5 +++++ src/proj.h | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index a6cb2623..5c9f398b 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -595,6 +595,11 @@ PJ_PROJ_INFO proj_pj_info(PJ *P) { memset(&info, 0, sizeof(PJ_PROJ_INFO)); + /* Expected accuracy of the transformation. Hardcoded for now, will be improved */ + /* later. Most likely to be used when a transformation is set up with */ + /* proj_create_crs_to_crs in a future version that leverages the EPSG database. */ + info.accuracy = -1.0; + if (!P) { return info; } diff --git a/src/proj.h b/src/proj.h index d344485d..600d5b30 100644 --- a/src/proj.h +++ b/src/proj.h @@ -305,10 +305,11 @@ struct PJ_INFO { }; struct PJ_PROJ_INFO { - char id[16]; /* Name of the projection in question */ - char description[128]; /* Description of the projection */ - char definition[512]; /* Projection definition */ - int has_inverse; /* 1 if an inverse mapping exists, 0 otherwise */ + char id[16]; /* Name of the projection in question */ + char description[128]; /* Description of the projection */ + char definition[512]; /* Projection definition */ + int has_inverse; /* 1 if an inverse mapping exists, 0 otherwise */ + double accuracy; /* Expected accuracy of the transformation. -1 if unknown. */ }; struct PJ_GRID_INFO { -- cgit v1.2.3 From 41ac8f6b2c1c4b94873393df0b3fa595ff4f0b2d Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 27 Sep 2017 22:18:05 +0200 Subject: decimalyear_to_mjd(): avoid almost infinite loop in case of crazy input. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3449. Credit to OSS Fuzz --- src/PJ_unitconvert.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 7ce6035c..8581dcad 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -112,9 +112,16 @@ static double decimalyear_to_mjd(double decimalyear) { /*********************************************************************** Epoch of modified julian date is 1858-11-16 00:00 ************************************************************************/ - int year = (int)floor(decimalyear); - double fractional_year = decimalyear - year; - double mjd = (year - 1859)*365 + 14 + 31; + int year; + double fractional_year; + double mjd; + + if( decimalyear < -10000 || decimalyear > 10000 ) + return 0; + + year = (int)floor(decimalyear); + fractional_year = decimalyear - year; + mjd = (year - 1859)*365 + 14 + 31; mjd += fractional_year*days_in_year(year); /* take care of leap days */ -- cgit v1.2.3 From fa318ed5db0e00bf0a9fb3c18852efb44a095427 Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Wed, 27 Sep 2017 13:54:30 +0200 Subject: Support a default destructor for PJ objects --- src/pj_ctx.c | 2 ++ src/pj_init.c | 47 ++++++++--------------------------------- src/pj_malloc.c | 47 +++-------------------------------------- src/pj_obs_api.c | 39 +++++++++------------------------- src/projects.h | 64 +++++--------------------------------------------------- 5 files changed, 29 insertions(+), 170 deletions(-) (limited to 'src') diff --git a/src/pj_ctx.c b/src/pj_ctx.c index 89b2816f..32a3d690 100644 --- a/src/pj_ctx.c +++ b/src/pj_ctx.c @@ -38,6 +38,8 @@ static volatile int default_context_initialized = 0; projCtx pj_get_ctx( projPJ pj ) { + if (0==pj) + return pj_get_default_ctx (); return pj->ctx; } diff --git a/src/pj_init.c b/src/pj_init.c index 7448fdb6..08a302c6 100644 --- a/src/pj_init.c +++ b/src/pj_init.c @@ -769,8 +769,8 @@ bum_call: /* cleanup error return */ /* This is the application callable entry point for destroying */ /* a projection definition. It does work generic to all */ /* projection types, and then calls the projection specific */ -/* free function (P->pfree()) to do local work. This maps to */ -/* the FREEUP code in the individual projection source files. */ +/* free function (P->pfree()) to do local work. In most cases */ +/* P->pfree()==pj_default_destructor. */ /************************************************************************/ void @@ -784,15 +784,10 @@ pj_free(PJ *P) { pj_dalloc(t); } - /* free array of grid pointers if we have one */ - if( P->gridlist != NULL ) - pj_dalloc( P->gridlist ); - - if( P->vgridlist_geoid != NULL ) - pj_dalloc( P->vgridlist_geoid ); - - if( P->catalog_name != NULL ) - pj_dalloc( P->catalog_name ); + /* free grid lists */ + pj_dealloc( P->gridlist ); + pj_dealloc( P->vgridlist_geoid ); + pj_dealloc( P->catalog_name ); /* We used to call pj_dalloc( P->catalog ), but this will leak */ /* memory. The safe way to clear catalog and grid is to call */ @@ -800,34 +795,10 @@ pj_free(PJ *P) { /* TODO: we should probably have a public pj_cleanup() method to do all */ /* that */ - if( P->geod != NULL ) - pj_dalloc( P->geod ); + /* free the interface to Charles Karney's geodesic library */ + pj_dealloc( P->geod ); /* free projection parameters */ - P->pfree(P); + P->destructor (P, 0); } } - - - - - - - - -/************************************************************************/ -/* pj_prepare() */ -/* */ -/* Helper function for the PJ_xxxx functions providing the */ -/* projection specific setup for each projection type. */ -/* */ -/* Currently not used, but placed here as part of the material */ -/* Demonstrating the idea for a future PJ_xxx architecture */ -/* (cf. pj_minimal.c) */ -/* */ -/************************************************************************/ -void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque) { - P->descr = description; - P->pfree = freeup; - P->opaque = pj_calloc (1, sizeof_struct_opaque); -} diff --git a/src/pj_malloc.c b/src/pj_malloc.c index 330b14a6..52cf7deb 100644 --- a/src/pj_malloc.c +++ b/src/pj_malloc.c @@ -115,7 +115,7 @@ pointer" to signal an error in a multi level allocation: /*****************************************************************************/ -static void *pj_freeup_msg_plain (PJ *P, int errlev) { /* Destructor */ +void *pj_default_destructor (PJ *P, int errlev) { /* Destructor */ /***************************************************************************** Does memory deallocation for "plain" PJ objects, i.e. that vast majority of PJs where the opaque object does not contain any additionally @@ -123,54 +123,13 @@ static void *pj_freeup_msg_plain (PJ *P, int errlev) { /* Destructor */ ******************************************************************************/ if (0==P) return 0; - + if (0!=errlev) pj_ctx_set_errno (P->ctx, errlev); - + if (0==P->opaque) return pj_dealloc (P); pj_dealloc (P->opaque); return pj_dealloc(P); } - - -/*****************************************************************************/ -void pj_freeup_plain (PJ *P) { -/***************************************************************************** - Adapts pj_freeup_msg_plain to the format defined for the callback in - the PJ object. - - i.e. reduces most instances of projection deallocation code to: - - static void freeup (PJ *P) { - pj_freeup_plain (P); - return; - } - - rather than: - - static void *freeup_msg_add (PJ *P, int errlev) { - if (0==P) - return 0; - pj_ctx_set_errno (P->ctx, errlev); - - if (0==P->opaque) - return pj_dealloc (P); - - (* projection specific deallocation goes here *) - - pj_dealloc (P->opaque); - return pj_dealloc(P); - } - - (* Adapts pipeline_freeup to the format defined for the PJ object *) - static void freeup_msg_add (PJ *P) { - freeup_new_add (P, 0); - return; - } - - ******************************************************************************/ - pj_freeup_msg_plain (P, 0); - return; - } diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index 5c9f398b..acf0b577 100644 --- a/src/pj_obs_api.c +++ b/src/pj_obs_api.c @@ -12,7 +12,7 @@ * Author: Thomas Knudsen, thokn@sdfe.dk, 2016-06-09/2016-11-06 * ****************************************************************************** - * Copyright (c) 2016, Thomas Knudsen/SDFE + * Copyright (c) 2016, 2017 Thomas Knudsen/SDFE * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -36,7 +36,7 @@ #include #include "proj_internal.h" #include "projects.h" -#include +#include "geodesic.h" #include #include @@ -407,34 +407,20 @@ PJ *proj_destroy (PJ *P) { return 0; } -/* For now, if PJ itself is clean, we return the thread local error level. */ -/* This may change as OBS_API error reporting matures */ int proj_errno (PJ *P) { - if (0==P) - return pj_ctx_get_errno (pj_get_default_ctx ()); - if (0 != P->last_errno) - return P->last_errno; return pj_ctx_get_errno (pj_get_ctx (P)); } /*****************************************************************************/ void proj_errno_set (PJ *P, int err) { /****************************************************************************** - Sets errno in the PJ, and bubbles it up to the context and pj_errno levels - through the low level pj_ctx interface. + Sets errno at the context and bubble it up to the thread local errno ******************************************************************************/ - if (0==P) { - errno = EINVAL; - return; - } - /* Use proj_errno_reset to explicitly clear the error status */ if (0==err) return; - /* set local error level */ - P->last_errno = err; - /* and let it bubble up */ + /* For P==0 err goes to the default context */ proj_context_errno_set (pj_get_ctx (P), err); errno = err; return; @@ -454,14 +440,16 @@ void proj_errno_restore (PJ *P, int err) { See usage example under proj_errno_reset () ******************************************************************************/ + if (0==err) + return; proj_errno_set (P, err); } /*****************************************************************************/ int proj_errno_reset (PJ *P) { /****************************************************************************** - Clears errno in the PJ, and bubbles it up to the context and - pj_errno levels through the low level pj_ctx interface. + Clears errno in the context and thread local levels + through the low level pj_ctx interface. Returns the previous value of the errno, for convenient reset/restore operations: @@ -471,24 +459,17 @@ int proj_errno_reset (PJ *P) { do_something_with_P (P); - (* failure - keep latest error status *) + // failure - keep latest error status if (proj_errno(P)) return; - (* success - restore previous error status *) + // success - restore previous error status proj_errno_restore (P, last_errno); return; } ******************************************************************************/ int last_errno; - if (0==P) { - errno = EINVAL; - return EINVAL; - } last_errno = proj_errno (P); - /* set local error level */ - P->last_errno = 0; - /* and let it bubble up */ pj_ctx_set_errno (pj_get_ctx (P), 0); errno = 0; return last_errno; diff --git a/src/projects.h b/src/projects.h index 872bf816..ece88cde 100644 --- a/src/projects.h +++ b/src/projects.h @@ -253,62 +253,8 @@ struct PJconsts { void (*spc)(LP, PJ *, struct FACTORS *); - void (*pfree)(PJ *); - - /************************************************************************************* - - E R R O R R E P O R T I N G - - ************************************************************************************** - - Currently, we're doing error reporting through the context->last_errno indicator. - - It is, however, not entirely sure this will be the right way to do it in all - cases: During allocation/initialization, it is certainly nice to have a higher - level error indicator, since we primarily signal "something went wrong", by - returning 0 from the pj_init family of functions - and with a null return we - cannot pass messages through internal state in the PJ object. - - Historically, the errno variable has been used for that kind of messages, but - apparently, thread safety was added to PROJ.4 at a time where it was not clear - that errno is actually thread local. - - Additionally, errno semantics has historically been misinterpreted in parts of - pj_init.c, a misinterpretation, that was mitigated by a hack in pj_malloc.c - some 15 years ago. - - This PJ-local errno is a first step towards a more structured approach to - error reporting, being implemented in the OBS_API (cf. pj_obs_api.[ch]), and - related plumbing efforts. - - In due course this will let us get rid of the pj_malloc.c hack, and allow us - to introduce a more layered error reporting structure, where errors are - reported where they occur, and bubble up to the higher levels (context->errno, - then thread local errno), so the highest level indicate "something went wrong - somewhere", then the more localized ones can be used for pinpointing: - - errno: "something went wrong somewhere on this thread", - context->last_errno: "something went wrong in some PROJ.4 related code", - PJ->last_errno: "It was in THIS PJ something went wrong", - pj_strerrno: "This was what went wrong". - - Which will be quite helpful, once fully implemented, especially for - debugging complex transformation pipelines, while still maintaining backward - compatibility in the messaging system. - - Note that there is even a global pj_errno, which is here and there accessed - without acquiring lock. This, and the practise of resetting the thread local - errno, should be given some consideration during the cleanup of the error - reporting system. - - The name "last_errno", rather than "errno" is used partially for alignment - with the context->last_errno, partially because in a multithreaded environment, - errno is a macro, and spurious spaces turning "errno" into a separate token - will expose it to macro expansion, to the tune of much confusion and agony. - - **************************************************************************************/ - int last_errno; - + void *(*destructor)(PJ *, int); + /************************************************************************************* @@ -616,7 +562,7 @@ C_NAMESPACE PJ *pj_##name (PJ *P) { \ P = (PJ*) pj_calloc (1, sizeof(PJ)); \ if (0==P) \ return 0; \ - P->pfree = freeup; \ + P->destructor = pj_default_destructor; \ P->descr = des_##name; \ return P; \ } \ @@ -707,8 +653,6 @@ int pj_datum_set(projCtx,paralist *, PJ *); int pj_prime_meridian_set(paralist *, PJ *); int pj_angular_units_set(paralist *, PJ *); -void pj_prepare (PJ *P, const char *description, void (*freeup)(struct PJconsts *), size_t sizeof_struct_opaque); - paralist *pj_clone_paralist( const paralist* ); paralist *pj_search_initcache( const char *filekey ); void pj_insert_initcache( const char *filekey, const paralist *list); @@ -822,6 +766,8 @@ struct PJ_LIST *pj_get_list_ref( void ); struct PJ_SELFTEST_LIST *pj_get_selftest_list_ref ( void ); struct PJ_PRIME_MERIDIANS *pj_get_prime_meridians_ref( void ); +void *pj_default_destructor (PJ *P, int errlev); + double pj_atof( const char* nptr ); double pj_strtod( const char *nptr, char **endptr ); void pj_freeup_plain (PJ *P); -- cgit v1.2.3 From 0495fdca92fc620d44572ce1e4e871f57f968198 Mon Sep 17 00:00:00 2001 From: Kristian Evers Date: Wed, 27 Sep 2017 14:47:07 +0200 Subject: Add PJD_ERR_* aliases for error numbers without one --- src/projects.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src') diff --git a/src/projects.h b/src/projects.h index ece88cde..47f4261f 100644 --- a/src/projects.h +++ b/src/projects.h @@ -470,7 +470,24 @@ struct FACTORS { /* library errors */ #define PJD_ERR_NO_ARGS -1 +#define PJD_ERR_NO_OPTION_IN_INIT_FILE -2 +#define PJD_ERR_NO_COLOR_IN_INIT_STRING -3 +#define PJD_ERR_PROJ_NOT_NAMED -4 +#define PJD_ERR_UNKNOWN_PROJECTION_ID -5 +#define PJD_ERR_ECCENTRICITY_IS_ONE -6 +#define PJD_ERR_UNKNOW_UNIT_ID -7 +#define PJD_ERR_INVALID_BOOLEAN_PARAM -8 +#define PJD_ERR_UNKNOWN_ELLP_PARAM -9 +#define PJD_ERR_REC_FLATTENING_IS_ZERO -10 +#define PJD_ERR_REF_RAD_LARGER_THAN_90 -11 +#define PJD_ERR_ES_LESS_THAN_ZERO -12 +#define PJD_ERR_MAJOR_AXIS_NOT_GIVEN -13 #define PJD_ERR_LAT_OR_LON_EXCEED_LIMIT -14 +#define PJD_ERR_INVALID_X_OR_Y -15 +#define PJD_ERR_WRONG_FORMAT_DMS_VALUE -16 +#define PJD_ERR_NON_CONV_INV_MERI_DIST -17 +#define PJD_ERR_NON_CON_INV_PHI2 -18 +#define PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE -19 #define PJD_ERR_TOLERANCE_CONDITION -20 #define PJD_ERR_CONIC_LAT_EQUAL -21 #define PJD_ERR_LAT_LARGER_THAN_90 -22 @@ -482,20 +499,27 @@ struct FACTORS { #define PJD_ERR_LSAT_NOT_IN_RANGE -28 #define PJD_ERR_PATH_NOT_IN_RANGE -29 #define PJD_ERR_H_LESS_THAN_ZERO -30 +#define PJD_ERR_K_LESS_THAN_ZERO -31 #define PJD_ERR_LAT_1_OR_2_ZERO_OR_90 -32 #define PJD_ERR_LAT_0_OR_ALPHA_EQ_90 -33 #define PJD_ERR_ELLIPSOID_USE_REQUIRED -34 #define PJD_ERR_INVALID_UTM_ZONE -35 +#define PJD_ERR_TCHEBY_VAL_OUT_OF_RANGE -36 #define PJD_ERR_FAILED_TO_FIND_PROJ -37 +#define PJD_ERR_FAILED_TO_LOAD_GRID -38 #define PJD_ERR_INVALID_M_OR_N -39 #define PJD_ERR_N_OUT_OF_RANGE -40 +#define PJD_ERR_LAT_1_2_UNSPECIFIED -41 #define PJD_ERR_ABS_LAT1_EQ_ABS_LAT2 -42 #define PJD_ERR_LAT_0_HALF_PI_FROM_MEAN -43 +#define PJD_ERR_UNPARSEABLE_CS_DEF -44 #define PJD_ERR_GEOCENTRIC -45 #define PJD_ERR_UNKNOWN_PRIME_MERIDIAN -46 #define PJD_ERR_AXIS -47 #define PJD_ERR_GRID_AREA -48 #define PJD_ERR_INVALID_SWEEP_AXIS -49 +#define PJD_ERR_MALFORMED_PIPELINE -50 +#define PJD_ERR_UNIT_FACTOR_LESS_THAN_0 -51 #define PJD_ERR_INVALID_SCALE -52 #define PJD_ERR_NON_CONVERGENT -53 #define PJD_ERR_MISSING_ARGS -54 -- cgit v1.2.3 From 33e1c8e78f7bb826617f08f29e182b530d2ea153 Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Thu, 28 Sep 2017 16:40:27 +0200 Subject: Introducing the cct 'Coordinate Conversion and Transformation' program (#574) * Introducing the cct 'Coordinate Conversion and Transformation' program * cct: Add some rudimentary documentation * Removed documentation again, moving to a separate doc PR * Minor corrections in response to a review by @kbevers --- src/CMakeLists.txt | 6 + src/Makefile.am | 6 +- src/bin_cct.cmake | 9 + src/cct.c | 324 +++++++++++++++++++++++++++++ src/makefile.vc | 8 +- src/optargpm.h | 593 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/proj_strtod.c | 251 +++++++++++++++++++++++ 7 files changed, 1194 insertions(+), 3 deletions(-) create mode 100644 src/bin_cct.cmake create mode 100644 src/cct.c create mode 100644 src/optargpm.h create mode 100644 src/proj_strtod.c (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eec7ddec..788273a9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,6 +3,7 @@ include(lib_proj.cmake) # configure executable build +option(BUILD_CCT "Build cct (coordinate conversion and transformation tool)" ON) option(BUILD_CS2CS "Build cs2cs (coordinate systems to coordinate systems translation tool)" ON) option(BUILD_PROJ "Build proj (cartographic projection tool : latlong <-> projected coordinates" ON) option(BUILD_GEOD "Build geod (computation of geodesic lines)" ON) @@ -22,6 +23,11 @@ if(NOT MSVC) endif () endif () +if(BUILD_CCT) + include(bin_cct.cmake) + set(BIN_TARGETS ${BIN_TARGETS} cct) +endif(BUILD_CCT) + if(BUILD_CS2CS) include(bin_cs2cs.cmake) set(BIN_TARGETS ${BIN_TARGETS} cs2cs) diff --git a/src/Makefile.am b/src/Makefile.am index 12d11c5f..de8fff4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = @C_WFLAGS@ -bin_PROGRAMS = proj nad2bin geod cs2cs +bin_PROGRAMS = proj nad2bin geod cs2cs cct EXTRA_PROGRAMS = multistresstest test228 TESTS = geodtest @@ -12,12 +12,13 @@ AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ include_HEADERS = proj.h proj_api.h projects.h geodesic.h \ org_proj4_Projections.h org_proj4_PJ.h -EXTRA_DIST = makefile.vc proj.def bin_cs2cs.cmake \ +EXTRA_DIST = makefile.vc proj.def bin_cct.cmake bin_cs2cs.cmake \ bin_geod.cmake bin_nad2bin.cmake bin_proj.cmake \ lib_proj.cmake CMakeLists.txt bin_geodtest.cmake geodtest.c proj_SOURCES = proj.c gen_cheb.c p_series.c cs2cs_SOURCES = cs2cs.c gen_cheb.c p_series.c +cct_SOURCES = cct.c proj_strtod.c optargpm.h nad2bin_SOURCES = nad2bin.c geod_SOURCES = geod.c geod_set.c geod_interface.c geod_interface.h multistresstest_SOURCES = multistresstest.c @@ -26,6 +27,7 @@ geodtest_SOURCES = geodtest.c proj_LDADD = libproj.la cs2cs_LDADD = libproj.la +cct_LDADD = libproj.la nad2bin_LDADD = libproj.la geod_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ diff --git a/src/bin_cct.cmake b/src/bin_cct.cmake new file mode 100644 index 00000000..a204e7e7 --- /dev/null +++ b/src/bin_cct.cmake @@ -0,0 +1,9 @@ +set(CCT_SRC cct.c proj_strtod.c) +set(CCT_INCLUDE optargpm.h) + +source_group("Source Files\\Bin" FILES ${CCT_SRC}) + +add_executable(cct ${CCT_SRC} ${CCT_INCLUDE}) +target_link_libraries(cct ${PROJ_LIBRARIES}) +install(TARGETS cct + RUNTIME DESTINATION ${BINDIR}) diff --git a/src/cct.c b/src/cct.c new file mode 100644 index 00000000..83a0b0a3 --- /dev/null +++ b/src/cct.c @@ -0,0 +1,324 @@ +/*********************************************************************** + + The cct 4D Transformation program + +************************************************************************ + +cct is a 4D equivalent to the "proj" projection program. + +cct is an acronym meaning "Coordinate Conversion and Transformation". + +The acronym refers to definitions given in the OGC 08-015r2/ISO-19111 +standard "Geographical Information -- Spatial Referencing by Coordinates", +which defines two different classes of coordinate operations: + +*Coordinate Conversions*, which are coordinate operations where input +and output datum are identical (e.g. conversion from geographical to +cartesian coordinates) and + +*Coordinate Transformations*, which are coordinate operations where +input and output datums differ (e.g. change of reference frame). + +cct, however, also refers to Carl Christian Tscherning (1942--2014), +professor of Geodesy at the University of Copenhagen, mentor and advisor +for a generation of Danish geodesists, colleague and collaborator for +two generations of global geodesists, Secretary General for the +International Association of Geodesy, IAG (1995--2007), fellow of the +Amercan Geophysical Union (1991), recipient of the IAG Levallois Medal +(2007), the European Geosciences Union Vening Meinesz Medal (2008), and +of numerous other honours. + +cct, or Christian, as he was known to most of us, was recognized for his +good mood, his sharp wit, his tireless work, and his great commitment to +the development of geodesy - both through his scientific contributions, +comprising more than 250 publications, and by his mentoring and teaching +of the next generations of geodesists. + +As Christian was an avid Fortran programmer, and a keen Unix connoiseur, +he would have enjoyed to know that his initials would be used to name a +modest Unix style transformation filter, hinting at the tireless aspect +of his personality, which was certainly one of the reasons he accomplished +so much, and meant so much to so many people. + +Hence, in honour of cct (the geodesist) this is cct (the program). + +************************************************************************ + +Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-09-19 + +************************************************************************ + +* Copyright (c) 2016, 2017 Thomas Knudsen +* Copyright (c) 2017, SDFE +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. + +***********************************************************************/ + +#include "optargpm.h" +#include +#include +#include +#include +#include +#include +#include + +double proj_strtod(const char *str, char **endptr); +double proj_atof(const char *str); + +char *column (char *buf, int n); +PJ_COORD parse_input_line (char *buf, int *columns, double fixed_height, double fixed_time); +int print_output_line (FILE *fout, char *buf, PJ_COORD point); +int main(int argc, char **argv); + + + +static const char usage[] = { + "--------------------------------------------------------------------------------\n" + "Usage: %s [-options]... [+operator_specs]... infile...\n" + "--------------------------------------------------------------------------------\n" + "Options:\n" + "--------------------------------------------------------------------------------\n" + " -o /path/to/file Specify output file name\n" + " -c x,y,z,t Specify input columns for (up to) 4 input parameters.\n" + " Defaults to 1,2,3,4\n" + " -z value Provide a fixed z value for all input data (e.g. -z 0)\n" + " -t value Provide a fixed t value for all input data (e.g. -t 0)\n" + " -v Verbose: Provide non-essential informational output.\n" + " Repeat -v for more verbosity (e.g. -vv)\n" + "--------------------------------------------------------------------------------\n" + "Long Options:\n" + "--------------------------------------------------------------------------------\n" + " --output Alias for -o\n" + " --columns Alias for -c\n" + " --height Alias for -z\n" + " --time Alias for -t\n" + " --verbose Alias for -v\n" + " --help Alias for -h\n" + "--------------------------------------------------------------------------------\n" + "Operator Specs:\n" + "--------------------------------------------------------------------------------\n" + "The operator specs describe the action to be performed by cct, e.g:\n" + "\n" + " +proj=utm +ellps=GRS80 +zone=32\n" + "\n" + "instructs cct to convert input data to Universal Transverse Mercator, zone 32\n" + "coordinates, based on the GRS80 ellipsoid.\n" + "\n" + "Hence, the command\n" + "\n" + " echo 12 55 | cct -z0 -t0 +proj=utm +zone=32 +ellps=GRS80\n" + "\n" + "Should give results comparable to the classic proj command\n" + "\n" + " echo 12 55 | proj +proj=utm +zone=32 +ellps=GRS80\n" + "--------------------------------------------------------------------------------\n" + "Examples:\n" + "--------------------------------------------------------------------------------\n" + "1. convert geographical input to UTM zone 32 on the GRS80 ellipsoid:\n" + " cct +proj=utm +ellps=GRS80 +zone=32\n" + "2. roundtrip accuracy check for the case above:\n" + " cct +proj=pipeline +proj=utm +ellps=GRS80 +zone=32 +step +step +inv\n" + "3. as (1) but specify input columns for longitude, latitude, height and time:\n" + " cct -c 5,2,1,4 +proj=utm +ellps=GRS80 +zone=32\n" + "4. as (1) but specify fixed height and time, hence needing only 2 cols in input:\n" + " cct -t 0 -z 0 +proj=utm +ellps=GRS80 +zone=32\n" + "--------------------------------------------------------------------------------\n" +}; + +int main(int argc, char **argv) { + PJ *P; + PJ_COORD point; + OPTARGS *o; + FILE *fout = stdout; + char *buf; + int input_unit, output_unit, nfields = 4, direction = 1, verbose; + double fixed_z = HUGE_VAL, fixed_time = HUGE_VAL; + int columns_xyzt[] = {1, 2, 3, 4}; + const char *longflags[] = {"v=verbose", "h=help", 0}; + const char *longkeys[] = {"o=output", "c=columns", "z=height", "t=time", 0}; + + o = opt_parse (argc, argv, "hv", "cozt", longflags, longkeys); + if (0==o) + return 0; + + if (opt_given (o, "h")) { + printf (usage, o->progname); + return 0; + } + + + direction = opt_given (o, "I")? -1: 1; + verbose = opt_given (o, "v"); + + if (opt_given (o, "o")) + fout = fopen (opt_arg (o, "output"), "rt"); + if (0==fout) { + fprintf (stderr, "%s: Cannot open '%s' for output\n", o->progname, opt_arg (o, "output")); + free (o); + return 1; + } + if (verbose > 3) + fprintf (fout, "%s: Running in very verbose mode\n", o->progname); + + + + if (opt_given (o, "z")) { + fixed_z = proj_atof (opt_arg (o, "z")); + nfields--; + } + + if (opt_given (o, "t")) { + fixed_time = proj_atof (opt_arg (o, "t")); + nfields--; + } + + if (opt_given (o, "c")) { + int ncols = sscanf (opt_arg (o, "c"), "%d,%d,%d,%d", columns_xyzt, columns_xyzt+1, columns_xyzt+3, columns_xyzt+3); + if (ncols != nfields) { + fprintf (stderr, "%s: Too few input columns given: '%s'\n", o->progname, opt_arg (o, "c")); + free (o); + if (stdout != fout) + fclose (fout); + return 1; + } + } + + /* Setup transformation */ + P = proj_create_argv (0, o->pargc, o->pargv); + if ((0==P) || (0==o->pargc)) { + fprintf (stderr, "%s: Bad transformation arguments. '%s -h' for help\n", o->progname, o->progname); + free (o); + if (stdout != fout) + fclose (fout); + return 1; + } + + input_unit = P->left; + output_unit = P->right; + if (PJ_IO_UNITS_CLASSIC==P->left) + input_unit = PJ_IO_UNITS_RADIANS; + if (PJ_IO_UNITS_CLASSIC==P->right) + output_unit = PJ_IO_UNITS_METERS; + if (direction==-1) { + enum pj_io_units swap = input_unit; + input_unit = output_unit; + output_unit = swap; + } + + /* Allocate input buffer */ + buf = calloc (1, 10000); + if (0==buf) { + fprintf (stderr, "%s: Out of memory\n", o->progname); + pj_free (P); + free (o); + if (stdout != fout) + fclose (fout); + return 1; + } + + + /* Loop over all lines of all input files */ + while (opt_input_loop (o, optargs_file_format_text)) { + void *ret = fgets (buf, 10000, o->input); + int res; + opt_eof_handler (o); + if (0==ret) { + fprintf (stderr, "Read error in record %d\n", (int) o->record_index); + continue; + } + point = parse_input_line (buf, columns_xyzt, fixed_z, fixed_time); + if (PJ_IO_UNITS_RADIANS==input_unit) { + point.lpzt.lam = proj_torad (point.lpzt.lam); + point.lpzt.phi = proj_torad (point.lpzt.phi); + } + point = proj_trans_coord (P, direction, point); + if (PJ_IO_UNITS_RADIANS==output_unit) { + point.lpzt.lam = proj_todeg (point.lpzt.lam); + point.lpzt.phi = proj_todeg (point.lpzt.phi); + } + res = print_output_line (fout, buf, point); + if (0==res) { + fprintf (fout, "# UNREADABLE: %s", buf); + if (verbose) + fprintf (stderr, "%s: Could not parse file '%s' line %d\n", o->progname, opt_filename (o), opt_record (o)); + } + } + if (stdout != fout) + fclose (fout); + free (o); + return 0; +} + + + + + +/* return a pointer to the n'th column of buf */ +char *column (char *buf, int n) { + int i; + if (n <= 0) + return buf; + for (i = 0; i < n; i++) { + while (isspace(*buf)) + buf++; + if (i == n - 1) + break; + while ((0 != *buf) && !isspace(*buf)) + buf++; + } + return buf; +} + + +PJ_COORD parse_input_line (char *buf, int *columns, double fixed_height, double fixed_time) { + PJ_COORD err = proj_coord (HUGE_VAL, HUGE_VAL, HUGE_VAL, HUGE_VAL); + PJ_COORD result = err; + int prev_errno = errno; + char *endptr = 0; + errno = 0; + + result.xyzt.z = fixed_height; + result.xyzt.t = fixed_time; + result.xyzt.x = proj_strtod (column (buf, columns[0]), &endptr); + result.xyzt.y = proj_strtod (column (buf, columns[1]), &endptr); + if (result.xyzt.z==HUGE_VAL) + result.xyzt.z = proj_strtod (column (buf, columns[2]), &endptr); + if (result.xyzt.t==HUGE_VAL) + result.xyzt.t = proj_strtod (column (buf, columns[3]), &endptr); + + if (0!=errno) + return err; + + errno = prev_errno; + return result; +} + + +int print_output_line (FILE *fout, char *buf, PJ_COORD point) { + char *c; + if (HUGE_VAL!=point.xyzt.x) + return fprintf (fout, "%20.15f %20.15f %20.15f %20.15f\n", point.xyzt.x, point.xyzt.y, point.xyzt.z, point.xyzt.t); + c = column (buf, 1); + /* reflect comments and blanks */ + if (c && ((*c=='\0') || (*c=='#'))) + return fprintf (fout, "%s\n", buf); + return 0; +} diff --git a/src/makefile.vc b/src/makefile.vc index cc57d806..7ab0dfc7 100644 --- a/src/makefile.vc +++ b/src/makefile.vc @@ -70,11 +70,13 @@ LIBOBJ = $(support) $(pseudo) $(azimuthal) $(conic) $(cylinder) $(misc) \ PROJEXE_OBJ = proj.obj gen_cheb.obj p_series.obj emess.obj CS2CSEXE_OBJ = cs2cs.obj gen_cheb.obj p_series.obj emess.obj GEODEXE_OBJ = geod.obj geod_set.obj geod_interface.obj emess.obj +CCTEXE_OBJ = cct.obj proj_strtod.obj MULTISTRESSTEST_OBJ = multistresstest.obj PROJ_DLL = proj$(VERSION).dll PROJ_EXE = proj.exe CS2CS_EXE = cs2cs.exe GEOD_EXE = geod.exe +CCT_EXE = cct.exe NAD2BIN_EXE = nad2bin.exe MULTISTRESSTEST_EXE = multistresstest.exe @@ -83,7 +85,7 @@ CFLAGS = /nologo -I. -DPROJ_LIB=\"$(PROJ_LIB_DIR)\" \ default: all -all: proj.lib $(PROJ_EXE) $(CS2CS_EXE) $(GEOD_EXE) $(NAD2BIN_EXE) +all: proj.lib $(PROJ_EXE) $(CS2CS_EXE) $(GEOD_EXE) $(CCT_EXE) $(NAD2BIN_EXE) proj.lib: $(LIBOBJ) if exist proj.lib del proj.lib @@ -108,6 +110,10 @@ $(GEOD_EXE): $(GEODEXE_OBJ) $(EXE_PROJ) cl $(GEODEXE_OBJ) $(EXE_PROJ) if exist $(GEOD_EXE).manifest mt -manifest $(GEOD_EXE).manifest -outputresource:$(GEOD_EXE);1 +$(CCT_EXE): $(CCTEXE_OBJ) $(EXE_PROJ) + cl $(CCTEXE_OBJ) $(EXE_PROJ) + if exist $(CCT_EXE).manifest mt -manifest $(CCT_EXE).manifest -outputresource:$(CCT_EXE);1 + $(NAD2BIN_EXE): nad2bin.obj emess.obj $(EXE_PROJ) cl nad2bin.obj emess.obj $(EXE_PROJ) diff --git a/src/optargpm.h b/src/optargpm.h new file mode 100644 index 00000000..6be2c9ef --- /dev/null +++ b/src/optargpm.h @@ -0,0 +1,593 @@ +/*********************************************************************** + + OPTARGPM - a header-only library for decoding + PROJ.4 style command line options + + Thomas Knudsen, 2017-09-10 + +************************************************************************ + +For PROJ.4 command line programs, we have a somewhat complex option +decoding situation, since we have to navigate in a cocktail of classic +single letter style options, prefixed by "-", GNU style long options +prefixwd by "--", transformation specification elements prefixed by "+", +and input file names prefixed by "" nothing. + +Hence, classic getopt.h style decoding does not cut the mustard, so +this is an attempt to catch up and chop the ketchup. + +Since optargpm (for "optarg plus minus") does not belong, in any +obvious way, in any systems development library, it is provided as +a "header only" library. + +While this is conventional in C++, it is frowned at in plain C. +But frown away - "header only" has its places, and this is one of +them. + +By convention, we expect a command line to consist of the following +elements: + + + [short ("-")/long ("--") options} + [operator ("+") specs] + [operands/input files] + +or less verbose: + + [options] [operator specs] [operands] + +or less abstract: + + proj -I --output=foo +proj=utm +zone=32 +ellps=GRS80 bar baz... + +Where + +Operator is proj +Options are -I --output=foo +Operator specs are +proj=utm +zone=32 +ellps=GRS80 +Operands are bar baz + + +While claiming neither to save the world, nor to hint at the "shape of +jazz to come", at least optargpm has shown useful in constructing cs2cs +style transformation filters. + +Supporting a wide range of option syntax, the getoptpm API is somewhat +quirky, but also compact, consisting of one data type, 3(+2) functions, +and one enumeration: + +OPTARGS + Housekeeping data type. An instance of OPTARGS is conventionally + called o or opt +opt_parse (opt, argc, argv ...): + The work horse: Define supported options; Split (argc, argv) + into groups (options, op specs, operands); Parse option + arguments. +opt_given (o, option): + The number of times