diff options
| author | Kristian Evers <kristianevers@gmail.com> | 2017-10-09 21:55:30 +0200 |
|---|---|---|
| committer | Kristian Evers <kristianevers@gmail.com> | 2017-10-09 21:55:30 +0200 |
| commit | 0d4ce7814091a716fc835eb3abe3ad41d49f3ee1 (patch) | |
| tree | 2404ee17446b91fe4c776445ad2b30db866ed8ef | |
| parent | f8d26297de7f6092e78bcd33876510c7082c3f35 (diff) | |
| parent | 8fc250a04edbfe81b9b7409187887066baeba29b (diff) | |
| download | PROJ-0d4ce7814091a716fc835eb3abe3ad41d49f3ee1.tar.gz PROJ-0d4ce7814091a716fc835eb3abe3ad41d49f3ee1.zip | |
Merge remote-tracking branch 'osgeo/master' into docs-release-4.10.0
161 files changed, 2855 insertions, 3004 deletions
@@ -1,4 +1,6 @@ *~ +build.local.bat +build.local.sh Makefile Makefile.in CMakeFiles @@ -8,8 +10,10 @@ cmake_install.cmake install_manifest.txt cmake/project-config*.cmake +/.vs* /*.manifest /*.swp +/*build* /aclocal.m4 /autom4te.cache /config.cache @@ -16,3 +16,4 @@ Karsten Engsager Knud Poder Kristian Evers <kreve@sdfe.dk> Thomas Knudsen <thokn@sdfe.dk> +Even Rouault <even.rouault@spatialys.com> diff --git a/CMakeLists.txt b/CMakeLists.txt index 702eafaf..d6bbe8ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -128,6 +128,7 @@ set(LIBDIR "${DEFAULT_LIBDIR}" CACHE PATH "The directory to install libraries in set(DATADIR "${DEFAULT_DATADIR}" CACHE PATH "The directory to install data files into.") set(DOCDIR "${DEFAULT_DOCDIR}" CACHE PATH "The directory to install doc files into.") set(INCLUDEDIR "${DEFAULT_INCLUDEDIR}" CACHE PATH "The directory to install includes into.") +set(CMAKECONFIGDIR "${DEFAULT_CMAKEDIR}" CACHE PATH "The directory to install cmake config files into.") ################################################################################# # Build configured components diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 742da0e9..0fcde0ca 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -2,13 +2,7 @@ # ${INSTALL_CMAKE_DIR} and @PROJECT_ROOT_DIR@ is the relative # path to the root from there. (Note that the whole install tree can # be relocated.) -if (NOT WIN32) - set (INSTALL_CMAKE_DIR "share/cmake/${PROJECT_NAME}") - set (PROJECT_ROOT_DIR "../../..") -else () - set (INSTALL_CMAKE_DIR "cmake") - set (PROJECT_ROOT_DIR "..") -endif () +file(RELATIVE_PATH PROJECT_ROOT_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKECONFIGDIR} ${CMAKE_INSTALL_PREFIX}) string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER) configure_file (project-config.cmake.in project-config.cmake @ONLY) @@ -16,14 +10,14 @@ configure_file (project-config-version.cmake.in project-config-version.cmake @ONLY) install (FILES "${CMAKE_CURRENT_BINARY_DIR}/project-config.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}" + DESTINATION "${CMAKECONFIGDIR}" RENAME "${PROJECT_NAME_LOWER}-config.cmake") install (FILES "${CMAKE_CURRENT_BINARY_DIR}/project-config-version.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}" + DESTINATION "${CMAKECONFIGDIR}" RENAME "${PROJECT_NAME_LOWER}-config-version.cmake") # Make information about the cmake targets (the library and the tools) # available. install (EXPORT targets FILE ${PROJECT_NAME_LOWER}-targets.cmake - DESTINATION "${INSTALL_CMAKE_DIR}") + DESTINATION "${CMAKECONFIGDIR}") diff --git a/cmake/Proj4InstallPath.cmake b/cmake/Proj4InstallPath.cmake index da1491c0..b06777f4 100644 --- a/cmake/Proj4InstallPath.cmake +++ b/cmake/Proj4InstallPath.cmake @@ -15,19 +15,29 @@ endif(UNIX) IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - SET(CMAKE_INSTALL_PREFIX ${DEFAULT_PROJ_ROOT_DIR} CACHE PATH "Foo install + SET(CMAKE_INSTALL_PREFIX ${DEFAULT_PROJ_ROOT_DIR} CACHE PATH "Proj.4 install prefix" FORCE) ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) -#TODO +#TODO # for data install testing the PROJ_LIB envVar +string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_LOWER) if(WIN32) set(DEFAULT_BIN_SUBDIR bin) set(DEFAULT_LIB_SUBDIR local/lib) set(DEFAULT_DATA_SUBDIR share) set(DEFAULT_INCLUDE_SUBDIR local/include) set(DEFAULT_DOC_SUBDIR share/doc/proj) + set(DEFAULT_CMAKE_SUBDIR local/lib/cmake/${PROJECT_NAME_LOWER}) +elseif(UNIX) + include(GNUInstallDirs) + set(DEFAULT_BIN_SUBDIR ${CMAKE_INSTALL_BINDIR}) + set(DEFAULT_LIB_SUBDIR ${CMAKE_INSTALL_LIBDIR}) + set(DEFAULT_DATA_SUBDIR ${CMAKE_INSTALL_DATAROOTDIR}/proj) + set(DEFAULT_INCLUDE_SUBDIR ${CMAKE_INSTALL_INCLUDEDIR}) + set(DEFAULT_DOC_SUBDIR ${CMAKE_INSTALL_DOCDIR}) + set(DEFAULT_CMAKE_SUBDIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME_LOWER}) else() # Common locatoins for Unix and Mac OS X set(DEFAULT_BIN_SUBDIR bin) @@ -35,9 +45,11 @@ else() set(DEFAULT_DATA_SUBDIR share/proj) set(DEFAULT_DOC_SUBDIR doc/proj) set(DEFAULT_INCLUDE_SUBDIR include) + set(DEFAULT_DOC_SUBDIR share/doc/proj) + set(DEFAULT_CMAKE_SUBDIR lib/cmake/${PROJECT_NAME_LOWER}) endif() -# Locations are changeable by user to customize layout of PDAL installation +# Locations are changeable by user to customize layout of Proj.4 installation # (default values are platform-specific) set(PROJ_BIN_SUBDIR ${DEFAULT_BIN_SUBDIR} CACHE STRING "Subdirectory where executables will be installed") @@ -48,20 +60,24 @@ set(PROJ_INCLUDE_SUBDIR ${DEFAULT_INCLUDE_SUBDIR} CACHE STRING set(PROJ_DATA_SUBDIR ${DEFAULT_DATA_SUBDIR} CACHE STRING "Subdirectory where data will be installed") set(PROJ_DOC_SUBDIR ${DEFAULT_DOC_SUBDIR} CACHE STRING - "Subdirectory where data will be installed") + "Subdirectory where doc will be installed") +set(PROJ_CMAKE_SUBDIR ${DEFAULT_CMAKE_SUBDIR} CACHE STRING + "Subdirectory where cmake proj4-config file will be installed") # Mark *DIR variables as advanced and dedicated to use by power-users only. mark_as_advanced(PROJ_ROOT_DIR PROJ_BIN_SUBDIR - PROJ_LIB_SUBDIR - PROJ_INCLUDE_SUBDIR + PROJ_LIB_SUBDIR + PROJ_INCLUDE_SUBDIR PROJ_DATA_SUBDIR - PROJ_DOC_SUBDIR ) + PROJ_DOC_SUBDIR + PROJ_CMAKE_SUBDIR ) set(DEFAULT_BINDIR "${PROJ_BIN_SUBDIR}") set(DEFAULT_LIBDIR "${PROJ_LIB_SUBDIR}") set(DEFAULT_DATADIR "${PROJ_DATA_SUBDIR}") set(DEFAULT_DOCDIR "${PROJ_DOC_SUBDIR}") set(DEFAULT_INCLUDEDIR "${PROJ_INCLUDE_SUBDIR}") +set(DEFAULT_CMAKEDIR "${PROJ_CMAKE_SUBDIR}") diff --git a/cmake/Proj4SystemInfo.cmake b/cmake/Proj4SystemInfo.cmake index 294a50b2..fda57edb 100644 --- a/cmake/Proj4SystemInfo.cmake +++ b/cmake/Proj4SystemInfo.cmake @@ -50,6 +50,12 @@ if(WIN32) if(MSVC_VERSION EQUAL 1800) set(PROJ_COMPILER_NAME "msvc-12.0") #Visual Studio 2013 endif() + if(MSVC_VERSION EQUAL 1900) # CMake 3.1+ + set(PROJ_COMPILER_NAME "msvc-14.0") #Visual Studio 2015 + endif() + if(MSVC_VERSION GREATER 1900 AND MSVC_VERSION LESS 1920) # CMake 3.8+ + set(PROJ_COMPILER_NAME "msvc-14.1") #Visual Studio 2017 + endif() endif(MSVC) if(MINGW) diff --git a/cmake/policies.cmake b/cmake/policies.cmake index c16fbc12..e1bfd53b 100644 --- a/cmake/policies.cmake +++ b/cmake/policies.cmake @@ -1,5 +1,4 @@ if (CMAKE_MAJOR_VERSION GREATER 2) - cmake_policy(SET CMP0022 OLD) # interface link libraries cmake_policy(SET CMP0042 NEW) # osx rpath cmake_policy(SET CMP0011 NEW) # policy setting endif() diff --git a/docs/source/download.rst b/docs/source/download.rst index 7db468c6..4b9cbb92 100644 --- a/docs/source/download.rst +++ b/docs/source/download.rst @@ -46,7 +46,7 @@ Docker ................................................................................ A `Docker`_ image with just PROJ.4 binaries and a full compliment of grid shift -files is available on `DockerHub`: +files is available on `DockerHub`_: .. _`Docker`: https://docker.org .. _`DockerHub`: https://hub.docker.com/r/osgeo/proj.4/ diff --git a/man/man3/geodesic.3 b/man/man3/geodesic.3 index 310fc3d5..938eed68 100644 --- a/man/man3/geodesic.3 +++ b/man/man3/geodesic.3 @@ -53,7 +53,7 @@ measure angles (latitudes, longitudes, and azimuths) in degrees, unlike the rest of the \fBproj\fR library, which uses radians. The documentation for this library is included in geodesic.h. A formatted version of the documentation is available at -https://geographiclib.sourceforge.io/1.48/C +https://geographiclib.sourceforge.io/1.49/C .SH EXAMPLE The following program reads in lines with the coordinates for two points in decimal degrees (\fIlat1\fR, \fIlon1\fR, \fIlat2\fR, \fIlon2\fR) and @@ -87,7 +87,7 @@ libproj.a \- library of projections and support procedures .SH SEE ALSO Full online documentation for \fBgeodesic(3)\fR, .br -https://geographiclib.sourceforge.io/1.48/C +https://geographiclib.sourceforge.io/1.49/C .PP .B geod(1) .PP diff --git a/nad/testvarious b/nad/testvarious index f11bc806..4ca20a63 100755 --- a/nad/testvarious +++ b/nad/testvarious @@ -642,14 +642,14 @@ EOF echo "##############################################################" >> ${OUT} echo "Check inverse error handling with ob_tran (#225)" >> ${OUT} $EXE +proj=ob_tran \ - +o_proj=moll +o_lon_p=LON_POLE +o_lat_p=LAT_POLE +lon_0=180 +ellps=WGS84 \ + +o_proj=moll +a=6378137 +es=0 +o_lon_p=LON_POLE +o_lat_p=LAT_POLE +lon_0=180 \ -E >>${OUT} <<EOF 300000 400000 20000000 30000000 EOF echo "Test inverse handling" >> ${OUT} $EXE -I +proj=ob_tran \ - +o_proj=moll +o_lon_p=LON_POLE +o_lat_p=LAT_POLE +lon_0=180 +ellps=WGS84 \ + +o_proj=moll +a=6378137 +es=0 +o_lon_p=LON_POLE +o_lat_p=LAT_POLE +lon_0=180 \ -E >>${OUT} <<EOF 10 20 EOF @@ -894,6 +894,11 @@ if [ $? -ne 0 ] ; then echo "PROBLEMS HAVE OCCURRED" echo "test file ${OUT} saved" echo + echo "----------------------------------------------------------" + echo "${OUT}" + echo "----------------------------------------------------------" + cat ${OUT} + echo "----------------------------------------------------------" exit 100 else echo "TEST OK" 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 dbfefe9c..25b7456c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,31 +1,38 @@ AM_CFLAGS = @C_WFLAGS@ -bin_PROGRAMS = proj nad2bin geod cs2cs +bin_PROGRAMS = proj nad2bin geod cs2cs cct EXTRA_PROGRAMS = multistresstest test228 +TESTS = geodtest +check_PROGRAMS = geodtest + AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ -DMUTEX_@MUTEX_SETTING@ @JNI_INCLUDE@ 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 test228_SOURCES = test228.c +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@ test228_LDADD = libproj.la @THREAD_LIB@ +geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la @@ -44,7 +51,7 @@ libproj_la_SOURCES = \ PJ_tcc.c PJ_tcea.c PJ_times.c PJ_tmerc.c \ PJ_airy.c PJ_aitoff.c PJ_august.c PJ_bacon.c \ PJ_chamb.c PJ_hammer.c PJ_lagrng.c PJ_larr.c \ - PJ_lask.c PJ_nocol.c PJ_ob_tran.c PJ_oea.c \ + PJ_lask.c PJ_latlong.c PJ_nocol.c PJ_ob_tran.c PJ_oea.c \ PJ_tpeqd.c PJ_vandg.c PJ_vandg2.c PJ_vandg4.c \ PJ_wag7.c PJ_lcca.c PJ_geos.c proj_etmerc.c \ PJ_boggs.c PJ_collg.c PJ_comill.c PJ_crast.c PJ_denoy.c \ @@ -55,7 +62,7 @@ libproj_la_SOURCES = \ PJ_nell.c PJ_nell_h.c PJ_patterson.c PJ_putp2.c PJ_putp3.c \ PJ_putp4p.c PJ_putp5.c PJ_putp6.c PJ_qsc.c PJ_robin.c \ PJ_sch.c PJ_sts.c PJ_urm5.c PJ_urmfps.c PJ_wag2.c \ - PJ_wag3.c PJ_wink1.c PJ_wink2.c pj_latlong.c pj_geocent.c \ + PJ_wag3.c PJ_wink1.c PJ_wink2.c pj_geocent.c \ aasincos.c adjlon.c bch2bps.c bchgen.c \ biveval.c dmstor.c mk_cheby.c pj_auth.c \ pj_deriv.c pj_ell_set.c pj_ellps.c pj_errno.c \ diff --git a/src/PJ_aea.c b/src/PJ_aea.c index 7d0e935d..228d3afd 100644 --- a/src/PJ_aea.c +++ b/src/PJ_aea.c @@ -29,6 +29,7 @@ #define PJ_LIB__ #include <proj.h> +#include <errno.h> #include "projects.h" # define EPS10 1.e-10 @@ -79,23 +80,19 @@ struct pj_opaque { }; -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); + return pj_default_destructor (P, errlev); } -static void freeup (PJ *P) { - freeup_new (P); - return; -} + static XY e_forward (LP lp, PJ *P) { /* Ellipsoid/spheroid, forward */ @@ -154,17 +151,16 @@ static PJ *setup(PJ *P) { P->inv = e_inverse; P->fwd = e_forward; - if (fabs(Q->phi1 + Q->phi2) < EPS10) { - proj_errno_set(P, PJD_ERR_CONIC_LAT_EQUAL); - return freeup_new(P); - } + if (fabs(Q->phi1 + Q->phi2) < EPS10) + return destructor(P, PJD_ERR_CONIC_LAT_EQUAL); Q->n = sinphi = sin(Q->phi1); cosphi = cos(Q->phi1); secant = fabs(Q->phi1 - Q->phi2) >= EPS10; if( (Q->ellips = (P->es > 0.))) { double ml1, m1; - if (!(Q->en = pj_enfn(P->es))) return freeup_new(P); + if (!(Q->en = pj_enfn(P->es))) + return destructor(P, 0); m1 = pj_msfn(sinphi, cosphi, P->es); ml1 = pj_qsfn(sinphi, P->e, P->one_es); if (secant) { /* secant cone */ @@ -175,9 +171,8 @@ static PJ *setup(PJ *P) { m2 = pj_msfn(sinphi, cosphi, P->es); ml2 = pj_qsfn(sinphi, P->e, P->one_es); if (ml2 == ml1) - { - return freeup_new(P); - } + return destructor(P, 0); + Q->n = (m1 * m1 - m2 * m2) / (ml2 - ml1); } Q->ec = 1. - .5 * P->one_es * log((1. - P->e) / @@ -201,8 +196,9 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(aea) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; @@ -213,7 +209,7 @@ PJ *PROJECTION(aea) { PJ *PROJECTION(leac) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->phi2 = pj_param(P->ctx, P->params, "rlat_1").f; diff --git a/src/PJ_aeqd.c b/src/PJ_aeqd.c index 4a46cf1c..c6fa9e06 100644 --- a/src/PJ_aeqd.c +++ b/src/PJ_aeqd.c @@ -28,6 +28,7 @@ #define PJ_LIB__ #include "geodesic.h" #include <proj.h> +#include <errno.h> #include "projects.h" struct pj_opaque { @@ -54,23 +55,18 @@ PROJ_HEAD(aeqd, "Azimuthal Equidistant") "\n\tAzi, Sph&Ell\n\tlat_0 guam"; #define OBLIQ 3 -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); - if (P->opaque->en) - pj_dealloc(P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); + pj_dealloc (P->opaque->en); + return pj_default_destructor (P, errlev); } -static void freeup (PJ *P) { - freeup_new (P); - return; -} static XY e_guam_fwd(LP lp, PJ *P) { /* Guam elliptical */ XY xy = {0.0,0.0}; @@ -268,8 +264,9 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ PJ *PROJECTION(aeqd) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; geod_init(&Q->g, P->a, P->es / (1 + sqrt(P->one_es))); P->phi0 = pj_param(P->ctx, P->params, "rlat_0").f; @@ -290,7 +287,8 @@ PJ *PROJECTION(aeqd) { P->inv = s_inverse; P->fwd = s_forward; } else { - if (!(Q->en = pj_enfn(P->es))) return freeup_new(P); + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor (P, 0); if (pj_param(P->ctx, P->params, "bguam").i) { Q->M1 = pj_mlfn(P->phi0, Q->sinph0, Q->cosph0, Q->en); P->inv = e_guam_inv; diff --git a/src/PJ_airy.c b/src/PJ_airy.c index 2c58bb79..d832b9b7 100644 --- a/src/PJ_airy.c +++ b/src/PJ_airy.c @@ -28,6 +28,7 @@ #define PJ_LIB__ #include <proj.h> +#include <errno.h> #include "projects.h" PROJ_HEAD(airy, "Airy") "\n\tMisc Sph, no inv.\n\tno_cut lat_b="; @@ -104,28 +105,13 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(airy) { double beta; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/PJ_aitoff.c b/src/PJ_aitoff.c index 8b1d7f94..3455fa71 100644 --- a/src/PJ_aitoff.c +++ b/src/PJ_aitoff.c @@ -30,6 +30,7 @@ #define PJ_LIB__ #include <proj.h> +#include <errno.h> #include "projects.h" @@ -152,22 +153,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } - -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - static PJ *setup(PJ *P) { P->inv = s_inverse; P->fwd = s_forward; @@ -179,7 +164,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(aitoff) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; Q->mode = 0; @@ -190,15 +175,13 @@ PJ *PROJECTION(aitoff) { PJ *PROJECTION(wintri) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; Q->mode = 1; if (pj_param(P->ctx, P->params, "tlat_1").i) { - if ((Q->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f)) == 0.) { - proj_errno_set(P, PJD_ERR_LAT_LARGER_THAN_90); - return freeup_new(P); - } + if ((Q->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f)) == 0.) + return pj_default_destructor (P, PJD_ERR_LAT_LARGER_THAN_90); } else /* 50d28' or acos(2/pi) */ Q->cosphi1 = 0.636619772367581343; diff --git a/src/PJ_august.c b/src/PJ_august.c index f5028938..d81644bf 100644 --- a/src/PJ_august.c +++ b/src/PJ_august.c @@ -23,15 +23,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(august) { P->inv = 0; diff --git a/src/PJ_bacon.c b/src/PJ_bacon.c index a9c6da44..cb7286be 100644 --- a/src/PJ_bacon.c +++ b/src/PJ_bacon.c @@ -1,6 +1,7 @@ # define HLFPI2 2.46740110027233965467 /* (pi/2)^2 */ # define EPS 1e-10 #define PJ_LIB__ +#include <errno.h> #include <projects.h> @@ -34,26 +35,11 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(bacon) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->bacn = 1; @@ -67,7 +53,7 @@ PJ *PROJECTION(bacon) { PJ *PROJECTION(apian) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->bacn = Q->ortl = 0; @@ -80,7 +66,7 @@ PJ *PROJECTION(apian) { PJ *PROJECTION(ortel) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->bacn = 0; diff --git a/src/PJ_bipc.c b/src/PJ_bipc.c index 97284fcc..0019d614 100644 --- a/src/PJ_bipc.c +++ b/src/PJ_bipc.c @@ -1,5 +1,6 @@ #define PJ_LIB__ #include <proj.h> +#include <errno.h> #include "projects.h" PROJ_HEAD(bipc, "Bipolar conic of western hemisphere") "\n\tConic Sph."; @@ -156,23 +157,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(bipc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->noskew = pj_param(P->ctx, P->params, "bns").i; diff --git a/src/PJ_boggs.c b/src/PJ_boggs.c index 8ede9f16..e6efd7d3 100644 --- a/src/PJ_boggs.c +++ b/src/PJ_boggs.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +# include <errno.h> # include <projects.h> PROJ_HEAD(boggs, "Boggs Eumorphic") "\n\tPCyl., no inv., Sph."; # define NITER 20 @@ -33,15 +34,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(boggs) { P->es = 0.; diff --git a/src/PJ_bonne.c b/src/PJ_bonne.c index 2a576c60..368829c5 100644 --- a/src/PJ_bonne.c +++ b/src/PJ_bonne.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -83,20 +84,16 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ + +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor (P, errlev); } @@ -104,14 +101,14 @@ PJ *PROJECTION(bonne) { double c; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; - if (fabs(Q->phi1) < EPS10) { - proj_errno_set(P, PJD_ERR_LAT1_IS_ZERO); - return freeup_new(P); - } + if (fabs(Q->phi1) < EPS10) + return destructor (P, PJD_ERR_LAT1_IS_ZERO); + if (P->es != 0.0) { Q->en = pj_enfn(P->es); Q->m1 = pj_mlfn(Q->phi1, Q->am1 = sin(Q->phi1), diff --git a/src/PJ_calcofi.c b/src/PJ_calcofi.c index 25521eed..b188f7e9 100644 --- a/src/PJ_calcofi.c +++ b/src/PJ_calcofi.c @@ -149,16 +149,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc (P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(calcofi) { P->opaque = 0; diff --git a/src/PJ_cart.c b/src/PJ_cart.c index 1373e870..914fa94b 100644 --- a/src/PJ_cart.c +++ b/src/PJ_cart.c @@ -108,11 +108,6 @@ PROJ_HEAD(cart, "Geodetic/cartesian conversions"); **************************************************************/ -static void freeup (PJ *P) { - pj_freeup_plain (P); - return; -} - /*********************************************************************/ static double normal_radius_of_curvature (double a, double es, double phi) { /*********************************************************************/ @@ -245,6 +240,11 @@ int pj_cart_selftest (void) { PJ_DERIVS derivs; PJ_FACTORS factors; + const PJ_OPERATIONS *oper_list; + const PJ_ELLPS *ellps_list; + const PJ_UNITS *unit_list; + const PJ_PRIME_MERIDIANS *pm_list; + int err; size_t n, sz; double dist, h, t; @@ -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; @@ -320,8 +320,8 @@ int pj_cart_selftest (void) { b = proj_trans_obs (P, PJ_FWD, a); /* Check roundtrip precision for 10000 iterations each way */ - dist = proj_roundtrip (P, PJ_FWD, 10000, a); - dist = proj_roundtrip (P, PJ_INV, 10000, b); + dist = proj_roundtrip (P, PJ_FWD, 10000, a.coo); + dist = proj_roundtrip (P, PJ_INV, 10000, b.coo); if (dist > 2e-9) return 7; @@ -333,7 +333,7 @@ int pj_cart_selftest (void) { a.coo.lpz.z = 100; /* Forward projection: Ellipsoidal-to-3D-Cartesian */ - dist = proj_roundtrip (P, PJ_FWD, 1, a); + dist = proj_roundtrip (P, PJ_FWD, 1, a.coo); if (dist > 1e-12) return 8; @@ -344,7 +344,7 @@ int pj_cart_selftest (void) { a.coo.lpz.z = 100; /* Forward projection: Ellipsoidal-to-3D-Cartesian */ - dist = proj_roundtrip (P, PJ_FWD, 1, a); + dist = proj_roundtrip (P, PJ_FWD, 1, a.coo); if (dist > 1e-12) return 9; @@ -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; @@ -486,20 +486,20 @@ 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 */ + 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; } @@ -518,7 +518,8 @@ int pj_cart_selftest (void) { if ( strlen(init_info.filename) != 0 ) return 67; init_info = proj_init_info("epsg"); - if ( strcmp(init_info.origin, "EPSG") ) return 69; + /* Need to allow for "Unknown" until all commonly distributed EPSG-files comes with a metadata section */ + if ( strcmp(init_info.origin, "EPSG") && strcmp(init_info.origin, "Unknown") ) return 69; if ( strcmp(init_info.name, "epsg") ) return 68; @@ -539,7 +540,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); @@ -566,6 +567,22 @@ int pj_cart_selftest (void) { proj_destroy(P); + /* Check that proj_list_* functions work by looping through them */ + n = 0; + for (oper_list = proj_list_operations(); oper_list->id; ++oper_list) n++; + if (n == 0) return 90; + + n = 0; + for (ellps_list = proj_list_ellps(); ellps_list->id; ++ellps_list) n++; + if (n == 0) return 91; + + n = 0; + for (unit_list = proj_list_units(); unit_list->id; ++unit_list) n++; + if (n == 0) return 92; + + n = 0; + for (pm_list = proj_list_prime_meridians(); pm_list->id; ++pm_list) n++; + if (n == 0) return 93; return 0; } diff --git a/src/PJ_cass.c b/src/PJ_cass.c index 85280205..6955146e 100644 --- a/src/PJ_cass.c +++ b/src/PJ_cass.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -# include <projects.h> +# include <errno.h> +# include "projects.h" PROJ_HEAD(cass, "Cassini") "\n\tCyl, Sph&Ell"; @@ -77,22 +78,18 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ return lp; } - -static void *freeup_new(PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); - pj_dealloc(P->opaque->en); - pj_dealloc(P->opaque); - return pj_dealloc(P); + pj_dealloc (P->opaque->en); + return pj_default_destructor (P, errlev); } -static void freeup(PJ *P) { /* Destructor */ - freeup_new (P); - return; -} + PJ *PROJECTION(cass) { @@ -106,11 +103,12 @@ PJ *PROJECTION(cass) { /* otherwise it's ellipsoidal */ P->opaque = pj_calloc (1, sizeof (struct pj_opaque)); if (0==P->opaque) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); + P->destructor = destructor; P->opaque->en = pj_enfn (P->es); if (0==P->opaque->en) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque->m0 = pj_mlfn (P->phi0, sin (P->phi0), cos (P->phi0), P->opaque->en); P->inv = e_inverse; diff --git a/src/PJ_cc.c b/src/PJ_cc.c index d43f5a88..9ba51386 100644 --- a/src/PJ_cc.c +++ b/src/PJ_cc.c @@ -27,16 +27,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(cc) { P->es = 0.; diff --git a/src/PJ_cea.c b/src/PJ_cea.c index 20f03547..0ec7376c 100644 --- a/src/PJ_cea.c +++ b/src/PJ_cea.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -52,46 +53,39 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ return (lp); } - -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); pj_dealloc (P->opaque->apa); - pj_dealloc (P->opaque); - return pj_dealloc (P); + return pj_default_destructor (P, errlev); } -static void freeup (PJ *P) { - freeup_new (P); - return; -} PJ *PROJECTION(cea) { double t = 0.0; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; if (pj_param(P->ctx, P->params, "tlat_ts").i) { P->k0 = cos(t = pj_param(P->ctx, P->params, "rlat_ts").f); - if (P->k0 < 0.) { - proj_errno_set(P, PJD_ERR_LAT_TS_LARGER_THAN_90); - freeup_new(P); - return 0; - } + if (P->k0 < 0.) + return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); } if (P->es != 0.0) { t = sin(t); P->k0 /= sqrt(1. - P->es * t * t); P->e = sqrt(P->es); - if (!(Q->apa = pj_authset(P->es))) { - return freeup_new(P); - } + if (!(Q->apa = pj_authset(P->es))) + return pj_default_destructor(P, ENOMEM); + Q->qp = pj_qsfn(1., P->e, P->one_es); P->inv = e_inverse; P->fwd = e_forward; diff --git a/src/PJ_chamb.c b/src/PJ_chamb.c index c6028a7a..9edb699f 100644 --- a/src/PJ_chamb.c +++ b/src/PJ_chamb.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -93,28 +94,13 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(chamb) { int i, j; char line[10]; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -131,10 +117,8 @@ PJ *PROJECTION(chamb) { j = i == 2 ? 0 : i + 1; Q->c[i].v = vect(P->ctx,Q->c[j].phi - Q->c[i].phi, Q->c[i].cosphi, Q->c[i].sinphi, Q->c[j].cosphi, Q->c[j].sinphi, Q->c[j].lam - Q->c[i].lam); - if (Q->c[i].v.r == 0.0) { - proj_errno_set(P, PJD_ERR_CONTROL_POINT_NO_DIST); - return freeup_new(P); - } + if (Q->c[i].v.r == 0.0) + return pj_default_destructor (P, PJD_ERR_CONTROL_POINT_NO_DIST); /* co-linearity problem ignored for now */ } Q->beta_0 = lc(P->ctx,Q->c[0].v.r, Q->c[2].v.r, Q->c[1].v.r); diff --git a/src/PJ_collg.c b/src/PJ_collg.c index c646d99a..01c65cd0 100644 --- a/src/PJ_collg.c +++ b/src/PJ_collg.c @@ -41,16 +41,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(collg) { P->es = 0.0; P->inv = s_inverse; diff --git a/src/PJ_comill.c b/src/PJ_comill.c index 1a4508b1..a329c0ac 100644 --- a/src/PJ_comill.c +++ b/src/PJ_comill.c @@ -70,15 +70,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ return lp; } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(comill) { P->es = 0; diff --git a/src/PJ_crast.c b/src/PJ_crast.c index 09c4f1e4..b47b0e55 100644 --- a/src/PJ_crast.c +++ b/src/PJ_crast.c @@ -29,17 +29,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(crast) { P->es = 0.0; P->inv = s_inverse; diff --git a/src/PJ_denoy.c b/src/PJ_denoy.c index 9eb818b9..3964c7da 100644 --- a/src/PJ_denoy.c +++ b/src/PJ_denoy.c @@ -22,16 +22,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(denoy) { P->es = 0.0; P->fwd = s_forward; diff --git a/src/PJ_eck1.c b/src/PJ_eck1.c index da159017..bd5c1916 100644 --- a/src/PJ_eck1.c +++ b/src/PJ_eck1.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(eck1, "Eckert I") "\n\tPCyl., Sph."; #define FC 0.92131773192356127802 @@ -28,23 +28,14 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(eck1) { P->es = 0.0; P->inv = s_inverse; P->fwd = s_forward; - return P
; + return P +; } diff --git a/src/PJ_eck2.c b/src/PJ_eck2.c index 6ef2a96c..3b2e4e49 100644 --- a/src/PJ_eck2.c +++ b/src/PJ_eck2.c @@ -43,16 +43,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc (P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(eck2) { P->es = 0.; diff --git a/src/PJ_eck3.c b/src/PJ_eck3.c index 3fe5c49f..8dc72c7c 100644 --- a/src/PJ_eck3.c +++ b/src/PJ_eck3.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(eck3, "Eckert III") "\n\tPCyl, Sph."; PROJ_HEAD(putp1, "Putnins P1") "\n\tPCyl, Sph."; @@ -36,22 +37,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - static PJ *setup(PJ *P) { P->es = 0.; P->inv = s_inverse; @@ -63,7 +48,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(eck3) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->C_x = 0.42223820031577120149; @@ -78,7 +63,7 @@ PJ *PROJECTION(eck3) { PJ *PROJECTION(kav7) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; /* Defined twice in original code - Using 0.866..., @@ -96,7 +81,7 @@ PJ *PROJECTION(kav7) { PJ *PROJECTION(wag6) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->C_x = Q->C_y = 0.94745; @@ -110,7 +95,7 @@ PJ *PROJECTION(wag6) { PJ *PROJECTION(putp1) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->C_x = 1.89490; diff --git a/src/PJ_eck4.c b/src/PJ_eck4.c index 358c0224..0ad9ec43 100644 --- a/src/PJ_eck4.c +++ b/src/PJ_eck4.c @@ -51,18 +51,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(eck4) { P->es = 0.0; P->inv = s_inverse; diff --git a/src/PJ_eck5.c b/src/PJ_eck5.c index 5fbdf7db..13617c1d 100644 --- a/src/PJ_eck5.c +++ b/src/PJ_eck5.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(eck5, "Eckert V") "\n\tPCyl, Sph."; @@ -28,18 +28,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(eck5) { P->es = 0.0; P->inv = s_inverse; diff --git a/src/PJ_eqc.c b/src/PJ_eqc.c index 576e0e3a..4f471df1 100644 --- a/src/PJ_eqc.c +++ b/src/PJ_eqc.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -32,33 +33,14 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(eqc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; - if ((Q->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) { - proj_errno_set(P, PJD_ERR_LAT_TS_LARGER_THAN_90); - return freeup_new(P); - } + if ((Q->rc = cos(pj_param(P->ctx, P->params, "rlat_ts").f)) <= 0.) + return pj_default_destructor (P, PJD_ERR_LAT_TS_LARGER_THAN_90); P->inv = s_inverse; P->fwd = s_forward; P->es = 0.; diff --git a/src/PJ_eqdc.c b/src/PJ_eqdc.c index eaf4db0b..6b3449f7 100644 --- a/src/PJ_eqdc.c +++ b/src/PJ_eqdc.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -66,23 +67,15 @@ static void special(LP lp, PJ *P, struct FACTORS *fac) { } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; - if (0==P->opaque) - return pj_dealloc (P); - - if (P->opaque->en) - pj_dealloc (P->opaque->en); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} + if (0==P->opaque) + return pj_default_destructor (P, errlev); -static void freeup (PJ *P) { - freeup_new (P); - return; + pj_dealloc (P->opaque->en); + return pj_default_destructor (P, errlev); } @@ -92,20 +85,18 @@ PJ *PROJECTION(eqdc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; Q->phi2 = pj_param(P->ctx, P->params, "rlat_2").f; - if (fabs(Q->phi1 + Q->phi2) < EPS10) { - proj_errno_set(P, PJD_ERR_CONIC_LAT_EQUAL); - freeup_new(P); - return 0; - } + if (fabs(Q->phi1 + Q->phi2) < EPS10) + pj_default_destructor (P, PJD_ERR_CONIC_LAT_EQUAL); if (!(Q->en = pj_enfn(P->es))) - return freeup_new(P); + return pj_default_destructor(P, ENOMEM); Q->n = sinphi = sin(Q->phi1); cosphi = cos(Q->phi1); diff --git a/src/PJ_fahey.c b/src/PJ_fahey.c index 4f4b92a4..42318f8f 100644 --- a/src/PJ_fahey.c +++ b/src/PJ_fahey.c @@ -29,19 +29,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(fahey) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_fouc_s.c b/src/PJ_fouc_s.c index 32eeeb4f..343e5878 100644 --- a/src/PJ_fouc_s.c +++ b/src/PJ_fouc_s.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -48,34 +49,16 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(fouc_s) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; 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(P); - } + if (Q->n < 0. || Q->n > 1.) + return pj_default_destructor (P, PJD_ERR_N_OUT_OF_RANGE); + Q->n1 = 1. - Q->n; P->es = 0; P->inv = s_inverse; diff --git a/src/PJ_gall.c b/src/PJ_gall.c index bca36bc7..01a56e33 100644 --- a/src/PJ_gall.c +++ b/src/PJ_gall.c @@ -31,20 +31,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(gall) { P->es = 0.0; diff --git a/src/PJ_geos.c b/src/PJ_geos.c index b929c06b..5fd3e56b 100644 --- a/src/PJ_geos.c +++ b/src/PJ_geos.c @@ -28,6 +28,7 @@ */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -39,7 +40,6 @@ struct pj_opaque { double radius_g; double radius_g_1; double C; - char *sweep_axis; int flip_axis; }; @@ -189,47 +189,27 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(geos) { + char *sweep_axis; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; - if ((Q->h = pj_param(P->ctx, P->params, "dh").f) <= 0.){ - proj_errno_set(P, PJD_ERR_H_LESS_THAN_ZERO); - return freeup_new(P); - } + if ((Q->h = pj_param(P->ctx, P->params, "dh").f) <= 0.) + return pj_default_destructor (P, PJD_ERR_H_LESS_THAN_ZERO); - if (P->phi0 != 0.0) { - proj_errno_set(P, PJD_ERR_UNKNOWN_PRIME_MERIDIAN); - return freeup_new(P); - } + if (P->phi0 != 0.0) + return pj_default_destructor (P, PJD_ERR_UNKNOWN_PRIME_MERIDIAN); - Q->sweep_axis = pj_param(P->ctx, P->params, "ssweep").s; - if (Q->sweep_axis == NULL) + sweep_axis = pj_param(P->ctx, P->params, "ssweep").s; + if (sweep_axis == NULL) Q->flip_axis = 0; else { - if (Q->sweep_axis[1] != '\0' || (Q->sweep_axis[0] != 'x' && Q->sweep_axis[0] != 'y')) { - proj_errno_set(P, PJD_ERR_INVALID_SWEEP_AXIS); - return freeup_new(P); - } - if (Q->sweep_axis[0] == 'x') + if (sweep_axis[1] != '\0' || (sweep_axis[0] != 'x' && sweep_axis[0] != 'y')) + return pj_default_destructor (P, PJD_ERR_INVALID_SWEEP_AXIS); + + if (sweep_axis[0] == 'x') Q->flip_axis = 1; else Q->flip_axis = 0; diff --git a/src/PJ_gins8.c b/src/PJ_gins8.c index 48bdf3a5..b27ec092 100644 --- a/src/PJ_gins8.c +++ b/src/PJ_gins8.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(gins8, "Ginsburg VIII (TsNIIGAiK)") "\n\tPCyl, Sph., no inv."; @@ -22,19 +22,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(gins8) { P->es = 0.0; P->inv = 0; diff --git a/src/PJ_gn_sinu.c b/src/PJ_gn_sinu.c index 57bbecc8..d13f2834 100644 --- a/src/PJ_gn_sinu.c +++ b/src/PJ_gn_sinu.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -86,40 +87,18 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_msg (PJ *P, int errlev) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; - if (0!=P->ctx) - pj_ctx_set_errno (P->ctx, errlev); - - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; if (0==P->opaque) - return pj_dealloc (P); - - if (P->opaque->en) - pj_dalloc(P->opaque->en); + return pj_default_destructor (P, errlev); - pj_dealloc (P->opaque); - return pj_dealloc(P); + pj_dealloc (P->opaque->en); + return pj_default_destructor (P, errlev); } -static void freeup (PJ *P) { - freeup_new (P); - return; -} - /* for spheres, only */ static void setup(PJ *P) { @@ -135,12 +114,13 @@ static void setup(PJ *P) { PJ *PROJECTION(sinu) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; if (!(Q->en = pj_enfn(P->es))) - return freeup_new(P); - + return pj_default_destructor (P, ENOMEM); + if (P->es != 0.0) { P->inv = e_inverse; P->fwd = e_forward; @@ -156,8 +136,9 @@ PJ *PROJECTION(sinu) { PJ *PROJECTION(eck6) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; Q->m = 1.; Q->n = 2.570796326794896619231321691; @@ -170,8 +151,9 @@ PJ *PROJECTION(eck6) { PJ *PROJECTION(mbtfps) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; Q->m = 0.5; Q->n = 1.785398163397448309615660845; @@ -184,16 +166,17 @@ PJ *PROJECTION(mbtfps) { PJ *PROJECTION(gn_sinu) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; if (pj_param(P->ctx, P->params, "tn").i && pj_param(P->ctx, P->params, "tm").i) { Q->n = pj_param(P->ctx, P->params, "dn").f; Q->m = pj_param(P->ctx, P->params, "dm").f; - if (Q->n < 0 || Q->m < 0) - return freeup_msg(P, PJD_ERR_INVALID_M_OR_N); + if (Q->n <= 0 || Q->m < 0) + return destructor (P, PJD_ERR_INVALID_M_OR_N); } else - return freeup_msg(P, PJD_ERR_INVALID_M_OR_N); + return destructor (P, PJD_ERR_INVALID_M_OR_N); setup(P); diff --git a/src/PJ_gnom.c b/src/PJ_gnom.c index 099f32fb..1d3f3386 100644 --- a/src/PJ_gnom.c +++ b/src/PJ_gnom.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -111,27 +112,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(gnom) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) { diff --git a/src/PJ_goode.c b/src/PJ_goode.c index fff12a78..3bfeb21f 100644 --- a/src/PJ_goode.c +++ b/src/PJ_goode.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -43,42 +44,34 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; if (0==P->opaque) - return pj_dealloc(P); - if (P->opaque->sinu) - pj_dealloc(P->opaque->sinu); - if (P->opaque->moll) - pj_dealloc(P->opaque->moll); - pj_dealloc (P->opaque); - return pj_dealloc(P); - + return pj_default_destructor (P, errlev); + pj_free (P->opaque->sinu); + pj_free (P->opaque->moll); + return pj_default_destructor (P, errlev); } -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(goode) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; P->es = 0.; if (!(Q->sinu = pj_sinu(0)) || !(Q->moll = pj_moll(0))) - return freeup_new(P); + return destructor (P, ENOMEM); Q->sinu->es = 0.; - Q->sinu->ctx = P->ctx; - Q->moll->ctx = P->ctx; + Q->sinu->ctx = P->ctx; + Q->moll->ctx = P->ctx; if (!(Q->sinu = pj_sinu(Q->sinu)) || !(Q->moll = pj_moll(Q->moll))) - return freeup_new(P); - + return destructor (P, ENOMEM); + P->fwd = s_forward; P->inv = s_inverse; @@ -104,7 +97,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 +111,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); } diff --git a/src/PJ_gstmerc.c b/src/PJ_gstmerc.c index a550ab2c..c2846761 100644 --- a/src/PJ_gstmerc.c +++ b/src/PJ_gstmerc.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(gstmerc, "Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion)") "\n\tCyl, Sph&Ell\n\tlat_0= lon_0= k_0="; @@ -46,27 +47,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(gstmerc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->lamc = P->lam0; diff --git a/src/PJ_hammer.c b/src/PJ_hammer.c index 58182398..c18c9a69 100644 --- a/src/PJ_hammer.c +++ b/src/PJ_hammer.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -8,7 +9,7 @@ PROJ_HEAD(hammer, "Hammer & Eckert-Greifendorff") #define EPS 1.0e-10 struct pj_opaque { - double w; \ + double w; double m, rm; }; @@ -43,40 +44,20 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(hammer) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; if (pj_param(P->ctx, P->params, "tW").i) { - if ((Q->w = fabs(pj_param(P->ctx, P->params, "dW").f)) <= 0.) { - proj_errno_set(P, PJD_ERR_W_OR_M_ZERO_OR_LESS); - return freeup_new(P); - } + if ((Q->w = fabs(pj_param(P->ctx, P->params, "dW").f)) <= 0.) + return pj_default_destructor (P, PJD_ERR_W_OR_M_ZERO_OR_LESS); } else Q->w = .5; if (pj_param(P->ctx, P->params, "tM").i) { - if ((Q->m = fabs(pj_param(P->ctx, P->params, "dM").f)) <= 0.) { - proj_errno_set(P, PJD_ERR_W_OR_M_ZERO_OR_LESS); - return freeup_new(P); - } + if ((Q->m = fabs(pj_param(P->ctx, P->params, "dM").f)) <= 0.) + return pj_default_destructor (P, PJD_ERR_W_OR_M_ZERO_OR_LESS); } else Q->m = 1.; diff --git a/src/PJ_hatano.c b/src/PJ_hatano.c index d75a96a3..be95fe73 100644 --- a/src/PJ_hatano.c +++ b/src/PJ_hatano.c @@ -71,19 +71,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(hatano) { P->es = 0.; P->inv = s_inverse; @@ -110,10 +97,14 @@ int pj_hatano_selftest (void) { }; XY s_fwd_expect[] = { - { 189878.87894652804, 131409.8024406255
}, - { 189881.08195244463, -131409.14227607418
}, - {-189878.87894652804, 131409.8024406255
}, - {-189881.08195244463, -131409.14227607418
}, + { 189878.87894652804, 131409.8024406255 +}, + { 189881.08195244463, -131409.14227607418 +}, + {-189878.87894652804, 131409.8024406255 +}, + {-189881.08195244463, -131409.14227607418 +}, }; XY inv_in[] = { @@ -124,10 +115,14 @@ int pj_hatano_selftest (void) { }; LP s_inv_expect[] = { - { 0.0021064624821817597, 0.00076095689425791926
}, - { 0.0021064624821676096, -0.00076095777439265377
}, - {-0.0021064624821817597, 0.00076095689425791926
}, - {-0.0021064624821676096, -0.00076095777439265377
}, + { 0.0021064624821817597, 0.00076095689425791926 +}, + { 0.0021064624821676096, -0.00076095777439265377 +}, + {-0.0021064624821817597, 0.00076095689425791926 +}, + {-0.0021064624821676096, -0.00076095777439265377 +}, }; 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); diff --git a/src/PJ_healpix.c b/src/PJ_healpix.c index ef53e58f..241d7ef4 100644 --- a/src/PJ_healpix.c +++ b/src/PJ_healpix.c @@ -29,6 +29,7 @@ * SOFTWARE. *****************************************************************************/ # define PJ_LIB__ +# include <errno.h> # include <proj.h> # include "projects.h" @@ -598,30 +599,24 @@ static LP e_rhealpix_inverse(XY xy, PJ *P) { /* ellipsoid */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; - if (0==P->opaque) - return pj_dealloc (P); - - if (P->opaque->apa) - pj_dealloc(P->opaque->apa); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} + if (0==P->opaque) + return pj_default_destructor (P, errlev); -static void freeup (PJ *P) { - freeup_new (P); - return; + pj_dealloc (P->opaque->apa); + return pj_default_destructor (P, errlev); } PJ *PROJECTION(healpix) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; if (P->es != 0.0) { Q->apa = pj_authset(P->es); /* For auth_lat(). */ @@ -642,21 +637,18 @@ PJ *PROJECTION(healpix) { PJ *PROJECTION(rhealpix) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; Q->north_square = pj_param(P->ctx, P->params,"inorth_square").i; Q->south_square = pj_param(P->ctx, P->params,"isouth_square").i; /* Check for valid north_square and south_square inputs. */ - if (Q->north_square < 0 || Q->north_square > 3) { - proj_errno_set(P, PJD_ERR_AXIS); - return freeup_new(P); - } - if (Q->south_square < 0 || Q->south_square > 3) { - proj_errno_set(P, PJD_ERR_AXIS); - return freeup_new(P); - } + if (Q->north_square < 0 || Q->north_square > 3) + return destructor (P, PJD_ERR_AXIS); + if (Q->south_square < 0 || Q->south_square > 3) + return destructor (P, PJD_ERR_AXIS); if (P->es != 0.0) { Q->apa = pj_authset(P->es); /* For auth_lat(). */ Q->qp = pj_qsfn(1.0, P->e, P->one_es); /* For auth_lat(). */ diff --git a/src/PJ_helmert.c b/src/PJ_helmert.c index e291c189..ffbdd01a 100644 --- a/src/PJ_helmert.c +++ b/src/PJ_helmert.c @@ -43,12 +43,12 @@ Last update: 2017-05-15 ***********************************************************************/ #define PJ_LIB__ -#include "proj_internal.h" -#include <projects.h> -#include <geocent.h> #include <assert.h> #include <stddef.h> #include <errno.h> +#include "proj_internal.h" +#include "projects.h" +#include "geocent.h" PROJ_HEAD(helmert, "3(6)-, 4(8)- and 7(14)-parameter Helmert shift"); static XYZ helmert_forward_3d (LPZ lpz, PJ *P); @@ -56,28 +56,6 @@ static LPZ helmert_reverse_3d (XYZ xyz, PJ *P); -static void *freeup_msg (PJ *P, int errlev) { /* Destructor */ - if (0==P) - return 0; - - if (0!=P->ctx) - pj_ctx_set_errno (P->ctx, errlev); - - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -/* Adapts pipeline_freeup to the format defined for the PJ object */ -static void freeup (PJ *P) { - freeup_msg (P, 0); - return; -} - - /***********************************************************************/ struct pj_opaque_helmert { /************************************************************************ @@ -484,7 +462,7 @@ PJ *PROJECTION(helmert) { /***********************************************************************/ struct pj_opaque_helmert *Q = pj_calloc (1, sizeof (struct pj_opaque_helmert)); if (0==Q) - return freeup_msg (P, ENOMEM); + return pj_default_destructor (P, ENOMEM); P->opaque = (void *) Q; P->fwdobs = helmert_forward_obs; @@ -527,7 +505,7 @@ PJ *PROJECTION(helmert) { if (pj_param (P->ctx, P->params, "ts").i) { Q->scale_0 = pj_param (P->ctx, P->params, "ds").f; if (pj_param (P->ctx, P->params, "ttheta").i && Q->scale_0 == 0.0) - return freeup_msg(P, -PJD_ERR_INVALID_SCALE); + return pj_default_destructor (P, PJD_ERR_INVALID_SCALE); } /* Translation rates */ diff --git a/src/PJ_hgridshift.c b/src/PJ_hgridshift.c index 41c2b629..0adc9e00 100644 --- a/src/PJ_hgridshift.c +++ b/src/PJ_hgridshift.c @@ -1,25 +1,9 @@ #define PJ_LIB__ #include "proj_internal.h" -#include <projects.h> +#include "projects.h" PROJ_HEAD(hgridshift, "Horizontal grid shift"); -static void *freeup_msg (PJ *P, int errlev) { - if (0==P) - return 0; - - if (0!=P->ctx) - pj_ctx_set_errno (P->ctx, errlev); - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_msg (P, 0); - return; -} - static XYZ forward_3d(LPZ lpz, PJ *P) { PJ_TRIPLET point; @@ -67,23 +51,30 @@ static PJ_OBS reverse_obs(PJ_OBS obs, PJ *P) { } -PJ *PROJECTION(hgridshift) { - if (!pj_param(P->ctx, P->params, "tgrids").i) { - proj_log_error(P, "hgridshift: +grids parameter missing."); - return freeup_msg(P, -1); - } +#if 0 +static XY forward_xy(LP lp, PJ *P) { + PJ_TRIPLET point; + point.lp = lp; + point.lpz.z = 0; + point.xyz = forward_3d (point.lpz, P); + return point.xy; +} - /* Build gridlist. P->gridlist can be empty if +grids only ask for optional grids. */ - P->gridlist = pj_gridlist_from_nadgrids( P->ctx, pj_param(P->ctx, P->params, "sgrids").s, - &(P->gridlist_count) ); - /* Was gridlist compiled properly? */ - if ( pj_ctx_get_errno(P->ctx) ) { - proj_log_error(P, "hgridshift: could not find required grid(s)."); - return freeup_msg(P, -38); - } +static LP reverse_lp(XY xy, PJ *P) { + PJ_TRIPLET point; + point.xy = xy; + point.xyz.z = 0; + point.lpz = reverse_3d (point.xyz, P); + return point.lp; +} +#endif + + +PJ *PROJECTION(hgridshift) { + P->fwdobs = forward_obs; P->invobs = reverse_obs; P->fwd3d = forward_3d; @@ -94,6 +85,21 @@ PJ *PROJECTION(hgridshift) { P->left = PJ_IO_UNITS_RADIANS; P->right = PJ_IO_UNITS_RADIANS; + if (0==pj_param(P->ctx, P->params, "tgrids").i) { + proj_log_error(P, "hgridshift: +grids parameter missing."); + return pj_default_destructor (P, PJD_ERR_NO_ARGS); + } + + /* Build gridlist. P->gridlist can be empty if +grids only ask for optional grids. */ + P->gridlist = pj_gridlist_from_nadgrids( P->ctx, pj_param(P->ctx, P->params, "sgrids").s, + &(P->gridlist_count) ); + + /* Was gridlist compiled properly? */ + if ( pj_ctx_get_errno(pj_get_ctx(P)) ) { + proj_log_error(P, "hgridshift: could not find required grid(s)."); + return pj_default_destructor (P, PJD_ERR_FAILED_TO_LOAD_GRID); + } + return P; } @@ -108,26 +114,29 @@ int pj_hgridshift_selftest (void) { double dist; /* fail on purpose: +grids parameter is mandatory*/ - P = proj_create(0, "+proj=hgridshift"); - if (0!=P) + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift"); + if (0!=P) { + proj_destroy (P); return 99; - + } + /* fail on purpose: open non-existing grid */ - P = proj_create(0, "+proj=hgridshift +grids=nonexistinggrid.gsb"); - if (0!=P) + P = proj_create(PJ_DEFAULT_CTX, "+proj=hgridshift +grids=@nonexistinggrid.gsb,anothernonexistinggrid.gsb"); + if (0!=P) { + proj_destroy (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; - + a = proj_obs_null; a.coo.lpz.lam = PJ_TORAD(173); a.coo.lpz.phi = PJ_TORAD(-45); - - dist = proj_roundtrip (P, PJ_FWD, 1, a); + + dist = proj_roundtrip (P, PJ_FWD, 1, a.coo); if (dist > 0.00000001) return 1; diff --git a/src/PJ_horner.c b/src/PJ_horner.c index 56980f72..d6d2c51c 100644 --- a/src/PJ_horner.c +++ b/src/PJ_horner.c @@ -1,6 +1,6 @@ #define PJ_LIB__ #include "proj_internal.h" -#include <projects.h> +#include "projects.h" #include <assert.h> #include <stddef.h> #include <math.h> @@ -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); @@ -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); } @@ -176,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 @@ -301,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 @@ -380,18 +382,14 @@ static PJ_OBS complex_horner_reverse_obs (PJ_OBS point, PJ *P) { } -static void *horner_freeup (PJ *P) { /* Destructor */ +static void *horner_freeup (PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); horner_free ((HORNER *) P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - horner_freeup (P); - return; + P->opaque = 0; + return pj_default_destructor (P, errlev); } @@ -406,8 +404,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); @@ -438,13 +438,14 @@ PJ *PROJECTION(horner) { P->fwd = 0; P->inv = 0; P->left = P->right = PJ_IO_UNITS_METERS; + P->destructor = horner_freeup; /* Polynomial degree specified? */ if (pj_param (P->ctx, P->params, "tdeg").i) /* degree specified? */ degree = pj_param(P->ctx, P->params, "ideg").i; else { proj_log_debug (P, "Horner: Must specify polynomial degree, (+deg=n)"); - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); } if (pj_param (P->ctx, P->params, "tfwd_c").i || pj_param (P->ctx, P->params, "tinv_c").i) /* complex polynomium? */ @@ -452,17 +453,15 @@ PJ *PROJECTION(horner) { Q = horner_alloc (degree, complex_horner); if (Q == 0) - { - return horner_freeup (P); - } + return horner_freeup (P, ENOMEM); P->opaque = (void *) Q; if (complex_horner) { n = 2*degree + 2; if (0==parse_coefs (P, Q->fwd_c, "fwd_c", n)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); if (0==parse_coefs (P, Q->inv_c, "inv_c", n)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); P->fwdobs = complex_horner_forward_obs; P->invobs = complex_horner_reverse_obs; @@ -470,19 +469,19 @@ PJ *PROJECTION(horner) { else { n = horner_number_of_coefficients (degree); if (0==parse_coefs (P, Q->fwd_u, "fwd_u", n)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); if (0==parse_coefs (P, Q->fwd_v, "fwd_v", n)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); if (0==parse_coefs (P, Q->inv_u, "inv_u", n)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); if (0==parse_coefs (P, Q->inv_v, "inv_v", n)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); } if (0==parse_coefs (P, (double *)(Q->fwd_origin), "fwd_origin", 2)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); if (0==parse_coefs (P, (double *)(Q->inv_origin), "inv_origin", 2)) - return horner_freeup (P); + return horner_freeup (P, PJD_ERR_MISSING_ARGS); if (0==parse_coefs (P, &Q->range, "range", 1)) Q->range = 500000; @@ -525,7 +524,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; @@ -534,12 +533,12 @@ int pj_horner_selftest (void) { a.coo.uv.u = 878354.8539; /* Check roundtrip precision for 1 iteration each way, starting in forward direction */ - dist = proj_roundtrip (P, PJ_FWD, 1, a); + dist = proj_roundtrip (P, PJ_FWD, 1, a.coo); if (dist > 0.01) 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; @@ -563,7 +562,7 @@ int pj_horner_selftest (void) { return 3; /* Check roundtrip precision for 1 iteration each way */ - dist = proj_roundtrip (P, PJ_FWD, 1, a); + dist = proj_roundtrip (P, PJ_FWD, 1, a.coo); if (dist > 0.01) return 4; diff --git a/src/PJ_igh.c b/src/PJ_igh.c index 9b5f7075..33cdde22 100644 --- a/src/PJ_igh.c +++ b/src/PJ_igh.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include "projects.h" PROJ_HEAD(igh, "Interrupted Goode Homolosine") "\n\tPCyl, Sph."; @@ -130,26 +131,20 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { int i; if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); for (i = 0; i < 12; ++i) { if (P->opaque->pj[i]) - P->opaque->pj[i]->pfree(P->opaque->pj[i]); + P->opaque->pj[i]->destructor(P->opaque->pj[i], errlev); } - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor(P, errlev); } @@ -175,8 +170,8 @@ static void freeup (PJ *P) { */ #define SETUP(n, proj, x_0, y_0, lon_0) \ - if (!(Q->pj[n-1] = pj_##proj(0))) return freeup_new(P); \ - if (!(Q->pj[n-1] = pj_##proj(Q->pj[n-1]))) return freeup_new(P); \ + if (!(Q->pj[n-1] = pj_##proj(0))) return destructor(P, ENOMEM); \ + if (!(Q->pj[n-1] = pj_##proj(Q->pj[n-1]))) return destructor(P, ENOMEM); \ Q->pj[n-1]->ctx = P->ctx; \ Q->pj[n-1]->x0 = x_0; \ Q->pj[n-1]->y0 = y_0; \ @@ -188,7 +183,7 @@ PJ *PROJECTION(igh) { LP lp = { 0, d4044118 }; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -220,6 +215,7 @@ PJ *PROJECTION(igh) { P->inv = s_inverse; P->fwd = s_forward; + P->destructor = destructor; P->es = 0.; return P; diff --git a/src/PJ_imw_p.c b/src/PJ_imw_p.c index 0b2a6602..29ed3457 100644 --- a/src/PJ_imw_p.c +++ b/src/PJ_imw_p.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -130,36 +131,31 @@ static void xy(PJ *P, double phi, double *x, double *y, double *sp, double *R) { } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); if( P->opaque->en ) pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor(P, errlev); } PJ *PROJECTION(imw_p) { double del, sig, s, t, x1, x2, T2, y1, m1, m2, y2; - int i; + int err; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; - if (!(Q->en = pj_enfn(P->es))) return freeup_new(P); - if( (i = phi12(P, &del, &sig)) != 0) { - proj_errno_set(P, i); - return freeup_new(P); + if (!(Q->en = pj_enfn(P->es))) return pj_default_destructor (P, ENOMEM); + if( (err = phi12(P, &del, &sig)) != 0) { + return destructor(P, err); } if (Q->phi_2 < Q->phi_1) { /* make sure P->phi_1 most southerly */ del = Q->phi_1; @@ -204,6 +200,7 @@ PJ *PROJECTION(imw_p) { P->fwd = e_forward; P->inv = e_inverse; + P->destructor = destructor; return P; } diff --git a/src/PJ_isea.c b/src/PJ_isea.c index deaecb0f..223d8f28 100644 --- a/src/PJ_isea.c +++ b/src/PJ_isea.c @@ -1034,6 +1034,7 @@ isea_forward(struct isea_dgg *g, struct isea_geo *in) */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -1062,27 +1063,11 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(isea) { char *opt; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -1100,8 +1085,7 @@ PJ *PROJECTION(isea) { } else if (!strcmp(opt, "pole")) { isea_orient_pole(&Q->dgg); } else { - proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); } } @@ -1140,8 +1124,7 @@ PJ *PROJECTION(isea) { } else { /* TODO verify error code. Possibly eliminate magic */ - proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); } } diff --git a/src/PJ_krovak.c b/src/PJ_krovak.c index bee66b07..640ce07f 100644 --- a/src/PJ_krovak.c +++ b/src/PJ_krovak.c @@ -77,7 +77,8 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(krovak, "Krovak") "\n\tPCyl., Ellps."; @@ -173,27 +174,11 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc(P); - - pj_dealloc(P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(krovak) { double u0, n0, g; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; /* we want Bessel as fixed ellipsoid */ diff --git a/src/PJ_labrd.c b/src/PJ_labrd.c index dfc54478..4b5d93a5 100644 --- a/src/PJ_labrd.c +++ b/src/PJ_labrd.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(labrd, "Laborde") "\n\tCyl, Sph\n\tSpecial for Madagascar"; #define EPS 1.e-10 @@ -95,28 +96,11 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(labrd) { double Az, sinp, R, N, t; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->rot = pj_param(P->ctx, P->params, "bno_rot").i == 0; diff --git a/src/PJ_laea.c b/src/PJ_laea.c index 0a638fb0..ddca63d9 100644 --- a/src/PJ_laea.c +++ b/src/PJ_laea.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -219,20 +220,16 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); pj_dealloc (P->opaque->apa); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor(P, errlev); } @@ -240,8 +237,9 @@ PJ *PROJECTION(laea) { double t; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; + P->destructor = destructor; t = fabs(P->phi0); if (fabs(t - M_HALFPI) < EPS10) diff --git a/src/PJ_lagrng.c b/src/PJ_lagrng.c index 98500900..e30f6a36 100644 --- a/src/PJ_lagrng.c +++ b/src/PJ_lagrng.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -35,42 +36,22 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(lagrng) { double phi1; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->rw = pj_param(P->ctx, P->params, "dW").f; - if (Q->rw <= 0) { - proj_errno_set(P, PJD_ERR_W_OR_M_ZERO_OR_LESS); - return freeup_new(P); - } + if (Q->rw <= 0) + return pj_default_destructor(P, PJD_ERR_W_OR_M_ZERO_OR_LESS); Q->rw = 1. / Q->rw; Q->hrw = 0.5 * Q->rw; phi1 = sin(pj_param(P->ctx, P->params, "rlat_1").f); - if (fabs(fabs(phi1) - 1.) < TOL) { - proj_errno_set(P, PJD_ERR_LAT_LARGER_THAN_90); - return freeup_new(P); - } + if (fabs(fabs(phi1) - 1.) < TOL) + return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); Q->a1 = pow((1. - phi1)/(1. + phi1), Q->hrw); diff --git a/src/PJ_larr.c b/src/PJ_larr.c index dba2534c..cd6e6c8a 100644 --- a/src/PJ_larr.c +++ b/src/PJ_larr.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(larr, "Larrivee") "\n\tMisc Sph, no inv."; @@ -16,20 +16,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(larr) { P->es = 0; diff --git a/src/PJ_lask.c b/src/PJ_lask.c index 9aa96206..d0efeb7d 100644 --- a/src/PJ_lask.c +++ b/src/PJ_lask.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(lask, "Laskowski") "\n\tMisc Sph, no inv."; @@ -28,19 +28,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ return xy; } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(lask) { diff --git a/src/pj_latlong.c b/src/PJ_latlong.c index 761eadc5..dec69b70 100644 --- a/src/pj_latlong.c +++ b/src/PJ_latlong.c @@ -53,19 +53,6 @@ static LP inverse(XY xy, PJ *P) { } -static void *freeup_new (PJ *P) { - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(latlong) { P->is_latlong = 1; P->x0 = 0.0; diff --git a/src/PJ_lcc.c b/src/PJ_lcc.c index 905f7086..78c227b8 100644 --- a/src/PJ_lcc.c +++ b/src/PJ_lcc.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -88,29 +89,13 @@ static void special(LP lp, PJ *P, struct FACTORS *fac) { } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(lcc) { double cosphi, sinphi; int secant; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -122,10 +107,9 @@ PJ *PROJECTION(lcc) { if (!pj_param(P->ctx, P->params, "tlat_0").i) P->phi0 = Q->phi1; } - if (fabs(Q->phi1 + Q->phi2) < EPS10) { - proj_errno_set(P, PJD_ERR_CONIC_LAT_EQUAL); - return freeup_new(P); - } + if (fabs(Q->phi1 + Q->phi2) < EPS10) + return pj_default_destructor(P, PJD_ERR_CONIC_LAT_EQUAL); + Q->n = sinphi = sin(Q->phi1); cosphi = cos(Q->phi1); secant = fabs(Q->phi1 - Q->phi2) >= EPS10; diff --git a/src/PJ_lcca.c b/src/PJ_lcca.c index 77704375..7d1355b9 100644 --- a/src/PJ_lcca.c +++ b/src/PJ_lcca.c @@ -1,6 +1,7 @@ /* PROJ.4 Cartographic Projection System */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -69,20 +70,15 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor (P, errlev); } @@ -90,16 +86,15 @@ PJ *PROJECTION(lcca) { double s2p0, N0, R0, tan0; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; (Q->en = pj_enfn(P->es)); if (!Q->en) - return freeup_new(P); + return pj_default_destructor (P, ENOMEM); if (P->phi0 == 0.) { - proj_errno_set(P, PJD_ERR_LAT_0_IS_ZERO); - return freeup_new(P); + return destructor(P, PJD_ERR_LAT_0_IS_ZERO); } Q->l = sin(P->phi0); Q->M0 = pj_mlfn(P->phi0, Q->l, cos(P->phi0), Q->en); @@ -113,6 +108,7 @@ PJ *PROJECTION(lcca) { P->inv = e_inverse; P->fwd = e_forward; + P->destructor = destructor; return P; } diff --git a/src/PJ_loxim.c b/src/PJ_loxim.c index 6cd56eef..a4ae074b 100644 --- a/src/PJ_loxim.c +++ b/src/PJ_loxim.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -49,34 +50,17 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(loxim) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->phi1 = pj_param(P->ctx, P->params, "rlat_1").f; Q->cosphi1 = cos(Q->phi1); - if (Q->cosphi1 < EPS) { - proj_errno_set(P, PJD_ERR_LAT_LARGER_THAN_90); - return freeup_new(P); - } + if (Q->cosphi1 < EPS) + return pj_default_destructor(P, PJD_ERR_LAT_LARGER_THAN_90); + Q->tanphi1 = tan(M_FORTPI + 0.5 * Q->phi1); diff --git a/src/PJ_lsat.c b/src/PJ_lsat.c index 15009d61..1b3778d6 100644 --- a/src/PJ_lsat.c +++ b/src/PJ_lsat.c @@ -1,5 +1,6 @@ /* based upon Snyder and Linck, USGS-NMD */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -148,40 +149,22 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(lsat) { int land, path; double lam, alf, esc, ess; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; land = pj_param(P->ctx, P->params, "ilsat").i; - if (land <= 0 || land > 5) { - proj_errno_set(P, PJD_ERR_LSAT_NOT_IN_RANGE); - return freeup_new(P); - } + if (land <= 0 || land > 5) + return pj_default_destructor(P, PJD_ERR_LSAT_NOT_IN_RANGE); + path = pj_param(P->ctx, P->params, "ipath").i; - if (path <= 0 || path > (land <= 3 ? 251 : 233)) { - proj_errno_set(P, PJD_ERR_PATH_NOT_IN_RANGE); - return freeup_new(P); - } + if (path <= 0 || path > (land <= 3 ? 251 : 233)) + pj_default_destructor(P, PJD_ERR_PATH_NOT_IN_RANGE); + if (land <= 3) { P->lam0 = DEG_TO_RAD * 128.87 - M_TWOPI / 251. * path; Q->p22 = 103.2669323; diff --git a/src/PJ_mbt_fps.c b/src/PJ_mbt_fps.c index 5a3f3774..c35da04c 100644 --- a/src/PJ_mbt_fps.c +++ b/src/PJ_mbt_fps.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(mbt_fps, "McBryde-Thomas Flat-Pole Sine (No. 2)") "\n\tCyl., Sph."; @@ -44,20 +44,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(mbt_fps) { P->es = 0; diff --git a/src/PJ_mbtfpp.c b/src/PJ_mbtfpp.c index f8a5e807..2bbb16b1 100644 --- a/src/PJ_mbtfpp.c +++ b/src/PJ_mbtfpp.c @@ -52,19 +52,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(mbtfpp) { P->es = 0.; diff --git a/src/PJ_mbtfpq.c b/src/PJ_mbtfpq.c index b6910a45..4901401e 100644 --- a/src/PJ_mbtfpq.c +++ b/src/PJ_mbtfpq.c @@ -61,19 +61,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(mbtfpq) { P->es = 0.; diff --git a/src/PJ_merc.c b/src/PJ_merc.c index 04e5dc21..d17a2d50 100644 --- a/src/PJ_merc.c +++ b/src/PJ_merc.c @@ -49,22 +49,14 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void freeup(PJ *P) { /* Destructor */ - pj_dealloc(P); -} - - PJ *PROJECTION(merc) { double phits=0.0; int is_phits; if( (is_phits = pj_param(P->ctx, P->params, "tlat_ts").i) ) { phits = fabs(pj_param(P->ctx, P->params, "rlat_ts").f); - if (phits >= M_HALFPI) { - proj_errno_set(P, PJD_ERR_LAT_TS_LARGER_THAN_90); - freeup(P); - return 0; - } + if (phits >= M_HALFPI) + return pj_default_destructor(P, PJD_ERR_LAT_TS_LARGER_THAN_90); } if (P->es != 0.0) { /* ellipsoid */ diff --git a/src/PJ_mill.c b/src/PJ_mill.c index 17763410..829bc3be 100644 --- a/src/PJ_mill.c +++ b/src/PJ_mill.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(mill, "Miller Cylindrical") "\n\tCyl, Sph"; @@ -25,19 +25,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(mill) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_minimal.c b/src/PJ_minimal.c deleted file mode 100644 index 1108c4fa..00000000 --- a/src/PJ_minimal.c +++ /dev/null @@ -1,204 +0,0 @@ -/*********************************************************************** - - A minimal example of a new proj.4 projection implementation - - ...and a verbose justification for some highly intrusive code - surgery - -************************************************************************ - -**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:** - -Gerald I. Evenden's original design for the proj.4 projection system -is a beautiful example of software architecture, where a very limited -set of policy rules leads to a well defined hierarchical structure and -a high degree of both encapsulation and internal interoperability. - -In the proj.4 code, the policy rules are *enforced* by a system of -preprocessor macros for building the scaffolding for implementation -of a new projection. - -While this system of macros undeniably possesses the property of both -reducing repetitive code and enforcing policy, unfortunately it also -possesses two much less desirable properties: - -First, while enforcing policy, it also *hides* policy: The "beauty in -simplicity" of Gerald's design is hidden behind layers of macros, -whose architectural clarity do not match that of proj.4 in general. - -Second (and related), the macros make the source code look like -something only vaguely related to C, making it hard to read (an effect -that gets amplified to the tune of syntax highlighters getting confused -by the macros). - -While the policy rule enforcement macros can be eliminated in relatively -non-intrusive ways, a more fundamental flaw in the proj.4 use of macros -is found in the PJ_xxx.c files implementing the individual projections: -The use of internal redefinition of PJ, the fundamental proj data object, -through the use of the PROJ_PARMS__ macro, makes the sizeof (PJ) -fundamentally unknown to the calling pj_init function. - -This leads to code that is probably not in full conformance with the -C standard. - -It is also a memory management catastrophe waiting to happen. - -But first and foremost, it leads to some very clumsy initialization code, -where pj_init (the constructor function), needs to start the constsruction -process by asking the PJ_xxx function to do the memory allocation (because -pj_init does not know the size of the PROJ_PARMS-mangled PJ object being -instantiated). - -Then, after doing some initialization work, pj_init returns control to -PJ_xxx, asking it to finalize the initialization with the projection -specific parameters specified by the PROJ_PARMS__ macro. - -Behind the scenes, hidden by two layers of macros, what happens is even -worse, as a lot of the initialization code is duplicated in every PJ_xxx -file, rather than being centralized in the pj_init function. - -**Solution procedure:** - -Evidently, the way to eliminate this clumsyness will be to introduce an -opaque object, that is managed by tne individual PJ_xxx projection code, -and represented as a simple void-pointer in the PJ object. - -This can be done one projection code file at a time, working through the -code base as time permits (it will take at least a month). - -When a PJ_xxx file is on the surgical bench, it will also have its -ENTRYA/ENTRY0/ENTRY1/ENTRY2/ENDENTRY/etc. etc. macro-guts torn out and -replaced by the PROJECTION macro (introduced in projects.h). - -This leads to code that looks a lot more like real C, and hence is much -less confusing to both syntax higlighters and humans. It also leads -to code that, after all projections have been processed, with a final -sweep over the code base can be brought into the style of the code in -PJ_minimal.c - -In my humble opinion the result wil be a code base that is not only easier -to maintain, but also more welcoming to new contributors. - -And if proj is to expand its strong basis in projections into the fields -of geodetic transformations and general geometric geodesy, we will need -to be able to attract quite a few expert geodesist contributors. - -And since expert geodesists are not necessarily expert coders, a welcoming -code base is a real asset (to put the icing on the cake of the already -welcoming user- and developer community). - -Note that the entire process does not touch the algorithmic/mathematical -parts of the code at all - it is actuallly an attempt to make this part -stand out more clearly. - ---- - -The attached material is an attempt to show what happens if we remove -the layers of macros, and introduce a more centralized approach to -memory allocation and initialization. - -Please note, however, that the level of cantralization achieved here -is not yet fully supported by the proj.4 infrastructure: It is an -example, intended to show what can be achieved through a smooth, -gradual and safe refactoring of the existing layered macro system. - -In my humble opinion, this version makes the beauty of Gerald's design -much more evident than the current layered-macro-version. - -Thomas Knudsen, thokn@sdfe.dk, 2016-03-31 - -***********************************************************************/ - -#define PJ_LIB__ -#include <projects.h> -#include <assert.h> -PROJ_HEAD(minimal, "Minimal example (brief description goes here)"); - - -/* Projection specific elements for the PJ object */ -struct pj_opaque { - double a; - int b; -}; - - -static XY e_forward (LP lp, PJ *P) { /* Ellipsoidal, forward */ - XY xy = {0.0,0.0}; - /* Actual ellipsoidal forward code goes here */ - xy.y = lp.lam + P->es; - xy.x = lp.phi + 42; - return xy; -} - - -static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ - XY xy = {0.0,0.0}; - /* Actual spheroidal forward code goes here */ - xy.y = lp.lam + P->es; - xy.x = lp.phi + 42; - return xy; -} - - -static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ - LP lp = {0.0,0.0}; - /* Actual ellipsoidal forward code goes here */ - lp.lam = xy.x - P->es; - lp.phi = xy.y - P->opaque->b; - return lp; -} - - -static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ - LP lp = {0.0,0.0}; - /* Actual spheroidal forward code goes here */ - lp.lam = xy.x - P->es; - lp.phi = xy.y - P->opaque->b; - return lp; -} - - -static void freeup(PJ *P) { /* Destructor */ - if (P==0) - return; - /* Projection specific deallocation goes here */ - pj_dealloc (P->opaque); - pj_dealloc (P); - return; -} - - -PJ *pj_projection_specific_setup_minimal (PJ *P) { - pj_prepare (P, des_minimal, freeup, sizeof (struct pj_opaque)); - if (0==P->opaque) { - freeup (P); - return 0; - } - - P->opaque->a = 42.42; - P->opaque->b = 42; - - /* Spheroidal? */ - if (0==P->es) { - P->fwd = s_forward; - P->inv = s_inverse; - return P; - } - - /* Otherwise it's ellipsoidal */ - P->fwd = e_forward; - P->inv = e_inverse; - - return P; -} diff --git a/src/PJ_misrsom.c b/src/PJ_misrsom.c index 49be1669..5c5a226f 100644 --- a/src/PJ_misrsom.c +++ b/src/PJ_misrsom.c @@ -21,6 +21,7 @@ *****************************************************************************/ /* based upon Snyder and Linck, USGS-NMD */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -164,36 +165,19 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(misrsom) { int path; double lam, alf, esc, ess; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; path = pj_param(P->ctx, P->params, "ipath").i; - if (path <= 0 || path > 233) { - proj_errno_set(P, PJD_ERR_PATH_NOT_IN_RANGE); - return freeup_new(P); - } + if (path <= 0 || path > 233) + return pj_default_destructor(P, PJD_ERR_PATH_NOT_IN_RANGE); + P->lam0 = DEG_TO_RAD * 129.3056 - M_TWOPI / 233. * path; alf = 98.30382 * DEG_TO_RAD; Q->p22 = 98.88 / 1440.0; diff --git a/src/PJ_mod_ster.c b/src/PJ_mod_ster.c index f8c90bc4..767863c1 100644 --- a/src/PJ_mod_ster.c +++ b/src/PJ_mod_ster.c @@ -1,6 +1,7 @@ /* based upon Snyder and Linck, USGS-NMD */ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(mil_os, "Miller Oblated Stereographic") "\n\tAzi(mod)"; PROJ_HEAD(lee_os, "Lee Oblated Stereographic") "\n\tAzi(mod)"; @@ -98,21 +99,6 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - static PJ *setup(PJ *P) { /* general initialization */ struct pj_opaque *Q = P->opaque; double esphi, chio; @@ -142,7 +128,7 @@ PJ *PROJECTION(mil_os) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->n = 2; @@ -165,7 +151,7 @@ PJ *PROJECTION(lee_os) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->n = 2; @@ -190,7 +176,7 @@ PJ *PROJECTION(gs48) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->n = 4; @@ -225,7 +211,7 @@ PJ *PROJECTION(alsk) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->n = 5; @@ -273,7 +259,7 @@ PJ *PROJECTION(gs50) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->n = 9; diff --git a/src/PJ_moll.c b/src/PJ_moll.c index b975cc73..8470bb3e 100644 --- a/src/PJ_moll.c +++ b/src/PJ_moll.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(moll, "Mollweide") "\n\tPCyl., Sph."; PROJ_HEAD(wag4, "Wagner IV") "\n\tPCyl., Sph."; @@ -51,23 +52,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - static PJ * setup(PJ *P, double p) { struct pj_opaque *Q = P->opaque; double r, sp, p2 = p + p; @@ -89,7 +73,7 @@ static PJ * setup(PJ *P, double p) { PJ *PROJECTION(moll) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; return setup(P, M_HALFPI); @@ -99,7 +83,7 @@ PJ *PROJECTION(moll) { PJ *PROJECTION(wag4) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; return setup(P, M_PI/3.); @@ -108,7 +92,7 @@ PJ *PROJECTION(wag4) { PJ *PROJECTION(wag5) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; P->es = 0; diff --git a/src/PJ_molodensky.c b/src/PJ_molodensky.c index 49e27763..f09f07cd 100644 --- a/src/PJ_molodensky.c +++ b/src/PJ_molodensky.c @@ -63,27 +63,6 @@ struct pj_opaque_molodensky { }; -static void *freeup_msg(PJ *P, int errlev) { - if (0==P) - return 0; - - if (0!=P->ctx) - pj_ctx_set_errno (P->ctx, errlev); - - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - - return pj_dealloc(P); -} - -static void freeup(PJ *P) { - freeup_msg (P, 0); - return; -} - - static double RN (double a, double es, double phi) { /********************************************************** N(phi) - prime vertical radius of curvature @@ -287,7 +266,7 @@ static PJ_OBS reverse_obs(PJ_OBS obs, PJ *P) { PJ *PROJECTION(molodensky) { struct pj_opaque_molodensky *Q = pj_calloc(1, sizeof(struct pj_opaque_molodensky)); if (0==Q) - return freeup_msg(P, ENOMEM); + return pj_default_destructor(P, ENOMEM); P->opaque = (void *) Q; P->fwdobs = forward_obs; @@ -320,10 +299,10 @@ PJ *PROJECTION(molodensky) { /* We want all parameters (except +abridged) to be set */ if ((Q->dx == 0) && (Q->dy == 0) && (Q->dz == 0) && (Q->da == 0) && (Q->df == 0)) - return freeup_msg(P, PJD_ERR_NO_ARGS); + return pj_default_destructor(P, PJD_ERR_NO_ARGS); if ((Q->dx == 0) || (Q->dy == 0) || (Q->dz == 0) || (Q->da == 0) || (Q->df == 0)) - return freeup_msg(P, PJD_ERR_MISSING_ARGS); + return pj_default_destructor(P, PJD_ERR_MISSING_ARGS); return P; } @@ -338,7 +317,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 " @@ -362,7 +341,7 @@ int pj_molodensky_selftest (void) { } /* let's try a roundtrip */ - if (proj_roundtrip(P, PJ_FWD, 100, in) > 1) { + if (proj_roundtrip(P, PJ_FWD, 100, in.coo) > 1) { proj_destroy(P); return 12; } @@ -376,7 +355,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 " ); @@ -391,7 +370,7 @@ int pj_molodensky_selftest (void) { } /* let's try a roundtrip */ - if (proj_roundtrip(P, PJ_FWD, 100, in) > 1) { + if (proj_roundtrip(P, PJ_FWD, 100, in.coo) > 1) { proj_destroy(P); return 22; } diff --git a/src/PJ_natearth.c b/src/PJ_natearth.c index 8d0dae08..9c40f3da 100644 --- a/src/PJ_natearth.c +++ b/src/PJ_natearth.c @@ -13,7 +13,7 @@ and designed in collaboration with Tom Patterson. Port to PROJ.4 by Bernhard Jenny, 6 June 2011 */ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(natearth, "Natural Earth") "\n\tPCyl., Sph."; @@ -88,20 +88,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(natearth) { P->es = 0; P->inv = s_inverse; diff --git a/src/PJ_natearth2.c b/src/PJ_natearth2.c index aab9f9ac..95bb8646 100644 --- a/src/PJ_natearth2.c +++ b/src/PJ_natearth2.c @@ -6,7 +6,7 @@ and Atmospheric Sciences, Oregon State University. Port to PROJ.4 by Bojan Savric, 4 April 2016 */ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(natearth2, "Natural Earth 2") "\n\tPCyl., Sph."; @@ -85,20 +85,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(natearth2) { P->es = 0; P->inv = s_inverse; diff --git a/src/PJ_nell.c b/src/PJ_nell.c index 1b6af010..ac071fc9 100644 --- a/src/PJ_nell.c +++ b/src/PJ_nell.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(nell, "Nell") "\n\tPCyl., Sph."; @@ -38,20 +38,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(nell) { P->es = 0; diff --git a/src/PJ_nell_h.c b/src/PJ_nell_h.c index dfad72b2..fe9a75c6 100644 --- a/src/PJ_nell_h.c +++ b/src/PJ_nell_h.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(nell_h, "Nell-Hammer") "\n\tPCyl., Sph."; @@ -41,20 +41,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(nell_h) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_nocol.c b/src/PJ_nocol.c index 88836a10..934ba7ab 100644 --- a/src/PJ_nocol.c +++ b/src/PJ_nocol.c @@ -1,5 +1,5 @@ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(nicol, "Nicolosi Globular") "\n\tMisc Sph, no inv."; @@ -43,20 +43,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(nicol) { P->es = 0.; P->fwd = s_forward; diff --git a/src/PJ_nsper.c b/src/PJ_nsper.c index 589b6203..4975bb17 100644 --- a/src/PJ_nsper.c +++ b/src/PJ_nsper.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -134,29 +135,12 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - static PJ *setup(PJ *P) { struct pj_opaque *Q = P->opaque; - if ((Q->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) { - proj_errno_set(P, PJD_ERR_H_LESS_THAN_ZERO); - return freeup_new(P); - } + if ((Q->height = pj_param(P->ctx, P->params, "dh").f) <= 0.) + return pj_default_destructor(P, PJD_ERR_H_LESS_THAN_ZERO); + if (fabs(fabs(P->phi0) - M_HALFPI) < EPS10) Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; else if (fabs(P->phi0) < EPS10) @@ -174,6 +158,7 @@ static PJ *setup(PJ *P) { P->inv = s_inverse; P->fwd = s_forward; P->es = 0.; + return P; } @@ -181,7 +166,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(nsper) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->tilt = 0; @@ -195,7 +180,7 @@ PJ *PROJECTION(tpers) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; omega = pj_param(P->ctx, P->params, "dtilt").f * DEG_TO_RAD; diff --git a/src/PJ_nzmg.c b/src/PJ_nzmg.c index 6c705502..b489e32f 100644 --- a/src/PJ_nzmg.c +++ b/src/PJ_nzmg.c @@ -26,7 +26,7 @@ * DEALINGS IN THE SOFTWARE. *****************************************************************************/ #define PJ_LIB__ -#include <projects.h> +#include "projects.h" PROJ_HEAD(nzmg, "New Zealand Map Grid") "\n\tfixed Earth"; @@ -103,19 +103,6 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(nzmg) { /* force to International major axis */ P->ra = 1. / (P->a = 6378388.0); diff --git a/src/PJ_ob_tran.c b/src/PJ_ob_tran.c index 238dba67..d35bb1b3 100644 --- a/src/PJ_ob_tran.c +++ b/src/PJ_ob_tran.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" #include <string.h> @@ -80,89 +81,127 @@ static LP t_inverse(XY xy, PJ *P) { /* spheroid */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor(PJ *P, int errlev) { if (0==P) return 0; if (0==P->opaque) - return pj_dealloc (P); - + return pj_default_destructor (P, errlev); + if (P->opaque->link) - P->opaque->link->pfree(P->opaque->link); + P->opaque->link->destructor (P->opaque->link, errlev); + + return pj_default_destructor(P, errlev); +} + + + + +/*********************************************************************** + +These functions are modified versions of the functions "argc_params" +and "argv_params" from PJ_pipeline.c + +Basically, they do the somewhat backwards stunt of turning the paralist +representation of the +args back into the original +argv, +argc +representation accepted by pj_init_ctx(). + +This, however, also begs the question of whether we really need the +paralist linked list representation, or if we could do with a simpler +null-terminated argv style array? This would simplfy some code, and +keep memory allocations more localized. + +***********************************************************************/ - pj_dealloc (P->opaque); - return pj_dealloc(P); +typedef struct {int argc; char **argv;} ARGS; + +/* count the number of args in the linked list <params> */ +static size_t paralist_params_argc (paralist *params) { + size_t argc = 0; + for (; params != 0; params = params->next) + argc++; + return argc; } -static void freeup (PJ *P) { - freeup_new (P); - return; +/* turn paralist into argc/argv style argument list */ +static ARGS ob_tran_target_params (paralist *params) { + int i = 0; + ARGS args = {0, 0}; + size_t argc = paralist_params_argc (params); + if (argc < 2) + return args; + + /* all args except the proj_ob_tran */ + args.argv = pj_calloc (argc - 1, sizeof (char *)); + if (0==args.argv) + return args; + + /* Copy all args *except* the proj=ob_tran arg to the argv array */ + for (i = 0; params != 0; params = params->next) { + if (0==strcmp (params->param, "proj=ob_tran")) + continue; + args.argv[i++] = params->param; + } + args.argc = i; + + /* Then convert the o_proj=xxx element to proj=xxx */ + for (i = 0; i < args.argc; i++) { + if (0!=strncmp (args.argv[i], "o_proj=", 7)) + continue; + args.argv[i] += 2; + break; + } + + return args; } + PJ *PROJECTION(ob_tran) { - int i; double phip; - char *name, *s; + char *name; + ARGS args; + PJ *R; /* projection to rotate */ struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return destructor(P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + +#if 0 + if (0 != P->es) + return destructor(P, PJD_ERR_ELLIPSOIDAL_UNSUPPORTED); +#endif /* get name of projection to be translated */ - if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) { - proj_errno_set(P, PJD_ERR_NO_ROTATION_PROJ); - return freeup_new(P); - } + if (!(name = pj_param(P->ctx, P->params, "so_proj").s)) + return destructor(P, PJD_ERR_NO_ROTATION_PROJ); + /* avoid endless recursion */ - if( strcmp(name, "ob_tran") == 0 ) { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); - } - for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ; - if (!s || !(Q->link = (*pj_list[i].proj)(0))) { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); - } - /* copy existing header into new */ - P->es = 0.; /* force to spherical */ - Q->link->params = P->params; - Q->link->ctx = P->ctx; - Q->link->over = P->over; - Q->link->geoc = P->geoc; - Q->link->a = P->a; - Q->link->es = P->es; - Q->link->ra = P->ra; - Q->link->lam0 = P->lam0; - Q->link->phi0 = P->phi0; - Q->link->x0 = P->x0; - Q->link->y0 = P->y0; - Q->link->k0 = P->k0; - /* force spherical earth */ - Q->link->one_es = Q->link->rone_es = 1.; - Q->link->es = Q->link->e = 0.; - if (!(Q->link = pj_list[i].proj(Q->link))) { - return freeup_new(P); - } - if( Q->link->fwd == 0 ) { - return freeup_new(P); - } + if( strcmp(name, "ob_tran") == 0 ) + return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + + /* Create the target projection object to rotate */ + args = ob_tran_target_params (P->params); + R = pj_init_ctx (pj_get_ctx(P), args.argc, args.argv); + pj_dealloc (args.argv); + + if (0==R) + return destructor (P, PJD_ERR_UNKNOWN_PROJECTION_ID); + Q->link = R; + if (pj_param(P->ctx, P->params, "to_alpha").i) { double lamc, phic, alpha; lamc = pj_param(P->ctx, P->params, "ro_lon_c").f; phic = pj_param(P->ctx, P->params, "ro_lat_c").f; alpha = pj_param(P->ctx, P->params, "ro_alpha").f; -/* - if (fabs(phic) <= TOL || - fabs(fabs(phic) - HALFPI) <= TOL || - fabs(fabs(alpha) - HALFPI) <= TOL) -*/ - if (fabs(fabs(phic) - M_HALFPI) <= TOL) { - proj_errno_set(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); - return freeup_new(P); - } + + if (fabs(fabs(phic) - M_HALFPI) <= TOL) + return destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); + Q->lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic)); phip = aasin(P->ctx,cos(phic) * sin(alpha)); } else if (pj_param(P->ctx, P->params, "to_lat_p").i) { /* specified new pole */ @@ -176,16 +215,16 @@ PJ *PROJECTION(ob_tran) { lam2 = pj_param(P->ctx, P->params, "ro_lon_2").f; phi2 = pj_param(P->ctx, P->params, "ro_lat_2").f; if (fabs(phi1 - phi2) <= TOL || (con = fabs(phi1)) <= TOL || - fabs(con - M_HALFPI) <= TOL || fabs(fabs(phi2) - M_HALFPI) <= TOL) { - proj_errno_set(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); - return freeup_new(P); - } + fabs(con - M_HALFPI) <= TOL || fabs(fabs(phi2) - M_HALFPI) <= TOL) + return destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); + Q->lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) - sin(phi1) * cos(phi2) * cos(lam2), sin(phi1) * cos(phi2) * sin(lam2) - cos(phi1) * sin(phi2) * sin(lam1)); phip = atan(-cos(Q->lamp - lam1) / tan(phi1)); } + if (fabs(phip) > TOL) { /* oblique */ Q->cphip = cos(phip); Q->sphip = sin(phip); @@ -206,8 +245,11 @@ int pj_ob_tran_selftest (void) {return 0;} int pj_ob_tran_selftest (void) { double tolerance_lp = 1e-10; double tolerance_xy = 1e-7; + double d; + PJ *P; + PJ_COORD a, b; - char s_args[] = {"+proj=ob_tran +a=6400000 +o_proj=latlon +o_lon_p=20 +o_lat_p=20 +lon_0=180"}; + char s_args[] = {"+proj=ob_tran +R=6400000 +o_proj=latlon +o_lon_p=20 +o_lat_p=20 +lon_0=180"}; LP fwd_in[] = { { 2, 1}, @@ -237,7 +279,31 @@ int pj_ob_tran_selftest (void) { {-65.862385598848391, 51.830295078417215}, }; + /* -- Tests from nad/testvarious -------------------------------------------- */ + P = proj_create (0, "+proj=ob_tran +o_proj=moll +R=6378137.0 +o_lon_p=0 +o_lat_p=0 +lon_0=180"); + if (0==P) + return 1; + + a = proj_coord (300000, 400000, 0, 0); + b.lpz.lam = -proj_torad (42 + (45 + 22.377/60)/60); + b.lpz.phi = proj_torad (85 + (35 + 28.083/60)/60); + a = proj_trans_coord (P, -1, a); + d = proj_lp_dist (P, a.lp, b.lp); + if (d > 1e-3) + return 2; + + a = proj_coord (proj_torad(10), proj_torad(20), 0, 0); + b = proj_coord (-1384841.18787, 7581707.88240, 0, 0); + a = proj_trans_coord (P, 1, a); + d = proj_xy_dist (a.xy, b.xy); + if (d > 1e-3) + return 3; + + proj_destroy (P); + /* -------------------------------------------------------------------------- */ + + 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); } -#endif +#endif
\ No newline at end of file diff --git a/src/PJ_ocea.c b/src/PJ_ocea.c index 1fbe2768..d3fe9fe7 100644 --- a/src/PJ_ocea.c +++ b/src/PJ_ocea.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <projects.h> PROJ_HEAD(ocea, "Oblique Cylindrical Equal Area") "\n\tCyl, Sph" @@ -44,28 +45,12 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(ocea) { double phi_0=0.0, phi_1, phi_2, lam_1, lam_2, lonz, alpha; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->rok = 1. / P->k0; diff --git a/src/PJ_oea.c b/src/PJ_oea.c index 2ba7917f..800a266e 100644 --- a/src/PJ_oea.c +++ b/src/PJ_oea.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -52,32 +53,17 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} PJ *PROJECTION(oea) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; if (((Q->n = pj_param(P->ctx, P->params, "dn").f) <= 0.) || ((Q->m = pj_param(P->ctx, P->params, "dm").f) <= 0.)) { - proj_errno_set(P, PJD_ERR_INVALID_M_OR_N); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_INVALID_M_OR_N); } else { Q->theta = pj_param(P->ctx, P->params, "rtheta").f; Q->sp0 = sin(P->phi0); diff --git a/src/PJ_omerc.c b/src/PJ_omerc.c index 0d86e460..f0b4b439 100644 --- a/src/PJ_omerc.c +++ b/src/PJ_omerc.c @@ -22,6 +22,7 @@ ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -111,22 +112,6 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(omerc) { double con, com, cosph0, D, F, H, L, sinph0, p, J, gamma=0, gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0; @@ -134,7 +119,7 @@ PJ *PROJECTION(omerc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->no_rot = pj_param(P->ctx, P->params, "tno_rot").i; @@ -164,10 +149,8 @@ PJ *PROJECTION(omerc) { (con = fabs(phi1)) <= TOL || fabs(con - M_HALFPI) <= TOL || fabs(fabs(P->phi0) - M_HALFPI) <= TOL || - fabs(fabs(phi2) - M_HALFPI) <= TOL) { - proj_errno_set(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); - return freeup_new(P); - } + fabs(fabs(phi2) - M_HALFPI) <= TOL) + return pj_default_destructor(P, PJD_ERR_LAT_0_OR_ALPHA_EQ_90); } com = sqrt(P->one_es); if (fabs(P->phi0) > EPS) { diff --git a/src/PJ_ortho.c b/src/PJ_ortho.c index bb150f05..3179189b 100644 --- a/src/PJ_ortho.c +++ b/src/PJ_ortho.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -104,26 +105,11 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(ortho) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; if (fabs(fabs(P->phi0) - M_HALFPI) <= EPS10) diff --git a/src/PJ_patterson.c b/src/PJ_patterson.c index 952b63ea..40b90010 100644 --- a/src/PJ_patterson.c +++ b/src/PJ_patterson.c @@ -105,19 +105,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(patterson) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_pipeline.c b/src/PJ_pipeline.c index 6e42c0cb..9352b4fd 100644 --- a/src/PJ_pipeline.c +++ b/src/PJ_pipeline.c @@ -260,29 +260,17 @@ static LP pipeline_reverse (XY xy, PJ *P) { return point.coo.lp; } -static void freeup(PJ *P) { /* Destructor */ - if (P==0) - return; - /* Projection specific deallocation goes here */ - pj_dealloc (P->opaque); - pj_dealloc (P); - return; -} - -static void *pipeline_freeup (PJ *P, int errlev) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { int i; if (0==P) return 0; - if (errlev) - proj_errno_set (P, errlev); - if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); for (i = 0; i < P->opaque->steps; i++) - pj_free (P->opaque->pipeline[i+1]); + pj_default_destructor (P->opaque->pipeline[i+1], errlev); pj_dealloc (P->opaque->reverse_step); pj_dealloc (P->opaque->omit_forward); @@ -291,15 +279,7 @@ static void *pipeline_freeup (PJ *P, int errlev) { /* Destructor */ pj_dealloc (P->opaque->current_argv); pj_dealloc (P->opaque->pipeline); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -/* Adapts pipeline_freeup to the format defined for the PJ object */ -static void pipeline_freeup_wrapper (PJ *P) { - pipeline_freeup (P, 0); - return; + return pj_default_destructor(P, errlev); } @@ -364,27 +344,27 @@ PJ *PROJECTION(pipeline) { P->inv3d = pipeline_reverse_3d; P->fwd = pipeline_forward; P->inv = pipeline_reverse; - P->pfree = pipeline_freeup_wrapper; + P->destructor = destructor; P->opaque = pj_calloc (1, sizeof(struct pj_opaque)); if (0==P->opaque) - return 0; + return pj_default_destructor(P, ENOMEM); argc = (int)argc_params (P->params); P->opaque->argv = argv = argv_params (P->params, argc); if (0==argv) - return pipeline_freeup (P, ENOMEM); + return destructor (P, ENOMEM); P->opaque->current_argv = current_argv = pj_calloc (argc, sizeof (char *)); if (0==current_argv) - return pipeline_freeup (P, ENOMEM); + return destructor (P, ENOMEM); /* Do some syntactical sanity checking */ for (i = 0; i < argc; i++) { if (0==strcmp ("step", argv[i])) { if (-1==i_pipeline) { proj_log_error (P, "Pipeline: +step before +proj=pipeline"); - return pipeline_freeup (P, -50); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); } if (0==nsteps) i_first_step = i; @@ -395,7 +375,7 @@ PJ *PROJECTION(pipeline) { if (0==strcmp ("proj=pipeline", argv[i])) { if (-1 != i_pipeline) { proj_log_error (P, "Pipeline: Nesting invalid"); - return pipeline_freeup (P, -50); /* ERROR: nested pipelines */ + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: nested pipelines */ } i_pipeline = i; } @@ -404,14 +384,14 @@ PJ *PROJECTION(pipeline) { P->opaque->steps = nsteps; if (-1==i_pipeline) - return pipeline_freeup (P, -50); /* ERROR: no pipeline def */ + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: no pipeline def */ if (0==nsteps) - return pipeline_freeup (P, -50); /* ERROR: no pipeline def */ + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: no pipeline def */ /* Make room for the pipeline and execution indicators */ if (0==pj_create_pipeline (P, nsteps)) - return pipeline_freeup (P, ENOMEM); + return destructor (P, ENOMEM); /* Now loop over all steps, building a new set of arguments for each init */ for (i_current_step = i_first_step, i = 0; i < nsteps; i++) { @@ -454,7 +434,7 @@ PJ *PROJECTION(pipeline) { proj_log_trace (P, "Pipeline: Step %d at %p", i, next_step); if (0==next_step) { proj_log_error (P, "Pipeline: Bad step definition: %s", current_argv[0]); - return pipeline_freeup (P, -50); /* ERROR: bad pipeline def */ + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); /* ERROR: bad pipeline def */ } P->opaque->pipeline[i+1] = next_step; proj_log_trace (P, "Pipeline: step done"); @@ -470,7 +450,7 @@ PJ *PROJECTION(pipeline) { break; if (i==nsteps) { proj_log_error (P, "Pipeline: No forward steps"); - return pipeline_freeup (P, -50); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); } if (P->opaque->reverse_step[i + 1]) @@ -493,7 +473,7 @@ PJ *PROJECTION(pipeline) { break; if (i==-1) { proj_log_error (P, "Pipeline: No reverse steps"); - return pipeline_freeup (P, -50); + return destructor (P, PJD_ERR_MALFORMED_PIPELINE); } if (P->opaque->reverse_step[i + 1]) @@ -526,7 +506,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 +528,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 +552,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_poly.c b/src/PJ_poly.c index f5af36ac..209669c0 100644 --- a/src/PJ_poly.c +++ b/src/PJ_poly.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -126,32 +127,31 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor(PJ *P, int errlev) { if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); + if (P->opaque->en) pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor(P, errlev); } PJ *PROJECTION(poly) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; if (P->es != 0.0) { - if (!(Q->en = pj_enfn(P->es))) return freeup_new(P); + if (!(Q->en = pj_enfn(P->es))) + return pj_default_destructor (P, ENOMEM); Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); P->inv = e_inverse; P->fwd = e_forward; diff --git a/src/PJ_putp2.c b/src/PJ_putp2.c index 052d95bb..83aa5f45 100644 --- a/src/PJ_putp2.c +++ b/src/PJ_putp2.c @@ -49,19 +49,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(putp2) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_putp3.c b/src/PJ_putp3.c index 93720915..cb216370 100644 --- a/src/PJ_putp3.c +++ b/src/PJ_putp3.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <projects.h> struct pj_opaque { @@ -32,27 +33,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(putp3) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->A = 4. * RPISQ; @@ -67,7 +51,7 @@ PJ *PROJECTION(putp3) { PJ *PROJECTION(putp3p) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->A = 2. * RPISQ; diff --git a/src/PJ_putp4p.c b/src/PJ_putp4p.c index f8b65cee..197f24c4 100644 --- a/src/PJ_putp4p.c +++ b/src/PJ_putp4p.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <projects.h> struct pj_opaque { @@ -36,27 +37,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(putp4p) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->C_x = 0.874038744; @@ -73,7 +57,7 @@ PJ *PROJECTION(putp4p) { PJ *PROJECTION(weren) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->C_x = 1.; diff --git a/src/PJ_putp5.c b/src/PJ_putp5.c index 87b7af74..f8b431b1 100644 --- a/src/PJ_putp5.c +++ b/src/PJ_putp5.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" struct pj_opaque { double A, B; @@ -34,27 +35,11 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(putp5) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->A = 2.; @@ -71,7 +56,7 @@ PJ *PROJECTION(putp5) { PJ *PROJECTION(putp5p) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->A = 1.5; diff --git a/src/PJ_putp6.c b/src/PJ_putp6.c index 6c4fc246..50859f14 100644 --- a/src/PJ_putp6.c +++ b/src/PJ_putp6.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <projects.h> struct pj_opaque { @@ -51,27 +52,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(putp6) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; Q->C_x = 1.01346; @@ -91,7 +75,7 @@ PJ *PROJECTION(putp6) { PJ *PROJECTION(putp6p) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; Q->C_x = 0.44329; diff --git a/src/PJ_qsc.c b/src/PJ_qsc.c index e5fee0ea..f8c760a9 100644 --- a/src/PJ_qsc.c +++ b/src/PJ_qsc.c @@ -39,7 +39,8 @@ */ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" struct pj_opaque { int face; @@ -361,27 +362,10 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(qsc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; P->inv = e_inverse; diff --git a/src/PJ_robin.c b/src/PJ_robin.c index 60a52324..d3f92cd9 100644 --- a/src/PJ_robin.c +++ b/src/PJ_robin.c @@ -145,20 +145,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(robin) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_rpoly.c b/src/PJ_rpoly.c index d0ff8319..8f7b16c6 100644 --- a/src/PJ_rpoly.c +++ b/src/PJ_rpoly.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <projects.h> struct pj_opaque { @@ -34,27 +35,11 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(rpoly) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; if ((Q->mode = (Q->phi1 = fabs(pj_param(P->ctx, P->params, "rlat_ts").f)) > EPS)) { diff --git a/src/PJ_sch.c b/src/PJ_sch.c index 6c97a4f3..dc8cc770 100644 --- a/src/PJ_sch.c +++ b/src/PJ_sch.c @@ -33,6 +33,7 @@ ****************************************************************************/ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" #include "geocent.h" @@ -86,11 +87,6 @@ static LPZ inverse3d(XYZ xyz, PJ *P) { lpz.phi = temp[0] ; lpz.z = temp[2]; -#if 0 - printf("INVERSE: \n"); - printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z); - printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z); -#endif return lpz; } @@ -129,30 +125,10 @@ static XYZ forward3d(LPZ lpz, PJ *P) { xyz.y = temp[0] * Q->rcurv / P->a; xyz.z = temp[2]; -#if 0 - printf("FORWARD: \n"); - printf("LPZ: %f %f %f \n", lpz.lam, lpz.phi, lpz.z); - printf("XYZ: %f %f %f \n", xyz.x, xyz.y, xyz.z); -#endif return xyz; } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - static PJ *setup(PJ *P) { /* general initialization */ struct pj_opaque *Q = P->opaque; double reast, rnorth; @@ -165,10 +141,8 @@ static PJ *setup(PJ *P) { /* general initialization */ temp = P->a * sqrt(1.0 - P->es); /* Setup original geocentric system */ - if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0) { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); - } + if ( pj_Set_Geocentric_Parameters(&(Q->elp_0), P->a, temp) != 0) + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); clt = cos(Q->plat); slt = sin(Q->plat); @@ -185,17 +159,10 @@ static PJ *setup(PJ *P) { /* general initialization */ Q->rcurv = Q->h0 + (reast*rnorth)/(reast * chdg * chdg + rnorth * shdg * shdg); -#if 0 - printf("North Radius: %f \n", rnorth); - printf("East Radius: %f \n", reast); - printf("Effective Radius: %f \n", Q->rcurv); -#endif - /* Set up local sphere at the given peg point */ - if ( pj_Set_Geocentric_Parameters(&(Q->sph), Q->rcurv, Q->rcurv) != 0) { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); - } + if ( pj_Set_Geocentric_Parameters(&(Q->sph), Q->rcurv, Q->rcurv) != 0) + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); + /* Set up the transformation matrices */ Q->transMat[0] = clt * clo; Q->transMat[1] = -shdg*slo - slt*clo * chdg; @@ -210,20 +177,13 @@ static PJ *setup(PJ *P) { /* general initialization */ if( pj_Convert_Geodetic_To_Geocentric( &(Q->elp_0), Q->plat, Q->plon, Q->h0, pxyz, pxyz+1, pxyz+2 ) != 0 ) - { - proj_errno_set(P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); - return freeup_new(P); - } + return pj_default_destructor(P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); Q->xyzoff[0] = pxyz[0] - (Q->rcurv) * clt * clo; Q->xyzoff[1] = pxyz[1] - (Q->rcurv) * clt * slo; Q->xyzoff[2] = pxyz[2] - (Q->rcurv) * slt; -#if 0 - printf("Offset: %f %f %f \n", Q->xyzoff[0], Q->xyzoff[1], Q->xyzoff[2]); -#endif - P->fwd3d = forward3d; P->inv3d = inverse3d; return P; @@ -233,7 +193,7 @@ static PJ *setup(PJ *P) { /* general initialization */ PJ *PROJECTION(sch) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; Q->h0 = 0.0; @@ -242,24 +202,21 @@ PJ *PROJECTION(sch) { if (pj_param(P->ctx, P->params, "tplat_0").i) Q->plat = pj_param(P->ctx, P->params, "rplat_0").f; else { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); } /* Check if peg longitude was defined */ if (pj_param(P->ctx, P->params, "tplon_0").i) Q->plon = pj_param(P->ctx, P->params, "rplon_0").f; else { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); } /* Check if peg latitude is defined */ if (pj_param(P->ctx, P->params, "tphdg_0").i) Q->phdg = pj_param(P->ctx, P->params, "rphdg_0").f; else { - proj_errno_set(P, PJD_ERR_FAILED_TO_FIND_PROJ); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); } @@ -267,10 +224,6 @@ PJ *PROJECTION(sch) { if (pj_param(P->ctx, P->params, "th_0").i) Q->h0 = pj_param(P->ctx, P->params, "dh_0").f; - /* Completed reading in the projection parameters */ -#if 0 - printf("PSA: Lat = %f Lon = %f Hdg = %f \n", Q->plat, Q->plon, Q->phdg); -#endif return setup(P); } diff --git a/src/PJ_sconics.c b/src/PJ_sconics.c index 8759c66e..7f6e094c 100644 --- a/src/PJ_sconics.c +++ b/src/PJ_sconics.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -105,35 +106,19 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, (and ellipsoidal?) inverse } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - static PJ *setup(PJ *P, int type) { double del, cs; - int i; + int err; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->type = type; - i = phi12 (P, &del); - if(i) { - proj_errno_set(P, i); - return freeup_new(P); - } + err = phi12 (P, &del); + if(err) + return pj_default_destructor (P, err); + switch (Q->type) { case TISSOT: @@ -172,10 +157,9 @@ static PJ *setup(PJ *P, int type) { Q->n = sin (Q->sig); Q->c2 = cos (del); Q->c1 = 1./tan (Q->sig); - if (fabs (del = P->phi0 - Q->sig) - EPS10 >= M_HALFPI) { - proj_errno_set(P, PJD_ERR_LAT_0_HALF_PI_FROM_MEAN); - return freeup_new(P); - } + if (fabs (del = P->phi0 - Q->sig) - EPS10 >= M_HALFPI) + return pj_default_destructor(P, PJD_ERR_LAT_0_HALF_PI_FROM_MEAN); + Q->rho_0 = Q->c2 * (Q->c1 - tan (del)); break; diff --git a/src/PJ_somerc.c b/src/PJ_somerc.c index 751d0c77..7324d48a 100644 --- a/src/PJ_somerc.c +++ b/src/PJ_somerc.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -63,31 +64,11 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -#if 0 -FREEUP; if (P) pj_dalloc(P); } -#endif - - -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(somerc) { double cp, phip0, sp; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/PJ_stere.c b/src/PJ_stere.c index befca308..02b73507 100644 --- a/src/PJ_stere.c +++ b/src/PJ_stere.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -213,19 +214,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - static PJ *setup(PJ *P) { /* general initialization */ double t; struct pj_opaque *Q = P->opaque; @@ -291,7 +279,7 @@ static PJ *setup(PJ *P) { /* general initialization */ PJ *PROJECTION(stere) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->phits = pj_param (P->ctx, P->params, "tlat_ts").i ? @@ -304,14 +292,14 @@ PJ *PROJECTION(stere) { PJ *PROJECTION(ups) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; /* International Ellipsoid */ P->phi0 = pj_param(P->ctx, P->params, "bsouth").i ? - M_HALFPI: M_HALFPI; if (P->es == 0.0) { proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return freeup_new(P); + return pj_default_destructor (P, ENOMEM); } P->k0 = .994; P->x0 = 2000000.; diff --git a/src/PJ_sterea.c b/src/PJ_sterea.c index 73c6b48c..e0ff15e7 100644 --- a/src/PJ_sterea.c +++ b/src/PJ_sterea.c @@ -24,7 +24,8 @@ ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include <projects.h> struct pj_opaque { @@ -78,21 +79,15 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor (P, errlev); } @@ -101,12 +96,12 @@ PJ *PROJECTION(sterea) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->en = pj_gauss_ini(P->e, P->phi0, &(Q->phic0), &R); if (0==Q->en) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); Q->sinc0 = sin (Q->phic0); Q->cosc0 = cos (Q->phic0); @@ -114,6 +109,8 @@ PJ *PROJECTION(sterea) { P->inv = e_inverse; P->fwd = e_forward; + P->destructor = destructor; + return P; } diff --git a/src/PJ_sts.c b/src/PJ_sts.c index b6b6dc43..3e6168bd 100644 --- a/src/PJ_sts.c +++ b/src/PJ_sts.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -# include <projects.h> +#include <errno.h> +#include "projects.h" PROJ_HEAD(kav5, "Kavraisky V") "\n\tPCyl., Sph."; PROJ_HEAD(qua_aut, "Quartic Authalic") "\n\tPCyl., Sph."; @@ -8,7 +9,7 @@ PROJ_HEAD(mbt_s, "McBryde-Thomas Flat-Polar Sine (No. 1)") "\n\tPCyl., Sph."; struct pj_opaque { - double C_x, C_y, C_p; \ + double C_x, C_y, C_p; int tan_mode; }; @@ -50,19 +51,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - static PJ *setup(PJ *P, double p, double q, int mode) { P->es = 0.; P->inv = s_inverse; @@ -81,7 +69,7 @@ static PJ *setup(PJ *P, double p, double q, int mode) { PJ *PROJECTION(fouc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; return setup(P, 2., 2., 1); } @@ -151,7 +139,7 @@ int pj_fouc_selftest (void) { PJ *PROJECTION(kav5) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; return setup(P, 1.50488, 1.35439, 0); @@ -221,7 +209,7 @@ int pj_kav5_selftest (void) { PJ *PROJECTION(qua_aut) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; return setup(P, 2., 2., 0); } @@ -289,7 +277,7 @@ int pj_qua_aut_selftest (void) { PJ *PROJECTION(mbt_s) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; return setup(P, 1.48875, 1.36509, 0); } diff --git a/src/PJ_tcc.c b/src/PJ_tcc.c index 80bb6bc8..26cf67b6 100644 --- a/src/PJ_tcc.c +++ b/src/PJ_tcc.c @@ -22,16 +22,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(tcc) { P->es = 0.; P->fwd = s_forward; diff --git a/src/PJ_tcea.c b/src/PJ_tcea.c index d219928d..65b3c604 100644 --- a/src/PJ_tcea.c +++ b/src/PJ_tcea.c @@ -25,16 +25,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(tcea) { P->inv = s_inverse; P->fwd = s_forward; diff --git a/src/PJ_times.c b/src/PJ_times.c index 5d3b0391..a8d6e67a 100644 --- a/src/PJ_times.c +++ b/src/PJ_times.c @@ -66,20 +66,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(times) { P->es = 0.0; diff --git a/src/PJ_tmerc.c b/src/PJ_tmerc.c index 04afc64c..b3ec0030 100644 --- a/src/PJ_tmerc.c +++ b/src/PJ_tmerc.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -160,26 +161,24 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor(PJ *P, int errlev) { /* Destructor */ if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor(P, errlev); + pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); + return pj_default_destructor(P, errlev); } -static void freeup (PJ *P) { - freeup_new (P); - return; -} static PJ *setup(PJ *P) { /* general initialization */ struct pj_opaque *Q = P->opaque; if (P->es != 0.0) { if (!(Q->en = pj_enfn(P->es))) - return freeup_new(P); + return pj_default_destructor(P, ENOMEM); + Q->ml0 = pj_mlfn(P->phi0, sin(P->phi0), cos(P->phi0), Q->en); Q->esp = P->es / (1. - P->es); P->inv = e_inverse; @@ -197,8 +196,11 @@ static PJ *setup(PJ *P) { /* general initialization */ PJ *PROJECTION(tmerc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); + P->opaque = Q; + P->destructor = destructor; + return setup(P); } diff --git a/src/PJ_tpeqd.c b/src/PJ_tpeqd.c index 90dd7568..6bea3968 100644 --- a/src/PJ_tpeqd.c +++ b/src/PJ_tpeqd.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -7,7 +8,7 @@ PROJ_HEAD(tpeqd, "Two Point Equidistant") "\n\tMisc Sph\n\tlat_1= lon_1= lat_2= lon_2="; struct pj_opaque { - double cp1, sp1, cp2, sp2, ccs, cs, sc, r2z0, z02, dlam2; \ + double cp1, sp1, cp2, sp2, ccs, cs, sc, r2z0, z02, dlam2; double hz0, thz0, rhshz0, ca, sa, lp, lamc; }; @@ -55,26 +56,11 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(tpeqd) { double lam_1, lam_2, phi_1, phi_2, A12, pp; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; @@ -84,10 +70,9 @@ PJ *PROJECTION(tpeqd) { phi_2 = pj_param(P->ctx, P->params, "rlat_2").f; lam_2 = pj_param(P->ctx, P->params, "rlon_2").f; - if (phi_1 == phi_2 && lam_1 == lam_2) { - proj_errno_set(P, PJD_ERR_CONTROL_POINT_NO_DIST); - return freeup_new(P); - } + if (phi_1 == phi_2 && lam_1 == lam_2) + return pj_default_destructor(P, PJD_ERR_CONTROL_POINT_NO_DIST); + P->lam0 = adjlon (0.5 * (lam_1 + lam_2)); Q->dlam2 = adjlon (lam_2 - lam_1); diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 27672c8d..c5cf93ae 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -65,9 +65,9 @@ Last update: 2017-05-16 #define PJ_LIB__ #include <time.h> -#include "proj_internal.h" -#include <projects.h> #include <errno.h> +#include "proj_internal.h" +#include "projects.h" PROJ_HEAD(unitconvert, "Unit conversion"); @@ -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 */ @@ -192,26 +199,6 @@ struct pj_opaque_unitconvert { /***********************************************************************/ -static void *freeup_msg (PJ *P, int errlev) { -/***********************************************************************/ - if (0==P) - return 0; - - if (0!=P->ctx) - pj_ctx_set_errno (P->ctx, errlev); - - return pj_dealloc(P); -} - - -/***********************************************************************/ -static void freeup (PJ *P) { -/***********************************************************************/ - freeup_msg (P, 0); - return; -} - -/***********************************************************************/ static XY forward_2d(LP lp, PJ *P) { /************************************************************************ Forward unit conversions in the plane @@ -309,9 +296,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; @@ -326,7 +313,7 @@ PJ *PROJECTION(unitconvert) { int i; if (0==Q) - return freeup_msg (P, ENOMEM); + return pj_default_destructor (P, ENOMEM); P->opaque = (void *) Q; P->fwdobs = forward_obs; @@ -346,7 +333,7 @@ PJ *PROJECTION(unitconvert) { if ((name = pj_param (P->ctx, P->params, "sxy_in").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - if (!s) return freeup_msg(P, -8); /* unknown unit conversion id */ + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOW_UNIT_ID); Q->xy_in_id = i; proj_log_debug(P, "xy_in unit: %s", pj_units[i].name); @@ -355,7 +342,7 @@ PJ *PROJECTION(unitconvert) { if ((name = pj_param (P->ctx, P->params, "sxy_out").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - if (!s) return freeup_msg(P, -8); /* unknown unit conversion id */ + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOW_UNIT_ID); Q->xy_out_id = i; proj_log_debug(P, "xy_out unit: %s", pj_units[i].name); @@ -364,7 +351,7 @@ PJ *PROJECTION(unitconvert) { if ((name = pj_param (P->ctx, P->params, "sz_in").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - if (!s) return freeup_msg(P, -8); /* unknown unit conversion id */ + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOW_UNIT_ID); /* unknown unit conversion id */ Q->z_in_id = i; proj_log_debug(P, "z_in unit: %s", pj_units[i].name); @@ -373,7 +360,7 @@ PJ *PROJECTION(unitconvert) { if ((name = pj_param (P->ctx, P->params, "sz_out").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - if (!s) return freeup_msg(P, -8); /* unknown unit conversion id */ + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOW_UNIT_ID); /* unknown unit conversion id */ Q->z_out_id = i; proj_log_debug(P, "z_out unit: %s", pj_units[i].name); @@ -383,7 +370,7 @@ PJ *PROJECTION(unitconvert) { if ((name = pj_param (P->ctx, P->params, "st_in").s) != NULL) { for (i = 0; (s = time_units[i].id) && strcmp(name, s) ; ++i); - if (!s) return freeup_msg(P, -8); /* unknown unit conversion id */ + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOW_UNIT_ID); /* unknown unit conversion id */ Q->t_in_id = i; proj_log_debug(P, "t_in unit: %s", time_units[i].name); @@ -392,9 +379,9 @@ PJ *PROJECTION(unitconvert) { s = 0; if ((name = pj_param (P->ctx, P->params, "st_out").s) != NULL) { for (i = 0; (s = time_units[i].id) && strcmp(name, s) ; ++i); - if (!s) { - return freeup_msg(P, -8); /* unknown unit conversion id */ - } + + if (!s) return pj_default_destructor(P, PJD_ERR_UNKNOW_UNIT_ID); /* unknown unit conversion id */ + Q->t_out_id = i; proj_log_debug(P, "t_out unit: %s", time_units[i].name); } @@ -410,7 +397,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) @@ -436,7 +423,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_urm5.c b/src/PJ_urm5.c index 9d904fc7..bd073459 100644 --- a/src/PJ_urm5.c +++ b/src/PJ_urm5.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -22,36 +23,19 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (P->opaque) - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(urm5) { double alpha, t; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; if (pj_param(P->ctx, P->params, "tn").i) { 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); - } + if (Q->n <= 0. || Q->n > 1.) + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); } else { - proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(0); + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); } Q->q3 = pj_param(P->ctx, P->params, "dq").f / 3.; alpha = pj_param(P->ctx, P->params, "ralpha").f; diff --git a/src/PJ_urmfps.c b/src/PJ_urmfps.c index fcc7b853..64eb5c80 100644 --- a/src/PJ_urmfps.c +++ b/src/PJ_urmfps.c @@ -1,4 +1,5 @@ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -31,20 +32,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - static PJ *setup(PJ *P) { P->opaque->C_y = Cy / P->opaque->n; P->es = 0.; @@ -57,18 +44,16 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(urmfps) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; if (pj_param(P->ctx, P->params, "tn").i) { P->opaque->n = pj_param(P->ctx, P->params, "dn").f; - if (P->opaque->n <= 0. || P->opaque->n > 1.) { - proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(P); - } + if (P->opaque->n <= 0. || P->opaque->n > 1.) + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); } else { - proj_errno_set(P, PJD_ERR_N_OUT_OF_RANGE); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_N_OUT_OF_RANGE); } return setup(P); @@ -78,7 +63,7 @@ PJ *PROJECTION(urmfps) { PJ *PROJECTION(wag1) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; P->opaque->n = 0.8660254037844386467637231707; diff --git a/src/PJ_vandg.c b/src/PJ_vandg.c index 282eb661..e19d01b8 100644 --- a/src/PJ_vandg.c +++ b/src/PJ_vandg.c @@ -97,20 +97,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(vandg) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_vandg2.c b/src/PJ_vandg2.c index fac7e85d..3f11e289 100644 --- a/src/PJ_vandg2.c +++ b/src/PJ_vandg2.c @@ -1,5 +1,6 @@ #define PJ_LIB__ -#include <projects.h> +#include <errno.h> +#include "projects.h" struct pj_opaque { int vdg3; @@ -44,27 +45,10 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(vandg2) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->vdg3 = 0; @@ -76,7 +60,7 @@ PJ *PROJECTION(vandg2) { PJ *PROJECTION(vandg3) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->vdg3 = 1; diff --git a/src/PJ_vandg4.c b/src/PJ_vandg4.c index 2dbb0713..f7f48b43 100644 --- a/src/PJ_vandg4.c +++ b/src/PJ_vandg4.c @@ -44,20 +44,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(vandg4) { P->es = 0.; P->fwd = s_forward; diff --git a/src/PJ_vgridshift.c b/src/PJ_vgridshift.c index e790cd4d..ededd544 100644 --- a/src/PJ_vgridshift.c +++ b/src/PJ_vgridshift.c @@ -1,25 +1,9 @@ #define PJ_LIB__ #include "proj_internal.h" -#include <projects.h> +#include "projects.h" PROJ_HEAD(vgridshift, "Vertical grid shift"); -static void *freeup_msg (PJ *P, int errlev) { - if (0==P) - return 0; - - if (0!=P->ctx) - pj_ctx_set_errno (P->ctx, errlev); - - return pj_dealloc(P); -} - - -static void freeup (PJ *P) { - freeup_msg (P, 0); - return; -} - static XYZ forward_3d(LPZ lpz, PJ *P) { PJ_TRIPLET point; @@ -74,7 +58,7 @@ PJ *PROJECTION(vgridshift) { if (!pj_param(P->ctx, P->params, "tgrids").i) { proj_log_error(P, "vgridshift: +grids parameter missing."); - return freeup_msg(P, -1); + return pj_default_destructor(P, PJD_ERR_NO_ARGS); } /* Build gridlist. P->gridlist can be empty if +grids only ask for optional grids. */ @@ -84,9 +68,7 @@ PJ *PROJECTION(vgridshift) { /* Was gridlist compiled properly? */ if ( pj_ctx_get_errno(P->ctx) ) { proj_log_error(P, "vgridshift: could not find required grid(s)."); - pj_dalloc(P->gridlist); - P->gridlist = NULL; - return freeup_msg(P, -38); + return pj_default_destructor(P, -38); } P->fwdobs = forward_obs; @@ -111,19 +93,24 @@ int pj_vgridshift_selftest (void) { PJ *P; PJ_OBS expect, a, b; double dist; + int failures = 0; - /* fail on purpose: +grids parameter it mandatory*/ - P = proj_create(0, "+proj=vgridshift"); - if (0!=P) + /* fail on purpose: +grids parameter is mandatory*/ + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift"); + if (0!=P) { + proj_destroy (P); return 99; + } /* fail on purpose: open non-existing grid */ - P = proj_create(0, "+proj=vgridshift +grids=nonexistinggrid.gtx"); - if (0!=P) + P = proj_create(PJ_DEFAULT_CTX, "+proj=vgridshift +grids=nonexistinggrid.gtx"); + if (0!=P) { + proj_destroy (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; @@ -131,18 +118,26 @@ int pj_vgridshift_selftest (void) { a.coo.lpz.lam = PJ_TORAD(12.5); a.coo.lpz.phi = PJ_TORAD(55.5); - dist = proj_roundtrip (P, PJ_FWD, 1, a); + dist = proj_roundtrip (P, PJ_FWD, 1, a.coo); if (dist > 0.00000001) return 1; expect = a; - expect.coo.lpz.z = -36.021305084228515625; + /* Appears there is a difference between the egm96_15.gtx distributed by OSGeo4W, */ + /* and the one from http://download.osgeo.org/proj/vdatum/egm96_15/egm96_15.gtx */ + /* Was: expect.coo.lpz.z = -36.021305084228515625; (download.osgeo.org) */ + /* Was: expect.coo.lpz.z = -35.880001068115234000; (OSGeo4W) */ + /* This is annoying, but must be handled elsewhere. So for now, we check for both. */ + expect.coo.lpz.z = -36.021305084228516; + failures = 0; b = proj_trans_obs(P, PJ_FWD, a); - if (proj_xyz_dist(expect.coo.xyz, b.coo.xyz) > 1e-10) + if (proj_xyz_dist(expect.coo.xyz, b.coo.xyz) > 1e-4) failures++; + expect.coo.lpz.z = -35.880001068115234000; + if (proj_xyz_dist(expect.coo.xyz, b.coo.xyz) > 1e-4) failures++; + if (failures > 1) return 2; - - - pj_free(P); + + proj_destroy (P); return 0; } diff --git a/src/PJ_wag2.c b/src/PJ_wag2.c index 9a41ab63..0588167e 100644 --- a/src/PJ_wag2.c +++ b/src/PJ_wag2.c @@ -25,16 +25,6 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(wag2) { P->es = 0.; P->inv = s_inverse; diff --git a/src/PJ_wag3.c b/src/PJ_wag3.c index 7f5aa4ad..7f300add 100644 --- a/src/PJ_wag3.c +++ b/src/PJ_wag3.c @@ -1,6 +1,9 @@ #define PJ_LIB__ -# include <projects.h> +#include <projects.h> +#include <errno.h> + PROJ_HEAD(wag3, "Wagner III") "\n\tPCyl., Sph.\n\tlat_ts="; + #define TWOTHIRD 0.6666666666666666666667 struct pj_opaque { @@ -16,11 +19,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -#if 0 -INVERSE(s_inverse); /* spheroid */ -#endif - - static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ LP lp = {0.0,0.0}; lp.phi = xy.y; @@ -28,20 +26,13 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ return lp; } -static void freeup (PJ *P) { - pj_freeup_plain (P); - return; -} - PJ *PROJECTION(wag3) { double ts; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - { - freeup(P); - return 0; - } + return pj_default_destructor(P, ENOMEM); + P->opaque = Q; ts = pj_param (P->ctx, P->params, "rlat_ts").f; diff --git a/src/PJ_wag7.c b/src/PJ_wag7.c index d24f4e1a..9152fdea 100644 --- a/src/PJ_wag7.c +++ b/src/PJ_wag7.c @@ -19,17 +19,6 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - - PJ *PROJECTION(wag7) { P->fwd = s_forward; P->inv = 0; diff --git a/src/PJ_wink1.c b/src/PJ_wink1.c index 320a4fb6..c1e2e909 100644 --- a/src/PJ_wink1.c +++ b/src/PJ_wink1.c @@ -1,7 +1,8 @@ #define PJ_LIB__ #include <projects.h> -PROJ_HEAD(wink1, "Winkel I") "\n\tPCyl., Sph.\n\tlat_ts="; +#include <errno.h> +PROJ_HEAD(wink1, "Winkel I") "\n\tPCyl., Sph.\n\tlat_ts="; struct pj_opaque { double cosphi1; @@ -25,25 +26,10 @@ static LP s_inverse (XY xy, PJ *P) { /* Spheroidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(wink1) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; P->opaque->cosphi1 = cos (pj_param(P->ctx, P->params, "rlat_ts").f); diff --git a/src/PJ_wink2.c b/src/PJ_wink2.c index 4b82e423..43b6cfce 100644 --- a/src/PJ_wink2.c +++ b/src/PJ_wink2.c @@ -1,5 +1,6 @@ #define PJ_LIB__ # include <projects.h> +#include <errno.h> PROJ_HEAD(wink2, "Winkel II") "\n\tPCyl., Sph., no inv.\n\tlat_1="; @@ -33,25 +34,10 @@ static XY s_forward (LP lp, PJ *P) { /* Spheroidal, forward */ } -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - - PJ *PROJECTION(wink2) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; P->opaque->cosphi1 = cos(pj_param(P->ctx, P->params, "rlat_1").f); 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 <proj.h> +#include <projects.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <math.h> + +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/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 <math.h> +#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 - * <a href="../index.html">GeographicLib</a> 1.48. + * <a href="../index.html">GeographicLib</a> 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 <math.h> #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);} diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index c22e1b52..1be10362 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -89,6 +89,7 @@ SET(SRC_LIBPROJ_PJ PJ_lagrng.c PJ_larr.c PJ_lask.c + PJ_latlong.c PJ_lcca.c PJ_lcc.c PJ_loxim.c @@ -193,7 +194,6 @@ SET(SRC_LIBPROJ_CORE pj_initcache.c pj_inv.c pj_inv3d.c - pj_latlong.c pj_list.c pj_list.h pj_log.c diff --git a/src/makefile.vc b/src/makefile.vc index cc57d806..ac5acf15 100644 --- a/src/makefile.vc +++ b/src/makefile.vc @@ -25,7 +25,7 @@ misc = \ PJ_chamb.obj PJ_hammer.obj PJ_lagrng.obj PJ_larr.obj \ PJ_lask.obj PJ_nocol.obj PJ_ob_tran.obj PJ_oea.obj \ PJ_sch.obj PJ_tpeqd.obj PJ_vandg.obj PJ_vandg2.obj \ - PJ_vandg4.obj PJ_wag7.obj pj_latlong.obj PJ_krovak.obj \ + PJ_vandg4.obj PJ_wag7.obj PJ_latlong.obj PJ_krovak.obj \ pj_geocent.obj PJ_healpix.obj PJ_qsc.obj pseudo = \ @@ -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/multistresstest.c b/src/multistresstest.c index 8fb764e2..ddbbb033 100644 --- a/src/multistresstest.c +++ b/src/multistresstest.c @@ -363,6 +363,7 @@ static int do_main(void) { printf( "Unable to translate:\n%s\n", test->src_def ); test->skip = 1; + pj_free (dst_pj); continue; } @@ -370,6 +371,7 @@ static int do_main(void) { printf( "Unable to translate:\n%s\n", test->dst_def ); test->skip = 1; + pj_free (src_pj); continue; } 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: + + <operator/program name> + [short ("-")/long ("--") options} + [operator ("+") specs] + [operands/input files] + +or less verbose: + + <operator> [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 <option> was given on the command line. + (i.e. 0 if not given or option unsupported) +opt_arg (o, option): + A char pointer to the argument for <option> + +The 2 additional functions (of which, one is really a macro) implements +a "read all operands sequentially" functionality, eliminating the need to +handle open/close of a sequence of input files: + +enum OPTARGS_FILE_MODE: + indicates whether to read operands in text (0) or binary (1) mode +opt_input_loop (o, mode): + When used as condition in a while loop, traverses all operands, + giving the impression of reading just a single input file. +opt_eof_handler (o): + Auxiliary macro, to be called inside the input loop after each + read operation + +Usage is probably easiest understood by a brief textbook style example: + +Consider a simple program taking the conventinal "-v, -h, -o" options +indicating "verbose output", "help please", and "output file specification", +respectively. + +The "-v" and "-h" options are *flags*, taking no arguments, while the +"-o" option is a *key*, taking a *value* argument, representing the +output file name. + +The short options have long aliases: "--verbose", "--help" and "--output". +Additionally, the long key "--hello", without any short counterpart, is +supported. + +------------------------------------------------------------------------------- + + +int main(int argc, char **argv) { + PJ *P; + OPTARGS *o; + FILE *out = stdout; + char *longflags[] = {"v=verbose", "h=help", 0}; + char *longkeys[] = {"o=output", "hello", 0}; + + o = opt_parse (argc, argv, "hv", "o", longflags, longkeys); + if (0==o) + return 0; + + + if (opt_given (o, "h")) { + printf ("Usage: %s [-v|--verbose] [-h|--help] [-o|--output <filename>] [--hello=<name>] infile...", o->progname); + exit (0); + } + + if (opt_given (o, "v")) + puts ("Feeling chatty today?"); + + if (opt_given (o, "hello")) { + printf ("Hello, %s!\n", opt_arg(o, "hello")); + exit (0); + } + + if (opt_given (o, "o")) + out = fopen (opt_arg (o, "output"), "rt"); // Note: "output" translates to "o" internally + + // Setup transformation + P = proj_create_argv (0, o->pargc, o->pargv); + + // Loop over all lines of all input files + while (opt_input_loop (o, optargs_file_format_text)) { + char buf[1000]; + int ret = fgets (buf, 1000, o->input); + opt_eof_handler (o); + if (0==ret) { + fprintf (stderr, "Read error in record %d\n", (int) o->record_index); + continue; + } + do_what_needs_to_be_done (buf); + } + + return 0; +} + + +------------------------------------------------------------------------------- + +Note how short aliases for longflags and longkeys are defined by prefixing +an "o=", "h=" or "v=", respectively. This also means that it is possible to +have more than one alias for each short option, e.g. + + longkeys = {"o=output", "o=banana", 0} + +would define both "--output" and "--banana" to be aliases for "-o". + +************************************************************************ + +Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-09-10 + +************************************************************************ + +* Copyright (c) 2016, 2017 Thomas Knudsen +* +* 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. + +***********************************************************************/ + +#define PJ_LIB__ +#include <proj.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <math.h> +#include <errno.h> + +/**************************************************************************************************/ +struct OPTARGS; +typedef struct OPTARGS OPTARGS; +enum OPTARGS_FILE_FORMAT {optargs_file_format_text = 0, optargs_file_format_binary = 1}; + +char *opt_filename (OPTARGS *opt); +static int opt_eof (OPTARGS *opt); +int opt_record (OPTARGS *opt); +int opt_input_loop (OPTARGS *opt, int binary); +static int opt_is_flag (OPTARGS *opt, int ordinal); +static int opt_raise_flag (OPTARGS *opt, int ordinal); +static int opt_ordinal (OPTARGS *opt, char *option); +int opt_given (OPTARGS *opt, char *option); +char *opt_arg (OPTARGS *opt, char *option); +OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, const char **longflags, const char **longkeys); + +#define opt_eof_handler(opt) if (opt_eof (opt)) {continue;} else {;} +/**************************************************************************************************/ + +struct OPTARGS { + int argc, margc, pargc, fargc; + char **argv, **margv, **pargv, **fargv; + FILE *input; + int input_index; + int record_index; + char *progname; /* argv[0], stripped from /path/to, if present */ + char flaglevel[21]; /* if flag -f is specified n times, its optarg pointer is set to flaglevel + n */ + char *optarg[256]; /* optarg[(int) 'f'] holds a pointer to the argument of option "-f" */ + char *flags; /* a list of flag style options supported, e.g. "hv" (help and verbose) */ + char *keys; /* a list of key/value style options supported, e.g. "o" (output) */ + const char **longflags; /* long flags, {"help", "verbose"}, or {"h=help", "v=verbose"}, to indicate homologous short options */ + const char **longkeys; /* e.g. {"output"} or {o=output"} to support --output=/path/to/output-file. In the latter case, */ + /* all operations on "--output" gets redirected to "-o", so user code need handle arguments to "-o" only */ +}; + + +/* name of file currently read from */ +char *opt_filename (OPTARGS *opt) { + if (0==opt) + return 0; + if (0==opt->fargc) + return opt->flaglevel; + return opt->fargv[opt->input_index]; +} + +static int opt_eof (OPTARGS *opt) { + if (0==opt) + return 1; + return feof (opt->input); +} + +/* record number of most recently read record */ +int opt_record (OPTARGS *opt) { + if (0==opt) + return 0; + return opt->record_index + 1; +} + + +/* handle closing/opening of a "stream-of-streams" */ +int opt_input_loop (OPTARGS *opt, int binary) { + if (0==opt) + return 0; + + /* most common case: increment record index and read on */ + if ( (opt->input!=0) && !feof (opt->input) ) { + opt->record_index++; + return 1; + } + + opt->record_index = 0; + + /* no input files specified - read from stdin */ + if ((0==opt->fargc) && (0==opt->input)) { + opt->input = stdin; + return 1; + } + + /* if we're here, we have either reached eof on current input file. */ + /* or not yet opened a file. If eof on stdin, we're done */ + if (opt->input==stdin) + return 0; + + /* end if no more input */ + if (0!=opt->input) + fclose (opt->input); + if (opt->input_index >= opt->fargc) + return 0; + + /* otherwise, open next input file */ + opt->input = fopen (opt->fargv[opt->input_index++], binary? "rb": "rt"); + + /* ignore non-existing files - go on! */ + if (0==opt->input) + return opt_input_loop (opt, binary); + return 0; +} + + +/* return true if option with given ordinal is a flag, false if undefined or key=value */ +static int opt_is_flag (OPTARGS *opt, int ordinal) { + if (opt->optarg[ordinal] < opt->flaglevel) + return 0; + if (opt->optarg[ordinal] > opt->flaglevel + 20) + return 0; + return 1; +} + +static int opt_raise_flag (OPTARGS *opt, int ordinal) { + if (opt->optarg[ordinal] < opt->flaglevel) + return 1; + if (opt->optarg[ordinal] > opt->flaglevel + 20) + return 1; + + /* Max out at 20 */ + if (opt->optarg[ordinal]==opt->flaglevel + 20) + return 0; + opt->optarg[ordinal]++; + return 0; +} + +/* Find the ordinal value of any (short or long) option */ +static int opt_ordinal (OPTARGS *opt, char *option) { + int i; + if (0==opt) + return 0; + if (0==option) + return 0; + if (0==option[0]) + return 0; + /* An ordinary -o style short option */ + if (strlen (option)==1) { + /* Undefined option? */ + if (0==opt->optarg[(int) option[0]]) + return 0; + return (int) option[0]; + } + + /* --longname style long options are slightly harder */ + for (i = 0; i < 64; i++) { + const char **f = opt->longflags; + if (0==f) + break; + if (0==f[i]) + break; + if (0==strcmp(f[i], "END")) + break; + if (0==strcmp(f[i], option)) + return 128 + i; + + /* long alias? - return ordinal for corresponding short */ + if ((strlen(f[i]) > 2) && (f[i][1]=='=') && (0==strcmp(f[i]+2, option))) { + /* Undefined option? */ + if (0==opt->optarg[(int) f[i][0]]) + return 0; + return (int) f[i][0]; + } + } + + for (i = 0; i < 64; i++) { + const char **v = opt->longkeys; + if (0==v) + return 0; + if (0==v[i]) + return 0; + if (0==strcmp (v[i], "END")) + return 0; + if (0==strcmp(v[i], option)) + return 192 + i; + + /* long alias? - return ordinal for corresponding short */ + if ((strlen(v[i]) > 2) && (v[i][1]=='=') && (0==strcmp(v[i]+2, option))) { + /* Undefined option? */ + if (0==opt->optarg[(int) v[i][0]]) + return 0; + return (int) v[i][0]; + } + + } + + return 0; +} + + +/* Returns 0 if option was not given on command line, non-0 otherwise */ +int opt_given (OPTARGS *opt, char *option) { + int ordinal = opt_ordinal (opt, option); + if (0==ordinal) + return 0; + /* For flags we return the number of times the flag was specified (mostly for repeated -v(erbose) flags) */ + if (opt_is_flag (opt, ordinal)) + return (int) (opt->optarg[ordinal] - opt->flaglevel); + return opt->argv[0] != opt->optarg[ordinal]; +} + + +/* Returns the argument to a given option */ +char *opt_arg (OPTARGS *opt, char *option) { + int ordinal = opt_ordinal (opt, option); + if (0==ordinal) + return 0; + return opt->optarg[ordinal]; +} + + +/* split command line options into options/flags ("-" style), projdefs ("+" style) and input file args */ +OPTARGS *opt_parse (int argc, char **argv, const char *flags, const char *keys, const char **longflags, const char **longkeys) { + int i, j; + OPTARGS *o; + char *last_path_delim; + + o = (OPTARGS *) calloc (1, sizeof(OPTARGS)); + if (0==o) + return 0; + + o->argc = argc; + o->argv = argv; + o->progname = argv[0]; + last_path_delim = strrchr (argv[0], '\\'); + if (last_path_delim > o->progname) + o->progname = last_path_delim; + last_path_delim = strrchr (argv[0], '/'); + if (last_path_delim > o->progname) + o->progname = last_path_delim; + + + /* Reset all flags */ + for (i = 0; i < (int) strlen (flags); i++) + o->optarg[(int) flags[i]] = o->flaglevel; + + /* Flag args for all argument taking options as "unset" */ + for (i = 0; i < (int) strlen (keys); i++) + o->optarg[(int) keys[i]] = argv[0]; + + /* Hence, undefined/illegal options have an argument of 0 */ + + /* long opts are handled similarly, but are mapped to the high bit character range (above 128) */ + o->longflags = longflags; + o->longkeys = longkeys; + + + /* check aliases, An end user should never experience this, but the developer should make sure that aliases are valid */ + for (i = 0; longflags && longflags[i]; i++) { + /* Go on if it does not look like an alias */ + if (strlen (longflags[i]) < 3) + continue; + if ('='!=longflags[i][1]) + continue; + if (0==strchr (flags, longflags[i][0])) { + fprintf (stderr, "%s: Invalid alias - '%s'. Valid short flags are '%s'\n", o->progname, longflags[i], flags); + free (o); + return 0; + } + } + for (i = 0; longkeys && longkeys[i]; i++) { + /* Go on if it does not look like an alias */ + if (strlen (longkeys[i]) < 3) + continue; + if ('='!=longkeys[i][1]) + continue; + if (0==strchr (keys, longkeys[i][0])) { + fprintf (stderr, "%s: Invalid alias - '%s'. Valid short flags are '%s'\n", o->progname, longkeys[i], keys); + free (o); + return 0; + } + } + + /* aside from counting the number of times a flag has been specified, we also abuse the */ + /* flaglevel array to provide a pseudo-filename for the case of reading from stdin */ + strcpy (o->flaglevel, "<stdin>"); + + for (i = 128; (longflags != 0) && (longflags[i - 128] != 0); i++) { + if (i==192) { + free (o); + fprintf (stderr, "Too many flag style long options\n"); + return 0; + } + o->optarg[i] = o->flaglevel; + } + + for (i = 192; (longkeys != 0) && (longkeys[i - 192] != 0); i++) { + if (i==256) { + free (o); + fprintf (stderr, "Too many value style long options\n"); + return 0; + } + o->optarg[i] = argv[0]; + } + + /* Now, set up the agrc/argv pairs, and interpret args */ + o->argc = argc; + o->argv = argv; + + /* Process all '-' and '--'-style options */ + for (i = 1; i < argc; i++) { + int arg_group_size = (int) strlen (argv[i]); + + if ('-' != argv[i][0]) + break; + if (0==o->margv) + o->margv = argv + i; + o->margc++; + + for (j = 1; j < arg_group_size; j++) { + int c = argv[i][j]; + char cstring[2], *crepr = cstring; + cstring[0] = (char) c; + cstring[1] = 0; + + + /* Long style flags and options (--long_opt_name, --long_opt_namr arg, --long_opt_name=arg) */ + if (c== (int)'-') { + char *equals; + crepr = argv[i] + 2; + + /* need to maniplulate a bit to support gnu style --pap=pop syntax */ + equals = strchr (crepr, '='); + if (equals) + *equals = 0; + c = opt_ordinal (o, crepr); + if (0==c) + return fprintf (stderr, "Invalid option \"%s\"\n", crepr), (OPTARGS *) 0; + + /* inline (gnu) --foo=bar style arg */ + if (equals) { + *equals = '='; + if (opt_is_flag (o, c)) + return fprintf (stderr, "Option \"%s\" takes no arguments\n", crepr), (OPTARGS *) 0; + o->optarg[c] = equals + 1; + break; + } + + /* "outline" --foo bar style arg */ + if (!opt_is_flag (o, c)) { + if ((argc==i + 1) || ('+'==argv[i+1][0]) || ('-'==argv[i+1][0])) + return fprintf (stderr, "Missing argument for option \"%s\"\n", crepr), (OPTARGS *) 0; + o->optarg[c] = argv[i + 1]; + i++; /* eat the arg */ + break; + } + + if (!opt_is_flag (o, c)) + return fprintf (stderr, "Expected flag style long option here, but got \"%s\"\n", crepr), (OPTARGS *) 0; + + /* Flag style option, i.e. taking no arguments */ + opt_raise_flag (o, c); + break; + } + + /* classic short options */ + if (0==o->optarg[c]) + return fprintf (stderr, "Invalid option \"%s\"\n", crepr), (OPTARGS *) 0; + + /* Flag style option, i.e. taking no arguments */ + if (opt_is_flag (o, c)) { + opt_raise_flag (o, c); + continue; + } + + /* options taking argumants */ + + /* argument separate (i.e. "-i 10") */ + if (j + 1==arg_group_size) { + if ((argc==i + 1) || ('+'==argv[i+1][0]) || ('-'==argv[i+1][0])) + return fprintf (stderr, "Bad or missing arg for option \"%s\"\n", crepr), (OPTARGS *) 0; + o->optarg[(int) c] = argv[i + 1]; + i++; + break; + } + + /* Option arg inline (i.e. "-i10") */ + o->optarg[c] = argv[i] + j + 1; + break; + } + } + + /* Process all '+'-style options, starting from where '-'-style processing ended */ + o->pargv = argv + i; + for (/* empty */; i < argc; i++) { + if ('-' == argv[i][0]) { + free (o); + fprintf (stderr, "+ and - style options must not be mixed\n"); + return 0; + } + + if ('+' != argv[i][0]) + break; + o->pargc++; + } + + /* Handle input file names */ + o->fargc = argc - i; + if (0!=o->fargc) + o->fargv = argv + i; + + return o; + +} diff --git a/src/pj_ctx.c b/src/pj_ctx.c index 89b2816f..a8edaf43 100644 --- a/src/pj_ctx.c +++ b/src/pj_ctx.c @@ -27,6 +27,7 @@ #include <projects.h> #include <string.h> +#include <errno.h> static projCtx_t default_context; static volatile int default_context_initialized = 0; @@ -38,6 +39,10 @@ static volatile int default_context_initialized = 0; projCtx pj_get_ctx( projPJ pj ) { + if (0==pj) + return pj_get_default_ctx (); + if (0==pj->ctx) + return pj_get_default_ctx (); return pj->ctx; } @@ -50,6 +55,8 @@ projCtx pj_get_ctx( projPJ pj ) void pj_set_ctx( projPJ pj, projCtx ctx ) { + if (pj==0) + return; pj->ctx = ctx; } @@ -98,6 +105,8 @@ projCtx pj_ctx_alloc() { projCtx ctx = (projCtx_t *) malloc(sizeof(projCtx_t)); + if (0==ctx) + return 0; memcpy( ctx, pj_get_default_ctx(), sizeof(projCtx_t) ); ctx->last_errno = 0; @@ -111,7 +120,7 @@ projCtx pj_ctx_alloc() void pj_ctx_free( projCtx ctx ) { - free( ctx ); + pj_dealloc( ctx ); } /************************************************************************/ @@ -121,21 +130,25 @@ void pj_ctx_free( projCtx ctx ) int pj_ctx_get_errno( projCtx ctx ) { + if (0==ctx) + return pj_get_default_ctx ()->last_errno; return ctx->last_errno; } /************************************************************************/ /* pj_ctx_set_errno() */ /* */ -/* Also sets the global errno. */ +/* Also sets the global errno */ /************************************************************************/ void pj_ctx_set_errno( projCtx ctx, int new_errno ) { ctx->last_errno = new_errno; - if( new_errno != 0 ) - pj_errno = new_errno; + if( new_errno == 0 ) + return; + errno = new_errno; + pj_errno = new_errno; } /************************************************************************/ @@ -145,6 +158,8 @@ void pj_ctx_set_errno( projCtx ctx, int new_errno ) void pj_ctx_set_debug( projCtx ctx, int new_debug ) { + if (0==ctx) + pj_get_default_ctx ()->debug_level = new_debug; ctx->debug_level = new_debug; } @@ -155,6 +170,8 @@ void pj_ctx_set_debug( projCtx ctx, int new_debug ) void pj_ctx_set_logger( projCtx ctx, void (*new_logger)(void*,int,const char*) ) { + if (0==ctx) + return; ctx->logger = new_logger; } @@ -165,6 +182,8 @@ void pj_ctx_set_logger( projCtx ctx, void (*new_logger)(void*,int,const char*) ) void pj_ctx_set_app_data( projCtx ctx, void *new_app_data ) { + if (0==ctx) + return; ctx->app_data = new_app_data; } @@ -175,6 +194,8 @@ void pj_ctx_set_app_data( projCtx ctx, void *new_app_data ) void *pj_ctx_get_app_data( projCtx ctx ) { + if (0==ctx) + return 0; return ctx->app_data; } @@ -185,6 +206,8 @@ void *pj_ctx_get_app_data( projCtx ctx ) void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi ) { + if (0==ctx) + return; ctx->fileapi = fileapi; } @@ -195,5 +218,7 @@ void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi ) projFileAPI *pj_ctx_get_fileapi( projCtx ctx ) { + if (0==ctx) + return 0; return ctx->fileapi; } diff --git a/src/pj_fwd.c b/src/pj_fwd.c index 02f18d1c..e010f6ec 100644 --- a/src/pj_fwd.c +++ b/src/pj_fwd.c @@ -17,8 +17,8 @@ pj_fwd(LP lp, PJ *P) { return err; last_errno = proj_errno_reset (P); - /* Check input coordinates if angular */ - if ((P->left==PJ_IO_UNITS_CLASSIC)||(P->left==PJ_IO_UNITS_RADIANS)) { + /* Check validity of angular input coordinates */ + if (P->left==PJ_IO_UNITS_RADIANS) { /* check for forward and latitude or longitude overange */ t = fabs(lp.phi)-M_HALFPI; diff --git a/src/pj_fwd3d.c b/src/pj_fwd3d.c index be683745..d141178f 100644 --- a/src/pj_fwd3d.c +++ b/src/pj_fwd3d.c @@ -20,8 +20,8 @@ XYZ pj_fwd3d(LPZ lpz, PJ *P) { last_errno = proj_errno_reset(P); - /* Check input coordinates if angular */ - if ((P->left==PJ_IO_UNITS_CLASSIC)||(P->left==PJ_IO_UNITS_RADIANS)) { + /* Check validity of angular input coordinates */ + if (P->left==PJ_IO_UNITS_RADIANS) { /* check for forward and latitude or longitude overange */ t = fabs(lpz.phi)-M_HALFPI; diff --git a/src/pj_geocent.c b/src/pj_geocent.c index a00fc991..667c29bd 100644 --- a/src/pj_geocent.c +++ b/src/pj_geocent.c @@ -48,19 +48,6 @@ static LP inverse(XY xy, PJ *P) { return lp; } - -static void *freeup_new (PJ *P) { - if (0==P) - return 0; - - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - PJ *PROJECTION(geocent) { P->is_geocent = 1; P->x0 = 0.0; diff --git a/src/pj_gridlist.c b/src/pj_gridlist.c index 4193526f..1123274e 100644 --- a/src/pj_gridlist.c +++ b/src/pj_gridlist.c @@ -102,11 +102,11 @@ static int pj_gridlist_merge_gridfile( projCtx ctx, PJ_GRIDINFO **new_list; int new_max = *p_gridmax + 20; - new_list = (PJ_GRIDINFO **) pj_malloc(sizeof(void*) * new_max); + new_list = (PJ_GRIDINFO **) pj_calloc(new_max, sizeof(void *)); if( *p_gridlist != NULL ) { memcpy( new_list, *p_gridlist, - sizeof(void*) * (*p_gridmax) ); + sizeof(void *) * (*p_gridmax) ); pj_dalloc( *p_gridlist ); } @@ -194,7 +194,7 @@ PJ_GRIDINFO **pj_gridlist_from_nadgrids( projCtx ctx, const char *nadgrids, if( end_char >= sizeof(name) ) { pj_dalloc( gridlist ); - pj_ctx_set_errno( ctx, -38 ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return NULL; } @@ -211,7 +211,7 @@ PJ_GRIDINFO **pj_gridlist_from_nadgrids( projCtx ctx, const char *nadgrids, && required ) { pj_dalloc( gridlist ); - pj_ctx_set_errno( ctx, -38 ); + pj_ctx_set_errno( ctx, PJD_ERR_FAILED_TO_LOAD_GRID ); pj_release_lock(); return NULL; } diff --git a/src/pj_init.c b/src/pj_init.c index 7448fdb6..951f1cfb 100644 --- a/src/pj_init.c +++ b/src/pj_init.c @@ -414,6 +414,8 @@ bum_call: return result; } + + /************************************************************************/ /* pj_init() */ /* */ @@ -438,15 +440,18 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { int found_def = 0; PJ *PIN = 0; + if (0==ctx) + ctx = pj_get_default_ctx (); + ctx->last_errno = 0; start = NULL; - /* put arguments into internal linked list */ if (argc <= 0) { - pj_ctx_set_errno( ctx, -1 ); - goto bum_call; + pj_ctx_set_errno (ctx, PJD_ERR_NO_ARGS); + return 0; } - + + /* put arguments into internal linked list */ start = curr = pj_mkparam(argv[0]); /* build parameter list and expand +init's. Does not take care of a single +init. */ @@ -458,12 +463,11 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { found_def = 0; curr = get_init(ctx, &curr, curr->next, pj_param(ctx, curr, "sinit").s, &found_def); if (!curr) - goto bum_call; + return pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); - if (!found_def) { - pj_ctx_set_errno( ctx, -2); - goto bum_call; - } + if (!found_def) + return pj_dealloc_params (ctx, start, PJD_ERR_NO_OPTION_IN_INIT_FILE); + } else { curr = curr->next; } @@ -475,31 +479,32 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { found_def = 0; curr = get_init(ctx, &start, curr, pj_param(ctx, start, "sinit").s, &found_def); if (!curr) - goto bum_call; - if (!found_def) { - pj_ctx_set_errno( ctx, -2); - goto bum_call; - } + return pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); + if (!found_def) + return pj_dealloc_params (ctx, start, PJD_ERR_NO_OPTION_IN_INIT_FILE); } - - if (ctx->last_errno) goto bum_call; - + + if (ctx->last_errno) + return pj_dealloc_params (ctx, start, ctx->last_errno); + /* find projection selection */ - if (!(name = pj_param(ctx, start, "sproj").s)) { - pj_ctx_set_errno( ctx, -4 ); - goto bum_call; - } + if (!(name = pj_param(ctx, start, "sproj").s)) + return pj_default_destructor (PIN, PJD_ERR_PROJ_NOT_NAMED); for (i = 0; (s = pj_list[i].id) && strcmp(name, s) ; ++i) ; - if (!s) { pj_ctx_set_errno( ctx, -5 ); goto bum_call; } - + if (!s) + return pj_dealloc_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID); + /* set defaults, unless inhibited */ - if (!pj_param(ctx, start, "bno_defs").i) + if (!(pj_param(ctx, start, "bno_defs").i)) curr = get_defaults(ctx,&start, curr, name); proj = (PJ *(*)(PJ *)) pj_list[i].proj; /* allocate projection structure */ - if (!(PIN = (*proj)(0))) goto bum_call; + PIN = proj(0); + if (0==PIN) + return pj_dealloc_params (ctx, start, ENOMEM); + PIN->ctx = ctx; PIN->params = start; PIN->is_latlong = 0; @@ -515,19 +520,19 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { PIN->vgridlist_geoid_count = 0; /* set datum parameters */ - if (pj_datum_set(ctx, start, PIN)) goto bum_call; + if (pj_datum_set(ctx, start, PIN)) + return pj_default_destructor (PIN, PJD_ERR_MISSING_ARGS); /* set ellipsoid/sphere parameters */ if (pj_ell_set(ctx, start, &PIN->a, &PIN->es)) { pj_log (ctx, PJ_LOG_DEBUG_MINOR, "pj_init_ctx: Must specify ellipsoid or sphere"); - goto bum_call; + return pj_default_destructor (PIN, PJD_ERR_MISSING_ARGS); } PIN->a_orig = PIN->a; PIN->es_orig = PIN->es; /* Compute some ancillary ellipsoidal parameters */ - PIN->e = sqrt(PIN->es); /* eccentricity */ PIN->alpha = asin (PIN->e); /* angular eccentricity */ @@ -536,7 +541,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { PIN->e2s = PIN->e2 * PIN->e2; /* third eccentricity */ - PIN->e3 = sin (PIN->alpha) / sqrt(2 - sin (PIN->alpha)*sin (PIN->alpha)); + PIN->e3 = (0!=PIN->alpha)? sin (PIN->alpha) / sqrt(2 - sin (PIN->alpha)*sin (PIN->alpha)): 0; PIN->e3s = PIN->e3 * PIN->e3; /* flattening */ @@ -544,7 +549,7 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { PIN->rf = PIN->f != 0.0 ? 1.0/PIN->f: HUGE_VAL; /* second flattening */ - PIN->f2 = 1/cos (PIN->alpha) - 1; + PIN->f2 = (cos(PIN->alpha)!=0)? 1/cos (PIN->alpha) - 1: 0; PIN->rf2 = PIN->f2 != 0.0 ? 1/PIN->f2: HUGE_VAL; /* third flattening */ @@ -557,7 +562,8 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { PIN->ra = 1. / PIN->a; PIN->one_es = 1. - PIN->es; - if (PIN->one_es == 0.) { pj_ctx_set_errno( ctx, -6 ); goto bum_call; } + if (PIN->one_es == 0.) + return pj_default_destructor (PIN, PJD_ERR_ECCENTRICITY_IS_ONE); PIN->rone_es = 1./PIN->one_es; @@ -586,38 +592,28 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { /* longitude center for wrapping */ PIN->is_long_wrap_set = pj_param(ctx, start, "tlon_wrap").i; - if (PIN->is_long_wrap_set) - { + if (PIN->is_long_wrap_set) { PIN->long_wrap_center = pj_param(ctx, start, "rlon_wrap").f; /* Don't accept excessive values otherwise we might perform badly */ /* when correcting longitudes around it */ /* The test is written this way to error on long_wrap_center "=" NaN */ if( !(fabs(PIN->long_wrap_center) < 10 * M_TWOPI) ) - { - pj_ctx_set_errno( ctx, -14 ); - goto bum_call; - } + return pj_default_destructor (PIN, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); } - + /* axis orientation */ if( (pj_param(ctx, start,"saxis").s) != NULL ) { static const char *axis_legal = "ewnsud"; const char *axis_arg = pj_param(ctx, start,"saxis").s; if( strlen(axis_arg) != 3 ) - { - pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); - goto bum_call; - } + return pj_default_destructor (PIN, PJD_ERR_AXIS); if( strchr( axis_legal, axis_arg[0] ) == NULL || strchr( axis_legal, axis_arg[1] ) == NULL || strchr( axis_legal, axis_arg[2] ) == NULL) - { - pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); - goto bum_call; - } - + return pj_default_destructor (PIN, PJD_ERR_AXIS); + /* it would be nice to validate we don't have on axis repeated */ strcpy( PIN->axis, axis_arg ); } @@ -631,6 +627,8 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { /* false easting and northing */ PIN->x0 = pj_param(ctx, start, "dx_0").f; PIN->y0 = pj_param(ctx, start, "dy_0").f; + PIN->z0 = pj_param(ctx, start, "dz_0").f; + PIN->t0 = pj_param(ctx, start, "dt_0").f; /* general scaling factor */ if (pj_param(ctx, start, "tk_0").i) @@ -639,26 +637,23 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { PIN->k0 = pj_param(ctx, start, "dk").f; else PIN->k0 = 1.; - if (PIN->k0 <= 0.) { - pj_ctx_set_errno( ctx, -31 ); - goto bum_call; - } + if (PIN->k0 <= 0.) + return pj_default_destructor (PIN, PJD_ERR_K_LESS_THAN_ZERO); /* set units */ s = 0; if ((name = pj_param(ctx, start, "sunits").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ; - if (!s) { pj_ctx_set_errno( ctx, -7 ); goto bum_call; } + if (!s) + return pj_default_destructor (PIN, PJD_ERR_UNKNOW_UNIT_ID); s = pj_units[i].to_meter; } if (s || (s = pj_param(ctx, start, "sto_meter").s)) { PIN->to_meter = pj_strtod(s, &s); if (*s == '/') /* ratio number */ PIN->to_meter /= pj_strtod(++s, 0); - if (PIN->to_meter <= 0.0) { - pj_ctx_set_errno( ctx, -51); - goto bum_call; - } + if (PIN->to_meter <= 0.0) + return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); PIN->fr_meter = 1. / PIN->to_meter; } else PIN->to_meter = PIN->fr_meter = 1.; @@ -667,17 +662,16 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { s = 0; if ((name = pj_param(ctx, start, "svunits").s) != NULL) { for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i) ; - if (!s) { pj_ctx_set_errno( ctx, -7 ); goto bum_call; } + if (!s) + return pj_default_destructor (PIN, PJD_ERR_UNKNOW_UNIT_ID); s = pj_units[i].to_meter; } if (s || (s = pj_param(ctx, start, "svto_meter").s)) { PIN->vto_meter = pj_strtod(s, &s); if (*s == '/') /* ratio number */ PIN->vto_meter /= pj_strtod(++s, 0); - if (PIN->vto_meter <= 0.0) { - pj_ctx_set_errno( ctx, -51); - goto bum_call; - } + if (PIN->vto_meter <= 0.0) + return pj_default_destructor (PIN, PJD_ERR_UNIT_FACTOR_LESS_THAN_0); PIN->vfr_meter = 1. / PIN->vto_meter; } else { PIN->vto_meter = PIN->to_meter; @@ -704,7 +698,8 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { && *next_str == '\0' ) value = name; - if (!value) { pj_ctx_set_errno( ctx, -46 ); goto bum_call; } + if (!value) + return pj_default_destructor (PIN, PJD_ERR_UNKNOWN_PRIME_MERIDIAN); PIN->from_greenwich = dmstor_ctx(ctx,value,NULL); } else @@ -712,55 +707,15 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) { /* Private object for the geodesic functions */ PIN->geod = pj_calloc (1, sizeof (struct geod_geodesic)); - if (0!=PIN->geod) - geod_init(PIN->geod, PIN->a, (1 - sqrt (1 - PIN->es))); + if (0==PIN->geod) + return pj_default_destructor (PIN, ENOMEM); + geod_init(PIN->geod, PIN->a, (1 - sqrt (1 - PIN->es))); /* projection specific initialization */ - { - /* Backup those variables so that we can clean them in case - * (*proj)(PIN) fails */ - void* gridlist = PIN->gridlist; - void* vgridlist_geoid = PIN->vgridlist_geoid; - void* catalog_name = PIN->catalog_name; - void* geod = PIN->geod; - if (!(PIN = (*proj)(PIN)) || ctx->last_errno) { - if (PIN) - pj_free(PIN); - else { - for ( ; start; start = curr) { - curr = start->next; - pj_dalloc(start); - } - if( gridlist ) - pj_dalloc( gridlist ); - if( vgridlist_geoid ) - pj_dalloc( vgridlist_geoid ); - if( catalog_name ) - pj_dalloc( catalog_name ); - if( geod ) - pj_dalloc( geod ); - } - PIN = 0; - } - } - - return PIN; - -bum_call: /* cleanup error return */ - { - if (PIN) - { - pj_free(PIN); - } - else { - for ( ; start; start = curr) { - curr = start->next; - pj_dalloc(start); - } - } + PIN = proj(PIN); + if ((0==PIN) || ctx->last_errno) return 0; - } - + return PIN; } /************************************************************************/ @@ -769,65 +724,17 @@ 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 -pj_free(PJ *P) { - if (P) { - paralist *t, *n; - - /* free parameter list elements */ - for (t = P->params; t; t = n) { - n = t->next; - 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 ); - - /* We used to call pj_dalloc( P->catalog ), but this will leak */ - /* memory. The safe way to clear catalog and grid is to call */ - /* pj_gc_unloadall(pj_get_default_ctx()); and pj_deallocate_grids(); */ - /* TODO: we should probably have a public pj_cleanup() method to do all */ - /* that */ - - if( P->geod != NULL ) - pj_dalloc( P->geod ); - - /* free projection parameters */ - P->pfree(P); - } -} - - - - - - - - -/************************************************************************/ -/* 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); +void pj_free(PJ *P) { + if (0==P) + return; + /* free projection parameters - all the hard work is done by */ + /* pj_default_destructor (in pj_malloc.c), which is supposed */ + /* to be called as the last step of the local destructor */ + /* pointed to by P->destructor. In most cases, */ + /* pj_default_destructor actually *is* what is pointed to */ + P->destructor (P, 0); } diff --git a/src/pj_inv.c b/src/pj_inv.c index 55fc917f..68a5595b 100644 --- a/src/pj_inv.c +++ b/src/pj_inv.c @@ -42,7 +42,7 @@ LP pj_inv(XY xy, PJ *P) { if (P->ctx->last_errno) return err; - if ((P->left==PJ_IO_UNITS_CLASSIC)||(P->left==PJ_IO_UNITS_RADIANS)) { + if (P->left==PJ_IO_UNITS_RADIANS) { /* reduce from del lp.lam */ lp.lam += P->lam0; diff --git a/src/pj_inv3d.c b/src/pj_inv3d.c index a01cfa7e..53e39a76 100644 --- a/src/pj_inv3d.c +++ b/src/pj_inv3d.c @@ -42,7 +42,7 @@ LPZ pj_inv3d (XYZ xyz, PJ *P) { if (P->ctx->last_errno) return err; - if ((P->left==PJ_IO_UNITS_CLASSIC)||(P->left==PJ_IO_UNITS_RADIANS)) { + if (P->left==PJ_IO_UNITS_RADIANS) { /* reduce from del lp.lam */ lpz.lam += P->lam0; diff --git a/src/pj_malloc.c b/src/pj_malloc.c index 330b14a6..4e465c46 100644 --- a/src/pj_malloc.c +++ b/src/pj_malloc.c @@ -40,7 +40,7 @@ ** projection system memory allocation/deallocation call with custom ** application procedures. */ -#include <projects.h> +#include "projects.h" #include <errno.h> /**********************************************************************/ @@ -52,30 +52,43 @@ https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=86420. It seems, that pj_init and similar functions incorrectly (under debian/glibs-2.3.2) assume that pj_malloc resets errno after success. pj_malloc tries to mimic this. -***********************************************************************/ - int old_errno = errno; - void *res = malloc(size); - if ( res && !old_errno ) - errno = 0; - return res; -} -/**********************************************************************/ -void pj_dalloc(void *ptr) { -/**********************************************************************/ - free(ptr); +NOTE (2017-09-29): The problem described at the bugzilla page +referred to above, is most likely a case of someone not +understanding the proper usage of errno. We should review +whether "the problem is actually a problem" in PROJ.4 code. + +Library specific allocators can be useful, and improve +interoperability, if properly used. That is, by making them +run/initialization time switchable, somewhat like the file i/o +interface. + +But as things stand, we are more likely to get benefit +from reviewing the code for proper errno usage, which is hard, +due to the presence of context local and global pj_errnos. + +Probably, these were introduced in order to support incomplete +implementations of thread local errnos at an early phase of the +implementation of multithreading support in PROJ.4). + +It is likely too late to get rid of contexts, but we can still +benefit from a better usage of errno. +***********************************************************************/ + int old_errno = errno; + void *res = malloc(size); + if ( res && !old_errno ) + errno = 0; + return res; } /**********************************************************************/ void *pj_calloc (size_t n, size_t size) { /*********************************************************************** - pj_calloc is the pj-equivalent of calloc(). It allocates space for an array of <n> elements of size <size>. The array is initialized to zeros. - ***********************************************************************/ void *res = pj_malloc (n*size); if (0==res) @@ -86,9 +99,15 @@ The array is initialized to zeros. /**********************************************************************/ +void pj_dalloc(void *ptr) { +/**********************************************************************/ + free(ptr); +} + + +/**********************************************************************/ void *pj_dealloc (void *ptr) { /*********************************************************************** - pj_dealloc supports the common use case of "clean up and return a null pointer" to signal an error in a multi level allocation: @@ -113,64 +132,59 @@ pointer" to signal an error in a multi level allocation: +/*****************************************************************************/ +void *pj_dealloc_params (projCtx ctx, paralist *start, int errlev) { +/***************************************************************************** + Companion to pj_default_destructor (below). Deallocates a linked list + of "+proj=xxx" initialization parameters. + + Also called from pj_init_ctx when encountering errors before the PJ + proper is allocated. +******************************************************************************/ + paralist *t, *n; + for (t = start; t; t = n) { + n = t->next; + pj_dealloc(t); + } + pj_ctx_set_errno (ctx, errlev); + return (void *) 0; +} + /*****************************************************************************/ -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 - allocated memory. + allocated memory below the P->opaque level. ******************************************************************************/ - if (0==P) - return 0; + /* Even if P==0, we set the errlev on pj_error and the default context */ + /* Note that both, in the multithreaded case, may then contain undefined */ + /* values. This is expected behaviour. For MT have one ctx per thread */ if (0!=errlev) - pj_ctx_set_errno (P->ctx, errlev); + pj_ctx_set_errno (pj_get_ctx(P), errlev); - if (0==P->opaque) - return pj_dealloc (P); + if (0==P) + return 0; + + /* 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 */ + /* pj_gc_unloadall(pj_get_default_ctx()); and pj_deallocate_grids(); */ + /* TODO: we should probably have a public pj_cleanup() method to do all */ + /* that */ + + /* free the interface to Charles Karney's geodesic library */ + pj_dealloc( P->geod ); + + /* free parameter list elements */ + pj_dealloc_params (pj_get_ctx(P), P->params, errlev); 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_mlfn.c b/src/pj_mlfn.c index 2b823026..e00f2bf1 100644 --- a/src/pj_mlfn.c +++ b/src/pj_mlfn.c @@ -19,19 +19,23 @@ #define EPS 1e-11 #define MAX_ITER 10 #define EN_SIZE 5 - double * -pj_enfn(double es) { - double t, *en; - if ((en = (double *)pj_malloc(EN_SIZE * sizeof(double))) != NULL) { - en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08))); - en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08))); - en[2] = (t = es * es) * (C44 - es * (C46 + es * C48)); - en[3] = (t *= es) * (C66 - es * C68); - en[4] = t * es * C88; - } /* else return NULL if unable to allocate memory */ - return en; +double *pj_enfn(double es) { + double t, *en; + + en = (double *) pj_malloc(EN_SIZE * sizeof (double)); + if (0==en) + return 0; + + en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08))); + en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08))); + en[2] = (t = es * es) * (C44 - es * (C46 + es * C48)); + en[3] = (t *= es) * (C66 - es * C68); + en[4] = t * es * C88; + + return en; } + double pj_mlfn(double phi, double sphi, double cphi, double *en) { cphi *= sphi; diff --git a/src/pj_obs_api.c b/src/pj_obs_api.c index b2929a07..9f699fcf 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 <proj.h> #include "proj_internal.h" #include "projects.h" -#include <geodesic.h> +#include "geodesic.h" #include <stddef.h> #include <errno.h> @@ -69,8 +69,8 @@ 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) { +/* Geodesic distance (in meter) between two points with angular 2D coordinates */ +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); @@ -90,9 +90,10 @@ 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_COORD coo) { int i; - PJ_OBS o, u; + PJ_COORD o, u; + enum pj_io_units unit; if (0==P) return HUGE_VAL; @@ -102,30 +103,48 @@ double proj_roundtrip (PJ *P, enum proj_direction direction, int n, PJ_OBS obs) return HUGE_VAL; } - o.coo = obs.coo; - - for (i = 0; i < n; i++) { - switch (direction) { - case PJ_FWD: - u = pj_fwdobs (o, P); - o = pj_invobs (u, P); - break; - case PJ_INV: - u = pj_invobs (o, P); - o = pj_fwdobs (u, P); - break; - default: - proj_errno_set (P, EINVAL); - return HUGE_VAL; - } + o = coo; + + switch (direction) { + case PJ_FWD: + for (i = 0; i < n; i++) { + u = pj_fwdcoord (o, P); + o = pj_invcoord (u, P); + } + break; + case PJ_INV: + for (i = 0; i < n; i++) { + u = pj_invcoord (o, P); + o = pj_fwdcoord (u, P); + } + break; + default: + proj_errno_set (P, EINVAL); + return HUGE_VAL; } - return proj_xyz_dist (o.coo.xyz, obs.coo.xyz); + /* left when forward, because we do a roundtrip, and end where we begin */ + unit = direction==PJ_FWD? P->left: P->right; + if (unit==PJ_IO_UNITS_RADIANS) + return hypot (proj_lp_dist (P, coo.lp, o.lp), coo.lpz.z - o.lpz.z); + + return proj_xyz_dist (coo.xyz, coo.xyz); } + + + + + + + + + + + /* 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 +166,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 +190,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 +338,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 +356,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. @@ -407,34 +426,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 +459,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 +478,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; @@ -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; } @@ -582,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. @@ -594,6 +595,11 @@ PJ_PROJ_INFO proj_pj_info(const 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; } @@ -606,7 +612,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); @@ -729,7 +735,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. @@ -739,8 +745,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, P, &derivs)) { /* errno set in pj_derivs */ memset(&derivs, 0, sizeof(PJ_DERIVS)); } @@ -750,7 +755,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,8 +771,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, P, 0.0, &factors)) { /* errno set in pj_factors */ memset(&factors, 0, sizeof(PJ_FACTORS)); } @@ -776,6 +780,22 @@ PJ_FACTORS proj_factors(const PJ *P, const LP lp) { } +const PJ_ELLPS *proj_list_ellps(void) { + return pj_get_ellps_ref(); +} + +const PJ_UNITS *proj_list_units(void) { + return pj_get_units_ref(); +} + +const PJ_OPERATIONS *proj_list_operations(void) { + return pj_get_list_ref(); +} + +const PJ_PRIME_MERIDIANS *proj_list_prime_meridians(void) { + return pj_get_prime_meridians_ref(); +} + double proj_torad (double angle_in_degrees) { return PJ_TORAD (angle_in_degrees);} double proj_todeg (double angle_in_radians) { return PJ_TODEG (angle_in_radians);} @@ -787,5 +807,3 @@ double proj_dmstor(const char *is, char **rs) { char* proj_rtodms(char *s, double r, int pos, int neg) { return rtodms(s, r, pos, neg); } - - diff --git a/src/pj_run_selftests.c b/src/pj_run_selftests.c index 87aee76d..90193af8 100644 --- a/src/pj_run_selftests.c +++ b/src/pj_run_selftests.c @@ -40,7 +40,8 @@ int pj_run_selftests (int verbosity) { static void run_one_test (const char *mnemonic, int (testfunc)(void), int verbosity, int *n_ok, int *n_ko, int *n_stubs) { - int ret = testfunc (); + int ret; + ret = testfunc (); switch (ret) { case 0: (*n_ok)++; break; case 10000: (*n_stubs)++; break; diff --git a/src/pj_strerrno.c b/src/pj_strerrno.c index 74a7eea0..89a5a025 100644 --- a/src/pj_strerrno.c +++ b/src/pj_strerrno.c @@ -61,30 +61,36 @@ pj_err_list[] = { "non-convergent computation", /* -53 */ "missing required arguments", /* -54 */ "lat_0 = 0", /* -55 */ + "ellipsoidal usage unsupported", /* -56 */ + + /* When adding error messages, remember to update ID defines in + projects.h, and transient_error array in pj_transform */ }; char *pj_strerrno(int err) { static char note[50]; + size_t adjusted_err; if (0==err) return 0; + /* System error codes are positive */ if (err > 0) { #ifdef HAVE_STRERROR return strerror(err); #else - sprintf(note,"no system list, errno: %d\n", err); + /* Defend string boundary against exorbitantly large err values */ + /* which may occur on platforms with 64-bit ints */ + sprintf(note,"no system list, errno: %d\n", (err < 9999)? err: 9999); return note; #endif } - else /*if (err < 0)*/ { - size_t adjusted_err = - err - 1; - if (adjusted_err < (sizeof(pj_err_list) / sizeof(char *))) - return(pj_err_list[adjusted_err]); - else { - sprintf( note, "invalid projection system error (%d)", err ); - return note; - } - } + /* PROJ.4 error codes are negative */ + adjusted_err = - err - 1; + if (adjusted_err < (sizeof(pj_err_list) / sizeof(char *))) + return(pj_err_list[adjusted_err]); + + sprintf( note, "invalid projection system error (%d)", (err > -9999)? err: -9999); + return note; } diff --git a/src/pj_transform.c b/src/pj_transform.c index a842ba72..9f532188 100644 --- a/src/pj_transform.c +++ b/src/pj_transform.c @@ -54,22 +54,32 @@ static int pj_adjust_axis( projCtx ctx, const char *axis, int denormalize_flag, /* ** This table is intended to indicate for any given error code in -** the range 0 to -44, whether that error will occur for all locations (ie. +** the range 0 to -56, whether that error will occur for all locations (ie. ** it is a problem with the coordinate system as a whole) in which case the ** value would be 0, or if the problem is with the point being transformed ** in which case the value is 1. ** ** At some point we might want to move this array in with the error message ** list or something, but while experimenting with it this should be fine. +** +** +** NOTE (2017-10-01): Non-transient errors really should have resulted in a +** PJ==0 during initialization, and hence should be handled at the level +** before calling pj_transform. The only obvious example of the contrary +** appears to be the PJD_ERR_GRID_AREA case, which may also be taken to +** mean "no grids available" +** +** */ -static const int transient_error[50] = { +static const int transient_error[60] = { /* 0 1 2 3 4 5 6 7 8 9 */ /* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; + /* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + /* 50 to 59 */ 1, 0, 1, 0, 1, 1, 1, 0, 0, 0 }; /************************************************************************/ /* pj_transform() */ @@ -21,243 +21,288 @@ 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); + +/* 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, scale if warranted by output units */ + if (inverse) { + if (Proj->left == PJ_IO_UNITS_RADIANS) { + data.v *= RAD_TO_DEG; + data.u *= RAD_TO_DEG; } - (void)fputs(bin_in ? "\n" : s, stdout); - } + } else { + if (Proj->right == PJ_IO_UNITS_RADIANS) { + 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; } + } + + /* 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()) { + 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 +318,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 +505,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 +524,7 @@ int main(int argc, char **argv) { } } } + if (inverse) informat = strtod; else { @@ -485,8 +533,7 @@ int main(int argc, char **argv) { oform = "%.2f"; } - if (bin_out) - { + if (bin_out) { SET_BINARY_MODE(stdout); } @@ -516,7 +563,9 @@ int main(int argc, char **argv) { (void)fclose(fid); emess_dat.File_name = 0; } + if( Proj ) pj_free(Proj); + exit(0); /* normal completion */ } diff --git a/src/proj.def b/src/proj.def index 12816f1c..598f2824 100644 --- a/src/proj.def +++ b/src/proj.def @@ -143,3 +143,7 @@ EXPORTS proj_derivatives @130 proj_factors @131 + proj_list_operations @132 + proj_list_ellps @133 + proj_list_units @134 + proj_list_prime_meridians @135 @@ -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; @@ -205,6 +205,23 @@ typedef struct PJ_GRID_INFO PJ_GRID_INFO; struct PJ_INIT_INFO; typedef struct PJ_INIT_INFO PJ_INIT_INFO; +/* Data types for list of operations, ellipsoids, datums and units used in PROJ.4 */ +struct PJ_LIST; +typedef struct PJ_LIST PJ_OPERATIONS; + +struct PJ_ELLPS; +typedef struct PJ_ELLPS PJ_ELLPS; + +struct PJ_DATUMS; +typedef struct PJ_DATUMS PJ_DATUMS; + +struct PJ_UNITS; +typedef struct PJ_UNITS PJ_UNITS; + +struct PJ_PRIME_MERIDIANS; +typedef struct PJ_PRIME_MERIDIANS PJ_PRIME_MERIDIANS; + + /* Omega, Phi, Kappa: Rotations */ typedef struct {double o, p, k;} PJ_OPK; @@ -288,22 +305,10 @@ 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 */ +#define PJ_IS_ANAL_CONV 010 /* convergence analytic */ struct PJ_INFO { char release[64]; /* Release info. Version + date */ @@ -317,10 +322,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 { @@ -351,8 +357,10 @@ 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); + /* Manage the transformation definition object PJ */ @@ -363,38 +371,38 @@ 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_COORD coo); + /* 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); @@ -410,15 +418,21 @@ 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); +/* List functions: */ +/* Get lists of operations, ellipsoids, units and prime meridians. */ +const PJ_OPERATIONS *proj_list_operations(void); +const PJ_ELLPS *proj_list_ellps(void); +const PJ_UNITS *proj_list_units(void); +const PJ_PRIME_MERIDIANS *proj_list_prime_meridians(void); /* These are trivial, and while occasionaly useful in real code, primarily here to */ /* simplify demo code, and in acknowledgement of the proj-internal discrepancy between */ diff --git a/src/proj_etmerc.c b/src/proj_etmerc.c index ff466ea8..a756a7ac 100644 --- a/src/proj_etmerc.c +++ b/src/proj_etmerc.c @@ -42,6 +42,7 @@ #define PROJ_LIB__ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -232,28 +233,12 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } - -static void *freeup_new (PJ *P) { /* Destructor */ - if (0==P) - return 0; - if (0==P->opaque) - return pj_dealloc (P); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} - -static void freeup (PJ *P) { - freeup_new (P); - return; -} - static PJ *setup(PJ *P) { /* general initialization */ double f, n, np, Z; struct pj_opaque *Q = P->opaque; if (P->es <= 0) { - proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); } /* flattening */ @@ -340,7 +325,7 @@ static PJ *setup(PJ *P) { /* general initialization */ PJ *PROJECTION(etmerc) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; return setup (P); } @@ -411,12 +396,12 @@ PJ *PROJECTION(utm) { int zone; struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor (P, ENOMEM); P->opaque = Q; if (P->es == 0.0) { proj_errno_set(P, PJD_ERR_ELLIPSOID_USE_REQUIRED); - return freeup_new(P); + return pj_default_destructor(P, ENOMEM); } P->y0 = pj_param (P->ctx, P->params, "bsouth").i ? 10000000. : 0.; P->x0 = 500000.; @@ -426,8 +411,7 @@ PJ *PROJECTION(utm) { if (zone > 0 && zone <= 60) --zone; else { - proj_errno_set(P, PJD_ERR_INVALID_UTM_ZONE); - return freeup_new(P); + return pj_default_destructor(P, PJD_ERR_INVALID_UTM_ZONE); } } else /* nearest central meridian input */ diff --git a/src/proj_rouss.c b/src/proj_rouss.c index b33e7926..952e5c55 100644 --- a/src/proj_rouss.c +++ b/src/proj_rouss.c @@ -24,6 +24,7 @@ ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define PJ_LIB__ +#include <errno.h> #include <proj.h> #include "projects.h" @@ -79,21 +80,17 @@ static LP e_inverse (XY xy, PJ *P) { /* Ellipsoidal, inverse */ } -static void *freeup_new (PJ *P) { /* Destructor */ +static void *destructor (PJ *P, int errlev) { if (0==P) return 0; + if (0==P->opaque) - return pj_dealloc (P); + return pj_default_destructor (P, errlev); if (P->opaque->en) pj_dealloc (P->opaque->en); - pj_dealloc (P->opaque); - return pj_dealloc(P); -} -static void freeup (PJ *P) { - freeup_new (P); - return; + return pj_default_destructor (P, ENOMEM); } @@ -102,11 +99,12 @@ PJ *PROJECTION(rouss) { struct pj_opaque *Q = pj_calloc (1, sizeof (struct pj_opaque)); if (0==Q) - return freeup_new (P); + return pj_default_destructor(P, ENOMEM); P->opaque = Q; if (!((Q->en = proj_mdist_ini(P->es)))) - return freeup_new(P); + return pj_default_destructor (P, ENOMEM); + es2 = sin(P->phi0); Q->s0 = proj_mdist(P->phi0, es2, cos(P->phi0), Q->en); t = 1. - (es2 = P->es * es2 * es2); @@ -149,6 +147,7 @@ PJ *PROJECTION(rouss) { P->fwd = e_forward; P->inv = e_inverse; + P->destructor = destructor; return P; } diff --git a/src/proj_strtod.c b/src/proj_strtod.c new file mode 100644 index 00000000..e9942e5c --- /dev/null +++ b/src/proj_strtod.c @@ -0,0 +1,251 @@ +/*********************************************************************** + + proj_strtod: Convert string to double, accepting underscore separators + + Thomas Knudsen, 2017-01-17/09-19 + +************************************************************************ + +Conventionally, PROJ.4 does not honor locale settings, consistently +behaving as if LC_ALL=C. + +For this to work, we have, for many years, been using other solutions +than the C standard library strtod/atof functions for converting strings +to doubles. + +In the early versions of proj, iirc, a gnu version of strtod was used, +mostly to work around cases where the same system library was used for +C and Fortran linking, hence making strtod accept "D" and "d" as +exponentiation indicators, following Fortran Double Precision constant +syntax. This broke the proj angular syntax accepting a "d" to mean +"degree": 12d34'56", meaning 12 degrees 34 minutes and 56 seconds. + +With an explicit MIT licence, PROJ.4 could not include GPL code any +longer, and apparently at some time, the GPL code was replaced by the +current C port of a GDAL function (in pj_strtod.c), which reads the +LC_NUMERIC setting and, behind the back of the user, momentarily changes +the conventional '.' delimiter to whatever the locale requires, then +calls the system supplied strtod. + +While this requires a minimum amount of coding, it only solves one +problem, and not in a very generic way. + +Another problem, I would like to see solved, is the handling of underscores +as generic delimiters. This is getting popular in a number of programming +languages (Ada, C++, C#, D, Java, Julia, Perl 5, Python, Rust, etc. +cf. e.g. https://www.python.org/dev/peps/pep-0515/), and in our case of +handling numbers being in the order of magnitude of the Earth's dimensions, +and a resolution of submillimetre, i.e. having 10 or more significant digits, +splitting the "wall of digits" into smaller chunks is of immense value. + +Hence this reimplementation of strtod, which hardcodes '.' as indicator of +numeric fractions, and accepts '_' anywhere in a numerical string sequence: +So a typical northing value can be written + + 6_098_907.8250 m +rather than + 6098907.8250 m + +which, in my humble opinion, is well worth the effort. + +While writing this code, I took ample inspiration from Michael Ringgaard's +strtod version over at http://www.jbox.dk/sanos/source/lib/strtod.c.html, +and Yasuhiro Matsumoto's public domain version over at +https://gist.github.com/mattn/1890186. The code below is, however, not +copied from any of the two mentioned - it is a reimplementation, and +probably suffers from its own set of bugs. So for now, it is intended +not as a replacement of pj_strtod, but only as an experimental piece of +code for use in an experimental new transformation program, cct. + +************************************************************************ + +Thomas Knudsen, thokn@sdfe.dk, 2017-01-17/2017-09-18 + +************************************************************************ + +* Copyright (c) 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"), +* 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 <errno.h> +#include <ctype.h> +#include <float.h> /* for HUGE_VAL */ +#include <math.h> /* for pow() */ + +double proj_strtod(const char *str, char **endptr); +double proj_atof(const char *str); + + +double proj_strtod(const char *str, char **endptr) { + double number = 0; + int exponent = 0; + int sign = 0; + char *p = (char *) str; + int n = 0; + int num_digits_total = 0; + int num_digits_after_comma = 0; + + if (0==str) { + errno = EFAULT; + if (endptr) + *endptr = p; + return HUGE_VAL; + } + + /* First skip leading whitespace */ + while (isspace(*p)) + p++; + + /* Empty string? */ + if (0==*p) { + errno = EINVAL; + if (endptr) + *endptr = p; + return HUGE_VAL; + } + + /* Then handle optional prefixed sign */ + switch (*p) { + case '-': + sign = -1, p++; break; + case '+': + sign = 1, p++; break; + default: + if (isdigit(*p) || '_'==*p || '.'==*p) + break; + if (endptr) + *endptr = p; + errno = EINVAL; + return HUGE_VAL; + } + + /* Now expect a (potentially zero-length) string of digits */ + while (isdigit(*p) || ('_'==*p)) { + if ('_'==*p) { + p++; + continue; + } + number = number * 10. + (*p - '0'); + p++; + num_digits_total++; + } + + /* Do we have a fractional part? */ + if ('.'==*p) { + p++; + + while (isdigit(*p) || '_'==*p) { + if ('_'==*p) { + p++; + continue; + } + number = number * 10. + (*p - '0'); + p++; + num_digits_total++; + num_digits_after_comma++; + } + + exponent = -num_digits_after_comma; + } + + /* non-digit */ + if (0==num_digits_total) { + errno = EINVAL; + if (endptr) + *endptr = p; + return HUGE_VAL; + } + + if (sign==-1) + number = -number; + + /* Do we have an exponent part? */ + if (*p == 'e' || *p == 'E') { + p++; + /* Does it have a sign? */ + sign = 0; + if ('-'==*p) + sign = -1; + if ('+'==*p) + sign = +1; + if (0==sign) { + if (!isdigit(*p) && *p!='_') { + if (endptr) + *endptr = p; + return HUGE_VAL; + } + } + else + p++; + + + /* Go on and read the exponent */ + n = 0; + while (isdigit(*p) || '_'==*p) { + if ('_'==*p) { + p++; + continue; + } + n = n * 10 + (*p - '0'); + p++; + } + + if (-1==sign) + n = -n; + exponent += n; + } + + if ((exponent < DBL_MIN_EXP) || (exponent > DBL_MAX_EXP)) { + errno = ERANGE; + if (endptr) + *endptr = p; + return HUGE_VAL; + } + + number *= pow (10, exponent); + + if (fabs(number) > DBL_MAX) + errno = ERANGE; + + if (endptr) + *endptr = p; + + return number; +} + +double proj_atof(const char *str) { + return proj_strtod(str, (void *) 0); +} + +#ifdef TEST +#include <string.h> + +int main (int argc, char **argv) { + double res; + char *endptr; + if (argc < 2) + return 0; + res = proj_strtod (argv[1], &endptr); + printf ("res = %20.15g. Rest = [%s], errno = %d\n", res, endptr, (int) errno); + return 0; +} +#endif diff --git a/src/projects.h b/src/projects.h index 872bf816..9391835d 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); + /************************************************************************************* @@ -386,7 +332,7 @@ struct PJconsts { **************************************************************************************/ double lam0, phi0; /* central longitude, latitude */ - double x0, y0; /* false easting and northing */ + double x0, y0, z0, t0; /* false easting and northing (and height and time) */ /************************************************************************************* @@ -524,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 @@ -536,24 +499,32 @@ 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 #define PJD_ERR_LAT_0_IS_ZERO -55 +#define PJD_ERR_ELLIPSOIDAL_UNSUPPORTED -56 struct projFileAPI_t; @@ -616,8 +587,10 @@ 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; \ + P->left = PJ_IO_UNITS_RADIANS; \ + P->right = PJ_IO_UNITS_CLASSIC; \ return P; \ } \ PJ *pj_projection_specific_setup_##name (PJ *P) @@ -707,12 +680,12 @@ 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); paralist *pj_get_init(projCtx ctx, paralist **start, paralist *next, char *name, int *found_def); +void *pj_dealloc_params (projCtx ctx, paralist *start, int errlev); + double *pj_enfn(double); double pj_mlfn(double, double, double, double *); @@ -822,6 +795,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); diff --git a/src/test228.c b/src/test228.c index 1f3d04e8..94f0ec08 100644 --- a/src/test228.c +++ b/src/test228.c @@ -54,6 +54,8 @@ static void* thread_main(void* unused) assert(fabs(y - 49.999396034285531698) < 1e-15); } + pj_free (p_OSGB36_proj); + pj_free (p_WGS84_proj); return NULL; } diff --git a/travis/before_install.sh b/travis/before_install.sh index 8a4bbd24..249cb591 100755 --- a/travis/before_install.sh +++ b/travis/before_install.sh @@ -1,6 +1,20 @@ #!/bin/bash -pip install --user cpp-coveralls -./travis/docker.sh +# All platform-specific before_install scripts starts by running this +# "global" before_install script. +# Specify which version of python to use. The default python to use on Travis +# can vary from platform to platform, so we use pyenv to make sure we use +# a version that works for the complete build processs. (Not in use at the moment, +# since the pyenv setup on Travis is not consistent across platforms and partly +# broken as well) +#pyenv global system 3.5 +#pyenv versions # a bit of debug info +# What is the current python setup? +which python +python --version +python3 --version + +which pip +pip --version diff --git a/travis/install.sh b/travis/install.sh index 70b8e90d..51a8ea2f 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -84,7 +84,6 @@ PROJ_LIB=$GRIDDIR ./src/proj -VC # install & run the working GIGS test # create locations that pyproj understands -python3 --version ln -s src include ln -s src/.libs lib mkdir share @@ -92,12 +91,12 @@ ln -s nad share/proj pwd # install pyproj export CFLAGS= -PROJ_DIR=`pwd` pip3 install -v --user pyproj +PROJ_DIR=`pwd` pip install -v --user pyproj cd test/gigs # run test_json.py -PROJ_LIB=../../nad python3 test_json.py --test conversion 5101.1-jhs.json 5101.4-jhs-etmerc.json 5105.2.json 5106.json 5108.json 5110.json 5111.1.json -PROJ_LIB=../../nad python3 test_json.py 5101.2-jhs.json 5101.3-jhs.json 5102.1.json 5103.1.json 5103.2.json 5103.3.json 5107.json 5109.json 5112.json 5113.json 5201.json 5208.json +PROJ_LIB=../../nad python test_json.py --test conversion 5101.1-jhs.json 5101.4-jhs-etmerc.json 5105.2.json 5106.json 5108.json 5110.json 5111.1.json +PROJ_LIB=../../nad python test_json.py 5101.2-jhs.json 5101.3-jhs.json 5102.1.json 5103.1.json 5103.2.json 5103.3.json 5107.json 5109.json 5112.json 5113.json 5201.json 5208.json cd ../.. mv src/.libs/*.gc* src diff --git a/travis/linux_clang/before_install.sh b/travis/linux_clang/before_install.sh index 75acd97a..f6e21076 100755 --- a/travis/linux_clang/before_install.sh +++ b/travis/linux_clang/before_install.sh @@ -2,4 +2,5 @@ set -e +./travis/before_install.sh # do nothing diff --git a/travis/linux_clang/install.sh b/travis/linux_clang/install.sh index 56e16ce6..a0dd9353 100755 --- a/travis/linux_clang/install.sh +++ b/travis/linux_clang/install.sh @@ -4,4 +4,4 @@ set -e export CCACHE_CPP2=yes -CC="ccache clang" CFLAGS="-g -Wall -Wextra -Werror -Wunused-parameter -Wmissing-prototypes -Wmissing-declarations -Wformat -Werror=format-security -Wshadow -Wfloat-conversion -O2" ./travis/install.sh +CC="ccache clang" CFLAGS="-g -Wall -Wextra -Werror -Wunused-parameter -Wmissing-prototypes -Wmissing-declarations -Wformat -Werror=format-security -Wshadow -Wfloat-conversion -fsanitize=address -O2" ./travis/install.sh diff --git a/travis/linux_gcc/before_install.sh b/travis/linux_gcc/before_install.sh index 31805e80..0c37643c 100755 --- a/travis/linux_gcc/before_install.sh +++ b/travis/linux_gcc/before_install.sh @@ -1,5 +1,7 @@ #!/bin/bash +./travis/before_install.sh + sudo apt-get install -y cppcheck cppcheck --inline-suppr --template='{file}:{line},{severity},{id},{message}' --enable=all --inconclusive --std=posix -DPJ_SELFTEST=1 src/*.c 2>/tmp/cppcheck.txt @@ -12,4 +14,6 @@ fi set -e -./travis/before_install.sh +pip install --user cpp-coveralls +./travis/docker.sh + diff --git a/travis/mingw32/before_install.sh b/travis/mingw32/before_install.sh index 18949b75..5cadb761 100755 --- a/travis/mingw32/before_install.sh +++ b/travis/mingw32/before_install.sh @@ -2,6 +2,8 @@ set -e +./travis/before_install.sh + sudo apt-get update -qq sudo apt-get install -qq wine sudo apt-get install -qq mingw32 diff --git a/travis/osx/before_install.sh b/travis/osx/before_install.sh index cd553dda..4ca62084 100755 --- a/travis/osx/before_install.sh +++ b/travis/osx/before_install.sh @@ -2,5 +2,7 @@ set -e +./travis/before_install.sh + brew install ccache brew install python3 |
