From 186c6e3303ccef8e833026e4e9dbaa76be6cb93b Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Fri, 1 Apr 2016 23:10:44 +0200 Subject: First steps toward simplified macros/internals The brief version:: In an attempt to make proj.4 code slightly more secure and much easier to read and maintain, I'm trying to eliminate a few unfortunate design decisions from the early days of proj.4 The work will be *very* intrusive, especially in the PJ_xxx segment of the code tree, but great care has been taken to design a process that can be implemented stepwise and localized, one projection at a time, then finalized with a relatively small and concentrated work package. The (very) long version: See the comments in PJ_minimal.c --- src/projects.h | 78 +++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 23 deletions(-) (limited to 'src/projects.h') diff --git a/src/projects.h b/src/projects.h index 411a3403..3106eb76 100644 --- a/src/projects.h +++ b/src/projects.h @@ -48,7 +48,7 @@ #define C_NAMESPACE extern "C" #define C_NAMESPACE_VAR extern "C" extern "C" { -#else +#else #define C_NAMESPACE extern #define C_NAMESPACE_VAR #endif @@ -132,8 +132,8 @@ typedef struct { /* datum_type values */ #define PJD_UNKNOWN 0 -#define PJD_3PARAM 1 -#define PJD_7PARAM 2 +#define PJD_3PARAM 1 +#define PJD_7PARAM 2 #define PJD_GRIDSHIFT 3 #define PJD_WGS84 4 /* WGS84 (or anything considered equivelent) */ @@ -143,7 +143,7 @@ typedef struct { #define PJD_ERR_GRID_AREA -48 #define PJD_ERR_CATALOG -49 -#define USE_PROJUV +#define USE_PROJUV typedef struct { double u, v; } projUV; typedef struct { double r, i; } COMPLEX; @@ -163,7 +163,7 @@ typedef struct { double lam, phi, z; } LPZ; typedef union { double f; int i; char *s; } PROJVALUE; struct PJconsts; - + struct PJ_LIST { char *id; /* projection keyword */ struct PJconsts *(*proj)(struct PJconsts*);/* projection entry point */ @@ -197,14 +197,14 @@ typedef struct { double ll_long; /* lower left corner coordinates (radians) */ double ll_lat; double ur_long; /* upper right corner coordinates (radians) */ - double ur_lat; + double ur_lat; } PJ_Region; struct DERIVS { double x_l, x_p; /* derivatives of x for lambda-phi */ double y_l, y_p; /* derivatives of y for lambda-phi */ }; - + struct FACTORS { struct DERIVS der; double h, k; /* meridinal, parallel scales */ @@ -226,12 +226,18 @@ typedef struct ARG_list { /* base projection data structure */ +#ifdef PJ_LIB__ + /* we need this forward declaration in order to be able to add a + pointer to struct opaque to the typedef struct PJconsts below */ + struct opaque; +#endif + typedef struct PJconsts { projCtx_t *ctx; XY (*fwd)(LP, struct PJconsts *); LP (*inv)(XY, struct PJconsts *); XYZ (*fwd3d)(LPZ, struct PJconsts *); - LPZ (*inv3d)(XYZ, struct PJconsts *); + LPZ (*inv3d)(XYZ, struct PJconsts *); void (*spc)(LP, struct PJconsts *, struct FACTORS *); void (*pfree)(struct PJconsts *); const char *descr; @@ -253,7 +259,7 @@ typedef struct PJconsts { x0, y0, /* easting and northing */ k0, /* general scaling factor */ to_meter, fr_meter; /* cartesian scaling */ - + int datum_type; /* PJD_UNKNOWN/3PARAM/7PARAM/GRIDSHIFT/WGS84 */ double datum_params[7]; struct _pj_gi **gridlist; @@ -272,9 +278,9 @@ typedef struct PJconsts { /* New Datum Shift Grid Catalogs */ char *catalog_name; struct _PJ_GridCatalog *catalog; - + double datum_date; - + struct _pj_gi *last_before_grid; PJ_Region last_before_region; double last_before_date; @@ -283,6 +289,10 @@ typedef struct PJconsts { PJ_Region last_after_region; double last_after_date; +#ifdef PJ_LIB__ + struct opaque *opaq; +#endif + #ifdef PROJ_PARMS__ PROJ_PARMS__ #endif /* end of optional extensions */ @@ -297,7 +307,7 @@ extern struct PJ_LIST pj_list[]; #else #define PROJ_HEAD(id, name) \ struct PJconsts *pj_##id(struct PJconsts*); extern char * const pj_s_##id; - + #include "pj_list.h" #undef PROJ_HEAD #define PROJ_HEAD(id, name) {#id, pj_##id, &pj_s_##id}, @@ -350,7 +360,27 @@ extern struct PJ_PRIME_MERIDIANS pj_prime_meridians[]; #define INVERSE3D(name) static LPZ name(XYZ xyz, PJ *P) {LPZ lpz = {0.0, 0.0, 0.0} #define FREEUP static void freeup(PJ *P) { #define SPECIAL(name) static void name(LP lp, PJ *P, struct FACTORS *fac) + + +/* cleaned up alternative to most of the "repetitive projection code" macros */ +#define PROJECTION(name) \ +pj_projection_specific_setup_##name (PJ *P); \ +C_NAMESPACE_VAR const char * const pj_s_##name = des_##name; \ +C_NAMESPACE PJ *pj_##name (PJ *P) { \ + if (P) \ + return pj_projection_specific_setup_##name (P); \ + P = (PJ*) pj_calloc (1, sizeof(PJ)); \ + if (0==P) \ + return 0; \ + P->pfree = freeup; \ + P->descr = des_##name; \ + return P; \ +} \ +PJ *pj_projection_specific_setup_##name (PJ *P) + #endif + + #define MAX_TAB_ID 80 typedef struct { float lam, phi; } FLP; typedef struct { int lam, phi; } ILP; @@ -366,8 +396,8 @@ struct CTABLE { typedef struct _pj_gi { char *gridname; /* identifying name of grid, eg "conus" or ntv2_0.gsb */ char *filename; /* full path to filename */ - - const char *format; /* format of this grid, ie "ctable", "ntv1", + + const char *format; /* format of this grid, ie "ctable", "ntv1", "ntv2" or "missing". */ int grid_offset; /* offset in file, for delayed loading */ @@ -414,6 +444,7 @@ int pj_ell_set(projCtx ctx, paralist *, double *, double *); 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 ); @@ -439,7 +470,7 @@ struct PW_COEF {/* row coefficient structure */ int m; /* number of c coefficients (=0 for none) */ double *c; /* power coefficients */ }; - + /* Approximation structures and procedures */ typedef struct { /* Chebyshev or Power series structure */ projUV a, b; /* power series range for evaluation */ @@ -457,6 +488,7 @@ void **vector2(int, int, int); void freev2(void **v, int nrows); int bchgen(projUV, projUV, int, int, projUV **, projUV(*)(projUV)); int bch2bps(projUV, projUV, projUV **, int, int); + /* nadcon related protos */ LP nad_intr(LP, struct CTABLE *); LP nad_cvt(LP, int, struct CTABLE *); @@ -470,15 +502,15 @@ void nad_free(struct CTABLE *); /* higher level handling of datum grid shift files */ int pj_apply_vgridshift( PJ *defn, const char *listname, - PJ_GRIDINFO ***gridlist_p, + PJ_GRIDINFO ***gridlist_p, int *gridlist_count_p, - int inverse, + int inverse, long point_count, int point_offset, double *x, double *y, double *z ); -int pj_apply_gridshift_2( PJ *defn, int inverse, +int pj_apply_gridshift_2( PJ *defn, int inverse, long point_count, int point_offset, double *x, double *y, double *z ); -int pj_apply_gridshift_3( projCtx ctx, +int pj_apply_gridshift_3( projCtx ctx, PJ_GRIDINFO **gridlist, int gridlist_count, int inverse, long point_count, int point_offset, double *x, double *y, double *z ); @@ -493,15 +525,15 @@ void pj_gridinfo_free( projCtx, PJ_GRIDINFO * ); PJ_GridCatalog *pj_gc_findcatalog( projCtx, const char * ); PJ_GridCatalog *pj_gc_readcatalog( projCtx, const char * ); void pj_gc_unloadall( projCtx ); -int pj_gc_apply_gridshift( PJ *defn, int inverse, +int pj_gc_apply_gridshift( PJ *defn, int inverse, long point_count, int point_offset, double *x, double *y, double *z ); -int pj_gc_apply_gridshift( PJ *defn, int inverse, +int pj_gc_apply_gridshift( PJ *defn, int inverse, long point_count, int point_offset, double *x, double *y, double *z ); -PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, - PJ_GridCatalog *catalog, int after, +PJ_GRIDINFO *pj_gc_findgrid( projCtx ctx, + PJ_GridCatalog *catalog, int after, LP location, double date, PJ_Region *optional_region, double *grid_date ); -- cgit v1.2.3 From eeea65526dfd0301a7759a978a5b8fcbcf5baecd Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Tue, 5 Apr 2016 19:05:06 +0200 Subject: Some initial work on internal regression tests Need these to reduce the chance I'm screwing up something during this rather intrusive code surgery --- src/projects.h | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src/projects.h') diff --git a/src/projects.h b/src/projects.h index 3106eb76..2b638e94 100644 --- a/src/projects.h +++ b/src/projects.h @@ -229,7 +229,7 @@ typedef struct ARG_list { #ifdef PJ_LIB__ /* we need this forward declaration in order to be able to add a pointer to struct opaque to the typedef struct PJconsts below */ - struct opaque; + struct pj_opaque; #endif typedef struct PJconsts { @@ -290,7 +290,7 @@ typedef struct PJconsts { double last_after_date; #ifdef PJ_LIB__ - struct opaque *opaq; + struct pj_opaque *opaque; #endif #ifdef PROJ_PARMS__ @@ -381,6 +381,24 @@ PJ *pj_projection_specific_setup_##name (PJ *P) #endif +int pj_generic_selftest ( + char *e_args, + char *s_args, + double tolerance_xy, + double tolerance_lp, + int n_fwd, + int n_inv, + LP *fwd_in, + XY *e_fwd_expect, + XY *s_fwd_expect, + XY *inv_in, + LP *e_inv_expect, + LP *s_inv_expect +); + + + + #define MAX_TAB_ID 80 typedef struct { float lam, phi; } FLP; typedef struct { int lam, phi; } ILP; -- cgit v1.2.3 From 2d111097d76ce52fb0ba019b20e02b33abe842ed Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Thu, 7 Apr 2016 22:21:21 +0200 Subject: pj_list cleanup + added selftest stubs for all projections The projection list maintained by code in pj_list.c depended on stuff in projects.h. This stuff is non-obvious and since it is only used in pj_list.c, it has been moved from projects.h to pj_list.c (The material moved is based on some really clever X-macro techniques implemented by numerous redefinitions of the PROJ_HEAD macro, followed by immediate re-inclusion of te pj_list.h file). Also, the self test runner pj_run_selftests has been remodelled, now depending on a list of self test functions, generated in a similar way to the projection list, and like the projection list generated by X-macro techniques in pj_list.c. For this to work, self test functions need to be available for all projections. To fulfill this, stubs for all projections not having self tests already, have been added to PJ_aea.c Along with the recent build system patches by @kbevers, this first part of the macro-refactoring project is considered close to finished. --- src/projects.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/projects.h') diff --git a/src/projects.h b/src/projects.h index 2b638e94..307b69bd 100644 --- a/src/projects.h +++ b/src/projects.h @@ -169,6 +169,13 @@ struct PJ_LIST { struct PJconsts *(*proj)(struct PJconsts*);/* projection entry point */ char * const *descr; /* description text */ }; + +/* Merging this into the PJ_LIST infrastructure is tempting, but may imply ABI breakage. Perhaps at next major version? */ +struct PJ_SELFTEST_LIST { + char *id; /* projection keyword */ + int (* testfunc)(void); /* projection entry point */ +}; + struct PJ_ELLPS { char *id; /* ellipse keyword name */ char *major; /* a= value */ @@ -301,24 +308,16 @@ PROJ_PARMS__ /* public API */ #include "proj_api.h" + /* Generate pj_list external or make list from include file */ + #ifndef USE_PJ_LIST_H extern struct PJ_LIST pj_list[]; -#else -#define PROJ_HEAD(id, name) \ - struct PJconsts *pj_##id(struct PJconsts*); extern char * const pj_s_##id; - -#include "pj_list.h" -#undef PROJ_HEAD -#define PROJ_HEAD(id, name) {#id, pj_##id, &pj_s_##id}, - struct PJ_LIST -pj_list[] = { -#include "pj_list.h" - {0, 0, 0}, - }; -#undef PROJ_HEAD +extern struct PJ_SELFTEST_LIST pj_selftest_list[]; #endif + + #ifndef PJ_ELLPS__ extern struct PJ_ELLPS pj_ellps[]; #endif @@ -571,6 +570,7 @@ struct PJ_ELLPS *pj_get_ellps_ref( void ); struct PJ_DATUMS *pj_get_datums_ref( void ); struct PJ_UNITS *pj_get_units_ref( void ); 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 ); double pj_atof( const char* nptr ); -- cgit v1.2.3 From 86a3221bdc26ea2cdbe85fcf270263ce02fef0e6 Mon Sep 17 00:00:00 2001 From: Thomas Knudsen Date: Tue, 12 Apr 2016 17:25:22 +0200 Subject: refactoring + added selftest for 8 more projections calcofi, cass,cc,wag2, wag3, wag7, wink1, wink2 --- src/projects.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/projects.h') diff --git a/src/projects.h b/src/projects.h index 307b69bd..2957f848 100644 --- a/src/projects.h +++ b/src/projects.h @@ -359,7 +359,7 @@ extern struct PJ_PRIME_MERIDIANS pj_prime_meridians[]; #define INVERSE3D(name) static LPZ name(XYZ xyz, PJ *P) {LPZ lpz = {0.0, 0.0, 0.0} #define FREEUP static void freeup(PJ *P) { #define SPECIAL(name) static void name(LP lp, PJ *P, struct FACTORS *fac) - +#define ELLIPSOIDAL(P) ((P->es==0)? (FALSE): (TRUE)) /* cleaned up alternative to most of the "repetitive projection code" macros */ #define PROJECTION(name) \ -- cgit v1.2.3