diff options
Diffstat (limited to 'src')
144 files changed, 3398 insertions, 5244 deletions
diff --git a/src/4D_api.cpp b/src/4D_api.cpp index 86c0e071..d6eb901d 100644 --- a/src/4D_api.cpp +++ b/src/4D_api.cpp @@ -778,14 +778,14 @@ PJ *pj_create_internal (PJ_CONTEXT *ctx, const char *definition) { argc = pj_trim_argc (args); if (argc==0) { - pj_dealloc (args); + free (args); proj_context_errno_set(ctx, PJD_ERR_NO_ARGS); return nullptr; } argv = pj_trim_argv (argc, args); if (!argv) { - pj_dealloc(args); + free(args); proj_context_errno_set(ctx, ENOMEM); return nullptr; } @@ -795,8 +795,8 @@ PJ *pj_create_internal (PJ_CONTEXT *ctx, const char *definition) { allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, FALSE); P = pj_init_ctx_with_allow_init_epsg (ctx, (int) argc, argv, allow_init_epsg); - pj_dealloc (argv); - pj_dealloc (args); + free (argv); + free (args); /* Support cs2cs-style modifiers */ ret = cs2cs_emulation_setup (P); @@ -834,7 +834,7 @@ indicator, as in {"+proj=utm", "+zone=32"}, or leave it out, as in {"proj=utm", P = proj_create (ctx, c); - pj_dealloc ((char *) c); + free ((char *) c); return P; } @@ -862,13 +862,13 @@ Same as proj_create_argv() but calls pj_create_internal() instead of proj_create P = pj_create_internal (ctx, c); - pj_dealloc ((char *) c); + free ((char *) c); return P; } /** Create an area of use */ PJ_AREA * proj_area_create(void) { - return static_cast<PJ_AREA*>(pj_calloc(1, sizeof(PJ_AREA))); + return static_cast<PJ_AREA*>(calloc(1, sizeof(PJ_AREA))); } /** Assign a bounding box to an area of use. */ @@ -886,7 +886,7 @@ void proj_area_set_bbox(PJ_AREA *area, /** Free an area of use */ void proj_area_destroy(PJ_AREA* area) { - pj_dealloc(area); + free(area); } /************************************************************************/ @@ -1260,8 +1260,20 @@ std::vector<CoordOperation> pj_create_prepared_operations(PJ_CONTEXT *ctx, } } +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +static const char *getOptionValue(const char *option, + const char *keyWithEqual) noexcept { + if (ci_starts_with(option, keyWithEqual)) { + return option + strlen(keyWithEqual); + } + return nullptr; +} +//! @endcond + /*****************************************************************************/ -PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, const PJ *target_crs, PJ_AREA *area, const char* const *) { +PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, const PJ *target_crs, PJ_AREA *area, const char* const * options) { /****************************************************************************** Create a transformation pipeline between two known coordinate reference systems. @@ -1273,7 +1285,20 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons ctx = pj_get_default_ctx(); } - auto operation_ctx = proj_create_operation_factory_context(ctx, nullptr); + const char* authority = nullptr; + for (auto iter = options; iter && iter[0]; ++iter) { + const char *value; + if ((value = getOptionValue(*iter, "AUTHORITY="))) { + authority = value; + } else { + std::string msg("Unknown option :"); + msg += *iter; + ctx->logger(ctx->logger_app_data, PJ_LOG_ERROR, msg.c_str()); + return nullptr; + } + } + + auto operation_ctx = proj_create_operation_factory_context(ctx, authority); if( !operation_ctx ) { return nullptr; } @@ -1287,9 +1312,11 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons area->east_lon_degree, area->north_lat_degree); } + else { + proj_operation_factory_context_set_spatial_criterion( + ctx, operation_ctx, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION); + } - proj_operation_factory_context_set_spatial_criterion( - ctx, operation_ctx, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION); proj_operation_factory_context_set_grid_availability_use( ctx, operation_ctx, proj_context_is_network_enabled(ctx) ? @@ -1353,17 +1380,13 @@ PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, const PJ *source_crs, cons return P; } -PJ *proj_destroy (PJ *P) { - pj_free (P); - return nullptr; -} /*****************************************************************************/ int proj_errno (const PJ *P) { /****************************************************************************** Read an error level from the context of a PJ. ******************************************************************************/ - return pj_ctx_get_errno (pj_get_ctx ((PJ *) P)); + return proj_context_errno (pj_get_ctx ((PJ *) P)); } /*****************************************************************************/ @@ -1374,7 +1397,7 @@ int proj_context_errno (PJ_CONTEXT *ctx) { ******************************************************************************/ if (nullptr==ctx) ctx = pj_get_default_ctx(); - return pj_ctx_get_errno (ctx); + return ctx->last_errno; } /*****************************************************************************/ @@ -1389,6 +1412,7 @@ int proj_errno_set (const PJ *P, int err) { /* For P==0 err goes to the default context */ proj_context_errno_set (pj_get_ctx ((PJ *) P), err); errno = err; + return err; } @@ -1439,16 +1463,15 @@ int proj_errno_reset (const PJ *P) { int last_errno; last_errno = proj_errno (P); - pj_ctx_set_errno (pj_get_ctx ((PJ *) P), 0); + proj_context_errno_set (pj_get_ctx ((PJ *) P), 0); errno = 0; - pj_errno = 0; return last_errno; } /* Create a new context based on the default context */ PJ_CONTEXT *proj_context_create (void) { - return pj_ctx_alloc (); + return new (std::nothrow) pj_ctx(*pj_get_default_ctx()); } @@ -1460,7 +1483,7 @@ PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx) { if (pj_get_default_ctx ()==ctx) return nullptr; - pj_ctx_free (ctx); + delete ctx; return nullptr; } @@ -1499,15 +1522,15 @@ static char *path_append (char *buf, const char *app, size_t *buf_size) { /* "pj_realloc", so to speak */ if (*buf_size < len) { - p = static_cast<char*>(pj_calloc (2 * len, sizeof (char))); + p = static_cast<char*>(calloc (2 * len, sizeof (char))); if (nullptr==p) { - pj_dealloc (buf); + free (buf); return nullptr; } *buf_size = 2 * len; if (buf != nullptr) strcpy (p, buf); - pj_dealloc (buf); + free (buf); buf = p; } assert(buf); @@ -1560,7 +1583,7 @@ PJ_INFO proj_info (void) { } } - pj_dalloc(const_cast<char*>(info.searchpath)); + free(const_cast<char*>(info.searchpath)); info.searchpath = buf ? buf : empty; info.paths = ctx ? ctx->c_compat_paths : nullptr; @@ -1635,7 +1658,7 @@ PJ_PROJ_INFO proj_pj_info(PJ *P) { pjinfo.definition = empty; else pjinfo.definition = pj_shrink (def); - /* Make pj_free clean this up eventually */ + /* Make proj_destroy clean this up eventually */ P->def_full = def; pjinfo.has_inverse = pj_has_inverse(P); @@ -1746,7 +1769,7 @@ PJ_INIT_INFO proj_init_info(const char *initname){ if( strcmp(initname, "epsg") == 0 || strcmp(initname, "EPSG") == 0 ) { const char* val; - pj_ctx_set_errno( ctx, 0 ); + proj_context_errno_set( ctx, 0 ); strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); strcpy(ininfo.origin, "EPSG"); @@ -1764,7 +1787,7 @@ PJ_INIT_INFO proj_init_info(const char *initname){ if( strcmp(initname, "IGNF") == 0 ) { const char* val; - pj_ctx_set_errno( ctx, 0 ); + proj_context_errno_set( ctx, 0 ); strncpy (ininfo.name, initname, sizeof(ininfo.name) - 1); strcpy(ininfo.origin, "IGNF"); @@ -1809,7 +1832,7 @@ PJ_INIT_INFO proj_init_info(const char *initname){ for ( ; start; start = next) { next = start->next; - pj_dalloc(start); + free(start); } return ininfo; diff --git a/src/Makefile.am b/src/Makefile.am index 5b36c8bd..83ee4adc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ AM_CFLAGS = @C_WFLAGS@ -EXTRA_PROGRAMS = multistresstest test228 +EXTRA_PROGRAMS = multistresstest TESTS = geodtest check_PROGRAMS = geodtest @@ -9,7 +9,7 @@ AM_CPPFLAGS = -DPROJ_LIB=\"$(pkgdatadir)\" \ -DMUTEX_@MUTEX_SETTING@ -I$(top_srcdir)/include @SQLITE3_CFLAGS@ @TIFF_CFLAGS@ @TIFF_ENABLED_FLAGS@ @CURL_CFLAGS@ @CURL_ENABLED_FLAGS@ AM_CXXFLAGS = @CXX_WFLAGS@ @FLTO_FLAG@ -include_HEADERS = proj.h proj_experimental.h proj_constants.h proj_api.h geodesic.h \ +include_HEADERS = proj.h proj_experimental.h proj_constants.h geodesic.h \ proj_symbol_rename.h EXTRA_DIST = bin_cct.cmake bin_gie.cmake bin_cs2cs.cmake \ @@ -36,7 +36,6 @@ bin_PROGRAMS = proj geod cs2cs gie cct projinfo $(PROJSYNC_BIN) gie_SOURCES = apps/gie.cpp apps/proj_strtod.cpp apps/proj_strtod.h apps/optargpm.h multistresstest_SOURCES = tests/multistresstest.cpp -test228_SOURCES = tests/test228.cpp geodtest_SOURCES = tests/geodtest.cpp cct_LDADD = libproj.la @@ -47,7 +46,6 @@ projinfo_LDADD = libproj.la gie_LDADD = libproj.la multistresstest_LDADD = libproj.la @THREAD_LIB@ -test228_LDADD = libproj.la @THREAD_LIB@ geodtest_LDADD = libproj.la lib_LTLIBRARIES = libproj.la @@ -187,6 +185,7 @@ libproj_la_SOURCES = \ conversions/geoc.cpp \ conversions/geocent.cpp \ conversions/noop.cpp \ + conversions/topocentric.cpp \ conversions/set.cpp \ conversions/unitconvert.cpp \ \ @@ -209,19 +208,17 @@ libproj_la_SOURCES = \ \ aasincos.cpp adjlon.cpp \ dmstor.cpp auth.cpp \ - deriv.cpp ell_set.cpp ellps.cpp errno.cpp \ + deriv.cpp ell_set.cpp ellps.cpp \ factors.cpp fwd.cpp init.cpp inv.cpp \ list.cpp malloc.cpp mlfn.cpp mlfn.hpp msfn.cpp proj_mdist.cpp \ param.cpp phi2.cpp pr_list.cpp \ qsfn.cpp strerrno.cpp \ tsfn.cpp units.cpp ctx.cpp log.cpp zpoly1.cpp rtodms.cpp \ release.cpp gauss.cpp \ - fileapi.cpp \ generic_inverse.cpp \ quadtree.hpp \ \ - datums.cpp datum_set.cpp transform.cpp \ - utils.cpp \ + datums.cpp datum_set.cpp \ mutex.cpp initcache.cpp geodesic.c \ strtod.cpp \ \ diff --git a/src/aasincos.cpp b/src/aasincos.cpp index 398a8cfc..c4314c67 100644 --- a/src/aasincos.cpp +++ b/src/aasincos.cpp @@ -9,24 +9,24 @@ #define ATOL 1e-50 double -aasin(projCtx ctx,double v) { +aasin(PJ_CONTEXT *ctx,double v) { double av; if ((av = fabs(v)) >= 1.) { if (av > ONE_TOL) - pj_ctx_set_errno( ctx, PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE ); + proj_context_errno_set( ctx, PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE ); return (v < 0. ? -M_HALFPI : M_HALFPI); } return asin(v); } double -aacos(projCtx ctx, double v) { +aacos(PJ_CONTEXT *ctx, double v) { double av; if ((av = fabs(v)) >= 1.) { if (av > ONE_TOL) - pj_ctx_set_errno( ctx, PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE ); + proj_context_errno_set( ctx, PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE ); return (v < 0. ? M_PI : 0.); } return acos(v); diff --git a/src/apps/cct.cpp b/src/apps/cct.cpp index f7413872..4f21f10a 100644 --- a/src/apps/cct.cpp +++ b/src/apps/cct.cpp @@ -78,6 +78,9 @@ Thomas Knudsen, thokn@sdfe.dk, 2016-05-25/2017-10-26 #include <string.h> #include <stdarg.h> +#include <fstream> // std::ifstream +#include <iostream> + #include "proj.h" #include "proj_internal.h" #include "proj_strtod.h" @@ -193,9 +196,8 @@ static void print(PJ_LOG_LEVEL log_level, const char *fmt, ...) { free( msg_buf ); } - int main(int argc, char **argv) { - PJ *P; + PJ *P = nullptr; PJ_COORD point; PJ_PROJ_INFO info; OPTARGS *o; @@ -292,10 +294,73 @@ int main(int argc, char **argv) { } /* Setup transformation */ - P = proj_create_argv (nullptr, o->pargc, o->pargv); - if ((nullptr==P) || (0==o->pargc)) { + if (o-> pargc == 0 && o->fargc > 0) { + std::string input(o->fargv[0]); + + if (!input.empty() && input[0] == '@') { + std::ifstream fs; + auto filename = input.substr(1); + fs.open(filename, std::fstream::in | std::fstream::binary); + if (!fs.is_open()) { + std::cerr << "cannot open " << filename << std::endl; + std::exit(1); + } + input.clear(); + while (!fs.eof()) { + char buffer[256]; + fs.read(buffer, sizeof(buffer)); + input.append(buffer, static_cast<size_t>(fs.gcount())); + if (input.size() > 100 * 1000) { + fs.close(); + std::cerr << "too big file " << filename << std::endl; + std::exit(1); + } + } + fs.close(); + } + + /* Assume we got a auth:code combination */ + auto n = input.find(":"); + if (n > 0) { + std::string auth = input.substr(0,n); + std::string code = input.substr(n+1, input.length()); + // Check that the authority matches one of the known ones + auto authorityList = proj_get_authorities_from_database(nullptr); + if( authorityList ) + { + for( auto iter = authorityList; *iter; iter++ ) + { + if( *iter == auth ) { + P = proj_create_from_database( + nullptr, auth.c_str(), code.c_str(), + PJ_CATEGORY_COORDINATE_OPERATION, 0, nullptr); + break; + } + } + proj_string_list_destroy(authorityList); + } + } + if( P == nullptr ) { + /* if we didn't get a auth:code combo we try to see if the input matches */ + /* anything else */ + P = proj_create(nullptr, input.c_str()); + } + + /* If instantiating operation without +-options optargpm thinks the input is */ + /* a file, hence we move all o->fargv entries one place closer to the start */ + /* of the array. This effectively overwrites the input and only leaves a list */ + /* of files in o->fargv. */ + o->fargc = o->fargc-1; + for (int j=0; j < o->fargc; j++) { + o->fargv[j] = o->fargv[j+1]; + } + } else { + P = proj_create_argv (nullptr, o->pargc, o->pargv); + } + + if (nullptr==P) { print (PJ_LOG_ERROR, "%s: Bad transformation arguments - (%s)\n '%s -h' for help", - o->progname, pj_strerrno (proj_errno(P)), o->progname); + o->progname, proj_errno_string (proj_errno(P)), o->progname); free (o); if (stdout != fout) fclose (fout); @@ -322,7 +387,7 @@ int main(int argc, char **argv) { buf = static_cast<char*>(calloc (1, 10000)); if (nullptr==buf) { print (PJ_LOG_ERROR, "%s: Out of memory", o->progname); - pj_free (P); + proj_destroy (P); free (o); if (stdout != fout) fclose (fout); @@ -370,7 +435,7 @@ int main(int argc, char **argv) { if (HUGE_VAL==point.xyzt.x) { /* transformation error */ print (PJ_LOG_NONE, "# Record %d TRANSFORMATION ERROR: %s (%s)", - (int) o->record_index, buf, pj_strerrno (proj_errno(P))); + (int) o->record_index, buf, proj_errno_string (proj_errno(P))); proj_errno_restore (P, err); continue; } @@ -385,12 +450,22 @@ int main(int argc, char **argv) { colmax = MAX(colmax, columns_xyzt[i]); comment = column(buf, colmax+1); } + /* remove the line feed from comment, as logger() above, invoked + by print() below (output), will add one */ + size_t len = strlen(comment); + if (len >= 1) + comment[len - 1] = '\0'; comment_delimiter = (comment && *comment) ? whitespace : blank_comment; /* Time to print the result */ - if (proj_angular_output (P, direction)) { - point.lpzt.lam = proj_todeg (point.lpzt.lam); - point.lpzt.phi = proj_todeg (point.lpzt.phi); + /* use same arguments to printf format string for both radians and + degrees; convert radians to degrees before printing */ + if (proj_angular_output (P, direction) || + proj_degree_output (P, direction)) { + if (proj_angular_output (P, direction)) { + point.lpzt.lam = proj_todeg (point.lpzt.lam); + point.lpzt.phi = proj_todeg (point.lpzt.phi); + } print (PJ_LOG_NONE, "%14.*f %14.*f %12.*f %12.4f%s%s", decimals_angles, point.xyzt.x, decimals_angles, point.xyzt.y, @@ -405,6 +480,8 @@ int main(int argc, char **argv) { decimals_distances, point.xyzt.z, point.xyzt.t, comment_delimiter, comment ); + if( fout == stdout ) + fflush(stdout); } proj_destroy(P); diff --git a/src/apps/cs2cs.cpp b/src/apps/cs2cs.cpp index 58c164c9..409a5ef3 100644 --- a/src/apps/cs2cs.cpp +++ b/src/apps/cs2cs.cpp @@ -36,8 +36,13 @@ #include <string.h> #include <cassert> +#include <iostream> #include <string> +#include <proj/io.hpp> +#include <proj/metadata.hpp> +#include <proj/util.hpp> + #include <proj/internal/internal.hpp> // PROJ include order is sensitive @@ -70,12 +75,19 @@ static const char *oform = static char oform_buffer[16]; /* buffer for oform when using -d */ static const char *oterr = "*\t*"; /* output line for unprojectable input */ static const char *usage = - "%s\nusage: %s [-dDeEfIlrstvwW [args]] [+opt[=arg] ...]\n" - " [+to +opt[=arg] ...] [file ...]\n"; + "%s\nusage: %s [-dDeEfIlrstvwW [args]]\n" + " [[--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]]\n" + " [--authority {name}]\n" + " [+opt[=arg] ...] [+to +opt[=arg] ...] [file ...]\n"; static double (*informat)(const char *, char **); /* input data deformatter function */ +using namespace NS_PROJ::io; +using namespace NS_PROJ::metadata; +using namespace NS_PROJ::util; +using namespace NS_PROJ::internal; + /************************************************************************/ /* process() */ /* */ @@ -217,6 +229,7 @@ static void process(FILE *fid) printf("%s", s); else printf("\n"); + fflush(stdout); } } @@ -358,9 +371,57 @@ int main(int argc, char **argv) { } } + ExtentPtr bboxFilter; + std::string area; + const char* authority = nullptr; + /* process run line arguments */ while (--argc > 0) { /* collect run line arguments */ - if (**++argv == '-') { + ++argv; + if (strcmp(*argv, "--area") == 0 ) { + ++argv; + --argc; + if( argc == 0 ) { + emess(1, "missing argument for --area"); + std::exit(1); + } + area = *argv; + } + else if (strcmp(*argv, "--bbox") == 0) { + ++argv; + --argc; + if( argc == 0 ) { + emess(1, "missing argument for --bbox"); + std::exit(1); + } + auto bboxStr(*argv); + auto bbox(split(bboxStr, ',')); + if (bbox.size() != 4) { + std::cerr << "Incorrect number of values for option --bbox: " + << bboxStr << std::endl; + std::exit(1); + } + try { + bboxFilter = Extent::createFromBBOX( + c_locale_stod(bbox[0]), c_locale_stod(bbox[1]), + c_locale_stod(bbox[2]), c_locale_stod(bbox[3])) + .as_nullable(); + } catch (const std::exception &e) { + std::cerr << "Invalid value for option --bbox: " << bboxStr + << ", " << e.what() << std::endl; + std::exit(1); + } + } + else if (strcmp(*argv, "--authority") == 0 ) { + ++argv; + --argc; + if( argc == 0 ) { + emess(1, "missing argument for --authority"); + std::exit(1); + } + authority = *argv; + } + else if (**argv == '-') { for (arg = *argv;;) { switch (*++arg) { case '\0': /* position of "stdin" */ @@ -467,10 +528,23 @@ int main(int argc, char **argv) { reverseout = 1; continue; case 'D': /* set debug level */ + { if (--argc <= 0) goto noargument; - pj_ctx_set_debug(pj_get_default_ctx(), atoi(*++argv)); + int log_level = atoi(*++argv); + if (log_level <= 0) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_NONE); + } else if (log_level == 1) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_ERROR); + } else if (log_level == 2) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_DEBUG); + } else if (log_level == 3) { + proj_log_level(pj_get_default_ctx(), PJ_LOG_TRACE); + } else { + proj_log_level(pj_get_default_ctx(), PJ_LOG_TELL); + } continue; + } case 'd': if (--argc <= 0) goto noargument; @@ -522,6 +596,102 @@ int main(int argc, char **argv) { } } + if (bboxFilter && !area.empty()) { + std::cerr << "ERROR: --bbox and --area are exclusive" << std::endl; + std::exit(1); + } + + PJ_AREA* pj_area = nullptr; + if (!area.empty()) { + + DatabaseContextPtr dbContext; + try { + dbContext = + DatabaseContext::create().as_nullable(); + } catch (const std::exception &e) { + std::cerr << "ERROR: Cannot create database connection: " + << e.what() << std::endl; + std::exit(1); + } + + // Process area of use + try { + if (area.find(' ') == std::string::npos && + area.find(':') != std::string::npos) { + auto tokens = split(area, ':'); + if (tokens.size() == 2) { + const std::string &areaAuth = tokens[0]; + const std::string &areaCode = tokens[1]; + bboxFilter = AuthorityFactory::create( + NN_NO_CHECK(dbContext), areaAuth) + ->createExtent(areaCode) + .as_nullable(); + } + } + if (!bboxFilter) { + auto authFactory = AuthorityFactory::create( + NN_NO_CHECK(dbContext), std::string()); + auto res = authFactory->listAreaOfUseFromName(area, false); + if (res.size() == 1) { + bboxFilter = + AuthorityFactory::create(NN_NO_CHECK(dbContext), + res.front().first) + ->createExtent(res.front().second) + .as_nullable(); + } else { + res = authFactory->listAreaOfUseFromName(area, true); + if (res.size() == 1) { + bboxFilter = + AuthorityFactory::create(NN_NO_CHECK(dbContext), + res.front().first) + ->createExtent(res.front().second) + .as_nullable(); + } else if (res.empty()) { + std::cerr << "No area of use matching provided name" + << std::endl; + std::exit(1); + } else { + std::cerr << "Several candidates area of use " + "matching provided name :" + << std::endl; + for (const auto &candidate : res) { + auto obj = + AuthorityFactory::create( + NN_NO_CHECK(dbContext), candidate.first) + ->createExtent(candidate.second); + std::cerr << " " << candidate.first << ":" + << candidate.second << " : " + << *obj->description() << std::endl; + } + std::exit(1); + } + } + } + } catch (const std::exception &e) { + std::cerr << "Area of use retrieval failed: " << e.what() + << std::endl; + std::exit(1); + } + } + + if (bboxFilter) { + auto geogElts = bboxFilter->geographicElements(); + if (geogElts.size() == 1) + { + auto bbox = std::dynamic_pointer_cast<GeographicBoundingBox>( + geogElts[0].as_nullable()); + if (bbox) + { + pj_area = proj_area_create(); + proj_area_set_bbox(pj_area, + bbox->westBoundLongitude(), + bbox->southBoundLatitude(), + bbox->eastBoundLongitude(), + bbox->northBoundLatitude()); + } + } + } + /* * If the user has requested inverse, then just reverse the * coordinate systems. @@ -602,15 +772,23 @@ int main(int argc, char **argv) { } } + std::string authorityOption; /* keep this variable in this outer scope ! */ + const char* options[2] = { nullptr, nullptr }; + if( authority ) { + authorityOption = "AUTHORITY="; + authorityOption += authority; + options[0] = authorityOption.data(); + } transformation = proj_create_crs_to_crs_from_pj(nullptr, src, dst, - nullptr, nullptr); + pj_area, options); proj_destroy(src); proj_destroy(dst); + proj_area_destroy(pj_area); if (!transformation) { emess(3, "cannot initialize transformation\ncause: %s", - pj_strerrno(pj_errno)); + proj_errno_string(proj_context_errno(nullptr))); } if (use_env_locale) { diff --git a/src/apps/emess.cpp b/src/apps/emess.cpp index 53018ba8..5a50cd25 100644 --- a/src/apps/emess.cpp +++ b/src/apps/emess.cpp @@ -9,17 +9,13 @@ # endif #endif -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif - #include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "proj_api.h" +#include "proj_internal.h" #include "proj_config.h" #define EMESS_ROUTINE #include "emess.h" diff --git a/src/apps/geod.cpp b/src/apps/geod.cpp index 919430ca..35a8e826 100644 --- a/src/apps/geod.cpp +++ b/src/apps/geod.cpp @@ -124,6 +124,7 @@ process(FILE *fid) { (void)fputs(rtodms(pline, al21, 0, 0), stdout); } (void)fputs(s, stdout); + fflush(stdout); } } diff --git a/src/apps/geod_set.cpp b/src/apps/geod_set.cpp index 603f0d95..d6516f22 100644 --- a/src/apps/geod_set.cpp +++ b/src/apps/geod_set.cpp @@ -75,6 +75,6 @@ geod_set(int argc, char **argv) { /* free up linked list */ for ( ; start; start = curr) { curr = start->next; - pj_dalloc(start); + free(start); } } diff --git a/src/apps/gie.cpp b/src/apps/gie.cpp index 8940afde..b504b922 100644 --- a/src/apps/gie.cpp +++ b/src/apps/gie.cpp @@ -880,8 +880,8 @@ static int expect_failure_with_errno_message (int expected, int got) { banner (T.operation); fprintf (T.fout, "%s", T.op_ko? " -----\n": delim); fprintf (T.fout, " FAILURE in %s(%d):\n", opt_strip_path (T.curr_file), (int) F->lineno); - fprintf (T.fout, " got errno %s (%d): %s\n", err_const_from_errno(got), got, pj_strerrno (got)); - fprintf (T.fout, " expected %s (%d): %s", err_const_from_errno(expected), expected, pj_strerrno (expected)); + fprintf (T.fout, " got errno %s (%d): %s\n", err_const_from_errno(got), got, proj_errno_string (got)); + fprintf (T.fout, " expected %s (%d): %s", err_const_from_errno(expected), expected, proj_errno_string (expected)); fprintf (T.fout, "\n"); return 1; } @@ -934,7 +934,7 @@ Tell GIE what to expect, when transforming the ACCEPTed input /* Otherwise, it's a true failure */ banner (T.operation); errmsg (3, "%sInvalid operation definition in line no. %d:\n %s (errno=%s/%d)\n", - delim, (int) T.operation_lineno, pj_strerrno(proj_errno(T.P)), + delim, (int) T.operation_lineno, proj_errno_string (proj_errno(T.P)), err_const_from_errno (proj_errno(T.P)), proj_errno(T.P) ); return another_failing_failure (); @@ -1124,7 +1124,7 @@ static const struct errno_vs_err_const lookup[] = { {"pjd_err_invalid_x_or_y" , -15}, {"pjd_err_wrong_format_dms_value" , -16}, {"pjd_err_non_conv_inv_meri_dist" , -17}, - {"pjd_err_non_con_inv_phi2" , -18}, + {"pjd_err_non_conv_sinhpsi2tanphi" , -18}, {"pjd_err_acos_asin_arg_too_large" , -19}, {"pjd_err_tolerance_condition" , -20}, {"pjd_err_conic_lat_equal" , -21}, @@ -1186,7 +1186,7 @@ static int list_err_codes (void) { if (9999==lookup[i].the_errno) break; fprintf (T.fout, "%25s (%2.2d): %s\n", lookup[i].the_err_const + 8, - lookup[i].the_errno, pj_strerrno(lookup[i].the_errno)); + lookup[i].the_errno, proj_errno_string (lookup[i].the_errno)); } return 0; } diff --git a/src/apps/proj.cpp b/src/apps/proj.cpp index 0bf98b3a..0108cb74 100644 --- a/src/apps/proj.cpp +++ b/src/apps/proj.cpp @@ -9,6 +9,8 @@ #include "emess.h" #include "utils.h" +#include <vector> + #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__WIN32__) # include <fcntl.h> # include <io.h> @@ -171,6 +173,7 @@ static void process(FILE *fid) { (void)fputs("\t<* * * * * *>", stdout); } (void)fputs(bin_in ? "\n" : s, stdout); + fflush(stdout); } } @@ -249,10 +252,8 @@ static void vprocess(FILE *fid) { if (postscale) { dat_xy.x *= fscale; dat_xy.y *= fscale; } } - /* For some reason pj_errno does not work as expected in some */ - /* versions of Visual Studio, so using pj_get_errno_ref instead */ - if (*pj_get_errno_ref()) { - emess(-1, pj_strerrno(*pj_get_errno_ref())); + if (proj_context_errno(nullptr)) { + emess(-1, proj_errno_string(proj_context_errno(nullptr))); continue; } @@ -286,15 +287,17 @@ static void vprocess(FILE *fid) { (void)fputs(proj_rtodms(pline, facs.meridian_convergence, 0, 0), stdout); (void)printf(" [ %.8f ]\n", facs.meridian_convergence * RAD_TO_DEG); (void)printf("Max-min (Tissot axis a-b) scale error: %.5f %.5f\n\n", facs.tissot_semimajor, facs.tissot_semiminor); + + fflush(stdout); } } int main(int argc, char **argv) { char *arg; - char *pargv[MAX_PARGS] = {}; + std::vector<char*> argvVector; char **eargv = argv; FILE *fid; - int pargc = 0, eargc = 0, mon = 0; + int eargc = 0, mon = 0; if ( (emess_dat.Prog_name = strrchr(*argv,DIR_CHAR)) != nullptr) ++emess_dat.Prog_name; @@ -449,10 +452,7 @@ int main(int argc, char **argv) { } break; } else if (**argv == '+') { /* + argument */ - if (pargc < MAX_PARGS) - pargv[pargc++] = *argv + 1; - else - emess(1,"overflowed + argument table"); + argvVector.push_back(*argv + 1); } else /* assumed to be input file name(s) */ eargv[eargc++] = *argv; } @@ -472,9 +472,14 @@ int main(int argc, char **argv) { postscale = 0; fscale = 1./fscale; } - if (!(Proj = pj_init(pargc, pargv))) + proj_context_use_proj4_init_rules(nullptr, true); + + // proj historically ignores any datum shift specifier, like nadgrids, towgs84, etc + argvVector.push_back(const_cast<char*>("break_cs2cs_recursion")); + + if (!(Proj = proj_create_argv(nullptr, static_cast<int>(argvVector.size()), argvVector.data()))) emess(3,"projection initialization failure\ncause: %s", - pj_strerrno(pj_errno)); + proj_errno_string(proj_context_errno(nullptr))); if (!proj_angular_input(Proj, PJ_FWD)) { emess(3, "can't initialize operations that take non-angular input coordinates"); @@ -559,7 +564,7 @@ int main(int argc, char **argv) { } if( Proj ) - pj_free(Proj); + proj_destroy(Proj); exit(0); /* normal completion */ } diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 37b76346..da885fbb 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -72,6 +72,7 @@ struct OutputOptions { bool singleLine = false; bool strict = true; bool ballparkAllowed = true; + bool allowEllipsoidalHeightAsVerticalCRS = false; }; } // anonymous namespace @@ -79,7 +80,8 @@ struct OutputOptions { static void usage() { std::cerr - << "usage: projinfo [-o formats] [-k crs|operation|datum|ellipsoid] " + << "usage: projinfo [-o formats] " + "[-k crs|operation|datum|ensemble|ellipsoid] " "[--summary] [-q]" << std::endl << " ([--area name_or_code] | " @@ -94,6 +96,8 @@ static void usage() { << " [--pivot-crs always|if_no_direct_transformation|" << "never|{auth:code[,auth:code]*}]" << std::endl << " [--show-superseded] [--hide-ballpark]" << std::endl + << " [--allow-ellipsoidal-height-as-vertical-crs]" + << std::endl << " [--boundcrs-to-wgs84]" << std::endl << " [--main-db-path path] [--aux-db-path path]*" << std::endl @@ -184,11 +188,11 @@ static BaseObjectNNPtr buildObject( auto urn = "urn:ogc:def:coordinateOperation:" + tokens[0] + "::" + tokens[1]; obj = createFromUserInput(urn, dbContext).as_nullable(); - } else if (kind == "ellipsoid" && tokens.size() == 2) { - auto urn = "urn:ogc:def:ellipsoid:" + tokens[0] + "::" + tokens[1]; - obj = createFromUserInput(urn, dbContext).as_nullable(); - } else if (kind == "datum" && tokens.size() == 2) { - auto urn = "urn:ogc:def:datum:" + tokens[0] + "::" + tokens[1]; + } else if ((kind == "ellipsoid" || kind == "datum" || + kind == "ensemble") && + tokens.size() == 2) { + auto urn = + "urn:ogc:def:" + kind + ":" + tokens[0] + "::" + tokens[1]; obj = createFromUserInput(urn, dbContext).as_nullable(); } else { // Convenience to be able to use C escaped strings... @@ -222,6 +226,9 @@ static BaseObjectNNPtr buildObject( AuthorityFactory::ObjectType::ELLIPSOID); else if (kind == "datum") allowedTypes.push_back(AuthorityFactory::ObjectType::DATUM); + else if (kind == "ensemble") + allowedTypes.push_back( + AuthorityFactory::ObjectType::DATUM_ENSEMBLE); constexpr size_t limitResultCount = 10; auto factory = AuthorityFactory::create(NN_NO_CHECK(dbContext), std::string()); @@ -483,6 +490,8 @@ static void outputObject( formatter->setMultiLine(false); } formatter->setStrict(outputOpt.strict); + formatter->setAllowEllipsoidalHeightAsVerticalCRS( + outputOpt.allowEllipsoidalHeightAsVerticalCRS); auto wkt = wktExportable->exportToWKT(formatter.get()); if (outputOpt.c_ify) { wkt = c_ify_string(wkt); @@ -689,6 +698,7 @@ static void outputOperations( std::vector<CoordinateOperationNNPtr> list; size_t spatialCriterionPartialIntersectionResultCount = 0; + bool spatialCriterionPartialIntersectionMoreRelevant = false; try { auto authFactory = dbContext @@ -714,10 +724,15 @@ static void outputOperations( ctxt->setSpatialCriterion( CoordinateOperationContext::SpatialCriterion:: PARTIAL_INTERSECTION); - spatialCriterionPartialIntersectionResultCount = - CoordinateOperationFactory::create() - ->createOperations(nnSourceCRS, nnTargetCRS, ctxt) - .size(); + auto list2 = + CoordinateOperationFactory::create()->createOperations( + nnSourceCRS, nnTargetCRS, ctxt); + spatialCriterionPartialIntersectionResultCount = list2.size(); + if (spatialCriterionPartialIntersectionResultCount == 1 && + list.size() == 1 && + list2[0]->nameStr() != list[0]->nameStr()) { + spatialCriterionPartialIntersectionMoreRelevant = true; + } } catch (const std::exception &) { } } @@ -736,6 +751,10 @@ static void outputOperations( "more results (" << spatialCriterionPartialIntersectionResultCount << ")" << std::endl; + } else if (spatialCriterionPartialIntersectionMoreRelevant) { + std::cout << "Note: using '--spatial-test intersects' would bring " + "more relevant results." + << std::endl; } if (summary) { for (const auto &op : list) { @@ -929,6 +948,8 @@ int main(int argc, char **argv) { objectKind = "ellipsoid"; } else if (ci_equal(kind, "datum")) { objectKind = "datum"; + } else if (ci_equal(kind, "ensemble")) { + objectKind = "ensemble"; } else { std::cerr << "Unrecognized value for option -k: " << kind << std::endl; @@ -1054,6 +1075,8 @@ int main(int argc, char **argv) { showSuperseded = true; } else if (arg == "--lax") { outputOpt.strict = false; + } else if (arg == "--allow-ellipsoidal-height-as-vertical-crs") { + outputOpt.allowEllipsoidalHeightAsVerticalCRS = true; } else if (arg == "--hide-ballpark") { outputOpt.ballparkAllowed = false; } else if (ci_equal(arg, "--3d")) { diff --git a/src/auth.cpp b/src/auth.cpp index a8ee262a..ced02fb4 100644 --- a/src/auth.cpp +++ b/src/auth.cpp @@ -18,7 +18,7 @@ pj_authset(double es) { double t, *APA; - if ((APA = (double *)pj_malloc(APA_SIZE * sizeof(double))) != nullptr) { + if ((APA = (double *)malloc(APA_SIZE * sizeof(double))) != nullptr) { APA[0] = es * P00; t = es * es; APA[0] += t * P01; diff --git a/src/bin_projinfo.cmake b/src/bin_projinfo.cmake index 16c9e9d0..8610a3a7 100644 --- a/src/bin_projinfo.cmake +++ b/src/bin_projinfo.cmake @@ -15,3 +15,7 @@ install(TARGETS binprojinfo if(MSVC AND BUILD_SHARED_LIBS) target_compile_definitions(binprojinfo PRIVATE PROJ_MSVC_DLL_IMPORT=1) endif() + +if(CURL_ENABLED) + target_compile_definitions(binprojinfo PRIVATE -DCURL_ENABLED) +endif() diff --git a/src/conversions/axisswap.cpp b/src/conversions/axisswap.cpp index 4ae2b4e4..1aa339c3 100644 --- a/src/conversions/axisswap.cpp +++ b/src/conversions/axisswap.cpp @@ -169,7 +169,7 @@ static PJ_COORD reverse_4d(PJ_COORD coo, PJ *P) { /***********************************************************************/ PJ *CONVERSION(axisswap,0) { /***********************************************************************/ - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); char *s; unsigned int i, j, n = 0; diff --git a/src/conversions/set.cpp b/src/conversions/set.cpp index 7628bf4f..2f30bda8 100644 --- a/src/conversions/set.cpp +++ b/src/conversions/set.cpp @@ -39,7 +39,7 @@ PJ *OPERATION(set, 0) { P->inv4d = set_fwd_inv; P->fwd4d = set_fwd_inv; - auto set = static_cast<struct Set*>(pj_calloc (1, sizeof(struct Set))); + auto set = static_cast<struct Set*>(calloc (1, sizeof(struct Set))); P->opaque = set; if (nullptr==P->opaque) return pj_default_destructor(P, ENOMEM); diff --git a/src/conversions/topocentric.cpp b/src/conversions/topocentric.cpp new file mode 100644 index 00000000..f6f328ad --- /dev/null +++ b/src/conversions/topocentric.cpp @@ -0,0 +1,165 @@ +/****************************************************************************** + * Project: PROJ + * Purpose: Convert between geocentric coordinates and topocentric (ENU) coordinates + * + ****************************************************************************** + * Copyright (c) 2020, Even Rouault <even.rouault at spatialys.com> + * + * 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_internal.h" +#include <errno.h> +#include <math.h> + +PROJ_HEAD(topocentric, "Geocentric/Topocentric conversion"); + +// Notations and formulas taken from IOGP Publication 373-7-2 - +// Geomatics Guidance Note number 7, part 2 - October 2020 + +namespace { // anonymous namespace +struct pj_opaque { + double X0; + double Y0; + double Z0; + double sinphi0; + double cosphi0; + double sinlam0; + double coslam0; +}; +} // anonymous namespace + +// Convert from geocentric to topocentric +static PJ_COORD topocentric_fwd(PJ_COORD in, PJ * P) +{ + struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); + PJ_COORD out; + const double dX = in.xyz.x - Q->X0; + const double dY = in.xyz.y - Q->Y0; + const double dZ = in.xyz.z - Q->Z0; + out.xyz.x = -dX * Q->sinlam0 + dY * Q->coslam0; + out.xyz.y = -dX * Q->sinphi0 * Q->coslam0 - dY * Q->sinphi0 * Q->sinlam0 + dZ * Q->cosphi0; + out.xyz.z = dX * Q->cosphi0 * Q->coslam0 + dY * Q->cosphi0 * Q->sinlam0 + dZ * Q->sinphi0; + return out; +} + +// Convert from topocentric to geocentric +static PJ_COORD topocentric_inv(PJ_COORD in, PJ * P) +{ + struct pj_opaque *Q = static_cast<struct pj_opaque*>(P->opaque); + PJ_COORD out; + out.xyz.x = Q->X0 - in.xyz.x * Q->sinlam0 - in.xyz.y * Q->sinphi0 * Q->coslam0 + in.xyz.z * Q->cosphi0 * Q->coslam0; + out.xyz.y = Q->Y0 + in.xyz.x * Q->coslam0 - in.xyz.y * Q->sinphi0 * Q->sinlam0 + in.xyz.z * Q->cosphi0 * Q->sinlam0; + out.xyz.z = Q->Z0 + in.xyz.y * Q->cosphi0 + in.xyz.z * Q->sinphi0; + return out; +} + + +/*********************************************************************/ +PJ *CONVERSION(topocentric,1) { +/*********************************************************************/ + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); + if (nullptr==Q) + return pj_default_destructor (P, ENOMEM); + P->opaque = static_cast<void *>(Q); + + // The topocentric origin can be specified either in geocentric coordinates + // (X_0,Y_0,Z_0) or as geographic coordinates (lon_0,lat_0,h_0) + // Checks: + // - X_0 or lon_0 must be specified + // - If X_0 is specified, the Y_0 and Z_0 must also be + // - If lon_0 is specified, then lat_0 must also be + // - If any of X_0, Y_0, Z_0 is specified, then any of lon_0,lat_0,h_0 must + // not be, and vice versa. + const auto hasX0 = pj_param_exists(P->params, "X_0"); + const auto hasY0 = pj_param_exists(P->params, "Y_0"); + const auto hasZ0 = pj_param_exists(P->params, "Z_0"); + const auto hasLon0 = pj_param_exists(P->params, "lon_0"); + const auto hasLat0 = pj_param_exists(P->params, "lat_0"); + const auto hash0 = pj_param_exists(P->params, "h_0"); + if( !hasX0 && !hasLon0 ) + { + return pj_default_destructor(P, PJD_ERR_MISSING_ARGS); + } + if ( (hasX0 || hasY0 || hasZ0) && + (hasLon0 || hasLat0 || hash0) ) + { + return pj_default_destructor(P, PJD_ERR_MUTUALLY_EXCLUSIVE_ARGS); + } + if( hasX0 && (!hasY0 || !hasZ0) ) + { + return pj_default_destructor(P, PJD_ERR_MISSING_ARGS); + } + if( hasLon0 && !hasLat0 ) // allow missing h_0 + { + return pj_default_destructor(P, PJD_ERR_MISSING_ARGS); + } + + // Pass a dummy ellipsoid definition that will be overridden just afterwards + PJ* cart = proj_create(P->ctx, "+proj=cart +a=1"); + if (cart == nullptr) + return pj_default_destructor(P, ENOMEM); + /* inherit ellipsoid definition from P to cart */ + pj_inherit_ellipsoid_def (P, cart); + + if( hasX0 ) + { + Q->X0 = pj_param(P->ctx, P->params, "dX_0").f; + Q->Y0 = pj_param(P->ctx, P->params, "dY_0").f; + Q->Z0 = pj_param(P->ctx, P->params, "dZ_0").f; + + // Compute lam0, phi0 from X0,Y0,Z0 + PJ_XYZ xyz; + xyz.x = Q->X0; + xyz.y = Q->Y0; + xyz.z = Q->Z0; + const auto lpz = pj_inv3d(xyz, cart); + Q->sinphi0 = sin(lpz.phi); + Q->cosphi0 = cos(lpz.phi); + Q->sinlam0 = sin(lpz.lam); + Q->coslam0 = cos(lpz.lam); + } + else + { + // Compute X0,Y0,Z0 from lam0, phi0, h0 + PJ_LPZ lpz; + lpz.lam = P->lam0; + lpz.phi = P->phi0; + lpz.z = pj_param(P->ctx, P->params, "dh_0").f; + const auto xyz = pj_fwd3d(lpz, cart); + Q->X0 = xyz.x; + Q->Y0 = xyz.y; + Q->Z0 = xyz.z; + + Q->sinphi0 = sin(P->phi0); + Q->cosphi0 = cos(P->phi0); + Q->sinlam0 = sin(P->lam0); + Q->coslam0 = cos(P->lam0); + } + + proj_destroy(cart); + + P->fwd4d = topocentric_fwd; + P->inv4d = topocentric_inv; + P->left = PJ_IO_UNITS_CARTESIAN; + P->right = PJ_IO_UNITS_CARTESIAN; + return P; +} diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp index 172e2c48..61bccbf1 100644 --- a/src/conversions/unitconvert.cpp +++ b/src/conversions/unitconvert.cpp @@ -433,7 +433,7 @@ static double get_unit_conversion_factor(const char* name, /***********************************************************************/ PJ *CONVERSION(unitconvert,0) { /***********************************************************************/ - struct pj_opaque_unitconvert *Q = static_cast<struct pj_opaque_unitconvert*>(pj_calloc (1, sizeof (struct pj_opaque_unitconvert))); + struct pj_opaque_unitconvert *Q = static_cast<struct pj_opaque_unitconvert*>(calloc (1, sizeof (struct pj_opaque_unitconvert))); const char *s, *name; int i; double f; diff --git a/src/ctx.cpp b/src/ctx.cpp index 6dbe0de5..2093950b 100644 --- a/src/ctx.cpp +++ b/src/ctx.cpp @@ -1,6 +1,6 @@ /****************************************************************************** * Project: PROJ.4 - * Purpose: Implementation of the projCtx thread context object. + * Purpose: Implementation of the PJ_CONTEXT thread context object. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** @@ -43,7 +43,7 @@ /* pj_get_ctx() */ /************************************************************************/ -projCtx pj_get_ctx( projPJ pj ) +PJ_CONTEXT* pj_get_ctx( PJ *pj ) { if (nullptr==pj) @@ -54,13 +54,17 @@ projCtx pj_get_ctx( projPJ pj ) } /************************************************************************/ -/* pj_set_ctx() */ -/* */ -/* Note we do not deallocate the old context! */ +/* proj_assign_context() */ /************************************************************************/ -void pj_set_ctx( projPJ pj, projCtx ctx ) - +/** \brief Re-assign a context to a PJ* object. + * + * This may be useful if the PJ* has been created with a context that is + * thread-specific, and is later used in another thread. In that case, + * the user may want to assign another thread-specific context to the + * object. + */ +void proj_assign_context( PJ* pj, PJ_CONTEXT *ctx ) { if (pj==nullptr) return; @@ -71,36 +75,20 @@ void pj_set_ctx( projPJ pj, projCtx ctx ) } for( const auto &alt: pj->alternativeCoordinateOperations ) { - pj_set_ctx(alt.pj, ctx); + proj_assign_context(alt.pj, ctx); } -} - -/************************************************************************/ -/* proj_assign_context() */ -/************************************************************************/ -/** \brief Re-assign a context to a PJ* object. - * - * This may be useful if the PJ* has been created with a context that is - * thread-specific, and is later used in another thread. In that case, - * the user may want to assign another thread-specific context to the - * object. - */ -void proj_assign_context( PJ* pj, PJ_CONTEXT* ctx ) -{ - pj_set_ctx( pj, ctx ); } /************************************************************************/ /* createDefault() */ /************************************************************************/ -projCtx_t projCtx_t::createDefault() +pj_ctx pj_ctx::createDefault() { - projCtx_t ctx; + pj_ctx ctx; ctx.debug_level = PJ_LOG_NONE; ctx.logger = pj_stderr_logger; - ctx.fileapi_legacy = pj_get_default_fileapi(); NS_PROJ::FileManager::fillDefaultNetworkInterface(&ctx); if( getenv("PROJ_DEBUG") != nullptr ) @@ -117,7 +105,7 @@ projCtx_t projCtx_t::createDefault() /* get_cpp_context() */ /**************************************************************************/ -projCppContext* projCtx_t::get_cpp_context() +projCppContext* pj_ctx::get_cpp_context() { if (cpp_context == nullptr) { cpp_context = new projCppContext(this); @@ -125,12 +113,11 @@ projCppContext* projCtx_t::get_cpp_context() return cpp_context; } - /**************************************************************************/ /* safeAutoCloseDbIfNeeded() */ /**************************************************************************/ -void projCtx_t::safeAutoCloseDbIfNeeded() +void pj_ctx::safeAutoCloseDbIfNeeded() { if (cpp_context) { cpp_context->autoCloseDbIfNeeded(); @@ -141,7 +128,7 @@ void projCtx_t::safeAutoCloseDbIfNeeded() /* set_search_paths() */ /************************************************************************/ -void projCtx_t::set_search_paths(const std::vector<std::string>& search_paths_in ) +void pj_ctx::set_search_paths(const std::vector<std::string>& search_paths_in ) { search_paths = search_paths_in; delete[] c_compat_paths; @@ -158,26 +145,24 @@ void projCtx_t::set_search_paths(const std::vector<std::string>& search_paths_in /* set_ca_bundle_path() */ /**************************************************************************/ -void projCtx_t::set_ca_bundle_path(const std::string& ca_bundle_path_in) +void pj_ctx::set_ca_bundle_path(const std::string& ca_bundle_path_in) { ca_bundle_path = ca_bundle_path_in; } /************************************************************************/ -/* projCtx_t(const projCtx_t& other) */ +/* pj_ctx(const pj_ctx& other) */ /************************************************************************/ -projCtx_t::projCtx_t(const projCtx_t& other) : +pj_ctx::pj_ctx(const pj_ctx& other) : debug_level(other.debug_level), logger(other.logger), logger_app_data(other.logger_app_data), - fileapi_legacy(other.fileapi_legacy), cpp_context(other.cpp_context ? other.cpp_context->clone(this) : nullptr), use_proj4_init_rules(other.use_proj4_init_rules), epsg_file_exists(other.epsg_file_exists), ca_bundle_path(other.ca_bundle_path), env_var_proj_lib(other.env_var_proj_lib), - file_finder_legacy(other.file_finder_legacy), file_finder(other.file_finder), file_finder_user_data(other.file_finder_user_data), custom_sqlite3_vfs_name(other.custom_sqlite3_vfs_name), @@ -197,129 +182,35 @@ projCtx_t::projCtx_t(const projCtx_t& other) : /* pj_get_default_ctx() */ /************************************************************************/ -projCtx pj_get_default_ctx() +PJ_CONTEXT* pj_get_default_ctx() { // C++11 rules guarantee a thread-safe instantiation. - static projCtx_t default_context(projCtx_t::createDefault()); + static pj_ctx default_context(pj_ctx::createDefault()); return &default_context; } /************************************************************************/ -/* ~projCtx_t() */ +/* ~pj_ctx() */ /************************************************************************/ -projCtx_t::~projCtx_t() +pj_ctx::~pj_ctx() { delete[] c_compat_paths; proj_context_delete_cpp_context(cpp_context); } /************************************************************************/ -/* pj_ctx_alloc() */ -/************************************************************************/ - -projCtx pj_ctx_alloc() - -{ - return new (std::nothrow) projCtx_t(*pj_get_default_ctx()); -} - -/************************************************************************/ /* proj_context_clone() */ /* Create a new context based on a custom context */ /************************************************************************/ -PJ_CONTEXT *proj_context_clone (PJ_CONTEXT *ctx) -{ - if (nullptr==ctx) - return pj_ctx_alloc (); - - return new (std::nothrow) projCtx_t(*ctx); -} - -/************************************************************************/ -/* pj_ctx_free() */ -/************************************************************************/ - -void pj_ctx_free( projCtx ctx ) - -{ - delete ctx; -} - -/************************************************************************/ -/* pj_ctx_get_errno() */ -/************************************************************************/ - -int pj_ctx_get_errno( projCtx ctx ) - +PJ_CONTEXT* proj_context_clone (PJ_CONTEXT *ctx) { if (nullptr==ctx) - return pj_get_default_ctx ()->last_errno; - return ctx->last_errno; -} - -/************************************************************************/ -/* pj_ctx_set_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 ) - return; - errno = new_errno; - pj_errno = new_errno; -} - -/************************************************************************/ -/* pj_ctx_set_debug() */ -/************************************************************************/ - -void pj_ctx_set_debug( projCtx ctx, int new_debug ) + return proj_context_create(); -{ - if (nullptr==ctx) - return; - ctx->debug_level = new_debug; + return new (std::nothrow) pj_ctx(*ctx); } -/************************************************************************/ -/* pj_ctx_set_logger() */ -/************************************************************************/ - -void pj_ctx_set_logger( projCtx ctx, void (*new_logger)(void*,int,const char*) ) -{ - if (nullptr==ctx) - return; - ctx->logger = new_logger; -} - -/************************************************************************/ -/* pj_ctx_set_app_data() */ -/************************************************************************/ - -void pj_ctx_set_app_data( projCtx ctx, void *new_app_data ) - -{ - if (nullptr==ctx) - return; - ctx->logger_app_data = new_app_data; -} - -/************************************************************************/ -/* pj_ctx_get_app_data() */ -/************************************************************************/ - -void *pj_ctx_get_app_data( projCtx ctx ) - -{ - if (nullptr==ctx) - return nullptr; - return ctx->logger_app_data; -} diff --git a/src/datum_set.cpp b/src/datum_set.cpp index 15d51613..3f612633 100644 --- a/src/datum_set.cpp +++ b/src/datum_set.cpp @@ -38,7 +38,7 @@ /* pj_datum_set() */ /************************************************************************/ -int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) +int pj_datum_set(PJ_CONTEXT *ctx, paralist *pl, PJ *projdef) { const char *name, *towgs84, *nadgrids; @@ -71,7 +71,7 @@ int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) for (i = 0; (s = pj_datums[i].id) && strcmp(name, s) ; ++i) {} if (!s) { - pj_ctx_set_errno(ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); + proj_context_errno_set(ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); return 1; } @@ -84,25 +84,27 @@ int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef) sizeof(entry) - 1 - strlen(entry) ); entry[ sizeof(entry) - 1 ] = '\0'; - curr = curr->next = pj_mkparam(entry); - if (nullptr == curr) + auto param = pj_mkparam(entry); + if (nullptr == param) { - pj_ctx_set_errno(ctx, ENOMEM); + proj_context_errno_set(ctx, ENOMEM); return 1; } + curr->next = param; + curr = param; } if( pj_datums[i].defn && strlen(pj_datums[i].defn) > 0 ) { - curr = curr->next = pj_mkparam(pj_datums[i].defn); - if (nullptr == curr) + auto param = pj_mkparam(pj_datums[i].defn); + if (nullptr == param) { - pj_ctx_set_errno(ctx, ENOMEM); + proj_context_errno_set(ctx, ENOMEM); return 1; } + curr->next = param; + /* curr = param; */ } - - (void)curr; /* make clang static analyzer happy */ } /* -------------------------------------------------------------------- */ diff --git a/src/dmstor.cpp b/src/dmstor.cpp index 3ba66030..24887a11 100644 --- a/src/dmstor.cpp +++ b/src/dmstor.cpp @@ -26,7 +26,7 @@ dmstor(const char *is, char **rs) { } double -dmstor_ctx(projCtx ctx, const char *is, char **rs) { +dmstor_ctx(PJ_CONTEXT *ctx, const char *is, char **rs) { int sign, n, nl; char *s, work[MAX_WORK]; const char* p; @@ -61,7 +61,7 @@ dmstor_ctx(projCtx ctx, const char *is, char **rs) { n = 2; break; case 'r': case 'R': if (nl) { - pj_ctx_set_errno( ctx, PJD_ERR_WRONG_FORMAT_DMS_VALUE ); + proj_context_errno_set( ctx, PJD_ERR_WRONG_FORMAT_DMS_VALUE ); return HUGE_VAL; } ++s; @@ -73,7 +73,7 @@ dmstor_ctx(projCtx ctx, const char *is, char **rs) { continue; } if (n < nl) { - pj_ctx_set_errno( ctx, PJD_ERR_WRONG_FORMAT_DMS_VALUE ); + proj_context_errno_set( ctx, PJD_ERR_WRONG_FORMAT_DMS_VALUE ); return HUGE_VAL; } v += tv * vm[n]; diff --git a/src/ell_set.cpp b/src/ell_set.cpp index ddd507ac..176fc553 100644 --- a/src/ell_set.cpp +++ b/src/ell_set.cpp @@ -77,13 +77,13 @@ int pj_ellipsoid (PJ *P) { int err = proj_errno_reset (P); const char *empty = {""}; - pj_dealloc(P->def_size); + free(P->def_size); P->def_size = nullptr; - pj_dealloc(P->def_shape); + free(P->def_shape); P->def_shape = nullptr; - pj_dealloc(P->def_spherification); + free(P->def_spherification); P->def_spherification = nullptr; - pj_dealloc(P->def_ellps); + free(P->def_ellps); P->def_ellps = nullptr; /* Specifying R overrules everything */ @@ -162,7 +162,7 @@ static int ellps_ellps (PJ *P) { new_params->next = pj_mkparam (ellps->ell); if (nullptr == new_params->next) { - pj_dealloc(new_params); + free(new_params); return proj_errno_set (P, ENOMEM); } paralist* old_params = P->params; @@ -176,8 +176,8 @@ static int ellps_ellps (PJ *P) { ellps_shape (P); P->params = old_params; - pj_dealloc (new_params->next); - pj_dealloc (new_params); + free (new_params->next); + free (new_params); if (proj_errno (P)) return proj_errno (P); @@ -195,7 +195,7 @@ static int ellps_size (PJ *P) { paralist *par = nullptr; int a_was_set = 0; - pj_dealloc(P->def_size); + free(P->def_size); P->def_size = nullptr; /* A size parameter *must* be given, but may have been given as ellps prior */ @@ -235,7 +235,7 @@ static int ellps_shape (PJ *P) { par = nullptr; len = sizeof (keys) / sizeof (char *); - pj_dealloc(P->def_shape); + free(P->def_shape); P->def_shape = nullptr; /* Check which shape key is specified */ @@ -552,7 +552,7 @@ int pj_calc_ellipsoid_params (PJ *P, double a, double es) { if (0==P->f) P->f = 1 - cos (P->alpha); /* = 1 - sqrt (1 - PIN->es); */ if (P->f == 1.0) { - pj_ctx_set_errno( P->ctx, PJD_ERR_INVALID_ECCENTRICITY); + proj_context_errno_set( P->ctx, PJD_ERR_INVALID_ECCENTRICITY); return PJD_ERR_INVALID_ECCENTRICITY; } P->rf = P->f != 0.0 ? 1.0/P->f: HUGE_VAL; @@ -573,7 +573,7 @@ int pj_calc_ellipsoid_params (PJ *P, double a, double es) { P->one_es = 1. - P->es; if (P->one_es == 0.) { - pj_ctx_set_errno( P->ctx, PJD_ERR_INVALID_ECCENTRICITY); + proj_context_errno_set( P->ctx, PJD_ERR_INVALID_ECCENTRICITY); return PJD_ERR_INVALID_ECCENTRICITY; } @@ -609,7 +609,7 @@ int pj_ell_set (PJ_CONTEXT *ctx, paralist *pl, double *a, double *es) { /**************************************************************************************/ -int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { +int pj_ell_set (PJ_CONTEXT *ctx, paralist *pl, double *a, double *es) { /*************************************************************************************** Initialize ellipsoidal parameters: This is the original ellipsoid setup function by Gerald Evenden - significantly more compact than pj_ellipsoid and @@ -630,7 +630,7 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { paralist *start = 0; /* clear any previous error */ - pj_ctx_set_errno(ctx,0); + proj_context_errno_set(ctx,0); /* check for varying forms of ellipsoid input */ *a = *es = 0.; @@ -648,7 +648,7 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { for (start = pl; start && start->next ; start = start->next) ; for (i = 0; (s = pj_ellps[i].id) && strcmp(name, s) ; ++i) ; if (!s) { - pj_ctx_set_errno( ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); + proj_context_errno_set( ctx, PJD_ERR_UNKNOWN_ELLP_PARAM); return 1; } start->next = pj_mkparam(pj_ellps[i].major); @@ -662,14 +662,14 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { else if (pj_param(ctx,pl, "te").i) { /* eccentricity */ e = pj_param(ctx,pl, "de").f; if (e < 0) { - pj_ctx_set_errno(ctx, PJD_ERR_INVALID_ECCENTRICITY); + proj_context_errno_set(ctx, PJD_ERR_INVALID_ECCENTRICITY); return 1; } *es = e * e; } else if (pj_param(ctx,pl, "trf").i) { /* recip flattening */ *es = pj_param(ctx,pl, "drf").f; if (*es == 0.0) { - pj_ctx_set_errno(ctx, PJD_ERR_REV_FLATTENING_IS_ZERO); + proj_context_errno_set(ctx, PJD_ERR_REV_FLATTENING_IS_ZERO); goto bomb; } *es = 1./ *es; @@ -700,7 +700,7 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { *es = 0.; } else if (pj_param(ctx,pl, "bR_h").i) { /* sphere--harmonic mean */ if ( (*a + b) == 0.0) { - pj_ctx_set_errno(ctx, PJD_ERR_TOLERANCE_CONDITION); + proj_context_errno_set(ctx, PJD_ERR_TOLERANCE_CONDITION); goto bomb; } *a = 2. * *a * b / (*a + b); @@ -711,7 +711,7 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { tmp = sin(pj_param(ctx,pl, i ? "rR_lat_a" : "rR_lat_g").f); if (fabs(tmp) > M_HALFPI) { - pj_ctx_set_errno(ctx, PJD_ERR_REF_RAD_LARGER_THAN_90); + proj_context_errno_set(ctx, PJD_ERR_REF_RAD_LARGER_THAN_90); goto bomb; } tmp = 1. - *es * tmp * tmp; @@ -721,8 +721,8 @@ int pj_ell_set (projCtx ctx, paralist *pl, double *a, double *es) { } bomb: if (start) { /* clean up temporary extension of list */ - pj_dalloc(start->next->next); - pj_dalloc(start->next); + free(start->next->next); + free(start->next); start->next = 0; } if (ctx->last_errno) @@ -730,15 +730,15 @@ bomb: } /* some remaining checks */ if (*es < 0.) { - pj_ctx_set_errno(ctx, PJD_ERR_ES_LESS_THAN_ZERO); + proj_context_errno_set(ctx, PJD_ERR_ES_LESS_THAN_ZERO); return 1; } if (*es >= 1.) { - pj_ctx_set_errno(ctx, PJD_ERR_INVALID_ECCENTRICITY); + proj_context_errno_set(ctx, PJD_ERR_INVALID_ECCENTRICITY); return 1; } if (*a <= 0.) { - pj_ctx_set_errno(ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); + proj_context_errno_set(ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN); return 1; } return 0; diff --git a/src/errno.cpp b/src/errno.cpp deleted file mode 100644 index 4f3119b3..00000000 --- a/src/errno.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* For full ANSI compliance of global variable */ - -#include "proj.h" -#include "proj_internal.h" - -int pj_errno = 0; - -/************************************************************************/ -/* pj_get_errno_ref() */ -/************************************************************************/ - -int *pj_get_errno_ref() - -{ - return &pj_errno; -} - -/* end */ diff --git a/src/fileapi.cpp b/src/fileapi.cpp deleted file mode 100644 index 70be2502..00000000 --- a/src/fileapi.cpp +++ /dev/null @@ -1,240 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Implementation of the pj_ctx_* file api, and the default stdio - * based implementation. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2013, Frank Warmerdam - * - * 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 <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "proj.h" -#include "proj_internal.h" -#include "filemanager.hpp" - -static PAFile stdio_fopen(projCtx ctx, const char *filename, - const char *access); -static size_t stdio_fread(void *buffer, size_t size, size_t nmemb, - PAFile file); -static int stdio_fseek(PAFile file, long offset, int whence); -static long stdio_ftell(PAFile file); -static void stdio_fclose(PAFile file); - -static projFileAPI default_fileapi = { - stdio_fopen, - stdio_fread, - stdio_fseek, - stdio_ftell, - stdio_fclose -}; - -typedef struct { - projCtx ctx; - FILE *fp; -} stdio_pafile; - -/************************************************************************/ -/* pj_get_default_fileapi() */ -/************************************************************************/ - -projFileAPI *pj_get_default_fileapi(void) -{ - return &default_fileapi; -} - -/************************************************************************/ -/* stdio_fopen() */ -/************************************************************************/ - -static PAFile stdio_fopen(projCtx ctx, const char *filename, - const char *access) -{ - stdio_pafile *pafile; - FILE *fp; - - fp = fopen(filename, access); - if (fp == nullptr) - { - return nullptr; - } - - pafile = (stdio_pafile *) malloc(sizeof(stdio_pafile)); - if (!pafile) - { - pj_ctx_set_errno(ctx, ENOMEM); - fclose(fp); - return nullptr; - } - - pafile->fp = fp; - pafile->ctx = ctx; - return (PAFile) pafile; -} - -/************************************************************************/ -/* stdio_fread() */ -/************************************************************************/ - -static size_t stdio_fread(void *buffer, size_t size, size_t nmemb, - PAFile file) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - return fread(buffer, size, nmemb, pafile->fp); -} - -/************************************************************************/ -/* stdio_fseek() */ -/************************************************************************/ -static int stdio_fseek(PAFile file, long offset, int whence) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - return fseek(pafile->fp, offset, whence); -} - -/************************************************************************/ -/* stdio_ftell() */ -/************************************************************************/ -static long stdio_ftell(PAFile file) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - return ftell(pafile->fp); -} - -/************************************************************************/ -/* stdio_fclose() */ -/************************************************************************/ -static void stdio_fclose(PAFile file) -{ - stdio_pafile *pafile = (stdio_pafile *) file; - fclose(pafile->fp); - free(pafile); -} - -/************************************************************************/ -/* pj_ctx_fopen() */ -/* */ -/* Open a file using the provided file io hooks. */ -/************************************************************************/ - -PAFile pj_ctx_fopen(projCtx ctx, const char *filename, const char *access) -{ - return ctx->fileapi_legacy->FOpen(ctx, filename, access); -} - -/************************************************************************/ -/* pj_ctx_fread() */ -/************************************************************************/ -size_t pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile file) -{ - return ctx->fileapi_legacy->FRead(buffer, size, nmemb, file); -} - -/************************************************************************/ -/* pj_ctx_fseek() */ -/************************************************************************/ -int pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence) -{ - return ctx->fileapi_legacy->FSeek(file, offset, whence); -} - -/************************************************************************/ -/* pj_ctx_ftell() */ -/************************************************************************/ -long pj_ctx_ftell(projCtx ctx, PAFile file) -{ - return ctx->fileapi_legacy->FTell(file); -} - -/************************************************************************/ -/* pj_ctx_fclose() */ -/************************************************************************/ -void pj_ctx_fclose(projCtx ctx, PAFile file) -{ - ctx->fileapi_legacy->FClose(file); -} - -/************************************************************************/ -/* pj_ctx_fgets() */ -/* */ -/* A not very optimal implementation of fgets on top of */ -/* fread(). If we end up using this a lot more care should be */ -/* taken. */ -/************************************************************************/ - -char *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file) -{ - long start = pj_ctx_ftell(ctx, file); - size_t bytes_read; - int i; - int max_size; - - line[size-1] = '\0'; - bytes_read = pj_ctx_fread(ctx, line, 1, size-1, file); - if(bytes_read == 0) - return nullptr; - if(bytes_read < (size_t)size) - { - line[bytes_read] = '\0'; - } - - max_size = (int)MIN(bytes_read, (size_t)(size > 2 ? size - 2 : 0)); - for( i = 0; i < max_size; i++) - { - if (line[i] == '\n') - { - line[i+1] = '\0'; - pj_ctx_fseek(ctx, file, start + i + 1, SEEK_SET); - break; - } - } - return line; -} - -/************************************************************************/ -/* pj_ctx_set_fileapi() */ -/************************************************************************/ - -void pj_ctx_set_fileapi( projCtx ctx, projFileAPI *fileapi ) - -{ - if (nullptr==ctx) - return; - ctx->fileapi_legacy = fileapi; -} - -/************************************************************************/ -/* pj_ctx_get_fileapi() */ -/************************************************************************/ - -projFileAPI *pj_ctx_get_fileapi( projCtx ctx ) - -{ - if (nullptr==ctx) - return nullptr; - return ctx->fileapi_legacy; -} - diff --git a/src/filemanager.cpp b/src/filemanager.cpp index e6a9ed95..b51205eb 100644 --- a/src/filemanager.cpp +++ b/src/filemanager.cpp @@ -786,75 +786,6 @@ std::unique_ptr<File> FileStdio::open(PJ_CONTEXT *ctx, const char *filename, // --------------------------------------------------------------------------- -#ifndef REMOVE_LEGACY_SUPPORT - -class FileLegacyAdapter : public File { - PJ_CONTEXT *m_ctx; - PAFile m_fp; - - FileLegacyAdapter(const FileLegacyAdapter &) = delete; - FileLegacyAdapter &operator=(const FileLegacyAdapter &) = delete; - - protected: - FileLegacyAdapter(const std::string &filename, PJ_CONTEXT *ctx, PAFile fp) - : File(filename), m_ctx(ctx), m_fp(fp) {} - - public: - ~FileLegacyAdapter() override; - - size_t read(void *buffer, size_t sizeBytes) override; - size_t write(const void *, size_t) override { return 0; } - bool seek(unsigned long long offset, int whence = SEEK_SET) override; - unsigned long long tell() override; - void reassign_context(PJ_CONTEXT *ctx) override { m_ctx = ctx; } - - // We may lie, but the real use case is only for network files - bool hasChanged() const override { return false; } - - static std::unique_ptr<File> open(PJ_CONTEXT *ctx, const char *filename, - FileAccess access); -}; - -// --------------------------------------------------------------------------- - -FileLegacyAdapter::~FileLegacyAdapter() { pj_ctx_fclose(m_ctx, m_fp); } - -// --------------------------------------------------------------------------- - -size_t FileLegacyAdapter::read(void *buffer, size_t sizeBytes) { - return pj_ctx_fread(m_ctx, buffer, 1, sizeBytes, m_fp); -} - -// --------------------------------------------------------------------------- - -bool FileLegacyAdapter::seek(unsigned long long offset, int whence) { - if (offset != static_cast<unsigned long long>(static_cast<long>(offset))) { - pj_log(m_ctx, PJ_LOG_ERROR, - "Attempt at seeking to a 64 bit offset. Not supported yet"); - return false; - } - return pj_ctx_fseek(m_ctx, m_fp, static_cast<long>(offset), whence) == 0; -} - -// --------------------------------------------------------------------------- - -unsigned long long FileLegacyAdapter::tell() { - return pj_ctx_ftell(m_ctx, m_fp); -} - -// --------------------------------------------------------------------------- - -std::unique_ptr<File> -FileLegacyAdapter::open(PJ_CONTEXT *ctx, const char *filename, FileAccess) { - auto fid = pj_ctx_fopen(ctx, filename, "rb"); - return std::unique_ptr<File>(fid ? new FileLegacyAdapter(filename, ctx, fid) - : nullptr); -} - -#endif // REMOVE_LEGACY_SUPPORT - -// --------------------------------------------------------------------------- - class FileApiAdapter : public File { PJ_CONTEXT *m_ctx; PROJ_FILE_HANDLE *m_fp; @@ -954,12 +885,6 @@ std::unique_ptr<File> FileManager::open(PJ_CONTEXT *ctx, const char *filename, } return pj_network_file_open(ctx, filename); } -#ifndef REMOVE_LEGACY_SUPPORT - // If the user has specified a legacy fileapi, use it - if (ctx->fileapi_legacy != pj_get_default_fileapi()) { - return FileLegacyAdapter::open(ctx, filename, access); - } -#endif if (ctx->fileApi.open_cbk != nullptr) { return FileApiAdapter::open(ctx, filename, access); } @@ -1444,10 +1369,10 @@ static bool dontReadUserWritableDirectory() { return envVar != nullptr && envVar[0] != '\0'; } -static void * -pj_open_lib_internal(projCtx ctx, const char *name, const char *mode, - void *(*open_file)(projCtx, const char *, const char *), - char *out_full_filename, size_t out_full_filename_size) { +static void *pj_open_lib_internal( + PJ_CONTEXT *ctx, const char *name, const char *mode, + void *(*open_file)(PJ_CONTEXT *, const char *, const char *), + char *out_full_filename, size_t out_full_filename_size) { try { std::string fname; const char *sysname = nullptr; @@ -1493,10 +1418,6 @@ pj_open_lib_internal(projCtx ctx, const char *name, const char *mode, ctx, name, ctx->file_finder_user_data)) != nullptr) ; - else if (ctx->file_finder_legacy != nullptr && - (sysname = ctx->file_finder_legacy(name)) != nullptr) - ; - /* The user has search paths set */ else if (!ctx->search_paths.empty()) { for (const auto &path : ctx->search_paths) { @@ -1566,7 +1487,7 @@ pj_open_lib_internal(projCtx ctx, const char *name, const char *mode, } if (ctx->last_errno == 0 && errno != 0) - pj_ctx_set_errno(ctx, errno); + proj_context_errno_set(ctx, errno); pj_log(ctx, PJ_LOG_DEBUG_MAJOR, "pj_open_lib(%s): call fopen(%s) - %s", name, sysname, fid == nullptr ? "failed" : "succeeded"); @@ -1617,7 +1538,7 @@ std::vector<std::string> pj_get_default_searchpaths(PJ_CONTEXT *ctx) { /* pj_open_file_with_manager() */ /************************************************************************/ -static void *pj_open_file_with_manager(projCtx ctx, const char *name, +static void *pj_open_file_with_manager(PJ_CONTEXT *ctx, const char *name, const char * /* mode */) { return NS_PROJ::FileManager::open(ctx, name, NS_PROJ::FileAccess::READ_ONLY) .release(); @@ -1639,7 +1560,7 @@ static NS_PROJ::io::DatabaseContextPtr getDBcontext(PJ_CONTEXT *ctx) { /************************************************************************/ std::unique_ptr<NS_PROJ::File> -NS_PROJ::FileManager::open_resource_file(projCtx ctx, const char *name) { +NS_PROJ::FileManager::open_resource_file(PJ_CONTEXT *ctx, const char *name) { if (ctx == nullptr) { ctx = pj_get_default_ctx(); @@ -1666,7 +1587,7 @@ NS_PROJ::FileManager::open_resource_file(projCtx ctx, const char *name) { pj_open_file_with_manager, nullptr, 0))); if (file) { - pj_ctx_set_errno(ctx, 0); + proj_context_errno_set(ctx, 0); } else { // For final network access attempt, use the new // name. @@ -1696,7 +1617,7 @@ NS_PROJ::FileManager::open_resource_file(projCtx ctx, const char *name) { pj_open_file_with_manager, nullptr, 0))); if (file) { - pj_ctx_set_errno(ctx, 0); + proj_context_errno_set(ctx, 0); } } } catch (const std::exception &e) { @@ -1721,7 +1642,7 @@ NS_PROJ::FileManager::open_resource_file(projCtx ctx, const char *name) { if (file) { pj_log(ctx, PJ_LOG_DEBUG_MAJOR, "Using %s", remote_file.c_str()); - pj_ctx_set_errno(ctx, 0); + proj_context_errno_set(ctx, 0); } } } @@ -1729,26 +1650,6 @@ NS_PROJ::FileManager::open_resource_file(projCtx ctx, const char *name) { } /************************************************************************/ -/* pj_open_lib() */ -/************************************************************************/ - -#ifndef REMOVE_LEGACY_SUPPORT - -// Used by following legacy function -static void *pj_ctx_fopen_adapter(projCtx ctx, const char *name, - const char *mode) { - return pj_ctx_fopen(ctx, name, mode); -} - -// Legacy function -PAFile pj_open_lib(projCtx ctx, const char *name, const char *mode) { - return (PAFile)pj_open_lib_internal(ctx, name, mode, pj_ctx_fopen_adapter, - nullptr, 0); -} - -#endif // REMOVE_LEGACY_SUPPORT - -/************************************************************************/ /* pj_find_file() */ /************************************************************************/ @@ -1764,7 +1665,7 @@ PAFile pj_open_lib(projCtx ctx, const char *name, const char *mode) { * @param out_full_filename_size size of out_full_filename. * @return 1 if the file was found, 0 otherwise. */ -int pj_find_file(projCtx ctx, const char *short_filename, +int pj_find_file(PJ_CONTEXT *ctx, const char *short_filename, char *out_full_filename, size_t out_full_filename_size) { auto file = std::unique_ptr<NS_PROJ::File>( reinterpret_cast<NS_PROJ::File *>(pj_open_lib_internal( @@ -1812,7 +1713,7 @@ static std::string trim(const std::string &s) { /* pj_load_ini() */ /************************************************************************/ -void pj_load_ini(projCtx ctx) { +void pj_load_ini(PJ_CONTEXT *ctx) { if (ctx->iniFileLoaded) return; @@ -1891,19 +1792,6 @@ void pj_load_ini(projCtx ctx) { //! @endcond /************************************************************************/ -/* pj_set_finder() */ -/************************************************************************/ - -void pj_set_finder(const char *(*new_finder)(const char *)) - -{ - auto ctx = pj_get_default_ctx(); - if (ctx) { - ctx->file_finder_legacy = new_finder; - } -} - -/************************************************************************/ /* proj_context_set_file_finder() */ /************************************************************************/ @@ -1974,19 +1862,6 @@ void proj_context_set_search_paths(PJ_CONTEXT *ctx, int count_paths, } /************************************************************************/ -/* pj_set_searchpath() */ -/* */ -/* Path control for callers that can't practically provide */ -/* pj_set_finder() style callbacks. Call with (0,NULL) as args */ -/* to clear the searchpath set. */ -/************************************************************************/ - -void pj_set_searchpath(int count, const char **path) { - proj_context_set_search_paths(nullptr, count, - const_cast<const char *const *>(path)); -} - -/************************************************************************/ /* proj_context_set_ca_bundle_path() */ /************************************************************************/ diff --git a/src/gauss.cpp b/src/gauss.cpp index a34a8f5b..96bd5166 100644 --- a/src/gauss.cpp +++ b/src/gauss.cpp @@ -81,7 +81,7 @@ void *pj_gauss_ini(double e, double phi0, double *chi, double *rc) { return ((void *)en); } -PJ_LP pj_gauss(projCtx ctx, PJ_LP elp, const void *data) { +PJ_LP pj_gauss(PJ_CONTEXT *ctx, PJ_LP elp, const void *data) { const struct GAUSS *en = (const struct GAUSS *)data; PJ_LP slp; (void) ctx; @@ -93,7 +93,7 @@ PJ_LP pj_gauss(projCtx ctx, PJ_LP elp, const void *data) { return(slp); } -PJ_LP pj_inv_gauss(projCtx ctx, PJ_LP slp, const void *data) { +PJ_LP pj_inv_gauss(PJ_CONTEXT *ctx, PJ_LP slp, const void *data) { const struct GAUSS *en = (const struct GAUSS *)data; PJ_LP elp; double num; @@ -109,6 +109,6 @@ PJ_LP pj_inv_gauss(projCtx ctx, PJ_LP slp, const void *data) { } /* convergence failed */ if (!i) - pj_ctx_set_errno(ctx, PJD_ERR_NON_CONV_INV_MERI_DIST); + proj_context_errno_set(ctx, PJD_ERR_NON_CONV_INV_MERI_DIST); return (elp); } diff --git a/src/generic_inverse.cpp b/src/generic_inverse.cpp index a15cfae1..ddd5060b 100644 --- a/src/generic_inverse.cpp +++ b/src/generic_inverse.cpp @@ -109,6 +109,6 @@ PJ_LP pj_generic_inverse_2d(PJ_XY xy, PJ *P, PJ_LP lpInitial) { lp.phi = M_HALFPI; } } - pj_ctx_set_errno(P->ctx, PJD_ERR_NON_CONVERGENT); + proj_context_errno_set(P->ctx, PJD_ERR_NON_CONVERGENT); return lp; } diff --git a/src/geodesic.c b/src/geodesic.c index 7d612d3f..53ec9ed6 100644 --- a/src/geodesic.c +++ b/src/geodesic.c @@ -18,7 +18,7 @@ * * See the comments in geodesic.h for documentation. * - * Copyright (c) Charles Karney (2012-2019) <charles@karney.com> and licensed + * Copyright (c) Charles Karney (2012-2020) <charles@karney.com> and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ */ @@ -28,15 +28,6 @@ #include <limits.h> #include <float.h> -#if !defined(HAVE_C99_MATH) -#if defined(PROJ_LIB) -/* PROJ requires C99 so HAVE_C99_MATH is implicit */ -#define HAVE_C99_MATH 1 -#else -#define HAVE_C99_MATH 0 -#endif -#endif - #if !defined(__cplusplus) #define nullptr 0 #endif @@ -88,19 +79,7 @@ static void Init() { tolb = tol0 * tol2; xthresh = 1000 * tol2; degree = pi/180; -#if defined(NAN) - NaN = NAN; /* NAN is defined in C99 */ -#else -#if HAVE_C99_MATH NaN = nan("0"); -#else - { - real minus1 = -1; - /* cppcheck-suppress wrongmathcall */ - NaN = sqrt(minus1); - } -#endif -#endif init = 1; } } @@ -116,95 +95,6 @@ enum captype { OUT_ALL = 0x7F80U }; -#if HAVE_C99_MATH -#define hypotx hypot -/* no need to redirect log1px, since it's only used by atanhx */ -#define atanhx atanh -#define copysignx copysign -#define cbrtx cbrt -#define remainderx remainder -#define remquox remquo -#else -/* Replacements for C99 math functions */ - -static real hypotx(real x, real y) { - x = fabs(x); y = fabs(y); - if (x < y) { - x /= y; /* y is nonzero */ - return y * sqrt(1 + x * x); - } else { - y /= (x != 0 ? x : 1); - return x * sqrt(1 + y * y); - } -} - -static real log1px(real x) { - volatile real - y = 1 + x, - z = y - 1; - /* Here's the explanation for this magic: y = 1 + z, exactly, and z - * approx x, thus log(y)/z (which is nearly constant near z = 0) returns - * a good approximation to the true log(1 + x)/x. The multiplication x * - * (log(y)/z) introduces little additional error. */ - return z == 0 ? x : x * log(y) / z; -} - -static real atanhx(real x) { - real y = fabs(x); /* Enforce odd parity */ - y = log1px(2 * y/(1 - y))/2; - return x > 0 ? y : (x < 0 ? -y : x); /* atanh(-0.0) = -0.0 */ -} - -static real copysignx(real x, real y) { - /* 1/y trick to get the sign of -0.0 */ - return fabs(x) * (y < 0 || (y == 0 && 1/y < 0) ? -1 : 1); -} - -static real cbrtx(real x) { - real y = pow(fabs(x), 1/(real)(3)); /* Return the real cube root */ - return x > 0 ? y : (x < 0 ? -y : x); /* cbrt(-0.0) = -0.0 */ -} - -static real remainderx(real x, real y) { - real z; - y = fabs(y); /* The result doesn't depend on the sign of y */ - z = fmod(x, y); - if (z == 0) - /* This shouldn't be necessary. However, before version 14 (2015), - * Visual Studio had problems dealing with -0.0. Specifically - * VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0 - * python 2.7 on Windows 32-bit machines has the same problem. */ - z = copysignx(z, x); - else if (2 * fabs(z) == y) - z -= fmod(x, 2 * y) - z; /* Implement ties to even */ - else if (2 * fabs(z) > y) - z += (z < 0 ? y : -y); /* Fold remaining cases to (-y/2, y/2) */ - return z; -} - -static real remquox(real x, real y, int* n) { - real z = remainderx(x, y); - if (n) { - real - a = remainderx(x, 2 * y), - b = remainderx(x, 4 * y), - c = remainderx(x, 8 * y); - *n = (a > z ? 1 : (a < z ? -1 : 0)); - *n += (b > a ? 2 : (b < a ? -2 : 0)); - *n += (c > b ? 4 : (c < b ? -4 : 0)); - if (y < 0) *n *= -1; - if (y != 0) { - if (x/y > 0 && *n <= 0) - *n += 8; - else if (x/y < 0 && *n >= 0) - *n -= 8; - } - } - return z; -} - -#endif - static real sq(real x) { return x * x; } static real sumx(real u, real v, real* t) { @@ -237,13 +127,13 @@ static void swapx(real* x, real* y) { real t = *x; *x = *y; *y = t; } static void norm2(real* sinx, real* cosx) { - real r = hypotx(*sinx, *cosx); + real r = hypot(*sinx, *cosx); *sinx /= r; *cosx /= r; } static real AngNormalize(real x) { - x = remainderx(x, (real)(360)); + x = remainder(x, (real)(360)); return x != -180 ? x : 180; } @@ -275,7 +165,7 @@ 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; - r = remquox(x, (real)(90), &q); + r = remquo(x, (real)(90), &q); /* now abs(r) <= 45 */ r *= degree; /* Possibly could call the gnu extension sincos */ @@ -396,7 +286,7 @@ void geod_init(struct geod_geodesic* g, real a, real f) { g->b = g->a * g->f1; g->c2 = (sq(g->a) + sq(g->b) * (g->e2 == 0 ? 1 : - (g->e2 > 0 ? atanhx(sqrt(g->e2)) : atan(sqrt(-g->e2))) / + (g->e2 > 0 ? atanh(sqrt(g->e2)) : atan(sqrt(-g->e2))) / sqrt(fabs(g->e2))))/2; /* authalic radius squared */ /* The sig12 threshold for "really short". Using the auxiliary sphere * solution with dnm computed at (bet1 + bet2) / 2, the relative error in the @@ -446,7 +336,7 @@ static void geod_lineinit_int(struct geod_geodesicline* l, l->salp0 = l->salp1 * cbet1; /* alp0 in [0, pi/2 - |bet1|] */ /* Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following * is slightly better (consider the case salp1 = 0). */ - l->calp0 = hypotx(l->calp1, l->salp1 * sbet1); + l->calp0 = hypot(l->calp1, l->salp1 * sbet1); /* Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1). * sig = 0 is nearest northward crossing of equator. * With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line). @@ -550,9 +440,8 @@ real geod_genposition(const struct geod_geodesicline* l, (pS12 ? GEOD_AREA : GEOD_NONE); outmask &= l->caps & OUT_ALL; - if (!( /*Init() &&*/ - (flags & GEOD_ARCMODE || (l->caps & (GEOD_DISTANCE_IN & OUT_ALL))) )) - /* Uninitialized or impossible distance calculation requested */ + if (!( (flags & GEOD_ARCMODE || (l->caps & (GEOD_DISTANCE_IN & OUT_ALL))) )) + /* Impossible distance calculation requested */ return NaN; if (flags & GEOD_ARCMODE) { @@ -617,7 +506,7 @@ real geod_genposition(const struct geod_geodesicline* l, /* sin(bet2) = cos(alp0) * sin(sig2) */ sbet2 = l->calp0 * ssig2; /* Alt: cbet2 = hypot(csig2, salp0 * ssig2); */ - cbet2 = hypotx(l->salp0, l->calp0 * csig2); + cbet2 = hypot(l->salp0, l->calp0 * csig2); if (cbet2 == 0) /* I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case */ cbet2 = csig2 = tiny; @@ -630,7 +519,7 @@ real geod_genposition(const struct geod_geodesicline* l, s12_a12; if (outmask & GEOD_LONGITUDE) { - real E = copysignx(1, l->salp0); /* east or west going? */ + real E = copysign(1, l->salp0); /* east or west going? */ /* tan(omg2) = sin(alp0) * tan(sig2) */ somg2 = l->salp0 * ssig2; comg2 = csig2; /* No need to normalize */ /* omg12 = omg2 - omg1 */ @@ -1045,7 +934,7 @@ static real geod_geninverse_int(const struct geod_geodesic* g, real /* From Lambda12: sin(alp1) * cos(bet1) = sin(alp0) */ salp0 = salp1 * cbet1, - calp0 = hypotx(calp1, salp1 * sbet1); /* calp0 > 0 */ + calp0 = hypot(calp1, salp1 * sbet1); /* calp0 > 0 */ real alp12; if (calp0 != 0 && salp0 != 0) { real @@ -1279,8 +1168,8 @@ real Astroid(real x, real y) { * of precision due to cancellation. The result is unchanged because * of the way the T is used in definition of u. */ T3 += T3 < 0 ? -sqrt(disc) : sqrt(disc); /* T3 = (r * t)^3 */ - /* N.B. cbrtx always returns the real root. cbrtx(-8) = -2. */ - T = cbrtx(T3); /* T = r * t */ + /* N.B. cbrt always returns the real root. cbrt(-8) = -2. */ + T = cbrt(T3); /* T = r * t */ /* T can be zero; but then r2 / T -> 0. */ u += T + (T != 0 ? r2 / T : 0); } else { @@ -1348,7 +1237,7 @@ real InverseStart(const struct geod_geodesic* g, sbet12 + cbet2 * sbet1 * sq(somg12) / (1 + comg12) : sbet12a - cbet2 * sbet1 * sq(somg12) / (1 - comg12); - ssig12 = hypotx(salp1, calp1); + ssig12 = hypot(salp1, calp1); csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12; if (shortline && ssig12 < g->etol2) { @@ -1500,7 +1389,7 @@ real Lambda12(const struct geod_geodesic* g, /* sin(alp1) * cos(bet1) = sin(alp0) */ salp0 = salp1 * cbet1; - calp0 = hypotx(calp1, salp1 * sbet1); /* calp0 > 0 */ + calp0 = hypot(calp1, salp1 * sbet1); /* calp0 > 0 */ /* tan(bet1) = tan(sig1) * cos(alp1) * tan(omg1) = sin(alp0) * tan(sig1) = tan(omg1)=tan(alp1)*sin(bet1) */ @@ -1850,8 +1739,8 @@ int transit(real lon1, real lon2) { int transitdirect(real lon1, real lon2) { /* Compute exactly the parity of int(ceil(lon2 / 360)) - int(ceil(lon1 / 360)) */ - lon1 = remainderx(lon1, (real)(720)); - lon2 = remainderx(lon2, (real)(720)); + lon1 = remainder(lon1, (real)(720)); + lon2 = remainder(lon2, (real)(720)); return ( (lon2 <= 0 && lon2 > -360 ? 1 : 0) - (lon1 <= 0 && lon1 > -360 ? 1 : 0) ); } @@ -1891,7 +1780,7 @@ void accneg(real s[]) { void accrem(real s[], real y) { /* Reduce to [-y/2, y/2]. */ - s[0] = remainderx(s[0], y); + s[0] = remainder(s[0], y); accadd(s, (real)(0)); } @@ -2093,7 +1982,7 @@ real areareduceA(real area[], real area0, real areareduceB(real area, real area0, int crossings, boolx reverse, boolx sign) { - area = remainderx(area, area0); + area = remainder(area, area0); if (crossings & 1) area += (area < 0 ? 1 : -1) * area0/2; /* area is with the clockwise sense. If !reverse convert to diff --git a/src/geodesic.h b/src/geodesic.h index b21e6c8c..548fbf47 100644 --- a/src/geodesic.h +++ b/src/geodesic.h @@ -107,12 +107,12 @@ * twice about restructuring the internals of the C code since this may make * porting fixes from the C++ code more difficult. * - * Copyright (c) Charles Karney (2012-2019) <charles@karney.com> and licensed + * Copyright (c) Charles Karney (2012-2020) <charles@karney.com> and licensed * under the MIT/X11 License. For more information, see * https://geographiclib.sourceforge.io/ * * This library was distributed with - * <a href="../index.html">GeographicLib</a> 1.50. + * <a href="../index.html">GeographicLib</a> 1.51. **********************************************************************/ #if !defined(GEODESIC_H) @@ -127,7 +127,7 @@ * The minor version of the geodesic library. (This tracks the version of * GeographicLib.) **********************************************************************/ -#define GEODESIC_VERSION_MINOR 50 +#define GEODESIC_VERSION_MINOR 51 /** * The patch level of the geodesic library. (This tracks the version of * GeographicLib.) diff --git a/src/grids.cpp b/src/grids.cpp index 8065813a..871e21ed 100644 --- a/src/grids.cpp +++ b/src/grids.cpp @@ -197,7 +197,7 @@ GTXVerticalShiftGrid *GTXVerticalShiftGrid::open(PJ_CONTEXT *ctx, /* Read the header. */ /* -------------------------------------------------------------------- */ if (fp->read(header, sizeof(header)) != sizeof(header)) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -223,7 +223,7 @@ GTXVerticalShiftGrid *GTXVerticalShiftGrid::open(PJ_CONTEXT *ctx, if (xorigin < -360 || xorigin > 360 || yorigin < -90 || yorigin > 90) { pj_log(ctx, PJ_LOG_ERROR, "gtx file header has invalid extents, corrupt?"); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -258,7 +258,7 @@ bool GTXVerticalShiftGrid::valueAt(int x, int y, float &out) const { m_fp->seek(40 + sizeof(float) * (y * m_width + x)); if (m_fp->read(&out, sizeof(out)) != sizeof(out)) { - pj_ctx_set_errno(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return false; } if (IS_LSB) { @@ -1389,7 +1389,7 @@ VerticalShiftGridSet::open(PJ_CONTEXT *ctx, const std::string &filename) { auto set = std::unique_ptr<VerticalShiftGridSet>( GTiffVGridShiftSet::open(ctx, std::move(fp), actualName)); if (!set) - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return set; #else pj_log(ctx, PJ_LOG_ERROR, @@ -1570,7 +1570,7 @@ NTv1Grid *NTv1Grid::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp, /* Read the header. */ /* -------------------------------------------------------------------- */ if (fp->read(header, sizeof(header)) != sizeof(header)) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -1590,7 +1590,7 @@ NTv1Grid *NTv1Grid::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp, if (*((int *)(header + 8)) != 12) { pj_log(ctx, PJ_LOG_ERROR, "NTv1 grid shift file has wrong record count, corrupt?"); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -1609,7 +1609,7 @@ NTv1Grid *NTv1Grid::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp, extent.resY > 1e-10)) { pj_log(ctx, PJ_LOG_ERROR, "Inconsistent georeferencing for %s", filename.c_str()); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } const int columns = static_cast<int>( @@ -1631,7 +1631,7 @@ bool NTv1Grid::valueAt(int x, int y, bool compensateNTConvention, m_fp->seek(192 + 2 * sizeof(double) * (y * m_width + m_width - 1 - x)); if (m_fp->read(&two_doubles[0], sizeof(two_doubles)) != sizeof(two_doubles)) { - pj_ctx_set_errno(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return false; } if (IS_LSB) { @@ -1692,7 +1692,7 @@ CTable2Grid *CTable2Grid::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp, /* Read the header. */ /* -------------------------------------------------------------------- */ if (fp->read(header, sizeof(header)) != sizeof(header)) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -1718,7 +1718,7 @@ CTable2Grid *CTable2Grid::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp, extent.resX > 1e-10 && extent.resY > 1e-10)) { pj_log(ctx, PJ_LOG_ERROR, "Inconsistent georeferencing for %s", filename.c_str()); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } int width; @@ -1726,7 +1726,7 @@ CTable2Grid *CTable2Grid::open(PJ_CONTEXT *ctx, std::unique_ptr<File> fp, memcpy(&width, header + 128, 4); memcpy(&height, header + 132, 4); if (width <= 0 || height <= 0) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } extent.east = extent.west + (width - 1) * extent.resX; @@ -1744,7 +1744,7 @@ bool CTable2Grid::valueAt(int x, int y, bool compensateNTConvention, float two_floats[2]; m_fp->seek(160 + 2 * sizeof(float) * (y * m_width + x)); if (m_fp->read(&two_floats[0], sizeof(two_floats)) != sizeof(two_floats)) { - pj_ctx_set_errno(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return false; } if (!IS_LSB) { @@ -1828,7 +1828,7 @@ bool NTv2Grid::valueAt(int x, int y, bool compensateNTConvention, 4 * sizeof(float) * (static_cast<unsigned long long>(y) * m_width + m_width - 1 - x)); if (m_fp->read(&two_float[0], sizeof(two_float)) != sizeof(two_float)) { - pj_ctx_set_errno(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(m_ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return false; } if (m_mustSwap) { @@ -1862,14 +1862,14 @@ std::unique_ptr<NTv2GridSet> NTv2GridSet::open(PJ_CONTEXT *ctx, /* Read the header. */ /* -------------------------------------------------------------------- */ if (fpRaw->read(header, sizeof(header)) != sizeof(header)) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } constexpr int OFFSET_GS_TYPE = 56; if (memcmp(header + OFFSET_GS_TYPE, "SECONDS", 7) != 0) { pj_log(ctx, PJ_LOG_ERROR, "Only GS_TYPE=SECONDS is supported"); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -1899,12 +1899,12 @@ std::unique_ptr<NTv2GridSet> NTv2GridSet::open(PJ_CONTEXT *ctx, for (unsigned subfile = 0; subfile < num_subfiles; subfile++) { // Read header if (fpRaw->read(header, sizeof(header)) != sizeof(header)) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } if (strncmp(header, "SUB_NAME", 8) != 0) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -1946,7 +1946,7 @@ std::unique_ptr<NTv2GridSet> NTv2GridSet::open(PJ_CONTEXT *ctx, extent.resY > 1e-10)) { pj_log(ctx, PJ_LOG_ERROR, "Inconsistent georeferencing for %s", filename.c_str()); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } const int columns = static_cast<int>( @@ -1966,7 +1966,7 @@ std::unique_ptr<NTv2GridSet> NTv2GridSet::open(PJ_CONTEXT *ctx, pj_log(ctx, PJ_LOG_ERROR, "GS_COUNT(%u) does not match expected cells (%dx%d)", gs_count, columns, rows); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return nullptr; } @@ -2367,7 +2367,7 @@ HorizontalShiftGridSet::open(PJ_CONTEXT *ctx, const std::string &filename) { auto set = std::unique_ptr<HorizontalShiftGridSet>( GTiffHGridShiftSet::open(ctx, std::move(fp), actualName)); if (!set) - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return set; #else pj_log(ctx, PJ_LOG_ERROR, @@ -2703,7 +2703,7 @@ GenericShiftGridSet::open(PJ_CONTEXT *ctx, const std::string &filename) { auto set = std::unique_ptr<GenericShiftGridSet>( GTiffGenericGridShiftSet::open(ctx, std::move(fp), actualName)); if (!set) - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return set; #else pj_log(ctx, PJ_LOG_ERROR, @@ -2786,11 +2786,12 @@ ListOfGenericGrids pj_generic_grid_init(PJ *P, const char *gridkey) { if (!gridSet) { if (!canFail) { if (proj_context_errno(P->ctx) != PJD_ERR_NETWORK_ERROR) { - pj_ctx_set_errno(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); } return {}; } - pj_ctx_set_errno(P->ctx, 0); // don't treat as a persistent error + proj_context_errno_set(P->ctx, + 0); // don't treat as a persistent error } else { grids.emplace_back(std::move(gridSet)); } @@ -2830,11 +2831,11 @@ static ListOfHGrids getListOfGridSets(PJ_CONTEXT *ctx, const char *grids) { if (!gridSet) { if (!canFail) { if (proj_context_errno(ctx) != PJD_ERR_NETWORK_ERROR) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); } return {}; } - pj_ctx_set_errno(ctx, 0); // don't treat as a persistent error + proj_context_errno_set(ctx, 0); // don't treat as a persistent error } else { list.emplace_back(std::move(gridSet)); } @@ -2948,7 +2949,7 @@ static PJ_LP pj_hgrid_interpolate(PJ_LP t, const HorizontalShiftGrid *grid, #define MAX_ITERATIONS 10 #define TOL 1e-12 -static PJ_LP pj_hgrid_apply_internal(projCtx ctx, PJ_LP in, +static PJ_LP pj_hgrid_apply_internal(PJ_CONTEXT *ctx, PJ_LP in, PJ_DIRECTION direction, const HorizontalShiftGrid *grid, HorizontalShiftGridSet *gridset, @@ -3066,7 +3067,7 @@ PJ_LP pj_hgrid_apply(PJ_CONTEXT *ctx, const ListOfHGrids &grids, PJ_LP lp, HorizontalShiftGridSet *gridset = nullptr; const auto grid = findGrid(grids, lp, gridset); if (!grid) { - pj_ctx_set_errno(ctx, PJD_ERR_GRID_AREA); + proj_context_errno_set(ctx, PJD_ERR_GRID_AREA); return out; } if (grid->isNullGrid()) { @@ -3082,7 +3083,7 @@ PJ_LP pj_hgrid_apply(PJ_CONTEXT *ctx, const ListOfHGrids &grids, PJ_LP lp, } if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) - pj_ctx_set_errno(ctx, PJD_ERR_GRID_AREA); + proj_context_errno_set(ctx, PJD_ERR_GRID_AREA); return out; } @@ -3098,7 +3099,7 @@ PJ_LP pj_hgrid_value(PJ *P, const ListOfHGrids &grids, PJ_LP lp) { HorizontalShiftGridSet *gridset = nullptr; const auto grid = findGrid(grids, lp, gridset); if (!grid) { - pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); + proj_context_errno_set(P->ctx, PJD_ERR_GRID_AREA); return out; } @@ -3107,7 +3108,7 @@ PJ_LP pj_hgrid_value(PJ *P, const ListOfHGrids &grids, PJ_LP lp) { if (!extent.isGeographic) { pj_log(P->ctx, PJ_LOG_ERROR, "Can only handle grids referenced in a geographic CRS"); - pj_ctx_set_errno(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return out; } @@ -3130,7 +3131,7 @@ PJ_LP pj_hgrid_value(PJ *P, const ListOfHGrids &grids, PJ_LP lp) { } if (out.lam == HUGE_VAL || out.phi == HUGE_VAL) { - pj_ctx_set_errno(P->ctx, PJD_ERR_GRID_AREA); + proj_context_errno_set(P->ctx, PJD_ERR_GRID_AREA); } return out; @@ -3157,7 +3158,7 @@ static double read_vgrid_value(PJ_CONTEXT *ctx, const ListOfVGrids &grids, } } if (!grid) { - pj_ctx_set_errno(ctx, PJD_ERR_GRID_AREA); + proj_context_errno_set(ctx, PJD_ERR_GRID_AREA); return HUGE_VAL; } if (grid->isNullGrid()) { @@ -3168,7 +3169,7 @@ static double read_vgrid_value(PJ_CONTEXT *ctx, const ListOfVGrids &grids, if (!extent.isGeographic) { pj_log(ctx, PJ_LOG_ERROR, "Can only handle grids referenced in a geographic CRS"); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return HUGE_VAL; } @@ -3200,7 +3201,7 @@ static double read_vgrid_value(PJ_CONTEXT *ctx, const ListOfVGrids &grids, if (!(grid_ix >= 0 && grid_ix < grid->width())) { // in the unlikely case we end up here... pj_log(ctx, PJ_LOG_ERROR, "grid_ix not in grid"); - pj_ctx_set_errno(ctx, PJD_ERR_GRID_AREA); + proj_context_errno_set(ctx, PJD_ERR_GRID_AREA); return HUGE_VAL; } int grid_iy = static_cast<int>(lround(floor(grid_y))); @@ -3309,11 +3310,12 @@ ListOfVGrids pj_vgrid_init(PJ *P, const char *gridkey) { if (!gridSet) { if (!canFail) { if (proj_context_errno(P->ctx) != PJD_ERR_NETWORK_ERROR) { - pj_ctx_set_errno(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(P->ctx, PJD_ERR_FAILED_TO_LOAD_GRID); } return {}; } - pj_ctx_set_errno(P->ctx, 0); // don't treat as a persistent error + proj_context_errno_set(P->ctx, + 0); // don't treat as a persistent error } else { grids.emplace_back(std::move(gridSet)); } @@ -3377,7 +3379,7 @@ bool pj_bilinear_interpolation_three_samples( if (!extent.isGeographic) { pj_log(ctx, PJ_LOG_ERROR, "Can only handle grids referenced in a geographic CRS"); - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); + proj_context_errno_set(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); return false; } @@ -3442,50 +3444,3 @@ bool pj_bilinear_interpolation_three_samples( } NS_PROJ_END - -/************************************************************************/ -/* pj_apply_gridshift() */ -/* */ -/* This is the externally callable interface - part of the */ -/* public API - though it is not used internally any more and I */ -/* doubt it is used by any other applications. But we preserve */ -/* it to honour our public api. */ -/************************************************************************/ - -int pj_apply_gridshift(projCtx ctx, const char *nadgrids, int inverse, - long point_count, int point_offset, double *x, double *y, - double * /*z */) - -{ - auto hgrids = NS_PROJ::getListOfGridSets(ctx, nadgrids); - if (hgrids.empty()) { - pj_ctx_set_errno(ctx, PJD_ERR_FAILED_TO_LOAD_GRID); - return 1; - } - - for (long i = 0; i < point_count; i++) { - PJ_LP input; - - long io = i * point_offset; - input.phi = y[io]; - input.lam = x[io]; - - auto output = - pj_hgrid_apply(ctx, hgrids, input, inverse ? PJ_INV : PJ_FWD); - - if (output.lam != HUGE_VAL) { - y[io] = output.phi; - x[io] = output.lam; - } else { - if (ctx->debug_level >= PJ_LOG_DEBUG_MAJOR) { - pj_log(ctx, PJ_LOG_DEBUG_MAJOR, - "pj_apply_gridshift(): failed to find a grid shift " - "table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, y[io] * RAD_TO_DEG); - } - } - } - - return 0; -} diff --git a/src/init.cpp b/src/init.cpp index 101fc8ad..1e89402d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1,7 +1,7 @@ /****************************************************************************** * Project: PROJ.4 * Purpose: Initialize projection object from string definition. Includes - * pj_init(), pj_init_plus() and pj_free() function. + * pj_init(), and pj_init_plus() function. * Author: Gerald Evenden, Frank Warmerdam <warmerdam@pobox.com> * ****************************************************************************** @@ -55,7 +55,7 @@ static paralist *string_to_paralist (PJ_CONTEXT *ctx, char *definition) { /* Keep a handle to the start of the list, so we have something to return */ auto param = pj_mkparam_ws (c, &c); if (nullptr==param) { - pj_dealloc_params (ctx, first, ENOMEM); + free_params (ctx, first, ENOMEM); return nullptr; } if (nullptr==last) { @@ -84,7 +84,7 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { char *buffer = nullptr; size_t n; - fname = static_cast<char*>(pj_malloc (MAX_PATH_FILENAME+ID_TAG_MAX+3)); + fname = static_cast<char*>(malloc (MAX_PATH_FILENAME+ID_TAG_MAX+3)); if (nullptr==fname) { return nullptr; } @@ -96,7 +96,7 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { else key += 5; if (MAX_PATH_FILENAME + ID_TAG_MAX + 2 < strlen (key)) { - pj_dealloc (fname); + free (fname); return nullptr; } memmove (fname, key, strlen (key) + 1); @@ -105,7 +105,7 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { section = strrchr(fname, ':'); if (nullptr==section) { proj_context_errno_set (ctx, PJD_ERR_NO_COLON_IN_INIT_STRING); - pj_dealloc (fname); + free (fname); return nullptr; } *section = 0; @@ -117,7 +117,7 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { auto file = NS_PROJ::FileManager::open_resource_file(ctx, fname); if (nullptr==file) { - pj_dealloc (fname); + free (fname); proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); return nullptr; } @@ -131,7 +131,7 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { line = file->read_line(MAX_LINE_LENGTH, maxLenReached, eofReached); /* End of file? */ if (maxLenReached || eofReached) { - pj_dealloc (fname); + free (fname); proj_context_errno_set (ctx, PJD_ERR_NO_OPTION_IN_INIT_FILE); return nullptr; } @@ -149,9 +149,9 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { } /* We're at the first line of the right section - copy line to buffer */ - buffer = static_cast<char*>(pj_malloc (current_buffer_size)); + buffer = static_cast<char*>(malloc (current_buffer_size)); if (nullptr==buffer) { - pj_dealloc (fname); + free (fname); return nullptr; } @@ -183,22 +183,22 @@ static char *get_init_string (PJ_CONTEXT *ctx, const char *name) { pj_chomp (&line[0]); /* Remove '#' style comments */ next_length = strlen (line.data()) + buffer_length + 2; if (next_length > current_buffer_size) { - char *b = static_cast<char*>(pj_malloc (2 * current_buffer_size)); + char *b = static_cast<char*>(malloc (2 * current_buffer_size)); if (nullptr==b) { - pj_dealloc (buffer); + free (buffer); buffer = nullptr; break; } strcpy (b, buffer); current_buffer_size *= 2; - pj_dealloc (buffer); + free (buffer); buffer = b; } buffer[buffer_length] = ' '; strcpy (buffer + buffer_length + 1, line.data()); } - pj_dealloc (fname); + free (fname); if (nullptr==buffer) return nullptr; pj_shrink (buffer); @@ -257,7 +257,7 @@ Expand key from buffer or (if not in buffer) from init file PJ* src; const char* proj_string; - pj_ctx_set_errno( ctx, 0 ); + proj_context_errno_set( ctx, 0 ); if( !allow_init_epsg ) { pj_log (ctx, PJ_LOG_TRACE, "%s expansion disallowed", xkey); @@ -306,7 +306,7 @@ Expand key from buffer or (if not in buffer) from init file definition, init_items->param, init_items->next ? init_items->next->param : "(empty)"); - pj_dealloc (definition); + free (definition); if (nullptr==init_items) return nullptr; @@ -400,90 +400,6 @@ paralist *pj_expand_init(PJ_CONTEXT *ctx, paralist *init) { /************************************************************************/ -/* pj_init_plus() */ -/* */ -/* Same as pj_init() except it takes one argument string with */ -/* individual arguments preceded by '+', such as "+proj=utm */ -/* +zone=11 +ellps=WGS84". */ -/************************************************************************/ - -PJ * -pj_init_plus( const char *definition ) - -{ - return pj_init_plus_ctx( pj_get_default_ctx(), definition ); -} - -PJ * -pj_init_plus_ctx( projCtx ctx, const char *definition ) -{ -#define MAX_ARG 200 - char *argv[MAX_ARG]; - char *defn_copy; - int argc = 0, i, blank_count = 0; - PJ *result = nullptr; - - /* make a copy that we can manipulate */ - defn_copy = (char *) pj_malloc( strlen(definition)+1 ); - if (!defn_copy) - return nullptr; - strcpy( defn_copy, definition ); - - /* split into arguments based on '+' and trim white space */ - - for( i = 0; defn_copy[i] != '\0'; i++ ) - { - switch( defn_copy[i] ) - { - case '+': - if( i == 0 || defn_copy[i-1] == '\0' || blank_count > 0 ) - { - /* trim trailing spaces from the previous param */ - if( blank_count > 0 ) - { - defn_copy[i - blank_count] = '\0'; - blank_count = 0; - } - - if( argc+1 == MAX_ARG ) - { - pj_dalloc( defn_copy ); - pj_ctx_set_errno( ctx, PJD_ERR_UNPARSEABLE_CS_DEF ); - return nullptr; - } - - argv[argc++] = defn_copy + i + 1; - } - break; - - case ' ': - case '\t': - case '\n': - /* trim leading spaces from the current param */ - if( i == 0 || defn_copy[i-1] == '\0' || argc == 0 || argv[argc-1] == defn_copy + i ) - defn_copy[i] = '\0'; - else - blank_count++; - break; - - default: - /* reset blank_count */ - blank_count = 0; - } - } - /* trim trailing spaces from the last param */ - defn_copy[i - blank_count] = '\0'; - - /* perform actual initialization */ - result = pj_init_ctx( ctx, argc, argv ); - - pj_dalloc( defn_copy ); - return result; -} - - - -/************************************************************************/ /* pj_init() */ /* */ /* Main entry point for initialing a PJ projections */ @@ -492,11 +408,6 @@ pj_init_plus_ctx( projCtx ctx, const char *definition ) /* large enough to hold projection specific parameters. */ /************************************************************************/ -PJ * -pj_init(int argc, char **argv) { - return pj_init_ctx( pj_get_default_ctx(), argc, argv ); -} - static PJ_CONSTRUCTOR locate_constructor (const char *name) { int i; @@ -511,15 +422,7 @@ static PJ_CONSTRUCTOR locate_constructor (const char *name) { PJ * -pj_init_ctx(projCtx ctx, int argc, char **argv) { - /* Legacy interface: allow init=epsg:XXXX syntax by default */ - int allow_init_epsg = proj_context_get_use_proj4_init_rules(ctx, TRUE); - return pj_init_ctx_with_allow_init_epsg(ctx, argc, argv, allow_init_epsg); -} - - -PJ * -pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_init_epsg) { +pj_init_ctx_with_allow_init_epsg(PJ_CONTEXT *ctx, int argc, char **argv, int allow_init_epsg) { const char *s; char *name; PJ_CONSTRUCTOR proj; @@ -538,7 +441,7 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i ctx->last_errno = 0; if (argc <= 0) { - pj_ctx_set_errno (ctx, PJD_ERR_NO_ARGS); + proj_context_errno_set (ctx, PJD_ERR_NO_ARGS); return nullptr; } @@ -552,13 +455,13 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i /* can't have nested pipelines directly */ if (n_pipelines > 1) { - pj_ctx_set_errno (ctx, PJD_ERR_MALFORMED_PIPELINE); + proj_context_errno_set (ctx, PJD_ERR_MALFORMED_PIPELINE); return nullptr; } /* don't allow more than one +init in non-pipeline operations */ if (n_pipelines == 0 && n_inits > 1) { - pj_ctx_set_errno (ctx, PJD_ERR_TOO_MANY_INITS); + proj_context_errno_set (ctx, PJD_ERR_TOO_MANY_INITS); return nullptr; } @@ -566,14 +469,14 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i /* put arguments into internal linked list */ start = curr = pj_mkparam(argv[0]); if (!curr) { - pj_dealloc_params (ctx, start, ENOMEM); + free_params (ctx, start, ENOMEM); return nullptr; } for (i = 1; i < argc; ++i) { curr->next = pj_mkparam(argv[i]); if (!curr->next) { - pj_dealloc_params (ctx, start, ENOMEM); + free_params (ctx, start, ENOMEM); return nullptr; } curr = curr->next; @@ -588,31 +491,31 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i if (init && n_pipelines == 0) { init = pj_expand_init_internal (ctx, init, allow_init_epsg); if (!init) { - pj_dealloc_params (ctx, start, PJD_ERR_NO_ARGS); + free_params (ctx, start, PJD_ERR_NO_ARGS); return nullptr; } } if (ctx->last_errno) { - pj_dealloc_params (ctx, start, ctx->last_errno); + free_params (ctx, start, ctx->last_errno); return nullptr; } /* Find projection selection */ curr = pj_param_exists (start, "proj"); if (nullptr==curr) { - pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); + free_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); return nullptr; } name = curr->param; if (strlen (name) < 6) { - pj_dealloc_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); + free_params (ctx, start, PJD_ERR_PROJ_NOT_NAMED); return nullptr; } name += 5; proj = locate_constructor (name); if (nullptr==proj) { - pj_dealloc_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID); + free_params (ctx, start, PJD_ERR_UNKNOWN_PROJECTION_ID); return nullptr; } @@ -621,7 +524,7 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i /* Allocate projection structure */ PIN = proj(nullptr); if (nullptr==PIN) { - pj_dealloc_params (ctx, start, ENOMEM); + free_params (ctx, start, ENOMEM); return nullptr; } @@ -820,7 +723,7 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i PIN->from_greenwich = 0.0; /* Private object for the geodesic functions */ - PIN->geod = static_cast<struct geod_geodesic*>(pj_calloc (1, sizeof (struct geod_geodesic))); + PIN->geod = static_cast<struct geod_geodesic*>(calloc (1, sizeof (struct geod_geodesic))); if (nullptr==PIN->geod) return pj_default_destructor (PIN, ENOMEM); geod_init(PIN->geod, PIN->a, (1 - sqrt (1 - PIN->es))); @@ -829,7 +732,7 @@ pj_init_ctx_with_allow_init_epsg(projCtx ctx, int argc, char **argv, int allow_i err = proj_errno_reset (PIN); PIN = proj(PIN); if (proj_errno (PIN)) { - pj_free(PIN); + proj_destroy(PIN); return nullptr; } proj_errno_restore (PIN, err); diff --git a/src/initcache.cpp b/src/initcache.cpp index af20fb82..cf9460ab 100644 --- a/src/initcache.cpp +++ b/src/initcache.cpp @@ -48,7 +48,7 @@ paralist *pj_clone_paralist( const paralist *list) for( ; list != nullptr; list = list->next ) { paralist *newitem = (paralist *) - pj_malloc(sizeof(paralist) + strlen(list->param)); + malloc(sizeof(paralist) + strlen(list->param)); newitem->used = 0; newitem->next = nullptr; @@ -83,17 +83,17 @@ void pj_clear_initcache() { paralist *n, *t = cache_paralist[i]; - pj_dalloc( cache_key[i] ); + free( cache_key[i] ); /* free parameter list elements */ for (; t != nullptr; t = n) { n = t->next; - pj_dalloc(t); + free(t); } } - pj_dalloc( cache_key ); - pj_dalloc( cache_paralist ); + free( cache_key ); + free( cache_paralist ); cache_count = 0; cache_alloc= 0; cache_key = nullptr; @@ -151,29 +151,29 @@ void pj_insert_initcache( const char *filekey, const paralist *list ) cache_alloc = cache_alloc * 2 + 15; - cache_key_new = (char **) pj_malloc(sizeof(char*) * cache_alloc); + cache_key_new = (char **) malloc(sizeof(char*) * cache_alloc); if( cache_key && cache_count ) { memcpy( cache_key_new, cache_key, sizeof(char*) * cache_count); } - pj_dalloc( cache_key ); + free( cache_key ); cache_key = cache_key_new; cache_paralist_new = (paralist **) - pj_malloc(sizeof(paralist*) * cache_alloc); + malloc(sizeof(paralist*) * cache_alloc); if( cache_paralist && cache_count ) { memcpy( cache_paralist_new, cache_paralist, sizeof(paralist*) * cache_count ); } - pj_dalloc( cache_paralist ); + free( cache_paralist ); cache_paralist = cache_paralist_new; } /* ** Duplicate the filekey and paralist, and insert in cache. */ - cache_key[cache_count] = (char *) pj_malloc(strlen(filekey)+1); + cache_key[cache_count] = (char *) malloc(strlen(filekey)+1); strcpy( cache_key[cache_count], filekey ); cache_paralist[cache_count] = pj_clone_paralist( list ); diff --git a/src/internal.cpp b/src/internal.cpp index 91994077..175ffa9b 100644 --- a/src/internal.cpp +++ b/src/internal.cpp @@ -141,15 +141,15 @@ Check if a a PJ has an inverse. void proj_context_set (PJ *P, PJ_CONTEXT *ctx) { if (nullptr==ctx) ctx = pj_get_default_ctx (); - pj_set_ctx (P, ctx); + proj_assign_context (P, ctx); } void proj_context_inherit (PJ *parent, PJ *child) { if (nullptr==parent) - pj_set_ctx (child, pj_get_default_ctx()); + proj_assign_context (child, pj_get_default_ctx()); else - pj_set_ctx (child, pj_get_ctx(parent)); + proj_assign_context (child, pj_get_ctx(parent)); } @@ -411,13 +411,16 @@ to that context. ******************************************************************************/ if (nullptr==ctx) ctx = pj_get_default_ctx(); - pj_ctx_set_errno (ctx, err); + ctx->last_errno = err; + if( err == 0 ) + return; + errno = err; } /* logging */ /* pj_vlog resides in pj_log.c and relates to pj_log as vsprintf relates to sprintf */ -void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ); +void pj_vlog( PJ_CONTEXT *ctx, int level, const char *fmt, va_list args ); /***************************************************************************************/ diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 7582f37f..6bc1f166 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -79,10 +79,10 @@ static void PROJ_NO_INLINE proj_log_error(PJ_CONTEXT *ctx, const char *function, msg += ": "; msg += text; ctx->logger(ctx->logger_app_data, PJ_LOG_ERROR, msg.c_str()); - auto previous_errno = pj_ctx_get_errno(ctx); + auto previous_errno = proj_context_errno(ctx); if (previous_errno == 0) { // only set errno if it wasn't set deeper down the call stack - pj_ctx_set_errno(ctx, PJD_ERR_GENERIC_ERROR); + proj_context_errno_set(ctx, PJD_ERR_GENERIC_ERROR); } } @@ -675,6 +675,9 @@ PJ *proj_create_from_database(PJ_CONTEXT *ctx, const char *auth_name, codeStr, usePROJAlternativeGridNames != 0) .as_nullable(); break; + case PJ_CATEGORY_DATUM_ENSEMBLE: + obj = factory->createDatumEnsemble(codeStr).as_nullable(); + break; } return pj_obj_create(ctx, NN_NO_CHECK(obj)); } catch (const std::exception &e) { @@ -916,7 +919,7 @@ convertPJObjectTypeToObjectType(PJ_TYPE type, bool &valid) { break; case PJ_TYPE_DATUM_ENSEMBLE: - cppType = AuthorityFactory::ObjectType::DATUM; + cppType = AuthorityFactory::ObjectType::DATUM_ENSEMBLE; break; case PJ_TYPE_TEMPORAL_DATUM: @@ -1418,6 +1421,13 @@ const char *proj_get_id_code(const PJ *obj, int index) { * variants, for WKT1_GDAL for ProjectedCRS with easting/northing ordering * (otherwise stripped), but not for WKT1_ESRI. Setting to YES will output * them unconditionally, and to NO will omit them unconditionally.</li> + * <li>STRICT=YES/NO. Default is YES. If NO, a Geographic 3D CRS can be for + * example exported as WKT1_GDAL with 3 axes, whereas this is normally not + * allowed.</li> + * <li>ALLOW_ELLIPSOIDAL_HEIGHT_AS_VERTICAL_CRS=YES/NO. Default is NO. If set + * to YES and type == PJ_WKT1_GDAL, a Geographic 3D CRS or a Projected 3D CRS + * will be exported as a compound CRS whose vertical part represents an + * ellipsoidal height (for example for use with LAS 1.4 WKT1).</li> * </ul> * @return a string, or NULL in case of error. */ @@ -1468,6 +1478,11 @@ const char *proj_as_wkt(PJ_CONTEXT *ctx, const PJ *obj, PJ_WKT_TYPE type, } } else if ((value = getOptionValue(*iter, "STRICT="))) { formatter->setStrict(ci_equal(value, "YES")); + } else if ((value = getOptionValue( + *iter, + "ALLOW_ELLIPSOIDAL_HEIGHT_AS_VERTICAL_CRS="))) { + formatter->setAllowEllipsoidalHeightAsVerticalCRS( + ci_equal(value, "YES")); } else { std::string msg("Unknown option :"); msg += *iter; @@ -2050,6 +2065,8 @@ PJ *proj_get_ellipsoid(PJ_CONTEXT *ctx, const PJ *obj) { /** \brief Get the horizontal datum from a CRS * + * This function may return a Datum or DatumEnsemble object. + * * The returned object must be unreferenced with proj_destroy() after * use. * It should be used by at most one thread at a time. @@ -2685,11 +2702,11 @@ proj_get_crs_info_list_from_database(PJ_CONTEXT *ctx, const char *auth_name, void proj_crs_info_list_destroy(PROJ_CRS_INFO **list) { if (list) { for (int i = 0; list[i] != nullptr; i++) { - pj_dalloc(list[i]->auth_name); - pj_dalloc(list[i]->code); - pj_dalloc(list[i]->name); - pj_dalloc(list[i]->area_name); - pj_dalloc(list[i]->projection_method_name); + free(list[i]->auth_name); + free(list[i]->code); + free(list[i]->name); + free(list[i]->area_name); + free(list[i]->projection_method_name); delete list[i]; } delete[] list; @@ -2779,11 +2796,11 @@ PROJ_UNIT_INFO **proj_get_units_from_database(PJ_CONTEXT *ctx, void proj_unit_list_destroy(PROJ_UNIT_INFO **list) { if (list) { for (int i = 0; list[i] != nullptr; i++) { - pj_dalloc(list[i]->auth_name); - pj_dalloc(list[i]->code); - pj_dalloc(list[i]->name); - pj_dalloc(list[i]->category); - pj_dalloc(list[i]->proj_short_name); + free(list[i]->auth_name); + free(list[i]->code); + free(list[i]->name); + free(list[i]->category); + free(list[i]->proj_short_name); delete list[i]; } delete[] list; @@ -4438,8 +4455,9 @@ PJ *proj_create_cartesian_2D_cs(PJ_CONTEXT *ctx, PJ_CARTESIAN_CS_2D_TYPE type, * * @param ctx PROJ context, or NULL for default context * @param type Coordinate system type. - * @param unit_name Unit name. - * @param unit_conv_factor Unit conversion factor to SI. + * @param unit_name Name of the angular units. Or NULL for Degree + * @param unit_conv_factor Conversion factor from the angular unit to radian. + * Or 0 for Degree if unit_name == NULL. Otherwise should be not NULL * * @return Object that must be unreferenced with * proj_destroy(), or NULL in case of error. @@ -4478,13 +4496,17 @@ PJ *proj_create_ellipsoidal_2D_cs(PJ_CONTEXT *ctx, * * @param ctx PROJ context, or NULL for default context * @param type Coordinate system type. - * @param horizontal_angular_unit_name Horizontal angular unit name. - * @param horizontal_angular_unit_conv_factor Horizontal angular unit conversion - * factor to SI. - * @param vertical_linear_unit_name Vertical linear unit name. + * @param horizontal_angular_unit_name Name of the angular units. Or NULL for + * Degree. + * @param horizontal_angular_unit_conv_factor Conversion factor from the angular + * unit to radian. Or 0 for Degree if horizontal_angular_unit_name == NULL. + * Otherwise should be not NULL + * @param vertical_linear_unit_name Vertical linear unit name. Or NULL for + * Metre. * @param vertical_linear_unit_conv_factor Vertical linear unit conversion - * factor to SI. - * + * factor to metre. Or 0 for Metre if vertical_linear_unit_name == NULL. + * Otherwise should be not NULL + * @return Object that must be unreferenced with * proj_destroy(), or NULL in case of error. * @since 6.3 @@ -7987,6 +8009,9 @@ double proj_coordoperation_get_accuracy(PJ_CONTEXT *ctx, /** \brief Returns the datum of a SingleCRS. * + * If that function returns NULL, @see proj_crs_get_datum_ensemble() to + * potentially get a DatumEnsemble instead. + * * The returned object must be unreferenced with proj_destroy() after * use. * It should be used by at most one thread at a time. @@ -8018,6 +8043,9 @@ PJ *proj_crs_get_datum(PJ_CONTEXT *ctx, const PJ *crs) { /** \brief Returns the datum ensemble of a SingleCRS. * + * If that function returns NULL, @see proj_crs_get_datum() to + * potentially get a Datum instead. + * * The returned object must be unreferenced with proj_destroy() after * use. * It should be used by at most one thread at a time. diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index be15b3e0..83b626b3 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -64,6 +64,30 @@ // #define DEBUG_CONCATENATED_OPERATION #if defined(DEBUG_SORT) || defined(DEBUG_CONCATENATED_OPERATION) #include <iostream> + +void dumpWKT(const NS_PROJ::crs::CRS *crs); +void dumpWKT(const NS_PROJ::crs::CRS *crs) { + auto f(NS_PROJ::io::WKTFormatter::create( + NS_PROJ::io::WKTFormatter::Convention::WKT2_2019)); + std::cerr << crs->exportToWKT(f.get()) << std::endl; +} + +void dumpWKT(const NS_PROJ::crs::CRSPtr &crs); +void dumpWKT(const NS_PROJ::crs::CRSPtr &crs) { dumpWKT(crs.get()); } + +void dumpWKT(const NS_PROJ::crs::CRSNNPtr &crs); +void dumpWKT(const NS_PROJ::crs::CRSNNPtr &crs) { + dumpWKT(crs.as_nullable().get()); +} + +void dumpWKT(const NS_PROJ::crs::GeographicCRSPtr &crs); +void dumpWKT(const NS_PROJ::crs::GeographicCRSPtr &crs) { dumpWKT(crs.get()); } + +void dumpWKT(const NS_PROJ::crs::GeographicCRSNNPtr &crs); +void dumpWKT(const NS_PROJ::crs::GeographicCRSNNPtr &crs) { + dumpWKT(crs.as_nullable().get()); +} + #endif using namespace NS_PROJ::internal; @@ -6010,28 +6034,39 @@ void Conversion::_exportToPROJString( !isHeightDepthReversal; bool applyTargetCRSModifiers = applySourceCRSModifiers; + if (formatter->getCRSExport()) { + if (methodEPSGCode == EPSG_CODE_METHOD_GEOCENTRIC_TOPOCENTRIC || + methodEPSGCode == EPSG_CODE_METHOD_GEOGRAPHIC_TOPOCENTRIC) { + throw io::FormattingException("Transformation cannot be exported " + "as a PROJ.4 string (but can be part " + "of a PROJ pipeline)"); + } + } + auto l_sourceCRS = sourceCRS(); + crs::GeographicCRSPtr srcGeogCRS; if (!formatter->getCRSExport() && l_sourceCRS && applySourceCRSModifiers) { - crs::CRS *horiz = l_sourceCRS.get(); - const auto compound = dynamic_cast<const crs::CompoundCRS *>(horiz); + crs::CRSPtr horiz = l_sourceCRS; + const auto compound = + dynamic_cast<const crs::CompoundCRS *>(l_sourceCRS.get()); if (compound) { const auto &components = compound->componentReferenceSystems(); if (!components.empty()) { - horiz = components.front().get(); + horiz = components.front().as_nullable(); } } - auto geogCRS = dynamic_cast<const crs::GeographicCRS *>(horiz); - if (geogCRS) { + srcGeogCRS = std::dynamic_pointer_cast<crs::GeographicCRS>(horiz); + if (srcGeogCRS) { formatter->setOmitProjLongLatIfPossible(true); formatter->startInversion(); - geogCRS->_exportToPROJString(formatter); + srcGeogCRS->_exportToPROJString(formatter); formatter->stopInversion(); formatter->setOmitProjLongLatIfPossible(false); } - auto projCRS = dynamic_cast<const crs::ProjectedCRS *>(horiz); + auto projCRS = dynamic_cast<const crs::ProjectedCRS *>(horiz.get()); if (projCRS) { formatter->startInversion(); formatter->pushOmitZUnitConversion(); @@ -6301,6 +6336,30 @@ void Conversion::_exportToPROJString( } bConversionDone = true; bEllipsoidParametersDone = true; + } else if (methodEPSGCode == EPSG_CODE_METHOD_GEOGRAPHIC_TOPOCENTRIC) { + if (!srcGeogCRS) { + throw io::FormattingException( + "Export of Geographic/Topocentric conversion to a PROJ string " + "requires an input geographic CRS"); + } + + formatter->addStep("cart"); + srcGeogCRS->ellipsoid()->_exportToPROJString(formatter); + + formatter->addStep("topocentric"); + const auto latOrigin = parameterValueNumeric( + EPSG_CODE_PARAMETER_LATITUDE_TOPOGRAPHIC_ORIGIN, + common::UnitOfMeasure::DEGREE); + const auto lonOrigin = parameterValueNumeric( + EPSG_CODE_PARAMETER_LONGITUDE_TOPOGRAPHIC_ORIGIN, + common::UnitOfMeasure::DEGREE); + const auto heightOrigin = parameterValueNumeric( + EPSG_CODE_PARAMETER_ELLIPSOIDAL_HEIGHT_TOPOCENTRIC_ORIGIN, + common::UnitOfMeasure::METRE); + formatter->addParam("lat_0", latOrigin); + formatter->addParam("lon_0", lonOrigin); + formatter->addParam("h_0", heightOrigin); + bConversionDone = true; } auto l_targetCRS = targetCRS(); @@ -6425,7 +6484,9 @@ void Conversion::_exportToPROJString( } if (!bEllipsoidParametersDone) { - auto targetGeogCRS = horiz->extractGeographicCRS(); + auto targetGeodCRS = horiz->extractGeodeticCRS(); + auto targetGeogCRS = + std::dynamic_pointer_cast<crs::GeographicCRS>(targetGeodCRS); if (targetGeogCRS) { if (formatter->getCRSExport()) { targetGeogCRS->addDatumInfoToPROJString(formatter); @@ -6434,6 +6495,8 @@ void Conversion::_exportToPROJString( targetGeogCRS->primeMeridian()->_exportToPROJString( formatter); } + } else if (targetGeodCRS) { + targetGeodCRS->ellipsoid()->_exportToPROJString(formatter); } } @@ -8836,11 +8899,16 @@ createSimilarPropertiesTransformation(TransformationNNPtr obj) { // The domain(s) are unchanged addDomains(map, obj.get()); - std::string forwardName = obj->nameStr(); + const std::string &forwardName = obj->nameStr(); if (!forwardName.empty()) { map.set(common::IdentifiedObject::NAME_KEY, forwardName); } + const std::string &remarks = obj->remarks(); + if (!remarks.empty()) { + map.set(common::IdentifiedObject::REMARKS_KEY, remarks); + } + addModifiedIdentifier(map, obj.get(), false, true); return map; @@ -9179,6 +9247,14 @@ static void setupPROJGeodeticSourceCRS(io::PROJStringFormatter *formatter, formatter->startInversion(); sourceCRSGeog->_exportToPROJString(formatter); formatter->stopInversion(); + if (util::isOfExactType<crs::DerivedGeographicCRS>( + *(sourceCRSGeog.get()))) { + // The export of a DerivedGeographicCRS in non-CRS mode adds + // unit conversion and axis swapping. We must compensate for that + formatter->startInversion(); + sourceCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + formatter->stopInversion(); + } if (addPushV3) { formatter->addStep("push"); @@ -9212,7 +9288,12 @@ static void setupPROJGeodeticTargetCRS(io::PROJStringFormatter *formatter, formatter->addStep("pop"); formatter->addParam("v_3"); } - + if (util::isOfExactType<crs::DerivedGeographicCRS>( + *(targetCRSGeog.get()))) { + // The export of a DerivedGeographicCRS in non-CRS mode adds + // unit conversion and axis swapping. We must compensate for that + targetCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + } targetCRSGeog->_exportToPROJString(formatter); } else { auto targetCRSGeod = dynamic_cast<const crs::GeodeticCRS *>(crs.get()); @@ -11191,6 +11272,12 @@ struct CoordinateOperationFactory::Private { const crs::GeographicCRS *geogDst, std::vector<CoordinateOperationNNPtr> &res); + static void createOperationsVertToGeogBallpark( + const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, + Private::Context &context, const crs::VerticalCRS *vertSrc, + const crs::GeographicCRS *geogDst, + std::vector<CoordinateOperationNNPtr> &res); + static void createOperationsBoundToBound( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, Private::Context &context, const crs::BoundCRS *boundSrc, @@ -11292,6 +11379,7 @@ struct PrecomputedOpCharacteristics { bool gridsKnown_ = false; size_t stepCount_ = 0; bool isApprox_ = false; + bool hasBallparkVertical_ = false; bool isNullTransformation_ = false; PrecomputedOpCharacteristics() = default; @@ -11299,10 +11387,12 @@ struct PrecomputedOpCharacteristics { bool isPROJExportable, bool hasGrids, bool gridsAvailable, bool gridsKnown, size_t stepCount, bool isApprox, + bool hasBallparkVertical, bool isNullTransformation) : area_(area), accuracy_(accuracy), isPROJExportable_(isPROJExportable), hasGrids_(hasGrids), gridsAvailable_(gridsAvailable), gridsKnown_(gridsKnown), stepCount_(stepCount), isApprox_(isApprox), + hasBallparkVertical_(hasBallparkVertical), isNullTransformation_(isNullTransformation) {} }; @@ -11346,6 +11436,15 @@ struct SortFunction { return false; } + if (!iterA->second.hasBallparkVertical_ && + iterB->second.hasBallparkVertical_) { + return true; + } + if (iterA->second.hasBallparkVertical_ && + !iterB->second.hasBallparkVertical_) { + return false; + } + if (!iterA->second.isNullTransformation_ && iterB->second.isNullTransformation_) { return true; @@ -11612,7 +11711,9 @@ struct FilterResults { ? CoordinateOperationContext::SpatialCriterion:: STRICT_CONTAINMENT : context->getSpatialCriterion(); - bool hasFoundOpWithExtent = false; + bool hasOnlyBallpark = true; + bool hasNonBallparkWithoutExtent = false; + bool hasNonBallparkOpWithExtent = false; const bool allowBallpark = context->getAllowBallparkTransformations(); for (const auto &op : sourceList) { if (desiredAccuracy != 0) { @@ -11627,9 +11728,15 @@ struct FilterResults { if (areaOfInterest) { bool emptyIntersection = false; auto extent = getExtent(op, true, emptyIntersection); - if (!extent) + if (!extent) { + if (!op->hasBallparkTransformation()) { + hasNonBallparkWithoutExtent = true; + } continue; - hasFoundOpWithExtent = true; + } + if (!op->hasBallparkTransformation()) { + hasNonBallparkOpWithExtent = true; + } bool extentContains = extent->contains(NN_NO_CHECK(areaOfInterest)); if (!hasOpThatContainsAreaOfInterestAndNoGrid && @@ -11656,9 +11763,15 @@ struct FilterResults { BOTH) { bool emptyIntersection = false; auto extent = getExtent(op, true, emptyIntersection); - if (!extent) + if (!extent) { + if (!op->hasBallparkTransformation()) { + hasNonBallparkWithoutExtent = true; + } continue; - hasFoundOpWithExtent = true; + } + if (!op->hasBallparkTransformation()) { + hasNonBallparkOpWithExtent = true; + } bool extentContainsExtent1 = !extent1 || extent->contains(NN_NO_CHECK(extent1)); bool extentContainsExtent2 = @@ -11688,12 +11801,16 @@ struct FilterResults { } } } + if (!op->hasBallparkTransformation()) { + hasOnlyBallpark = false; + } res.emplace_back(op); } // In case no operation has an extent and no result is found, // retain all initial operations that match accuracy criterion. - if (res.empty() && !hasFoundOpWithExtent) { + if ((res.empty() && !hasNonBallparkOpWithExtent) || + (hasOnlyBallpark && hasNonBallparkWithoutExtent)) { for (const auto &op : sourceList) { if (desiredAccuracy != 0) { const double accuracy = getAccuracy(op); @@ -11797,6 +11914,8 @@ struct FilterResults { area, getAccuracy(op), isPROJExportable, hasGrids, gridsAvailable, gridsKnown, stepCount, op->hasBallparkTransformation(), + op->nameStr().find("ballpark vertical transformation") != + std::string::npos, isNullTransformation(op->nameStr())); } @@ -12615,6 +12734,55 @@ createGeodToGeodPROJBased(const crs::CRSNNPtr &geodSrc, // --------------------------------------------------------------------------- +static std::string +getRemarks(const std::vector<operation::CoordinateOperationNNPtr> &ops) { + std::string remarks; + for (const auto &op : ops) { + const auto &opRemarks = op->remarks(); + if (!opRemarks.empty()) { + if (!remarks.empty()) { + remarks += '\n'; + } + + std::string opName(op->nameStr()); + if (starts_with(opName, INVERSE_OF)) { + opName = opName.substr(INVERSE_OF.size()); + } + + remarks += "For "; + remarks += opName; + + const auto &ids = op->identifiers(); + if (!ids.empty()) { + std::string authority(*ids.front()->codeSpace()); + if (starts_with(authority, "INVERSE(") && + authority.back() == ')') { + authority = authority.substr(strlen("INVERSE("), + authority.size() - 1 - + strlen("INVERSE(")); + } + if (starts_with(authority, "DERIVED_FROM(") && + authority.back() == ')') { + authority = authority.substr(strlen("DERIVED_FROM("), + authority.size() - 1 - + strlen("DERIVED_FROM(")); + } + + remarks += " ("; + remarks += authority; + remarks += ':'; + remarks += ids.front()->code(); + remarks += ')'; + } + remarks += ": "; + remarks += opRemarks; + } + } + return remarks; +} + +// --------------------------------------------------------------------------- + static CoordinateOperationNNPtr createHorizVerticalPROJBased( const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, const operation::CoordinateOperationNNPtr &horizTransform, @@ -12640,6 +12808,10 @@ static CoordinateOperationNNPtr createHorizVerticalPROJBased( properties.set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, NN_NO_CHECK(extent)); } + const auto &remarks = verticalTransform->remarks(); + if (!remarks.empty()) { + properties.set(common::IdentifiedObject::REMARKS_KEY, remarks); + } return createPROJBased( properties, exportable, sourceCRS, targetCRS, nullptr, verticalTransform->coordinateOperationAccuracies(), @@ -12664,6 +12836,11 @@ static CoordinateOperationNNPtr createHorizVerticalPROJBased( NN_NO_CHECK(extent)); } + const auto remarks = getRemarks(ops); + if (!remarks.empty()) { + properties.set(common::IdentifiedObject::REMARKS_KEY, remarks); + } + std::vector<metadata::PositionalAccuracyNNPtr> accuracies; const double accuracy = getAccuracy(ops); if (accuracy >= 0.0) { @@ -12724,6 +12901,11 @@ static CoordinateOperationNNPtr createHorizVerticalHorizPROJBased( NN_NO_CHECK(extent)); } + const auto remarks = getRemarks(ops); + if (!remarks.empty()) { + properties.set(common::IdentifiedObject::REMARKS_KEY, remarks); + } + std::vector<metadata::PositionalAccuracyNNPtr> accuracies; const double accuracy = getAccuracy(ops); if (accuracy >= 0.0) { @@ -13542,11 +13724,17 @@ bool CoordinateOperationFactory::Private::createOperationsFromDatabase( ENTER_FUNCTION(); if (geogSrc && vertDst) { - res = createOperationsGeogToVertFromGeoid(sourceCRS, targetCRS, vertDst, - context); + createOperationsFromDatabase(targetCRS, sourceCRS, context, geodDst, + geodSrc, geogDst, geogSrc, vertDst, + vertSrc, res); + res = applyInverse(res); } else if (geogDst && vertSrc) { res = applyInverse(createOperationsGeogToVertFromGeoid( targetCRS, sourceCRS, vertSrc, context)); + if (!res.empty()) { + createOperationsVertToGeogBallpark(sourceCRS, targetCRS, context, + vertSrc, geogDst, res); + } } if (!res.empty()) { @@ -14222,6 +14410,20 @@ void CoordinateOperationFactory::Private::createOperationsBoundToGeog( const auto &hubSrc = boundSrc->hubCRS(); auto hubSrcGeog = dynamic_cast<const crs::GeographicCRS *>(hubSrc.get()); auto geogCRSOfBaseOfBoundSrc = boundSrc->baseCRS()->extractGeographicCRS(); + { + // If geogCRSOfBaseOfBoundSrc is a DerivedGeographicCRS, use its base + // instead (if it is a GeographicCRS) + auto derivedGeogCRS = + std::dynamic_pointer_cast<crs::DerivedGeographicCRS>( + geogCRSOfBaseOfBoundSrc); + if (derivedGeogCRS) { + auto baseCRS = std::dynamic_pointer_cast<crs::GeographicCRS>( + derivedGeogCRS->baseCRS().as_nullable()); + if (baseCRS) { + geogCRSOfBaseOfBoundSrc = baseCRS; + } + } + } const auto &authFactory = context.context->getAuthorityFactory(); const auto dbContext = @@ -14643,23 +14845,38 @@ void CoordinateOperationFactory::Private::createOperationsVertToGeog( match.get(), util::IComparable::Criterion::EQUIVALENT) && !match->identifiers().empty()) { - res = createOperations( + auto resTmp = createOperations( NN_NO_CHECK( util::nn_dynamic_pointer_cast<crs::VerticalCRS>( match)), targetCRS, context); + res.insert(res.end(), resTmp.begin(), resTmp.end()); return; } } } } + createOperationsVertToGeogBallpark(sourceCRS, targetCRS, context, vertSrc, + geogDst, res); +} + +// --------------------------------------------------------------------------- + +void CoordinateOperationFactory::Private::createOperationsVertToGeogBallpark( + const crs::CRSNNPtr &sourceCRS, const crs::CRSNNPtr &targetCRS, + Private::Context &, const crs::VerticalCRS *vertSrc, + const crs::GeographicCRS *geogDst, + std::vector<CoordinateOperationNNPtr> &res) { + + ENTER_FUNCTION(); + const auto &srcAxis = vertSrc->coordinateSystem()->axisList()[0]; const double convSrc = srcAxis->unit().conversionToSI(); double convDst = 1.0; const auto &geogAxis = geogDst->coordinateSystem()->axisList(); bool dstIsUp = true; - bool dstIsDown = true; + bool dstIsDown = false; if (geogAxis.size() == 3) { const auto &dstAxis = geogAxis[2]; convDst = dstAxis->unit().conversionToSI(); @@ -14672,12 +14889,24 @@ void CoordinateOperationFactory::Private::createOperationsVertToGeog( ((srcIsUp && dstIsDown) || (srcIsDown && dstIsUp)); const double factor = convSrc / convDst; - auto conv = Transformation::createChangeVerticalUnit( - util::PropertyMap().set( - common::IdentifiedObject::NAME_KEY, + + const auto &sourceCRSExtent = getExtent(sourceCRS); + const auto &targetCRSExtent = getExtent(targetCRS); + const bool sameExtent = + sourceCRSExtent && targetCRSExtent && + sourceCRSExtent->_isEquivalentTo( + targetCRSExtent.get(), util::IComparable::Criterion::EQUIVALENT); + + util::PropertyMap map; + map.set(common::IdentifiedObject::NAME_KEY, buildTransfName(sourceCRS->nameStr(), targetCRS->nameStr()) + - BALLPARK_VERTICAL_TRANSFORMATION_NO_ELLIPSOID_VERT_HEIGHT), - sourceCRS, targetCRS, + BALLPARK_VERTICAL_TRANSFORMATION_NO_ELLIPSOID_VERT_HEIGHT) + .set(common::ObjectUsage::DOMAIN_OF_VALIDITY_KEY, + sameExtent ? NN_NO_CHECK(sourceCRSExtent) + : metadata::Extent::WORLD); + + auto conv = Transformation::createChangeVerticalUnit( + map, sourceCRS, targetCRS, common::Scale(heightDepthReversal ? -factor : factor), {}); conv->setHasBallparkTransformation(true); res.push_back(conv); @@ -15477,149 +15706,6 @@ void CoordinateOperationFactory::Private::createOperationsBoundToCompound( // --------------------------------------------------------------------------- -static crs::CRSNNPtr -getResolvedCRS(const crs::CRSNNPtr &crs, - const CoordinateOperationContextNNPtr &context, - metadata::ExtentPtr &extentOut) { - const auto &authFactory = context->getAuthorityFactory(); - const auto &ids = crs->identifiers(); - const auto &name = crs->nameStr(); - - bool approxExtent; - extentOut = getExtentPossiblySynthetized(crs, approxExtent); - - // We try to "identify" the provided CRS with the ones of the database, - // but in a more restricted way that what identify() does. - // If we get a match from id in priority, and from name as a fallback, and - // that they are equivalent to the input CRS, then use the identified CRS. - // Even if they aren't equivalent, we update extentOut with the one of the - // identified CRS if our input one is absent/not reliable. - - const auto tryToIdentifyByName = [&crs, &name, &authFactory, approxExtent, - &extentOut]( - io::AuthorityFactory::ObjectType objectType) { - if (name != "unknown" && name != "unnamed") { - auto matches = authFactory->createObjectsFromName( - name, {objectType}, false, 2); - if (matches.size() == 1) { - const auto match = - util::nn_static_pointer_cast<crs::CRS>(matches.front()); - if (approxExtent || !extentOut) { - extentOut = getExtent(match); - } - if (match->isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT)) { - return match; - } - } - } - return crs; - }; - - auto geogCRS = dynamic_cast<crs::GeographicCRS *>(crs.get()); - if (geogCRS && authFactory) { - if (!ids.empty()) { - const auto tmpAuthFactory = io::AuthorityFactory::create( - authFactory->databaseContext(), *ids.front()->codeSpace()); - try { - auto resolvedCrs( - tmpAuthFactory->createGeographicCRS(ids.front()->code())); - if (approxExtent || !extentOut) { - extentOut = getExtent(resolvedCrs); - } - if (resolvedCrs->isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT)) { - return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); - } - } catch (const std::exception &) { - } - } else { - return tryToIdentifyByName( - geogCRS->coordinateSystem()->axisList().size() == 2 - ? io::AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS - : io::AuthorityFactory::ObjectType::GEOGRAPHIC_3D_CRS); - } - } - - auto projectedCrs = dynamic_cast<crs::ProjectedCRS *>(crs.get()); - if (projectedCrs && authFactory) { - if (!ids.empty()) { - const auto tmpAuthFactory = io::AuthorityFactory::create( - authFactory->databaseContext(), *ids.front()->codeSpace()); - try { - auto resolvedCrs( - tmpAuthFactory->createProjectedCRS(ids.front()->code())); - if (approxExtent || !extentOut) { - extentOut = getExtent(resolvedCrs); - } - if (resolvedCrs->isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT)) { - return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); - } - } catch (const std::exception &) { - } - } else { - return tryToIdentifyByName( - io::AuthorityFactory::ObjectType::PROJECTED_CRS); - } - } - - auto compoundCrs = dynamic_cast<crs::CompoundCRS *>(crs.get()); - if (compoundCrs && authFactory) { - if (!ids.empty()) { - const auto tmpAuthFactory = io::AuthorityFactory::create( - authFactory->databaseContext(), *ids.front()->codeSpace()); - try { - auto resolvedCrs( - tmpAuthFactory->createCompoundCRS(ids.front()->code())); - if (approxExtent || !extentOut) { - extentOut = getExtent(resolvedCrs); - } - if (resolvedCrs->isEquivalentTo( - crs.get(), util::IComparable::Criterion::EQUIVALENT)) { - return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); - } - } catch (const std::exception &) { - } - } else { - auto outCrs = tryToIdentifyByName( - io::AuthorityFactory::ObjectType::COMPOUND_CRS); - const auto &components = compoundCrs->componentReferenceSystems(); - if (outCrs.get() != crs.get()) { - bool hasGeoid = false; - if (components.size() == 2) { - auto vertCRS = - dynamic_cast<crs::VerticalCRS *>(components[1].get()); - if (vertCRS && !vertCRS->geoidModel().empty()) { - hasGeoid = true; - } - } - if (!hasGeoid) { - return outCrs; - } - } - if (approxExtent || !extentOut) { - // If we still did not get a reliable extent, then try to - // resolve the components of the compoundCRS, and take the - // intersection of their extent. - extentOut = metadata::ExtentPtr(); - for (const auto &component : components) { - metadata::ExtentPtr componentExtent; - getResolvedCRS(component, context, componentExtent); - if (extentOut && componentExtent) - extentOut = extentOut->intersection( - NN_NO_CHECK(componentExtent)); - else if (componentExtent) - extentOut = componentExtent; - } - } - } - } - return crs; -} - -// --------------------------------------------------------------------------- - /** \brief Find a list of CoordinateOperation from sourceCRS to targetCRS. * * The operations are sorted with the most relevant ones first: by @@ -15655,13 +15741,14 @@ CoordinateOperationFactory::createOperations( const auto &targetBoundCRS = targetCRS->canonicalBoundCRS(); auto l_sourceCRS = srcBoundCRS ? NN_NO_CHECK(srcBoundCRS) : sourceCRS; auto l_targetCRS = targetBoundCRS ? NN_NO_CHECK(targetBoundCRS) : targetCRS; + const auto &authFactory = context->getAuthorityFactory(); metadata::ExtentPtr sourceCRSExtent; auto l_resolvedSourceCRS = - getResolvedCRS(l_sourceCRS, context, sourceCRSExtent); + crs::CRS::getResolvedCRS(l_sourceCRS, authFactory, sourceCRSExtent); metadata::ExtentPtr targetCRSExtent; auto l_resolvedTargetCRS = - getResolvedCRS(l_targetCRS, context, targetCRSExtent); + crs::CRS::getResolvedCRS(l_targetCRS, authFactory, targetCRSExtent); Private::Context contextPrivate(sourceCRSExtent, targetCRSExtent, context); if (context->getSourceAndTargetCRSExtentUse() == @@ -15986,4 +16073,152 @@ PROJBasedOperation::gridsNeeded(const io::DatabaseContextPtr &databaseContext, // --------------------------------------------------------------------------- } // namespace operation + +namespace crs { +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress + +crs::CRSNNPtr CRS::getResolvedCRS(const crs::CRSNNPtr &crs, + const io::AuthorityFactoryPtr &authFactory, + metadata::ExtentPtr &extentOut) { + const auto &ids = crs->identifiers(); + const auto &name = crs->nameStr(); + + bool approxExtent; + extentOut = getExtentPossiblySynthetized(crs, approxExtent); + + // We try to "identify" the provided CRS with the ones of the database, + // but in a more restricted way that what identify() does. + // If we get a match from id in priority, and from name as a fallback, and + // that they are equivalent to the input CRS, then use the identified CRS. + // Even if they aren't equivalent, we update extentOut with the one of the + // identified CRS if our input one is absent/not reliable. + + const auto tryToIdentifyByName = [&crs, &name, &authFactory, approxExtent, + &extentOut]( + io::AuthorityFactory::ObjectType objectType) { + if (name != "unknown" && name != "unnamed") { + auto matches = authFactory->createObjectsFromName( + name, {objectType}, false, 2); + if (matches.size() == 1) { + const auto match = + util::nn_static_pointer_cast<crs::CRS>(matches.front()); + if (approxExtent || !extentOut) { + extentOut = getExtent(match); + } + if (match->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return match; + } + } + } + return crs; + }; + + auto geogCRS = dynamic_cast<crs::GeographicCRS *>(crs.get()); + if (geogCRS && authFactory) { + if (!ids.empty()) { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createGeographicCRS(ids.front()->code())); + if (approxExtent || !extentOut) { + extentOut = getExtent(resolvedCrs); + } + if (resolvedCrs->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); + } + } catch (const std::exception &) { + } + } else { + return tryToIdentifyByName( + geogCRS->coordinateSystem()->axisList().size() == 2 + ? io::AuthorityFactory::ObjectType::GEOGRAPHIC_2D_CRS + : io::AuthorityFactory::ObjectType::GEOGRAPHIC_3D_CRS); + } + } + + auto projectedCrs = dynamic_cast<crs::ProjectedCRS *>(crs.get()); + if (projectedCrs && authFactory) { + if (!ids.empty()) { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createProjectedCRS(ids.front()->code())); + if (approxExtent || !extentOut) { + extentOut = getExtent(resolvedCrs); + } + if (resolvedCrs->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); + } + } catch (const std::exception &) { + } + } else { + return tryToIdentifyByName( + io::AuthorityFactory::ObjectType::PROJECTED_CRS); + } + } + + auto compoundCrs = dynamic_cast<crs::CompoundCRS *>(crs.get()); + if (compoundCrs && authFactory) { + if (!ids.empty()) { + const auto tmpAuthFactory = io::AuthorityFactory::create( + authFactory->databaseContext(), *ids.front()->codeSpace()); + try { + auto resolvedCrs( + tmpAuthFactory->createCompoundCRS(ids.front()->code())); + if (approxExtent || !extentOut) { + extentOut = getExtent(resolvedCrs); + } + if (resolvedCrs->isEquivalentTo( + crs.get(), util::IComparable::Criterion::EQUIVALENT)) { + return util::nn_static_pointer_cast<crs::CRS>(resolvedCrs); + } + } catch (const std::exception &) { + } + } else { + auto outCrs = tryToIdentifyByName( + io::AuthorityFactory::ObjectType::COMPOUND_CRS); + const auto &components = compoundCrs->componentReferenceSystems(); + if (outCrs.get() != crs.get()) { + bool hasGeoid = false; + if (components.size() == 2) { + auto vertCRS = + dynamic_cast<crs::VerticalCRS *>(components[1].get()); + if (vertCRS && !vertCRS->geoidModel().empty()) { + hasGeoid = true; + } + } + if (!hasGeoid) { + return outCrs; + } + } + if (approxExtent || !extentOut) { + // If we still did not get a reliable extent, then try to + // resolve the components of the compoundCRS, and take the + // intersection of their extent. + extentOut = metadata::ExtentPtr(); + for (const auto &component : components) { + metadata::ExtentPtr componentExtent; + getResolvedCRS(component, authFactory, componentExtent); + if (extentOut && componentExtent) + extentOut = extentOut->intersection( + NN_NO_CHECK(componentExtent)); + else if (componentExtent) + extentOut = componentExtent; + } + } + } + } + return crs; +} + +//! @endcond + +} // namespace crs NS_PROJ_END diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index edc8a71f..573dd6db 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -533,8 +533,12 @@ CRSNNPtr CRS::createBoundCRSToWGS84IfPossible( auto authFactory = io::AuthorityFactory::create( NN_NO_CHECK(dbContext), authority == "any" ? std::string() : authority); + metadata::ExtentPtr extentResolved(extent); + if (!extent) { + getResolvedCRS(thisAsCRS, authFactory, extentResolved); + } auto ctxt = operation::CoordinateOperationContext::create( - authFactory, extent, 0.0); + authFactory, extentResolved, 0.0); ctxt->setAllowUseIntermediateCRS(allowIntermediateCRSUse); // ctxt->setSpatialCriterion( // operation::CoordinateOperationContext::SpatialCriterion::PARTIAL_INTERSECTION); @@ -1616,6 +1620,34 @@ static bool exportAsESRIWktCompoundCRSWithEllipsoidalHeight( vertCRSList.front()->_exportToWKT(formatter); return true; } + +// --------------------------------------------------------------------------- + +// Try to format a Geographic/ProjectedCRS 3D CRS as a +// GEOGCS[]/PROJCS[],VERTCS["Ellipsoid (metre)",DATUM["Ellipsoid",2002],...] +static bool exportAsWKT1CompoundCRSWithEllipsoidalHeight( + const CRSNNPtr &base2DCRS, + const cs::CoordinateSystemAxisNNPtr &verticalAxis, + io::WKTFormatter *formatter) { + std::string verticalCRSName = "Ellipsoid ("; + verticalCRSName += verticalAxis->unit().name(); + verticalCRSName += ')'; + auto vertDatum = datum::VerticalReferenceFrame::create( + util::PropertyMap() + .set(common::IdentifiedObject::NAME_KEY, "Ellipsoid") + .set("VERT_DATUM_TYPE", "2002")); + auto vertCRS = VerticalCRS::create( + util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, + verticalCRSName), + vertDatum.as_nullable(), nullptr, + cs::VerticalCS::create(util::PropertyMap(), verticalAxis)); + formatter->startNode(io::WKTConstants::COMPD_CS, false); + formatter->addQuotedString(base2DCRS->nameStr() + " + " + verticalCRSName); + base2DCRS->_exportToWKT(formatter); + vertCRS->_exportToWKT(formatter); + formatter->endNode(); + return true; +} //! @endcond // --------------------------------------------------------------------------- @@ -1683,6 +1715,13 @@ void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const { return; } + if (formatter->isAllowedEllipsoidalHeightAsVerticalCRS()) { + if (exportAsWKT1CompoundCRSWithEllipsoidalHeight( + geogCRS2D, axisList[2], formatter)) { + return; + } + } + io::FormattingException::Throw( "WKT1 does not support Geographic 3D CRS."); } @@ -1922,11 +1961,19 @@ getStandardCriterion(util::IComparable::Criterion criterion) { bool GeodeticCRS::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion, const io::DatabaseContextPtr &dbContext) const { + if (other == nullptr || !util::isOfExactType<GeodeticCRS>(*other)) { + return false; + } + return _isEquivalentToNoTypeCheck(other, criterion, dbContext); +} + +bool GeodeticCRS::_isEquivalentToNoTypeCheck( + const util::IComparable *other, util::IComparable::Criterion criterion, + const io::DatabaseContextPtr &dbContext) const { const auto standardCriterion = getStandardCriterion(criterion); - auto otherGeodCRS = dynamic_cast<const GeodeticCRS *>(other); + // TODO test velocityModel - return otherGeodCRS != nullptr && - SingleCRS::baseIsEquivalentTo(other, standardCriterion, dbContext); + return SingleCRS::baseIsEquivalentTo(other, standardCriterion, dbContext); } //! @endcond @@ -2482,12 +2529,13 @@ bool GeographicCRS::is2DPartOf3D(util::nn<const GeographicCRS *> other, bool GeographicCRS::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion, const io::DatabaseContextPtr &dbContext) const { - auto otherGeogCRS = dynamic_cast<const GeographicCRS *>(other); - if (otherGeogCRS == nullptr) { + if (other == nullptr || !util::isOfExactType<GeographicCRS>(*other)) { return false; } + const auto standardCriterion = getStandardCriterion(criterion); - if (GeodeticCRS::_isEquivalentTo(other, standardCriterion, dbContext)) { + if (GeodeticCRS::_isEquivalentToNoTypeCheck(other, standardCriterion, + dbContext)) { return true; } if (criterion != @@ -2506,7 +2554,29 @@ bool GeographicCRS::_isEquivalentTo( cs::EllipsoidalCS::AxisOrder::LONG_EAST_LAT_NORTH ? cs::EllipsoidalCS::createLatitudeLongitude(unit) : cs::EllipsoidalCS::createLongitudeLatitude(unit)) - ->GeodeticCRS::_isEquivalentTo(other, standardCriterion, dbContext); + ->GeodeticCRS::_isEquivalentToNoTypeCheck(other, standardCriterion, + dbContext); + } + if (axisOrder == + cs::EllipsoidalCS::AxisOrder::LONG_EAST_LAT_NORTH_HEIGHT_UP || + axisOrder == + cs::EllipsoidalCS::AxisOrder::LAT_NORTH_LONG_EAST_HEIGHT_UP) { + const auto &angularUnit = coordinateSystem()->axisList()[0]->unit(); + const auto &linearUnit = coordinateSystem()->axisList()[2]->unit(); + return GeographicCRS::create( + util::PropertyMap().set(common::IdentifiedObject::NAME_KEY, + nameStr()), + datum(), datumEnsemble(), + axisOrder == cs::EllipsoidalCS::AxisOrder:: + LONG_EAST_LAT_NORTH_HEIGHT_UP + ? cs::EllipsoidalCS:: + createLatitudeLongitudeEllipsoidalHeight( + angularUnit, linearUnit) + : cs::EllipsoidalCS:: + createLongitudeLatitudeEllipsoidalHeight( + angularUnit, linearUnit)) + ->GeodeticCRS::_isEquivalentToNoTypeCheck(other, standardCriterion, + dbContext); } return false; } @@ -3605,6 +3675,14 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const { return; } + if (!formatter->useESRIDialect() && + formatter->isAllowedEllipsoidalHeightAsVerticalCRS()) { + if (exportAsWKT1CompoundCRSWithEllipsoidalHeight( + projCRS2D, axisList[2], formatter)) { + return; + } + } + io::FormattingException::Throw( "Projected 3D CRS can only be exported since WKT2:2019"); } @@ -3885,8 +3963,7 @@ ProjectedCRS::create(const util::PropertyMap &properties, bool ProjectedCRS::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion, const io::DatabaseContextPtr &dbContext) const { - auto otherProjCRS = dynamic_cast<const ProjectedCRS *>(other); - return otherProjCRS != nullptr && + return other != nullptr && util::isOfExactType<ProjectedCRS>(*other) && DerivedCRS::_isEquivalentTo(other, criterion, dbContext); } diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 5bc8074c..8e1b8257 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -43,7 +43,6 @@ // clang-format off #include "proj.h" #include "proj_internal.h" -#include "proj_api.h" // clang-format on #include "proj_json_streaming_writer.hpp" @@ -352,6 +351,23 @@ void PrimeMeridian::_exportToWKT( if (!(isWKT2 && formatter->primeMeridianOmittedIfGreenwich() && l_name == "Greenwich")) { formatter->startNode(io::WKTConstants::PRIMEM, !identifiers().empty()); + + if (formatter->useESRIDialect()) { + bool aliasFound = false; + const auto &dbContext = formatter->databaseContext(); + if (dbContext) { + auto l_alias = dbContext->getAliasFromOfficialName( + l_name, "prime_meridian", "ESRI"); + if (!l_alias.empty()) { + l_name = l_alias; + aliasFound = true; + } + } + if (!aliasFound) { + l_name = io::WKTFormatter::morphNameToESRI(l_name); + } + } + formatter->addQuotedString(l_name); const auto &l_long = longitude(); if (formatter->primeMeridianInDegree()) { @@ -418,7 +434,7 @@ std::string PrimeMeridian::getPROJStringWellKnownName(const common::Angle &angle) { const double valRad = angle.getSIValue(); std::string projPMName; - projCtx ctxt = pj_ctx_alloc(); + PJ_CONTEXT *ctxt = proj_context_create(); auto proj_pm = proj_list_prime_meridians(); for (int i = 0; proj_pm[i].id != nullptr; ++i) { double valRefRad = dmstor_ctx(ctxt, proj_pm[i].defn, nullptr); @@ -427,7 +443,7 @@ PrimeMeridian::getPROJStringWellKnownName(const common::Angle &angle) { break; } } - pj_ctx_free(ctxt); + proj_context_destroy(ctxt); return projPMName; } //! @endcond @@ -1731,6 +1747,14 @@ void DatumEnsemble::_exportToWKT( formatter->startNode(io::WKTConstants::ENSEMBLEACCURACY, false); formatter->add(positionalAccuracy()->value()); formatter->endNode(); + + // In theory, we should do the following, but currently the WKT grammar + // doesn't allow this + // ObjectUsage::baseExportToWKT(formatter); + if (formatter->outputId()) { + formatID(formatter); + } + formatter->endNode(); } //! @endcond diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 5d02aeea..2a03fd4e 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -65,7 +65,6 @@ // clang-format off #include "proj.h" #include "proj_internal.h" -#include "proj_api.h" // clang-format on #include <sqlite3.h> @@ -94,6 +93,12 @@ namespace io { #define GEOG_3D_SINGLE_QUOTED "'geographic 3D'" #define GEOCENTRIC_SINGLE_QUOTED "'geocentric'" +// See data/sql/metadata.sql for the semantics of those constants +constexpr int DATABASE_LAYOUT_VERSION_MAJOR = 1; +// If the code depends on the new additions, then DATABASE_LAYOUT_VERSION_MINOR +// must be incremented. +constexpr int DATABASE_LAYOUT_VERSION_MINOR = 0; + // --------------------------------------------------------------------------- struct SQLValues { @@ -192,6 +197,13 @@ struct DatabaseContext::Private { void cache(const std::string &code, const datum::GeodeticReferenceFrameNNPtr &datum); + datum::DatumEnsemblePtr + // cppcheck-suppress functionStatic + getDatumEnsembleFromCache(const std::string &code); + // cppcheck-suppress functionStatic + void cache(const std::string &code, + const datum::DatumEnsembleNNPtr &datumEnsemble); + datum::EllipsoidPtr // cppcheck-suppress functionStatic getEllipsoidFromCache(const std::string &code); @@ -258,6 +270,7 @@ struct DatabaseContext::Private { LRUCacheOfObjects cacheCRS_{CACHE_SIZE}; LRUCacheOfObjects cacheEllipsoid_{CACHE_SIZE}; LRUCacheOfObjects cacheGeodeticDatum_{CACHE_SIZE}; + LRUCacheOfObjects cacheDatumEnsemble_{CACHE_SIZE}; LRUCacheOfObjects cachePrimeMeridian_{CACHE_SIZE}; LRUCacheOfObjects cacheCS_{CACHE_SIZE}; LRUCacheOfObjects cacheExtent_{CACHE_SIZE}; @@ -270,6 +283,8 @@ struct DatabaseContext::Private { lru11::Cache<std::string, std::list<std::string>> cacheAliasNames_{ CACHE_SIZE}; + void checkDatabaseLayout(); + static void insertIntoCache(LRUCacheOfObjects &cache, const std::string &code, const util::BaseObjectPtr &obj); @@ -417,6 +432,22 @@ void DatabaseContext::Private::cache( // --------------------------------------------------------------------------- +datum::DatumEnsemblePtr +DatabaseContext::Private::getDatumEnsembleFromCache(const std::string &code) { + util::BaseObjectPtr obj; + getFromCache(cacheDatumEnsemble_, code, obj); + return std::static_pointer_cast<datum::DatumEnsemble>(obj); +} + +// --------------------------------------------------------------------------- + +void DatabaseContext::Private::cache( + const std::string &code, const datum::DatumEnsembleNNPtr &datumEnsemble) { + insertIntoCache(cacheDatumEnsemble_, code, datumEnsemble.as_nullable()); +} + +// --------------------------------------------------------------------------- + datum::EllipsoidPtr DatabaseContext::Private::getEllipsoidFromCache(const std::string &code) { util::BaseObjectPtr obj; @@ -548,6 +579,61 @@ void DatabaseContext::Private::open(const std::string &databasePath, // --------------------------------------------------------------------------- +void DatabaseContext::Private::checkDatabaseLayout() { + auto res = run("SELECT key, value FROM metadata WHERE key IN " + "('DATABASE.LAYOUT.VERSION.MAJOR', " + "'DATABASE.LAYOUT.VERSION.MINOR')"); + if (res.size() != 2) { + // The database layout of PROJ 7.2 that shipped with EPSG v10.003 is + // at the time of writing still compatible of the one we support. + static_assert( + // cppcheck-suppress knownConditionTrueFalse + DATABASE_LAYOUT_VERSION_MAJOR == 1 && + // cppcheck-suppress knownConditionTrueFalse + DATABASE_LAYOUT_VERSION_MINOR == 0, + "remove that assertion and below lines next time we upgrade " + "database structure"); + res = run("SELECT 1 FROM metadata WHERE key = 'EPSG.VERSION' AND " + "value = 'v10.003'"); + if (!res.empty()) { + return; + } + + throw FactoryException( + databasePath_ + + " lacks DATABASE.LAYOUT.VERSION.MAJOR / " + "DATABASE.LAYOUT.VERSION.MINOR " + "metadata. It comes from another PROJ installation."); + } + int nMajor = 0; + int nMinor = 0; + for (const auto &row : res) { + if (row[0] == "DATABASE.LAYOUT.VERSION.MAJOR") { + nMajor = atoi(row[1].c_str()); + } else if (row[0] == "DATABASE.LAYOUT.VERSION.MINOR") { + nMinor = atoi(row[1].c_str()); + } + } + if (nMajor != DATABASE_LAYOUT_VERSION_MAJOR) { + throw FactoryException(databasePath_ + + " contains DATABASE.LAYOUT.VERSION.MAJOR = " + + toString(nMajor) + " whereas " + + toString(DATABASE_LAYOUT_VERSION_MAJOR) + + " is expected. " + "It comes from another PROJ installation."); + } + if (nMinor < DATABASE_LAYOUT_VERSION_MINOR) { + throw FactoryException(databasePath_ + + " contains DATABASE.LAYOUT.VERSION.MINOR = " + + toString(nMinor) + " whereas a number >= " + + toString(DATABASE_LAYOUT_VERSION_MINOR) + + " is expected. " + "It comes from another PROJ installation."); + } +} + +// --------------------------------------------------------------------------- + void DatabaseContext::Private::setHandle(sqlite3 *sqlite_handle) { assert(sqlite_handle); @@ -865,6 +951,7 @@ DatabaseContext::create(const std::string &databasePath, if (!auxiliaryDatabasePaths.empty()) { dbCtx->getPrivate()->attachExtraDatabases(auxiliaryDatabasePaths); } + dbCtx->getPrivate()->checkDatabaseLayout(); return dbCtx; } @@ -1064,18 +1151,6 @@ std::string DatabaseContext::getOldProjGridName(const std::string &gridName) { // --------------------------------------------------------------------------- -// FIXME: as we don't support datum ensemble yet, add it from name -static std::string removeEnsembleSuffix(const std::string &name) { - if (name == "World Geodetic System 1984 ensemble") { - return "World Geodetic System 1984"; - } else if (name == "European Terrestrial Reference System 1989 ensemble") { - return "European Terrestrial Reference System 1989"; - } - return name; -} - -// --------------------------------------------------------------------------- - /** \brief Gets the alias name from an official name. * * @param officialName Official name. Mandatory @@ -2012,18 +2087,38 @@ AuthorityFactory::createEllipsoid(const std::string &code) const { datum::GeodeticReferenceFrameNNPtr AuthorityFactory::createGeodeticDatum(const std::string &code) const { + + datum::GeodeticReferenceFramePtr datum; + datum::DatumEnsemblePtr datumEnsemble; + constexpr bool turnEnsembleAsDatum = true; + createGeodeticDatumOrEnsemble(code, datum, datumEnsemble, + turnEnsembleAsDatum); + return NN_NO_CHECK(datum); +} + +// --------------------------------------------------------------------------- + +void AuthorityFactory::createGeodeticDatumOrEnsemble( + const std::string &code, datum::GeodeticReferenceFramePtr &outDatum, + datum::DatumEnsemblePtr &outDatumEnsemble, bool turnEnsembleAsDatum) const { const auto cacheKey(d->authority() + code); { - auto datum = d->context()->d->getGeodeticDatumFromCache(cacheKey); - if (datum) { - return NN_NO_CHECK(datum); + outDatumEnsemble = d->context()->d->getDatumEnsembleFromCache(cacheKey); + if (outDatumEnsemble) { + if (!turnEnsembleAsDatum) + return; + outDatumEnsemble = nullptr; + } + outDatum = d->context()->d->getGeodeticDatumFromCache(cacheKey); + if (outDatum) { + return; } } auto res = d->runWithCodeParam("SELECT name, ellipsoid_auth_name, ellipsoid_code, " "prime_meridian_auth_name, prime_meridian_code, " "publication_date, frame_reference_epoch, " - "deprecated FROM geodetic_datum " + "ensemble_accuracy, deprecated FROM geodetic_datum " "WHERE " "auth_name = ? AND code = ?", code); @@ -2040,29 +2135,63 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { const auto &prime_meridian_code = row[4]; const auto &publication_date = row[5]; const auto &frame_reference_epoch = row[6]; - const bool deprecated = row[7] == "1"; - auto ellipsoid = d->createFactory(ellipsoid_auth_name) - ->createEllipsoid(ellipsoid_code); - auto pm = d->createFactory(prime_meridian_auth_name) - ->createPrimeMeridian(prime_meridian_code); - auto props = d->createPropertiesSearchUsages( - "geodetic_datum", code, removeEnsembleSuffix(name), deprecated); - auto anchor = util::optional<std::string>(); - if (!publication_date.empty()) { - props.set("PUBLICATION_DATE", publication_date); - } - auto datum = - frame_reference_epoch.empty() - ? datum::GeodeticReferenceFrame::create(props, ellipsoid, - anchor, pm) - : util::nn_static_pointer_cast<datum::GeodeticReferenceFrame>( - datum::DynamicGeodeticReferenceFrame::create( - props, ellipsoid, anchor, pm, - common::Measure(c_locale_stod(frame_reference_epoch), - common::UnitOfMeasure::YEAR), - util::optional<std::string>())); - d->context()->d->cache(cacheKey, datum); - return datum; + const auto &ensemble_accuracy = row[7]; + const bool deprecated = row[8] == "1"; + + std::string massagedName = name; + if (turnEnsembleAsDatum) { + if (name == "World Geodetic System 1984 ensemble") { + massagedName = "World Geodetic System 1984"; + } else if (name == + "European Terrestrial Reference System 1989 ensemble") { + massagedName = "European Terrestrial Reference System 1989"; + } + } + auto props = d->createPropertiesSearchUsages("geodetic_datum", code, + massagedName, deprecated); + + if (!turnEnsembleAsDatum && !ensemble_accuracy.empty()) { + auto resMembers = + d->run("SELECT member_auth_name, member_code FROM " + "geodetic_datum_ensemble_member WHERE " + "ensemble_auth_name = ? AND ensemble_code = ? " + "ORDER BY sequence", + {d->authority(), code}); + + std::vector<datum::DatumNNPtr> members; + for (const auto &memberRow : resMembers) { + members.push_back( + d->createFactory(memberRow[0])->createDatum(memberRow[1])); + } + auto datumEnsemble = datum::DatumEnsemble::create( + props, std::move(members), + metadata::PositionalAccuracy::create(ensemble_accuracy)); + d->context()->d->cache(cacheKey, datumEnsemble); + outDatumEnsemble = datumEnsemble.as_nullable(); + } else { + auto ellipsoid = d->createFactory(ellipsoid_auth_name) + ->createEllipsoid(ellipsoid_code); + auto pm = d->createFactory(prime_meridian_auth_name) + ->createPrimeMeridian(prime_meridian_code); + + auto anchor = util::optional<std::string>(); + if (!publication_date.empty()) { + props.set("PUBLICATION_DATE", publication_date); + } + auto datum = frame_reference_epoch.empty() + ? datum::GeodeticReferenceFrame::create( + props, ellipsoid, anchor, pm) + : util::nn_static_pointer_cast< + datum::GeodeticReferenceFrame>( + datum::DynamicGeodeticReferenceFrame::create( + props, ellipsoid, anchor, pm, + common::Measure( + c_locale_stod(frame_reference_epoch), + common::UnitOfMeasure::YEAR), + util::optional<std::string>())); + d->context()->d->cache(cacheKey, datum); + outDatum = datum.as_nullable(); + } } catch (const std::exception &ex) { throw buildFactoryException("geodetic reference frame", code, ex); } @@ -2080,9 +2209,23 @@ AuthorityFactory::createGeodeticDatum(const std::string &code) const { datum::VerticalReferenceFrameNNPtr AuthorityFactory::createVerticalDatum(const std::string &code) const { + datum::VerticalReferenceFramePtr datum; + datum::DatumEnsemblePtr datumEnsemble; + constexpr bool turnEnsembleAsDatum = true; + createVerticalDatumOrEnsemble(code, datum, datumEnsemble, + turnEnsembleAsDatum); + return NN_NO_CHECK(datum); +} + +// --------------------------------------------------------------------------- + +void AuthorityFactory::createVerticalDatumOrEnsemble( + const std::string &code, datum::VerticalReferenceFramePtr &outDatum, + datum::DatumEnsemblePtr &outDatumEnsemble, bool turnEnsembleAsDatum) const { auto res = d->runWithCodeParam("SELECT name, publication_date, " - "frame_reference_epoch, deprecated FROM " + "frame_reference_epoch, ensemble_accuracy, " + "deprecated FROM " "vertical_datum WHERE auth_name = ? AND code = ?", code); if (res.empty()) { @@ -2094,24 +2237,49 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { const auto &name = row[0]; const auto &publication_date = row[1]; const auto &frame_reference_epoch = row[2]; - const bool deprecated = row[3] == "1"; + const auto &ensemble_accuracy = row[3]; + const bool deprecated = row[4] == "1"; auto props = d->createPropertiesSearchUsages("vertical_datum", code, name, deprecated); - if (!publication_date.empty()) { - props.set("PUBLICATION_DATE", publication_date); - } - if (d->authority() == "ESRI" && starts_with(code, "from_geogdatum_")) { - props.set("VERT_DATUM_TYPE", "2002"); - } - auto anchor = util::optional<std::string>(); - if (frame_reference_epoch.empty()) { - return datum::VerticalReferenceFrame::create(props, anchor); + if (!turnEnsembleAsDatum && !ensemble_accuracy.empty()) { + auto resMembers = + d->run("SELECT member_auth_name, member_code FROM " + "vertical_datum_ensemble_member WHERE " + "ensemble_auth_name = ? AND ensemble_code = ? " + "ORDER BY sequence", + {d->authority(), code}); + + std::vector<datum::DatumNNPtr> members; + for (const auto &memberRow : resMembers) { + members.push_back( + d->createFactory(memberRow[0])->createDatum(memberRow[1])); + } + auto datumEnsemble = datum::DatumEnsemble::create( + props, std::move(members), + metadata::PositionalAccuracy::create(ensemble_accuracy)); + outDatumEnsemble = datumEnsemble.as_nullable(); } else { - return datum::DynamicVerticalReferenceFrame::create( - props, anchor, util::optional<datum::RealizationMethod>(), - common::Measure(c_locale_stod(frame_reference_epoch), - common::UnitOfMeasure::YEAR), - util::optional<std::string>()); + if (!publication_date.empty()) { + props.set("PUBLICATION_DATE", publication_date); + } + if (d->authority() == "ESRI" && + starts_with(code, "from_geogdatum_")) { + props.set("VERT_DATUM_TYPE", "2002"); + } + auto anchor = util::optional<std::string>(); + if (frame_reference_epoch.empty()) { + outDatum = datum::VerticalReferenceFrame::create(props, anchor) + .as_nullable(); + } else { + outDatum = + datum::DynamicVerticalReferenceFrame::create( + props, anchor, + util::optional<datum::RealizationMethod>(), + common::Measure(c_locale_stod(frame_reference_epoch), + common::UnitOfMeasure::YEAR), + util::optional<std::string>()) + .as_nullable(); + } } } catch (const std::exception &ex) { throw buildFactoryException("vertical reference frame", code, ex); @@ -2472,20 +2640,24 @@ AuthorityFactory::createGeodeticCRS(const std::string &code, auto cs = d->createFactory(cs_auth_name)->createCoordinateSystem(cs_code); - auto datum = - d->createFactory(datum_auth_name)->createGeodeticDatum(datum_code); + datum::GeodeticReferenceFramePtr datum; + datum::DatumEnsemblePtr datumEnsemble; + constexpr bool turnEnsembleAsDatum = false; + d->createFactory(datum_auth_name) + ->createGeodeticDatumOrEnsemble(datum_code, datum, datumEnsemble, + turnEnsembleAsDatum); auto ellipsoidalCS = util::nn_dynamic_pointer_cast<cs::EllipsoidalCS>(cs); if ((type == GEOG_2D || type == GEOG_3D) && ellipsoidalCS) { auto crsRet = crs::GeographicCRS::create( - props, datum, NN_NO_CHECK(ellipsoidalCS)); + props, datum, datumEnsemble, NN_NO_CHECK(ellipsoidalCS)); d->context()->d->cache(cacheKey, crsRet); return crsRet; } auto geocentricCS = util::nn_dynamic_pointer_cast<cs::CartesianCS>(cs); if (type == GEOCENTRIC && geocentricCS) { - auto crsRet = crs::GeodeticCRS::create(props, datum, + auto crsRet = crs::GeodeticCRS::create(props, datum, datumEnsemble, NN_NO_CHECK(geocentricCS)); d->context()->d->cache(cacheKey, crsRet); return crsRet; @@ -2539,16 +2711,19 @@ AuthorityFactory::createVerticalCRS(const std::string &code) const { const bool deprecated = row[5] == "1"; auto cs = d->createFactory(cs_auth_name)->createCoordinateSystem(cs_code); - auto datum = - d->createFactory(datum_auth_name)->createVerticalDatum(datum_code); - + datum::VerticalReferenceFramePtr datum; + datum::DatumEnsemblePtr datumEnsemble; + constexpr bool turnEnsembleAsDatum = false; + d->createFactory(datum_auth_name) + ->createVerticalDatumOrEnsemble(datum_code, datum, datumEnsemble, + turnEnsembleAsDatum); auto props = d->createPropertiesSearchUsages("vertical_crs", code, name, deprecated); auto verticalCS = util::nn_dynamic_pointer_cast<cs::VerticalCS>(cs); if (verticalCS) { - auto crsRet = - crs::VerticalCRS::create(props, datum, NN_NO_CHECK(verticalCS)); + auto crsRet = crs::VerticalCRS::create(props, datum, datumEnsemble, + NN_NO_CHECK(verticalCS)); d->context()->d->cache(cacheKey, crsRet); return crsRet; } @@ -5340,6 +5515,11 @@ AuthorityFactory::getAuthorityCodes(const ObjectType &type, case ObjectType::CONCATENATED_OPERATION: sql = "SELECT code FROM concatenated_operation WHERE "; break; + case ObjectType::DATUM_ENSEMBLE: + sql = "SELECT code FROM object_view WHERE table_name IN " + "('geodetic_datum', 'vertical_datum') AND " + "type = 'ensemble' AND "; + break; } sql += "auth_name = ?"; @@ -5617,7 +5797,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias( if (res.empty()) { // shouldn't happen normally return std::string(); } - return removeEnsembleSuffix(res.front()[0]); + return res.front()[0]; } } return std::string(); @@ -5667,7 +5847,7 @@ std::string AuthorityFactory::getOfficialNameFromAlias( outTableName = row[1]; outAuthName = row[2]; outCode = row[3]; - return removeEnsembleSuffix(row[0]); + return row[0]; } } @@ -5849,12 +6029,28 @@ AuthorityFactory::createObjectsFromNameEx( res.emplace_back( TableType("concatenated_operation", std::string())); break; + case ObjectType::DATUM_ENSEMBLE: + res.emplace_back(TableType("geodetic_datum", "ensemble")); + res.emplace_back(TableType("vertical_datum", "ensemble")); + break; } } } return res; }; + bool datumEnsembleAllowed = false; + if (allowedObjectTypes.empty()) { + datumEnsembleAllowed = true; + } else { + for (const auto type : allowedObjectTypes) { + if (type == ObjectType::DATUM_ENSEMBLE) { + datumEnsembleAllowed = true; + break; + } + } + } + const auto listTableNameType = getTableAndTypeConstraints(); bool first = true; ListOfParams params; @@ -5872,6 +6068,8 @@ AuthorityFactory::createObjectsFromNameEx( if (!tableNameTypePair.second.empty()) { if (tableNameTypePair.second == "frame_reference_epoch") { sql += "AND frame_reference_epoch IS NOT NULL "; + } else if (tableNameTypePair.second == "ensemble") { + sql += "AND ensemble_accuracy IS NOT NULL "; } else { sql += "AND type = '"; sql += tableNameTypePair.second; @@ -5906,6 +6104,8 @@ AuthorityFactory::createObjectsFromNameEx( if (!tableNameTypePair.second.empty()) { if (tableNameTypePair.second == "frame_reference_epoch") { sql += "AND ov.frame_reference_epoch IS NOT NULL "; + } else if (tableNameTypePair.second == "ensemble") { + sql += "AND ov.ensemble_accuracy IS NOT NULL "; } else { sql += "AND ov.type = '"; sql += tableNameTypePair.second; @@ -6019,6 +6219,8 @@ AuthorityFactory::createObjectsFromNameEx( auto sqlRes = d->run(sql, params); bool isFirst = true; bool firstIsDeprecated = false; + bool foundExactMatch = false; + std::size_t hashCodeFirstMatch = 0; for (const auto &row : sqlRes) { const auto &name = row[3]; if (approximateMatch) { @@ -6053,7 +6255,7 @@ AuthorityFactory::createObjectsFromNameEx( break; } auto factory = d->createFactory(auth_name); - auto getObject = [&factory]( + auto getObject = [&factory, datumEnsembleAllowed]( const std::string &l_table_name, const std::string &l_code) -> common::IdentifiedObjectNNPtr { if (l_table_name == "prime_meridian") { @@ -6061,8 +6263,32 @@ AuthorityFactory::createObjectsFromNameEx( } else if (l_table_name == "ellipsoid") { return factory->createEllipsoid(l_code); } else if (l_table_name == "geodetic_datum") { + if (datumEnsembleAllowed) { + datum::GeodeticReferenceFramePtr datum; + datum::DatumEnsemblePtr datumEnsemble; + constexpr bool turnEnsembleAsDatum = false; + factory->createGeodeticDatumOrEnsemble( + l_code, datum, datumEnsemble, turnEnsembleAsDatum); + if (datum) { + return NN_NO_CHECK(datum); + } + assert(datumEnsemble); + return NN_NO_CHECK(datumEnsemble); + } return factory->createGeodeticDatum(l_code); } else if (l_table_name == "vertical_datum") { + if (datumEnsembleAllowed) { + datum::VerticalReferenceFramePtr datum; + datum::DatumEnsemblePtr datumEnsemble; + constexpr bool turnEnsembleAsDatum = false; + factory->createVerticalDatumOrEnsemble( + l_code, datum, datumEnsemble, turnEnsembleAsDatum); + if (datum) { + return NN_NO_CHECK(datum); + } + assert(datumEnsemble); + return NN_NO_CHECK(datumEnsemble); + } return factory->createVerticalDatum(l_code); } else if (l_table_name == "geodetic_crs") { return factory->createGeodeticCRS(l_code); @@ -6082,11 +6308,38 @@ AuthorityFactory::createObjectsFromNameEx( } throw std::runtime_error("Unsupported table_name"); }; - res.emplace_back(PairObjectName(getObject(table_name, code), name)); + const auto obj = getObject(table_name, code); + if (metadata::Identifier::canonicalizeName(obj->nameStr()) == + canonicalizedSearchedName) { + foundExactMatch = true; + } + + const auto objPtr = obj.get(); + if (res.empty()) { + hashCodeFirstMatch = typeid(*objPtr).hash_code(); + } else if (hashCodeFirstMatch != typeid(*objPtr).hash_code()) { + hashCodeFirstMatch = 0; + } + + res.emplace_back(PairObjectName(obj, name)); if (limitResultCount > 0 && res.size() == limitResultCount) { break; } } + + // If we found a name that is an exact match, and all objects have the + // same type, and we are not in approximate mode, only keep the objet(s) + // with the exact name match. + if (foundExactMatch && hashCodeFirstMatch != 0 && !approximateMatch) { + std::list<PairObjectName> resTmp; + for (const auto &pair : res) { + if (metadata::Identifier::canonicalizeName( + pair.first->nameStr()) == canonicalizedSearchedName) { + resTmp.emplace_back(pair); + } + } + res = std::move(resTmp); + } } auto sortLambda = [](const PairObjectName &a, const PairObjectName &b) { diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index f4ec7740..8a42e7ee 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -70,7 +70,6 @@ // clang-format off #include "proj.h" #include "proj_internal.h" -#include "proj_api.h" // clang-format on using namespace NS_PROJ::common; @@ -140,6 +139,7 @@ struct WKTFormatter::Private { bool primeMeridianInDegree_ = false; bool use2019Keywords_ = false; bool useESRIDialect_ = false; + bool allowEllipsoidalHeightAsVerticalCRS_ = false; OutputAxisRule outputAxis_ = WKTFormatter::OutputAxisRule::YES; }; Params params_{}; @@ -251,6 +251,8 @@ WKTFormatter::setOutputAxis(OutputAxisRule outputAxisIn) noexcept { * * The default is strict mode, in which case a FormattingException can be * thrown. + * In non-strict mode, a Geographic 3D CRS can be for example exported as + * WKT1_GDAL with 3 axes, whereas this is normally not allowed. */ WKTFormatter &WKTFormatter::setStrict(bool strictIn) noexcept { d->params_.strict_ = strictIn; @@ -264,6 +266,28 @@ bool WKTFormatter::isStrict() const noexcept { return d->params_.strict_; } // --------------------------------------------------------------------------- +/** \brief Set whether the formatter should export, in WKT1, a Geographic or + * Projected 3D CRS as a compound CRS whose vertical part represents an + * ellipsoidal height. + */ +WKTFormatter & +WKTFormatter::setAllowEllipsoidalHeightAsVerticalCRS(bool allow) noexcept { + d->params_.allowEllipsoidalHeightAsVerticalCRS_ = allow; + return *this; +} + +// --------------------------------------------------------------------------- + +/** \brief Return whether the formatter should export, in WKT1, a Geographic or + * Projected 3D CRS as a compound CRS whose vertical part represents an + * ellipsoidal height. + */ +bool WKTFormatter::isAllowedEllipsoidalHeightAsVerticalCRS() const noexcept { + return d->params_.allowEllipsoidalHeightAsVerticalCRS_; +} + +// --------------------------------------------------------------------------- + /** Returns the WKT string from the formatter. */ const std::string &WKTFormatter::toString() const { if (d->indentLevel_ > 0 || d->level_ > 0) { @@ -1979,14 +2003,80 @@ PrimeMeridianNNPtr WKTParser::Private::buildPrimeMeridian( try { double angleValue = asDouble(children[1]); - // Correct for GDAL WKT1 departure + // Correct for GDAL WKT1 and WKT1-ESRI departure if (name == "Paris" && std::fabs(angleValue - 2.33722917) < 1e-8 && - unit == UnitOfMeasure::GRAD) { + unit._isEquivalentTo(UnitOfMeasure::GRAD, + util::IComparable::Criterion::EQUIVALENT)) { angleValue = 2.5969213; + } else { + static const struct { + const char *name; + int deg; + int min; + double sec; + } primeMeridiansDMS[] = { + {"Lisbon", -9, 7, 54.862}, {"Bogota", -74, 4, 51.3}, + {"Madrid", -3, 41, 14.55}, {"Rome", 12, 27, 8.4}, + {"Bern", 7, 26, 22.5}, {"Jakarta", 106, 48, 27.79}, + {"Ferro", -17, 40, 0}, {"Brussels", 4, 22, 4.71}, + {"Stockholm", 18, 3, 29.8}, {"Athens", 23, 42, 58.815}, + {"Oslo", 10, 43, 22.5}, {"Paris RGS", 2, 20, 13.95}, + {"Paris_RGS", 2, 20, 13.95}}; + + // Current epsg.org output may use the EPSG:9110 "sexagesimal DMS" + // unit and a DD.MMSSsss value, but this will likely be changed to + // use decimal degree. + // Or WKT1 may for example use the Paris RGS decimal degree value + // but with a GEOGCS with UNIT["Grad"] + for (const auto &pmDef : primeMeridiansDMS) { + if (name == pmDef.name) { + double dmsAsDecimalValue = + (pmDef.deg >= 0 ? 1 : -1) * + (std::abs(pmDef.deg) + pmDef.min / 100. + + pmDef.sec / 10000.); + double dmsAsDecimalDegreeValue = + (pmDef.deg >= 0 ? 1 : -1) * + (std::abs(pmDef.deg) + pmDef.min / 60. + + pmDef.sec / 3600.); + if (std::fabs(angleValue - dmsAsDecimalValue) < 1e-8 || + std::fabs(angleValue - dmsAsDecimalDegreeValue) < + 1e-8) { + angleValue = dmsAsDecimalDegreeValue; + unit = UnitOfMeasure::DEGREE; + } + break; + } + } + } + + auto &properties = buildProperties(node); + if (dbContext_ && esriStyle_) { + std::string outTableName; + std::string codeFromAlias; + std::string authNameFromAlias; + auto authFactory = AuthorityFactory::create(NN_NO_CHECK(dbContext_), + std::string()); + auto officialName = authFactory->getOfficialNameFromAlias( + name, "prime_meridian", "ESRI", false, outTableName, + authNameFromAlias, codeFromAlias); + if (!officialName.empty()) { + properties.set(IdentifiedObject::NAME_KEY, officialName); + if (!authNameFromAlias.empty()) { + auto identifiers = ArrayOfBaseObject::create(); + identifiers->add(Identifier::create( + codeFromAlias, + PropertyMap() + .set(Identifier::CODESPACE_KEY, authNameFromAlias) + .set(Identifier::AUTHORITY_KEY, + authNameFromAlias))); + properties.set(IdentifiedObject::IDENTIFIERS_KEY, + identifiers); + } + } } Angle angle(angleValue, unit); - return PrimeMeridian::create(buildProperties(node), angle); + return PrimeMeridian::create(properties, angle); } catch (const std::exception &e) { throw buildRethrow(__FUNCTION__, e); } @@ -2098,9 +2188,15 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( return false; }; - if (name == "WGS_1984") { + // Remap GDAL WGS_1984 to EPSG v9 "World Geodetic System 1984" official + // name. + // Also remap EPSG v10 datum ensemble names to non-ensemble EPSG v9 + if (name == "WGS_1984" || name == "World Geodetic System 1984 ensemble") { properties.set(IdentifiedObject::NAME_KEY, GeodeticReferenceFrame::EPSG_6326->nameStr()); + } else if (name == "European Terrestrial Reference System 1989 ensemble") { + properties.set(IdentifiedObject::NAME_KEY, + "European Terrestrial Reference System 1989"); } else if (starts_with(name, "D_")) { esriStyle_ = true; const char *tableNameForAlias = nullptr; @@ -2110,6 +2206,10 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame( name = "World Geodetic System 1984"; authNameFromAlias = Identifier::EPSG; codeFromAlias = "6326"; + } else if (name == "D_ETRS_1989") { + name = "European Terrestrial Reference System 1989"; + authNameFromAlias = Identifier::EPSG; + codeFromAlias = "6258"; } else { tableNameForAlias = "geodetic_datum"; } @@ -2734,6 +2834,9 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) { throw ParsingException("Missing DATUM or ENSEMBLE node"); } + // Do that now so that esriStyle_ can be set before buildPrimeMeridian() + auto props = buildProperties(node); + auto &dynamicNode = nodeP->lookForChild(WKTConstants::DYNAMIC); auto &csNode = nodeP->lookForChild(WKTConstants::CS_); @@ -2771,7 +2874,6 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) { angularUnit = primeMeridian->longitude().unit(); } - auto props = buildProperties(node); addExtensionProj4ToProp(nodeP, props); // No explicit AXIS node ? (WKT1) @@ -2790,6 +2892,32 @@ WKTParser::Private::buildGeodeticCRS(const WKTNodeNNPtr &node) { .as_nullable() : nullptr; auto cs = buildCS(csNode, node, angularUnit); + + // If there's no CS[] node, typically for a BASEGEODCRS of a projected CRS, + // in a few rare cases, this might be a Geocentric CRS, and thus a + // Cartesian CS, and not the ellipsoidalCS we assumed above. The only way + // to figure that is to resolve the CRS from its code... + if (isNull(csNode) && dbContext_ && + ci_equal(nodeName, WKTConstants::BASEGEODCRS)) { + const auto &nodeChildren = nodeP->children(); + for (const auto &subNode : nodeChildren) { + const auto &subNodeName(subNode->GP()->value()); + if (ci_equal(subNodeName, WKTConstants::ID) || + ci_equal(subNodeName, WKTConstants::AUTHORITY)) { + auto id = buildId(subNode, true, false); + if (id) { + try { + auto authFactory = AuthorityFactory::create( + NN_NO_CHECK(dbContext_), *id->codeSpace()); + auto dbCRS = authFactory->createGeodeticCRS(id->code()); + cs = dbCRS->coordinateSystem(); + } catch (const util::Exception &) { + } + } + } + } + } + auto ellipsoidalCS = nn_dynamic_pointer_cast<EllipsoidalCS>(cs); if (ellipsoidalCS) { if (ci_equal(nodeName, WKTConstants::GEOCCS)) { @@ -2940,7 +3068,8 @@ UnitOfMeasure WKTParser::Private::guessUnitForParameter( const UnitOfMeasure &defaultAngularUnit) { UnitOfMeasure unit; // scale must be first because of 'Scale factor on pseudo standard parallel' - if (ci_find(paramName, "scale") != std::string::npos) { + if (ci_find(paramName, "scale") != std::string::npos || + ci_find(paramName, "scaling factor") != std::string::npos) { unit = UnitOfMeasure::SCALE_UNITY; } else if (ci_find(paramName, "latitude") != std::string::npos || ci_find(paramName, "longitude") != std::string::npos || @@ -3872,8 +4001,16 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { return createPseudoMercator(props, NN_NO_CHECK(cartesianCS)); } - auto linearUnit = buildUnitInSubNode(node, UnitOfMeasure::Type::LINEAR); - auto angularUnit = baseGeodCRS->coordinateSystem()->axisList()[0]->unit(); + // For WKT2, if there is no explicit parameter unit, use metre for linear + // units and degree for angular units + auto linearUnit = + !isNull(conversionNode) + ? UnitOfMeasure::METRE + : buildUnitInSubNode(node, UnitOfMeasure::Type::LINEAR); + auto angularUnit = + !isNull(conversionNode) + ? UnitOfMeasure::DEGREE + : baseGeodCRS->coordinateSystem()->axisList()[0]->unit(); auto conversion = !isNull(conversionNode) @@ -4941,6 +5078,10 @@ class JSONParser { TransformationNNPtr buildTransformation(const json &j); ConcatenatedOperationNNPtr buildConcatenatedOperation(const json &j); + void buildGeodeticDatumOrDatumEnsemble(const json &j, + GeodeticReferenceFramePtr &datum, + DatumEnsemblePtr &datumEnsemble); + static util::optional<std::string> getAnchor(const json &j) { util::optional<std::string> anchor; if (j.contains("anchor")) { @@ -5400,9 +5541,9 @@ BaseObjectNNPtr JSONParser::create(const json &j) // --------------------------------------------------------------------------- -GeographicCRSNNPtr JSONParser::buildGeographicCRS(const json &j) { - GeodeticReferenceFramePtr datum; - DatumEnsemblePtr datumEnsemble; +void JSONParser::buildGeodeticDatumOrDatumEnsemble( + const json &j, GeodeticReferenceFramePtr &datum, + DatumEnsemblePtr &datumEnsemble) { if (j.contains("datum")) { auto datumJ = getObject(j, "datum"); datum = util::nn_dynamic_pointer_cast<GeodeticReferenceFrame>( @@ -5415,6 +5556,14 @@ GeographicCRSNNPtr JSONParser::buildGeographicCRS(const json &j) { datumEnsemble = buildDatumEnsemble(getObject(j, "datum_ensemble")).as_nullable(); } +} + +// --------------------------------------------------------------------------- + +GeographicCRSNNPtr JSONParser::buildGeographicCRS(const json &j) { + GeodeticReferenceFramePtr datum; + DatumEnsemblePtr datumEnsemble; + buildGeodeticDatumOrDatumEnsemble(j, datum, datumEnsemble); auto csJ = getObject(j, "coordinate_system"); auto ellipsoidalCS = util::nn_dynamic_pointer_cast<EllipsoidalCS>(buildCS(csJ)); @@ -5428,12 +5577,9 @@ GeographicCRSNNPtr JSONParser::buildGeographicCRS(const json &j) { // --------------------------------------------------------------------------- GeodeticCRSNNPtr JSONParser::buildGeodeticCRS(const json &j) { - auto datumJ = getObject(j, "datum"); - if (getType(datumJ) != "GeodeticReferenceFrame") { - throw ParsingException("Unsupported type for datum."); - } - auto datum = buildGeodeticReferenceFrame(datumJ); + GeodeticReferenceFramePtr datum; DatumEnsemblePtr datumEnsemble; + buildGeodeticDatumOrDatumEnsemble(j, datum, datumEnsemble); auto csJ = getObject(j, "coordinate_system"); auto cs = buildCS(csJ); auto props = buildProperties(j); @@ -5468,7 +5614,13 @@ GeodeticCRSNNPtr JSONParser::buildGeodeticCRS(const json &j) { // --------------------------------------------------------------------------- ProjectedCRSNNPtr JSONParser::buildProjectedCRS(const json &j) { - auto baseCRS = buildGeographicCRS(getObject(j, "base_crs")); + auto jBaseCRS = getObject(j, "base_crs"); + auto jBaseCS = getObject(jBaseCRS, "coordinate_system"); + auto baseCS = buildCS(jBaseCS); + auto baseCRS = dynamic_cast<EllipsoidalCS *>(baseCS.get()) != nullptr + ? util::nn_static_pointer_cast<GeodeticCRS>( + buildGeographicCRS(jBaseCRS)) + : buildGeodeticCRS(jBaseCRS); auto csJ = getObject(j, "coordinate_system"); auto cartesianCS = util::nn_dynamic_pointer_cast<CartesianCS>(buildCS(csJ)); if (!cartesianCS) { @@ -6263,6 +6415,9 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, if (type == "datum") { return factory->createDatum(code); } + if (type == "ensemble") { + return factory->createDatumEnsemble(code); + } if (type == "ellipsoid") { return factory->createEllipsoid(code); } @@ -6381,6 +6536,8 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, AuthorityFactory::ObjectType:: DATUM, AuthorityFactory::ObjectType:: + DATUM_ENSEMBLE, + AuthorityFactory::ObjectType:: COORDINATE_OPERATION}, goOn); } catch (const std::exception &) { @@ -9460,8 +9617,8 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( std::string methodName = "PROJ " + step.name; for (const auto ¶m : step.paramValues) { if (is_in_stringlist(param.key, - "wktext,no_defs,datum,ellps,a,b,R,towgs84," - "nadgrids,geoidgrids," + "wktext,no_defs,datum,ellps,a,b,R,f,rf," + "towgs84,nadgrids,geoidgrids," "units,to_meter,vunits,vto_meter,type")) { continue; } @@ -9761,7 +9918,7 @@ PROJStringParser::createFromPROJString(const std::string &projString) { paralist *list = pj_expand_init(ctx, init); ctx->projStringParserCreateFromPROJStringRecursionCounter--; if (!list) { - pj_dealloc(init); + free(init); throw ParsingException("cannot expand " + projString); } std::string expanded; @@ -9784,7 +9941,7 @@ PROJStringParser::createFromPROJString(const std::string &projString) { } auto n = t->next; - pj_dealloc(t); + free(t); t = n; } for (const auto &pair : d->steps_[0].paramValues) { diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake index 67bc1f4e..3a4880c6 100644 --- a/src/lib_proj.cmake +++ b/src/lib_proj.cmake @@ -173,6 +173,7 @@ set(SRC_LIBPROJ_CONVERSIONS conversions/geoc.cpp conversions/geocent.cpp conversions/noop.cpp + conversions/topocentric.cpp conversions/set.cpp conversions/unitconvert.cpp ) @@ -217,9 +218,7 @@ set(SRC_LIBPROJ_CORE dmstor.cpp ell_set.cpp ellps.cpp - errno.cpp factors.cpp - fileapi.cpp fwd.cpp gauss.cpp generic_inverse.cpp @@ -246,10 +245,8 @@ set(SRC_LIBPROJ_CORE rtodms.cpp strerrno.cpp strtod.cpp - transform.cpp tsfn.cpp units.cpp - utils.cpp wkt1_generated_parser.c wkt1_generated_parser.h wkt1_parser.cpp @@ -275,7 +272,6 @@ set(SRC_LIBPROJ_CORE ) set(HEADERS_LIBPROJ - proj_api.h proj.h proj_experimental.h proj_constants.h diff --git a/src/log.cpp b/src/log.cpp index 3cc10cfd..c343e65b 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -48,9 +48,9 @@ void pj_stderr_logger( void *app_data, int level, const char *msg ) /************************************************************************/ /* pj_vlog() */ /************************************************************************/ -void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ); +void pj_vlog( PJ_CONTEXT *ctx, int level, const char *fmt, va_list args ); /* Workhorse for the log functions - relates to pj_log as vsprintf relates to sprintf */ -void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ) +void pj_vlog( PJ_CONTEXT *ctx, int level, const char *fmt, va_list args ) { char *msg_buf; @@ -84,7 +84,7 @@ void pj_vlog( projCtx ctx, int level, const char *fmt, va_list args ) /* pj_log() */ /************************************************************************/ -void pj_log( projCtx ctx, int level, const char *fmt, ... ) +void pj_log( PJ_CONTEXT *ctx, int level, const char *fmt, ... ) { va_list args; diff --git a/src/malloc.cpp b/src/malloc.cpp index c8de6630..6b7fbf26 100644 --- a/src/malloc.cpp +++ b/src/malloc.cpp @@ -53,99 +53,13 @@ using namespace NS_PROJ; -/**********************************************************************/ -void *pj_malloc(size_t size) { -/*********************************************************************** -Currently, pj_malloc is a hack to solve an errno problem. -The problem is described in more details at -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. - -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 (nullptr==res) - return nullptr; - memset (res, 0, n*size); - return res; -} - - -/**********************************************************************/ -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: - - struct foo { int bar; int *baz; }; - - struct foo *p = pj_calloc (1, sizeof (struct foo)); - if (0==p) - return 0; - - p->baz = pj_calloc (10, sizeof(int)); - if (0==p->baz) - return pj_dealloc (p); // clean up + signal error by 0-return - - return p; // success - -***********************************************************************/ - if (nullptr==ptr) - return nullptr; - pj_dalloc (ptr); - return nullptr; -} /**********************************************************************/ char *pj_strdup(const char *str) /**********************************************************************/ { size_t len = strlen(str) + 1; - char *dup = static_cast<char*>(pj_malloc(len)); + char *dup = static_cast<char*>(malloc(len)); if (dup) memcpy(dup, str, len); return dup; @@ -153,7 +67,7 @@ char *pj_strdup(const char *str) /*****************************************************************************/ -void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { +void *free_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { /***************************************************************************** Companion to pj_default_destructor (below). Deallocates a linked list of "+proj=xxx" initialization parameters. @@ -164,9 +78,9 @@ void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { paralist *t, *n; for (t = start; t; t = n) { n = t->next; - pj_dealloc(t); + free(t); } - pj_ctx_set_errno (ctx, errlev); + proj_context_errno_set (ctx, errlev); return (void *) nullptr; } @@ -174,7 +88,7 @@ void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { /************************************************************************/ -/* pj_free() */ +/* proj_destroy() */ /* */ /* This is the application callable entry point for destroying */ /* a projection definition. It does work generic to all */ @@ -183,15 +97,16 @@ void *pj_dealloc_params (PJ_CONTEXT *ctx, paralist *start, int errlev) { /* In most cases P->destructor()==pj_default_destructor. */ /************************************************************************/ -void pj_free(PJ *P) { +PJ *proj_destroy(PJ *P) { if (nullptr==P || !P->destructor) - return; + return nullptr; /* free projection parameters - all the hard work is done by */ /* pj_default_destructor, 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, proj_errno(P)); + return nullptr; } /*****************************************************************************/ @@ -218,42 +133,42 @@ PJ *pj_default_destructor (PJ *P, int errlev) { /* Destructor */ /* Note that both, in the multithreaded case, may then contain undefined */ /* values. This is expected behavior. For MT have one ctx per thread */ if (0!=errlev) - pj_ctx_set_errno (pj_get_ctx(P), errlev); + proj_context_errno_set (pj_get_ctx(P), errlev); if (nullptr==P) return nullptr; - pj_dealloc(P->def_size); - pj_dealloc(P->def_shape); - pj_dealloc(P->def_spherification); - pj_dealloc(P->def_ellps); + free(P->def_size); + free(P->def_shape); + free(P->def_spherification); + free(P->def_ellps); delete static_cast<ListOfHGrids*>(P->hgrids_legacy); delete static_cast<ListOfVGrids*>(P->vgrids_legacy); - /* We used to call pj_dalloc( P->catalog ), but this will leak */ + /* We used to call free( 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(); */ + /* pj_gc_unloadall(pj_get_default_ctx()); and freeate_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( P->geod ); /* free parameter list elements */ - pj_dealloc_params (pj_get_ctx(P), P->params, errlev); - pj_dealloc (P->def_full); + free_params (pj_get_ctx(P), P->params, errlev); + free (P->def_full); /* free the cs2cs emulation elements */ - pj_free (P->axisswap); - pj_free (P->helmert); - pj_free (P->cart); - pj_free (P->cart_wgs84); - pj_free (P->hgridshift); - pj_free (P->vgridshift); - - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)); + proj_destroy (P->axisswap); + proj_destroy (P->helmert); + proj_destroy (P->cart); + proj_destroy (P->cart_wgs84); + proj_destroy (P->hgridshift); + proj_destroy (P->vgridshift); + + free (static_cast<struct pj_opaque*>(P->opaque)); delete P; return nullptr; } @@ -262,7 +177,6 @@ PJ *pj_default_destructor (PJ *P, int errlev) { /* Destructor */ void proj_cleanup() { /*****************************************************************************/ pj_clear_initcache(); - pj_deallocate_grids(); FileManager::clearMemoryCache(); pj_clear_hgridshift_knowngrids_cache(); pj_clear_vgridshift_knowngrids_cache(); diff --git a/src/mlfn.cpp b/src/mlfn.cpp index 80f9163b..763d83ee 100644 --- a/src/mlfn.cpp +++ b/src/mlfn.cpp @@ -26,7 +26,7 @@ double *pj_enfn(double es) { double t, *en; - en = (double *) pj_malloc(EN_SIZE * sizeof (double)); + en = (double *) malloc(EN_SIZE * sizeof (double)); if (nullptr==en) return nullptr; @@ -45,7 +45,7 @@ pj_mlfn(double phi, double sphi, double cphi, const double *en) { } double -pj_inv_mlfn(projCtx ctx, double arg, double es, const double *en) { +pj_inv_mlfn(PJ_CONTEXT *ctx, double arg, double es, const double *en) { double sinphi_ignored; double cosphi_ignored; return inline_pj_inv_mlfn(ctx, arg, es, en, &sinphi_ignored, &cosphi_ignored); diff --git a/src/mlfn.hpp b/src/mlfn.hpp index 26a2959f..228c65a4 100644 --- a/src/mlfn.hpp +++ b/src/mlfn.hpp @@ -15,7 +15,7 @@ inline static double inline_pj_mlfn(double phi, double sphi, double cphi, const } inline static double -inline_pj_inv_mlfn(projCtx ctx, double arg, double es, const double *en, +inline_pj_inv_mlfn(PJ_CONTEXT *ctx, double arg, double es, const double *en, double* sinphi, double* cosphi) { const double k = 1./(1.-es); constexpr double INV_MLFN_EPS = 1e-11; @@ -66,7 +66,7 @@ inline_pj_inv_mlfn(projCtx ctx, double arg, double es, const double *en, } *sinphi = s; *cosphi = c; - pj_ctx_set_errno( ctx, PJD_ERR_NON_CONV_INV_MERI_DIST ); + proj_context_errno_set( ctx, PJD_ERR_NON_CONV_INV_MERI_DIST ); return phi; } diff --git a/src/mutex.cpp b/src/mutex.cpp index da415e55..b1a23ccd 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -33,13 +33,8 @@ #include "proj.h" #ifndef _WIN32 #include "proj_config.h" -#include "proj_internal.h" -#else -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif -#include "proj_api.h" #endif +#include "proj_internal.h" /* on win32 we always use win32 mutexes, even if pthreads are available */ #if defined(_WIN32) && !defined(MUTEX_stub) @@ -184,7 +179,7 @@ void pj_cleanup_lock() #include <windows.h> -static HANDLE mutex_lock = NULL; +static HANDLE mutex_lock = nullptr; #if _WIN32_WINNT >= 0x0600 @@ -199,7 +194,7 @@ static BOOL CALLBACK pj_create_lock(PINIT_ONCE InitOnce, (void)InitOnce; (void)Parameter; (void)Context; - mutex_lock = CreateMutex( NULL, FALSE, NULL ); + mutex_lock = CreateMutex( nullptr, FALSE, nullptr ); return TRUE; } #endif @@ -213,10 +208,10 @@ static void pj_init_lock() { #if _WIN32_WINNT >= 0x0600 static INIT_ONCE sInitOnce = INIT_ONCE_STATIC_INIT; - InitOnceExecuteOnce( &sInitOnce, pj_create_lock, NULL, NULL ); + InitOnceExecuteOnce( &sInitOnce, pj_create_lock, nullptr, nullptr ); #else - if( mutex_lock == NULL ) - mutex_lock = CreateMutex( NULL, FALSE, NULL ); + if( mutex_lock == nullptr ) + mutex_lock = CreateMutex( nullptr, FALSE, nullptr ); #endif } @@ -228,7 +223,7 @@ static void pj_init_lock() void pj_acquire_lock() { - if( mutex_lock == NULL ) + if( mutex_lock == nullptr ) pj_init_lock(); WaitForSingleObject( mutex_lock, INFINITE ); @@ -242,7 +237,7 @@ void pj_acquire_lock() void pj_release_lock() { - if( mutex_lock == NULL ) + if( mutex_lock == nullptr ) pj_init_lock(); else ReleaseMutex( mutex_lock ); @@ -253,10 +248,10 @@ void pj_release_lock() /************************************************************************/ void pj_cleanup_lock() { - if( mutex_lock != NULL ) + if( mutex_lock != nullptr ) { CloseHandle( mutex_lock ); - mutex_lock = NULL; + mutex_lock = nullptr; } } diff --git a/src/networkfilemanager.cpp b/src/networkfilemanager.cpp index f6521ed2..9edffaad 100644 --- a/src/networkfilemanager.cpp +++ b/src/networkfilemanager.cpp @@ -1315,7 +1315,7 @@ std::unique_ptr<File> NetworkFile::open(PJ_CONTEXT *ctx, const char *filename) { errorBuffer.resize(strlen(errorBuffer.data())); pj_log(ctx, PJ_LOG_ERROR, "Cannot open %s: %s", filename, errorBuffer.c_str()); - pj_ctx_set_errno(ctx, PJD_ERR_NETWORK_ERROR); + proj_context_errno_set(ctx, PJD_ERR_NETWORK_ERROR); } bool ok = false; @@ -1404,7 +1404,7 @@ size_t NetworkFile::read(void *buffer, size_t sizeBytes) { &nRead, errorBuffer.size(), &errorBuffer[0], m_ctx->networking.user_data); if (!m_handle) { - pj_ctx_set_errno(m_ctx, PJD_ERR_NETWORK_ERROR); + proj_context_errno_set(m_ctx, PJD_ERR_NETWORK_ERROR); return 0; } } else { @@ -1420,7 +1420,7 @@ size_t NetworkFile::read(void *buffer, size_t sizeBytes) { pj_log(m_ctx, PJ_LOG_ERROR, "Cannot read in %s: %s", m_url.c_str(), errorBuffer.c_str()); } - pj_ctx_set_errno(m_ctx, PJD_ERR_NETWORK_ERROR); + proj_context_errno_set(m_ctx, PJD_ERR_NETWORK_ERROR); return 0; } diff --git a/src/param.cpp b/src/param.cpp index 289faca3..28d6bc3e 100644 --- a/src/param.cpp +++ b/src/param.cpp @@ -38,7 +38,7 @@ static void unquote_string(char* param_str) { paralist *pj_mkparam(const char *str) { paralist *newitem; - if((newitem = (paralist *)pj_malloc(sizeof(paralist) + strlen(str))) != nullptr) { + if((newitem = (paralist *)malloc(sizeof(paralist) + strlen(str))) != nullptr) { newitem->used = 0; newitem->next = nullptr; if (*str == '+') @@ -82,7 +82,7 @@ paralist *pj_mkparam_ws (const char *str, const char **next_str) { *next_str = str + len; /* Use calloc to automagically 0-terminate the copy */ - newitem = (paralist *) pj_calloc (1, sizeof(paralist) + len + 1); + newitem = (paralist *) calloc (1, sizeof(paralist) + len + 1); if (nullptr==newitem) return nullptr; memcpy(newitem->param, str, len); @@ -151,7 +151,7 @@ paralist *pj_param_exists (paralist *list, const char *parameter) { /* */ /************************************************************************/ -PROJVALUE pj_param (projCtx ctx, paralist *pl, const char *opt) { +PROJVALUE pj_param (PJ_CONTEXT *ctx, paralist *pl, const char *opt) { int type; unsigned l; @@ -220,7 +220,7 @@ PROJVALUE pj_param (projCtx ctx, paralist *pl, const char *opt) { value.i = 1; break; default: - pj_ctx_set_errno (ctx, PJD_ERR_INVALID_BOOLEAN_PARAM); + proj_context_errno_set (ctx, PJD_ERR_INVALID_BOOLEAN_PARAM); value.i = 0; break; } diff --git a/src/phi2.cpp b/src/phi2.cpp index b81456b0..2f258e47 100644 --- a/src/phi2.cpp +++ b/src/phi2.cpp @@ -1,68 +1,134 @@ /* Determine latitude angle phi-2. */ #include <math.h> +#include <limits> +#include <algorithm> #include "proj.h" #include "proj_internal.h" -static const double TOL = 1.0e-10; -static const int N_ITER = 15; +double pj_sinhpsi2tanphi(PJ_CONTEXT *ctx, const double taup, const double e) { + /**************************************************************************** + * Convert tau' = sinh(psi) = tan(chi) to tau = tan(phi). The code is taken + * from GeographicLib::Math::tauf(taup, e). + * + * Here + * phi = geographic latitude (radians) + * psi is the isometric latitude + * psi = asinh(tan(phi)) - e * atanh(e * sin(phi)) + * = asinh(tan(chi)) + * chi is the conformal latitude + * + * The representation of latitudes via their tangents, tan(phi) and tan(chi), + * maintains full *relative* accuracy close to latitude = 0 and +/- pi/2. + * This is sometimes important, e.g., to compute the scale of the transverse + * Mercator projection which involves cos(phi)/cos(chi) tan(phi) + * + * From Karney (2011), Eq. 7, + * + * tau' = sinh(psi) = sinh(asinh(tan(phi)) - e * atanh(e * sin(phi))) + * = tan(phi) * cosh(e * atanh(e * sin(phi))) - + * sec(phi) * sinh(e * atanh(e * sin(phi))) + * = tau * sqrt(1 + sigma^2) - sqrt(1 + tau^2) * sigma + * where + * sigma = sinh(e * atanh( e * tau / sqrt(1 + tau^2) )) + * + * For e small, + * + * tau' = (1 - e^2) * tau + * + * The relation tau'(tau) can therefore by reliably inverted by Newton's + * method with + * + * tau = tau' / (1 - e^2) + * + * as an initial guess. Newton's method requires dtau'/dtau. Noting that + * + * dsigma/dtau = e^2 * sqrt(1 + sigma^2) / + * (sqrt(1 + tau^2) * (1 + (1 - e^2) * tau^2)) + * d(sqrt(1 + tau^2))/dtau = tau / sqrt(1 + tau^2) + * + * we have + * + * dtau'/dtau = (1 - e^2) * sqrt(1 + tau'^2) * sqrt(1 + tau^2) / + * (1 + (1 - e^2) * tau^2) + * + * This works fine unless tau^2 and tau'^2 overflows. This may be partially + * cured by writing, e.g., sqrt(1 + tau^2) as hypot(1, tau). However, nan + * will still be generated with tau' = inf, since (inf - inf) will appear in + * the Newton iteration. + * + * If we note that for sufficiently large |tau|, i.e., |tau| >= 2/sqrt(eps), + * sqrt(1 + tau^2) = |tau| and + * + * tau' = exp(- e * atanh(e)) * tau + * + * So + * + * tau = exp(e * atanh(e)) * tau' + * + * can be returned unless |tau| >= 2/sqrt(eps); this then avoids overflow + * problems for large tau' and returns the correct result for tau' = +/-inf + * and nan. + * + * Newton's method usually take 2 iterations to converge to double precision + * accuracy (for WGS84 flattening). However only 1 iteration is needed for + * |chi| < 3.35 deg. In addition, only 1 iteration is needed for |chi| > + * 89.18 deg (tau' > 70), if tau = exp(e * atanh(e)) * tau' is used as the + * starting guess. + ****************************************************************************/ -/*****************************************************************************/ -double pj_phi2(projCtx ctx, const double ts0, const double e) { -/****************************************************************************** -Determine latitude angle phi-2. -Inputs: - ts = exp(-psi) where psi is the isometric latitude (dimensionless) - e = eccentricity of the ellipsoid (dimensionless) -Output: - phi = geographic latitude (radians) -Here isometric latitude is defined by - psi = log( tan(pi/4 + phi/2) * - ( (1 - e*sin(phi)) / (1 + e*sin(phi)) )^(e/2) ) - = asinh(tan(phi)) - e * atanh(e * sin(phi)) -This routine inverts this relation using the iterative scheme given -by Snyder (1987), Eqs. (7-9) - (7-11) -*******************************************************************************/ - const double eccnth = .5 * e; - double ts = ts0; -#ifdef no_longer_used_original_convergence_on_exact_dphi - double Phi = M_HALFPI - 2. * atan(ts); -#endif - int i = N_ITER; + constexpr int numit = 5; + // min iterations = 1, max iterations = 2; mean = 1.954 + static const double rooteps = sqrt(std::numeric_limits<double>::epsilon()); + static const double tol = rooteps / 10; // the criterion for Newton's method + static const double tmax = 2 / rooteps; // threshold for large arg limit exact + const double e2m = 1 - e * e; + const double stol = tol * std::max(1.0, fabs(taup)); + // The initial guess. 70 corresponds to chi = 89.18 deg (see above) + double tau = fabs(taup) > 70 ? taup * exp(e * atanh(e)) : taup / e2m; + if (!(fabs(tau) < tmax)) // handles +/-inf and nan and e = 1 + return tau; + // If we need to deal with e > 1, then we could include: + // if (e2m < 0) return std::numeric_limits<double>::quiet_NaN(); + int i = numit; + for (; i; --i) { + double tau1 = sqrt(1 + tau * tau); + double sig = sinh( e * atanh(e * tau / tau1) ); + double taupa = sqrt(1 + sig * sig) * tau - sig * tau1; + double dtau = ( (taup - taupa) * (1 + e2m * (tau * tau)) / + (e2m * tau1 * sqrt(1 + taupa * taupa)) ); + tau += dtau; + if (!(fabs(dtau) >= stol)) // backwards test to allow nans to succeed. + break; + } + if (i == 0) + proj_context_errno_set(ctx, PJD_ERR_NON_CONV_SINHPSI2TANPHI); + return tau; +} - for(;;) { - /* - * sin(Phi) = sin(PI/2 - 2* atan(ts)) - * = cos(2*atan(ts)) - * = 2*cos^2(atan(ts)) - 1 - * = 2 / (1 + ts^2) - 1 - * = (1 - ts^2) / (1 + ts^2) - */ - const double sinPhi = (1 - ts * ts) / (1 + ts * ts); - const double con = e * sinPhi; - double old_ts = ts; - ts = ts0 * pow((1. - con) / (1. + con), eccnth); -#ifdef no_longer_used_original_convergence_on_exact_dphi - /* The convergence criterion is nominally on exact dphi */ - const double newPhi = M_HALFPI - 2. * atan(ts); - const double dphi = newPhi - Phi; - Phi = newPhi; -#else - /* If we don't immediately update Phi from this, we can - * change the conversion criterion to save us computing atan() at each step. - * Particularly we can observe that: - * |atan(ts) - atan(old_ts)| <= |ts - old_ts| - * So if |ts - old_ts| matches our convergence criterion, we're good. - */ - const double dphi = 2 * (ts - old_ts); -#endif - if (fabs(dphi) > TOL && --i) { - continue; - } - break; - } - if (i <= 0) - pj_ctx_set_errno(ctx, PJD_ERR_NON_CON_INV_PHI2); - return M_HALFPI - 2. * atan(ts); +/*****************************************************************************/ +double pj_phi2(PJ_CONTEXT *ctx, const double ts0, const double e) { + /**************************************************************************** + * Determine latitude angle phi-2. + * Inputs: + * ts = exp(-psi) where psi is the isometric latitude (dimensionless) + * this variable is defined in Snyder (1987), Eq. (7-10) + * e = eccentricity of the ellipsoid (dimensionless) + * Output: + * phi = geographic latitude (radians) + * Here isometric latitude is defined by + * psi = log( tan(pi/4 + phi/2) * + * ( (1 - e*sin(phi)) / (1 + e*sin(phi)) )^(e/2) ) + * = asinh(tan(phi)) - e * atanh(e * sin(phi)) + * = asinh(tan(chi)) + * chi = conformal latitude + * + * This routine converts t = exp(-psi) to + * + * tau' = tan(chi) = sinh(psi) = (1/t - t)/2 + * + * returns atan(sinpsi2tanphi(tau')) + ***************************************************************************/ + return atan(pj_sinhpsi2tanphi(ctx, (1/ts0 - ts0) / 2, e)); } diff --git a/src/pipeline.cpp b/src/pipeline.cpp index 80ee0397..e9d11604 100644 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -294,8 +294,8 @@ static PJ *destructor (PJ *P, int errlev) { auto pipeline = static_cast<struct Pipeline*>(P->opaque); - pj_dealloc (pipeline->argv); - pj_dealloc (pipeline->current_argv); + free (pipeline->argv); + free (pipeline->current_argv); delete pipeline; P->opaque = nullptr; @@ -321,7 +321,7 @@ static const char *argv_sentinel = "step"; static char **argv_params (paralist *params, size_t argc) { char **argv; size_t i = 0; - argv = static_cast<char**>(pj_calloc (argc, sizeof (char *))); + argv = static_cast<char**>(calloc (argc, sizeof (char *))); if (nullptr==argv) return nullptr; for (; params != nullptr; params = params->next) @@ -461,7 +461,7 @@ PJ *OPERATION(pipeline,0) { if (nullptr==argv) return destructor (P, ENOMEM); - pipeline->current_argv = current_argv = static_cast<char**>(pj_calloc (argc, sizeof (char *))); + pipeline->current_argv = current_argv = static_cast<char**>(calloc (argc, sizeof (char *))); if (nullptr==current_argv) return destructor (P, ENOMEM); @@ -533,7 +533,7 @@ PJ *OPERATION(pipeline,0) { int err_to_report = proj_errno(P); if (0==err_to_report) err_to_report = PJD_ERR_MALFORMED_PIPELINE; - proj_log_error (P, "Pipeline: Bad step definition: %s (%s)", current_argv[0], pj_strerrno (err_to_report)); + proj_log_error (P, "Pipeline: Bad step definition: %s (%s)", current_argv[0], proj_errno_string (err_to_report)); return destructor (P, err_to_report); /* ERROR: bad pipeline def */ } next_step->parent = P; @@ -679,7 +679,7 @@ static PJ_COORD pop(PJ_COORD point, PJ *P) { static PJ *setup_pushpop(PJ *P) { - auto pushpop = static_cast<struct PushPop*>(pj_calloc (1, sizeof(struct PushPop))); + auto pushpop = static_cast<struct PushPop*>(calloc (1, sizeof(struct PushPop))); P->opaque = pushpop; if (nullptr==P->opaque) return destructor(P, ENOMEM); diff --git a/src/pj_list.h b/src/pj_list.h index bcdc189e..d00e780f 100644 --- a/src/pj_list.h +++ b/src/pj_list.h @@ -155,6 +155,7 @@ PROJ_HEAD(tinshift, "Triangulation based transformation") PROJ_HEAD(tissot, "Tissot Conic") PROJ_HEAD(tmerc, "Transverse Mercator") PROJ_HEAD(tobmerc, "Tobler-Mercator") +PROJ_HEAD(topocentric, "Geocentric/Topocentric conversion") PROJ_HEAD(tpeqd, "Two Point Equidistant") PROJ_HEAD(tpers, "Tilted perspective") PROJ_HEAD(unitconvert, "Unit conversion") diff --git a/src/pr_list.cpp b/src/pr_list.cpp index 77db5bfb..30fc6571 100644 --- a/src/pr_list.cpp +++ b/src/pr_list.cpp @@ -66,7 +66,7 @@ char *pj_get_def( PJ *P, int options ) size_t def_max = 10; (void) options; - definition = (char *) pj_malloc(def_max); + definition = (char *) malloc(def_max); if (!definition) return nullptr; definition[0] = '\0'; @@ -84,14 +84,14 @@ char *pj_get_def( PJ *P, int options ) char *def2; def_max = def_max * 2 + l + 5; - def2 = (char *) pj_malloc(def_max); + def2 = (char *) malloc(def_max); if (def2) { strcpy( def2, definition ); - pj_dalloc( definition ); + free( definition ); definition = def2; } else { - pj_dalloc( definition ); + free( definition ); return nullptr; } } @@ -119,8 +119,8 @@ #include <stddef.h> /* For size_t */ -#ifdef PROJ_API_H -#error proj.h must be included before proj_api.h +#ifdef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H + #error "The proj_api.h header has been removed from PROJ with version 8.0.0" #endif #ifdef PROJ_RENAME_SYMBOLS @@ -340,9 +340,9 @@ typedef enum PJ_LOG_LEVEL { typedef void (*PJ_LOG_FUNCTION)(void *, int, const char *); -/* The context type - properly namespaced synonym for projCtx */ -struct projCtx_t; -typedef struct projCtx_t PJ_CONTEXT; +/* The context type - properly namespaced synonym for pj_ctx */ +struct pj_ctx; +typedef struct pj_ctx PJ_CONTEXT; /* A P I */ @@ -694,7 +694,8 @@ typedef enum PJ_CATEGORY_PRIME_MERIDIAN, PJ_CATEGORY_DATUM, PJ_CATEGORY_CRS, - PJ_CATEGORY_COORDINATE_OPERATION + PJ_CATEGORY_COORDINATE_OPERATION, + PJ_CATEGORY_DATUM_ENSEMBLE } PJ_CATEGORY; /** \brief Object type. */ diff --git a/src/proj_api.h b/src/proj_api.h deleted file mode 100644 index a26088ca..00000000 --- a/src/proj_api.h +++ /dev/null @@ -1,227 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Public (application) include file for PROJ.4 API, and constants. - * Author: Frank Warmerdam, <warmerdam@pobox.com> - * - ****************************************************************************** - * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com> - * - * 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. - *****************************************************************************/ - -/* - * This version number should be updated with every release! - * - * This file is expected to be removed from the PROJ distribution - * when a few minor-version releases has been made. - * - */ - -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#error 'To use the proj_api.h you must define the macro ACCEPT_USE_OF_DEPRECATED_PROJ_API_H' -#endif - -#ifndef PJ_VERSION -#define PJ_VERSION 800 -#endif - -#ifdef PROJ_RENAME_SYMBOLS -#include "proj_symbol_rename.h" -#endif - - -/* If we're not asked for PJ_VERSION only, give them everything */ -#ifndef PROJ_API_INCLUDED_FOR_PJ_VERSION_ONLY -/* General projections header file */ -#ifndef PROJ_API_H -#define PROJ_API_H - -/* standard inclusions */ -#include <math.h> -#include <stddef.h> -#include <stdlib.h> - -#ifndef PROJ_DLL -#ifdef PROJ_MSVC_DLL_EXPORT -#define PROJ_DLL __declspec(dllexport) -#elif defined(PROJ_MSVC_DLL_IMPORT) -#define PROJ_DLL __declspec(dllimport) -#elif defined(__GNUC__) -#define PROJ_DLL __attribute__ ((visibility("default"))) -#else -#define PROJ_DLL -#endif -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -/* pj_init() and similar functions can be used with a non-C locale */ -/* Can be detected too at runtime if the symbol pj_atof exists */ -#define PJ_LOCALE_SAFE 1 - -#define RAD_TO_DEG 57.295779513082321 -#define DEG_TO_RAD .017453292519943296 - - -#if defined(PROJ_H) -#define PROJ_API_H_NOT_INVOKED_AS_PRIMARY_API -#endif - - - -extern char const PROJ_DLL pj_release[]; /* global release id string */ -PROJ_DLL extern int pj_errno; /* global error return code */ - -#ifndef PROJ_INTERNAL_H -/* replaced by enum proj_log_level in proj_internal.h */ -#define PJ_LOG_NONE 0 -#define PJ_LOG_ERROR 1 -#define PJ_LOG_DEBUG_MAJOR 2 -#define PJ_LOG_DEBUG_MINOR 3 -#endif - -#ifdef PROJ_API_H_NOT_INVOKED_AS_PRIMARY_API - /* These make the function declarations below conform with classic proj */ - typedef PJ *projPJ; /* projPJ is a pointer to PJ */ - typedef struct projCtx_t *projCtx; /* projCtx is a pointer to projCtx_t */ -# define projXY PJ_XY -# define projLP PJ_LP -# define projXYZ PJ_XYZ -# define projLPZ PJ_LPZ - -#else - /* i.e. proj_api invoked as primary API */ - typedef struct { double u, v; } projUV; - typedef struct { double u, v, w; } projUVW; - typedef void *projPJ; - #define projXY projUV - #define projLP projUV - #define projXYZ projUVW - #define projLPZ projUVW - typedef void *projCtx; -#endif - - -/* If included *after* proj.h finishes, we have alternative names */ -/* file reading api, like stdio */ -typedef int *PAFile; -typedef struct projFileAPI_t { - PAFile (*FOpen)(projCtx ctx, const char *filename, const char *access); - size_t (*FRead)(void *buffer, size_t size, size_t nmemb, PAFile file); - int (*FSeek)(PAFile file, long offset, int whence); - long (*FTell)(PAFile file); - void (*FClose)(PAFile); -} projFileAPI; - - - -/* procedure prototypes */ - -projCtx PROJ_DLL pj_get_default_ctx(void); -projCtx PROJ_DLL pj_get_ctx( projPJ ); - -projXY PROJ_DLL pj_fwd(projLP, projPJ); -projLP PROJ_DLL pj_inv(projXY, projPJ); - -projXYZ PROJ_DLL pj_fwd3d(projLPZ, projPJ); -projLPZ PROJ_DLL pj_inv3d(projXYZ, projPJ); - - -int PROJ_DLL pj_transform( projPJ src, projPJ dst, long point_count, int point_offset, - double *x, double *y, double *z ); -int PROJ_DLL pj_datum_transform( projPJ src, projPJ dst, long point_count, int point_offset, - double *x, double *y, double *z ); -int PROJ_DLL pj_geocentric_to_geodetic( double a, double es, - long point_count, int point_offset, - double *x, double *y, double *z ); -int PROJ_DLL pj_geodetic_to_geocentric( double a, double es, - long point_count, int point_offset, - double *x, double *y, double *z ); -int PROJ_DLL pj_compare_datums( projPJ srcdefn, projPJ dstdefn ); -int PROJ_DLL pj_apply_gridshift( projCtx, const char *, int, - long point_count, int point_offset, - double *x, double *y, double *z ); -void PROJ_DLL pj_deallocate_grids(void); -void PROJ_DLL pj_clear_initcache(void); -int PROJ_DLL pj_is_latlong(projPJ); -int PROJ_DLL pj_is_geocent(projPJ); -void PROJ_DLL pj_get_spheroid_defn(projPJ defn, double *major_axis, double *eccentricity_squared); -void PROJ_DLL pj_pr_list(projPJ); -void PROJ_DLL pj_free(projPJ); -void PROJ_DLL pj_set_finder( const char *(*)(const char *) ); -void PROJ_DLL pj_set_searchpath ( int count, const char **path ); -projPJ PROJ_DLL pj_init(int, char **); -projPJ PROJ_DLL pj_init_plus(const char *); -projPJ PROJ_DLL pj_init_ctx( projCtx, int, char ** ); -projPJ PROJ_DLL pj_init_plus_ctx( projCtx, const char * ); -char PROJ_DLL *pj_get_def(projPJ, int); -projPJ PROJ_DLL pj_latlong_from_proj( projPJ ); -int PROJ_DLL pj_has_inverse(projPJ); - - -void PROJ_DLL *pj_malloc(size_t); -void PROJ_DLL pj_dalloc(void *); -void PROJ_DLL *pj_calloc (size_t n, size_t size); -void PROJ_DLL *pj_dealloc (void *ptr); -char PROJ_DLL *pj_strdup(const char *str); -char PROJ_DLL *pj_strerrno(int); -int PROJ_DLL *pj_get_errno_ref(void); -const char PROJ_DLL *pj_get_release(void); -void PROJ_DLL pj_acquire_lock(void); -void PROJ_DLL pj_release_lock(void); -void PROJ_DLL pj_cleanup_lock(void); - -void PROJ_DLL pj_set_ctx( projPJ, projCtx ); -projCtx PROJ_DLL pj_ctx_alloc(void); -void PROJ_DLL pj_ctx_free( projCtx ); -int PROJ_DLL pj_ctx_get_errno( projCtx ); -void PROJ_DLL pj_ctx_set_errno( projCtx, int ); -void PROJ_DLL pj_ctx_set_debug( projCtx, int ); -void PROJ_DLL pj_ctx_set_logger( projCtx, void (*)(void *, int, const char *) ); -void PROJ_DLL pj_ctx_set_app_data( projCtx, void * ); -void PROJ_DLL *pj_ctx_get_app_data( projCtx ); -void PROJ_DLL pj_ctx_set_fileapi( projCtx, projFileAPI *); -projFileAPI PROJ_DLL *pj_ctx_get_fileapi( projCtx ); - -void PROJ_DLL pj_log( projCtx ctx, int level, const char *fmt, ... ); -void PROJ_DLL pj_stderr_logger( void *, int, const char * ); - -/* file api */ -projFileAPI PROJ_DLL *pj_get_default_fileapi(void); - -PAFile PROJ_DLL pj_ctx_fopen(projCtx ctx, const char *filename, const char *access); -size_t PROJ_DLL pj_ctx_fread(projCtx ctx, void *buffer, size_t size, size_t nmemb, PAFile file); -int PROJ_DLL pj_ctx_fseek(projCtx ctx, PAFile file, long offset, int whence); -long PROJ_DLL pj_ctx_ftell(projCtx ctx, PAFile file); -void PROJ_DLL pj_ctx_fclose(projCtx ctx, PAFile file); -char PROJ_DLL *pj_ctx_fgets(projCtx ctx, char *line, int size, PAFile file); - -PAFile PROJ_DLL pj_open_lib(projCtx, const char *, const char *); -int PROJ_DLL pj_find_file(projCtx ctx, const char *short_filename, - char* out_full_filename, size_t out_full_filename_size); - -#ifdef __cplusplus -} -#endif - -#endif /* ndef PROJ_API_H */ -#endif /* ndef PROJ_API_INCLUDED_FOR_PJ_VERSION_ONLY */ diff --git a/src/proj_constants.h b/src/proj_constants.h index a3da2c10..ce3b2157 100644 --- a/src/proj_constants.h +++ b/src/proj_constants.h @@ -651,4 +651,24 @@ #define EPSG_CODE_METHOD_HEIGHT_DEPTH_REVERSAL 1068 #define EPSG_NAME_METHOD_HEIGHT_DEPTH_REVERSAL "Height Depth Reversal" +/* ------------------------------------------------------------------------ */ + +#define EPSG_NAME_METHOD_GEOCENTRIC_TOPOCENTRIC "Geocentric/topocentric conversions" +#define EPSG_CODE_METHOD_GEOCENTRIC_TOPOCENTRIC 9836 + +#define EPSG_NAME_PARAMETER_GEOCENTRIC_X_TOPOCENTRIC_ORIGIN "Geocentric X of topocentric origin" +#define EPSG_CODE_PARAMETER_GEOCENTRIC_X_TOPOCENTRIC_ORIGIN 8837 + +#define EPSG_NAME_PARAMETER_GEOCENTRIC_Y_TOPOCENTRIC_ORIGIN "Geocentric Y of topocentric origin" +#define EPSG_CODE_PARAMETER_GEOCENTRIC_Y_TOPOCENTRIC_ORIGIN 8838 + +#define EPSG_NAME_PARAMETER_GEOCENTRIC_Z_TOPOCENTRIC_ORIGIN "Geocentric Z of topocentric origin" +#define EPSG_CODE_PARAMETER_GEOCENTRIC_Z_TOPOCENTRIC_ORIGIN 8839 + +/* ------------------------------------------------------------------------ */ + +#define EPSG_NAME_METHOD_GEOGRAPHIC_TOPOCENTRIC "Geographic/topocentric conversions" +#define EPSG_CODE_METHOD_GEOGRAPHIC_TOPOCENTRIC 9837 + + #endif /* PROJ_CONSTANTS_INCLUDED */ diff --git a/src/proj_internal.h b/src/proj_internal.h index 79b1da10..32aaa1ec 100644 --- a/src/proj_internal.h +++ b/src/proj_internal.h @@ -33,10 +33,6 @@ #error "proj_internal.h can only be included from a C++ file" #endif -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif - #ifdef _MSC_VER # ifndef _CRT_SECURE_NO_DEPRECATE # define _CRT_SECURE_NO_DEPRECATE @@ -66,10 +62,6 @@ #include "proj.h" -#ifdef PROJ_API_H -#error proj_internal.h must be included before proj_api.h -#endif - #ifdef PROJ_RENAME_SYMBOLS #include "proj_symbol_rename.h" #endif @@ -248,8 +240,6 @@ struct PJ_AREA { double north_lat_degree; }; -struct projCtx_t; -typedef struct projCtx_t projCtx_t; /***************************************************************************** @@ -360,7 +350,7 @@ struct PJconsts { **************************************************************************************/ - projCtx_t *ctx = nullptr; + PJ_CONTEXT *ctx = nullptr; const char *descr = nullptr; /* From pj_list.h or individual PJ_*.c file */ paralist *params = nullptr; /* Parameter list */ char *def_full = nullptr; /* Full textual definition (usually 0 - set by proj_pj_info) */ @@ -401,7 +391,7 @@ struct PJconsts { PJ_OPERATOR inv4d = nullptr; PJ_DESTRUCTOR destructor = nullptr; - void (*reassign_context)(PJ*, projCtx_t *) = nullptr; + void (*reassign_context)(PJ*, PJ_CONTEXT*) = nullptr; /************************************************************************************* @@ -626,7 +616,7 @@ struct FACTORS { #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_NON_CONV_SINHPSI2TANPHI -18 #define PJD_ERR_ACOS_ASIN_ARG_TOO_LARGE -19 #define PJD_ERR_TOLERANCE_CONDITION -20 #define PJD_ERR_CONIC_LAT_EQUAL -21 @@ -716,12 +706,11 @@ struct projFileApiCallbackAndData }; /* proj thread context */ -struct projCtx_t { +struct pj_ctx{ int last_errno = 0; int debug_level = 0; void (*logger)(void *, int, const char *) = nullptr; void *logger_app_data = nullptr; - struct projFileAPI_t *fileapi_legacy = nullptr; // for proj_api.h legacy API struct projCppContext* cpp_context = nullptr; /* internal context for C++ code */ int use_proj4_init_rules = -1; /* -1 = unknown, 0 = no, 1 = yes */ int epsg_file_exists = -1; /* -1 = unknown, 0 = no, 1 = yes */ @@ -753,18 +742,18 @@ struct projCtx_t { int pipelineInitRecursiongCounter = 0; // to avoid potential infinite recursion in pipeline.cpp - projCtx_t() = default; - projCtx_t(const projCtx_t&); - ~projCtx_t(); + pj_ctx() = default; + pj_ctx(const pj_ctx&); + ~pj_ctx(); - projCtx_t& operator= (const projCtx_t&) = delete; + pj_ctx& operator= (const pj_ctx&) = delete; projCppContext* get_cpp_context(); void safeAutoCloseDbIfNeeded(); void set_search_paths(const std::vector<std::string>& search_paths_in); void set_ca_bundle_path(const std::string& ca_bundle_path_in); - static projCtx_t createDefault(); + static pj_ctx createDefault(); }; /* Generate pj_list external or make list from include file */ @@ -812,40 +801,41 @@ PJ *pj_projection_specific_setup_##name (PJ *P) /* procedure prototypes */ double PROJ_DLL dmstor(const char *, char **); -double dmstor_ctx(projCtx_t *ctx, const char *, char **); +double dmstor_ctx(PJ_CONTEXT *ctx, const char *, char **); void PROJ_DLL set_rtodms(int, int); char PROJ_DLL *rtodms(char *, double, int, int); double PROJ_DLL adjlon(double); -double aacos(projCtx_t *,double); -double aasin(projCtx_t *,double); +double aacos(PJ_CONTEXT *,double); +double aasin(PJ_CONTEXT *,double); double asqrt(double); double aatan2(double, double); -PROJVALUE PROJ_DLL pj_param(projCtx_t *ctx, paralist *, const char *); +PROJVALUE PROJ_DLL pj_param(PJ_CONTEXT *ctx, paralist *, const char *); paralist PROJ_DLL *pj_param_exists (paralist *list, const char *parameter); paralist PROJ_DLL *pj_mkparam(const char *); paralist *pj_mkparam_ws (const char *str, const char **next_str); -int PROJ_DLL pj_ell_set(projCtx_t *ctx, paralist *, double *, double *); -int pj_datum_set(projCtx_t *,paralist *, PJ *); +int PROJ_DLL pj_ell_set(PJ_CONTEXT *ctx, paralist *, double *, double *); +int pj_datum_set(PJ_CONTEXT *,paralist *, PJ *); int pj_angular_units_set(paralist *, PJ *); 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_expand_init(projCtx_t *ctx, paralist *init); +paralist *pj_expand_init(PJ_CONTEXT *ctx, paralist *init); -void *pj_dealloc_params (projCtx_t *ctx, paralist *start, int errlev); +void *free_params (PJ_CONTEXT *ctx, paralist *start, int errlev); double *pj_enfn(double); double pj_mlfn(double, double, double, const double *); -double pj_inv_mlfn(projCtx_t *, double, double, const double *); +double pj_inv_mlfn(PJ_CONTEXT *, double, double, const double *); double pj_qsfn(double, double, double); double pj_tsfn(double, double, double); double pj_msfn(double, double, double); -double PROJ_DLL pj_phi2(projCtx_t *, const double, const double); +double PROJ_DLL pj_phi2(PJ_CONTEXT *, const double, const double); +double pj_sinhpsi2tanphi(PJ_CONTEXT *, const double, const double); double pj_qsfn_(double, PJ *); double *pj_authset(double); double pj_authlat(double, double *); @@ -858,10 +848,10 @@ int pj_factors(PJ_LP, const PJ *, double, struct FACTORS *); void *proj_mdist_ini(double); double proj_mdist(double, double, double, const void *); -double proj_inv_mdist(projCtx_t *ctx, double, const void *); +double proj_inv_mdist(PJ_CONTEXT *ctx, double, const void *); void *pj_gauss_ini(double, double, double *,double *); -PJ_LP pj_gauss(projCtx_t *, PJ_LP, const void *); -PJ_LP pj_inv_gauss(projCtx_t *, PJ_LP, const void *); +PJ_LP pj_gauss(PJ_CONTEXT *, PJ_LP, const void *); +PJ_LP pj_inv_gauss(PJ_CONTEXT *, PJ_LP, const void *); struct PJ_DATUMS PROJ_DLL *pj_get_datums_ref( void ); @@ -872,7 +862,7 @@ double PROJ_DLL pj_atof( const char* nptr ); double pj_strtod( const char *nptr, char **endptr ); void pj_freeup_plain (PJ *P); -PJ* pj_init_ctx_with_allow_init_epsg( projCtx_t *ctx, int argc, char **argv, int allow_init_epsg ); +PJ* pj_init_ctx_with_allow_init_epsg( PJ_CONTEXT *ctx, int argc, char **argv, int allow_init_epsg ); std::string PROJ_DLL pj_add_type_crs_if_needed(const std::string& str); std::string pj_double_quote_string_param_if_needed(const std::string& str); @@ -909,7 +899,68 @@ void pj_clear_vgridshift_knowngrids_cache(); PJ_LP pj_generic_inverse_2d(PJ_XY xy, PJ *P, PJ_LP lpInitial); -/* classic public API */ -#include "proj_api.h" + + + +/*****************************************************************************/ +/* */ +/* proj_api.h */ +/* */ +/* The rest of this header file includes what used to be "proj_api.h" */ +/* */ +/*****************************************************************************/ + +/* pj_init() and similar functions can be used with a non-C locale */ +/* Can be detected too at runtime if the symbol pj_atof exists */ +#define PJ_LOCALE_SAFE 1 + +#define RAD_TO_DEG 57.295779513082321 +#define DEG_TO_RAD .017453292519943296 + + + + +extern char const PROJ_DLL pj_release[]; /* global release id string */ + +#ifndef PROJ_INTERNAL_H +/* replaced by enum proj_log_level in proj_internal.h */ +#define PJ_LOG_NONE 0 +#define PJ_LOG_ERROR 1 +#define PJ_LOG_DEBUG_MAJOR 2 +#define PJ_LOG_DEBUG_MINOR 3 +#endif + + +/* procedure prototypes */ + +PJ_CONTEXT PROJ_DLL *pj_get_default_ctx(void); +PJ_CONTEXT *pj_get_ctx( PJ *); + +PJ_XY PROJ_DLL pj_fwd(PJ_LP, PJ *); +PJ_LP PROJ_DLL pj_inv(PJ_XY, PJ *); + +PJ_XYZ pj_fwd3d(PJ_LPZ, PJ *); +PJ_LPZ pj_inv3d(PJ_XYZ, PJ *); + + +void pj_clear_initcache(void); +void PROJ_DLL pj_pr_list(PJ *); /* used by proj.cpp */ +char *pj_get_def(PJ *, int); +int pj_has_inverse(PJ *); + + +char *pj_strdup(const char *str); +const char PROJ_DLL *pj_get_release(void); +void pj_acquire_lock(void); +void pj_release_lock(void); +void pj_cleanup_lock(void); + +void pj_log( PJ_CONTEXT * ctx, int level, const char *fmt, ... ); +void pj_stderr_logger( void *, int, const char * ); + +int pj_find_file(PJ_CONTEXT * ctx, const char *short_filename, + char* out_full_filename, size_t out_full_filename_size); + + #endif /* ndef PROJ_INTERNAL_H */ diff --git a/src/proj_mdist.cpp b/src/proj_mdist.cpp index c515f6c5..ed07ffd1 100644 --- a/src/proj_mdist.cpp +++ b/src/proj_mdist.cpp @@ -107,7 +107,7 @@ proj_mdist(double phi, double sphi, double cphi, const void *data) { return(D + sc * sum); } double -proj_inv_mdist(projCtx ctx, double dist, const void *data) { +proj_inv_mdist(PJ_CONTEXT *ctx, double dist, const void *data) { const struct MDIST *b = (const struct MDIST *)data; double s, t, phi, k; int i; @@ -124,6 +124,6 @@ proj_inv_mdist(projCtx ctx, double dist, const void *data) { return phi; } /* convergence failed */ - pj_ctx_set_errno(ctx, PJD_ERR_NON_CONV_INV_MERI_DIST); + proj_context_errno_set(ctx, PJD_ERR_NON_CONV_INV_MERI_DIST); return phi; } diff --git a/src/projections/adams.cpp b/src/projections/adams.cpp index 4f7d1a03..d1217ff1 100644 --- a/src/projections/adams.cpp +++ b/src/projections/adams.cpp @@ -205,7 +205,7 @@ static PJ_LP adams_inverse(PJ_XY xy, PJ *P) static PJ *setup(PJ *P, projection_type mode) { struct pj_opaque *Q = static_cast<struct pj_opaque*>( - pj_calloc (1, sizeof (struct pj_opaque))); + calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); diff --git a/src/projections/aea.cpp b/src/projections/aea.cpp index 6ffb4fd6..af0f292d 100644 --- a/src/projections/aea.cpp +++ b/src/projections/aea.cpp @@ -94,7 +94,7 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } @@ -219,7 +219,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(aea) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -232,7 +232,7 @@ PJ *PROJECTION(aea) { PJ *PROJECTION(leac) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/aeqd.cpp b/src/projections/aeqd.cpp index ad8c289e..d5d90b62 100644 --- a/src/projections/aeqd.cpp +++ b/src/projections/aeqd.cpp @@ -69,7 +69,7 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } @@ -274,7 +274,7 @@ static PJ_LP aeqd_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(aeqd) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/airy.cpp b/src/projections/airy.cpp index f7602e53..15ff60d8 100644 --- a/src/projections/airy.cpp +++ b/src/projections/airy.cpp @@ -120,7 +120,7 @@ static PJ_XY airy_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward PJ *PROJECTION(airy) { double beta; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); diff --git a/src/projections/aitoff.cpp b/src/projections/aitoff.cpp index 7920309c..857ebb80 100644 --- a/src/projections/aitoff.cpp +++ b/src/projections/aitoff.cpp @@ -170,7 +170,7 @@ static PJ_LP aitoff_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inver if (iter == MAXITER && round == MAXROUND) { - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); /* fprintf(stderr, "Warning: Accuracy of 1e-12 not reached. Last increments: dlat=%e and dlon=%e\n", dp, dl); */ } @@ -187,7 +187,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(aitoff) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; @@ -198,7 +198,7 @@ PJ *PROJECTION(aitoff) { PJ *PROJECTION(wintri) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/bacon.cpp b/src/projections/bacon.cpp index 3efd4dbe..7ff2a7ac 100644 --- a/src/projections/bacon.cpp +++ b/src/projections/bacon.cpp @@ -43,7 +43,7 @@ static PJ_XY bacon_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forwar PJ *PROJECTION(bacon) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -57,7 +57,7 @@ PJ *PROJECTION(bacon) { PJ *PROJECTION(apian) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -70,7 +70,7 @@ PJ *PROJECTION(apian) { PJ *PROJECTION(ortel) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/bertin1953.cpp b/src/projections/bertin1953.cpp index b864f83a..58509e16 100644 --- a/src/projections/bertin1953.cpp +++ b/src/projections/bertin1953.cpp @@ -75,7 +75,7 @@ static PJ_XY bertin1953_s_forward (PJ_LP lp, PJ *P) { PJ *PROJECTION(bertin1953) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/bipc.cpp b/src/projections/bipc.cpp index bf4ba834..743acd1c 100644 --- a/src/projections/bipc.cpp +++ b/src/projections/bipc.cpp @@ -168,7 +168,7 @@ static PJ_LP bipc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(bipc) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/bonne.cpp b/src/projections/bonne.cpp index c94764cf..7817e968 100644 --- a/src/projections/bonne.cpp +++ b/src/projections/bonne.cpp @@ -106,14 +106,14 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } PJ *PROJECTION(bonne) { double c; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/calcofi.cpp b/src/projections/calcofi.cpp index 57c12dde..d1e96de8 100644 --- a/src/projections/calcofi.cpp +++ b/src/projections/calcofi.cpp @@ -4,7 +4,6 @@ #include "proj.h" #include "proj_internal.h" -#include "proj_api.h" PROJ_HEAD(calcofi, "Cal Coop Ocean Fish Invest Lines/Stations") "\n\tCyl, Sph&Ell"; diff --git a/src/projections/cass.cpp b/src/projections/cass.cpp index e253cafc..f5531f6a 100644 --- a/src/projections/cass.cpp +++ b/src/projections/cass.cpp @@ -95,7 +95,7 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } @@ -111,7 +111,7 @@ PJ *PROJECTION(cass) { } /* otherwise it's ellipsoidal */ - P->opaque = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + P->opaque = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==P->opaque) return pj_default_destructor (P, ENOMEM); P->destructor = destructor; diff --git a/src/projections/ccon.cpp b/src/projections/ccon.cpp index df995f21..7b3b7105 100644 --- a/src/projections/ccon.cpp +++ b/src/projections/ccon.cpp @@ -75,14 +75,14 @@ static PJ *destructor (PJ *P, int errlev) { if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } PJ *PROJECTION(ccon) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/cea.cpp b/src/projections/cea.cpp index 7e6d3212..b7874b90 100644 --- a/src/projections/cea.cpp +++ b/src/projections/cea.cpp @@ -66,14 +66,14 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->apa); + free (static_cast<struct pj_opaque*>(P->opaque)->apa); return pj_default_destructor (P, errlev); } PJ *PROJECTION(cea) { double t = 0.0; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/chamb.cpp b/src/projections/chamb.cpp index 36609e79..b315832a 100644 --- a/src/projections/chamb.cpp +++ b/src/projections/chamb.cpp @@ -29,7 +29,7 @@ PROJ_HEAD(chamb, "Chamberlin Trimetric") "\n\tMisc Sph, no inv" #define TOL 1e-9 /* distance and azimuth from point 1 to point 2 */ -static VECT vect(projCtx ctx, double dphi, double c1, double s1, double c2, double s2, double dlam) { +static VECT vect(PJ_CONTEXT *ctx, double dphi, double c1, double s1, double c2, double s2, double dlam) { VECT v; double cdl, dp, dl; @@ -49,7 +49,7 @@ static VECT vect(projCtx ctx, double dphi, double c1, double s1, double c2, doub } /* law of cosines */ -static double lc(projCtx ctx, double b,double c,double a) { +static double lc(PJ_CONTEXT *ctx, double b,double c,double a) { return aacos(ctx, .5 * (b * b + c * c - a * a) / (b * c)); } @@ -103,7 +103,7 @@ static PJ_XY chamb_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forwar PJ *PROJECTION(chamb) { int i, j; char line[10]; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/col_urban.cpp b/src/projections/col_urban.cpp index 5bc8407f..de0c178f 100644 --- a/src/projections/col_urban.cpp +++ b/src/projections/col_urban.cpp @@ -54,7 +54,7 @@ static PJ_LP col_urban_inverse (PJ_XY xy, PJ *P) { } PJ *PROJECTION(col_urban) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/comill.cpp b/src/projections/comill.cpp index 189e583e..44524990 100644 --- a/src/projections/comill.cpp +++ b/src/projections/comill.cpp @@ -66,7 +66,7 @@ static PJ_LP comill_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inver } } if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.phi = yc; /* longitude */ diff --git a/src/projections/eck3.cpp b/src/projections/eck3.cpp index 0deeb4f3..2563053f 100644 --- a/src/projections/eck3.cpp +++ b/src/projections/eck3.cpp @@ -52,7 +52,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(eck3) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -67,7 +67,7 @@ PJ *PROJECTION(eck3) { PJ *PROJECTION(kav7) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -85,7 +85,7 @@ PJ *PROJECTION(kav7) { PJ *PROJECTION(wag6) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -100,7 +100,7 @@ PJ *PROJECTION(wag6) { PJ *PROJECTION(putp1) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/eqc.cpp b/src/projections/eqc.cpp index 194625ef..9ebc9286 100644 --- a/src/projections/eqc.cpp +++ b/src/projections/eqc.cpp @@ -39,7 +39,7 @@ static PJ_LP eqc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(eqc) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/eqdc.cpp b/src/projections/eqdc.cpp index 659488b1..28767d74 100644 --- a/src/projections/eqdc.cpp +++ b/src/projections/eqdc.cpp @@ -68,7 +68,7 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } @@ -77,7 +77,7 @@ PJ *PROJECTION(eqdc) { double cosphi, sinphi; int secant; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/eqearth.cpp b/src/projections/eqearth.cpp index 832c9444..2ef2775b 100644 --- a/src/projections/eqearth.cpp +++ b/src/projections/eqearth.cpp @@ -110,7 +110,7 @@ static PJ_LP eqearth_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal/sphe } if( i == 0 ) { - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); return lp; } @@ -137,13 +137,13 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor */ if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->apa); + free (static_cast<struct pj_opaque*>(P->opaque)->apa); return pj_default_destructor (P, errlev); } PJ *PROJECTION(eqearth) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/fouc_s.cpp b/src/projections/fouc_s.cpp index c5989514..f7607635 100644 --- a/src/projections/fouc_s.cpp +++ b/src/projections/fouc_s.cpp @@ -55,7 +55,7 @@ static PJ_LP fouc_s_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inver PJ *PROJECTION(fouc_s) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/geos.cpp b/src/projections/geos.cpp index 338f07c2..5de4c7ca 100644 --- a/src/projections/geos.cpp +++ b/src/projections/geos.cpp @@ -199,7 +199,7 @@ static PJ_LP geos_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse PJ *PROJECTION(geos) { char *sweep_axis; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/gn_sinu.cpp b/src/projections/gn_sinu.cpp index 815de8be..ef312613 100644 --- a/src/projections/gn_sinu.cpp +++ b/src/projections/gn_sinu.cpp @@ -102,7 +102,7 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } @@ -121,7 +121,7 @@ static void setup(PJ *P) { PJ *PROJECTION(sinu) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -143,7 +143,7 @@ PJ *PROJECTION(sinu) { PJ *PROJECTION(eck6) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -158,7 +158,7 @@ PJ *PROJECTION(eck6) { PJ *PROJECTION(mbtfps) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -173,7 +173,7 @@ PJ *PROJECTION(mbtfps) { PJ *PROJECTION(gn_sinu) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/gnom.cpp b/src/projections/gnom.cpp index 23dee030..9abbb7ce 100644 --- a/src/projections/gnom.cpp +++ b/src/projections/gnom.cpp @@ -124,7 +124,7 @@ static PJ_LP gnom_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(gnom) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/goode.cpp b/src/projections/goode.cpp index fdace387..c0afd2d8 100644 --- a/src/projections/goode.cpp +++ b/src/projections/goode.cpp @@ -54,15 +54,15 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor */ return nullptr; if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_free (static_cast<struct pj_opaque*>(P->opaque)->sinu); - pj_free (static_cast<struct pj_opaque*>(P->opaque)->moll); + proj_destroy (static_cast<struct pj_opaque*>(P->opaque)->sinu); + proj_destroy (static_cast<struct pj_opaque*>(P->opaque)->moll); return pj_default_destructor (P, errlev); } PJ *PROJECTION(goode) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/gstmerc.cpp b/src/projections/gstmerc.cpp index 808d9ef7..b21f6ffd 100644 --- a/src/projections/gstmerc.cpp +++ b/src/projections/gstmerc.cpp @@ -28,9 +28,9 @@ static PJ_XY gstmerc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forw double L, Ls, sinLs1, Ls1; L = Q->n1*lp.lam; - Ls = Q->c + Q->n1 * log(pj_tsfn(-1.0 * lp.phi, -1.0 * sin(lp.phi), P->e)); + Ls = Q->c + Q->n1 * log(pj_tsfn(-lp.phi, -sin(lp.phi), P->e)); sinLs1 = sin(L) / cosh(Ls); - Ls1 = log(pj_tsfn(-1.0 * asin(sinLs1), 0.0, 0.0)); + Ls1 = log(pj_tsfn(-asin(sinLs1), -sinLs1, 0.0)); xy.x = (Q->XS + Q->n2*Ls1) * P->ra; xy.y = (Q->YS + Q->n2*atan(sinh(Ls) / cos(L))) * P->ra; @@ -45,28 +45,28 @@ static PJ_LP gstmerc_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inve L = atan(sinh((xy.x * P->a - Q->XS) / Q->n2) / cos((xy.y * P->a - Q->YS) / Q->n2)); sinC = sin((xy.y * P->a - Q->YS) / Q->n2) / cosh((xy.x * P->a - Q->XS) / Q->n2); - LC = log(pj_tsfn(-1.0 * asin(sinC), 0.0, 0.0)); + LC = log(pj_tsfn(-asin(sinC), -sinC, 0.0)); lp.lam = L / Q->n1; - lp.phi = -1.0 * pj_phi2(P->ctx, exp((LC - Q->c) / Q->n1), P->e); + lp.phi = -pj_phi2(P->ctx, exp((LC - Q->c) / Q->n1), P->e); return lp; } PJ *PROJECTION(gstmerc) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; Q->lamc = P->lam0; - Q->n1 = sqrt(1.0 + P->es * pow(cos(P->phi0), 4.0) / (1.0 - P->es)); + Q->n1 = sqrt(1 + P->es * pow(cos(P->phi0), 4.0) / (1 - P->es)); Q->phic = asin(sin(P->phi0) / Q->n1); - Q->c = log(pj_tsfn(-1.0 * Q->phic, 0.0, 0.0)) - - Q->n1 * log(pj_tsfn(-1.0 * P->phi0, -1.0 * sin(P->phi0), P->e)); - Q->n2 = P->k0 * P->a * sqrt(1.0 - P->es) / (1.0 - P->es * sin(P->phi0) * sin(P->phi0)); + Q->c = log(pj_tsfn(-Q->phic, -sin(P->phi0) / Q->n1, 0.0)) + - Q->n1 * log(pj_tsfn(-P->phi0, -sin(P->phi0), P->e)); + Q->n2 = P->k0 * P->a * sqrt(1 - P->es) / (1 - P->es * sin(P->phi0) * sin(P->phi0)); Q->XS = 0; - Q->YS = -1.0 * Q->n2 * Q->phic; + Q->YS = -Q->n2 * Q->phic; P->inv = gstmerc_s_inverse; P->fwd = gstmerc_s_forward; diff --git a/src/projections/hammer.cpp b/src/projections/hammer.cpp index 8d6d9408..d9bcafc7 100644 --- a/src/projections/hammer.cpp +++ b/src/projections/hammer.cpp @@ -57,7 +57,7 @@ static PJ_LP hammer_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inver PJ *PROJECTION(hammer) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/healpix.cpp b/src/projections/healpix.cpp index aab5c41e..c778f28f 100644 --- a/src/projections/healpix.cpp +++ b/src/projections/healpix.cpp @@ -524,7 +524,7 @@ static PJ_LP s_healpix_inverse(PJ_XY xy, PJ *P) { /* sphere */ PJ_LP lp; lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + proj_context_errno_set(P->ctx, PJD_ERR_INVALID_X_OR_Y); return lp; } return healpix_spherhealpix_e_inverse(xy); @@ -540,7 +540,7 @@ static PJ_LP e_healpix_inverse(PJ_XY xy, PJ *P) { /* ellipsoid */ if (in_image(xy.x, xy.y, 0, 0, 0) == 0) { lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + proj_context_errno_set(P->ctx, PJD_ERR_INVALID_X_OR_Y); return lp; } lp = healpix_spherhealpix_e_inverse(xy); @@ -574,7 +574,7 @@ static PJ_LP s_rhealpix_inverse(PJ_XY xy, PJ *P) { /* sphere */ PJ_LP lp; lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + proj_context_errno_set(P->ctx, PJD_ERR_INVALID_X_OR_Y); return lp; } xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); @@ -590,7 +590,7 @@ static PJ_LP e_rhealpix_inverse(PJ_XY xy, PJ *P) { /* ellipsoid */ if (in_image(xy.x, xy.y, 1, Q->north_square, Q->south_square) == 0) { lp.lam = HUGE_VAL; lp.phi = HUGE_VAL; - pj_ctx_set_errno(P->ctx, PJD_ERR_INVALID_X_OR_Y); + proj_context_errno_set(P->ctx, PJD_ERR_INVALID_X_OR_Y); return lp; } xy = combine_caps(xy.x, xy.y, Q->north_square, Q->south_square, 1); @@ -607,13 +607,13 @@ static PJ *destructor (PJ *P, int errlev) { /* Destructor if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->apa); + free (static_cast<struct pj_opaque*>(P->opaque)->apa); return pj_default_destructor (P, errlev); } PJ *PROJECTION(healpix) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -641,7 +641,7 @@ PJ *PROJECTION(healpix) { PJ *PROJECTION(rhealpix) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/igh.cpp b/src/projections/igh.cpp index 2be94889..8aaaaba1 100644 --- a/src/projections/igh.cpp +++ b/src/projections/igh.cpp @@ -208,7 +208,7 @@ static bool setup_zone(PJ *P, struct pj_opaque *Q, int n, PJ *PROJECTION(igh) { PJ_XY xy1, xy3; PJ_LP lp = { 0, phi_boundary }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/igh_o.cpp b/src/projections/igh_o.cpp index b14d79a5..80874845 100644 --- a/src/projections/igh_o.cpp +++ b/src/projections/igh_o.cpp @@ -222,7 +222,7 @@ static bool setup_zone(PJ *P, struct pj_opaque *Q, int n, PJ *PROJECTION(igh_o) { PJ_XY xy1, xy4; PJ_LP lp = { 0, phi_boundary }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/imw_p.cpp b/src/projections/imw_p.cpp index ee206091..6e82d287 100644 --- a/src/projections/imw_p.cpp +++ b/src/projections/imw_p.cpp @@ -160,7 +160,7 @@ static PJ *destructor (PJ *P, int errlev) { return pj_default_destructor (P, errlev); if( static_cast<struct pj_opaque*>(P->opaque)->en ) - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor(P, errlev); } @@ -169,7 +169,7 @@ static PJ *destructor (PJ *P, int errlev) { PJ *PROJECTION(imw_p) { double del, sig, s, t, x1, x2, T2, y1, m1, m2, y2; int err; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/isea.cpp b/src/projections/isea.cpp index dd1d48ff..77a5689b 100644 --- a/src/projections/isea.cpp +++ b/src/projections/isea.cpp @@ -1039,7 +1039,7 @@ static PJ_XY isea_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward PJ *PROJECTION(isea) { char *opt; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/krovak.cpp b/src/projections/krovak.cpp index aef44d42..adc039fe 100644 --- a/src/projections/krovak.cpp +++ b/src/projections/krovak.cpp @@ -181,7 +181,7 @@ static PJ_LP krovak_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, fi1 = lp.phi; } if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.lam -= P->lam0; @@ -191,7 +191,7 @@ static PJ_LP krovak_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, PJ *PROJECTION(krovak) { double u0, n0, g; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/labrd.cpp b/src/projections/labrd.cpp index c9dfdfc6..4fbcf460 100644 --- a/src/projections/labrd.cpp +++ b/src/projections/labrd.cpp @@ -105,7 +105,7 @@ static PJ_LP labrd_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, invers PJ *PROJECTION(labrd) { double Az, sinp, R, N, t; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/laea.cpp b/src/projections/laea.cpp index 3d135864..2d19cab1 100644 --- a/src/projections/laea.cpp +++ b/src/projections/laea.cpp @@ -234,7 +234,7 @@ static PJ *destructor (PJ *P, int errlev) { if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->apa); + free (static_cast<struct pj_opaque*>(P->opaque)->apa); return pj_default_destructor(P, errlev); } @@ -242,7 +242,7 @@ static PJ *destructor (PJ *P, int errlev) { PJ *PROJECTION(laea) { double t; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/lagrng.cpp b/src/projections/lagrng.cpp index d37a00e6..1029bf8d 100644 --- a/src/projections/lagrng.cpp +++ b/src/projections/lagrng.cpp @@ -71,7 +71,7 @@ static PJ_LP lagrng_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inver PJ *PROJECTION(lagrng) { double sin_phi1; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/lcc.cpp b/src/projections/lcc.cpp index 91ffc511..525281f4 100644 --- a/src/projections/lcc.cpp +++ b/src/projections/lcc.cpp @@ -80,7 +80,7 @@ static PJ_LP lcc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse PJ *PROJECTION(lcc) { double cosphi, sinphi; int secant; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc(1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc(1, sizeof (struct pj_opaque))); if (nullptr == Q) return pj_default_destructor(P, ENOMEM); @@ -106,10 +106,10 @@ PJ *PROJECTION(lcc) { double ml1, m1; m1 = pj_msfn(sinphi, cosphi, P->es); - ml1 = pj_tsfn(Q->phi1, sinphi, P->e); - if( ml1 == 0 ) { + if( fabs(Q->phi1) == M_HALFPI ) { return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); } + ml1 = pj_tsfn(Q->phi1, sinphi, P->e); if (secant) { /* secant cone */ sinphi = sin(Q->phi2); Q->n = log(m1 / pj_msfn(sinphi, cos(Q->phi2), P->es)); @@ -117,10 +117,10 @@ PJ *PROJECTION(lcc) { // Not quite, but es is very close to 1... return pj_default_destructor(P, PJD_ERR_INVALID_ECCENTRICITY); } - const double ml2 = pj_tsfn(Q->phi2, sinphi, P->e); - if( ml2 == 0 ) { - return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); + if( fabs(Q->phi2) == M_HALFPI ) { + return pj_default_destructor(P, PJD_ERR_LAT_1_OR_2_ZERO_OR_90); } + const double ml2 = pj_tsfn(Q->phi2, sinphi, P->e); const double denom = log(ml1 / ml2); if( denom == 0 ) { // Not quite, but es is very close to 1... diff --git a/src/projections/lcca.cpp b/src/projections/lcca.cpp index 51dd28aa..53646fc6 100644 --- a/src/projections/lcca.cpp +++ b/src/projections/lcca.cpp @@ -128,14 +128,14 @@ static PJ *destructor (PJ *P, int errlev) { if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } PJ *PROJECTION(lcca) { double s2p0, N0, R0, tan0; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/loxim.cpp b/src/projections/loxim.cpp index 2ee88037..64124bdd 100644 --- a/src/projections/loxim.cpp +++ b/src/projections/loxim.cpp @@ -56,7 +56,7 @@ static PJ_LP loxim_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers PJ *PROJECTION(loxim) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/lsat.cpp b/src/projections/lsat.cpp index f6114485..a811a3a6 100644 --- a/src/projections/lsat.cpp +++ b/src/projections/lsat.cpp @@ -158,7 +158,7 @@ static PJ_LP lsat_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse PJ *PROJECTION(lsat) { int land, path; double lam, alf, esc, ess; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/merc.cpp b/src/projections/merc.cpp index a77d7517..3a0ed7b4 100644 --- a/src/projections/merc.cpp +++ b/src/projections/merc.cpp @@ -10,45 +10,29 @@ PROJ_HEAD(merc, "Mercator") "\n\tCyl, Sph&Ell\n\tlat_ts="; PROJ_HEAD(webmerc, "Web Mercator / Pseudo Mercator") "\n\tCyl, Ell\n\t"; -#define EPS10 1.e-10 -static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ - if (fabs(x) <= DBL_EPSILON) { - /* tan(M_FORTPI + .5 * x) can be approximated by 1.0 + x */ - return log1p(x); - } - return log(tan(M_FORTPI + .5 * x)); -} - static PJ_XY merc_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forward */ PJ_XY xy = {0.0,0.0}; - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; - } xy.x = P->k0 * lp.lam; - xy.y = - P->k0 * log(pj_tsfn(lp.phi, sin(lp.phi), P->e)); + // Instead of calling tan and sin, call sin and cos which the compiler + // optimizes to a single call to sincos. + double sphi = sin(lp.phi); + double cphi = cos(lp.phi); + xy.y = P->k0 * (asinh(sphi/cphi) - P->e * atanh(P->e * sphi)); return xy; } static PJ_XY merc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0,0.0}; - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return xy; -} xy.x = P->k0 * lp.lam; - xy.y = P->k0 * logtanpfpim1(lp.phi); + xy.y = P->k0 * asinh(tan(lp.phi)); return xy; } static PJ_LP merc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse */ PJ_LP lp = {0.0,0.0}; - if ((lp.phi = pj_phi2(P->ctx, exp(- xy.y / P->k0), P->e)) == HUGE_VAL) { - proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); - return lp; -} + lp.phi = atan(pj_sinhpsi2tanphi(P->ctx, sinh(xy.y / P->k0), P->e)); lp.lam = xy.x / P->k0; return lp; } diff --git a/src/projections/misrsom.cpp b/src/projections/misrsom.cpp index 71116e1e..d7e199f2 100644 --- a/src/projections/misrsom.cpp +++ b/src/projections/misrsom.cpp @@ -178,7 +178,7 @@ PJ *PROJECTION(misrsom) { int path; double lam, alf, esc, ess; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/mod_ster.cpp b/src/projections/mod_ster.cpp index c7a8e899..0c30b7b6 100644 --- a/src/projections/mod_ster.cpp +++ b/src/projections/mod_ster.cpp @@ -134,7 +134,7 @@ PJ *PROJECTION(mil_os) { {0.019430, 0.} }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -157,7 +157,7 @@ PJ *PROJECTION(lee_os) { {-0.0088162, -0.00617325} }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -182,7 +182,7 @@ PJ *PROJECTION(gs48) { {0.075528, 0.} }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -217,7 +217,7 @@ PJ *PROJECTION(alsk) { { .3660976, -.2937382} }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -265,7 +265,7 @@ PJ *PROJECTION(gs50) { {-.0225161, .0853673} }; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/moll.cpp b/src/projections/moll.cpp index 5d4f7825..4864c8e1 100644 --- a/src/projections/moll.cpp +++ b/src/projections/moll.cpp @@ -77,7 +77,7 @@ static PJ * setup(PJ *P, double p) { PJ *PROJECTION(moll) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -87,7 +87,7 @@ PJ *PROJECTION(moll) { PJ *PROJECTION(wag4) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -96,7 +96,7 @@ PJ *PROJECTION(wag4) { } PJ *PROJECTION(wag5) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/natearth.cpp b/src/projections/natearth.cpp index 5c096605..e1f71089 100644 --- a/src/projections/natearth.cpp +++ b/src/projections/natearth.cpp @@ -82,7 +82,7 @@ static PJ_LP natearth_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inv } } if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.phi = yc; /* longitude */ diff --git a/src/projections/natearth2.cpp b/src/projections/natearth2.cpp index d149ca85..e4516a0a 100644 --- a/src/projections/natearth2.cpp +++ b/src/projections/natearth2.cpp @@ -76,7 +76,7 @@ static PJ_LP natearth2_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, in } } if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.phi = yc; /* longitude */ diff --git a/src/projections/nsper.cpp b/src/projections/nsper.cpp index 903946b9..951111ac 100644 --- a/src/projections/nsper.cpp +++ b/src/projections/nsper.cpp @@ -180,7 +180,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(nsper) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -194,7 +194,7 @@ PJ *PROJECTION(nsper) { PJ *PROJECTION(tpers) { double omega, gamma; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/ob_tran.cpp b/src/projections/ob_tran.cpp index 7cf1cf98..86798e0a 100644 --- a/src/projections/ob_tran.cpp +++ b/src/projections/ob_tran.cpp @@ -141,14 +141,15 @@ static ARGS ob_tran_target_params (paralist *params) { if (argc < 2) return args; - /* all args except the proj_ob_tran */ - args.argv = static_cast<char**>(pj_calloc (argc - 1, sizeof (char *))); + /* all args except the proj=ob_tran */ + args.argv = static_cast<char**>(calloc (argc - 1, sizeof (char *))); if (nullptr==args.argv) return args; - /* Copy all args *except* the proj=ob_tran arg to the argv array */ + /* Copy all args *except* the proj=ob_tran or inv arg to the argv array */ for (i = 0; params != nullptr; params = params->next) { - if (0==strcmp (params->param, "proj=ob_tran")) + if (0==strcmp (params->param, "proj=ob_tran") || + 0==strcmp (params->param, "inv") ) continue; args.argv[i++] = params->param; } @@ -160,7 +161,7 @@ static ARGS ob_tran_target_params (paralist *params) { continue; args.argv[i] += 2; if (strcmp(args.argv[i], "proj=ob_tran") == 0 ) { - pj_dealloc (args.argv); + free (args.argv); args.argc = 0; args.argv = nullptr; } @@ -177,7 +178,7 @@ PJ *PROJECTION(ob_tran) { ARGS args; PJ *R; /* projection to rotate */ - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return destructor(P, ENOMEM); @@ -194,8 +195,8 @@ PJ *PROJECTION(ob_tran) { if (args.argv == nullptr ) { return destructor(P, PJD_ERR_FAILED_TO_FIND_PROJ); } - R = pj_init_ctx (pj_get_ctx(P), args.argc, args.argv); - pj_dealloc (args.argv); + R = proj_create_argv (P->ctx, args.argc, args.argv); + free (args.argv); if (nullptr==R) return destructor (P, PJD_ERR_UNKNOWN_PROJECTION_ID); diff --git a/src/projections/ocea.cpp b/src/projections/ocea.cpp index de9838cb..c78e1ebc 100644 --- a/src/projections/ocea.cpp +++ b/src/projections/ocea.cpp @@ -52,7 +52,7 @@ static PJ_LP ocea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(ocea) { double phi_1, phi_2, lam_1, lam_2, lonz, alpha; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/oea.cpp b/src/projections/oea.cpp index 61fb0647..46c00d16 100644 --- a/src/projections/oea.cpp +++ b/src/projections/oea.cpp @@ -58,7 +58,7 @@ static PJ_LP oea_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(oea) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/omerc.cpp b/src/projections/omerc.cpp index e9f3b833..90067cc3 100644 --- a/src/projections/omerc.cpp +++ b/src/projections/omerc.cpp @@ -126,7 +126,7 @@ PJ *PROJECTION(omerc) { gamma0, lamc=0, lam1=0, lam2=0, phi1=0, phi2=0, alpha_c=0; int alp, gam, no_off = 0; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/ortho.cpp b/src/projections/ortho.cpp index 8dcfb53c..4417dac7 100644 --- a/src/projections/ortho.cpp +++ b/src/projections/ortho.cpp @@ -273,13 +273,13 @@ static PJ_LP ortho_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inver return lp; } } - pj_ctx_set_errno(P->ctx, PJD_ERR_NON_CONVERGENT); + proj_context_errno_set(P->ctx, PJD_ERR_NON_CONVERGENT); return lp; } PJ *PROJECTION(ortho) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/patterson.cpp b/src/projections/patterson.cpp index 71099cdb..32544580 100644 --- a/src/projections/patterson.cpp +++ b/src/projections/patterson.cpp @@ -100,7 +100,7 @@ static PJ_LP patterson_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, in } } if( i == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.phi = yc; /* longitude */ diff --git a/src/projections/poly.cpp b/src/projections/poly.cpp index 10d93ed2..4ea95cc7 100644 --- a/src/projections/poly.cpp +++ b/src/projections/poly.cpp @@ -147,14 +147,14 @@ static PJ *destructor(PJ *P, int errlev) { return pj_default_destructor (P, errlev); if (static_cast<struct pj_opaque*>(P->opaque)->en) - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor(P, errlev); } PJ *PROJECTION(poly) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); diff --git a/src/projections/putp3.cpp b/src/projections/putp3.cpp index c2df20e8..09763851 100644 --- a/src/projections/putp3.cpp +++ b/src/projections/putp3.cpp @@ -38,7 +38,7 @@ static PJ_LP putp3_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers PJ *PROJECTION(putp3) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -53,7 +53,7 @@ PJ *PROJECTION(putp3) { } PJ *PROJECTION(putp3p) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/putp4p.cpp b/src/projections/putp4p.cpp index 365f7c1b..8df18972 100644 --- a/src/projections/putp4p.cpp +++ b/src/projections/putp4p.cpp @@ -45,7 +45,7 @@ static PJ_LP putp4p_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inver PJ *PROJECTION(putp4p) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -62,7 +62,7 @@ PJ *PROJECTION(putp4p) { PJ *PROJECTION(weren) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/putp5.cpp b/src/projections/putp5.cpp index 1847e7a9..5e70382d 100644 --- a/src/projections/putp5.cpp +++ b/src/projections/putp5.cpp @@ -43,7 +43,7 @@ static PJ_LP putp5_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers PJ *PROJECTION(putp5) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -60,7 +60,7 @@ PJ *PROJECTION(putp5) { PJ *PROJECTION(putp5p) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/putp6.cpp b/src/projections/putp6.cpp index db334ff9..da8c0a7c 100644 --- a/src/projections/putp6.cpp +++ b/src/projections/putp6.cpp @@ -59,7 +59,7 @@ static PJ_LP putp6_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers PJ *PROJECTION(putp6) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; @@ -79,7 +79,7 @@ PJ *PROJECTION(putp6) { PJ *PROJECTION(putp6p) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/qsc.cpp b/src/projections/qsc.cpp index 98e3755e..dd9ce965 100644 --- a/src/projections/qsc.cpp +++ b/src/projections/qsc.cpp @@ -377,7 +377,7 @@ static PJ_LP qsc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inverse PJ *PROJECTION(qsc) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/robin.cpp b/src/projections/robin.cpp index 8b646502..6a1405b6 100644 --- a/src/projections/robin.cpp +++ b/src/projections/robin.cpp @@ -138,7 +138,7 @@ static PJ_LP robin_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers break; } if( iters == 0 ) - pj_ctx_set_errno( P->ctx, PJD_ERR_NON_CONVERGENT ); + proj_context_errno_set( P->ctx, PJD_ERR_NON_CONVERGENT ); lp.phi = (5 * i + t) * DEG_TO_RAD; if (xy.y < 0.) lp.phi = -lp.phi; lp.lam /= V(X[i], t); diff --git a/src/projections/rouss.cpp b/src/projections/rouss.cpp index f5a8f12f..2eb13b3d 100644 --- a/src/projections/rouss.cpp +++ b/src/projections/rouss.cpp @@ -93,7 +93,7 @@ static PJ *destructor (PJ *P, int errlev) { return pj_default_destructor (P, errlev); if (static_cast<struct pj_opaque*>(P->opaque)->en) - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, ENOMEM); } @@ -102,7 +102,7 @@ static PJ *destructor (PJ *P, int errlev) { PJ *PROJECTION(rouss) { double N0, es2, t, t2, R_R0_2, R_R0_4; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/rpoly.cpp b/src/projections/rpoly.cpp index b065861f..e3f09c59 100644 --- a/src/projections/rpoly.cpp +++ b/src/projections/rpoly.cpp @@ -44,7 +44,7 @@ static PJ_XY rpoly_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forwar PJ *PROJECTION(rpoly) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/sch.cpp b/src/projections/sch.cpp index 7548039d..359e8efc 100644 --- a/src/projections/sch.cpp +++ b/src/projections/sch.cpp @@ -184,7 +184,7 @@ static PJ *setup(PJ *P) { /* general initialization */ PJ *PROJECTION(sch) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/sconics.cpp b/src/projections/sconics.cpp index f305e291..c12b05a2 100644 --- a/src/projections/sconics.cpp +++ b/src/projections/sconics.cpp @@ -117,7 +117,7 @@ static PJ_LP sconics_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, (and ellipsoi static PJ *setup(PJ *P, enum Type type) { double del, cs; int err; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/somerc.cpp b/src/projections/somerc.cpp index fe6477fa..a184500c 100644 --- a/src/projections/somerc.cpp +++ b/src/projections/somerc.cpp @@ -71,7 +71,7 @@ static PJ_LP somerc_e_inverse (PJ_XY xy, PJ *P) { /* Ellipsoidal, inver PJ *PROJECTION(somerc) { double cp, phip0, sp; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/stere.cpp b/src/projections/stere.cpp index abc4aa13..ad1caae2 100644 --- a/src/projections/stere.cpp +++ b/src/projections/stere.cpp @@ -86,7 +86,10 @@ static PJ_XY stere_e_forward (PJ_LP lp, PJ *P) { /* Ellipsoidal, forwar sinphi = -sinphi; /*-fallthrough*/ case N_POLE: - xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e); + if( fabs(lp.phi - M_HALFPI) < 1e-15 ) + xy.x = 0; + else + xy.x = Q->akm1 * pj_tsfn (lp.phi, sinphi, P->e); xy.y = - xy.x * coslam; break; } @@ -299,7 +302,7 @@ static PJ *setup(PJ *P) { /* general initialization */ PJ *PROJECTION(stere) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -312,7 +315,7 @@ PJ *PROJECTION(stere) { PJ *PROJECTION(ups) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/sterea.cpp b/src/projections/sterea.cpp index 55404c86..4dd22d2f 100644 --- a/src/projections/sterea.cpp +++ b/src/projections/sterea.cpp @@ -93,14 +93,14 @@ static PJ *destructor (PJ *P, int errlev) { if (nullptr==P->opaque) return pj_default_destructor (P, errlev); - pj_dealloc (static_cast<struct pj_opaque*>(P->opaque)->en); + free (static_cast<struct pj_opaque*>(P->opaque)->en); return pj_default_destructor (P, errlev); } PJ *PROJECTION(sterea) { double R; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); diff --git a/src/projections/sts.cpp b/src/projections/sts.cpp index cbc36b7d..75190e85 100644 --- a/src/projections/sts.cpp +++ b/src/projections/sts.cpp @@ -70,7 +70,7 @@ static PJ *setup(PJ *P, double p, double q, int mode) { PJ *PROJECTION(fouc) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; @@ -80,7 +80,7 @@ PJ *PROJECTION(fouc) { PJ *PROJECTION(kav5) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; @@ -91,7 +91,7 @@ PJ *PROJECTION(kav5) { PJ *PROJECTION(qua_aut) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; @@ -101,7 +101,7 @@ PJ *PROJECTION(qua_aut) { PJ *PROJECTION(mbt_s) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/tmerc.cpp b/src/projections/tmerc.cpp index 69f4d352..8f897061 100644 --- a/src/projections/tmerc.cpp +++ b/src/projections/tmerc.cpp @@ -89,7 +89,7 @@ static PJ_XY approx_e_fwd (PJ_LP lp, PJ *P) if( lp.lam < -M_HALFPI || lp.lam > M_HALFPI ) { xy.x = HUGE_VAL; xy.y = HUGE_VAL; - pj_ctx_set_errno( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); + proj_context_errno_set( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); return xy; } @@ -115,25 +115,11 @@ static PJ_XY approx_e_fwd (PJ_LP lp, PJ *P) return (xy); } -static PJ_XY approx_s_fwd (PJ_LP lp, PJ *P) { +static PJ_XY tmerc_spherical_fwd (PJ_LP lp, PJ *P) { PJ_XY xy = {0.0,0.0}; double b, cosphi; const auto *Q = &(static_cast<struct tmerc_data*>(P->opaque)->approx); - /* - * Fail if our longitude is more than 90 degrees from the - * central meridian since the results are essentially garbage. - * Is error -20 really an appropriate return value? - * - * http://trac.osgeo.org/proj/ticket/5 - */ - if( lp.lam < -M_HALFPI || lp.lam > M_HALFPI ) { - xy.x = HUGE_VAL; - xy.y = HUGE_VAL; - pj_ctx_set_errno( P->ctx, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT ); - return xy; - } - cosphi = cos(lp.phi); b = cosphi * sin (lp.lam); if (fabs (fabs (b) - 1.) <= EPS10) { @@ -145,7 +131,12 @@ static PJ_XY approx_s_fwd (PJ_LP lp, PJ *P) { xy.y = cosphi * cos (lp.lam) / sqrt (1. - b * b); b = fabs ( xy.y ); - if (b >= 1.) { + if (cosphi == 1 && (lp.lam < -M_HALFPI || lp.lam > M_HALFPI) ) { + /* Helps to be able to roundtrip |longitudes| > 90 at lat=0 */ + /* We could also map to -M_PI ... */ + xy.y = M_PI; + } + else if (b >= 1.) { if ((b - 1.) > EPS10) { proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return xy; @@ -192,7 +183,7 @@ static PJ_LP approx_e_inv (PJ_XY xy, PJ *P) { return lp; } -static PJ_LP approx_s_inv (PJ_XY xy, PJ *P) { +static PJ_LP tmerc_spherical_inv (PJ_XY xy, PJ *P) { PJ_LP lp = {0.0, 0.0}; double h, g; const auto *Q = &(static_cast<struct tmerc_data*>(P->opaque)->approx); @@ -203,11 +194,13 @@ static PJ_LP approx_s_inv (PJ_XY xy, PJ *P) { return proj_coord_error().lp; } g = .5 * (h - 1. / h); - h = cos (P->phi0 + xy.y / Q->esp); + /* D, as in equation 8-8 of USGS "Map Projections - A Working Manual" */ + const double D = P->phi0 + xy.y / Q->esp; + h = cos (D); lp.phi = asin(sqrt((1. - h * h) / (1. + g * g))); /* Make sure that phi is on the correct hemisphere when false northing is used */ - if (xy.y < 0. && -lp.phi+P->phi0 < 0.0) lp.phi = -lp.phi; + lp.phi = copysign(lp.phi, D); lp.lam = (g != 0.0 || h != 0.0) ? atan2 (g, h) : 0.; return lp; @@ -221,7 +214,7 @@ static PJ *destructor(PJ *P, int errlev) { if (nullptr==P->opaque) return pj_default_destructor(P, errlev); - pj_dealloc (static_cast<struct tmerc_data*>(P->opaque)->approx.en); + free (static_cast<struct tmerc_data*>(P->opaque)->approx.en); return pj_default_destructor(P, errlev); } @@ -592,7 +585,7 @@ static PJ_LP auto_e_inv (PJ_XY xy, PJ *P) { static PJ *setup(PJ *P, TMercAlgo eAlg) { - struct tmerc_data *Q = static_cast<struct tmerc_data*>(pj_calloc (1, sizeof (struct tmerc_data))); + struct tmerc_data *Q = static_cast<struct tmerc_data*>(calloc (1, sizeof (struct tmerc_data))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -609,8 +602,8 @@ static PJ *setup(PJ *P, TMercAlgo eAlg) { return nullptr; if( P->es == 0 ) { - P->inv = approx_s_inv; - P->fwd = approx_s_fwd; + P->inv = tmerc_spherical_inv; + P->fwd = tmerc_spherical_fwd; } else { @@ -679,7 +672,7 @@ static bool getAlgoFromParams(PJ* P, TMercAlgo& algo) else { pj_load_ini(P->ctx); // if not already done - pj_ctx_set_errno(P->ctx, 0); // reset error in case proj.ini couldn't be found + proj_context_errno_set(P->ctx, 0); // reset error in case proj.ini couldn't be found algo = P->ctx->defaultTmercAlgo; } diff --git a/src/projections/tobmerc.cpp b/src/projections/tobmerc.cpp index a1616036..f05a9b6b 100644 --- a/src/projections/tobmerc.cpp +++ b/src/projections/tobmerc.cpp @@ -9,27 +9,24 @@ PROJ_HEAD(tobmerc, "Tobler-Mercator") "\n\tCyl, Sph"; -#define EPS10 1.e-10 -static double logtanpfpim1(double x) { /* log(tan(x/2 + M_FORTPI)) */ - if (fabs(x) <= DBL_EPSILON) { - /* tan(M_FORTPI + .5 * x) can be approximated by 1.0 + x */ - return log1p(x); - } - return log(tan(M_FORTPI + .5 * x)); -} - static PJ_XY tobmerc_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward */ PJ_XY xy = {0.0, 0.0}; double cosphi; - if (fabs(fabs(lp.phi) - M_HALFPI) <= EPS10) { + if (fabs(lp.phi) >= M_HALFPI) { + // builtins.gie tests "Test expected failure at the poles:". However + // given that M_HALFPI is strictly less than pi/2 in double precision, + // it's not clear why shouldn't just return a large result for xy.y (and + // it's not even that large, merely 38.025...). Even if the logic was + // such that phi was strictly equal to pi/2, allowing xy.y = inf would be + // a reasonable result. proj_errno_set(P, PJD_ERR_TOLERANCE_CONDITION); return xy; } cosphi = cos(lp.phi); xy.x = P->k0 * lp.lam * cosphi * cosphi; - xy.y = P->k0 * logtanpfpim1(lp.phi); + xy.y = P->k0 * asinh(tan(lp.phi)); return xy; } diff --git a/src/projections/tpeqd.cpp b/src/projections/tpeqd.cpp index 58aeb8e1..90efb395 100644 --- a/src/projections/tpeqd.cpp +++ b/src/projections/tpeqd.cpp @@ -64,7 +64,7 @@ static PJ_LP tpeqd_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers PJ *PROJECTION(tpeqd) { double lam_1, lam_2, phi_1, phi_2, A12; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/urm5.cpp b/src/projections/urm5.cpp index 499644d2..c3021841 100644 --- a/src/projections/urm5.cpp +++ b/src/projections/urm5.cpp @@ -30,7 +30,7 @@ static PJ_XY urm5_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forward PJ *PROJECTION(urm5) { double alpha, t; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/urmfps.cpp b/src/projections/urmfps.cpp index 3f9fdf23..5d689f9f 100644 --- a/src/projections/urmfps.cpp +++ b/src/projections/urmfps.cpp @@ -47,7 +47,7 @@ static PJ *setup(PJ *P) { PJ *PROJECTION(urmfps) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); @@ -66,7 +66,7 @@ PJ *PROJECTION(urmfps) { PJ *PROJECTION(wag1) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/vandg2.cpp b/src/projections/vandg2.cpp index 223620d6..cd7e7b6c 100644 --- a/src/projections/vandg2.cpp +++ b/src/projections/vandg2.cpp @@ -53,7 +53,7 @@ static PJ_XY vandg2_s_forward (PJ_LP lp, PJ *P) { /* Spheroidal, forwa PJ *PROJECTION(vandg2) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; @@ -65,7 +65,7 @@ PJ *PROJECTION(vandg2) { } PJ *PROJECTION(vandg3) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = Q; diff --git a/src/projections/wag3.cpp b/src/projections/wag3.cpp index 33313cdb..ed3250ef 100644 --- a/src/projections/wag3.cpp +++ b/src/projections/wag3.cpp @@ -35,7 +35,7 @@ static PJ_LP wag3_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, inverse PJ *PROJECTION(wag3) { double ts; - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); diff --git a/src/projections/wink1.cpp b/src/projections/wink1.cpp index d097978f..f4ffafe3 100644 --- a/src/projections/wink1.cpp +++ b/src/projections/wink1.cpp @@ -33,7 +33,7 @@ static PJ_LP wink1_s_inverse (PJ_XY xy, PJ *P) { /* Spheroidal, invers PJ *PROJECTION(wink1) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/projections/wink2.cpp b/src/projections/wink2.cpp index d457f842..b5b1e812 100644 --- a/src/projections/wink2.cpp +++ b/src/projections/wink2.cpp @@ -53,7 +53,7 @@ static PJ_LP wink2_s_inverse(PJ_XY xy, PJ *P) PJ *PROJECTION(wink2) { - struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque))); + struct pj_opaque *Q = static_cast<struct pj_opaque*>(calloc (1, sizeof (struct pj_opaque))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = Q; diff --git a/src/strerrno.cpp b/src/strerrno.cpp index 5ae0d7e1..3d0131c6 100644 --- a/src/strerrno.cpp +++ b/src/strerrno.cpp @@ -1,4 +1,4 @@ -/* list of projection system pj_errno values */ +/* list of projection system errno values */ #include <stddef.h> #include <stdio.h> @@ -27,7 +27,7 @@ pj_err_list[] = { "invalid x or y", /* -15 */ "improperly formed DMS value", /* -16 */ "non-convergent inverse meridional dist", /* -17 */ - "non-convergent inverse phi2", /* -18 */ + "non-convergent sinh(psi) to tan(phi)", /* -18 */ "acos/asin: |arg| >1.+1e-14", /* -19 */ "tolerance condition error", /* -20 */ "conic lat_1 = -lat_2", /* -21 */ @@ -74,10 +74,11 @@ pj_err_list[] = { "network error", /* -62 */ /* When adding error messages, remember to update ID defines in - projects.h, and transient_error array in pj_transform */ + src/proj_internal.h and src/apps/gie.cpp */ }; -char *pj_strerrno(int err) { + +const char* proj_errno_string(int err) { const int max_error = 9999; static char note[50]; size_t adjusted_err; @@ -98,7 +99,7 @@ char *pj_strerrno(int err) { #endif } - /* PROJ.4 error codes are negative: -1 to -9999 */ + /* PROJ error codes are negative: -1 to -9999 */ adjusted_err = err < -max_error ? max_error : -err - 1; if (adjusted_err < (sizeof(pj_err_list) / sizeof(char *))) return (char *)pj_err_list[adjusted_err]; @@ -107,7 +108,3 @@ char *pj_strerrno(int err) { (err > -max_error) ? err: -max_error); return note; } - -const char* proj_errno_string(int err) { - return pj_strerrno(err); -} diff --git a/src/tests/multistresstest.cpp b/src/tests/multistresstest.cpp index 33d2d738..6b7099ce 100644 --- a/src/tests/multistresstest.cpp +++ b/src/tests/multistresstest.cpp @@ -30,11 +30,7 @@ #include <stdlib.h> #include <string.h> -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif - -#include "proj_api.h" +#include "proj.h" #ifdef _WIN32 #include <windows.h> @@ -51,8 +47,8 @@ typedef struct { const char *src_def; const char *dst_def; - double src_x, src_y, src_z; - double dst_x, dst_y, dst_z; + PJ_COORD src; + PJ_COORD dst; int dst_error; int skip; @@ -62,125 +58,120 @@ static TestItem test_list[] = { { "+proj=utm +zone=11 +datum=WGS84", "+proj=latlong +datum=WGS84", - 150000.0, 3000000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 3000000.0, 0.0, 0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=utm +zone=11 +datum=NAD83", "+proj=latlong +datum=NAD27", - 150000.0, 3000000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 3000000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=utm +zone=11 +datum=NAD83", "+proj=latlong +nadgrids=@null +ellps=WGS84", - 150000.0, 3000000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 3000000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=utm +zone=11 +datum=WGS84", "+proj=merc +datum=potsdam", - 150000.0, 3000000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 3000000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=latlong +nadgrids=nzgd2kgrid0005.gsb", "+proj=latlong +datum=WGS84", - 150000.0, 3000000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 3000000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=latlong +nadgrids=nzgd2kgrid0005.gsb", "+proj=latlong +datum=WGS84", - 170 * DEG_TO_RAD, -40 * DEG_TO_RAD, 0.0, - 0.0, 0.0, 0.0, + proj_coord(170, -40, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=latlong +ellps=GRS80 +towgs84=2,3,5", "+proj=latlong +ellps=intl +towgs84=10,12,15", - 170 * DEG_TO_RAD, -40 * DEG_TO_RAD, 0.0, - 0.0, 0.0, 0.0, + proj_coord(170, -40, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=eqc +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", "+proj=stere +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=cea +lat_ts=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", "+proj=merc +lon_0=12 +k=0.999 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=bonne +lat_1=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", "+proj=cass +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=nzmg +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", "+proj=gnom +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=ortho +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", "+proj=laea +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=aeqd +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", "+proj=eqdc +lat_1=20 +lat_2=5 +lat_0=11 +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+proj=mill +lat_0=11 +lon_0=12 +y_0=200000 +datum=WGS84 ", "+proj=moll +lon_0=12 +x_0=100000 +y_0=200000 +datum=WGS84 ", - 150000.0, 250000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 250000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { "+init=epsg:3309", "+init=epsg:4326", - 150000.0, 30000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 30000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 }, { /* Bad projection (invalid ellipsoid parameter +R_A=0) */ "+proj=utm +zone=11 +datum=WGS84", "+proj=merc +datum=potsdam +R_A=0", - 150000.0, 3000000.0, 0.0, - 0.0, 0.0, 0.0, + proj_coord(150000.0, 3000000.0, 0.0, 0.0), + proj_coord(0.0, 0.0, 0.0, 0.0), 0, 0 } }; static volatile int active_thread_count = 0; -static projPJ custom_pj_init_plus_ctx(projCtx ctx, const char* def) -{ - return pj_init_plus_ctx(ctx, def); -} - /************************************************************************/ /* TestThread() */ /************************************************************************/ @@ -195,11 +186,10 @@ static void TestThread() /* -------------------------------------------------------------------- */ /* Initialize coordinate system definitions. */ /* -------------------------------------------------------------------- */ - projPJ *src_pj_list, *dst_pj_list; - projCtx ctx = pj_ctx_alloc(); + PJ **pj_list; + PJ_CONTEXT *ctx = proj_context_create(); - src_pj_list = (projPJ *) calloc(test_count,sizeof(projPJ)); - dst_pj_list = (projPJ *) calloc(test_count,sizeof(projPJ)); + pj_list = (PJ **) calloc(test_count,sizeof(PJ*)); if(!reinit_every_iteration) { @@ -207,8 +197,9 @@ static void TestThread() { TestItem *test = test_list + i; - src_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->src_def ); - dst_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->dst_def ); + pj_list[i] = proj_create_crs_to_crs( + ctx, test->src_def, test->dst_def, nullptr + ); } } @@ -221,28 +212,23 @@ static void TestThread() for( i = 0; i < test_count; i++ ) { TestItem *test = test_list + i; - double x, y, z; - int error; - - x = test->src_x; - y = test->src_y; - z = test->src_z; if( reinit_every_iteration ) { - src_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->src_def ); - dst_pj_list[i] = custom_pj_init_plus_ctx( ctx, test->dst_def ); + proj_context_use_proj4_init_rules(nullptr, true); + pj_list[i] = proj_create_crs_to_crs( + ctx, test->src_def, test->dst_def, nullptr + ); { - int skipTest = (src_pj_list[i] == nullptr || dst_pj_list[i] == nullptr); + int skipTest = (pj_list[i] == nullptr); if ( skipTest != test->skip ) fprintf( stderr, "Threaded projection initialization does not match unthreaded initialization\n" ); if (skipTest) { - pj_free( src_pj_list[i] ); - pj_free( dst_pj_list[i] ); + proj_destroy( pj_list[i] ); continue; } } @@ -251,31 +237,32 @@ static void TestThread() if ( test->skip ) continue; - error = pj_transform( src_pj_list[i], dst_pj_list[i], 1, 0, - &x, &y, &z ); + PJ_COORD out = proj_trans(pj_list[i], PJ_FWD, test->src); + int error = proj_errno(pj_list[i]); if( error != test->dst_error ) { fprintf( stderr, "Got error %d, expected %d\n", error, test->dst_error ); } + proj_errno_reset(pj_list[i]); - if( x != test->dst_x || y != test->dst_y || z != test->dst_z ) + if ( out.xyz.x != test->dst.xyz.x || out.xyz.y != test->dst.xyz.y || out.xyz.z != test->dst.xyz.z) + //if( x != test->dst_x || y != test->dst_y || z != test->dst_z ) { fprintf( stderr, "Got %.15g,%.15g,%.15g\n" "Expected %.15g,%.15g,%.15g\n" "Diff %.15g,%.15g,%.15g\n", - x, y, z, - test->dst_x, test->dst_y, test->dst_z, - x-test->dst_x, y-test->dst_y, z-test->dst_z); + out.xyz.x, out.xyz.y, out.xyz.z, + test->dst.xyz.x, test->dst.xyz.y, test->dst.xyz.z, + out.xyz.x-test->dst.xyz.x, out.xyz.y-test->dst.xyz.y, out.xyz.z-test->dst.xyz.z); } if( reinit_every_iteration ) { - pj_free( src_pj_list[i] ); - pj_free( dst_pj_list[i] ); + proj_destroy( pj_list[i] ); } } } @@ -287,15 +274,13 @@ static void TestThread() { for( i = 0; i < test_count; i++ ) { - pj_free( src_pj_list[i] ); - pj_free( dst_pj_list[i] ); + proj_destroy( pj_list[i] ); } } - free( src_pj_list ); - free( dst_pj_list ); + free( pj_list ); - pj_ctx_free( ctx ); + proj_context_destroy( ctx ); printf( "%d iterations of the %d tests complete in thread X\n", repeat_count, test_count ); @@ -349,43 +334,32 @@ static int do_main(void) { TestItem *test = test_list + i; - projPJ src_pj, dst_pj; + PJ *pj; - src_pj = custom_pj_init_plus_ctx( pj_get_default_ctx(), test->src_def ); - dst_pj = custom_pj_init_plus_ctx( pj_get_default_ctx(), test->dst_def ); - - if( src_pj == nullptr ) - { - printf( "Unable to translate:\n%s\n", test->src_def ); - test->skip = 1; - pj_free (dst_pj); - continue; - } + proj_context_use_proj4_init_rules(nullptr, true); + pj = proj_create_crs_to_crs( + nullptr, test->src_def, test->dst_def, nullptr + ); - if( dst_pj == nullptr ) + if( pj == nullptr ) { - printf( "Unable to translate:\n%s\n", test->dst_def ); + printf( "Unable to translate:\n%s\n or\n%s\n", test->src_def, test->dst_def ); test->skip = 1; - pj_free (src_pj); + proj_destroy(pj); continue; } - test->dst_x = test->src_x; - test->dst_y = test->src_y; - test->dst_z = test->src_z; - test->dst_error = pj_transform( src_pj, dst_pj, 1, 0, - &(test->dst_x), - &(test->dst_y), - &(test->dst_z) ); + PJ_COORD out = proj_trans(pj, PJ_FWD, test->src); + test->dst = out; + test->dst_error = proj_errno(pj); - pj_free( src_pj ); - pj_free( dst_pj ); + proj_destroy(pj); test->skip = 0; -#ifdef notdef - printf( "Test %d - output %.14g,%.14g,%g\n", i, test->dst_x, test->dst_y, test->dst_z ); +#ifdef nodef + printf( "Test %d - output %.14g,%.14g,%g\n", i, test->dst.xyz.x, test->dst.xyz.y, test->dst.xyz.z ); #endif } diff --git a/src/tests/test228.cpp b/src/tests/test228.cpp deleted file mode 100644 index 8ae17c87..00000000 --- a/src/tests/test228.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/****************************************************************************** - * - * Project: PROJ - * Purpose: Test - * Author: Even Rouault <even dot rouault at spatialys dot com> - * - ****************************************************************************** - * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com> - * - * 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. - ****************************************************************************/ - -#ifndef ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H -#endif - -#include "proj_api.h" -#include <stdio.h> /* for printf declaration */ - - -#ifdef _WIN32 - -int main(int argc, char* argv[]) -{ - printf("Test not yet ported on Win32\n"); - return 0; -} - -#else - -#include <pthread.h> -#include <stdio.h> -#include <assert.h> -#include <unistd.h> - -static volatile int run = 0; -static volatile int started = 0; - -static void* thread_main(void* unused) -{ - projCtx p_proj_ctxt; - projPJ p_WGS84_proj; - projPJ p_OSGB36_proj; - (void)unused; - - __sync_add_and_fetch(&started, 1); - while(run == 0); - - p_proj_ctxt=pj_ctx_alloc(); - p_WGS84_proj=pj_init_plus_ctx(p_proj_ctxt,"+proj=longlat " - "+ellps=WGS84 +datum=WGS84"); - p_OSGB36_proj=pj_init_plus_ctx(p_proj_ctxt, - "+proj=longlat +ellps=airy +datum=OSGB36 +nadgrids=OSTN15_NTv2_OSGBtoETRS.gsb"); - - while(run) - { - double x, y; - int proj_ret; - - x = -5.2*DEG_TO_RAD; - y = 50*DEG_TO_RAD; - proj_ret = pj_transform(p_WGS84_proj, - p_OSGB36_proj, 1, 1, &x, &y, nullptr ); - x *= RAD_TO_DEG; - y *= RAD_TO_DEG; - /*printf("%.18f %.18f\n", x, y); */ - assert(proj_ret == 0); - assert(fabs(x - -5.198965207267856492) < 1e-15); - assert(fabs(y - 49.999396074140378232) < 1e-15); - } - - pj_free (p_OSGB36_proj); - pj_free (p_WGS84_proj); - return nullptr; -} - -int main() -{ - int i; - - pthread_t tid1, tid2; - pthread_attr_t attr1, attr2; - - pthread_attr_init(&attr1); - pthread_attr_init(&attr2); - - pthread_create(&tid1, &attr1, thread_main, nullptr); - pthread_create(&tid2, &attr2, thread_main, nullptr); - while(started != 2); - run = 1; - for(i=0;i<2;i++) - sleep(1); - run = 0; - return 0; -} - -#endif /* _WIN32 */ diff --git a/src/transform.cpp b/src/transform.cpp deleted file mode 100644 index cff89232..00000000 --- a/src/transform.cpp +++ /dev/null @@ -1,1850 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Perform overall coordinate system to coordinate system - * transformations (pj_transform() function) including reprojection - * and datum shifting. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2000, Frank Warmerdam - * - * 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 <math.h> -#include <string.h> - -#include "proj.h" -#include "proj_internal.h" -#include "grids.hpp" - -using namespace NS_PROJ; - - -/////////////////////////////////////////////////////////////////////////////// -/// From older geocent.h -/////////////////////////////////////////////////////////////////////////////// - - -/***************************************************************************/ -/* RSC IDENTIFIER: GEOCENTRIC - * - * ABSTRACT - * - * This component provides conversions between Geodetic coordinates (latitude, - * longitude in radians and height in meters) and Geocentric coordinates - * (X, Y, Z) in meters. - * - * ERROR HANDLING - * - * This component checks parameters for valid values. If an invalid value - * is found, the error code is combined with the current error code using - * the bitwise or. This combining allows multiple error codes to be - * returned. The possible error codes are: - * - * GEOCENT_NO_ERROR : No errors occurred in function - * GEOCENT_LAT_ERROR : Latitude out of valid range - * (-90 to 90 degrees) - * GEOCENT_LON_ERROR : Longitude out of valid range - * (-180 to 360 degrees) - * GEOCENT_A_ERROR : Semi-major axis less than or equal to zero - * GEOCENT_B_ERROR : Semi-minor axis less than or equal to zero - * GEOCENT_A_LESS_B_ERROR : Semi-major axis less than semi-minor axis - * - * - * REUSE NOTES - * - * GEOCENTRIC is intended for reuse by any application that performs - * coordinate conversions between geodetic coordinates and geocentric - * coordinates. - * - * - * REFERENCES - * - * An Improved Algorithm for Geocentric to Geodetic Coordinate Conversion, - * Ralph Toms, February 1996 UCRL-JC-123138. - * - * Further information on GEOCENTRIC can be found in the Reuse Manual. - * - * GEOCENTRIC originated from : U.S. Army Topographic Engineering Center - * Geospatial Information Division - * 7701 Telegraph Road - * Alexandria, VA 22310-3864 - * - * LICENSES - * - * None apply to this component. - * - * RESTRICTIONS - * - * GEOCENTRIC has no restrictions. - * - * ENVIRONMENT - * - * GEOCENTRIC was tested and certified in the following environments: - * - * 1. Solaris 2.5 with GCC version 2.8.1 - * 2. Windows 95 with MS Visual C++ version 6 - * - * MODIFICATIONS - * - * Date Description - * ---- ----------- - * - * - */ - - -/***************************************************************************/ -/* - * DEFINES - */ -#define GEOCENT_NO_ERROR 0x0000 -#define GEOCENT_LAT_ERROR 0x0001 -#define GEOCENT_LON_ERROR 0x0002 -#define GEOCENT_A_ERROR 0x0004 -#define GEOCENT_B_ERROR 0x0008 -#define GEOCENT_A_LESS_B_ERROR 0x0010 - - -/***************************************************************************/ -/* - * FUNCTION PROTOTYPES - */ - -/* ensure proper linkage to c++ programs */ -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - double Geocent_a; /* Semi-major axis of ellipsoid in meters */ - double Geocent_b; /* Semi-minor axis of ellipsoid */ - double Geocent_a2; /* Square of semi-major axis */ - double Geocent_b2; /* Square of semi-minor axis */ - double Geocent_e2; /* Eccentricity squared */ - double Geocent_ep2; /* 2nd eccentricity squared */ -} GeocentricInfo; - -void pj_Init_Geocentric( GeocentricInfo *gi ); -long pj_Set_Geocentric_Parameters( GeocentricInfo *gi, - double a, - double b); - -/* - * The function Set_Geocentric_Parameters receives the ellipsoid parameters - * as inputs and sets the corresponding state variables. - * - * a : Semi-major axis, in meters. (input) - * b : Semi-minor axis, in meters. (input) - */ - - -void pj_Get_Geocentric_Parameters ( GeocentricInfo *gi, - double *a, - double *b); - -/* - * The function Get_Geocentric_Parameters returns the ellipsoid parameters - * to be used in geocentric coordinate conversions. - * - * a : Semi-major axis, in meters. (output) - * b : Semi-minor axis, in meters. (output) - */ - - -long pj_Convert_Geodetic_To_Geocentric ( GeocentricInfo *gi, - double Latitude, - double Longitude, - double Height, - double *X, - double *Y, - double *Z); -/* - * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates - * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z), - * according to the current ellipsoid parameters. - * - * Latitude : Geodetic latitude in radians (input) - * Longitude : Geodetic longitude in radians (input) - * Height : Geodetic height, in meters (input) - * X : Calculated Geocentric X coordinate, in meters. (output) - * Y : Calculated Geocentric Y coordinate, in meters. (output) - * Z : Calculated Geocentric Z coordinate, in meters. (output) - * - */ - - -void pj_Convert_Geocentric_To_Geodetic (GeocentricInfo *gi, - double X, - double Y, - double Z, - double *Latitude, - double *Longitude, - double *Height); -/* - * The function Convert_Geocentric_To_Geodetic converts geocentric - * coordinates (X, Y, Z) to geodetic coordinates (latitude, longitude, - * and height), according to the current ellipsoid parameters. - * - * X : Geocentric X coordinate, in meters. (input) - * Y : Geocentric Y coordinate, in meters. (input) - * Z : Geocentric Z coordinate, in meters. (input) - * Latitude : Calculated latitude value in radians. (output) - * Longitude : Calculated longitude value in radians. (output) - * Height : Calculated height value, in meters. (output) - */ - - -#ifdef __cplusplus -} -#endif - - -/////////////////////////////////////////////////////////////////////////////// -/// From older geocent.cpp -/////////////////////////////////////////////////////////////////////////////// - - -/***************************************************************************/ -/* RSC IDENTIFIER: GEOCENTRIC - * - * ABSTRACT - * - * This component provides conversions between Geodetic coordinates (latitude, - * longitude in radians and height in meters) and Geocentric coordinates - * (X, Y, Z) in meters. - * - * ERROR HANDLING - * - * This component checks parameters for valid values. If an invalid value - * is found, the error code is combined with the current error code using - * the bitwise or. This combining allows multiple error codes to be - * returned. The possible error codes are: - * - * GEOCENT_NO_ERROR : No errors occurred in function - * GEOCENT_LAT_ERROR : Latitude out of valid range - * (-90 to 90 degrees) - * GEOCENT_LON_ERROR : Longitude out of valid range - * (-180 to 360 degrees) - * GEOCENT_A_ERROR : Semi-major axis lessthan or equal to zero - * GEOCENT_B_ERROR : Semi-minor axis lessthan or equal to zero - * GEOCENT_A_LESS_B_ERROR : Semi-major axis less than semi-minor axis - * - * - * REUSE NOTES - * - * GEOCENTRIC is intended for reuse by any application that performs - * coordinate conversions between geodetic coordinates and geocentric - * coordinates. - * - * - * REFERENCES - * - * An Improved Algorithm for Geocentric to Geodetic Coordinate Conversion, - * Ralph Toms, February 1996 UCRL-JC-123138. - * - * Further information on GEOCENTRIC can be found in the Reuse Manual. - * - * GEOCENTRIC originated from : U.S. Army Topographic Engineering Center - * Geospatial Information Division - * 7701 Telegraph Road - * Alexandria, VA 22310-3864 - * - * LICENSES - * - * None apply to this component. - * - * RESTRICTIONS - * - * GEOCENTRIC has no restrictions. - * - * ENVIRONMENT - * - * GEOCENTRIC was tested and certified in the following environments: - * - * 1. Solaris 2.5 with GCC version 2.8.1 - * 2. Windows 95 with MS Visual C++ version 6 - * - * MODIFICATIONS - * - * Date Description - * ---- ----------- - * 25-02-97 Original Code - * - */ - - -/***************************************************************************/ -/* - * INCLUDES - */ -#include <math.h> -//#include "geocent.h" -/* - * math.h - is needed for calls to sin, cos, tan and sqrt. - * geocent.h - is needed for Error codes and prototype error checking. - */ - - -/***************************************************************************/ -/* - * DEFINES - */ -#define PI 3.14159265358979323e0 -#define PI_OVER_2 (PI / 2.0e0) -#define FALSE 0 -#define TRUE 1 -#define COS_67P5 0.38268343236508977 /* cosine of 67.5 degrees */ -#define AD_C 1.0026000 /* Toms region 1 constant */ - - -/***************************************************************************/ -/* - * FUNCTIONS - */ - - -long pj_Set_Geocentric_Parameters (GeocentricInfo *gi, double a, double b) - -{ /* BEGIN Set_Geocentric_Parameters */ -/* - * The function Set_Geocentric_Parameters receives the ellipsoid parameters - * as inputs and sets the corresponding state variables. - * - * a : Semi-major axis, in meters. (input) - * b : Semi-minor axis, in meters. (input) - */ - long Error_Code = GEOCENT_NO_ERROR; - - if (a <= 0.0) - Error_Code |= GEOCENT_A_ERROR; - if (b <= 0.0) - Error_Code |= GEOCENT_B_ERROR; - if (a < b) - Error_Code |= GEOCENT_A_LESS_B_ERROR; - if (!Error_Code) - { - gi->Geocent_a = a; - gi->Geocent_b = b; - gi->Geocent_a2 = a * a; - gi->Geocent_b2 = b * b; - gi->Geocent_e2 = (gi->Geocent_a2 - gi->Geocent_b2) / gi->Geocent_a2; - gi->Geocent_ep2 = (gi->Geocent_a2 - gi->Geocent_b2) / gi->Geocent_b2; - } - return (Error_Code); -} /* END OF Set_Geocentric_Parameters */ - - -void pj_Get_Geocentric_Parameters (GeocentricInfo *gi, - double *a, - double *b) -{ /* BEGIN Get_Geocentric_Parameters */ -/* - * The function Get_Geocentric_Parameters returns the ellipsoid parameters - * to be used in geocentric coordinate conversions. - * - * a : Semi-major axis, in meters. (output) - * b : Semi-minor axis, in meters. (output) - */ - - *a = gi->Geocent_a; - *b = gi->Geocent_b; -} /* END OF Get_Geocentric_Parameters */ - - -long pj_Convert_Geodetic_To_Geocentric (GeocentricInfo *gi, - double Latitude, - double Longitude, - double Height, - double *X, - double *Y, - double *Z) -{ /* BEGIN Convert_Geodetic_To_Geocentric */ -/* - * The function Convert_Geodetic_To_Geocentric converts geodetic coordinates - * (latitude, longitude, and height) to geocentric coordinates (X, Y, Z), - * according to the current ellipsoid parameters. - * - * Latitude : Geodetic latitude in radians (input) - * Longitude : Geodetic longitude in radians (input) - * Height : Geodetic height, in meters (input) - * X : Calculated Geocentric X coordinate, in meters (output) - * Y : Calculated Geocentric Y coordinate, in meters (output) - * Z : Calculated Geocentric Z coordinate, in meters (output) - * - */ - long Error_Code = GEOCENT_NO_ERROR; - double Rn; /* Earth radius at location */ - double Sin_Lat; /* sin(Latitude) */ - double Sin2_Lat; /* Square of sin(Latitude) */ - double Cos_Lat; /* cos(Latitude) */ - - /* - ** Don't blow up if Latitude is just a little out of the value - ** range as it may just be a rounding issue. Also removed longitude - ** test, it should be wrapped by cos() and sin(). NFW for PROJ.4, Sep/2001. - */ - if( Latitude < -PI_OVER_2 && Latitude > -1.001 * PI_OVER_2 ) - Latitude = -PI_OVER_2; - else if( Latitude > PI_OVER_2 && Latitude < 1.001 * PI_OVER_2 ) - Latitude = PI_OVER_2; - else if ((Latitude < -PI_OVER_2) || (Latitude > PI_OVER_2)) - { /* Latitude out of range */ - Error_Code |= GEOCENT_LAT_ERROR; - } - - if (!Error_Code) - { /* no errors */ - if (Longitude > PI) - Longitude -= (2*PI); - Sin_Lat = sin(Latitude); - Cos_Lat = cos(Latitude); - Sin2_Lat = Sin_Lat * Sin_Lat; - Rn = gi->Geocent_a / (sqrt(1.0e0 - gi->Geocent_e2 * Sin2_Lat)); - *X = (Rn + Height) * Cos_Lat * cos(Longitude); - *Y = (Rn + Height) * Cos_Lat * sin(Longitude); - *Z = ((Rn * (1 - gi->Geocent_e2)) + Height) * Sin_Lat; - - } - return (Error_Code); -} /* END OF Convert_Geodetic_To_Geocentric */ - -/* - * The function Convert_Geocentric_To_Geodetic converts geocentric - * coordinates (X, Y, Z) to geodetic coordinates (latitude, longitude, - * and height), according to the current ellipsoid parameters. - * - * X : Geocentric X coordinate, in meters. (input) - * Y : Geocentric Y coordinate, in meters. (input) - * Z : Geocentric Z coordinate, in meters. (input) - * Latitude : Calculated latitude value in radians. (output) - * Longitude : Calculated longitude value in radians. (output) - * Height : Calculated height value, in meters. (output) - */ - -#define USE_ITERATIVE_METHOD - -void pj_Convert_Geocentric_To_Geodetic (GeocentricInfo *gi, - double X, - double Y, - double Z, - double *Latitude, - double *Longitude, - double *Height) -{ /* BEGIN Convert_Geocentric_To_Geodetic */ -#if !defined(USE_ITERATIVE_METHOD) -/* - * The method used here is derived from 'An Improved Algorithm for - * Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996 - */ - -/* Note: Variable names follow the notation used in Toms, Feb 1996 */ - - double W; /* distance from Z axis */ - double W2; /* square of distance from Z axis */ - double T0; /* initial estimate of vertical component */ - double T1; /* corrected estimate of vertical component */ - double S0; /* initial estimate of horizontal component */ - double S1; /* corrected estimate of horizontal component */ - double Sin_B0; /* sin(B0), B0 is estimate of Bowring aux variable */ - double Sin3_B0; /* cube of sin(B0) */ - double Cos_B0; /* cos(B0) */ - double Sin_p1; /* sin(phi1), phi1 is estimated latitude */ - double Cos_p1; /* cos(phi1) */ - double Rn; /* Earth radius at location */ - double Sum; /* numerator of cos(phi1) */ - int At_Pole; /* indicates location is in polar region */ - - At_Pole = FALSE; - if (X != 0.0) - { - *Longitude = atan2(Y,X); - } - else - { - if (Y > 0) - { - *Longitude = PI_OVER_2; - } - else if (Y < 0) - { - *Longitude = -PI_OVER_2; - } - else - { - At_Pole = TRUE; - *Longitude = 0.0; - if (Z > 0.0) - { /* north pole */ - *Latitude = PI_OVER_2; - } - else if (Z < 0.0) - { /* south pole */ - *Latitude = -PI_OVER_2; - } - else - { /* center of earth */ - *Latitude = PI_OVER_2; - *Height = -Geocent_b; - return; - } - } - } - W2 = X*X + Y*Y; - W = sqrt(W2); - T0 = Z * AD_C; - S0 = sqrt(T0 * T0 + W2); - Sin_B0 = T0 / S0; - Cos_B0 = W / S0; - Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0; - T1 = Z + gi->Geocent_b * gi->Geocent_ep2 * Sin3_B0; - Sum = W - gi->Geocent_a * gi->Geocent_e2 * Cos_B0 * Cos_B0 * Cos_B0; - S1 = sqrt(T1*T1 + Sum * Sum); - Sin_p1 = T1 / S1; - Cos_p1 = Sum / S1; - Rn = gi->Geocent_a / sqrt(1.0 - gi->Geocent_e2 * Sin_p1 * Sin_p1); - if (Cos_p1 >= COS_67P5) - { - *Height = W / Cos_p1 - Rn; - } - else if (Cos_p1 <= -COS_67P5) - { - *Height = W / -Cos_p1 - Rn; - } - else - { - *Height = Z / Sin_p1 + Rn * (gi->Geocent_e2 - 1.0); - } - if (At_Pole == FALSE) - { - *Latitude = atan(Sin_p1 / Cos_p1); - } -#else /* defined(USE_ITERATIVE_METHOD) */ -/* -* Reference... -* ============ -* Wenzel, H.-G.(1985): Hochauflösende Kugelfunktionsmodelle für -* das Gravitationspotential der Erde. Wiss. Arb. Univ. Hannover -* Nr. 137, p. 130-131. - -* Programmed by GGA- Leibniz-Institute of Applied Geophysics -* Stilleweg 2 -* D-30655 Hannover -* Federal Republic of Germany -* Internet: www.gga-hannover.de -* -* Hannover, March 1999, April 2004. -* see also: comments in statements -* remarks: -* Mathematically exact and because of symmetry of rotation-ellipsoid, -* each point (X,Y,Z) has at least two solutions (Latitude1,Longitude1,Height1) and -* (Latitude2,Longitude2,Height2). Is point=(0.,0.,Z) (P=0.), so you get even -* four solutions, every two symmetrical to the semi-minor axis. -* Here Height1 and Height2 have at least a difference in order of -* radius of curvature (e.g. (0,0,b)=> (90.,0.,0.) or (-90.,0.,-2b); -* (a+100.)*(sqrt(2.)/2.,sqrt(2.)/2.,0.) => (0.,45.,100.) or -* (0.,225.,-(2a+100.))). -* The algorithm always computes (Latitude,Longitude) with smallest |Height|. -* For normal computations, that means |Height|<10000.m, algorithm normally -* converges after to 2-3 steps!!! -* But if |Height| has the amount of length of ellipsoid's axis -* (e.g. -6300000.m), algorithm needs about 15 steps. -*/ - -/* local definitions and variables */ -/* end-criterium of loop, accuracy of sin(Latitude) */ -#define genau 1.E-12 -#define genau2 (genau*genau) -#define maxiter 30 - - double P; /* distance between semi-minor axis and location */ - double RR; /* distance between center and location */ - double CT; /* sin of geocentric latitude */ - double ST; /* cos of geocentric latitude */ - double RX; - double RK; - double RN; /* Earth radius at location */ - double CPHI0; /* cos of start or old geodetic latitude in iterations */ - double SPHI0; /* sin of start or old geodetic latitude in iterations */ - double CPHI; /* cos of searched geodetic latitude */ - double SPHI; /* sin of searched geodetic latitude */ - double SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */ - int iter; /* # of continuous iteration, max. 30 is always enough (s.a.) */ - - P = sqrt(X*X+Y*Y); - RR = sqrt(X*X+Y*Y+Z*Z); - -/* special cases for latitude and longitude */ - if (P/gi->Geocent_a < genau) { - -/* special case, if P=0. (X=0., Y=0.) */ - *Longitude = 0.; - -/* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis - * of ellipsoid (=center of mass), Latitude becomes PI/2 */ - if (RR/gi->Geocent_a < genau) { - *Latitude = PI_OVER_2; - *Height = -gi->Geocent_b; - return ; - - } - } - else { -/* ellipsoidal (geodetic) longitude - * interval: -PI < Longitude <= +PI */ - *Longitude=atan2(Y,X); - } - -/* -------------------------------------------------------------- - * Following iterative algorithm was developed by - * "Institut für Erdmessung", University of Hannover, July 1988. - * Internet: www.ife.uni-hannover.de - * Iterative computation of CPHI,SPHI and Height. - * Iteration of CPHI and SPHI to 10**-12 radian resp. - * 2*10**-7 arcsec. - * -------------------------------------------------------------- - */ - CT = Z/RR; - ST = P/RR; - { - const double denominator = 1.0-gi->Geocent_e2*(2.0-gi->Geocent_e2)*ST*ST; - if( denominator == 0 ) - { - *Latitude = HUGE_VAL; - *Longitude = HUGE_VAL; - *Height = HUGE_VAL; - return; - } - RX = 1.0/sqrt(denominator); - } - CPHI0 = ST*(1.0-gi->Geocent_e2)*RX; - SPHI0 = CT*RX; - iter = 0; - -/* loop to find sin(Latitude) resp. Latitude - * until |sin(Latitude(iter)-Latitude(iter-1))| < genau */ - do - { - iter++; - RN = gi->Geocent_a/sqrt(1.0-gi->Geocent_e2*SPHI0*SPHI0); - -/* ellipsoidal (geodetic) height */ - *Height = P*CPHI0+Z*SPHI0-RN*(1.0-gi->Geocent_e2*SPHI0*SPHI0); - - /* avoid zero division */ - if (RN+*Height==0.0) { - *Latitude = 0.0; - return; - } - RK = gi->Geocent_e2*RN/(RN+*Height); - { - const double denominator = 1.0-RK*(2.0-RK)*ST*ST; - if( denominator == 0 ) - { - *Latitude = HUGE_VAL; - *Longitude = HUGE_VAL; - *Height = HUGE_VAL; - return; - } - RX = 1.0/sqrt(denominator); - } - CPHI = ST*(1.0-RK)*RX; - SPHI = CT*RX; - SDPHI = SPHI*CPHI0-CPHI*SPHI0; - CPHI0 = CPHI; - SPHI0 = SPHI; - } - while (SDPHI*SDPHI > genau2 && iter < maxiter); - -/* ellipsoidal (geodetic) latitude */ - *Latitude=atan2(SPHI, fabs(CPHI)); - -#endif /* defined(USE_ITERATIVE_METHOD) */ -} /* END OF Convert_Geocentric_To_Geodetic */ - - -/////////////////////////////////////////////////////////////////////////////// -/// Main of transform.cpp -/////////////////////////////////////////////////////////////////////////////// - - -static int adjust_axis( projCtx ctx, const char *axis, int denormalize_flag, - long point_count, int point_offset, - double *x, double *y, double *z ); - -#ifndef SRS_WGS84_SEMIMAJOR -#define SRS_WGS84_SEMIMAJOR 6378137.0 -#endif - -#ifndef SRS_WGS84_ESQUARED -#define SRS_WGS84_ESQUARED 0.0066943799901413165 -#endif - -#define Dx_BF (defn->datum_params[0]) -#define Dy_BF (defn->datum_params[1]) -#define Dz_BF (defn->datum_params[2]) -#define Rx_BF (defn->datum_params[3]) -#define Ry_BF (defn->datum_params[4]) -#define Rz_BF (defn->datum_params[5]) -#define M_BF (defn->datum_params[6]) - -/* -** This table is intended to indicate for any given error code -** 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[70] = { - /* 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, - /* 50 to 59 */ 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, - /* 60 to 69 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; - - -/* -------------------------------------------------------------------- */ -/* Read transient_error[] in a safe way. */ -/* -------------------------------------------------------------------- */ -static int get_transient_error_value(int pos_index) -{ - const int array_size = - (int)(sizeof(transient_error) / sizeof(transient_error[0])); - if( pos_index < 0 || pos_index >= array_size ) { - return 0; - } - return transient_error[pos_index]; -} - - -/* -------------------------------------------------------------------- */ -/* Transform unusual input coordinate axis orientation to */ -/* standard form if needed. */ -/* -------------------------------------------------------------------- */ -static int adjust_axes (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { - /* Nothing to do? */ - if (0==strcmp(P->axis,"enu")) - return 0; - - return adjust_axis( P->ctx, P->axis, - dir==PJ_FWD ? 1: 0, n, dist, x, y, z ); -} - - - -/* ----------------------------------------------------------------------- */ -/* Transform geographic (lat/long) source coordinates to */ -/* cartesian ("geocentric"), if needed */ -/* ----------------------------------------------------------------------- */ -static int geographic_to_cartesian (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { - int res; - long i; - double fac = P->to_meter; - - /* Nothing to do? */ - if (!P->is_geocent) - return 0; - - if ( z == nullptr ) { - pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); - return PJD_ERR_GEOCENTRIC; - } - - if (PJ_FWD==dir) { - fac = P->fr_meter; - res = pj_geodetic_to_geocentric( P->a_orig, P->es_orig, n, dist, x, y, z ); - if (res) - return res; - } - - if (fac != 1.0) { - for( i = 0; i < n; i++ ) { - if( x[dist*i] != HUGE_VAL ) { - x[dist*i] *= fac; - y[dist*i] *= fac; - z[dist*i] *= fac; - } - } - } - - if (PJ_FWD==dir) - return 0; - return pj_geocentric_to_geodetic( - P->a_orig, P->es_orig, - n, dist, - x, y, z - ); -} - - - - - - - - - - -/* -------------------------------------------------------------------- */ -/* Transform destination points to projection coordinates, if */ -/* desired. */ -/* */ -/* Ought to fold this into projected_to_geographic */ -/* -------------------------------------------------------------------- */ -static int geographic_to_projected (PJ *P, long n, int dist, double *x, double *y, double *z) { - long i; - - /* Nothing to do? */ - if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) - return 0; - if (P->is_geocent) - return 0; - - if(P->fwd3d != nullptr && !(z == nullptr && P->is_latlong)) - { - /* Three dimensions must be defined */ - if ( z == nullptr) - { - pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); - return PJD_ERR_GEOCENTRIC; - } - - for( i = 0; i < n; i++ ) - { - PJ_XYZ projected_loc; - PJ_LPZ geodetic_loc; - - geodetic_loc.lam = x[dist*i]; - geodetic_loc.phi = y[dist*i]; - geodetic_loc.z = z[dist*i]; - - if (geodetic_loc.lam == HUGE_VAL) - continue; - - proj_errno_reset( P ); - projected_loc = pj_fwd3d( geodetic_loc, P); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - projected_loc.x = HUGE_VAL; - projected_loc.y = HUGE_VAL; - projected_loc.z = HUGE_VAL; - } - } - - x[dist*i] = projected_loc.x; - y[dist*i] = projected_loc.y; - z[dist*i] = projected_loc.z; - } - return 0; - } - - // Ugly hack. See https://github.com/OSGeo/PROJ/issues/1782 - if( P->right == PJ_IO_UNITS_WHATEVER && P->descr && - strncmp(P->descr, "General Oblique Transformation", - strlen("General Oblique Transformation")) == 0 ) - { - P->right = PJ_IO_UNITS_PROJECTED; - } - - for( i = 0; i <n; i++ ) - { - PJ_XY projected_loc; - PJ_LP geodetic_loc; - - geodetic_loc.lam = x[dist*i]; - geodetic_loc.phi = y[dist*i]; - - if( geodetic_loc.lam == HUGE_VAL ) - continue; - - proj_errno_reset( P ); - projected_loc = pj_fwd( geodetic_loc, P ); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - projected_loc.x = HUGE_VAL; - projected_loc.y = HUGE_VAL; - } - } - - x[dist*i] = projected_loc.x; - y[dist*i] = projected_loc.y; - } - return 0; -} - - - - - -/* ----------------------------------------------------------------------- */ -/* Transform projected source coordinates to lat/long, if needed */ -/* ----------------------------------------------------------------------- */ -static int projected_to_geographic (PJ *P, long n, int dist, double *x, double *y, double *z) { - long i; - - /* Nothing to do? */ - if (P->is_latlong && !P->geoc && P->vto_meter == 1.0) - return 0; - if (P->is_geocent) - return 0; - - /* Check first if projection is invertible. */ - if( (P->inv3d == nullptr) && (P->inv == nullptr)) - { - pj_ctx_set_errno(pj_get_ctx(P), PJD_ERR_NON_CONV_INV_MERI_DIST); - pj_log( pj_get_ctx(P), PJ_LOG_ERROR, - "pj_transform(): source projection not invertable" ); - return PJD_ERR_NON_CONV_INV_MERI_DIST; - } - - /* If invertible - First try inv3d if defined */ - if (P->inv3d != nullptr && !(z == nullptr && P->is_latlong)) - { - /* Three dimensions must be defined */ - if ( z == nullptr) - { - pj_ctx_set_errno( pj_get_ctx(P), PJD_ERR_GEOCENTRIC); - return PJD_ERR_GEOCENTRIC; - } - - for (i=0; i < n; i++) - { - PJ_XYZ projected_loc; - PJ_LPZ geodetic_loc; - - projected_loc.x = x[dist*i]; - projected_loc.y = y[dist*i]; - projected_loc.z = z[dist*i]; - - if (projected_loc.x == HUGE_VAL) - continue; - - proj_errno_reset( P ); - geodetic_loc = pj_inv3d(projected_loc, P); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - geodetic_loc.lam = HUGE_VAL; - geodetic_loc.phi = HUGE_VAL; - geodetic_loc.z = HUGE_VAL; - } - } - - x[dist*i] = geodetic_loc.lam; - y[dist*i] = geodetic_loc.phi; - z[dist*i] = geodetic_loc.z; - - } - return 0; - } - - // Ugly hack. See https://github.com/OSGeo/PROJ/issues/1782 - if( P->right == PJ_IO_UNITS_WHATEVER && P->descr && - strncmp(P->descr, "General Oblique Transformation", - strlen("General Oblique Transformation")) == 0 ) - { - P->right = PJ_IO_UNITS_PROJECTED; - } - - /* Fallback to the original PROJ.4 API 2d inversion - inv */ - for( i = 0; i < n; i++ ) { - PJ_XY projected_loc; - PJ_LP geodetic_loc; - - projected_loc.x = x[dist*i]; - projected_loc.y = y[dist*i]; - - if( projected_loc.x == HUGE_VAL ) - continue; - - proj_errno_reset( P ); - geodetic_loc = pj_inv( projected_loc, P ); - if( P->ctx->last_errno != 0 ) - { - if( (P->ctx->last_errno != EDOM - && P->ctx->last_errno != ERANGE) - && (P->ctx->last_errno > 0 - || P->ctx->last_errno < -44 || n == 1 - || get_transient_error_value(-P->ctx->last_errno) == 0 ) ) - { - return P->ctx->last_errno; - } - else - { - geodetic_loc.lam = HUGE_VAL; - geodetic_loc.phi = HUGE_VAL; - } - } - - x[dist*i] = geodetic_loc.lam; - y[dist*i] = geodetic_loc.phi; - } - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Adjust for the prime meridian if needed. */ -/* -------------------------------------------------------------------- */ -static int prime_meridian (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x) { - int i; - double pm = P->from_greenwich; - - /* Nothing to do? */ - if (pm==0.0) - return 0; - if (!(P->is_geocent || P->is_latlong)) - return 0; - - if (dir==PJ_FWD) - pm = -pm; - - for (i = 0; i < n; i++) - if (x[dist*i] != HUGE_VAL) - x[dist*i] += pm; - - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Adjust for vertical scale factor if needed */ -/* -------------------------------------------------------------------- */ -static int height_unit (PJ *P, PJ_DIRECTION dir, long n, int dist, double *z) { - int i; - double fac = P->vto_meter; - - if (PJ_FWD==dir) - fac = P->vfr_meter; - - /* Nothing to do? */ - if (fac==1.0) - return 0; - if (nullptr==z) - return 0; - if (P->is_latlong) - return 0; /* done in pj_inv3d() / pj_fwd3d() */ - - for (i = 0; i < n; i++) - if (z[dist*i] != HUGE_VAL ) - z[dist*i] *= fac; - - return 0; -} - - -/************************************************************************/ -/* pj_apply_vgridshift() */ -/* */ -/* This implementation takes uses the gridlist from a coordinate */ -/* system definition. If the gridlist has not yet been */ -/* populated in the coordinate system definition we set it up */ -/* now. */ -/************************************************************************/ -static int pj_apply_vgridshift( PJ *defn, - int inverse, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - if( defn->vgrids_legacy == nullptr ) - { - defn->vgrids_legacy = new ListOfVGrids; - auto vgrids = pj_vgrid_init(defn, "geoidgrids"); - if( vgrids.empty() ) - return 0; - *static_cast<ListOfVGrids*>(defn->vgrids_legacy) = std::move(vgrids); - } - if( static_cast<ListOfVGrids*>(defn->vgrids_legacy)->empty() ) - { - return 0; - } - - for( int i = 0; i < point_count; i++ ) - { - double value; - long io = i * point_offset; - PJ_LP input; - - input.phi = y[io]; - input.lam = x[io]; - - value = pj_vgrid_value(defn, *static_cast<ListOfVGrids*>(defn->vgrids_legacy), input, 1.0); - - if( inverse ) - z[io] -= value; - else - z[io] += value; - - if( value == HUGE_VAL ) - { - std::string gridlist; - - proj_log_debug(defn, - "pj_apply_vgridshift(): failed to find a grid shift table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, - y[io] * RAD_TO_DEG ); - - for( const auto& gridset: *static_cast<ListOfVGrids*>(defn->vgrids_legacy) ) - { - if( gridlist.empty() ) - gridlist += " tried: "; - else - gridlist += ','; - gridlist += gridset->name(); - } - - proj_log_debug(defn, "%s", gridlist.c_str()); - pj_ctx_set_errno( defn->ctx, PJD_ERR_GRID_AREA ); - - return PJD_ERR_GRID_AREA; - } - } - - return 0; -} - - -/* -------------------------------------------------------------------- */ -/* Transform to ellipsoidal heights if needed */ -/* -------------------------------------------------------------------- */ -static int geometric_to_orthometric (PJ *P, PJ_DIRECTION dir, long n, int dist, double *x, double *y, double *z) { - int err; - if (0==P->has_geoid_vgrids) - return 0; - if (z==nullptr) - return PJD_ERR_GEOCENTRIC; - err = pj_apply_vgridshift (P, dir==PJ_FWD ? 1 : 0, n, dist, x, y, z ); - if (err) - return pj_ctx_get_errno(P->ctx); - return 0; -} - - - -/* -------------------------------------------------------------------- */ -/* Convert datums if needed, and possible. */ -/* -------------------------------------------------------------------- */ -static int datum_transform (PJ *P, PJ *Q, long n, int dist, double *x, double *y, double *z) { - if (0==pj_datum_transform (P, Q, n, dist, x, y, z)) - return 0; - if (P->ctx->last_errno) - return P->ctx->last_errno; - return Q->ctx->last_errno; -} - - - - - -/* -------------------------------------------------------------------- */ -/* If a wrapping center other than 0 is provided, rewrap around */ -/* the suggested center (for latlong coordinate systems only). */ -/* -------------------------------------------------------------------- */ -static int long_wrap (PJ *P, long n, int dist, double *x) { - long i; - - /* Nothing to do? */ - if (P->is_geocent) - return 0; - if (!P->is_long_wrap_set) - return 0; - if (!P->is_latlong) - return 0; - - for (i = 0; i < n; i++ ) { - double val = x[dist*i]; - if (val == HUGE_VAL) - continue; - - /* Get fast in ] -2 PI, 2 PI [ range */ - val = fmod(val, M_TWOPI); - while( val < P->long_wrap_center - M_PI ) - val += M_TWOPI; - while( val > P->long_wrap_center + M_PI ) - val -= M_TWOPI; - x[dist*i] = val; - } - return 0; -} - - - -/************************************************************************/ -/* pj_transform() */ -/* */ -/* Currently this function doesn't recognise if two projections */ -/* are identical (to short circuit reprojection) because it is */ -/* difficult to compare PJ structures (since there are some */ -/* projection specific components). */ -/************************************************************************/ - -int pj_transform( - PJ *src, PJ *dst, - long point_count, int point_offset, - double *x, double *y, double *z -){ - int err; - - src->ctx->last_errno = 0; - dst->ctx->last_errno = 0; - - if( point_offset == 0 ) - point_offset = 1; - - /* Bring input to "normal form": longitude, latitude, ellipsoidal height */ - - err = adjust_axes (src, PJ_INV, point_count, point_offset, x, y, z); - if (err) - return err; - err = geographic_to_cartesian (src, PJ_INV, point_count, point_offset, x, y, z); - if (err) - return err; - err = projected_to_geographic (src, point_count, point_offset, x, y, z); - if (err) - return err; - err = prime_meridian (src, PJ_INV, point_count, point_offset, x); - if (err) - return err; - err = height_unit (src, PJ_INV, point_count, point_offset, z); - if (err) - return err; - err = geometric_to_orthometric (src, PJ_INV, point_count, point_offset, x, y, z); - if (err) - return err; - - /* At the center of the process we do the datum shift (if needed) */ - - err = datum_transform(src, dst, point_count, point_offset, x, y, z ); - if (err) - return err; - - /* Now get out on the other side: Bring "normal form" to output form */ - - err = geometric_to_orthometric (dst, PJ_FWD, point_count, point_offset, x, y, z); - if (err) - return err; - err = height_unit (dst, PJ_FWD, point_count, point_offset, z); - if (err) - return err; - err = prime_meridian (dst, PJ_FWD, point_count, point_offset, x); - if (err) - return err; - err = geographic_to_cartesian (dst, PJ_FWD, point_count, point_offset, x, y, z); - if (err) - return err; - err = geographic_to_projected (dst, point_count, point_offset, x, y, z); - if (err) - return err; - err = long_wrap (dst, point_count, point_offset, x); - if (err) - return err; - err = adjust_axes (dst, PJ_FWD, point_count, point_offset, x, y, z); - if (err) - return err; - - return 0; -} - - - -/************************************************************************/ -/* pj_geodetic_to_geocentric() */ -/************************************************************************/ - -int pj_geodetic_to_geocentric( double a, double es, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double b; - int i; - GeocentricInfo gi; - int ret_errno = 0; - - if( es == 0.0 ) - b = a; - else - b = a * sqrt(1-es); - - if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 ) - { - return PJD_ERR_GEOCENTRIC; - } - - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - if( pj_Convert_Geodetic_To_Geocentric( &gi, y[io], x[io], z[io], - x+io, y+io, z+io ) != 0 ) - { - ret_errno = PJD_ERR_LAT_OR_LON_EXCEED_LIMIT; - x[io] = y[io] = HUGE_VAL; - /* but keep processing points! */ - } - } - - return ret_errno; -} - -/************************************************************************/ -/* pj_geocentric_to_geodetic() */ -/************************************************************************/ - -int pj_geocentric_to_geodetic( double a, double es, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double b; - int i; - GeocentricInfo gi; - - if( es == 0.0 ) - b = a; - else - b = a * sqrt(1-es); - - if( pj_Set_Geocentric_Parameters( &gi, a, b ) != 0 ) - { - return PJD_ERR_GEOCENTRIC; - } - - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - pj_Convert_Geocentric_To_Geodetic( &gi, x[io], y[io], z[io], - y+io, x+io, z+io ); - } - - return 0; -} - -/************************************************************************/ -/* pj_compare_datums() */ -/* */ -/* Returns TRUE if the two datums are identical, otherwise */ -/* FALSE. */ -/************************************************************************/ - -int pj_compare_datums( PJ *srcdefn, PJ *dstdefn ) - -{ - if( srcdefn->datum_type != dstdefn->datum_type ) - { - return 0; - } - else if( srcdefn->a_orig != dstdefn->a_orig - || ABS(srcdefn->es_orig - dstdefn->es_orig) > 0.000000000050 ) - { - /* the tolerance for es is to ensure that GRS80 and WGS84 are - considered identical */ - return 0; - } - else if( srcdefn->datum_type == PJD_3PARAM ) - { - return (srcdefn->datum_params[0] == dstdefn->datum_params[0] - && srcdefn->datum_params[1] == dstdefn->datum_params[1] - && srcdefn->datum_params[2] == dstdefn->datum_params[2]); - } - else if( srcdefn->datum_type == PJD_7PARAM ) - { - return (srcdefn->datum_params[0] == dstdefn->datum_params[0] - && srcdefn->datum_params[1] == dstdefn->datum_params[1] - && srcdefn->datum_params[2] == dstdefn->datum_params[2] - && srcdefn->datum_params[3] == dstdefn->datum_params[3] - && srcdefn->datum_params[4] == dstdefn->datum_params[4] - && srcdefn->datum_params[5] == dstdefn->datum_params[5] - && srcdefn->datum_params[6] == dstdefn->datum_params[6]); - } - else if( srcdefn->datum_type == PJD_GRIDSHIFT ) - { - const char* srcnadgrids = - pj_param(srcdefn->ctx, srcdefn->params,"snadgrids").s; - const char* dstnadgrids = - pj_param(dstdefn->ctx, dstdefn->params,"snadgrids").s; - return srcnadgrids != nullptr && dstnadgrids != nullptr && - strcmp( srcnadgrids, dstnadgrids ) == 0; - } - else - return 1; -} - -/************************************************************************/ -/* pj_geocentic_to_wgs84() */ -/************************************************************************/ - -static -int pj_geocentric_to_wgs84( PJ *defn, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - int i; - - if( defn->datum_type == PJD_3PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - x[io] = x[io] + Dx_BF; - y[io] = y[io] + Dy_BF; - z[io] = z[io] + Dz_BF; - } - } - else if( defn->datum_type == PJD_7PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - double x_out, y_out, z_out; - - if( x[io] == HUGE_VAL ) - continue; - - x_out = M_BF*( x[io] - Rz_BF*y[io] + Ry_BF*z[io]) + Dx_BF; - y_out = M_BF*( Rz_BF*x[io] + y[io] - Rx_BF*z[io]) + Dy_BF; - z_out = M_BF*(-Ry_BF*x[io] + Rx_BF*y[io] + z[io]) + Dz_BF; - - x[io] = x_out; - y[io] = y_out; - z[io] = z_out; - } - } - - return 0; -} - -/************************************************************************/ -/* pj_geocentic_from_wgs84() */ -/************************************************************************/ - -static -int pj_geocentric_from_wgs84( PJ *defn, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - int i; - - if( defn->datum_type == PJD_3PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - - if( x[io] == HUGE_VAL ) - continue; - - x[io] = x[io] - Dx_BF; - y[io] = y[io] - Dy_BF; - z[io] = z[io] - Dz_BF; - } - } - else if( defn->datum_type == PJD_7PARAM ) - { - for( i = 0; i < point_count; i++ ) - { - long io = i * point_offset; - double x_tmp, y_tmp, z_tmp; - - if( x[io] == HUGE_VAL ) - continue; - - x_tmp = (x[io] - Dx_BF) / M_BF; - y_tmp = (y[io] - Dy_BF) / M_BF; - z_tmp = (z[io] - Dz_BF) / M_BF; - - x[io] = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp; - y[io] = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp; - z[io] = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp; - } - } - - return 0; -} - - -/************************************************************************/ -/* pj_apply_gridshift_2() */ -/* */ -/* This implementation uses the gridlist from a coordinate */ -/* system definition. If the gridlist has not yet been */ -/* populated in the coordinate system definition we set it up */ -/* now. */ -/************************************************************************/ -static -int pj_apply_gridshift_2( PJ *defn, int inverse, - long point_count, int point_offset, - double *x, double *y, double * /*z*/ ) - -{ - if( defn->hgrids_legacy == nullptr ) - { - defn->hgrids_legacy = new ListOfHGrids; - auto hgrids = pj_hgrid_init(defn, "nadgrids"); - if( hgrids.empty() ) - return 0; - *static_cast<ListOfHGrids*>(defn->hgrids_legacy) = std::move(hgrids); - } - if( static_cast<ListOfHGrids*>(defn->hgrids_legacy)->empty() ) - { - return 0; - } - - for( long i = 0; i < point_count; i++ ) - { - PJ_LP input; - - long io = i * point_offset; - input.phi = y[io]; - input.lam = x[io]; - - auto output = pj_hgrid_apply(defn->ctx, *static_cast<ListOfHGrids*>(defn->hgrids_legacy), input, inverse ? PJ_INV : PJ_FWD); - - if ( output.lam != HUGE_VAL ) - { - y[io] = output.phi; - x[io] = output.lam; - } - else - { - if( defn->ctx->debug_level >= PJ_LOG_DEBUG_MAJOR ) - { - pj_log( defn->ctx, PJ_LOG_DEBUG_MAJOR, - "pj_apply_gridshift(): failed to find a grid shift table for\n" - " location (%.7fdW,%.7fdN)", - x[io] * RAD_TO_DEG, - y[io] * RAD_TO_DEG ); - } - } - } - - return 0; -} - - -/************************************************************************/ -/* pj_datum_transform() */ -/* */ -/* The input should be long/lat/z coordinates in radians in the */ -/* source datum, and the output should be long/lat/z */ -/* coordinates in radians in the destination datum. */ -/************************************************************************/ - -int pj_datum_transform( PJ *src, PJ *dst, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double src_a, src_es, dst_a, dst_es; - int z_is_temp = FALSE; - -/* -------------------------------------------------------------------- */ -/* We cannot do any meaningful datum transformation if either */ -/* the source or destination are of an unknown datum type */ -/* (ie. only a +ellps declaration, no +datum). This is new */ -/* behavior for PROJ 4.6.0. */ -/* -------------------------------------------------------------------- */ - if( src->datum_type == PJD_UNKNOWN - || dst->datum_type == PJD_UNKNOWN ) - return 0; - -/* -------------------------------------------------------------------- */ -/* Short cut if the datums are identical. */ -/* -------------------------------------------------------------------- */ - if( pj_compare_datums( src, dst ) ) - return 0; - - src_a = src->a_orig; - src_es = src->es_orig; - - dst_a = dst->a_orig; - dst_es = dst->es_orig; - -/* -------------------------------------------------------------------- */ -/* Create a temporary Z array if one is not provided. */ -/* -------------------------------------------------------------------- */ - if( z == nullptr ) - { - size_t bytes = sizeof(double) * point_count * point_offset; - z = (double *) pj_malloc(bytes); - memset( z, 0, bytes ); - z_is_temp = TRUE; - } - -#define CHECK_RETURN(defn) {if( defn->ctx->last_errno != 0 && (defn->ctx->last_errno > 0 || get_transient_error_value(-defn->ctx->last_errno) == 0) ) { if( z_is_temp ) pj_dalloc(z); return defn->ctx->last_errno; }} - -/* -------------------------------------------------------------------- */ -/* If this datum requires grid shifts, then apply it to geodetic */ -/* coordinates. */ -/* -------------------------------------------------------------------- */ - if( src->datum_type == PJD_GRIDSHIFT ) - { - pj_apply_gridshift_2( src, 0, point_count, point_offset, x, y, z ); - CHECK_RETURN(src); - - src_a = SRS_WGS84_SEMIMAJOR; - src_es = SRS_WGS84_ESQUARED; - } - - if( dst->datum_type == PJD_GRIDSHIFT ) - { - dst_a = SRS_WGS84_SEMIMAJOR; - dst_es = SRS_WGS84_ESQUARED; - } - -/* ==================================================================== */ -/* Do we need to go through geocentric coordinates? */ -/* ==================================================================== */ - if( src_es != dst_es || src_a != dst_a - || src->datum_type == PJD_3PARAM - || src->datum_type == PJD_7PARAM - || dst->datum_type == PJD_3PARAM - || dst->datum_type == PJD_7PARAM) - { -/* -------------------------------------------------------------------- */ -/* Convert to geocentric coordinates. */ -/* -------------------------------------------------------------------- */ - src->ctx->last_errno = - pj_geodetic_to_geocentric( src_a, src_es, - point_count, point_offset, x, y, z ); - CHECK_RETURN(src); - -/* -------------------------------------------------------------------- */ -/* Convert between datums. */ -/* -------------------------------------------------------------------- */ - if( src->datum_type == PJD_3PARAM - || src->datum_type == PJD_7PARAM ) - { - pj_geocentric_to_wgs84( src, point_count, point_offset,x,y,z); - CHECK_RETURN(src); - } - - if( dst->datum_type == PJD_3PARAM - || dst->datum_type == PJD_7PARAM ) - { - pj_geocentric_from_wgs84( dst, point_count,point_offset,x,y,z); - CHECK_RETURN(dst); - } - -/* -------------------------------------------------------------------- */ -/* Convert back to geodetic coordinates. */ -/* -------------------------------------------------------------------- */ - dst->ctx->last_errno = - pj_geocentric_to_geodetic( dst_a, dst_es, - point_count, point_offset, x, y, z ); - CHECK_RETURN(dst); - } - -/* -------------------------------------------------------------------- */ -/* Apply grid shift to destination if required. */ -/* -------------------------------------------------------------------- */ - if( dst->datum_type == PJD_GRIDSHIFT ) - { - pj_apply_gridshift_2( dst, 1, point_count, point_offset, x, y, z ); - CHECK_RETURN(dst); - } - - if( z_is_temp ) - pj_dalloc( z ); - - return 0; -} - -/************************************************************************/ -/* adjust_axis() */ -/* */ -/* Normalize or de-normalized the x/y/z axes. The normal form */ -/* is "enu" (easting, northing, up). */ -/************************************************************************/ -static int adjust_axis( projCtx ctx, - const char *axis, int denormalize_flag, - long point_count, int point_offset, - double *x, double *y, double *z ) - -{ - double x_in, y_in, z_in = 0.0; - int i, i_axis; - - if( !denormalize_flag ) - { - for( i = 0; i < point_count; i++ ) - { - x_in = x[point_offset*i]; - y_in = y[point_offset*i]; - if( z ) - z_in = z[point_offset*i]; - - for( i_axis = 0; i_axis < 3; i_axis++ ) - { - double value; - - if( i_axis == 0 ) - value = x_in; - else if( i_axis == 1 ) - value = y_in; - else - value = z_in; - - switch( axis[i_axis] ) - { - case 'e': - x[point_offset*i] = value; - break; - case 'w': - x[point_offset*i] = -value; - break; - case 'n': - y[point_offset*i] = value; - break; - case 's': - y[point_offset*i] = -value; - break; - case 'u': - if( z ) - z[point_offset*i] = value; - break; - case 'd': - if( z ) - z[point_offset*i] = -value; - break; - default: - pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); - return PJD_ERR_AXIS; - } - } /* i_axis */ - } /* i (point) */ - } - - else /* denormalize */ - { - for( i = 0; i < point_count; i++ ) - { - x_in = x[point_offset*i]; - y_in = y[point_offset*i]; - if( z ) - z_in = z[point_offset*i]; - - for( i_axis = 0; i_axis < 3; i_axis++ ) - { - double *target; - - if( i_axis == 2 && z == nullptr ) - continue; - - if( i_axis == 0 ) - target = x; - else if( i_axis == 1 ) - target = y; - else - target = z; - - switch( axis[i_axis] ) - { - case 'e': - target[point_offset*i] = x_in; break; - case 'w': - target[point_offset*i] = -x_in; break; - case 'n': - target[point_offset*i] = y_in; break; - case 's': - target[point_offset*i] = -y_in; break; - case 'u': - target[point_offset*i] = z_in; break; - case 'd': - target[point_offset*i] = -z_in; break; - default: - pj_ctx_set_errno( ctx, PJD_ERR_AXIS ); - return PJD_ERR_AXIS; - } - } /* i_axis */ - } /* i (point) */ - } - - return 0; -} -// --------------------------------------------------------------------------- - -void pj_deallocate_grids() -{ -} diff --git a/src/transformations/affine.cpp b/src/transformations/affine.cpp index 28f73b9a..43fd8642 100644 --- a/src/transformations/affine.cpp +++ b/src/transformations/affine.cpp @@ -110,7 +110,7 @@ static PJ_LP reverse_2d(PJ_XY xy, PJ *P) { } static struct pj_opaque_affine * initQ() { - struct pj_opaque_affine *Q = static_cast<struct pj_opaque_affine *>(pj_calloc(1, sizeof(struct pj_opaque_affine))); + struct pj_opaque_affine *Q = static_cast<struct pj_opaque_affine *>(calloc(1, sizeof(struct pj_opaque_affine))); if (nullptr==Q) return nullptr; diff --git a/src/transformations/helmert.cpp b/src/transformations/helmert.cpp index d3857d89..99aa74a4 100644 --- a/src/transformations/helmert.cpp +++ b/src/transformations/helmert.cpp @@ -476,7 +476,7 @@ static PJ_COORD helmert_reverse_4d (PJ_COORD point, PJ *P) { static PJ* init_helmert_six_parameters(PJ* P) { - struct pj_opaque_helmert *Q = static_cast<struct pj_opaque_helmert*>(pj_calloc (1, sizeof (struct pj_opaque_helmert))); + struct pj_opaque_helmert *Q = static_cast<struct pj_opaque_helmert*>(calloc (1, sizeof (struct pj_opaque_helmert))); if (nullptr==Q) return pj_default_destructor (P, ENOMEM); P->opaque = (void *) Q; diff --git a/src/transformations/horner.cpp b/src/transformations/horner.cpp index a6638773..2c049186 100644 --- a/src/transformations/horner.cpp +++ b/src/transformations/horner.cpp @@ -89,8 +89,8 @@ PROJ_HEAD(horner, "Horner polynomial evaluation"); /* make horner.h interface with proj's memory management */ -#define horner_dealloc(x) pj_dealloc(x) -#define horner_calloc(n,x) pj_calloc(n,x) +#define horner_dealloc(x) free(x) +#define horner_calloc(n,x) calloc(n,x) namespace { // anonymous namespace struct horner { @@ -412,7 +412,7 @@ static int parse_coefs (PJ *P, double *coefs, const char *param, int ncoefs) { char *buf, *init, *next = nullptr; int i; - buf = static_cast<char*>(pj_calloc (strlen (param) + 2, sizeof(char))); + buf = static_cast<char*>(calloc (strlen (param) + 2, sizeof(char))); if (nullptr==buf) { proj_log_error (P, "Horner: No memory left"); return 0; @@ -420,12 +420,12 @@ static int parse_coefs (PJ *P, double *coefs, const char *param, int ncoefs) { sprintf (buf, "t%s", param); if (0==pj_param (P->ctx, P->params, buf).i) { - pj_dealloc (buf); + free (buf); return 0; } sprintf (buf, "s%s", param); init = pj_param(P->ctx, P->params, buf).s; - pj_dealloc (buf); + free (buf); for (i = 0; i < ncoefs; i++) { if (i > 0) { diff --git a/src/transformations/molodensky.cpp b/src/transformations/molodensky.cpp index 7d17f64c..bf5960d2 100644 --- a/src/transformations/molodensky.cpp +++ b/src/transformations/molodensky.cpp @@ -298,7 +298,7 @@ static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { PJ *TRANSFORMATION(molodensky,1) { int count_required_params = 0; - struct pj_opaque_molodensky *Q = static_cast<struct pj_opaque_molodensky*>(pj_calloc(1, sizeof(struct pj_opaque_molodensky))); + struct pj_opaque_molodensky *Q = static_cast<struct pj_opaque_molodensky*>(calloc(1, sizeof(struct pj_opaque_molodensky))); if (nullptr==Q) return pj_default_destructor(P, ENOMEM); P->opaque = (void *) Q; diff --git a/src/tsfn.cpp b/src/tsfn.cpp index 32da09f2..8ed258d6 100644 --- a/src/tsfn.cpp +++ b/src/tsfn.cpp @@ -4,14 +4,28 @@ #include "proj_internal.h" double pj_tsfn(double phi, double sinphi, double e) { - double denominator; - sinphi *= e; + /**************************************************************************** + * Determine function ts(phi) defined in Snyder (1987), Eq. (7-10) + * Inputs: + * phi = geographic latitude (radians) + * e = eccentricity of the ellipsoid (dimensionless) + * Output: + * ts = exp(-psi) where psi is the isometric latitude (dimensionless) + * = 1 / (tan(chi) + sec(chi)) + * Here isometric latitude is defined by + * psi = log( tan(pi/4 + phi/2) * + * ( (1 - e*sin(phi)) / (1 + e*sin(phi)) )^(e/2) ) + * = asinh(tan(phi)) - e * atanh(e * sin(phi)) + * = asinh(tan(chi)) + * chi = conformal latitude + ***************************************************************************/ - /* avoid zero division, fail gracefully */ - denominator = 1.0 + sinphi; - if (denominator == 0.0) - return HUGE_VAL; - - return (tan (.5 * (M_HALFPI - phi)) / - pow((1. - sinphi) / (denominator), .5 * e)); + double cosphi = cos(phi); + // exp(-asinh(tan(phi))) = 1 / (tan(phi) + sec(phi)) + // = cos(phi) / (1 + sin(phi)) good for phi > 0 + // = (1 - sin(phi)) / cos(phi) good for phi < 0 + return exp(e * atanh(e * sinphi)) * + ( sinphi > 0 ? + cosphi / (1 + sinphi) : + (1 - sinphi) / cosphi ); } diff --git a/src/utils.cpp b/src/utils.cpp deleted file mode 100644 index 9cb13f44..00000000 --- a/src/utils.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/****************************************************************************** - * Project: PROJ.4 - * Purpose: Some utility functions we don't want to bother putting in - * their own source files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2001, Frank Warmerdam - * - * 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 <stdio.h> -#include <string.h> - -#include "proj.h" -#include "proj_internal.h" - -/************************************************************************/ -/* pj_is_latlong() */ -/* */ -/* Returns TRUE if this coordinate system object is */ -/* geographic. */ -/************************************************************************/ - -int pj_is_latlong( PJ *pj ) - -{ - return pj == nullptr || pj->is_latlong; -} - -/************************************************************************/ -/* pj_is_geocent() */ -/* */ -/* Returns TRUE if this coordinate system object is geocentric. */ -/************************************************************************/ - -int pj_is_geocent( PJ *pj ) - -{ - return pj != nullptr && pj->is_geocent; -} - -/************************************************************************/ -/* pj_latlong_from_proj() */ -/* */ -/* Return a PJ* definition defining the lat/long coordinate */ -/* system on which a projection is based. If the coordinate */ -/* system passed in is latlong, a clone of the same will be */ -/* returned. */ -/************************************************************************/ - -PJ *pj_latlong_from_proj( PJ *pj_in ) - -{ - char defn[512]; - int got_datum = FALSE; - - pj_errno = 0; - strcpy( defn, "+proj=latlong" ); - - if( pj_param(pj_in->ctx, pj_in->params, "tdatum").i ) - { - got_datum = TRUE; - sprintf( defn+strlen(defn), " +datum=%s", - pj_param(pj_in->ctx, pj_in->params,"sdatum").s ); - } - else if( pj_param(pj_in->ctx, pj_in->params, "tellps").i ) - { - sprintf( defn+strlen(defn), " +ellps=%s", - pj_param(pj_in->ctx, pj_in->params,"sellps").s ); - } - else if( pj_param(pj_in->ctx,pj_in->params, "ta").i ) - { - sprintf( defn+strlen(defn), " +a=%s", - pj_param(pj_in->ctx,pj_in->params,"sa").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tb").i ) - sprintf( defn+strlen(defn), " +b=%s", - pj_param(pj_in->ctx,pj_in->params,"sb").s ); - else if( pj_param(pj_in->ctx,pj_in->params, "tes").i ) - sprintf( defn+strlen(defn), " +es=%s", - pj_param(pj_in->ctx,pj_in->params,"ses").s ); - else if( pj_param(pj_in->ctx,pj_in->params, "tf").i ) - sprintf( defn+strlen(defn), " +f=%s", - pj_param(pj_in->ctx,pj_in->params,"sf").s ); - else - { - char* ptr = defn+strlen(defn); - sprintf( ptr, " +es=%.16g", pj_in->es ); - /* TODO later: use C++ ostringstream with imbue(std::locale::classic()) */ - /* to be locale unaware */ - for(; *ptr; ptr++) - { - if( *ptr == ',' ) - *ptr = '.'; - } - } - } - else - { - pj_ctx_set_errno( pj_in->ctx, PJD_ERR_MAJOR_AXIS_NOT_GIVEN ); - - return nullptr; - } - - if( !got_datum ) - { - if( pj_param(pj_in->ctx,pj_in->params, "ttowgs84").i ) - sprintf( defn+strlen(defn), " +towgs84=%s", - pj_param(pj_in->ctx,pj_in->params,"stowgs84").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tnadgrids").i ) - sprintf( defn+strlen(defn), " +nadgrids=%s", - pj_param(pj_in->ctx,pj_in->params,"snadgrids").s ); - } - - /* copy over some other information related to ellipsoid */ - if( pj_param(pj_in->ctx,pj_in->params, "tR").i ) - sprintf( defn+strlen(defn), " +R=%s", - pj_param(pj_in->ctx,pj_in->params,"sR").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_A").i ) - sprintf( defn+strlen(defn), " +R_A" ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_V").i ) - sprintf( defn+strlen(defn), " +R_V" ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_a").i ) - sprintf( defn+strlen(defn), " +R_a" ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_a").i ) - sprintf( defn+strlen(defn), " +R_lat_a=%s", - pj_param(pj_in->ctx,pj_in->params,"sR_lat_a").s ); - - if( pj_param(pj_in->ctx,pj_in->params, "tR_lat_g").i ) - sprintf( defn+strlen(defn), " +R_lat_g=%s", - pj_param(pj_in->ctx,pj_in->params,"sR_lat_g").s ); - - /* copy over prime meridian */ - if( pj_param(pj_in->ctx,pj_in->params, "tpm").i ) - sprintf( defn+strlen(defn), " +pm=%s", - pj_param(pj_in->ctx,pj_in->params,"spm").s ); - - return pj_init_plus_ctx( pj_in->ctx, defn ); -} - -/************************************************************************/ -/* pj_get_spheroid_defn() */ -/* */ -/* Fetch the internal definition of the spheroid. Note that */ -/* you can compute "b" from eccentricity_squared as: */ -/* */ -/* b = a * sqrt(1 - es) */ -/************************************************************************/ - -void pj_get_spheroid_defn(projPJ defn, double *major_axis, double *eccentricity_squared) -{ - if ( major_axis ) - *major_axis = defn->a; - - if ( eccentricity_squared ) - *eccentricity_squared = defn->es; -} diff --git a/src/wkt2_generated_parser.c b/src/wkt2_generated_parser.c index feb2cc6b..f7bb5798 100644 --- a/src/wkt2_generated_parser.c +++ b/src/wkt2_generated_parser.c @@ -542,16 +542,16 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 106 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 3132 +#define YYLAST 3219 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 164 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 353 /* YYNRULES -- Number of rules. */ -#define YYNRULES 694 +#define YYNRULES 695 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 1427 +#define YYNSTATES 1429 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ @@ -658,30 +658,30 @@ static const yytype_uint16 yyrline[] = 997, 1003, 1003, 1007, 1007, 1008, 1008, 1010, 1015, 1016, 1017, 1018, 1019, 1021, 1027, 1032, 1038, 1040, 1042, 1044, 1048, 1054, 1055, 1056, 1058, 1060, 1062, 1066, 1066, 1068, - 1070, 1075, 1076, 1078, 1080, 1082, 1084, 1088, 1088, 1090, - 1096, 1103, 1103, 1106, 1113, 1114, 1115, 1116, 1117, 1119, - 1123, 1125, 1127, 1127, 1131, 1136, 1136, 1136, 1140, 1145, - 1145, 1147, 1151, 1151, 1155, 1160, 1162, 1166, 1166, 1170, - 1175, 1177, 1181, 1182, 1183, 1184, 1185, 1187, 1187, 1189, - 1192, 1194, 1194, 1196, 1198, 1200, 1204, 1210, 1211, 1212, - 1213, 1215, 1217, 1221, 1226, 1228, 1231, 1236, 1240, 1246, - 1246, 1246, 1246, 1246, 1246, 1250, 1255, 1257, 1262, 1262, - 1263, 1265, 1265, 1267, 1274, 1274, 1276, 1283, 1283, 1285, - 1292, 1299, 1304, 1305, 1306, 1308, 1314, 1319, 1327, 1333, - 1335, 1337, 1343, 1345, 1345, 1346, 1346, 1350, 1356, 1356, - 1358, 1363, 1369, 1374, 1380, 1385, 1390, 1396, 1401, 1406, - 1412, 1417, 1422, 1428, 1428, 1429, 1429, 1430, 1430, 1431, - 1431, 1432, 1432, 1433, 1433, 1436, 1436, 1438, 1439, 1440, - 1442, 1444, 1448, 1451, 1451, 1454, 1455, 1456, 1458, 1462, - 1463, 1465, 1467, 1467, 1468, 1468, 1469, 1469, 1469, 1470, - 1471, 1471, 1472, 1472, 1473, 1473, 1475, 1475, 1476, 1476, - 1477, 1478, 1478, 1482, 1486, 1487, 1490, 1495, 1496, 1497, - 1498, 1499, 1500, 1501, 1503, 1505, 1507, 1510, 1512, 1514, - 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1533, 1537, 1538, - 1541, 1546, 1547, 1548, 1549, 1550, 1552, 1557, 1562, 1563, - 1566, 1572, 1572, 1572, 1572, 1574, 1575, 1576, 1577, 1579, - 1581, 1586, 1592, 1594, 1599, 1600, 1603, 1609, 1609, 1611, - 1612, 1613, 1614, 1616, 1618 + 1070, 1075, 1076, 1077, 1079, 1081, 1083, 1085, 1089, 1089, + 1091, 1097, 1104, 1104, 1107, 1114, 1115, 1116, 1117, 1118, + 1120, 1124, 1126, 1128, 1128, 1132, 1137, 1137, 1137, 1141, + 1146, 1146, 1148, 1152, 1152, 1156, 1161, 1163, 1167, 1167, + 1171, 1176, 1178, 1182, 1183, 1184, 1185, 1186, 1188, 1188, + 1190, 1193, 1195, 1195, 1197, 1199, 1201, 1205, 1211, 1212, + 1213, 1214, 1216, 1218, 1222, 1227, 1229, 1232, 1237, 1241, + 1247, 1247, 1247, 1247, 1247, 1247, 1251, 1256, 1258, 1263, + 1263, 1264, 1266, 1266, 1268, 1275, 1275, 1277, 1284, 1284, + 1286, 1293, 1300, 1305, 1306, 1307, 1309, 1315, 1320, 1328, + 1334, 1336, 1338, 1344, 1346, 1346, 1347, 1347, 1351, 1357, + 1357, 1359, 1364, 1370, 1375, 1381, 1386, 1391, 1397, 1402, + 1407, 1413, 1418, 1423, 1429, 1429, 1430, 1430, 1431, 1431, + 1432, 1432, 1433, 1433, 1434, 1434, 1437, 1437, 1439, 1440, + 1441, 1443, 1445, 1449, 1452, 1452, 1455, 1456, 1457, 1459, + 1463, 1464, 1466, 1468, 1468, 1469, 1469, 1470, 1470, 1470, + 1471, 1472, 1472, 1473, 1473, 1474, 1474, 1476, 1476, 1477, + 1477, 1478, 1479, 1479, 1483, 1487, 1488, 1491, 1496, 1497, + 1498, 1499, 1500, 1501, 1502, 1504, 1506, 1508, 1511, 1513, + 1515, 1517, 1519, 1521, 1523, 1525, 1527, 1529, 1534, 1538, + 1539, 1542, 1547, 1548, 1549, 1550, 1551, 1553, 1558, 1563, + 1564, 1567, 1573, 1573, 1573, 1573, 1575, 1576, 1577, 1578, + 1580, 1582, 1587, 1593, 1595, 1600, 1601, 1604, 1610, 1610, + 1612, 1613, 1614, 1615, 1617, 1619 }; #endif @@ -933,7 +933,7 @@ static const yytype_uint16 yytoknum[] = #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-1232))) -#define YYTABLE_NINF -633 +#define YYTABLE_NINF -634 #define yytable_value_is_error(Yytable_value) \ 0 @@ -942,149 +942,149 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - 2573, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, + 1574, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, - -1232, -1232, -1232, -1232, -1232, -1232, -1232, 114, -1232, -1232, - -1232, 231, -1232, -1232, -1232, 231, -1232, -1232, -1232, -1232, - -1232, -1232, 231, 231, -1232, 231, -1232, -75, 231, -1232, - 231, -1232, 231, -1232, -1232, -1232, 231, -1232, 231, -1232, - 231, -1232, 231, -1232, 231, -1232, 231, -1232, 231, -1232, - 231, -1232, -1232, -1232, -1232, -1232, -1232, -1232, 231, -1232, - -1232, -1232, -1232, -1232, -1232, 231, -1232, 231, -1232, 231, - -1232, 231, -1232, 231, -1232, 231, -1232, -1232, -1232, 33, - 33, 33, 33, 33, -1232, 81, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 879, - 33, 33, 33, 117, -1232, -1232, -75, -1232, -75, -1232, - -75, -75, -1232, -75, -1232, -1232, -1232, 231, -1232, -75, - -75, -1232, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -1232, -75, -1232, -75, -1232, -1232, -1232, -1232, 28, - -1232, -1232, -1232, -1232, -1232, 97, 168, 186, -1232, -1232, - -1232, -1232, 284, -1232, -75, -1232, -75, -75, -75, -1232, - -75, 231, 1038, 176, 66, 66, 713, 33, 287, 179, - 157, 766, 290, 284, 244, 284, 413, 284, 105, 286, - 284, 297, 1406, -1232, -1232, -1232, 428, 101, -1232, -1232, - 101, -1232, -1232, 101, -1232, -1232, 331, 879, -1232, -1232, - -1232, -1232, -1232, -1232, -1232, 728, -1232, -1232, -1232, -1232, - 265, 278, 293, 713, -1232, -75, -1232, -75, 231, -1232, - -1232, -1232, -1232, 231, -75, 231, -75, -1232, 231, 231, - -75, -75, -1232, -1232, -1232, -1232, -75, -75, -75, -75, - -1232, -75, -1232, -75, -75, -75, -1232, -1232, -1232, -1232, - 231, 231, -1232, -1232, -75, 231, -1232, -1232, 231, -75, - -75, -1232, -75, -1232, -1232, 231, -1232, -75, -75, 231, - -1232, -1232, -75, -75, 231, -1232, -1232, -75, -75, 231, - -1232, -1232, -75, -75, 231, -1232, -1232, -75, -75, 231, - -75, 231, -1232, -1232, -75, 231, -1232, -75, -1232, -1232, - -1232, -1232, 231, -1232, -75, 231, -75, -75, -75, -75, - -75, -1232, -75, 231, 284, -1232, 476, 728, -1232, -1232, - 387, 284, 283, 284, 284, 33, 33, 59, 404, 258, - 33, 33, 441, 441, 59, 258, 441, 441, 713, 476, - 284, 452, 33, 33, 349, 284, 33, 33, 88, 477, - 441, 33, 479, -1232, 479, 33, 477, 441, 33, 477, - 441, 33, 477, 441, 33, -1232, -1232, 682, 74, -1232, - 33, 441, 33, 1406, 728, 117, -1232, 33, 331, 117, - -1232, 487, 117, -1232, 331, 469, 879, -1232, 728, -1232, - -1232, -1232, -1232, -1232, -1232, -1232, -1232, -75, -75, 231, - -1232, 231, -1232, -1232, -75, -75, 231, -75, -1232, -1232, - -1232, -75, -75, -75, -1232, -75, 231, -1232, -1232, -1232, - -1232, -1232, -1232, 231, 284, -75, -1232, -75, -75, -1232, - -75, 231, -75, -75, 284, -75, -75, -1232, -75, -75, - 713, 284, -1232, -75, -75, -75, -1232, -75, -75, 231, - -1232, -1232, -75, -75, -75, 231, 284, -75, -75, -75, - -75, -1232, 284, 284, -75, -75, 284, -75, -75, 284, - -75, -75, -1232, -1232, 116, -1232, 284, -75, -1232, 284, - -75, -75, -75, 293, 284, -1232, 284, -75, -1232, -75, - 231, -75, -1232, -75, 231, 284, -1232, 488, 511, 33, - 33, -1232, -1232, 479, -1232, 1192, 486, 479, 284, 176, - 258, 614, 284, 728, 1482, -1232, 477, 56, 56, 477, - 33, 477, 258, -1232, 477, 477, 148, 284, 345, -1232, - -1232, -1232, 477, 56, 56, -1232, -1232, 33, 284, 176, - 477, 1503, -1232, 477, 277, -1232, -1232, -1232, -1232, 477, - -1, -1232, 477, -2, -1232, 477, 22, -1232, -1232, 728, - -1232, -1232, 728, -1232, -1232, -1232, 477, 179, 1669, 284, - 728, -1232, -1232, 487, 1210, 284, 33, 523, 1412, 284, - 33, -1232, -75, -1232, -1232, 284, -1232, 284, -1232, -75, - -1232, 284, -75, -1232, -75, -1232, -75, 284, -1232, -1232, - -1232, 231, -1232, 293, 284, -1232, -1232, -1232, -1232, -1232, - -1232, -1232, -1232, -1232, -75, -1232, -1232, -1232, -1232, -75, - -75, -75, -1232, -75, -75, -75, -75, 284, -1232, -75, - 284, 284, 284, 284, -1232, -1232, -75, -75, 231, -1232, - -1232, -1232, -75, 231, 284, -75, -75, -75, -75, -1232, - -75, -1232, -75, 284, -75, 284, -75, -75, 284, -75, - 284, -75, 284, -75, 159, 401, -1232, 767, 284, -1232, - -1232, -1232, -1232, -75, -1232, -1232, -1232, -1232, -1232, -1232, - -1232, -1232, -1232, -1232, -1232, -75, 231, -75, 231, -1232, - -75, 231, -75, 231, -75, 231, -75, 231, -75, -1232, - 231, -75, -1232, -1232, -75, -1232, -1232, -1232, 231, -75, - -75, 231, -75, 231, -1232, -1232, -75, -1232, 231, -1232, - -1232, -75, 511, -1232, -1232, -1232, -1232, -1232, -1232, 257, - -1232, 33, 728, -1232, 586, 586, 586, 586, 59, 196, - 284, 59, 284, -1232, 487, -1232, -1232, -1232, -1232, -1232, - -1232, 33, -1232, 33, -1232, 59, 141, 284, 59, 284, - 476, 631, -1232, 586, -1232, 88, 284, -1232, 284, -1232, - 284, -1232, 284, -1232, 728, -1232, -1232, 728, 728, -1232, - 415, -1232, -1232, -1232, -1232, 452, 145, 548, 528, -1232, - 33, 547, -1232, 33, 322, -1232, 1192, 325, -1232, 1192, - 267, -1232, 682, -1232, 439, -1232, 980, 284, 33, -1232, - -1232, 33, -1232, 1192, 479, 284, 282, 42, -1232, -1232, - -1232, -75, -1232, -75, -1232, -1232, -1232, -1232, -75, -75, - -75, -75, -75, -75, -75, -1232, -75, -1232, -75, -1232, - -75, -75, -75, -75, -1232, -75, -75, -1232, -75, -1232, - -1232, -75, -75, -75, -75, -1232, -1232, -1232, -1232, -1232, - 433, 415, -1232, 767, 728, -1232, -75, -1232, -75, -1232, - -75, -1232, -75, -1232, -1232, 284, -75, -75, -75, -1232, - 284, -75, -75, -1232, -75, -75, -1232, -75, -1232, -1232, - -75, -1232, 284, -1232, -1232, -75, -75, -75, 231, -75, - -1232, -75, -75, 284, -1232, -1232, -1232, -1232, -1232, -1232, - 284, -75, -75, 284, 284, 284, 284, 284, 284, -1232, - -1232, 284, 259, 284, 713, 713, 284, -1232, 345, -1232, - -1232, 284, 456, 284, 284, 284, -1232, -1232, 728, -1232, - -1232, -1232, 284, -1232, 212, -1232, -1232, 322, -1232, 325, - -1232, -1232, -1232, 325, -1232, -1232, 1192, -1232, 1192, 682, - -1232, -1232, -1232, 1052, -1232, 879, -1232, 476, 33, -1232, - -75, 167, 487, -1232, -1232, -75, -75, -75, -75, -1232, - -1232, -75, -75, -75, -1232, -1232, -75, -75, -1232, -75, - -1232, -1232, -1232, -1232, -1232, -1232, 231, -75, -1232, -75, - -1232, -1232, -1232, 1008, -1232, 284, -75, -75, -75, -1232, - -75, -75, -75, -75, -1232, -75, -1232, -75, -1232, -1232, - 284, -75, 284, -75, -1232, -75, 523, 231, -1232, -75, - -1232, 595, 595, 595, 595, -1232, -1232, -1232, 284, 284, - -1232, 33, -1232, 595, 1080, -1232, -1232, 315, 622, 553, - 325, -1232, -1232, -1232, -1232, 1192, 376, 284, -1232, -1232, - -1232, 775, 284, 231, 33, 1141, 284, -1232, -75, 231, - -75, 231, -75, -75, 231, -1232, -1232, -75, -75, 525, - 1080, -1232, -75, -75, -1232, -75, -1232, -1232, -75, -1232, - -75, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -75, - -1232, 231, -1232, 282, -75, -1232, -75, -75, -1232, 696, - -1232, 33, 688, -1232, 33, -1232, 974, -1232, 33, 713, - 1086, -1232, -1232, 622, 553, 553, -1232, 1192, 284, 33, - 284, 476, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, - -1232, -1232, -1232, -1232, -1232, 231, -1232, 231, -75, -1232, - -75, -1232, -75, -75, -75, -1232, -75, -75, -75, -1232, - -1232, -75, -75, 231, -75, -1232, -1232, -1232, -1232, 284, - -1232, -75, -75, -75, 33, 33, 1412, 2101, -1232, -1232, - 2559, -1232, 2630, 284, 478, -1232, -1232, 33, 553, -1232, - 713, 284, 1469, 284, 284, -75, -75, -1232, -1232, -1232, + -1232, -1232, -1232, -1232, -1232, -1232, -1232, 62, -1232, -1232, + -1232, 98, -1232, -1232, -1232, 98, -1232, -1232, -1232, -1232, + -1232, -1232, 98, 98, -1232, 98, -1232, -87, 98, -1232, + 98, -1232, 98, -1232, -1232, -1232, 98, -1232, 98, -1232, + 98, -1232, 98, -1232, 98, -1232, 98, -1232, 98, -1232, + 98, -1232, -1232, -1232, -1232, -1232, -1232, -1232, 98, -1232, + -1232, -1232, -1232, -1232, -1232, 98, -1232, 98, -1232, 98, + -1232, 98, -1232, 98, -1232, 98, -1232, -1232, -1232, -24, + -24, -24, -24, -24, -1232, 83, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -24, -24, -24, 810, + -24, -24, -24, 113, -1232, -1232, -87, -1232, -87, -1232, + -87, -87, -1232, -87, -1232, -1232, -1232, 98, -1232, -87, + -87, -1232, -87, -87, -87, -87, -87, -87, -87, -87, + -87, -1232, -87, -1232, -87, -1232, -1232, -1232, -1232, 26, + -1232, -1232, -1232, -1232, -1232, 37, 52, 179, -1232, -1232, + -1232, -1232, 360, -1232, -87, -1232, -87, -87, -87, -1232, + -87, 98, 1048, 212, 59, 59, 761, -24, 256, 138, + 156, 467, 304, 360, 203, 360, 322, 360, 217, 314, + 360, 275, 1439, -1232, -1232, -1232, 483, 69, -1232, -1232, + 69, -1232, -1232, 69, -1232, -1232, 335, 810, -1232, -1232, + -1232, -1232, -1232, -1232, -1232, 462, -1232, -1232, -1232, -1232, + 252, 265, 287, 761, -1232, -87, -1232, -87, 98, -1232, + -1232, -1232, -1232, 98, -87, 98, -87, -1232, 98, 98, + -87, -87, -1232, -1232, -1232, -1232, -87, -87, -87, -87, + -1232, -87, -1232, -87, -87, -87, -1232, -1232, -1232, -1232, + 98, 98, -1232, -1232, -87, 98, -1232, -1232, 98, -87, + -87, -1232, -87, -1232, -1232, 98, -1232, -87, -87, 98, + -1232, -1232, -87, -87, 98, -1232, -1232, -87, -87, 98, + -1232, -1232, -87, -87, 98, -1232, -1232, -87, -87, 98, + -87, 98, -1232, -1232, -87, 98, -1232, -87, -1232, -1232, + -1232, -1232, 98, -1232, -87, 98, -87, -87, -87, -87, + -87, -1232, -87, 98, 360, -1232, 416, 462, -1232, -1232, + 558, 360, 75, 360, 360, -24, -24, 78, 390, 102, + -24, -24, 413, 413, 78, 102, 413, 413, 761, 416, + 360, 466, -24, -24, 364, 360, -24, -24, 89, 477, + 413, -24, 488, -1232, 488, -24, 477, 413, -24, 477, + 413, -24, 477, 413, -24, -1232, -1232, 387, 104, -1232, + -24, 413, -24, 1439, 462, 113, -1232, -24, 335, 113, + -1232, 499, 113, -1232, 335, 461, 810, -1232, 462, -1232, + -1232, -1232, -1232, -1232, -1232, -1232, -1232, -87, -87, 98, + -1232, 98, -1232, -1232, -87, -87, 98, -87, -1232, -1232, + -1232, -87, -87, -87, -1232, -87, 98, -1232, -1232, -1232, + -1232, -1232, -1232, 98, 360, -87, -1232, -87, -87, -1232, + -87, 98, -87, -87, 360, -87, -87, -1232, -87, -87, + 761, 360, -1232, -87, -87, -87, -1232, -87, -87, 98, + -1232, -1232, -87, -87, -87, 98, 360, -87, -87, -87, + -87, -1232, 360, 360, -87, -87, 360, -87, -87, 360, + -87, -87, -1232, -1232, 159, -1232, 360, -87, -1232, 360, + -87, -87, -87, 287, 360, -1232, 360, -87, -1232, -87, + 98, -87, -1232, -87, 98, 360, -1232, 481, 486, -24, + -24, -1232, -1232, 488, -1232, 823, 479, 488, 360, 212, + 102, 517, 360, 462, 1699, -1232, 477, 112, 112, 477, + -24, 477, 102, -1232, 477, 477, 329, 360, 306, -1232, + -1232, -1232, 477, 112, 112, -1232, -1232, -24, 360, 212, + 477, 940, -1232, 477, 243, -1232, -1232, -1232, -1232, 477, + 108, -1232, 477, 192, -1232, 477, 25, -1232, -1232, 462, + -1232, -1232, 462, -1232, -1232, -1232, 477, 138, 1409, 360, + 462, -1232, -1232, 499, 1212, 360, -24, 498, 1047, 360, + -24, -1232, -87, -1232, -1232, 360, -1232, 360, -1232, -87, + -1232, 360, -87, -1232, -87, -1232, -87, 360, -1232, -1232, + -1232, 98, -1232, 287, 360, -1232, -1232, -1232, -1232, -1232, + -1232, -1232, -1232, -1232, -87, -1232, -1232, -1232, -1232, -87, + -87, -87, -1232, -87, -87, -87, -87, 360, -1232, -87, + 360, 360, 360, 360, -1232, -1232, -87, -87, 98, -1232, + -1232, -1232, -87, 98, 360, -87, -87, -87, -87, -1232, + -87, -1232, -87, 360, -87, 360, -87, -87, 360, -87, + 360, -87, 360, -87, 205, 427, -1232, 497, 360, -1232, + -1232, -1232, -1232, -87, -1232, -1232, -1232, -1232, -1232, -1232, + -1232, -1232, -1232, -1232, -1232, -87, 98, -87, 98, -1232, + -87, 98, -87, 98, -87, 98, -87, 98, -87, -1232, + 98, -87, -1232, -1232, -87, -1232, -1232, -1232, 98, -87, + -87, 98, -87, 98, -1232, -1232, -87, -1232, 98, -1232, + -1232, -87, 486, -1232, -1232, -1232, -1232, -1232, -1232, 117, + -1232, -24, 462, -1232, 398, 398, 398, 398, 78, 100, + 360, 78, 360, -1232, 499, -1232, -1232, -1232, -1232, -1232, + -1232, -24, -1232, -24, -1232, 78, 58, 360, 78, 360, + 416, 518, -1232, 398, -1232, 89, 360, -1232, 360, -1232, + 360, -1232, 360, -1232, 462, -1232, -1232, 462, 462, -1232, + 430, -1232, -1232, -1232, -1232, 466, 176, 566, 530, -1232, + -24, 547, -1232, -24, 425, -1232, 823, 281, -1232, 823, + 333, -1232, 387, -1232, 469, -1232, 1134, 360, -24, -1232, + -1232, -24, -1232, 823, 488, 360, 267, 47, -1232, -1232, + -1232, -87, -1232, -87, -1232, -1232, -1232, -1232, -87, -87, + -87, -87, -87, -87, -87, -1232, -87, -1232, -87, -1232, + -87, -87, -87, -87, -1232, -87, -87, -1232, -87, -1232, + -1232, -87, -87, -87, -87, -1232, -1232, -1232, -1232, -1232, + 465, 430, -1232, 497, 462, -1232, -87, -1232, -87, -1232, + -87, -1232, -87, -1232, -1232, 360, -87, -87, -87, -1232, + 360, -87, -87, -1232, -87, -87, -1232, -87, -1232, -1232, + -87, -1232, 360, -1232, -1232, -87, -87, -87, 98, -87, + -1232, -87, -87, 360, -1232, -1232, -1232, -1232, -1232, -1232, + 360, -87, -87, 360, 360, 360, 360, 360, 360, -1232, + -1232, 360, 103, 360, 761, 761, 360, -1232, 306, -1232, + -1232, 360, 746, 360, 360, 360, -1232, -1232, 462, -1232, + -1232, -1232, 360, -1232, 338, -1232, -1232, 425, -1232, 281, + -1232, -1232, -1232, 281, -1232, -1232, 823, -1232, 823, 387, + -1232, -1232, -1232, 1054, -1232, 810, -1232, 416, -24, -1232, + -87, 168, 499, -1232, -1232, -87, -87, -87, -87, -1232, + -1232, -87, -87, -87, -1232, -1232, -87, -87, -1232, -87, + -1232, -1232, -1232, -1232, -1232, -87, -1232, 98, -87, -1232, + -87, -1232, -1232, -1232, 681, -1232, 360, -87, -87, -87, + -1232, -87, -87, -87, -87, -1232, -87, -1232, -87, -1232, + -1232, 360, -87, 360, -87, -1232, -87, 498, 98, -1232, + -87, -1232, 623, 623, 623, 623, -1232, -1232, -1232, 360, + 360, -1232, -1232, -24, -1232, 623, 811, -1232, -1232, 199, + 535, 579, 281, -1232, -1232, -1232, -1232, 823, 372, 360, + -1232, -1232, -1232, 297, 360, 98, -24, 1415, 360, -1232, + -87, 98, -87, 98, -87, -87, 98, -1232, -1232, -87, + -87, 370, 811, -1232, -87, -87, -1232, -87, -1232, -1232, + -87, -1232, -87, -1232, -1232, -1232, -1232, -1232, -1232, -1232, + -1232, -87, -1232, 98, -1232, 267, -87, -1232, -87, -87, + -1232, 1348, -1232, -24, 1001, -1232, -24, -1232, 711, -1232, + -24, 761, 1104, -1232, -1232, 535, 579, 579, -1232, 823, + 360, -24, 360, 416, -1232, -1232, -1232, -1232, -1232, -1232, + -1232, -1232, -1232, -1232, -1232, -1232, -1232, 98, -1232, 98, + -87, -1232, -87, -1232, -87, -87, -87, -1232, -87, -87, + -87, -1232, -1232, -87, -87, 98, -87, -1232, -1232, -1232, + -1232, 360, -1232, -87, -87, -87, -24, -24, 1047, 2503, + -1232, -1232, 2115, -1232, 2716, 360, 1527, -1232, -1232, -24, + 579, -1232, 761, 360, 1340, 360, 360, -87, -87, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -1232, - -1232, -1232, -1232, -1232, -75, -75, -75, -75, -75, 284, - -1232, -75, -75, -75, -75, -75, 284, -1232, -75, -1232, - -75, -1232, -75, -1232, -75, -1232, -1232, -75, 231, -1232, - -1232, 713, 284, 55, 284, 563, 563, 723, 723, -1232, - 741, 457, 563, 593, 593, -1232, 530, -1232, 284, -1232, - -1232, 282, -75, -1232, -1232, -75, -75, -1232, -75, 231, - -1232, -1232, -75, -75, -1232, -75, 231, -75, -1232, -1232, - -75, -75, -1232, -75, 231, -75, -1232, -75, -75, -1232, - -75, -75, -1232, -75, -75, -1232, -75, -1232, -75, -75, - -1232, -75, -1232, -75, -1232, 284, 284, -1232, -1232, 92, - -1232, 728, -1232, -1232, 741, -1232, 1192, 763, -1232, -1232, - -1232, 741, -1232, 1192, 763, -1232, -1232, -1232, 763, -1232, - -1232, 530, -1232, -1232, -1232, 530, -1232, -1232, -1232, -1232, - -75, -1232, -75, 284, -75, -75, -75, -75, -75, -75, - 284, -75, -75, -75, -75, -1232, -1232, -1232, -1232, 763, - -1232, 577, -1232, -1232, 763, -1232, -1232, -1232, -1232, -1232, - -1232, -75, 284, -75, -1232, -1232, -1232 + -1232, -1232, -1232, -1232, -1232, -1232, -87, -87, -87, -87, + -87, 360, -1232, -87, -87, -87, -87, -87, 360, -1232, + -87, -1232, -87, -1232, -87, -1232, -87, -1232, -1232, -87, + 98, -1232, -1232, 761, 360, 272, 360, 679, 679, 710, + 710, -1232, 870, 412, 679, 494, 494, -1232, 336, -1232, + 360, -1232, -1232, 267, -87, -1232, -1232, -87, -87, -1232, + -87, 98, -1232, -1232, -87, -87, -1232, -87, 98, -87, + -1232, -1232, -87, -87, -1232, -87, 98, -87, -1232, -87, + -87, -1232, -87, -87, -1232, -87, -87, -1232, -87, -1232, + -87, -87, -1232, -87, -1232, -87, -1232, 360, 360, -1232, + -1232, 74, -1232, 462, -1232, -1232, 870, -1232, 823, 475, + -1232, -1232, -1232, 870, -1232, 823, 475, -1232, -1232, -1232, + 475, -1232, -1232, 336, -1232, -1232, -1232, 336, -1232, -1232, + -1232, -1232, -87, -1232, -87, 360, -87, -87, -87, -87, + -87, -87, 360, -87, -87, -87, -87, -1232, -1232, -1232, + -1232, 475, -1232, 438, -1232, -1232, 475, -1232, -1232, -1232, + -1232, -1232, -1232, -87, 360, -87, -1232, -1232, -1232 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -1092,190 +1092,190 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 0, 419, 406, 395, 405, 161, 431, 454, 397, 482, - 485, 600, 644, 679, 682, 507, 500, 356, 559, 492, - 489, 497, 495, 611, 666, 396, 421, 432, 398, 420, - 483, 487, 486, 508, 493, 490, 498, 0, 4, 5, - 2, 0, 13, 346, 347, 0, 583, 385, 383, 384, - 386, 387, 0, 0, 3, 0, 12, 416, 0, 585, - 0, 11, 0, 587, 467, 468, 0, 14, 0, 589, - 0, 15, 0, 591, 0, 16, 0, 593, 0, 17, - 0, 584, 540, 538, 539, 541, 542, 586, 0, 588, - 590, 592, 594, 19, 18, 0, 7, 0, 8, 0, + 0, 419, 406, 395, 405, 161, 431, 454, 397, 483, + 486, 601, 645, 680, 683, 508, 501, 356, 560, 493, + 490, 498, 496, 612, 667, 396, 421, 432, 398, 420, + 484, 488, 487, 509, 494, 491, 499, 0, 4, 5, + 2, 0, 13, 346, 347, 0, 584, 385, 383, 384, + 386, 387, 0, 0, 3, 0, 12, 416, 0, 586, + 0, 11, 0, 588, 468, 469, 0, 14, 0, 590, + 0, 15, 0, 592, 0, 16, 0, 594, 0, 17, + 0, 585, 541, 539, 540, 542, 543, 587, 0, 589, + 591, 593, 595, 19, 18, 0, 7, 0, 8, 0, 9, 0, 10, 0, 6, 0, 1, 73, 74, 0, 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78, 162, 0, 357, 0, 394, 0, 0, 407, 0, 411, 412, 417, 0, 422, 0, 0, 455, 0, 0, 423, 0, 423, 0, 423, 0, - 502, 560, 0, 601, 0, 612, 626, 613, 627, 614, - 615, 629, 616, 617, 618, 619, 620, 621, 622, 623, - 624, 625, 0, 609, 0, 645, 0, 0, 0, 650, + 503, 561, 0, 602, 0, 613, 627, 614, 628, 615, + 616, 630, 617, 618, 619, 620, 621, 622, 623, 624, + 625, 626, 0, 610, 0, 646, 0, 0, 0, 651, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 75, 76, 608, 0, 0, 633, 635, - 0, 657, 659, 0, 667, 669, 0, 0, 40, 20, + 0, 0, 0, 75, 76, 609, 0, 0, 634, 636, + 0, 658, 660, 0, 668, 670, 0, 0, 40, 20, 37, 38, 39, 41, 42, 0, 163, 21, 22, 26, 0, 25, 35, 0, 164, 154, 361, 0, 0, 446, 447, 369, 400, 0, 0, 0, 0, 399, 0, 0, - 0, 0, 544, 547, 545, 548, 0, 0, 0, 0, + 0, 0, 545, 548, 546, 549, 0, 0, 0, 0, 408, 0, 413, 0, 423, 0, 433, 434, 435, 436, - 0, 0, 458, 457, 451, 0, 572, 472, 0, 0, - 0, 471, 0, 568, 569, 0, 428, 190, 424, 0, - 484, 575, 0, 0, 0, 491, 578, 0, 0, 0, - 496, 581, 0, 0, 0, 514, 510, 190, 190, 0, - 190, 0, 501, 562, 0, 0, 595, 0, 596, 603, - 604, 610, 0, 647, 0, 0, 0, 0, 0, 0, - 0, 652, 0, 0, 0, 34, 27, 0, 33, 23, + 0, 0, 458, 457, 451, 0, 573, 473, 0, 0, + 0, 472, 0, 569, 570, 0, 428, 190, 424, 0, + 485, 576, 0, 0, 0, 492, 579, 0, 0, 0, + 497, 582, 0, 0, 0, 515, 511, 190, 190, 0, + 190, 0, 502, 563, 0, 0, 596, 0, 597, 604, + 605, 611, 0, 648, 0, 0, 0, 0, 0, 0, + 0, 653, 0, 0, 0, 34, 27, 0, 33, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 425, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 505, 0, 0, 503, - 0, 0, 0, 0, 0, 0, 634, 0, 0, 0, - 658, 0, 0, 668, 0, 0, 0, 649, 0, 29, + 0, 0, 0, 0, 0, 507, 506, 0, 0, 504, + 0, 0, 0, 0, 0, 0, 635, 0, 0, 0, + 659, 0, 0, 669, 0, 0, 0, 650, 0, 29, 31, 28, 36, 168, 171, 165, 166, 155, 158, 0, 160, 0, 153, 365, 0, 351, 0, 0, 348, 353, 362, 359, 0, 0, 371, 375, 0, 223, 393, 204, - 205, 206, 207, 0, 0, 0, 448, 0, 0, 521, + 205, 206, 207, 0, 0, 0, 448, 0, 0, 522, 0, 0, 0, 0, 0, 0, 0, 409, 402, 190, - 0, 0, 418, 0, 0, 0, 463, 190, 451, 0, + 0, 0, 418, 0, 0, 0, 464, 190, 451, 0, 450, 459, 190, 0, 0, 0, 0, 0, 0, 190, 190, 429, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 50, 511, 48, 512, 0, 190, 515, 0, - 0, 0, 597, 605, 0, 648, 0, 0, 524, 661, - 0, 0, 693, 80, 0, 0, 32, 0, 0, 0, + 0, 0, 50, 512, 48, 513, 0, 190, 516, 0, + 0, 0, 598, 606, 0, 649, 0, 0, 525, 662, + 0, 0, 694, 80, 0, 0, 32, 0, 0, 0, 0, 350, 355, 0, 354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 390, 0, 0, 0, 0, 0, 415, 24, 410, 0, 0, 0, 452, 453, 0, 0, 0, - 0, 0, 469, 0, 0, 191, 426, 427, 488, 0, - 0, 494, 0, 0, 499, 0, 0, 44, 58, 0, - 45, 49, 0, 509, 504, 513, 0, 0, 0, 0, - 606, 602, 646, 0, 0, 0, 0, 0, 0, 0, - 0, 651, 156, 159, 169, 0, 172, 0, 367, 351, + 0, 0, 470, 0, 0, 191, 426, 427, 489, 0, + 0, 495, 0, 0, 500, 0, 0, 44, 58, 0, + 45, 49, 0, 510, 505, 514, 0, 0, 0, 0, + 607, 603, 647, 0, 0, 0, 0, 0, 0, 0, + 0, 652, 156, 159, 169, 0, 172, 0, 367, 351, 366, 0, 351, 363, 359, 358, 0, 0, 380, 381, 376, 0, 368, 372, 0, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 234, 235, 236, 0, - 0, 0, 392, 0, 552, 0, 552, 0, 522, 0, + 0, 0, 392, 0, 553, 0, 553, 0, 523, 0, 0, 0, 0, 0, 199, 198, 190, 190, 0, 401, - 197, 196, 190, 0, 0, 0, 438, 0, 438, 464, + 197, 196, 190, 0, 0, 0, 438, 0, 438, 465, 0, 456, 0, 0, 0, 0, 0, 190, 0, 190, - 0, 190, 0, 190, 48, 0, 59, 0, 0, 563, - 564, 565, 566, 0, 174, 100, 133, 136, 144, 148, - 98, 599, 82, 88, 89, 93, 0, 85, 0, 92, + 0, 190, 0, 190, 48, 0, 59, 0, 0, 564, + 565, 566, 567, 0, 174, 100, 133, 136, 144, 148, + 98, 600, 82, 88, 89, 93, 0, 85, 0, 92, 85, 0, 85, 0, 85, 0, 85, 0, 85, 84, - 0, 597, 582, 607, 637, 536, 656, 665, 0, 661, - 661, 0, 80, 0, 660, 525, 378, 680, 0, 81, - 681, 0, 0, 167, 170, 352, 364, 349, 360, 0, + 0, 598, 583, 608, 638, 537, 657, 666, 0, 662, + 662, 0, 80, 0, 661, 526, 378, 681, 0, 81, + 682, 0, 0, 167, 170, 352, 364, 349, 360, 0, 389, 0, 373, 370, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 543, 0, 546, 391, 549, 550, 404, + 0, 0, 0, 544, 0, 547, 391, 550, 551, 404, 403, 0, 414, 0, 430, 0, 0, 0, 0, 0, - 27, 0, 470, 0, 567, 0, 0, 573, 0, 576, - 0, 579, 0, 46, 0, 43, 68, 0, 0, 53, - 71, 55, 66, 67, 558, 0, 0, 0, 0, 91, + 27, 0, 471, 0, 568, 0, 0, 574, 0, 577, + 0, 580, 0, 46, 0, 43, 68, 0, 0, 53, + 71, 55, 66, 67, 559, 0, 0, 0, 0, 91, 0, 0, 117, 0, 0, 118, 0, 0, 119, 0, - 0, 120, 0, 83, 0, 598, 0, 0, 0, 662, - 663, 0, 664, 0, 0, 0, 0, 0, 683, 685, + 0, 120, 0, 83, 0, 599, 0, 0, 0, 663, + 664, 0, 665, 0, 0, 0, 0, 0, 684, 686, 157, 0, 382, 378, 374, 237, 238, 239, 190, 190, - 190, 190, 552, 190, 190, 551, 552, 556, 517, 202, + 190, 190, 553, 190, 190, 552, 553, 557, 518, 202, 0, 0, 438, 190, 449, 190, 190, 437, 438, 444, - 465, 461, 0, 190, 190, 570, 574, 577, 580, 52, + 466, 461, 0, 190, 190, 571, 575, 578, 581, 52, 48, 71, 60, 0, 0, 70, 190, 96, 85, 94, 0, 90, 85, 87, 101, 0, 85, 85, 85, 134, 0, 85, 85, 137, 0, 85, 145, 0, 149, 150, - 0, 79, 0, 654, 643, 637, 637, 80, 0, 80, - 636, 0, 0, 0, 379, 523, 673, 674, 671, 672, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, - 553, 0, 0, 0, 0, 0, 0, 442, 0, 439, + 0, 79, 0, 655, 644, 638, 638, 80, 0, 80, + 637, 0, 0, 0, 379, 524, 674, 675, 672, 673, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, + 554, 0, 0, 0, 0, 0, 0, 442, 0, 439, 441, 0, 0, 0, 0, 0, 47, 69, 0, 54, 57, 72, 0, 95, 0, 86, 99, 0, 121, 0, 122, 123, 132, 0, 124, 125, 0, 126, 0, 0, - 173, 638, 639, 0, 640, 0, 642, 27, 0, 655, - 0, 0, 0, 684, 377, 0, 0, 0, 0, 555, - 557, 190, 517, 517, 516, 203, 190, 190, 443, 190, - 445, 188, 186, 185, 187, 466, 0, 190, 460, 0, - 571, 64, 56, 0, 561, 0, 102, 103, 104, 105, - 85, 85, 85, 85, 138, 0, 146, 142, 151, 152, - 0, 80, 0, 0, 537, 378, 0, 0, 688, 689, - 687, 0, 0, 0, 0, 520, 518, 519, 0, 0, - 440, 0, 462, 0, 0, 63, 97, 0, 0, 0, - 0, 127, 128, 129, 130, 0, 0, 0, 147, 641, - 653, 0, 0, 0, 0, 0, 0, 243, 214, 0, - 209, 0, 80, 220, 0, 192, 189, 0, 474, 65, - 0, 61, 106, 107, 108, 109, 110, 111, 85, 139, - 0, 143, 141, 534, 529, 530, 531, 532, 533, 378, - 527, 0, 535, 0, 0, 692, 689, 689, 686, 0, - 213, 0, 0, 208, 0, 218, 0, 219, 0, 0, - 0, 473, 62, 0, 0, 0, 131, 0, 0, 0, - 0, 27, 691, 690, 183, 180, 179, 182, 200, 181, - 201, 217, 345, 175, 177, 0, 176, 0, 215, 244, - 0, 212, 209, 80, 0, 222, 220, 0, 190, 480, - 478, 80, 80, 0, 112, 113, 114, 115, 140, 0, - 526, 194, 675, 190, 0, 0, 0, 0, 211, 210, - 0, 221, 0, 0, 0, 475, 477, 0, 0, 135, - 0, 0, 0, 0, 0, 0, 194, 216, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 297, 246, 248, 250, 252, 0, - 245, 270, 277, 279, 281, 283, 0, 276, 293, 184, - 80, 481, 378, 116, 190, 528, 678, 80, 0, 670, - 694, 0, 0, 0, 0, 0, 0, 0, 0, 240, - 0, 0, 0, 0, 0, 242, 0, 476, 0, 195, - 677, 0, 190, 193, 344, 190, 190, 298, 190, 0, - 241, 340, 190, 190, 247, 190, 0, 190, 249, 342, - 190, 190, 251, 190, 0, 190, 253, 190, 190, 271, - 190, 190, 278, 190, 190, 280, 190, 282, 190, 190, - 284, 190, 294, 190, 479, 0, 0, 299, 302, 0, - 300, 0, 254, 261, 0, 258, 0, 0, 260, 262, - 269, 0, 266, 0, 0, 268, 272, 275, 0, 273, - 285, 0, 287, 288, 289, 0, 291, 292, 295, 296, - 675, 178, 190, 0, 190, 190, 0, 190, 190, 190, - 0, 190, 190, 190, 190, 676, 301, 343, 257, 0, - 255, 0, 259, 265, 0, 263, 341, 267, 274, 286, - 290, 190, 0, 190, 256, 339, 264 + 173, 639, 640, 0, 641, 0, 643, 27, 0, 656, + 0, 0, 0, 685, 377, 0, 0, 0, 0, 556, + 558, 190, 518, 518, 517, 203, 190, 190, 443, 190, + 445, 188, 186, 185, 187, 190, 467, 0, 190, 460, + 0, 572, 64, 56, 0, 562, 0, 102, 103, 104, + 105, 85, 85, 85, 85, 138, 0, 146, 142, 151, + 152, 0, 80, 0, 0, 538, 378, 0, 0, 689, + 690, 688, 0, 0, 0, 0, 521, 519, 520, 0, + 0, 440, 462, 0, 463, 0, 0, 63, 97, 0, + 0, 0, 0, 127, 128, 129, 130, 0, 0, 0, + 147, 642, 654, 0, 0, 0, 0, 0, 0, 243, + 214, 0, 209, 0, 80, 220, 0, 192, 189, 0, + 475, 65, 0, 61, 106, 107, 108, 109, 110, 111, + 85, 139, 0, 143, 141, 535, 530, 531, 532, 533, + 534, 378, 528, 0, 536, 0, 0, 693, 690, 690, + 687, 0, 213, 0, 0, 208, 0, 218, 0, 219, + 0, 0, 0, 474, 62, 0, 0, 0, 131, 0, + 0, 0, 0, 27, 692, 691, 183, 180, 179, 182, + 200, 181, 201, 217, 345, 175, 177, 0, 176, 0, + 215, 244, 0, 212, 209, 80, 0, 222, 220, 0, + 190, 481, 479, 80, 80, 0, 112, 113, 114, 115, + 140, 0, 527, 194, 676, 190, 0, 0, 0, 0, + 211, 210, 0, 221, 0, 0, 0, 476, 478, 0, + 0, 135, 0, 0, 0, 0, 0, 0, 194, 216, + 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 297, 246, 248, 250, + 252, 0, 245, 270, 277, 279, 281, 283, 0, 276, + 293, 184, 80, 482, 378, 116, 190, 529, 679, 80, + 0, 671, 695, 0, 0, 0, 0, 0, 0, 0, + 0, 240, 0, 0, 0, 0, 0, 242, 0, 477, + 0, 195, 678, 0, 190, 193, 344, 190, 190, 298, + 190, 0, 241, 340, 190, 190, 247, 190, 0, 190, + 249, 342, 190, 190, 251, 190, 0, 190, 253, 190, + 190, 271, 190, 190, 278, 190, 190, 280, 190, 282, + 190, 190, 284, 190, 294, 190, 480, 0, 0, 299, + 302, 0, 300, 0, 254, 261, 0, 258, 0, 0, + 260, 262, 269, 0, 266, 0, 0, 268, 272, 275, + 0, 273, 285, 0, 287, 288, 289, 0, 291, 292, + 295, 296, 676, 178, 190, 0, 190, 190, 0, 190, + 190, 190, 0, 190, 190, 190, 190, 677, 301, 343, + 257, 0, 255, 0, 259, 265, 0, 263, 341, 267, + 274, 286, 290, 190, 0, 190, 256, 339, 264 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -1232, -1232, -1232, -222, -226, -189, -1232, 247, -195, 289, - -1232, -1232, -1232, -1232, -1232, -1232, -196, -342, -662, -56, - -783, -637, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -569, - -252, -1232, -1232, -1232, -849, -1232, -1232, -247, 1222, 1220, - -57, 1263, -1232, -708, -589, -607, -1232, -1232, -169, -1232, - -1232, -168, -1232, -1232, -1232, -167, -321, -1232, -1232, -791, - -1232, -1232, -1232, -1232, -1232, -788, -1232, -1232, -1232, -1232, - -655, -1232, -1232, -1232, 108, -1232, -1232, -1232, -1232, -1232, - 130, -1232, -1232, -503, -1232, -1232, -489, -1232, -1232, -1222, - -1232, -1232, -1232, -1232, -552, 1709, -427, -1231, -565, -1232, - -1232, -1232, -746, -909, -36, -1232, -516, -1232, -1232, -1232, - -1232, -518, -334, 99, -1232, -1232, -315, -1007, -385, -466, - -1008, -980, -1232, -942, -614, -1232, -1232, -1232, -1232, -600, - -1232, -1232, -1232, -1232, -606, -611, -1232, -583, -1232, -776, - -1232, -761, -1232, 711, -412, -190, 514, -417, 29, -245, - -310, 107, -1232, -1232, -1232, 193, -1232, -110, -1232, -77, - -1232, -1232, -1232, -1232, -1232, -1232, -835, -1232, -1232, -1232, - -1232, 635, 637, 638, 640, -283, 531, -1232, -1232, -91, - 41, -1232, -1232, -1232, -1232, -1232, -107, -1232, -1232, -1232, - -1232, 10, -1232, 502, -104, -1232, -1232, -1232, 642, -1232, - -1232, -1232, -620, -1232, -1232, -1232, 580, 584, 510, -174, - 2, 312, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -367, - -798, -966, -1232, -1232, 662, 671, -1232, 232, -1232, -411, - -1232, -1232, -1232, -182, -1232, 675, -1232, -178, -1232, 677, - -1232, -186, -1232, 679, -1232, -187, -1232, -1232, 414, -1232, - -1232, -1232, -1232, -1232, 969, -289, -1232, -1232, -379, -1232, - -1232, -785, -1232, -1232, -1232, -775, -1232, -1232, 687, -1232, - -1232, 625, -1232, 628, -1232, -1232, 230, -618, 234, 241, - 242, 699, -1232, -1232, -1232, -1232, -1232, 717, -1232, -1232, - -1232, -1232, 718, -1232, -1232, 719, -1232, -1232, 727, -1232, - -1232, 738, -188, -344, 109, -1232, -1232, -1232, -1232, -1232, - -1232, -1232, -1232, -1232, -1232, 842, -1232, 539, -179, -1232, - -119, -209, -1232, -1232, -86, -1232, 115, -1232, -1232, -1232, - -808, -1232, -1232, -1232, 549, 16, 887, -1232, -1232, 551, - -1083, -502, -1232, -988, 892, -1232, -1232, -1232, -49, -1232, - -375, -1232, -200 + -1232, -1232, -1232, -221, -226, -189, -1232, 266, -194, 293, + -1232, -1232, -1232, -1232, -1232, -1232, -196, -341, -654, -53, + -782, -642, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -563, + -250, -1232, -1232, -1232, -847, -1232, -1232, -237, 1251, 1249, + -57, 1948, -1232, -665, -567, -574, -1232, -1232, -157, -1232, + -1232, -156, -1232, -1232, -1232, -154, -306, -1232, -1232, -791, + -1232, -1232, -1232, -1232, -1232, -783, -1232, -1232, -1232, -1232, + -657, -1232, -1232, -1232, 110, -1232, -1232, -1232, -1232, -1232, + 143, -1232, -1232, -505, -1232, -1232, -473, -1232, -1232, -1231, + -1232, -1232, -1232, -1232, -557, 1794, -410, -1201, -544, -1232, + -1232, -1232, -748, -930, -37, -1232, -497, -1232, -1232, -1232, + -1232, -500, -334, 124, -1232, -1232, -290, -1018, -364, -446, + -1004, -578, -1232, -852, -597, -1232, -1232, -1232, -1232, -602, + -1232, -1232, -1232, -1232, -729, -588, -1232, -701, -1232, -556, + -1232, -724, -1232, 716, -416, -148, 519, -419, 36, -102, + -326, 101, -1232, -1232, -1232, 188, -1232, -117, -1232, -67, + -1232, -1232, -1232, -1232, -1232, -1232, -836, -1232, -1232, -1232, + -1232, 600, 604, 605, 607, -280, 663, -1232, -1232, -91, + 42, -1232, -1232, -1232, -1232, -1232, -107, -1232, -1232, -1232, + -1232, 10, -1232, 506, -105, -1232, -1232, -1232, 609, -1232, + -1232, -1232, -644, -1232, -1232, -1232, 546, 552, 527, -204, + 4, 277, -1232, -1232, -1232, -1232, -1232, -1232, -1232, -367, + -794, -938, -1232, -1232, 627, 633, -1232, 197, -1232, -448, + -1232, -1232, -1232, -192, -1232, 640, -1232, -185, -1232, 641, + -1232, -186, -1232, 644, -1232, -187, -1232, -1232, 378, -1232, + -1232, -1232, -1232, -1232, 540, -406, -1232, -1232, -384, -1232, + -1232, -781, -1232, -1232, -1232, -796, -1232, -1232, 648, -1232, + -1232, 588, -1232, 590, -1232, -1232, 190, -624, 193, 194, + 195, 660, -1232, -1232, -1232, -1232, -1232, 671, -1232, -1232, + -1232, -1232, 672, -1232, -1232, 673, -1232, -1232, 674, -1232, + -1232, 675, -179, -349, 76, -1232, -1232, -1232, -1232, -1232, + -1232, -1232, -1232, -1232, -1232, 806, -1232, 478, -253, -1232, + -119, -209, -1232, -1232, -109, -1232, 81, -1232, -1232, -1232, + -814, -1232, -1232, -1232, 489, -64, 816, -1232, -1232, 484, + -1087, -552, -1232, -1001, 842, -1232, -1232, -1232, -96, -1232, + -458, -1232, -249 }; /* YYDEFGOTO[NTERM-NUM]. */ @@ -1284,18 +1284,18 @@ static const yytype_int16 yydefgoto[] = -1, 37, 38, 39, 235, 620, 237, 880, 238, 470, 239, 240, 419, 420, 241, 348, 242, 243, 894, 589, 503, 590, 504, 695, 890, 591, 809, 969, 592, 810, - 893, 1032, 1033, 1110, 811, 812, 813, 895, 109, 215, + 893, 1033, 1034, 1112, 811, 812, 813, 895, 109, 215, 382, 456, 922, 609, 749, 819, 712, 713, 714, 715, - 716, 717, 718, 905, 1035, 719, 720, 721, 910, 722, - 723, 914, 1045, 1120, 1199, 724, 1087, 725, 917, 1047, - 726, 727, 920, 1050, 489, 351, 41, 136, 245, 427, - 428, 429, 615, 430, 431, 617, 729, 730, 1172, 1173, - 1174, 1175, 1025, 1026, 874, 383, 667, 1176, 1221, 673, - 668, 1177, 870, 1016, 448, 449, 1143, 450, 1140, 451, - 452, 1147, 453, 649, 650, 651, 858, 1100, 1098, 1103, - 1101, 1180, 1269, 1324, 1332, 1270, 1339, 1276, 1342, 1347, - 1277, 1352, 1294, 1317, 1264, 1325, 1326, 1333, 1334, 1327, - 1319, 1178, 42, 252, 353, 534, 44, 354, 253, 138, + 716, 717, 718, 905, 1036, 719, 720, 721, 910, 722, + 723, 914, 1046, 1122, 1201, 724, 1089, 725, 917, 1048, + 726, 727, 920, 1051, 489, 351, 41, 136, 245, 427, + 428, 429, 615, 430, 431, 617, 729, 730, 1174, 1175, + 1176, 1177, 1026, 1027, 874, 383, 667, 1178, 1223, 673, + 668, 1179, 870, 1016, 448, 449, 1145, 450, 1142, 451, + 452, 1149, 453, 649, 650, 651, 858, 1102, 1100, 1105, + 1103, 1182, 1271, 1326, 1334, 1272, 1341, 1278, 1344, 1349, + 1279, 1354, 1296, 1319, 1266, 1327, 1328, 1335, 1336, 1329, + 1321, 1180, 42, 252, 353, 534, 44, 354, 253, 138, 247, 538, 248, 441, 624, 435, 436, 621, 619, 254, 255, 445, 446, 634, 542, 630, 845, 631, 853, 46, 47, 48, 49, 50, 51, 454, 140, 52, 53, 256, @@ -1303,11 +1303,11 @@ static const yytype_int16 yydefgoto[] = 56, 257, 58, 149, 203, 298, 299, 492, 59, 60, 275, 276, 787, 277, 278, 279, 258, 259, 457, 876, 936, 375, 62, 152, 284, 285, 482, 478, 963, 738, - 680, 881, 1027, 63, 64, 65, 290, 486, 1151, 1192, - 1193, 1282, 66, 67, 68, 69, 70, 71, 72, 73, + 680, 881, 1028, 63, 64, 65, 290, 486, 1153, 1194, + 1195, 1284, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 210, 80, 318, 319, 506, 320, 321, 509, 937, 953, 461, 659, 941, 520, - 746, 739, 1129, 1130, 1131, 740, 741, 1055, 81, 82, + 746, 739, 1131, 1132, 1133, 740, 741, 1056, 81, 82, 83, 260, 84, 261, 85, 86, 262, 770, 263, 264, 265, 87, 88, 162, 324, 325, 703, 89, 292, 293, 294, 295, 90, 303, 304, 91, 308, 309, 92, 313, @@ -1315,8 +1315,8 @@ static const yytype_int16 yydefgoto[] = 96, 182, 97, 183, 184, 938, 218, 219, 837, 99, 186, 334, 335, 516, 336, 191, 342, 343, 927, 928, 742, 743, 100, 221, 222, 605, 939, 102, 224, 225, - 940, 1223, 103, 748, 328, 105, 523, 848, 849, 1059, - 1096, 524, 1060 + 940, 1225, 103, 748, 328, 105, 523, 848, 849, 1060, + 1098, 524, 1061 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -1324,638 +1324,654 @@ static const yytype_int16 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 115, 270, 61, 236, 421, 344, 672, 479, 146, 711, - 57, 337, 187, 188, 339, 737, 347, 532, 943, 291, - 307, 312, 531, 697, 326, 613, 302, 421, 929, 45, - 906, 1053, 519, 907, 842, 808, 911, 871, 772, 345, - 931, 54, 434, 932, 970, 485, 1017, 190, 349, 918, - 1160, 925, 205, 1099, 207, 1099, 1104, 803, 789, 512, - 1, 926, 1316, 1, 19, 21, 1108, 518, 1093, 1168, - 1, 15, 5, 1323, 1323, 1331, 1331, 1314, 1338, 192, - 1323, 193, 464, 194, 195, 249, 196, 144, 114, 34, - 36, 5, 198, 199, 250, 200, 201, 202, 204, 202, - 206, 202, 208, 209, 267, 211, 1168, 212, 40, 5, - 33, 442, 251, 822, 106, 825, 17, 828, 266, 831, - 333, 833, 251, 10, 289, 316, 17, 216, 1392, 217, - 220, 223, 483, 226, 338, 1182, 26, 340, 1104, 26, - 29, 189, 1394, 29, 1170, 1397, 26, 144, 670, 1398, - 29, 422, 1401, 671, 15, 664, 1402, 189, 5, 665, - 282, 425, 5, 145, 1184, 5, 908, 1012, 1187, 912, - 370, 704, 915, 467, 31, 32, 476, 1013, 311, 333, - 134, 1170, 283, 1037, 1075, 1051, 1038, 1421, 350, 1040, - 352, -628, 1423, 33, 525, 1203, 484, 357, 249, 359, - 710, 502, 144, 362, 363, 735, 1048, 250, 513, 364, - 365, 366, 367, 5, 368, 326, 369, 202, 371, 994, - 1092, 996, 526, 145, 734, 1111, 1058, 374, 1355, 626, - 288, 968, 378, 379, 1288, 380, 485, 246, 891, 274, - 1188, 384, 706, 707, 948, 386, 387, 924, 951, 850, - 389, 390, 956, 966, 731, 392, 393, 627, 961, 682, - -630, 1152, 2, 398, 144, 708, 709, 401, 476, 661, - 403, 587, 4, 588, 447, 560, 5, 405, 145, 408, - 409, 411, 412, 414, 5, 415, 1112, 600, 2, 1113, - 1115, 973, 2, 704, 1158, 975, 1134, 735, 4, 978, - 980, 981, 4, 5, 984, 985, 7, 5, 987, 19, - 297, 1284, 10, 296, -51, 301, 588, 317, 246, 1039, - 1136, 12, 1041, 338, 1042, 1107, 340, 899, 1043, 903, - 459, -631, 903, 251, 34, 903, 315, 316, 903, 5, - 145, 903, 5, 1089, 246, 433, 707, 633, 704, -632, - 493, 704, 670, 496, 1328, 807, 499, 671, 476, 24, - 1345, 323, 5, 31, 32, 1194, 5, 443, 708, 709, - 527, 528, 341, 473, 463, 708, 709, 352, 533, 709, - 536, 1183, 1312, 664, 537, 539, 540, 665, 541, 1191, - 107, 108, 687, 694, 1145, 868, 696, 691, 546, 693, - 547, 548, 689, 549, 733, 551, 552, 762, 554, 555, - 326, 556, 558, 1201, 1287, 346, 562, 563, 564, 423, - 424, 374, 1114, 1116, 1117, 1118, 569, 570, -30, 755, - 573, 574, 757, 1081, 1082, 1083, 1084, 579, 580, 531, - 582, 583, 229, 585, 586, 213, 214, 1308, 421, 851, - 859, 860, 861, 596, 597, 598, 654, 656, 1225, 1226, - 603, 444, 604, 1021, 607, 532, 608, 1022, 1023, 1024, - 653, 655, 676, 678, 5, 1209, 7, 1321, 883, 1314, - 21, 882, 477, 1215, 1216, 306, 675, 677, 903, 459, - 903, 751, 490, 447, 903, 5, 5, 686, 1195, 1196, - 1197, 696, 329, 330, 704, 36, 1135, 705, 706, 707, - 652, 1156, 518, 657, 1189, 660, 522, 1318, 662, 663, - 423, 1335, 1335, 517, 1340, 1344, 674, 1349, 1349, 521, - 1353, 708, 709, 710, 134, 228, 229, 685, 230, 231, - 232, 233, 234, 688, 424, 5, 690, 5, 433, 692, - 1171, 807, 1314, 1181, 704, 752, 587, 1185, 706, 707, - 698, 1190, 533, 1283, 5, 533, 854, 537, 747, 759, - 1164, 805, 1307, 704, 1165, 1166, 1167, 705, 707, 1310, - 5, 708, 709, 1321, 670, 1314, 921, 764, 1395, 671, - 588, 903, 765, 766, 767, 1399, 768, 769, 771, 769, - 708, 709, 774, 1097, 1271, 1403, 1278, 709, 889, 1404, - 5, 696, 892, 884, 1329, 1314, 469, 1227, 785, 786, - 788, 786, 154, 790, 156, 791, 158, 793, 160, 795, - 233, 234, 1169, 1286, 1057, 418, 502, 913, 942, 804, - 916, 618, 971, 141, 967, 623, 815, 897, 150, 900, - 153, 901, 155, 1036, 157, 421, 159, 612, 816, 1121, - 818, 1292, 864, 821, 666, 824, 1208, 827, 1211, 830, - 684, 830, 628, 629, 598, 708, 709, 836, 1102, 875, - 1186, -59, 604, 604, 1336, 608, -59, -59, -59, 844, - 1343, 807, 246, 433, 847, 1164, 1097, 696, 892, 1165, - 1166, 1167, 1168, 1164, 1350, 5, 728, 1165, 1166, 1167, - 1168, 43, 728, 5, 704, 287, 728, 705, 706, 707, - 1348, 1348, 704, 1066, 1067, 705, 706, 707, 1057, 622, - 1164, 758, 807, 933, 1165, 1166, 1167, 855, 856, 857, - 5, 708, 709, 710, 1329, 1314, 991, 992, 1164, 708, - 709, 710, 1165, 1166, 1167, 839, 840, 1169, 5, 1015, - 1015, 1162, 1163, 1314, 165, 1169, 166, 167, 807, 168, - 1164, 169, 1031, 1052, 1165, 1166, 1167, 1170, 862, 280, - 5, 866, 1123, 281, 1019, 1170, 1124, 1125, 1126, 1127, - 566, 170, 1169, 502, 759, 872, 844, 1044, 878, 1046, - 171, 10, 683, 1280, 172, 769, 173, 1074, 174, 769, - 1169, 952, 507, 954, 955, 786, 175, 896, 958, 421, - 268, 786, 251, 269, 962, 791, 17, 699, 176, 134, - 228, 700, 1169, 230, 231, 232, 286, 696, 701, 702, - 835, 830, 98, 974, 1128, 830, 177, 178, 179, 977, - 979, 830, 31, 32, 983, 830, 180, 986, 830, 1422, - 988, 228, 229, 989, 230, 231, 232, 181, 836, 836, - 993, 458, 608, 406, 997, 998, 228, 863, 1109, 230, - 231, 232, 474, 475, 1001, 1002, 410, 101, 1405, 3, - 413, 488, 104, 1003, 873, 1137, 1119, 6, 495, 0, - 0, 498, 0, 0, 501, 0, 8, 0, 0, 0, - 0, 0, 511, 9, 696, 228, 11, 0, 230, 231, - 232, 233, 234, 805, 898, 806, 902, 0, 0, 902, - 0, 16, 902, 0, 0, 902, 0, 0, 902, 0, - 0, 0, 18, 1056, 728, 20, 0, 22, 1061, 1062, - 1063, 1064, 934, 0, 1015, 952, 952, 0, 25, 0, - 27, 0, 28, 0, 30, 0, 0, 0, 1198, 0, - 35, 0, 1073, 0, 0, 0, 0, 0, 0, 1077, - 1078, 1079, 1097, 1080, 830, 830, 830, 0, 1085, 476, - 1086, 5, 0, 0, 608, 0, 1091, 5, 844, 0, - 704, 0, 1095, 705, 706, 707, 704, 0, 0, 705, - 706, 707, 0, 0, 0, 0, 0, 0, 735, 0, - 0, 0, 923, 736, 0, 1015, 0, 708, 709, 710, - 0, 0, 0, 708, 709, 710, 0, 0, 0, 0, - 0, 1139, 0, 1142, 0, 608, 1146, 0, 0, 0, - 1149, 1150, 0, 0, 0, 1153, 1154, 0, 1155, 0, - 1011, 830, 0, 1157, 0, 0, 0, 0, 0, 5, - 0, 0, 844, 0, 0, 0, 0, 1161, 704, 1095, - 1095, 705, 706, 707, 0, 902, 0, 902, 0, 0, - 0, 902, 0, 1164, 0, 736, 1015, 1165, 1166, 1167, - 1168, 728, 0, 5, 0, 708, 709, 710, 0, 0, - 0, 0, 704, 0, 0, 705, 706, 707, 0, 0, - 0, 1206, 1189, 1207, 0, 1142, 608, 1210, 0, 1146, - 1212, 0, 0, 0, 1214, 608, 0, 1218, 0, 708, - 709, 710, 0, 0, 1220, 1222, 0, 0, 0, 0, - 476, 0, 0, 0, 0, 1169, 228, 229, 5, 230, - 231, 232, 233, 234, 0, 1393, 806, 704, 1291, 1220, - 705, 706, 707, 0, 0, 1170, 0, 1396, 0, 735, - 0, 0, 0, 0, 1400, 134, 228, 229, 902, 230, - 231, 232, 233, 234, 708, 709, 710, 0, 0, 0, - 0, 0, 0, 728, 0, 0, 0, 1293, 1295, 1296, - 1297, 1298, 0, 0, 1300, 1301, 1302, 1303, 1304, 476, - 0, 1306, 0, 608, 0, 844, 0, 5, 228, 0, - 608, 230, 231, 232, 233, 234, 704, 0, 806, 705, - 706, 707, 0, 0, 0, 0, 0, 728, 735, 0, - 728, 0, 0, 736, 728, 0, 0, 0, 728, 0, - 0, 1359, 0, 708, 709, 710, 0, 110, 1364, 0, - 1367, 0, 0, 0, 111, 112, 1371, 113, 1374, 0, - 116, 0, 117, 1378, 118, 0, 1381, 0, 119, 0, - 120, 1385, 121, 0, 122, 0, 123, 0, 124, 0, - 125, 0, 126, 0, 0, 0, 0, 0, 0, 0, - 127, 0, 0, 0, 728, 0, 0, 128, 0, 129, - 0, 130, 728, 131, 0, 132, 0, 133, 0, 0, - 728, 460, 462, 1222, 0, 465, 466, 0, 1409, 1411, - 228, 229, 1414, 230, 231, 232, 233, 234, 0, 487, - 0, 0, 0, 0, 0, 0, 494, 0, 0, 497, - 0, 0, 500, 0, 0, 0, 0, 0, 0, 197, - 510, 0, 135, 137, 139, 139, 142, 0, 0, 148, - 139, 151, 139, 148, 139, 148, 139, 148, 139, 148, - 161, 163, 0, 185, 185, 185, 0, 0, 0, 0, - 0, 1315, 0, 1322, 1322, 1330, 1330, 0, 1337, 1341, - 1322, 1346, 1346, 227, 1351, 0, 3, 0, 0, 0, - 0, 0, 0, 300, 6, 305, 0, 310, 0, 5, - 322, 0, 0, 8, 0, 0, 0, 0, 704, 0, - 9, 705, 706, 707, 0, 0, 0, 0, 0, 0, - 0, 0, 14, 0, 0, 244, 0, 0, 16, 0, - 272, 0, 0, 0, 0, 708, 709, 710, 0, 18, - 355, 0, 20, 0, 22, 356, 0, 358, 0, 0, - 360, 361, 0, 0, 0, 25, 5, 27, 0, 28, - 0, 30, 0, 0, 0, 704, 0, 35, 705, 706, - 707, 0, 372, 373, 0, 0, 0, 376, 0, 0, - 377, 0, 736, 0, 747, 0, 0, 381, 0, 0, - 0, 385, 708, 709, 710, 0, 388, 0, 0, 0, - 0, 391, 0, 0, 0, 0, 394, 0, 0, 0, - 0, 397, 0, 400, 0, 0, 0, 402, 0, 0, - 0, 0, 0, 0, 404, 0, 0, 407, 0, 0, - 0, 0, 0, 0, 417, 416, 0, 0, 0, 0, - 0, 432, 0, 438, 439, 635, 636, 637, 638, 639, - 640, 641, 642, 643, 644, 645, 646, 647, 648, 0, - 472, 0, 0, 0, 0, 480, 635, 636, 637, 638, - 639, 640, 641, 642, 643, 0, 0, 0, 0, 0, - 0, 0, 0, 426, 0, 0, 0, 0, 440, 137, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 481, - 137, 0, 0, 0, 0, 0, 0, 0, 491, 0, - 0, 529, 0, 530, 0, 0, 0, 0, 535, 0, - 505, 0, 0, 508, 0, 0, 0, 0, 543, 0, - 515, 0, 0, 0, 545, 544, 0, 0, 0, 3, - 0, 0, 0, 550, 553, 0, 5, 6, 0, 0, - 0, 561, 0, 0, 0, 704, 8, 0, 705, 706, - 707, 567, 0, 9, 0, 0, 572, 571, 0, 0, - 0, 0, 577, 578, 0, 14, 581, 0, 0, 584, - 0, 16, 708, 709, 710, 0, 593, 0, 0, 595, - 0, 0, 18, 0, 601, 20, 602, 22, 0, 0, - 0, 0, 606, 0, 0, 611, 610, 0, 25, 0, - 27, 0, 28, 0, 30, 0, 0, 0, 625, 0, - 35, 0, 632, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 669, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 681, 0, - 0, 0, 614, 616, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 658, 0, 0, 0, 0, 0, 732, - 0, 0, 0, 0, 0, 744, 0, 0, 0, 750, - 679, 0, 0, 0, 0, 753, 0, 754, 0, 0, - 0, 756, 0, 0, 0, 0, 0, 760, 0, 0, - 0, 0, 0, 761, 763, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 745, - 0, 0, 0, 185, 0, 0, 0, 773, 0, 0, - 775, 776, 777, 778, 0, 0, 0, 0, 0, 0, - 781, 0, 0, 0, 784, 783, 0, 0, 0, 0, - 0, 0, 0, 792, 0, 794, 0, 0, 797, 0, - 799, 0, 801, 0, 0, 0, 0, 0, 814, 0, + 115, 672, 270, 236, 61, 421, 344, 479, 146, 291, + 57, 337, 187, 188, 339, 532, 347, 943, 531, 302, + 307, 312, 929, 613, 190, 1017, 434, 519, 421, 697, + 906, 711, 772, 326, 789, 871, 45, 737, 907, 345, + 926, 911, 54, 808, 931, 485, 970, 932, 1162, 349, + 918, 205, 803, 207, 512, 925, 1095, 1110, 1101, 1054, + 1101, 1106, 106, 1, 144, 670, 1325, 1325, 1333, 1333, + 671, 1340, 518, 1325, 15, 5, 114, 842, 249, 192, + 2, 193, 1, 194, 195, 464, 196, 250, 1170, 144, + 4, 5, 198, 199, 1318, 200, 201, 202, 204, 202, + 206, 202, 208, 209, 267, 211, 144, 212, 144, 189, + 40, 338, 476, 33, 340, 251, 1, 5, 447, 17, + 5, 5, 2, 134, 10, 333, 1184, 216, 266, 217, + 220, 223, 4, 226, 289, 1396, 246, 433, 1399, 26, + 145, 735, 1400, 29, 1106, 1403, 822, 333, 825, 1404, + 828, 422, 831, 189, 833, 316, 1013, 249, 26, 282, + 1394, 425, 29, 1172, 908, 145, 250, 912, 251, 370, + 915, 1012, 17, 19, 467, 31, 32, 476, 246, 1052, + 1423, 283, 145, 1038, 145, 1425, 484, 1077, 350, -629, + 352, 1039, 26, 5, 1041, 525, 29, 357, 34, 359, + -631, 502, 704, 362, 363, 1059, 735, 1049, 513, 364, + 365, 366, 367, 626, 368, -632, 369, 202, 371, 734, + 1094, 1190, 526, 1290, 326, 1205, 1357, 374, 956, 1113, + 707, 710, 378, 379, 961, 380, 485, 288, 948, 968, + 274, 384, 951, 682, 891, 386, 387, 850, 966, 731, + 389, 390, 708, 709, 442, 392, 393, 107, 108, 21, + 627, 2, 994, 398, 996, 1154, 15, 401, 19, 924, + 403, 4, 661, 246, 301, 483, 560, 405, 10, 408, + 409, 411, 412, 414, 36, 415, 1170, 600, 1114, 5, + 311, 7, 1286, 34, 1316, 1160, 1115, 1117, 5, 251, + 338, 1138, 1136, 340, 1125, 33, 12, 704, 1126, 1127, + 1128, 1129, 297, 670, 587, 459, 588, 1040, 671, 317, + 1042, 5, 1043, 5, 973, 1109, 1044, 296, 975, 31, + 32, 5, 978, 980, 981, 709, 664, 984, 985, 323, + 665, 987, -633, 899, 24, 903, 5, 633, 903, 493, + 5, 903, 496, 5, 903, 499, 807, 903, 1316, 704, + -51, 1172, 588, 1314, 315, 316, 1130, 443, 706, 707, + 527, 528, 1196, 476, 463, 473, 341, 352, 533, 664, + 536, 5, 687, 665, 537, 539, 540, 1091, 541, 21, + 868, 708, 709, 694, 306, 689, 696, 691, 546, 693, + 547, 548, 346, 549, 733, 551, 552, 762, 554, 555, + 1289, 556, 558, 1203, 36, -30, 562, 563, 564, 326, + 1185, 374, 1116, 1118, 1119, 1120, 569, 570, 1193, 5, + 573, 574, 1323, 851, 1316, 531, 229, 579, 580, 1147, + 582, 583, 5, 585, 586, 670, 1330, 444, 1310, 421, + 671, 704, 1347, 596, 597, 598, 654, 656, 1227, 1228, + 603, 459, 604, 532, 607, 882, 608, 1083, 1084, 1085, + 1086, 755, 676, 678, 757, 859, 860, 861, 708, 709, + 653, 655, 1166, 1273, 477, 1280, 1167, 1168, 1169, 517, + 7, 751, 5, 447, 490, 521, 675, 677, 1197, 1198, + 1199, 696, 10, 883, 903, 5, 903, 686, 522, 652, + 903, 5, 657, 423, 660, 1331, 1316, 662, 663, 424, + 1211, 213, 214, 251, 518, 674, -59, 17, 1217, 1218, + 1137, -59, -59, -59, 134, 228, 685, 286, 230, 231, + 232, 433, 688, 747, 1171, 690, 1158, 5, 692, 855, + 856, 857, 807, 31, 32, 752, 704, 329, 330, 698, + 706, 707, 533, 1285, 5, 533, 854, 537, 1186, 759, + 233, 234, 1189, 704, 1173, 628, 629, 1183, 707, 246, + 433, 1187, 587, 708, 709, 1192, 805, 764, 708, 709, + 423, 424, 765, 766, 767, 705, 768, 769, 771, 769, + 708, 709, 774, 884, 1350, 1350, 1067, 1068, 889, 903, + 228, 696, 892, 230, 231, 232, 921, 1309, 785, 786, + 788, 786, 588, 790, 1312, 791, 154, 793, 156, 795, + 158, 1099, 160, 709, 1058, 469, 502, 913, 942, 418, + 916, 1229, 804, 618, 971, 228, 815, 623, 230, 231, + 232, 233, 234, 805, 967, 806, 421, 1288, 816, 897, + 818, 900, 864, 821, 901, 824, 666, 827, 1037, 830, + 612, 830, 991, 992, 598, 839, 840, 836, 1123, 875, + 1164, 1165, 604, 604, 1294, 608, 1166, 1210, 1213, 844, + 1167, 1168, 1169, 807, 847, 684, 5, 696, 892, 1323, + 1104, 1316, 1188, 1338, 1352, 134, 228, 229, 728, 230, + 231, 232, 233, 234, 728, 1345, 43, 1166, 728, 1099, + 287, 1167, 1168, 1169, 622, 758, 933, 5, 5, 165, + 1058, 1331, 1316, 166, 167, 807, 168, 704, 169, 1320, + 705, 706, 707, 1337, 1337, 280, 1342, 1346, 1171, 1351, + 1351, 281, 1355, 1021, 1019, 566, 170, 1022, 1023, 1024, + 1015, 1015, 171, 5, 708, 709, 710, 683, 1282, 172, + 173, 807, 1032, 174, 1053, 141, 507, 175, 862, 1171, + 150, 866, 153, 268, 155, 269, 157, 699, 159, 176, + 700, 701, 702, 502, 759, 872, 844, 1045, 878, 1047, + 177, 178, 179, 180, 181, 769, 98, 835, 1076, 769, + 1397, 952, 406, 954, 955, 786, 101, 1401, 958, 896, + 3, 786, 421, 413, 962, 791, 410, 1405, 6, 228, + 229, 1406, 230, 231, 232, 233, 234, 8, 696, 806, + 1407, 830, 104, 974, 9, 830, 1003, 11, 1139, 977, + 979, 830, 0, 0, 983, 830, 1424, 986, 830, 0, + 988, 0, 16, 989, 0, 0, 0, 0, 836, 836, + 993, 0, 608, 18, 997, 998, 20, 1166, 22, 863, + 1111, 1167, 1168, 1169, 1001, 1002, 0, 5, 458, 25, + 0, 27, 1316, 28, 0, 30, 873, 0, 1121, 474, + 475, 35, 460, 462, 0, 0, 465, 466, 488, 228, + 229, 0, 230, 231, 232, 495, 696, 0, 498, 0, + 487, 501, 0, 0, 0, 0, 898, 494, 902, 511, + 497, 902, 0, 500, 902, 0, 0, 902, 0, 1171, + 902, 510, 0, 1057, 0, 0, 728, 0, 1062, 1063, + 1064, 1065, 0, 0, 934, 952, 952, 1015, 0, 228, + 0, 0, 230, 231, 232, 233, 234, 0, 0, 806, + 1200, 228, 229, 1075, 230, 231, 232, 233, 234, 0, + 1079, 1080, 1081, 0, 1082, 830, 830, 830, 0, 1087, + 0, 1088, 0, 0, 0, 608, 0, 1093, 0, 844, + 0, 0, 0, 1097, 0, 0, 0, 0, 1166, 1099, + 0, 0, 1167, 1168, 1169, 1170, 0, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 704, 1015, 0, + 705, 706, 707, 635, 636, 637, 638, 639, 640, 641, + 642, 643, 0, 1141, 0, 1144, 0, 608, 1148, 0, + 0, 0, 1151, 1152, 708, 709, 710, 1155, 1156, 0, + 1157, 0, 1011, 830, 5, 1159, 0, 0, 0, 0, + 1171, 5, 1025, 704, 844, 0, 705, 706, 707, 1163, + 704, 1097, 1097, 705, 706, 707, 0, 902, 0, 902, + 1172, 0, 0, 902, 0, 0, 0, 736, 0, 1015, + 708, 709, 710, 728, 0, 0, 0, 708, 709, 710, + 0, 1166, 0, 0, 0, 1167, 1168, 1169, 1170, 0, + 0, 5, 0, 1208, 0, 1209, 0, 1144, 608, 1212, + 704, 1148, 1214, 705, 706, 707, 1216, 608, 0, 1220, + 1191, 0, 0, 476, 0, 0, 1222, 1224, 0, 0, + 0, 5, 0, 0, 0, 0, 0, 708, 709, 710, + 704, 0, 0, 705, 706, 707, 0, 1395, 0, 0, + 1293, 1222, 735, 1171, 0, 0, 923, 736, 0, 1398, + 0, 0, 0, 0, 0, 0, 1402, 708, 709, 710, + 0, 0, 902, 1172, 0, 134, 228, 229, 0, 230, + 231, 232, 233, 234, 0, 0, 0, 728, 0, 1295, + 1297, 1298, 1299, 1300, 0, 0, 1302, 1303, 1304, 1305, + 1306, 476, 0, 1308, 0, 608, 0, 844, 0, 5, + 0, 0, 608, 0, 0, 0, 0, 0, 704, 0, + 0, 705, 706, 707, 0, 0, 0, 0, 0, 0, + 735, 728, 0, 0, 728, 736, 0, 0, 728, 0, + 0, 0, 728, 1361, 0, 708, 709, 710, 0, 0, + 1366, 0, 1369, 0, 0, 0, 0, 0, 1373, 0, + 1376, 0, 0, 0, 0, 1380, 0, 0, 1383, 0, + 0, 0, 0, 1387, 0, 0, 110, 0, 0, 0, + 0, 0, 0, 111, 112, 0, 113, 0, 0, 116, + 0, 117, 0, 118, 0, 0, 0, 119, 728, 120, + 0, 121, 0, 122, 0, 123, 728, 124, 0, 125, + 0, 126, 0, 0, 728, 1224, 0, 0, 0, 127, + 1411, 1413, 0, 0, 1416, 0, 128, 0, 129, 0, + 130, 0, 131, 0, 132, 1166, 133, 5, 0, 1167, + 1168, 1169, 1170, 0, 0, 5, 704, 0, 0, 705, + 706, 707, 0, 0, 704, 0, 0, 705, 706, 707, + 0, 0, 0, 736, 0, 747, 0, 0, 0, 0, + 0, 0, 0, 708, 709, 710, 0, 0, 197, 0, + 0, 708, 709, 710, 0, 1317, 0, 1324, 1324, 1332, + 1332, 0, 1339, 1343, 1324, 1348, 1348, 1171, 1353, 3, + 0, 0, 0, 0, 476, 0, 5, 6, 0, 0, + 0, 0, 5, 0, 0, 704, 8, 1172, 705, 706, + 707, 704, 227, 9, 705, 706, 707, 0, 0, 3, + 0, 0, 300, 735, 305, 14, 310, 6, 0, 322, + 0, 16, 708, 709, 710, 0, 8, 0, 708, 709, + 710, 0, 18, 9, 0, 20, 0, 22, 0, 0, + 0, 0, 0, 0, 0, 14, 0, 0, 25, 0, + 27, 16, 28, 0, 30, 0, 0, 0, 0, 355, + 35, 0, 18, 0, 356, 20, 358, 22, 0, 360, + 361, 0, 0, 0, 0, 0, 0, 0, 25, 0, + 27, 0, 28, 0, 30, 0, 0, 0, 0, 0, + 35, 372, 373, 0, 0, 0, 376, 0, 0, 377, + 0, 0, 0, 0, 5, 0, 381, 0, 0, 0, + 385, 0, 0, 704, 0, 388, 705, 706, 707, 0, + 391, 0, 0, 1191, 0, 394, 0, 0, 0, 0, + 397, 0, 400, 0, 0, 0, 402, 0, 1, 2, + 708, 709, 710, 404, 3, 0, 407, 0, 0, 4, + 0, 5, 6, 417, 416, 0, 0, 0, 7, 0, + 432, 8, 438, 439, 0, 0, 0, 0, 9, 10, + 0, 11, 0, 12, 0, 0, 0, 0, 13, 472, + 14, 0, 0, 15, 480, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 18, 0, 19, + 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, + 23, 24, 0, 25, 26, 27, 0, 28, 29, 30, + 31, 32, 33, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 817, 0, - 820, 0, 0, 823, 0, 826, 0, 829, 0, 832, - 0, 0, 834, 0, 0, 0, 0, 0, 0, 0, - 838, 0, 0, 841, 0, 843, 0, 0, 0, 0, - 846, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 529, 0, 530, 0, 0, 0, 0, 535, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, + 0, 0, 0, 545, 544, 0, 0, 0, 0, 0, + 0, 0, 550, 553, 0, 0, 0, 0, 0, 0, + 561, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 567, 0, 0, 0, 0, 572, 571, 0, 0, 0, + 0, 577, 578, 0, 0, 581, 0, 0, 584, 0, + 0, 0, 0, 0, 0, 593, 0, 0, 595, 0, + 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, + 0, 606, 0, 0, 611, 610, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 625, 0, 0, + 0, 632, 635, 636, 637, 638, 639, 640, 641, 642, + 643, 644, 645, 646, 647, 648, 669, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 865, 0, 867, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 877, 0, 879, - 0, 0, 0, 0, 0, 0, 885, 0, 886, 0, - 887, 0, 888, 0, 852, 0, 395, 396, 0, 399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 869, 0, 869, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 930, 0, 0, - 0, 0, 0, 0, 0, 935, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 732, 0, + 0, 0, 0, 0, 744, 0, 0, 0, 750, 0, + 0, 0, 0, 0, 753, 0, 754, 0, 0, 0, + 756, 0, 0, 0, 0, 0, 760, 0, 0, 0, + 0, 0, 761, 763, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 904, 0, 0, 909, 0, 0, 0, - 0, 0, 0, 0, 0, 919, 0, 0, 0, 0, - 0, 679, 0, 0, 679, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 773, 0, 0, 775, + 776, 777, 778, 0, 0, 0, 0, 0, 0, 781, + 0, 0, 0, 784, 783, 0, 0, 0, 0, 0, + 0, 0, 792, 0, 794, 0, 0, 797, 0, 799, + 0, 801, 0, 0, 0, 0, 0, 814, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 976, 0, 0, 0, 0, - 982, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 990, 0, 0, 0, 0, 0, 0, 0, - 995, 0, 0, 999, 0, 0, 0, 0, 0, 0, - 1000, 0, 0, 1004, 1005, 1006, 1007, 1008, 1009, 0, - 0, 1010, 0, 1014, 0, 0, 1018, 0, 559, 0, - 0, 1020, 0, 1028, 1029, 1030, 565, 0, 0, 0, - 0, 568, 1034, 0, 0, 0, 0, 0, 575, 576, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1228, - 1229, 1230, 1231, 1232, 1233, 1234, 594, 1235, 1236, 1237, - 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, - 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, - 1258, 0, 0, 1259, 1260, 1261, 1262, 1263, 1071, 0, - 0, 0, 1049, 0, 0, 1076, 0, 0, 0, 0, - 0, 1054, 0, 0, 0, 0, 0, 0, 0, 0, - 1088, 0, 1090, 0, 0, 0, 0, 0, 0, 1094, - 0, 0, 0, 0, 0, 0, 0, 0, 1105, 1106, + 0, 0, 0, 0, 0, 0, 0, 817, 0, 820, + 0, 0, 823, 0, 826, 0, 829, 0, 832, 0, + 0, 834, 0, 0, 0, 0, 0, 0, 0, 838, + 0, 0, 841, 0, 843, 0, 0, 0, 0, 846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1122, 0, 0, - 0, 0, 1132, 0, 0, 1133, 1138, 0, 0, 0, - 0, 1141, 0, 1144, 0, 0, 1148, 0, 0, 0, - 0, 0, 0, 0, 869, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 865, + 0, 867, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 877, 0, 879, 0, + 0, 0, 0, 0, 0, 885, 0, 886, 0, 887, + 0, 888, 0, 0, 0, 0, 0, 135, 137, 139, + 139, 142, 0, 0, 148, 139, 151, 139, 148, 139, + 148, 139, 148, 139, 148, 161, 163, 0, 185, 185, + 185, 0, 0, 0, 0, 0, 930, 0, 0, 0, + 0, 0, 0, 0, 935, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1159, 0, 0, 0, 679, 0, 0, + 0, 395, 396, 0, 399, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 779, 780, 0, 1200, 0, - 1202, 782, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 796, 1204, 798, 1205, - 800, 0, 802, 0, 1179, 0, 0, 1179, 0, 0, - 0, 1179, 0, 0, 0, 1217, 0, 0, 0, 1219, - 0, 0, 869, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1279, 0, 0, 0, 0, 0, 0, - 0, 1285, 0, 1289, 1290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 869, 869, 0, + 244, 0, 0, 0, 0, 272, 0, 0, 0, 0, + 0, 0, 0, 0, 976, 0, 0, 0, 0, 982, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1281, 0, 0, 0, 0, 0, 0, 0, 0, 1299, - 0, 0, 0, 0, 0, 0, 1305, 0, 0, 0, + 0, 990, 0, 0, 0, 0, 0, 0, 0, 995, + 0, 0, 999, 0, 0, 0, 0, 0, 0, 1000, + 0, 0, 1004, 1005, 1006, 1007, 1008, 1009, 0, 0, + 1010, 0, 1014, 0, 0, 1018, 0, 0, 0, 0, + 1020, 0, 1029, 1030, 1031, 0, 0, 0, 0, 0, + 0, 1035, 1267, 1230, 1231, 1232, 1233, 1234, 1235, 1236, + 1268, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, + 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, + 1256, 1257, 1258, 1259, 1260, 1269, 1270, 1261, 1262, 1263, + 1264, 1265, 0, 559, 0, 0, 0, 0, 0, 0, + 0, 565, 0, 0, 0, 0, 568, 0, 1073, 0, + 0, 0, 0, 575, 576, 1078, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 426, 0, + 1090, 594, 1092, 440, 137, 0, 0, 0, 0, 1096, + 0, 0, 0, 0, 0, 0, 0, 0, 1107, 1108, + 0, 0, 0, 0, 481, 137, 0, 0, 0, 0, + 0, 0, 0, 491, 0, 0, 0, 0, 1124, 0, + 0, 0, 0, 1134, 0, 505, 1135, 1140, 508, 0, + 0, 0, 1143, 0, 1146, 515, 0, 1150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1311, 0, 1313, 0, 1320, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1354, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1361, 0, 0, 0, 0, 0, 0, 1366, 0, - 0, 0, 0, 0, 0, 0, 1373, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 944, 945, 946, - 947, 0, 949, 950, 0, 1390, 1391, 1, 2, 0, - 0, 0, 957, 3, 959, 960, 0, 0, 4, 0, - 5, 6, 964, 965, 0, 0, 0, 7, 0, 0, - 8, 0, 0, 0, 0, 972, 0, 9, 10, 0, - 11, 0, 12, 1407, 0, 0, 0, 13, 0, 14, - 1416, 0, 15, 0, 0, 16, 0, 0, 0, 0, - 0, 0, 0, 17, 0, 0, 18, 0, 19, 20, - 21, 22, 1425, 0, 0, 0, 0, 0, 0, 23, - 24, 0, 25, 26, 27, 0, 28, 29, 30, 31, - 32, 33, 0, 34, 35, 36, 1265, 1228, 1229, 1230, - 1231, 1232, 1233, 1234, 1266, 1235, 1236, 1237, 1238, 1239, - 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, - 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1267, - 1268, 1259, 1260, 1261, 1262, 1263, 0, 0, 0, 0, + 0, 0, 0, 0, 1161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1065, 0, 0, 0, 0, 1068, 1069, 0, 1070, 0, - 0, 0, 0, 0, 0, 0, 1072, 1272, 1228, 1229, - 1230, 1231, 1232, 1233, 1234, 1273, 1235, 1236, 1237, 1238, - 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, - 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, - 1274, 1275, 1259, 1260, 1261, 1262, 1263, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1202, + 0, 1204, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1206, 0, + 1207, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1219, 0, 0, 0, + 1221, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 779, 780, 0, 0, 1281, 0, 782, 0, 0, 0, + 0, 0, 1287, 0, 1291, 1292, 0, 614, 616, 0, + 0, 796, 0, 798, 0, 800, 0, 802, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 658, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 679, 0, 0, 0, 0, + 1301, 0, 0, 0, 0, 0, 0, 1307, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1313, 0, 1315, 0, 1322, 0, 0, 0, 0, + 0, 0, 0, 0, 745, 0, 0, 0, 185, 1356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1363, 0, 0, 0, 0, 0, 0, 1368, + 0, 0, 0, 0, 0, 0, 0, 1375, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1392, 1393, 0, 0, + 0, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 0, 1237, + 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, + 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, + 1258, 1259, 1260, 0, 1409, 1261, 1262, 1263, 1264, 1265, + 0, 1418, 944, 945, 946, 947, 0, 949, 950, 0, + 0, 0, 0, 0, 0, 0, 0, 957, 0, 959, + 960, 0, 0, 1427, 0, 0, 0, 964, 965, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 972, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 852, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 869, + 0, 869, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 904, 0, + 0, 909, 0, 0, 0, 0, 0, 0, 0, 0, + 919, 0, 0, 0, 0, 0, 679, 0, 0, 679, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1066, 0, 0, 0, 0, + 1069, 1070, 0, 1071, 0, 0, 0, 0, 0, 1072, + 0, 0, 1074, 1274, 1230, 1231, 1232, 1233, 1234, 1235, + 1236, 1275, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, + 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, + 1255, 1256, 1257, 1258, 1259, 1260, 1276, 1277, 1261, 1262, + 1263, 1264, 1265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1050, 0, 0, + 0, 0, 0, 0, 0, 0, 1055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1215, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 869, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1356, 0, 0, 1357, 1358, 0, 1360, 0, 0, - 0, 1362, 1363, 0, 1365, 0, 1368, 0, 0, 1369, - 1370, 0, 1372, 0, 1375, 0, 1376, 1377, 0, 1379, - 1380, 0, 1382, 1383, 0, 1384, 0, 1386, 1387, 0, - 1388, 0, 1389, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 679, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1406, 0, 1408, 1410, 0, 1412, 1413, 1415, 0, - 1417, 1418, 1419, 1420, 0, 0, 0, 0, 0, 0, + 1311, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1181, 0, 0, 1181, 0, 0, 0, 1181, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1358, 869, + 0, 1359, 1360, 0, 1362, 0, 0, 0, 1364, 1365, + 0, 1367, 0, 1370, 0, 0, 1371, 1372, 0, 1374, + 0, 1377, 0, 1378, 1379, 0, 1381, 1382, 0, 1384, + 1385, 0, 1386, 0, 1388, 1389, 0, 1390, 0, 1391, + 0, 0, 0, 0, 869, 869, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1283, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1424, 0, 1426 + 0, 0, 0, 0, 0, 0, 0, 0, 1408, 0, + 1410, 1412, 0, 1414, 1415, 1417, 0, 1419, 1420, 1421, + 1422, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1426, 0, 1428 }; static const yytype_int16 yycheck[] = { - 57, 196, 0, 192, 346, 227, 558, 374, 115, 598, - 0, 220, 131, 132, 223, 604, 242, 434, 853, 201, - 206, 208, 434, 592, 212, 528, 204, 369, 836, 0, - 821, 997, 411, 821, 742, 697, 824, 783, 656, 235, - 838, 0, 352, 841, 893, 379, 955, 133, 243, 832, - 1133, 836, 156, 1061, 158, 1063, 1064, 694, 678, 403, - 4, 836, 1293, 4, 65, 67, 1073, 25, 1056, 14, - 4, 49, 17, 1295, 1296, 1297, 1298, 22, 1300, 136, - 1302, 138, 365, 140, 141, 19, 143, 6, 163, 90, - 92, 17, 149, 150, 28, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 195, 162, 14, 164, 0, 17, - 88, 356, 56, 720, 0, 722, 60, 724, 195, 726, - 78, 728, 56, 35, 201, 51, 60, 184, 1359, 186, - 187, 188, 377, 190, 220, 1142, 80, 223, 1146, 80, - 84, 40, 1364, 84, 89, 1367, 80, 6, 7, 1371, - 84, 347, 1374, 12, 49, 7, 1378, 40, 17, 11, - 3, 350, 17, 82, 1144, 17, 821, 952, 1148, 824, - 274, 26, 827, 368, 86, 87, 9, 952, 73, 78, - 147, 89, 25, 974, 1033, 993, 974, 1409, 245, 977, - 247, 163, 1414, 88, 416, 1161, 378, 254, 19, 256, - 55, 397, 6, 260, 261, 38, 989, 28, 404, 266, - 267, 268, 269, 17, 271, 403, 273, 274, 275, 927, - 1055, 929, 418, 82, 603, 1074, 1001, 284, 1311, 539, - 201, 893, 289, 290, 1222, 292, 570, 61, 807, 198, - 1149, 298, 30, 31, 862, 302, 303, 836, 866, 752, - 307, 308, 872, 890, 598, 312, 313, 540, 878, 569, - 163, 1110, 5, 320, 6, 53, 54, 324, 9, 552, - 327, 155, 15, 157, 16, 470, 17, 334, 82, 336, - 337, 338, 339, 340, 17, 342, 1077, 513, 5, 1077, - 1078, 898, 5, 26, 1129, 902, 1094, 38, 15, 906, - 907, 908, 15, 17, 911, 912, 24, 17, 915, 65, - 202, 1220, 35, 23, 155, 71, 157, 209, 61, 974, - 1095, 39, 977, 409, 979, 1071, 412, 816, 983, 818, - 48, 163, 821, 56, 90, 824, 50, 51, 827, 17, - 82, 830, 17, 1051, 61, 62, 31, 543, 26, 163, - 386, 26, 7, 389, 1296, 697, 392, 12, 9, 77, - 1302, 64, 17, 86, 87, 1153, 17, 357, 53, 54, - 427, 428, 41, 371, 364, 53, 54, 434, 435, 54, - 437, 1142, 1291, 7, 441, 442, 443, 11, 445, 1150, - 159, 160, 574, 589, 1102, 774, 592, 583, 455, 586, - 457, 458, 580, 460, 600, 462, 463, 633, 465, 466, - 598, 468, 469, 1159, 1222, 150, 473, 474, 475, 32, - 33, 478, 1077, 1078, 1079, 1080, 483, 484, 150, 619, - 487, 488, 622, 1040, 1041, 1042, 1043, 494, 495, 851, - 497, 498, 149, 500, 501, 161, 162, 1282, 790, 759, - 765, 766, 767, 510, 511, 512, 547, 548, 1204, 1205, - 517, 57, 519, 7, 521, 882, 523, 11, 12, 13, - 547, 548, 563, 564, 17, 1183, 24, 20, 793, 22, - 67, 791, 374, 1191, 1192, 72, 563, 564, 977, 48, - 979, 610, 384, 16, 983, 17, 17, 574, 1153, 1154, - 1155, 697, 74, 75, 26, 92, 1095, 29, 30, 31, - 546, 1118, 25, 549, 36, 551, 47, 1293, 554, 555, - 32, 1297, 1298, 408, 1300, 1301, 562, 1303, 1304, 414, - 1306, 53, 54, 55, 147, 148, 149, 573, 151, 152, - 153, 154, 155, 579, 33, 17, 582, 17, 62, 585, - 1139, 893, 22, 1142, 26, 612, 155, 1146, 30, 31, - 596, 1150, 619, 1218, 17, 622, 762, 624, 45, 626, - 7, 156, 1280, 26, 11, 12, 13, 29, 31, 1287, - 17, 53, 54, 20, 7, 22, 147, 644, 1364, 12, - 157, 1080, 649, 650, 651, 1371, 653, 654, 655, 656, - 53, 54, 659, 8, 1210, 1381, 1212, 54, 804, 1385, - 17, 807, 808, 795, 21, 22, 369, 1206, 675, 676, - 677, 678, 120, 680, 122, 682, 124, 684, 126, 686, - 154, 155, 69, 1222, 1001, 346, 832, 826, 847, 695, - 829, 533, 894, 112, 891, 537, 703, 816, 117, 817, - 119, 818, 121, 974, 123, 997, 125, 527, 715, 1086, - 717, 1226, 769, 720, 556, 722, 1182, 724, 1186, 726, - 571, 728, 58, 59, 731, 53, 54, 734, 1063, 786, - 1146, 156, 739, 740, 1298, 742, 161, 162, 163, 746, - 1301, 1033, 61, 62, 751, 7, 8, 893, 894, 11, - 12, 13, 14, 7, 1304, 17, 598, 11, 12, 13, - 14, 0, 604, 17, 26, 201, 608, 29, 30, 31, - 1303, 1304, 26, 1012, 1013, 29, 30, 31, 1095, 536, - 7, 624, 1074, 843, 11, 12, 13, 151, 152, 153, - 17, 53, 54, 55, 21, 22, 925, 926, 7, 53, - 54, 55, 11, 12, 13, 739, 740, 69, 17, 954, - 955, 1136, 1137, 22, 129, 69, 129, 129, 1110, 129, - 7, 129, 968, 995, 11, 12, 13, 89, 768, 199, - 17, 771, 7, 199, 958, 89, 11, 12, 13, 14, - 478, 129, 69, 989, 851, 785, 853, 986, 788, 988, - 129, 35, 570, 1214, 129, 862, 129, 1033, 129, 866, - 69, 868, 398, 870, 871, 872, 129, 815, 875, 1161, - 195, 878, 56, 195, 881, 882, 60, 597, 129, 147, - 148, 597, 69, 151, 152, 153, 70, 1033, 597, 597, - 731, 898, 0, 900, 69, 902, 129, 129, 129, 906, - 907, 908, 86, 87, 911, 912, 129, 914, 915, 1411, - 917, 148, 149, 920, 151, 152, 153, 129, 925, 926, - 927, 361, 929, 334, 931, 932, 148, 769, 1074, 151, - 152, 153, 372, 373, 941, 942, 337, 0, 1390, 10, - 339, 381, 0, 942, 786, 1095, 1085, 18, 388, -1, - -1, 391, -1, -1, 394, -1, 27, -1, -1, -1, - -1, -1, 402, 34, 1110, 148, 37, -1, 151, 152, - 153, 154, 155, 156, 816, 158, 818, -1, -1, 821, - -1, 52, 824, -1, -1, 827, -1, -1, 830, -1, - -1, -1, 63, 1000, 836, 66, -1, 68, 1005, 1006, - 1007, 1008, 844, -1, 1149, 1012, 1013, -1, 79, -1, - 81, -1, 83, -1, 85, -1, -1, -1, 1157, -1, - 91, -1, 1029, -1, -1, -1, -1, -1, -1, 1036, - 1037, 1038, 8, 1040, 1041, 1042, 1043, -1, 1045, 9, - 1047, 17, -1, -1, 1051, -1, 1053, 17, 1055, -1, - 26, -1, 1059, 29, 30, 31, 26, -1, -1, 29, - 30, 31, -1, -1, -1, -1, -1, -1, 38, -1, - -1, -1, 42, 43, -1, 1220, -1, 53, 54, 55, - -1, -1, -1, 53, 54, 55, -1, -1, -1, -1, - -1, 1098, -1, 1100, -1, 1102, 1103, -1, -1, -1, - 1107, 1108, -1, -1, -1, 1112, 1113, -1, 1115, -1, - 952, 1118, -1, 1120, -1, -1, -1, -1, -1, 17, - -1, -1, 1129, -1, -1, -1, -1, 1134, 26, 1136, - 1137, 29, 30, 31, -1, 977, -1, 979, -1, -1, - -1, 983, -1, 7, -1, 43, 1291, 11, 12, 13, - 14, 993, -1, 17, -1, 53, 54, 55, -1, -1, - -1, -1, 26, -1, -1, 29, 30, 31, -1, -1, - -1, 1178, 36, 1180, -1, 1182, 1183, 1184, -1, 1186, - 1187, -1, -1, -1, 1191, 1192, -1, 1194, -1, 53, - 54, 55, -1, -1, 1201, 1202, -1, -1, -1, -1, - 9, -1, -1, -1, -1, 69, 148, 149, 17, 151, - 152, 153, 154, 155, -1, 1361, 158, 26, 1225, 1226, - 29, 30, 31, -1, -1, 89, -1, 1366, -1, 38, - -1, -1, -1, -1, 1373, 147, 148, 149, 1080, 151, - 152, 153, 154, 155, 53, 54, 55, -1, -1, -1, - -1, -1, -1, 1095, -1, -1, -1, 1264, 1265, 1266, - 1267, 1268, -1, -1, 1271, 1272, 1273, 1274, 1275, 9, - -1, 1278, -1, 1280, -1, 1282, -1, 17, 148, -1, - 1287, 151, 152, 153, 154, 155, 26, -1, 158, 29, - 30, 31, -1, -1, -1, -1, -1, 1139, 38, -1, - 1142, -1, -1, 43, 1146, -1, -1, -1, 1150, -1, - -1, 1318, -1, 53, 54, 55, -1, 45, 1325, -1, - 1327, -1, -1, -1, 52, 53, 1333, 55, 1335, -1, - 58, -1, 60, 1340, 62, -1, 1343, -1, 66, -1, - 68, 1348, 70, -1, 72, -1, 74, -1, 76, -1, - 78, -1, 80, -1, -1, -1, -1, -1, -1, -1, - 88, -1, -1, -1, 1206, -1, -1, 95, -1, 97, - -1, 99, 1214, 101, -1, 103, -1, 105, -1, -1, - 1222, 362, 363, 1390, -1, 366, 367, -1, 1395, 1396, - 148, 149, 1399, 151, 152, 153, 154, 155, -1, 380, - -1, -1, -1, -1, -1, -1, 387, -1, -1, 390, - -1, -1, 393, -1, -1, -1, -1, -1, -1, 147, - 401, -1, 109, 110, 111, 112, 113, -1, -1, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, -1, 130, 131, 132, -1, -1, -1, -1, - -1, 1293, -1, 1295, 1296, 1297, 1298, -1, 1300, 1301, - 1302, 1303, 1304, 191, 1306, -1, 10, -1, -1, -1, - -1, -1, -1, 203, 18, 205, -1, 207, -1, 17, - 210, -1, -1, 27, -1, -1, -1, -1, 26, -1, - 34, 29, 30, 31, -1, -1, -1, -1, -1, -1, - -1, -1, 46, -1, -1, 192, -1, -1, 52, -1, - 197, -1, -1, -1, -1, 53, 54, 55, -1, 63, - 248, -1, 66, -1, 68, 253, -1, 255, -1, -1, - 258, 259, -1, -1, -1, 79, 17, 81, -1, 83, - -1, 85, -1, -1, -1, 26, -1, 91, 29, 30, - 31, -1, 280, 281, -1, -1, -1, 285, -1, -1, - 288, -1, 43, -1, 45, -1, -1, 295, -1, -1, - -1, 299, 53, 54, 55, -1, 304, -1, -1, -1, - -1, 309, -1, -1, -1, -1, 314, -1, -1, -1, - -1, 319, -1, 321, -1, -1, -1, 325, -1, -1, - -1, -1, -1, -1, 332, -1, -1, 335, -1, -1, - -1, -1, -1, -1, 344, 343, -1, -1, -1, -1, - -1, 351, -1, 353, 354, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, -1, - 370, -1, -1, -1, -1, 375, 93, 94, 95, 96, - 97, 98, 99, 100, 101, -1, -1, -1, -1, -1, - -1, -1, -1, 350, -1, -1, -1, -1, 355, 356, + 57, 558, 196, 192, 0, 346, 227, 374, 115, 201, + 0, 220, 131, 132, 223, 434, 242, 853, 434, 204, + 206, 208, 836, 528, 133, 955, 352, 411, 369, 592, + 821, 598, 656, 212, 678, 783, 0, 604, 821, 235, + 836, 824, 0, 697, 838, 379, 893, 841, 1135, 243, + 832, 156, 694, 158, 403, 836, 1057, 1075, 1062, 997, + 1064, 1065, 0, 4, 6, 7, 1297, 1298, 1299, 1300, + 12, 1302, 25, 1304, 49, 17, 163, 742, 19, 136, + 5, 138, 4, 140, 141, 365, 143, 28, 14, 6, + 15, 17, 149, 150, 1295, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 195, 162, 6, 164, 6, 40, + 0, 220, 9, 88, 223, 56, 4, 17, 16, 60, + 17, 17, 5, 147, 35, 78, 1144, 184, 195, 186, + 187, 188, 15, 190, 201, 1366, 61, 62, 1369, 80, + 82, 38, 1373, 84, 1148, 1376, 720, 78, 722, 1380, + 724, 347, 726, 40, 728, 51, 952, 19, 80, 3, + 1361, 350, 84, 89, 821, 82, 28, 824, 56, 274, + 827, 952, 60, 65, 368, 86, 87, 9, 61, 993, + 1411, 25, 82, 974, 82, 1416, 378, 1034, 245, 163, + 247, 974, 80, 17, 977, 416, 84, 254, 90, 256, + 163, 397, 26, 260, 261, 1001, 38, 989, 404, 266, + 267, 268, 269, 539, 271, 163, 273, 274, 275, 603, + 1056, 1151, 418, 1224, 403, 1163, 1313, 284, 872, 1076, + 31, 55, 289, 290, 878, 292, 570, 201, 862, 893, + 198, 298, 866, 569, 807, 302, 303, 752, 890, 598, + 307, 308, 53, 54, 356, 312, 313, 159, 160, 67, + 540, 5, 927, 320, 929, 1112, 49, 324, 65, 836, + 327, 15, 552, 61, 71, 377, 470, 334, 35, 336, + 337, 338, 339, 340, 92, 342, 14, 513, 1079, 17, + 73, 24, 1222, 90, 22, 1131, 1079, 1080, 17, 56, + 409, 1097, 1096, 412, 7, 88, 39, 26, 11, 12, + 13, 14, 202, 7, 155, 48, 157, 974, 12, 209, + 977, 17, 979, 17, 898, 1073, 983, 23, 902, 86, + 87, 17, 906, 907, 908, 54, 7, 911, 912, 64, + 11, 915, 163, 816, 77, 818, 17, 543, 821, 386, + 17, 824, 389, 17, 827, 392, 697, 830, 22, 26, + 155, 89, 157, 1293, 50, 51, 69, 357, 30, 31, + 427, 428, 1155, 9, 364, 371, 41, 434, 435, 7, + 437, 17, 574, 11, 441, 442, 443, 1052, 445, 67, + 774, 53, 54, 589, 72, 580, 592, 583, 455, 586, + 457, 458, 150, 460, 600, 462, 463, 633, 465, 466, + 1224, 468, 469, 1161, 92, 150, 473, 474, 475, 598, + 1144, 478, 1079, 1080, 1081, 1082, 483, 484, 1152, 17, + 487, 488, 20, 759, 22, 851, 149, 494, 495, 1104, + 497, 498, 17, 500, 501, 7, 1298, 57, 1284, 790, + 12, 26, 1304, 510, 511, 512, 547, 548, 1206, 1207, + 517, 48, 519, 882, 521, 791, 523, 1041, 1042, 1043, + 1044, 619, 563, 564, 622, 765, 766, 767, 53, 54, + 547, 548, 7, 1212, 374, 1214, 11, 12, 13, 408, + 24, 610, 17, 16, 384, 414, 563, 564, 1155, 1156, + 1157, 697, 35, 793, 977, 17, 979, 574, 47, 546, + 983, 17, 549, 32, 551, 21, 22, 554, 555, 33, + 1185, 161, 162, 56, 25, 562, 156, 60, 1193, 1194, + 1097, 161, 162, 163, 147, 148, 573, 70, 151, 152, + 153, 62, 579, 45, 69, 582, 1120, 17, 585, 151, + 152, 153, 893, 86, 87, 612, 26, 74, 75, 596, + 30, 31, 619, 1220, 17, 622, 762, 624, 1146, 626, + 154, 155, 1150, 26, 1141, 58, 59, 1144, 31, 61, + 62, 1148, 155, 53, 54, 1152, 156, 644, 53, 54, + 32, 33, 649, 650, 651, 29, 653, 654, 655, 656, + 53, 54, 659, 795, 1305, 1306, 1012, 1013, 804, 1082, + 148, 807, 808, 151, 152, 153, 147, 1282, 675, 676, + 677, 678, 157, 680, 1289, 682, 120, 684, 122, 686, + 124, 8, 126, 54, 1001, 369, 832, 826, 847, 346, + 829, 1208, 695, 533, 894, 148, 703, 537, 151, 152, + 153, 154, 155, 156, 891, 158, 997, 1224, 715, 816, + 717, 817, 769, 720, 818, 722, 556, 724, 974, 726, + 527, 728, 925, 926, 731, 739, 740, 734, 1088, 786, + 1138, 1139, 739, 740, 1228, 742, 7, 1184, 1188, 746, + 11, 12, 13, 1034, 751, 571, 17, 893, 894, 20, + 1064, 22, 1148, 1300, 1306, 147, 148, 149, 598, 151, + 152, 153, 154, 155, 604, 1303, 0, 7, 608, 8, + 201, 11, 12, 13, 536, 624, 843, 17, 17, 129, + 1097, 21, 22, 129, 129, 1076, 129, 26, 129, 1295, + 29, 30, 31, 1299, 1300, 199, 1302, 1303, 69, 1305, + 1306, 199, 1308, 7, 958, 478, 129, 11, 12, 13, + 954, 955, 129, 17, 53, 54, 55, 570, 1216, 129, + 129, 1112, 968, 129, 995, 112, 398, 129, 768, 69, + 117, 771, 119, 195, 121, 195, 123, 597, 125, 129, + 597, 597, 597, 989, 851, 785, 853, 986, 788, 988, + 129, 129, 129, 129, 129, 862, 0, 731, 1034, 866, + 1366, 868, 334, 870, 871, 872, 0, 1373, 875, 815, + 10, 878, 1163, 339, 881, 882, 337, 1383, 18, 148, + 149, 1387, 151, 152, 153, 154, 155, 27, 1034, 158, + 1392, 898, 0, 900, 34, 902, 942, 37, 1097, 906, + 907, 908, -1, -1, 911, 912, 1413, 914, 915, -1, + 917, -1, 52, 920, -1, -1, -1, -1, 925, 926, + 927, -1, 929, 63, 931, 932, 66, 7, 68, 769, + 1076, 11, 12, 13, 941, 942, -1, 17, 361, 79, + -1, 81, 22, 83, -1, 85, 786, -1, 1087, 372, + 373, 91, 362, 363, -1, -1, 366, 367, 381, 148, + 149, -1, 151, 152, 153, 388, 1112, -1, 391, -1, + 380, 394, -1, -1, -1, -1, 816, 387, 818, 402, + 390, 821, -1, 393, 824, -1, -1, 827, -1, 69, + 830, 401, -1, 1000, -1, -1, 836, -1, 1005, 1006, + 1007, 1008, -1, -1, 844, 1012, 1013, 1151, -1, 148, + -1, -1, 151, 152, 153, 154, 155, -1, -1, 158, + 1159, 148, 149, 1030, 151, 152, 153, 154, 155, -1, + 1037, 1038, 1039, -1, 1041, 1042, 1043, 1044, -1, 1046, + -1, 1048, -1, -1, -1, 1052, -1, 1054, -1, 1056, + -1, -1, -1, 1060, -1, -1, -1, -1, 7, 8, + -1, -1, 11, 12, 13, 14, -1, -1, 17, -1, + -1, -1, -1, -1, -1, -1, -1, 26, 1222, -1, + 29, 30, 31, 93, 94, 95, 96, 97, 98, 99, + 100, 101, -1, 1100, -1, 1102, -1, 1104, 1105, -1, + -1, -1, 1109, 1110, 53, 54, 55, 1114, 1115, -1, + 1117, -1, 952, 1120, 17, 1122, -1, -1, -1, -1, + 69, 17, 962, 26, 1131, -1, 29, 30, 31, 1136, + 26, 1138, 1139, 29, 30, 31, -1, 977, -1, 979, + 89, -1, -1, 983, -1, -1, -1, 43, -1, 1293, + 53, 54, 55, 993, -1, -1, -1, 53, 54, 55, + -1, 7, -1, -1, -1, 11, 12, 13, 14, -1, + -1, 17, -1, 1180, -1, 1182, -1, 1184, 1185, 1186, + 26, 1188, 1189, 29, 30, 31, 1193, 1194, -1, 1196, + 36, -1, -1, 9, -1, -1, 1203, 1204, -1, -1, + -1, 17, -1, -1, -1, -1, -1, 53, 54, 55, + 26, -1, -1, 29, 30, 31, -1, 1363, -1, -1, + 1227, 1228, 38, 69, -1, -1, 42, 43, -1, 1368, + -1, -1, -1, -1, -1, -1, 1375, 53, 54, 55, + -1, -1, 1082, 89, -1, 147, 148, 149, -1, 151, + 152, 153, 154, 155, -1, -1, -1, 1097, -1, 1266, + 1267, 1268, 1269, 1270, -1, -1, 1273, 1274, 1275, 1276, + 1277, 9, -1, 1280, -1, 1282, -1, 1284, -1, 17, + -1, -1, 1289, -1, -1, -1, -1, -1, 26, -1, + -1, 29, 30, 31, -1, -1, -1, -1, -1, -1, + 38, 1141, -1, -1, 1144, 43, -1, -1, 1148, -1, + -1, -1, 1152, 1320, -1, 53, 54, 55, -1, -1, + 1327, -1, 1329, -1, -1, -1, -1, -1, 1335, -1, + 1337, -1, -1, -1, -1, 1342, -1, -1, 1345, -1, + -1, -1, -1, 1350, -1, -1, 45, -1, -1, -1, + -1, -1, -1, 52, 53, -1, 55, -1, -1, 58, + -1, 60, -1, 62, -1, -1, -1, 66, 1208, 68, + -1, 70, -1, 72, -1, 74, 1216, 76, -1, 78, + -1, 80, -1, -1, 1224, 1392, -1, -1, -1, 88, + 1397, 1398, -1, -1, 1401, -1, 95, -1, 97, -1, + 99, -1, 101, -1, 103, 7, 105, 17, -1, 11, + 12, 13, 14, -1, -1, 17, 26, -1, -1, 29, + 30, 31, -1, -1, 26, -1, -1, 29, 30, 31, + -1, -1, -1, 43, -1, 45, -1, -1, -1, -1, + -1, -1, -1, 53, 54, 55, -1, -1, 147, -1, + -1, 53, 54, 55, -1, 1295, -1, 1297, 1298, 1299, + 1300, -1, 1302, 1303, 1304, 1305, 1306, 69, 1308, 10, + -1, -1, -1, -1, 9, -1, 17, 18, -1, -1, + -1, -1, 17, -1, -1, 26, 27, 89, 29, 30, + 31, 26, 191, 34, 29, 30, 31, -1, -1, 10, + -1, -1, 203, 38, 205, 46, 207, 18, -1, 210, + -1, 52, 53, 54, 55, -1, 27, -1, 53, 54, + 55, -1, 63, 34, -1, 66, -1, 68, -1, -1, + -1, -1, -1, -1, -1, 46, -1, -1, 79, -1, + 81, 52, 83, -1, 85, -1, -1, -1, -1, 248, + 91, -1, 63, -1, 253, 66, 255, 68, -1, 258, + 259, -1, -1, -1, -1, -1, -1, -1, 79, -1, + 81, -1, 83, -1, 85, -1, -1, -1, -1, -1, + 91, 280, 281, -1, -1, -1, 285, -1, -1, 288, + -1, -1, -1, -1, 17, -1, 295, -1, -1, -1, + 299, -1, -1, 26, -1, 304, 29, 30, 31, -1, + 309, -1, -1, 36, -1, 314, -1, -1, -1, -1, + 319, -1, 321, -1, -1, -1, 325, -1, 4, 5, + 53, 54, 55, 332, 10, -1, 335, -1, -1, 15, + -1, 17, 18, 344, 343, -1, -1, -1, 24, -1, + 351, 27, 353, 354, -1, -1, -1, -1, 34, 35, + -1, 37, -1, 39, -1, -1, -1, -1, 44, 370, + 46, -1, -1, 49, 375, -1, 52, -1, -1, -1, + -1, -1, -1, -1, 60, -1, -1, 63, -1, 65, + 66, 67, 68, -1, -1, -1, -1, -1, -1, -1, + 76, 77, -1, 79, 80, 81, -1, 83, 84, 85, + 86, 87, 88, -1, 90, 91, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 376, - 377, -1, -1, -1, -1, -1, -1, -1, 385, -1, - -1, 429, -1, 431, -1, -1, -1, -1, 436, -1, - 397, -1, -1, 400, -1, -1, -1, -1, 446, -1, - 407, -1, -1, -1, 454, 453, -1, -1, -1, 10, - -1, -1, -1, 461, 464, -1, 17, 18, -1, -1, - -1, 471, -1, -1, -1, 26, 27, -1, 29, 30, - 31, 479, -1, 34, -1, -1, 486, 485, -1, -1, - -1, -1, 492, 493, -1, 46, 496, -1, -1, 499, - -1, 52, 53, 54, 55, -1, 506, -1, -1, 509, - -1, -1, 63, -1, 514, 66, 516, 68, -1, -1, - -1, -1, 520, -1, -1, 525, 524, -1, 79, -1, - 81, -1, 83, -1, 85, -1, -1, -1, 538, -1, - 91, -1, 542, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 557, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 568, -1, - -1, -1, 529, 530, -1, -1, -1, -1, -1, -1, + 429, -1, 431, -1, -1, -1, -1, 436, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 446, -1, -1, + -1, -1, -1, 454, 453, -1, -1, -1, -1, -1, + -1, -1, 461, 464, -1, -1, -1, -1, -1, -1, + 471, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 479, -1, -1, -1, -1, 486, 485, -1, -1, -1, + -1, 492, 493, -1, -1, 496, -1, -1, 499, -1, + -1, -1, -1, -1, -1, 506, -1, -1, 509, -1, + -1, -1, -1, 514, -1, 516, -1, -1, -1, -1, + -1, 520, -1, -1, 525, 524, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 538, -1, -1, + -1, 542, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 557, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 568, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 550, -1, -1, -1, -1, -1, 599, - -1, -1, -1, -1, -1, 605, -1, -1, -1, 609, - 567, -1, -1, -1, -1, 615, -1, 617, -1, -1, - -1, 621, -1, -1, -1, -1, -1, 627, -1, -1, - -1, -1, -1, 631, 634, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 606, - -1, -1, -1, 610, -1, -1, -1, 657, -1, -1, - 660, 661, 662, 663, -1, -1, -1, -1, -1, -1, - 668, -1, -1, -1, 674, 673, -1, -1, -1, -1, - -1, -1, -1, 683, -1, 685, -1, -1, 688, -1, - 690, -1, 692, -1, -1, -1, -1, -1, 698, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 716, -1, - 718, -1, -1, 721, -1, 723, -1, 725, -1, 727, - -1, -1, 730, -1, -1, -1, -1, -1, -1, -1, - 738, -1, -1, 741, -1, 743, -1, -1, -1, -1, - 748, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 599, -1, + -1, -1, -1, -1, 605, -1, -1, -1, 609, -1, + -1, -1, -1, -1, 615, -1, 617, -1, -1, -1, + 621, -1, -1, -1, -1, -1, 627, -1, -1, -1, + -1, -1, 631, 634, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 770, -1, 772, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 787, -1, 789, - -1, -1, -1, -1, -1, -1, 796, -1, 798, -1, - 800, -1, 802, -1, 761, -1, 317, 318, -1, 320, + -1, -1, -1, -1, -1, -1, 657, -1, -1, 660, + 661, 662, 663, -1, -1, -1, -1, -1, -1, 668, + -1, -1, -1, 674, 673, -1, -1, -1, -1, -1, + -1, -1, 683, -1, 685, -1, -1, 688, -1, 690, + -1, 692, -1, -1, -1, -1, -1, 698, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 781, -1, 783, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 837, -1, -1, - -1, -1, -1, -1, -1, 845, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 716, -1, 718, + -1, -1, 721, -1, 723, -1, 725, -1, 727, -1, + -1, 730, -1, -1, -1, -1, -1, -1, -1, 738, + -1, -1, 741, -1, 743, -1, -1, -1, -1, 748, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 820, -1, -1, 823, -1, -1, -1, - -1, -1, -1, -1, -1, 832, -1, -1, -1, -1, - -1, 838, -1, -1, 841, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 770, + -1, 772, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 787, -1, 789, -1, + -1, -1, -1, -1, -1, 796, -1, 798, -1, 800, + -1, 802, -1, -1, -1, -1, -1, 109, 110, 111, + 112, 113, -1, -1, 116, 117, 118, 119, 120, 121, + 122, 123, 124, 125, 126, 127, 128, -1, 130, 131, + 132, -1, -1, -1, -1, -1, 837, -1, -1, -1, + -1, -1, -1, -1, 845, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 905, -1, -1, -1, -1, - 910, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 922, -1, -1, -1, -1, -1, -1, -1, - 928, -1, -1, 933, -1, -1, -1, -1, -1, -1, - 940, -1, -1, 943, 944, 945, 946, 947, 948, -1, - -1, 951, -1, 953, -1, -1, 956, -1, 469, -1, - -1, 961, -1, 963, 964, 965, 477, -1, -1, -1, - -1, 482, 972, -1, -1, -1, -1, -1, 489, 490, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 108, - 109, 110, 111, 112, 113, 114, 507, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, -1, -1, 142, 143, 144, 145, 146, 1026, -1, - -1, -1, 989, -1, -1, 1035, -1, -1, -1, -1, - -1, 998, -1, -1, -1, -1, -1, -1, -1, -1, - 1050, -1, 1052, -1, -1, -1, -1, -1, -1, 1057, - -1, -1, -1, -1, -1, -1, -1, -1, 1068, 1069, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1087, -1, -1, - -1, -1, 1092, -1, -1, 1093, 1096, -1, -1, -1, - -1, 1099, -1, 1101, -1, -1, 1104, -1, -1, -1, - -1, -1, -1, -1, 1071, -1, -1, -1, -1, -1, + -1, 317, 318, -1, 320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1131, -1, -1, -1, 1094, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 666, 667, -1, 1158, -1, - 1160, 672, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 687, 1175, 689, 1177, - 691, -1, 693, -1, 1141, -1, -1, 1144, -1, -1, - -1, 1148, -1, -1, -1, 1193, -1, -1, -1, 1199, - -1, -1, 1159, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1213, -1, -1, -1, -1, -1, -1, - -1, 1221, -1, 1223, 1224, -1, -1, -1, -1, -1, + 192, -1, -1, -1, -1, 197, -1, -1, -1, -1, + -1, -1, -1, -1, 905, -1, -1, -1, -1, 910, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1204, 1205, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1217, -1, -1, -1, -1, -1, -1, -1, -1, 1269, - -1, -1, -1, -1, -1, -1, 1276, -1, -1, -1, + -1, 922, -1, -1, -1, -1, -1, -1, -1, 928, + -1, -1, 933, -1, -1, -1, -1, -1, -1, 940, + -1, -1, 943, 944, 945, 946, 947, 948, -1, -1, + 951, -1, 953, -1, -1, 956, -1, -1, -1, -1, + 961, -1, 963, 964, 965, -1, -1, -1, -1, -1, + -1, 972, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, -1, 469, -1, -1, -1, -1, -1, -1, + -1, 477, -1, -1, -1, -1, 482, -1, 1027, -1, + -1, -1, -1, 489, 490, 1036, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 350, -1, + 1051, 507, 1053, 355, 356, -1, -1, -1, -1, 1058, + -1, -1, -1, -1, -1, -1, -1, -1, 1069, 1070, + -1, -1, -1, -1, 376, 377, -1, -1, -1, -1, + -1, -1, -1, 385, -1, -1, -1, -1, 1089, -1, + -1, -1, -1, 1094, -1, 397, 1095, 1098, 400, -1, + -1, -1, 1101, -1, 1103, 407, -1, 1106, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1288, -1, 1292, -1, 1294, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 1308, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1319, -1, -1, -1, -1, -1, -1, 1326, -1, - -1, -1, -1, -1, -1, -1, 1334, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 858, 859, 860, - 861, -1, 863, 864, -1, 1355, 1356, 4, 5, -1, - -1, -1, 873, 10, 875, 876, -1, -1, 15, -1, - 17, 18, 883, 884, -1, -1, -1, 24, -1, -1, - 27, -1, -1, -1, -1, 896, -1, 34, 35, -1, - 37, -1, 39, 1393, -1, -1, -1, 44, -1, 46, - 1400, -1, 49, -1, -1, 52, -1, -1, -1, -1, - -1, -1, -1, 60, -1, -1, 63, -1, 65, 66, - 67, 68, 1422, -1, -1, -1, -1, -1, -1, 76, - 77, -1, 79, 80, 81, -1, 83, 84, 85, 86, - 87, 88, -1, 90, 91, 92, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, -1, -1, -1, -1, + -1, -1, -1, -1, 1133, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1011, -1, -1, -1, -1, 1016, 1017, -1, 1019, -1, - -1, -1, -1, -1, -1, -1, 1027, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1160, + -1, 1162, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1177, -1, + 1179, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1195, -1, -1, -1, + 1201, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 666, 667, -1, -1, 1215, -1, 672, -1, -1, -1, + -1, -1, 1223, -1, 1225, 1226, -1, 529, 530, -1, + -1, 687, -1, 689, -1, 691, -1, 693, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 550, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 567, -1, -1, -1, -1, + 1271, -1, -1, -1, -1, -1, -1, 1278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1290, -1, 1294, -1, 1296, -1, -1, -1, -1, + -1, -1, -1, -1, 606, -1, -1, -1, 610, 1310, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1321, -1, -1, -1, -1, -1, -1, 1328, + -1, -1, -1, -1, -1, -1, -1, 1336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1357, 1358, -1, -1, + -1, 108, 109, 110, 111, 112, 113, 114, -1, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, -1, 1395, 142, 143, 144, 145, 146, + -1, 1402, 858, 859, 860, 861, -1, 863, 864, -1, + -1, -1, -1, -1, -1, -1, -1, 873, -1, 875, + 876, -1, -1, 1424, -1, -1, -1, 883, 884, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 896, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 761, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 781, + -1, 783, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 820, -1, + -1, 823, -1, -1, -1, -1, -1, -1, -1, -1, + 832, -1, -1, -1, -1, -1, 838, -1, -1, 841, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1011, -1, -1, -1, -1, + 1016, 1017, -1, 1019, -1, -1, -1, -1, -1, 1025, + -1, -1, 1028, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 1188, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 1203, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 989, -1, -1, + -1, -1, -1, -1, -1, -1, 998, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1190, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 1205, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 1284, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1073, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1312, -1, -1, 1315, 1316, -1, 1318, -1, -1, - -1, 1322, 1323, -1, 1325, -1, 1327, -1, -1, 1330, - 1331, -1, 1333, -1, 1335, -1, 1337, 1338, -1, 1340, - 1341, -1, 1343, 1344, -1, 1346, -1, 1348, 1349, -1, - 1351, -1, 1353, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 1096, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 1392, -1, 1394, 1395, -1, 1397, 1398, 1399, -1, - 1401, 1402, 1403, 1404, -1, -1, -1, -1, -1, -1, + 1286, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1143, -1, -1, 1146, -1, -1, -1, 1150, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 1314, 1161, + -1, 1317, 1318, -1, 1320, -1, -1, -1, 1324, 1325, + -1, 1327, -1, 1329, -1, -1, 1332, 1333, -1, 1335, + -1, 1337, -1, 1339, 1340, -1, 1342, 1343, -1, 1345, + 1346, -1, 1348, -1, 1350, 1351, -1, 1353, -1, 1355, + -1, -1, -1, -1, 1206, 1207, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1219, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1421, -1, 1423 + -1, -1, -1, -1, -1, -1, -1, -1, 1394, -1, + 1396, 1397, -1, 1399, 1400, 1401, -1, 1403, 1404, 1405, + 1406, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1423, -1, 1425 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing @@ -2064,47 +2080,47 @@ static const yytype_uint16 yystos[] = 203, 482, 482, 204, 207, 202, 207, 204, 204, 203, 203, 204, 204, 512, 203, 203, 203, 203, 203, 203, 203, 238, 425, 429, 203, 172, 267, 267, 203, 373, - 203, 7, 11, 12, 13, 256, 257, 386, 203, 203, - 203, 180, 195, 196, 203, 218, 220, 223, 229, 234, - 229, 234, 234, 234, 169, 226, 169, 233, 184, 205, - 237, 494, 167, 385, 205, 431, 204, 383, 429, 513, - 516, 204, 204, 204, 204, 259, 419, 419, 259, 259, - 259, 202, 259, 204, 168, 198, 203, 204, 204, 204, - 204, 209, 209, 209, 209, 204, 204, 230, 203, 207, - 203, 204, 330, 507, 202, 204, 514, 8, 282, 284, - 281, 284, 282, 283, 284, 203, 203, 266, 281, 180, - 197, 198, 223, 229, 234, 229, 234, 234, 234, 169, - 227, 260, 203, 7, 11, 12, 13, 14, 69, 426, - 427, 428, 203, 202, 384, 208, 429, 516, 203, 204, - 272, 202, 204, 270, 202, 207, 204, 275, 202, 204, - 204, 392, 198, 204, 204, 204, 209, 204, 330, 202, - 504, 204, 514, 514, 7, 11, 12, 13, 14, 69, - 89, 208, 252, 253, 254, 255, 261, 265, 305, 205, - 285, 208, 281, 305, 285, 208, 283, 285, 267, 36, - 208, 305, 393, 394, 229, 234, 234, 234, 169, 228, - 203, 266, 203, 385, 202, 202, 204, 204, 270, 207, - 204, 275, 204, 259, 204, 207, 207, 202, 204, 203, - 204, 262, 204, 505, 259, 266, 266, 208, 108, 109, - 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 142, - 143, 144, 145, 146, 298, 107, 115, 140, 141, 286, - 289, 298, 107, 115, 140, 141, 291, 294, 298, 203, - 393, 205, 395, 234, 267, 203, 208, 494, 507, 203, - 203, 204, 262, 204, 296, 204, 204, 204, 204, 203, - 204, 204, 204, 204, 204, 203, 204, 207, 330, 259, - 207, 202, 267, 203, 22, 238, 261, 297, 303, 304, - 203, 20, 238, 253, 287, 299, 300, 303, 287, 21, - 238, 253, 288, 301, 302, 303, 288, 238, 253, 290, - 303, 238, 292, 299, 303, 287, 238, 293, 301, 303, - 293, 238, 295, 303, 203, 504, 259, 259, 259, 204, - 259, 202, 259, 259, 204, 259, 202, 204, 259, 259, - 259, 204, 259, 202, 204, 259, 259, 259, 204, 259, - 259, 204, 259, 259, 259, 204, 259, 259, 259, 259, - 203, 203, 261, 180, 253, 303, 169, 253, 253, 303, - 169, 253, 253, 303, 303, 505, 259, 203, 259, 204, - 259, 204, 259, 259, 204, 259, 203, 259, 259, 259, - 259, 253, 258, 253, 259, 203, 259 + 203, 7, 11, 12, 13, 238, 256, 257, 386, 203, + 203, 203, 180, 195, 196, 203, 218, 220, 223, 229, + 234, 229, 234, 234, 234, 169, 226, 169, 233, 184, + 205, 237, 494, 167, 385, 205, 431, 204, 383, 429, + 513, 516, 204, 204, 204, 204, 259, 419, 419, 259, + 259, 259, 259, 202, 259, 204, 168, 198, 203, 204, + 204, 204, 204, 209, 209, 209, 209, 204, 204, 230, + 203, 207, 203, 204, 330, 507, 202, 204, 514, 8, + 282, 284, 281, 284, 282, 283, 284, 203, 203, 266, + 281, 180, 197, 198, 223, 229, 234, 229, 234, 234, + 234, 169, 227, 260, 203, 7, 11, 12, 13, 14, + 69, 426, 427, 428, 203, 202, 384, 208, 429, 516, + 203, 204, 272, 202, 204, 270, 202, 207, 204, 275, + 202, 204, 204, 392, 198, 204, 204, 204, 209, 204, + 330, 202, 504, 204, 514, 514, 7, 11, 12, 13, + 14, 69, 89, 208, 252, 253, 254, 255, 261, 265, + 305, 205, 285, 208, 281, 305, 285, 208, 283, 285, + 267, 36, 208, 305, 393, 394, 229, 234, 234, 234, + 169, 228, 203, 266, 203, 385, 202, 202, 204, 204, + 270, 207, 204, 275, 204, 259, 204, 207, 207, 202, + 204, 203, 204, 262, 204, 505, 259, 266, 266, 208, + 108, 109, 110, 111, 112, 113, 114, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, + 139, 142, 143, 144, 145, 146, 298, 107, 115, 140, + 141, 286, 289, 298, 107, 115, 140, 141, 291, 294, + 298, 203, 393, 205, 395, 234, 267, 203, 208, 494, + 507, 203, 203, 204, 262, 204, 296, 204, 204, 204, + 204, 203, 204, 204, 204, 204, 204, 203, 204, 207, + 330, 259, 207, 202, 267, 203, 22, 238, 261, 297, + 303, 304, 203, 20, 238, 253, 287, 299, 300, 303, + 287, 21, 238, 253, 288, 301, 302, 303, 288, 238, + 253, 290, 303, 238, 292, 299, 303, 287, 238, 293, + 301, 303, 293, 238, 295, 303, 203, 504, 259, 259, + 259, 204, 259, 202, 259, 259, 204, 259, 202, 204, + 259, 259, 259, 204, 259, 202, 204, 259, 259, 259, + 204, 259, 259, 204, 259, 259, 259, 204, 259, 259, + 259, 259, 203, 203, 261, 180, 253, 303, 169, 253, + 253, 303, 169, 253, 253, 303, 303, 505, 259, 203, + 259, 204, 259, 204, 259, 259, 204, 259, 203, 259, + 259, 259, 259, 253, 258, 253, 259, 203, 259 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ @@ -2156,30 +2172,30 @@ static const yytype_uint16 yyr1[] = 362, 363, 363, 364, 364, 364, 364, 365, 366, 366, 366, 366, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 375, 375, 376, 377, 378, 379, 379, 380, - 381, 382, 382, 383, 384, 385, 386, 387, 387, 388, - 389, 390, 390, 391, 392, 392, 392, 392, 392, 393, - 394, 395, 396, 396, 397, 398, 398, 398, 399, 400, - 400, 401, 402, 402, 403, 404, 405, 406, 406, 407, - 408, 409, 410, 410, 410, 410, 410, 411, 411, 412, - 413, 414, 414, 415, 416, 417, 418, 419, 419, 419, - 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 428, 428, 428, 428, 428, 429, 430, 431, 432, 432, - 432, 433, 433, 434, 435, 435, 436, 437, 437, 438, - 439, 440, 441, 441, 441, 442, 443, 444, 445, 446, - 447, 448, 449, 450, 450, 450, 450, 451, 452, 452, - 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, - 463, 464, 465, 466, 466, 466, 466, 466, 466, 466, - 466, 466, 466, 466, 466, 467, 467, 468, 468, 468, - 469, 470, 471, 472, 472, 473, 473, 473, 474, 475, - 475, 476, 477, 477, 477, 477, 477, 477, 477, 477, - 477, 477, 477, 477, 477, 477, 478, 478, 478, 478, - 478, 478, 478, 479, 480, 480, 481, 482, 482, 482, - 482, 482, 482, 482, 483, 484, 485, 486, 487, 488, - 489, 490, 491, 492, 493, 494, 495, 496, 497, 497, - 498, 499, 499, 499, 499, 499, 500, 501, 502, 502, - 503, 504, 504, 504, 504, 505, 505, 505, 505, 506, - 507, 508, 509, 510, 511, 511, 512, 513, 513, 514, - 514, 514, 514, 515, 516 + 381, 382, 382, 382, 383, 384, 385, 386, 387, 387, + 388, 389, 390, 390, 391, 392, 392, 392, 392, 392, + 393, 394, 395, 396, 396, 397, 398, 398, 398, 399, + 400, 400, 401, 402, 402, 403, 404, 405, 406, 406, + 407, 408, 409, 410, 410, 410, 410, 410, 411, 411, + 412, 413, 414, 414, 415, 416, 417, 418, 419, 419, + 419, 419, 420, 421, 422, 423, 424, 425, 426, 427, + 428, 428, 428, 428, 428, 428, 429, 430, 431, 432, + 432, 432, 433, 433, 434, 435, 435, 436, 437, 437, + 438, 439, 440, 441, 441, 441, 442, 443, 444, 445, + 446, 447, 448, 449, 450, 450, 450, 450, 451, 452, + 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 465, 466, 466, 466, 466, 466, 466, + 466, 466, 466, 466, 466, 466, 467, 467, 468, 468, + 468, 469, 470, 471, 472, 472, 473, 473, 473, 474, + 475, 475, 476, 477, 477, 477, 477, 477, 477, 477, + 477, 477, 477, 477, 477, 477, 477, 478, 478, 478, + 478, 478, 478, 478, 479, 480, 480, 481, 482, 482, + 482, 482, 482, 482, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, + 497, 498, 499, 499, 499, 499, 499, 500, 501, 502, + 502, 503, 504, 504, 504, 504, 505, 505, 505, 505, + 506, 507, 508, 509, 510, 511, 511, 512, 513, 513, + 514, 514, 514, 514, 515, 516 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -2231,30 +2247,30 @@ static const yytype_uint8 yyr2[] = 10, 1, 1, 1, 1, 1, 1, 7, 0, 3, 5, 3, 3, 9, 7, 9, 1, 1, 1, 1, 7, 0, 3, 3, 1, 1, 5, 1, 1, 1, - 7, 0, 3, 1, 1, 1, 1, 1, 1, 8, - 10, 1, 1, 10, 0, 3, 5, 3, 2, 5, - 1, 1, 1, 1, 5, 1, 1, 1, 8, 1, - 1, 5, 1, 1, 8, 1, 5, 1, 1, 8, - 1, 5, 0, 3, 5, 3, 3, 1, 1, 4, - 1, 1, 1, 4, 1, 1, 7, 0, 3, 3, - 3, 1, 1, 5, 1, 1, 9, 1, 5, 1, - 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, - 1, 1, 1, 10, 1, 1, 10, 1, 1, 10, - 10, 7, 0, 3, 3, 9, 7, 9, 10, 1, - 1, 9, 1, 1, 1, 1, 1, 10, 1, 1, - 7, 9, 1, 10, 7, 1, 10, 7, 1, 10, - 7, 1, 9, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 3, 2, - 1, 1, 4, 1, 1, 1, 2, 3, 4, 1, - 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 7, 0, 3, 3, 1, 1, 1, 1, 1, 1, + 8, 10, 1, 1, 10, 0, 3, 5, 3, 2, + 5, 1, 1, 1, 1, 5, 1, 1, 1, 8, + 1, 1, 5, 1, 1, 8, 1, 5, 1, 1, + 8, 1, 5, 0, 3, 5, 3, 3, 1, 1, + 4, 1, 1, 1, 4, 1, 1, 7, 0, 3, + 3, 3, 1, 1, 5, 1, 1, 9, 1, 5, + 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, + 1, 1, 1, 1, 10, 1, 1, 10, 1, 1, + 10, 10, 7, 0, 3, 3, 9, 7, 9, 10, + 1, 1, 9, 1, 1, 1, 1, 1, 10, 1, + 1, 7, 9, 1, 10, 7, 1, 10, 7, 1, + 10, 7, 1, 9, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, + 2, 1, 1, 4, 1, 1, 1, 2, 3, 4, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 4, 3, 1, 8, 0, 3, 3, - 3, 5, 3, 2, 1, 1, 4, 1, 1, 4, - 1, 4, 1, 4, 1, 4, 1, 4, 3, 1, - 6, 0, 3, 3, 3, 2, 1, 4, 3, 1, - 16, 1, 1, 1, 1, 0, 6, 3, 2, 1, - 1, 9, 1, 4, 3, 1, 6, 1, 1, 0, - 3, 3, 2, 1, 7 + 1, 1, 1, 1, 4, 3, 1, 8, 0, 3, + 3, 3, 5, 3, 2, 1, 1, 4, 1, 1, + 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, + 1, 6, 0, 3, 3, 3, 2, 1, 4, 3, + 1, 16, 1, 1, 1, 1, 0, 6, 3, 2, + 1, 1, 9, 1, 4, 3, 1, 6, 1, 1, + 0, 3, 3, 2, 1, 7 }; diff --git a/src/wkt2_grammar.y b/src/wkt2_grammar.y index 4f30b5b2..fc2e8bf0 100644 --- a/src/wkt2_grammar.y +++ b/src/wkt2_grammar.y @@ -1073,6 +1073,7 @@ map_projection_parameter: parameter_keyword left_delimiter parameter_name right_delimiter opt_separator_param_unit_identifier_list: + | wkt_separator identifier opt_separator_identifier_list | wkt_separator map_projection_parameter_unit opt_separator_identifier_list parameter_keyword: T_PARAMETER |
